diff options
489 files changed, 14315 insertions, 7098 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-event_source-devices-events b/Documentation/ABI/testing/sysfs-bus-event_source-devices-events new file mode 100644 index 000000000000..0adeb524c0d4 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-event_source-devices-events | |||
@@ -0,0 +1,62 @@ | |||
1 | What: /sys/devices/cpu/events/ | ||
2 | /sys/devices/cpu/events/branch-misses | ||
3 | /sys/devices/cpu/events/cache-references | ||
4 | /sys/devices/cpu/events/cache-misses | ||
5 | /sys/devices/cpu/events/stalled-cycles-frontend | ||
6 | /sys/devices/cpu/events/branch-instructions | ||
7 | /sys/devices/cpu/events/stalled-cycles-backend | ||
8 | /sys/devices/cpu/events/instructions | ||
9 | /sys/devices/cpu/events/cpu-cycles | ||
10 | |||
11 | Date: 2013/01/08 | ||
12 | |||
13 | Contact: Linux kernel mailing list <linux-kernel@vger.kernel.org> | ||
14 | |||
15 | Description: Generic performance monitoring events | ||
16 | |||
17 | A collection of performance monitoring events that may be | ||
18 | supported by many/most CPUs. These events can be monitored | ||
19 | using the 'perf(1)' tool. | ||
20 | |||
21 | The contents of each file would look like: | ||
22 | |||
23 | event=0xNNNN | ||
24 | |||
25 | where 'N' is a hex digit and the number '0xNNNN' shows the | ||
26 | "raw code" for the perf event identified by the file's | ||
27 | "basename". | ||
28 | |||
29 | |||
30 | What: /sys/devices/cpu/events/PM_LD_MISS_L1 | ||
31 | /sys/devices/cpu/events/PM_LD_REF_L1 | ||
32 | /sys/devices/cpu/events/PM_CYC | ||
33 | /sys/devices/cpu/events/PM_BRU_FIN | ||
34 | /sys/devices/cpu/events/PM_GCT_NOSLOT_CYC | ||
35 | /sys/devices/cpu/events/PM_BRU_MPRED | ||
36 | /sys/devices/cpu/events/PM_INST_CMPL | ||
37 | /sys/devices/cpu/events/PM_CMPLU_STALL | ||
38 | |||
39 | Date: 2013/01/08 | ||
40 | |||
41 | Contact: Linux kernel mailing list <linux-kernel@vger.kernel.org> | ||
42 | Linux Powerpc mailing list <linuxppc-dev@ozlabs.org> | ||
43 | |||
44 | Description: POWER-systems specific performance monitoring events | ||
45 | |||
46 | A collection of performance monitoring events that may be | ||
47 | supported by the POWER CPU. These events can be monitored | ||
48 | using the 'perf(1)' tool. | ||
49 | |||
50 | These events may not be supported by other CPUs. | ||
51 | |||
52 | The contents of each file would look like: | ||
53 | |||
54 | event=0xNNNN | ||
55 | |||
56 | where 'N' is a hex digit and the number '0xNNNN' shows the | ||
57 | "raw code" for the perf event identified by the file's | ||
58 | "basename". | ||
59 | |||
60 | Further, multiple terms like 'event=0xNNNN' can be specified | ||
61 | and separated with comma. All available terms are defined in | ||
62 | the /sys/bus/event_source/devices/<dev>/format file. | ||
diff --git a/Documentation/ABI/testing/sysfs-platform-ts5500 b/Documentation/ABI/testing/sysfs-platform-ts5500 new file mode 100644 index 000000000000..c88375a537a1 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-platform-ts5500 | |||
@@ -0,0 +1,47 @@ | |||
1 | What: /sys/devices/platform/ts5500/adc | ||
2 | Date: January 2013 | ||
3 | KernelVersion: 3.7 | ||
4 | Contact: "Savoir-faire Linux Inc." <kernel@savoirfairelinux.com> | ||
5 | Description: | ||
6 | Indicates the presence of an A/D Converter. If it is present, | ||
7 | it will display "1", otherwise "0". | ||
8 | |||
9 | What: /sys/devices/platform/ts5500/ereset | ||
10 | Date: January 2013 | ||
11 | KernelVersion: 3.7 | ||
12 | Contact: "Savoir-faire Linux Inc." <kernel@savoirfairelinux.com> | ||
13 | Description: | ||
14 | Indicates the presence of an external reset. If it is present, | ||
15 | it will display "1", otherwise "0". | ||
16 | |||
17 | What: /sys/devices/platform/ts5500/id | ||
18 | Date: January 2013 | ||
19 | KernelVersion: 3.7 | ||
20 | Contact: "Savoir-faire Linux Inc." <kernel@savoirfairelinux.com> | ||
21 | Description: | ||
22 | Product ID of the TS board. TS-5500 ID is 0x60. | ||
23 | |||
24 | What: /sys/devices/platform/ts5500/jumpers | ||
25 | Date: January 2013 | ||
26 | KernelVersion: 3.7 | ||
27 | Contact: "Savoir-faire Linux Inc." <kernel@savoirfairelinux.com> | ||
28 | Description: | ||
29 | Bitfield showing the jumpers' state. If a jumper is present, | ||
30 | the corresponding bit is set. For instance, 0x0e means jumpers | ||
31 | 2, 3 and 4 are set. | ||
32 | |||
33 | What: /sys/devices/platform/ts5500/rs485 | ||
34 | Date: January 2013 | ||
35 | KernelVersion: 3.7 | ||
36 | Contact: "Savoir-faire Linux Inc." <kernel@savoirfairelinux.com> | ||
37 | Description: | ||
38 | Indicates the presence of the RS485 option. If it is present, | ||
39 | it will display "1", otherwise "0". | ||
40 | |||
41 | What: /sys/devices/platform/ts5500/sram | ||
42 | Date: January 2013 | ||
43 | KernelVersion: 3.7 | ||
44 | Contact: "Savoir-faire Linux Inc." <kernel@savoirfairelinux.com> | ||
45 | Description: | ||
46 | Indicates the presence of the SRAM option. If it is present, | ||
47 | it will display "1", otherwise "0". | ||
diff --git a/Documentation/PCI/MSI-HOWTO.txt b/Documentation/PCI/MSI-HOWTO.txt index 53e6fca146d7..a09178086c30 100644 --- a/Documentation/PCI/MSI-HOWTO.txt +++ b/Documentation/PCI/MSI-HOWTO.txt | |||
@@ -127,15 +127,42 @@ on the number of vectors that can be allocated; pci_enable_msi_block() | |||
127 | returns as soon as it finds any constraint that doesn't allow the | 127 | returns as soon as it finds any constraint that doesn't allow the |
128 | call to succeed. | 128 | call to succeed. |
129 | 129 | ||
130 | 4.2.3 pci_disable_msi | 130 | 4.2.3 pci_enable_msi_block_auto |
131 | |||
132 | int pci_enable_msi_block_auto(struct pci_dev *dev, unsigned int *count) | ||
133 | |||
134 | This variation on pci_enable_msi() call allows a device driver to request | ||
135 | the maximum possible number of MSIs. The MSI specification only allows | ||
136 | interrupts to be allocated in powers of two, up to a maximum of 2^5 (32). | ||
137 | |||
138 | If this function returns a positive number, it indicates that it has | ||
139 | succeeded and the returned value is the number of allocated interrupts. In | ||
140 | this case, the function enables MSI on this device and updates dev->irq to | ||
141 | be the lowest of the new interrupts assigned to it. The other interrupts | ||
142 | assigned to the device are in the range dev->irq to dev->irq + returned | ||
143 | value - 1. | ||
144 | |||
145 | If this function returns a negative number, it indicates an error and | ||
146 | the driver should not attempt to request any more MSI interrupts for | ||
147 | this device. | ||
148 | |||
149 | If the device driver needs to know the number of interrupts the device | ||
150 | supports it can pass the pointer count where that number is stored. The | ||
151 | device driver must decide what action to take if pci_enable_msi_block_auto() | ||
152 | succeeds, but returns a value less than the number of interrupts supported. | ||
153 | If the device driver does not need to know the number of interrupts | ||
154 | supported, it can set the pointer count to NULL. | ||
155 | |||
156 | 4.2.4 pci_disable_msi | ||
131 | 157 | ||
132 | void pci_disable_msi(struct pci_dev *dev) | 158 | void pci_disable_msi(struct pci_dev *dev) |
133 | 159 | ||
134 | This function should be used to undo the effect of pci_enable_msi() or | 160 | This function should be used to undo the effect of pci_enable_msi() or |
135 | pci_enable_msi_block(). Calling it restores dev->irq to the pin-based | 161 | pci_enable_msi_block() or pci_enable_msi_block_auto(). Calling it restores |
136 | interrupt number and frees the previously allocated message signaled | 162 | dev->irq to the pin-based interrupt number and frees the previously |
137 | interrupt(s). The interrupt may subsequently be assigned to another | 163 | allocated message signaled interrupt(s). The interrupt may subsequently be |
138 | device, so drivers should not cache the value of dev->irq. | 164 | assigned to another device, so drivers should not cache the value of |
165 | dev->irq. | ||
139 | 166 | ||
140 | Before calling this function, a device driver must always call free_irq() | 167 | Before calling this function, a device driver must always call free_irq() |
141 | on any interrupt for which it previously called request_irq(). | 168 | on any interrupt for which it previously called request_irq(). |
diff --git a/Documentation/atomic_ops.txt b/Documentation/atomic_ops.txt index 27f2b21a9d5c..d9ca5be9b471 100644 --- a/Documentation/atomic_ops.txt +++ b/Documentation/atomic_ops.txt | |||
@@ -253,6 +253,8 @@ This performs an atomic exchange operation on the atomic variable v, setting | |||
253 | the given new value. It returns the old value that the atomic variable v had | 253 | the given new value. It returns the old value that the atomic variable v had |
254 | just before the operation. | 254 | just before the operation. |
255 | 255 | ||
256 | atomic_xchg requires explicit memory barriers around the operation. | ||
257 | |||
256 | int atomic_cmpxchg(atomic_t *v, int old, int new); | 258 | int atomic_cmpxchg(atomic_t *v, int old, int new); |
257 | 259 | ||
258 | This performs an atomic compare exchange operation on the atomic value v, | 260 | This performs an atomic compare exchange operation on the atomic value v, |
diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt index 3c4e1b3b80a1..fa5d8a9ae205 100644 --- a/Documentation/memory-barriers.txt +++ b/Documentation/memory-barriers.txt | |||
@@ -1685,6 +1685,7 @@ explicit lock operations, described later). These include: | |||
1685 | 1685 | ||
1686 | xchg(); | 1686 | xchg(); |
1687 | cmpxchg(); | 1687 | cmpxchg(); |
1688 | atomic_xchg(); | ||
1688 | atomic_cmpxchg(); | 1689 | atomic_cmpxchg(); |
1689 | atomic_inc_return(); | 1690 | atomic_inc_return(); |
1690 | atomic_dec_return(); | 1691 | atomic_dec_return(); |
diff --git a/Documentation/trace/ftrace.txt b/Documentation/trace/ftrace.txt index 6f51fed45f2d..53d6a3c51d87 100644 --- a/Documentation/trace/ftrace.txt +++ b/Documentation/trace/ftrace.txt | |||
@@ -1842,6 +1842,89 @@ an error. | |||
1842 | # cat buffer_size_kb | 1842 | # cat buffer_size_kb |
1843 | 85 | 1843 | 85 |
1844 | 1844 | ||
1845 | Snapshot | ||
1846 | -------- | ||
1847 | CONFIG_TRACER_SNAPSHOT makes a generic snapshot feature | ||
1848 | available to all non latency tracers. (Latency tracers which | ||
1849 | record max latency, such as "irqsoff" or "wakeup", can't use | ||
1850 | this feature, since those are already using the snapshot | ||
1851 | mechanism internally.) | ||
1852 | |||
1853 | Snapshot preserves a current trace buffer at a particular point | ||
1854 | in time without stopping tracing. Ftrace swaps the current | ||
1855 | buffer with a spare buffer, and tracing continues in the new | ||
1856 | current (=previous spare) buffer. | ||
1857 | |||
1858 | The following debugfs files in "tracing" are related to this | ||
1859 | feature: | ||
1860 | |||
1861 | snapshot: | ||
1862 | |||
1863 | This is used to take a snapshot and to read the output | ||
1864 | of the snapshot. Echo 1 into this file to allocate a | ||
1865 | spare buffer and to take a snapshot (swap), then read | ||
1866 | the snapshot from this file in the same format as | ||
1867 | "trace" (described above in the section "The File | ||
1868 | System"). Both reads snapshot and tracing are executable | ||
1869 | in parallel. When the spare buffer is allocated, echoing | ||
1870 | 0 frees it, and echoing else (positive) values clear the | ||
1871 | snapshot contents. | ||
1872 | More details are shown in the table below. | ||
1873 | |||
1874 | status\input | 0 | 1 | else | | ||
1875 | --------------+------------+------------+------------+ | ||
1876 | not allocated |(do nothing)| alloc+swap | EINVAL | | ||
1877 | --------------+------------+------------+------------+ | ||
1878 | allocated | free | swap | clear | | ||
1879 | --------------+------------+------------+------------+ | ||
1880 | |||
1881 | Here is an example of using the snapshot feature. | ||
1882 | |||
1883 | # echo 1 > events/sched/enable | ||
1884 | # echo 1 > snapshot | ||
1885 | # cat snapshot | ||
1886 | # tracer: nop | ||
1887 | # | ||
1888 | # entries-in-buffer/entries-written: 71/71 #P:8 | ||
1889 | # | ||
1890 | # _-----=> irqs-off | ||
1891 | # / _----=> need-resched | ||
1892 | # | / _---=> hardirq/softirq | ||
1893 | # || / _--=> preempt-depth | ||
1894 | # ||| / delay | ||
1895 | # TASK-PID CPU# |||| TIMESTAMP FUNCTION | ||
1896 | # | | | |||| | | | ||
1897 | <idle>-0 [005] d... 2440.603828: sched_switch: prev_comm=swapper/5 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=snapshot-test-2 next_pid=2242 next_prio=120 | ||
1898 | sleep-2242 [005] d... 2440.603846: sched_switch: prev_comm=snapshot-test-2 prev_pid=2242 prev_prio=120 prev_state=R ==> next_comm=kworker/5:1 next_pid=60 next_prio=120 | ||
1899 | [...] | ||
1900 | <idle>-0 [002] d... 2440.707230: sched_switch: prev_comm=swapper/2 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=snapshot-test-2 next_pid=2229 next_prio=120 | ||
1901 | |||
1902 | # cat trace | ||
1903 | # tracer: nop | ||
1904 | # | ||
1905 | # entries-in-buffer/entries-written: 77/77 #P:8 | ||
1906 | # | ||
1907 | # _-----=> irqs-off | ||
1908 | # / _----=> need-resched | ||
1909 | # | / _---=> hardirq/softirq | ||
1910 | # || / _--=> preempt-depth | ||
1911 | # ||| / delay | ||
1912 | # TASK-PID CPU# |||| TIMESTAMP FUNCTION | ||
1913 | # | | | |||| | | | ||
1914 | <idle>-0 [007] d... 2440.707395: sched_switch: prev_comm=swapper/7 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=snapshot-test-2 next_pid=2243 next_prio=120 | ||
1915 | snapshot-test-2-2229 [002] d... 2440.707438: sched_switch: prev_comm=snapshot-test-2 prev_pid=2229 prev_prio=120 prev_state=S ==> next_comm=swapper/2 next_pid=0 next_prio=120 | ||
1916 | [...] | ||
1917 | |||
1918 | |||
1919 | If you try to use this snapshot feature when current tracer is | ||
1920 | one of the latency tracers, you will get the following results. | ||
1921 | |||
1922 | # echo wakeup > current_tracer | ||
1923 | # echo 1 > snapshot | ||
1924 | bash: echo: write error: Device or resource busy | ||
1925 | # cat snapshot | ||
1926 | cat: snapshot: Device or resource busy | ||
1927 | |||
1845 | ----------- | 1928 | ----------- |
1846 | 1929 | ||
1847 | More details can be found in the source code, in the | 1930 | More details can be found in the source code, in the |
diff --git a/Documentation/x86/boot.txt b/Documentation/x86/boot.txt index e540fd67f767..b443f1de0e5a 100644 --- a/Documentation/x86/boot.txt +++ b/Documentation/x86/boot.txt | |||
@@ -390,6 +390,7 @@ Protocol: 2.00+ | |||
390 | F Special (0xFF = undefined) | 390 | F Special (0xFF = undefined) |
391 | 10 Reserved | 391 | 10 Reserved |
392 | 11 Minimal Linux Bootloader <http://sebastian-plotz.blogspot.de> | 392 | 11 Minimal Linux Bootloader <http://sebastian-plotz.blogspot.de> |
393 | 12 OVMF UEFI virtualization stack | ||
393 | 394 | ||
394 | Please contact <hpa@zytor.com> if you need a bootloader ID | 395 | Please contact <hpa@zytor.com> if you need a bootloader ID |
395 | value assigned. | 396 | value assigned. |
diff --git a/MAINTAINERS b/MAINTAINERS index 35a56bcd5e75..526fb85f2f7e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -1303,7 +1303,7 @@ F: include/linux/dmaengine.h | |||
1303 | F: include/linux/async_tx.h | 1303 | F: include/linux/async_tx.h |
1304 | 1304 | ||
1305 | AT24 EEPROM DRIVER | 1305 | AT24 EEPROM DRIVER |
1306 | M: Wolfram Sang <w.sang@pengutronix.de> | 1306 | M: Wolfram Sang <wsa@the-dreams.de> |
1307 | L: linux-i2c@vger.kernel.org | 1307 | L: linux-i2c@vger.kernel.org |
1308 | S: Maintained | 1308 | S: Maintained |
1309 | F: drivers/misc/eeprom/at24.c | 1309 | F: drivers/misc/eeprom/at24.c |
@@ -3757,12 +3757,11 @@ S: Maintained | |||
3757 | F: drivers/i2c/i2c-stub.c | 3757 | F: drivers/i2c/i2c-stub.c |
3758 | 3758 | ||
3759 | I2C SUBSYSTEM | 3759 | I2C SUBSYSTEM |
3760 | M: Wolfram Sang <w.sang@pengutronix.de> | 3760 | M: Wolfram Sang <wsa@the-dreams.de> |
3761 | M: "Ben Dooks (embedded platforms)" <ben-linux@fluff.org> | 3761 | M: "Ben Dooks (embedded platforms)" <ben-linux@fluff.org> |
3762 | L: linux-i2c@vger.kernel.org | 3762 | L: linux-i2c@vger.kernel.org |
3763 | W: http://i2c.wiki.kernel.org/ | 3763 | W: http://i2c.wiki.kernel.org/ |
3764 | T: quilt kernel.org/pub/linux/kernel/people/jdelvare/linux-2.6/jdelvare-i2c/ | 3764 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git |
3765 | T: git git://git.pengutronix.de/git/wsa/linux.git | ||
3766 | S: Maintained | 3765 | S: Maintained |
3767 | F: Documentation/i2c/ | 3766 | F: Documentation/i2c/ |
3768 | F: drivers/i2c/ | 3767 | F: drivers/i2c/ |
@@ -5778,15 +5777,6 @@ L: linux-i2c@vger.kernel.org | |||
5778 | S: Maintained | 5777 | S: Maintained |
5779 | F: drivers/i2c/muxes/i2c-mux-pca9541.c | 5778 | F: drivers/i2c/muxes/i2c-mux-pca9541.c |
5780 | 5779 | ||
5781 | PCA9564/PCA9665 I2C BUS DRIVER | ||
5782 | M: Wolfram Sang <w.sang@pengutronix.de> | ||
5783 | L: linux-i2c@vger.kernel.org | ||
5784 | S: Maintained | ||
5785 | F: drivers/i2c/algos/i2c-algo-pca.c | ||
5786 | F: drivers/i2c/busses/i2c-pca-* | ||
5787 | F: include/linux/i2c-algo-pca.h | ||
5788 | F: include/linux/i2c-pca-platform.h | ||
5789 | |||
5790 | PCDP - PRIMARY CONSOLE AND DEBUG PORT | 5780 | PCDP - PRIMARY CONSOLE AND DEBUG PORT |
5791 | M: Khalid Aziz <khalid@gonehiking.org> | 5781 | M: Khalid Aziz <khalid@gonehiking.org> |
5792 | S: Maintained | 5782 | S: Maintained |
@@ -6598,7 +6588,7 @@ F: drivers/dma/dw_dmac_regs.h | |||
6598 | F: drivers/dma/dw_dmac.c | 6588 | F: drivers/dma/dw_dmac.c |
6599 | 6589 | ||
6600 | TIMEKEEPING, NTP | 6590 | TIMEKEEPING, NTP |
6601 | M: John Stultz <johnstul@us.ibm.com> | 6591 | M: John Stultz <john.stultz@linaro.org> |
6602 | M: Thomas Gleixner <tglx@linutronix.de> | 6592 | M: Thomas Gleixner <tglx@linutronix.de> |
6603 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core | 6593 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core |
6604 | S: Supported | 6594 | S: Supported |
@@ -7543,6 +7533,11 @@ F: drivers/net/team/ | |||
7543 | F: include/linux/if_team.h | 7533 | F: include/linux/if_team.h |
7544 | F: include/uapi/linux/if_team.h | 7534 | F: include/uapi/linux/if_team.h |
7545 | 7535 | ||
7536 | TECHNOLOGIC SYSTEMS TS-5500 PLATFORM SUPPORT | ||
7537 | M: Savoir-faire Linux Inc. <kernel@savoirfairelinux.com> | ||
7538 | S: Maintained | ||
7539 | F: arch/x86/platform/ts5500/ | ||
7540 | |||
7546 | TECHNOTREND USB IR RECEIVER | 7541 | TECHNOTREND USB IR RECEIVER |
7547 | M: Sean Young <sean@mess.org> | 7542 | M: Sean Young <sean@mess.org> |
7548 | L: linux-media@vger.kernel.org | 7543 | L: linux-media@vger.kernel.org |
@@ -1,7 +1,7 @@ | |||
1 | VERSION = 3 | 1 | VERSION = 3 |
2 | PATCHLEVEL = 8 | 2 | PATCHLEVEL = 8 |
3 | SUBLEVEL = 0 | 3 | SUBLEVEL = 0 |
4 | EXTRAVERSION = -rc7 | 4 | EXTRAVERSION = |
5 | NAME = Unicycling Gorilla | 5 | NAME = Unicycling Gorilla |
6 | 6 | ||
7 | # *DOCUMENTATION* | 7 | # *DOCUMENTATION* |
@@ -165,7 +165,8 @@ export srctree objtree VPATH | |||
165 | # then ARCH is assigned, getting whatever value it gets normally, and | 165 | # then ARCH is assigned, getting whatever value it gets normally, and |
166 | # SUBARCH is subsequently ignored. | 166 | # SUBARCH is subsequently ignored. |
167 | 167 | ||
168 | SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ | 168 | SUBARCH := $(shell uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/ \ |
169 | -e s/sun4u/sparc64/ \ | ||
169 | -e s/arm.*/arm/ -e s/sa110/arm/ \ | 170 | -e s/arm.*/arm/ -e s/sa110/arm/ \ |
170 | -e s/s390x/s390/ -e s/parisc64/parisc/ \ | 171 | -e s/s390x/s390/ -e s/parisc64/parisc/ \ |
171 | -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ | 172 | -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ |
diff --git a/arch/Kconfig b/arch/Kconfig index 7f8f281f2585..97fb7d0365d1 100644 --- a/arch/Kconfig +++ b/arch/Kconfig | |||
@@ -76,6 +76,15 @@ config OPTPROBES | |||
76 | depends on KPROBES && HAVE_OPTPROBES | 76 | depends on KPROBES && HAVE_OPTPROBES |
77 | depends on !PREEMPT | 77 | depends on !PREEMPT |
78 | 78 | ||
79 | config KPROBES_ON_FTRACE | ||
80 | def_bool y | ||
81 | depends on KPROBES && HAVE_KPROBES_ON_FTRACE | ||
82 | depends on DYNAMIC_FTRACE_WITH_REGS | ||
83 | help | ||
84 | If function tracer is enabled and the arch supports full | ||
85 | passing of pt_regs to function tracing, then kprobes can | ||
86 | optimize on top of function tracing. | ||
87 | |||
79 | config UPROBES | 88 | config UPROBES |
80 | bool "Transparent user-space probes (EXPERIMENTAL)" | 89 | bool "Transparent user-space probes (EXPERIMENTAL)" |
81 | depends on UPROBE_EVENT && PERF_EVENTS | 90 | depends on UPROBE_EVENT && PERF_EVENTS |
@@ -158,6 +167,9 @@ config HAVE_KRETPROBES | |||
158 | config HAVE_OPTPROBES | 167 | config HAVE_OPTPROBES |
159 | bool | 168 | bool |
160 | 169 | ||
170 | config HAVE_KPROBES_ON_FTRACE | ||
171 | bool | ||
172 | |||
161 | config HAVE_NMI_WATCHDOG | 173 | config HAVE_NMI_WATCHDOG |
162 | bool | 174 | bool |
163 | # | 175 | # |
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig index 9d5904cc7712..9b504af2e966 100644 --- a/arch/alpha/Kconfig +++ b/arch/alpha/Kconfig | |||
@@ -5,7 +5,6 @@ config ALPHA | |||
5 | select HAVE_IDE | 5 | select HAVE_IDE |
6 | select HAVE_OPROFILE | 6 | select HAVE_OPROFILE |
7 | select HAVE_SYSCALL_WRAPPERS | 7 | select HAVE_SYSCALL_WRAPPERS |
8 | select HAVE_IRQ_WORK | ||
9 | select HAVE_PCSPKR_PLATFORM | 8 | select HAVE_PCSPKR_PLATFORM |
10 | select HAVE_PERF_EVENTS | 9 | select HAVE_PERF_EVENTS |
11 | select HAVE_DMA_ATTRS | 10 | select HAVE_DMA_ATTRS |
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index 14db93e4c8a8..dbc1760f418b 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c | |||
@@ -1139,6 +1139,7 @@ struct rusage32 { | |||
1139 | SYSCALL_DEFINE2(osf_getrusage, int, who, struct rusage32 __user *, ru) | 1139 | SYSCALL_DEFINE2(osf_getrusage, int, who, struct rusage32 __user *, ru) |
1140 | { | 1140 | { |
1141 | struct rusage32 r; | 1141 | struct rusage32 r; |
1142 | cputime_t utime, stime; | ||
1142 | 1143 | ||
1143 | if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN) | 1144 | if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN) |
1144 | return -EINVAL; | 1145 | return -EINVAL; |
@@ -1146,8 +1147,9 @@ SYSCALL_DEFINE2(osf_getrusage, int, who, struct rusage32 __user *, ru) | |||
1146 | memset(&r, 0, sizeof(r)); | 1147 | memset(&r, 0, sizeof(r)); |
1147 | switch (who) { | 1148 | switch (who) { |
1148 | case RUSAGE_SELF: | 1149 | case RUSAGE_SELF: |
1149 | jiffies_to_timeval32(current->utime, &r.ru_utime); | 1150 | task_cputime(current, &utime, &stime); |
1150 | jiffies_to_timeval32(current->stime, &r.ru_stime); | 1151 | jiffies_to_timeval32(utime, &r.ru_utime); |
1152 | jiffies_to_timeval32(stime, &r.ru_stime); | ||
1151 | r.ru_minflt = current->min_flt; | 1153 | r.ru_minflt = current->min_flt; |
1152 | r.ru_majflt = current->maj_flt; | 1154 | r.ru_majflt = current->maj_flt; |
1153 | break; | 1155 | break; |
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 67874b82a4ed..9bbe760f2352 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -36,7 +36,6 @@ config ARM | |||
36 | select HAVE_GENERIC_HARDIRQS | 36 | select HAVE_GENERIC_HARDIRQS |
37 | select HAVE_HW_BREAKPOINT if (PERF_EVENTS && (CPU_V6 || CPU_V6K || CPU_V7)) | 37 | select HAVE_HW_BREAKPOINT if (PERF_EVENTS && (CPU_V6 || CPU_V6K || CPU_V7)) |
38 | select HAVE_IDE if PCI || ISA || PCMCIA | 38 | select HAVE_IDE if PCI || ISA || PCMCIA |
39 | select HAVE_IRQ_WORK | ||
40 | select HAVE_KERNEL_GZIP | 39 | select HAVE_KERNEL_GZIP |
41 | select HAVE_KERNEL_LZMA | 40 | select HAVE_KERNEL_LZMA |
42 | select HAVE_KERNEL_LZO | 41 | select HAVE_KERNEL_LZO |
diff --git a/arch/arm/include/asm/smp_scu.h b/arch/arm/include/asm/smp_scu.h index 4eb6d005ffaa..86dff32a0737 100644 --- a/arch/arm/include/asm/smp_scu.h +++ b/arch/arm/include/asm/smp_scu.h | |||
@@ -7,8 +7,14 @@ | |||
7 | 7 | ||
8 | #ifndef __ASSEMBLER__ | 8 | #ifndef __ASSEMBLER__ |
9 | unsigned int scu_get_core_count(void __iomem *); | 9 | unsigned int scu_get_core_count(void __iomem *); |
10 | void scu_enable(void __iomem *); | ||
11 | int scu_power_mode(void __iomem *, unsigned int); | 10 | int scu_power_mode(void __iomem *, unsigned int); |
11 | |||
12 | #ifdef CONFIG_SMP | ||
13 | void scu_enable(void __iomem *scu_base); | ||
14 | #else | ||
15 | static inline void scu_enable(void __iomem *scu_base) {} | ||
16 | #endif | ||
17 | |||
12 | #endif | 18 | #endif |
13 | 19 | ||
14 | #endif | 20 | #endif |
diff --git a/arch/arm/kernel/smp_scu.c b/arch/arm/kernel/smp_scu.c index b9f015e843d8..45eac87ed66a 100644 --- a/arch/arm/kernel/smp_scu.c +++ b/arch/arm/kernel/smp_scu.c | |||
@@ -75,7 +75,7 @@ void scu_enable(void __iomem *scu_base) | |||
75 | int scu_power_mode(void __iomem *scu_base, unsigned int mode) | 75 | int scu_power_mode(void __iomem *scu_base, unsigned int mode) |
76 | { | 76 | { |
77 | unsigned int val; | 77 | unsigned int val; |
78 | int cpu = cpu_logical_map(smp_processor_id()); | 78 | int cpu = MPIDR_AFFINITY_LEVEL(cpu_logical_map(smp_processor_id()), 0); |
79 | 79 | ||
80 | if (mode > 3 || mode == 1 || cpu > 3) | 80 | if (mode > 3 || mode == 1 || cpu > 3) |
81 | return -EINVAL; | 81 | return -EINVAL; |
diff --git a/arch/arm/mach-highbank/highbank.c b/arch/arm/mach-highbank/highbank.c index 981dc1e1da51..e6c061282939 100644 --- a/arch/arm/mach-highbank/highbank.c +++ b/arch/arm/mach-highbank/highbank.c | |||
@@ -28,6 +28,7 @@ | |||
28 | 28 | ||
29 | #include <asm/arch_timer.h> | 29 | #include <asm/arch_timer.h> |
30 | #include <asm/cacheflush.h> | 30 | #include <asm/cacheflush.h> |
31 | #include <asm/cputype.h> | ||
31 | #include <asm/smp_plat.h> | 32 | #include <asm/smp_plat.h> |
32 | #include <asm/smp_twd.h> | 33 | #include <asm/smp_twd.h> |
33 | #include <asm/hardware/arm_timer.h> | 34 | #include <asm/hardware/arm_timer.h> |
@@ -59,7 +60,7 @@ static void __init highbank_scu_map_io(void) | |||
59 | 60 | ||
60 | void highbank_set_cpu_jump(int cpu, void *jump_addr) | 61 | void highbank_set_cpu_jump(int cpu, void *jump_addr) |
61 | { | 62 | { |
62 | cpu = cpu_logical_map(cpu); | 63 | cpu = MPIDR_AFFINITY_LEVEL(cpu_logical_map(cpu), 0); |
63 | writel(virt_to_phys(jump_addr), HB_JUMP_TABLE_VIRT(cpu)); | 64 | writel(virt_to_phys(jump_addr), HB_JUMP_TABLE_VIRT(cpu)); |
64 | __cpuc_flush_dcache_area(HB_JUMP_TABLE_VIRT(cpu), 16); | 65 | __cpuc_flush_dcache_area(HB_JUMP_TABLE_VIRT(cpu), 16); |
65 | outer_clean_range(HB_JUMP_TABLE_PHYS(cpu), | 66 | outer_clean_range(HB_JUMP_TABLE_PHYS(cpu), |
diff --git a/arch/arm/mach-highbank/sysregs.h b/arch/arm/mach-highbank/sysregs.h index 70af9d13fcef..5995df7f2622 100644 --- a/arch/arm/mach-highbank/sysregs.h +++ b/arch/arm/mach-highbank/sysregs.h | |||
@@ -37,7 +37,7 @@ extern void __iomem *sregs_base; | |||
37 | 37 | ||
38 | static inline void highbank_set_core_pwr(void) | 38 | static inline void highbank_set_core_pwr(void) |
39 | { | 39 | { |
40 | int cpu = cpu_logical_map(smp_processor_id()); | 40 | int cpu = MPIDR_AFFINITY_LEVEL(cpu_logical_map(smp_processor_id()), 0); |
41 | if (scu_base_addr) | 41 | if (scu_base_addr) |
42 | scu_power_mode(scu_base_addr, SCU_PM_POWEROFF); | 42 | scu_power_mode(scu_base_addr, SCU_PM_POWEROFF); |
43 | else | 43 | else |
@@ -46,7 +46,7 @@ static inline void highbank_set_core_pwr(void) | |||
46 | 46 | ||
47 | static inline void highbank_clear_core_pwr(void) | 47 | static inline void highbank_clear_core_pwr(void) |
48 | { | 48 | { |
49 | int cpu = cpu_logical_map(smp_processor_id()); | 49 | int cpu = MPIDR_AFFINITY_LEVEL(cpu_logical_map(smp_processor_id()), 0); |
50 | if (scu_base_addr) | 50 | if (scu_base_addr) |
51 | scu_power_mode(scu_base_addr, SCU_PM_NORMAL); | 51 | scu_power_mode(scu_base_addr, SCU_PM_NORMAL); |
52 | else | 52 | else |
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index f8f362aafee9..75e915b72471 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig | |||
@@ -21,7 +21,6 @@ config ARM64 | |||
21 | select HAVE_GENERIC_DMA_COHERENT | 21 | select HAVE_GENERIC_DMA_COHERENT |
22 | select HAVE_GENERIC_HARDIRQS | 22 | select HAVE_GENERIC_HARDIRQS |
23 | select HAVE_HW_BREAKPOINT if PERF_EVENTS | 23 | select HAVE_HW_BREAKPOINT if PERF_EVENTS |
24 | select HAVE_IRQ_WORK | ||
25 | select HAVE_MEMBLOCK | 24 | select HAVE_MEMBLOCK |
26 | select HAVE_PERF_EVENTS | 25 | select HAVE_PERF_EVENTS |
27 | select IRQ_DOMAIN | 26 | select IRQ_DOMAIN |
diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index b6f3ad5441c5..67e4aaad78f5 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig | |||
@@ -24,7 +24,6 @@ config BLACKFIN | |||
24 | select HAVE_FUNCTION_TRACER | 24 | select HAVE_FUNCTION_TRACER |
25 | select HAVE_FUNCTION_TRACE_MCOUNT_TEST | 25 | select HAVE_FUNCTION_TRACE_MCOUNT_TEST |
26 | select HAVE_IDE | 26 | select HAVE_IDE |
27 | select HAVE_IRQ_WORK | ||
28 | select HAVE_KERNEL_GZIP if RAMKERNEL | 27 | select HAVE_KERNEL_GZIP if RAMKERNEL |
29 | select HAVE_KERNEL_BZIP2 if RAMKERNEL | 28 | select HAVE_KERNEL_BZIP2 if RAMKERNEL |
30 | select HAVE_KERNEL_LZMA if RAMKERNEL | 29 | select HAVE_KERNEL_LZMA if RAMKERNEL |
@@ -38,7 +37,6 @@ config BLACKFIN | |||
38 | select HAVE_GENERIC_HARDIRQS | 37 | select HAVE_GENERIC_HARDIRQS |
39 | select GENERIC_ATOMIC64 | 38 | select GENERIC_ATOMIC64 |
40 | select GENERIC_IRQ_PROBE | 39 | select GENERIC_IRQ_PROBE |
41 | select IRQ_PER_CPU if SMP | ||
42 | select USE_GENERIC_SMP_HELPERS if SMP | 40 | select USE_GENERIC_SMP_HELPERS if SMP |
43 | select HAVE_NMI_WATCHDOG if NMI_WATCHDOG | 41 | select HAVE_NMI_WATCHDOG if NMI_WATCHDOG |
44 | select GENERIC_SMP_IDLE_THREAD | 42 | select GENERIC_SMP_IDLE_THREAD |
diff --git a/arch/frv/Kconfig b/arch/frv/Kconfig index 9d262645f667..17df48fc8f44 100644 --- a/arch/frv/Kconfig +++ b/arch/frv/Kconfig | |||
@@ -3,7 +3,6 @@ config FRV | |||
3 | default y | 3 | default y |
4 | select HAVE_IDE | 4 | select HAVE_IDE |
5 | select HAVE_ARCH_TRACEHOOK | 5 | select HAVE_ARCH_TRACEHOOK |
6 | select HAVE_IRQ_WORK | ||
7 | select HAVE_PERF_EVENTS | 6 | select HAVE_PERF_EVENTS |
8 | select HAVE_UID16 | 7 | select HAVE_UID16 |
9 | select HAVE_GENERIC_HARDIRQS | 8 | select HAVE_GENERIC_HARDIRQS |
diff --git a/arch/hexagon/Kconfig b/arch/hexagon/Kconfig index 0744f7d7b1fd..e4decc6b8947 100644 --- a/arch/hexagon/Kconfig +++ b/arch/hexagon/Kconfig | |||
@@ -12,9 +12,7 @@ config HEXAGON | |||
12 | # select ARCH_WANT_OPTIONAL_GPIOLIB | 12 | # select ARCH_WANT_OPTIONAL_GPIOLIB |
13 | # select ARCH_REQUIRE_GPIOLIB | 13 | # select ARCH_REQUIRE_GPIOLIB |
14 | # select HAVE_CLK | 14 | # select HAVE_CLK |
15 | # select IRQ_PER_CPU | ||
16 | # select GENERIC_PENDING_IRQ if SMP | 15 | # select GENERIC_PENDING_IRQ if SMP |
17 | select HAVE_IRQ_WORK | ||
18 | select GENERIC_ATOMIC64 | 16 | select GENERIC_ATOMIC64 |
19 | select HAVE_PERF_EVENTS | 17 | select HAVE_PERF_EVENTS |
20 | select HAVE_GENERIC_HARDIRQS | 18 | select HAVE_GENERIC_HARDIRQS |
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index 3279646120e3..00c2e88f7755 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig | |||
@@ -29,7 +29,6 @@ config IA64 | |||
29 | select ARCH_DISCARD_MEMBLOCK | 29 | select ARCH_DISCARD_MEMBLOCK |
30 | select GENERIC_IRQ_PROBE | 30 | select GENERIC_IRQ_PROBE |
31 | select GENERIC_PENDING_IRQ if SMP | 31 | select GENERIC_PENDING_IRQ if SMP |
32 | select IRQ_PER_CPU | ||
33 | select GENERIC_IRQ_SHOW | 32 | select GENERIC_IRQ_SHOW |
34 | select ARCH_WANT_OPTIONAL_GPIOLIB | 33 | select ARCH_WANT_OPTIONAL_GPIOLIB |
35 | select ARCH_HAVE_NMI_SAFE_CMPXCHG | 34 | select ARCH_HAVE_NMI_SAFE_CMPXCHG |
diff --git a/arch/ia64/include/asm/cputime.h b/arch/ia64/include/asm/cputime.h index 7fcf7f08ab06..e2d3f5baf265 100644 --- a/arch/ia64/include/asm/cputime.h +++ b/arch/ia64/include/asm/cputime.h | |||
@@ -11,99 +11,19 @@ | |||
11 | * as published by the Free Software Foundation; either version | 11 | * as published by the Free Software Foundation; either version |
12 | * 2 of the License, or (at your option) any later version. | 12 | * 2 of the License, or (at your option) any later version. |
13 | * | 13 | * |
14 | * If we have CONFIG_VIRT_CPU_ACCOUNTING, we measure cpu time in nsec. | 14 | * If we have CONFIG_VIRT_CPU_ACCOUNTING_NATIVE, we measure cpu time in nsec. |
15 | * Otherwise we measure cpu time in jiffies using the generic definitions. | 15 | * Otherwise we measure cpu time in jiffies using the generic definitions. |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #ifndef __IA64_CPUTIME_H | 18 | #ifndef __IA64_CPUTIME_H |
19 | #define __IA64_CPUTIME_H | 19 | #define __IA64_CPUTIME_H |
20 | 20 | ||
21 | #ifndef CONFIG_VIRT_CPU_ACCOUNTING | 21 | #ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE |
22 | #include <asm-generic/cputime.h> | 22 | # include <asm-generic/cputime.h> |
23 | #else | 23 | #else |
24 | 24 | # include <asm/processor.h> | |
25 | #include <linux/time.h> | 25 | # include <asm-generic/cputime_nsecs.h> |
26 | #include <linux/jiffies.h> | ||
27 | #include <asm/processor.h> | ||
28 | |||
29 | typedef u64 __nocast cputime_t; | ||
30 | typedef u64 __nocast cputime64_t; | ||
31 | |||
32 | #define cputime_one_jiffy jiffies_to_cputime(1) | ||
33 | |||
34 | /* | ||
35 | * Convert cputime <-> jiffies (HZ) | ||
36 | */ | ||
37 | #define cputime_to_jiffies(__ct) \ | ||
38 | ((__force u64)(__ct) / (NSEC_PER_SEC / HZ)) | ||
39 | #define jiffies_to_cputime(__jif) \ | ||
40 | (__force cputime_t)((__jif) * (NSEC_PER_SEC / HZ)) | ||
41 | #define cputime64_to_jiffies64(__ct) \ | ||
42 | ((__force u64)(__ct) / (NSEC_PER_SEC / HZ)) | ||
43 | #define jiffies64_to_cputime64(__jif) \ | ||
44 | (__force cputime64_t)((__jif) * (NSEC_PER_SEC / HZ)) | ||
45 | |||
46 | /* | ||
47 | * Convert cputime <-> microseconds | ||
48 | */ | ||
49 | #define cputime_to_usecs(__ct) \ | ||
50 | ((__force u64)(__ct) / NSEC_PER_USEC) | ||
51 | #define usecs_to_cputime(__usecs) \ | ||
52 | (__force cputime_t)((__usecs) * NSEC_PER_USEC) | ||
53 | #define usecs_to_cputime64(__usecs) \ | ||
54 | (__force cputime64_t)((__usecs) * NSEC_PER_USEC) | ||
55 | |||
56 | /* | ||
57 | * Convert cputime <-> seconds | ||
58 | */ | ||
59 | #define cputime_to_secs(__ct) \ | ||
60 | ((__force u64)(__ct) / NSEC_PER_SEC) | ||
61 | #define secs_to_cputime(__secs) \ | ||
62 | (__force cputime_t)((__secs) * NSEC_PER_SEC) | ||
63 | |||
64 | /* | ||
65 | * Convert cputime <-> timespec (nsec) | ||
66 | */ | ||
67 | static inline cputime_t timespec_to_cputime(const struct timespec *val) | ||
68 | { | ||
69 | u64 ret = val->tv_sec * NSEC_PER_SEC + val->tv_nsec; | ||
70 | return (__force cputime_t) ret; | ||
71 | } | ||
72 | static inline void cputime_to_timespec(const cputime_t ct, struct timespec *val) | ||
73 | { | ||
74 | val->tv_sec = (__force u64) ct / NSEC_PER_SEC; | ||
75 | val->tv_nsec = (__force u64) ct % NSEC_PER_SEC; | ||
76 | } | ||
77 | |||
78 | /* | ||
79 | * Convert cputime <-> timeval (msec) | ||
80 | */ | ||
81 | static inline cputime_t timeval_to_cputime(struct timeval *val) | ||
82 | { | ||
83 | u64 ret = val->tv_sec * NSEC_PER_SEC + val->tv_usec * NSEC_PER_USEC; | ||
84 | return (__force cputime_t) ret; | ||
85 | } | ||
86 | static inline void cputime_to_timeval(const cputime_t ct, struct timeval *val) | ||
87 | { | ||
88 | val->tv_sec = (__force u64) ct / NSEC_PER_SEC; | ||
89 | val->tv_usec = ((__force u64) ct % NSEC_PER_SEC) / NSEC_PER_USEC; | ||
90 | } | ||
91 | |||
92 | /* | ||
93 | * Convert cputime <-> clock (USER_HZ) | ||
94 | */ | ||
95 | #define cputime_to_clock_t(__ct) \ | ||
96 | ((__force u64)(__ct) / (NSEC_PER_SEC / USER_HZ)) | ||
97 | #define clock_t_to_cputime(__x) \ | ||
98 | (__force cputime_t)((__x) * (NSEC_PER_SEC / USER_HZ)) | ||
99 | |||
100 | /* | ||
101 | * Convert cputime64 to clock. | ||
102 | */ | ||
103 | #define cputime64_to_clock_t(__ct) \ | ||
104 | cputime_to_clock_t((__force cputime_t)__ct) | ||
105 | |||
106 | extern void arch_vtime_task_switch(struct task_struct *tsk); | 26 | extern void arch_vtime_task_switch(struct task_struct *tsk); |
27 | #endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */ | ||
107 | 28 | ||
108 | #endif /* CONFIG_VIRT_CPU_ACCOUNTING */ | ||
109 | #endif /* __IA64_CPUTIME_H */ | 29 | #endif /* __IA64_CPUTIME_H */ |
diff --git a/arch/ia64/include/asm/thread_info.h b/arch/ia64/include/asm/thread_info.h index ff2ae4136584..020d655ed082 100644 --- a/arch/ia64/include/asm/thread_info.h +++ b/arch/ia64/include/asm/thread_info.h | |||
@@ -31,7 +31,7 @@ struct thread_info { | |||
31 | mm_segment_t addr_limit; /* user-level address space limit */ | 31 | mm_segment_t addr_limit; /* user-level address space limit */ |
32 | int preempt_count; /* 0=premptable, <0=BUG; will also serve as bh-counter */ | 32 | int preempt_count; /* 0=premptable, <0=BUG; will also serve as bh-counter */ |
33 | struct restart_block restart_block; | 33 | struct restart_block restart_block; |
34 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 34 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE |
35 | __u64 ac_stamp; | 35 | __u64 ac_stamp; |
36 | __u64 ac_leave; | 36 | __u64 ac_leave; |
37 | __u64 ac_stime; | 37 | __u64 ac_stime; |
@@ -69,7 +69,7 @@ struct thread_info { | |||
69 | #define task_stack_page(tsk) ((void *)(tsk)) | 69 | #define task_stack_page(tsk) ((void *)(tsk)) |
70 | 70 | ||
71 | #define __HAVE_THREAD_FUNCTIONS | 71 | #define __HAVE_THREAD_FUNCTIONS |
72 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 72 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE |
73 | #define setup_thread_stack(p, org) \ | 73 | #define setup_thread_stack(p, org) \ |
74 | *task_thread_info(p) = *task_thread_info(org); \ | 74 | *task_thread_info(p) = *task_thread_info(org); \ |
75 | task_thread_info(p)->ac_stime = 0; \ | 75 | task_thread_info(p)->ac_stime = 0; \ |
diff --git a/arch/ia64/include/asm/xen/minstate.h b/arch/ia64/include/asm/xen/minstate.h index c57fa910f2c9..00cf03e0cb82 100644 --- a/arch/ia64/include/asm/xen/minstate.h +++ b/arch/ia64/include/asm/xen/minstate.h | |||
@@ -1,5 +1,5 @@ | |||
1 | 1 | ||
2 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 2 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE |
3 | /* read ar.itc in advance, and use it before leaving bank 0 */ | 3 | /* read ar.itc in advance, and use it before leaving bank 0 */ |
4 | #define XEN_ACCOUNT_GET_STAMP \ | 4 | #define XEN_ACCOUNT_GET_STAMP \ |
5 | MOV_FROM_ITC(pUStk, p6, r20, r2); | 5 | MOV_FROM_ITC(pUStk, p6, r20, r2); |
diff --git a/arch/ia64/kernel/asm-offsets.c b/arch/ia64/kernel/asm-offsets.c index a48bd9a9927b..46c9e3007315 100644 --- a/arch/ia64/kernel/asm-offsets.c +++ b/arch/ia64/kernel/asm-offsets.c | |||
@@ -41,7 +41,7 @@ void foo(void) | |||
41 | DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); | 41 | DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); |
42 | DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); | 42 | DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); |
43 | DEFINE(TI_PRE_COUNT, offsetof(struct thread_info, preempt_count)); | 43 | DEFINE(TI_PRE_COUNT, offsetof(struct thread_info, preempt_count)); |
44 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 44 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE |
45 | DEFINE(TI_AC_STAMP, offsetof(struct thread_info, ac_stamp)); | 45 | DEFINE(TI_AC_STAMP, offsetof(struct thread_info, ac_stamp)); |
46 | DEFINE(TI_AC_LEAVE, offsetof(struct thread_info, ac_leave)); | 46 | DEFINE(TI_AC_LEAVE, offsetof(struct thread_info, ac_leave)); |
47 | DEFINE(TI_AC_STIME, offsetof(struct thread_info, ac_stime)); | 47 | DEFINE(TI_AC_STIME, offsetof(struct thread_info, ac_stime)); |
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index 6bfd8429ee0f..7a53530f22c2 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S | |||
@@ -724,7 +724,7 @@ GLOBAL_ENTRY(__paravirt_leave_syscall) | |||
724 | #endif | 724 | #endif |
725 | .global __paravirt_work_processed_syscall; | 725 | .global __paravirt_work_processed_syscall; |
726 | __paravirt_work_processed_syscall: | 726 | __paravirt_work_processed_syscall: |
727 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 727 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE |
728 | adds r2=PT(LOADRS)+16,r12 | 728 | adds r2=PT(LOADRS)+16,r12 |
729 | MOV_FROM_ITC(pUStk, p9, r22, r19) // fetch time at leave | 729 | MOV_FROM_ITC(pUStk, p9, r22, r19) // fetch time at leave |
730 | adds r18=TI_FLAGS+IA64_TASK_SIZE,r13 | 730 | adds r18=TI_FLAGS+IA64_TASK_SIZE,r13 |
@@ -762,7 +762,7 @@ __paravirt_work_processed_syscall: | |||
762 | 762 | ||
763 | ld8 r29=[r2],16 // M0|1 load cr.ipsr | 763 | ld8 r29=[r2],16 // M0|1 load cr.ipsr |
764 | ld8 r28=[r3],16 // M0|1 load cr.iip | 764 | ld8 r28=[r3],16 // M0|1 load cr.iip |
765 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 765 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE |
766 | (pUStk) add r14=TI_AC_LEAVE+IA64_TASK_SIZE,r13 | 766 | (pUStk) add r14=TI_AC_LEAVE+IA64_TASK_SIZE,r13 |
767 | ;; | 767 | ;; |
768 | ld8 r30=[r2],16 // M0|1 load cr.ifs | 768 | ld8 r30=[r2],16 // M0|1 load cr.ifs |
@@ -793,7 +793,7 @@ __paravirt_work_processed_syscall: | |||
793 | ld8.fill r1=[r3],16 // M0|1 load r1 | 793 | ld8.fill r1=[r3],16 // M0|1 load r1 |
794 | (pUStk) mov r17=1 // A | 794 | (pUStk) mov r17=1 // A |
795 | ;; | 795 | ;; |
796 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 796 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE |
797 | (pUStk) st1 [r15]=r17 // M2|3 | 797 | (pUStk) st1 [r15]=r17 // M2|3 |
798 | #else | 798 | #else |
799 | (pUStk) st1 [r14]=r17 // M2|3 | 799 | (pUStk) st1 [r14]=r17 // M2|3 |
@@ -813,7 +813,7 @@ __paravirt_work_processed_syscall: | |||
813 | shr.u r18=r19,16 // I0|1 get byte size of existing "dirty" partition | 813 | shr.u r18=r19,16 // I0|1 get byte size of existing "dirty" partition |
814 | COVER // B add current frame into dirty partition & set cr.ifs | 814 | COVER // B add current frame into dirty partition & set cr.ifs |
815 | ;; | 815 | ;; |
816 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 816 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE |
817 | mov r19=ar.bsp // M2 get new backing store pointer | 817 | mov r19=ar.bsp // M2 get new backing store pointer |
818 | st8 [r14]=r22 // M save time at leave | 818 | st8 [r14]=r22 // M save time at leave |
819 | mov f10=f0 // F clear f10 | 819 | mov f10=f0 // F clear f10 |
@@ -948,7 +948,7 @@ GLOBAL_ENTRY(__paravirt_leave_kernel) | |||
948 | adds r16=PT(CR_IPSR)+16,r12 | 948 | adds r16=PT(CR_IPSR)+16,r12 |
949 | adds r17=PT(CR_IIP)+16,r12 | 949 | adds r17=PT(CR_IIP)+16,r12 |
950 | 950 | ||
951 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 951 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE |
952 | .pred.rel.mutex pUStk,pKStk | 952 | .pred.rel.mutex pUStk,pKStk |
953 | MOV_FROM_PSR(pKStk, r22, r29) // M2 read PSR now that interrupts are disabled | 953 | MOV_FROM_PSR(pKStk, r22, r29) // M2 read PSR now that interrupts are disabled |
954 | MOV_FROM_ITC(pUStk, p9, r22, r29) // M fetch time at leave | 954 | MOV_FROM_ITC(pUStk, p9, r22, r29) // M fetch time at leave |
@@ -981,7 +981,7 @@ GLOBAL_ENTRY(__paravirt_leave_kernel) | |||
981 | ;; | 981 | ;; |
982 | ld8.fill r12=[r16],16 | 982 | ld8.fill r12=[r16],16 |
983 | ld8.fill r13=[r17],16 | 983 | ld8.fill r13=[r17],16 |
984 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 984 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE |
985 | (pUStk) adds r3=TI_AC_LEAVE+IA64_TASK_SIZE,r18 | 985 | (pUStk) adds r3=TI_AC_LEAVE+IA64_TASK_SIZE,r18 |
986 | #else | 986 | #else |
987 | (pUStk) adds r18=IA64_TASK_THREAD_ON_USTACK_OFFSET,r18 | 987 | (pUStk) adds r18=IA64_TASK_THREAD_ON_USTACK_OFFSET,r18 |
@@ -989,7 +989,7 @@ GLOBAL_ENTRY(__paravirt_leave_kernel) | |||
989 | ;; | 989 | ;; |
990 | ld8 r20=[r16],16 // ar.fpsr | 990 | ld8 r20=[r16],16 // ar.fpsr |
991 | ld8.fill r15=[r17],16 | 991 | ld8.fill r15=[r17],16 |
992 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 992 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE |
993 | (pUStk) adds r18=IA64_TASK_THREAD_ON_USTACK_OFFSET,r18 // deferred | 993 | (pUStk) adds r18=IA64_TASK_THREAD_ON_USTACK_OFFSET,r18 // deferred |
994 | #endif | 994 | #endif |
995 | ;; | 995 | ;; |
@@ -997,7 +997,7 @@ GLOBAL_ENTRY(__paravirt_leave_kernel) | |||
997 | ld8.fill r2=[r17] | 997 | ld8.fill r2=[r17] |
998 | (pUStk) mov r17=1 | 998 | (pUStk) mov r17=1 |
999 | ;; | 999 | ;; |
1000 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 1000 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE |
1001 | // mmi_ : ld8 st1 shr;; mmi_ : st8 st1 shr;; | 1001 | // mmi_ : ld8 st1 shr;; mmi_ : st8 st1 shr;; |
1002 | // mib : mov add br -> mib : ld8 add br | 1002 | // mib : mov add br -> mib : ld8 add br |
1003 | // bbb_ : br nop cover;; mbb_ : mov br cover;; | 1003 | // bbb_ : br nop cover;; mbb_ : mov br cover;; |
diff --git a/arch/ia64/kernel/fsys.S b/arch/ia64/kernel/fsys.S index e662f178b990..c4cd45d97749 100644 --- a/arch/ia64/kernel/fsys.S +++ b/arch/ia64/kernel/fsys.S | |||
@@ -529,7 +529,7 @@ GLOBAL_ENTRY(paravirt_fsys_bubble_down) | |||
529 | nop.i 0 | 529 | nop.i 0 |
530 | ;; | 530 | ;; |
531 | mov ar.rsc=0 // M2 set enforced lazy mode, pl 0, LE, loadrs=0 | 531 | mov ar.rsc=0 // M2 set enforced lazy mode, pl 0, LE, loadrs=0 |
532 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 532 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE |
533 | MOV_FROM_ITC(p0, p6, r30, r23) // M get cycle for accounting | 533 | MOV_FROM_ITC(p0, p6, r30, r23) // M get cycle for accounting |
534 | #else | 534 | #else |
535 | nop.m 0 | 535 | nop.m 0 |
@@ -555,7 +555,7 @@ GLOBAL_ENTRY(paravirt_fsys_bubble_down) | |||
555 | cmp.ne pKStk,pUStk=r0,r0 // A set pKStk <- 0, pUStk <- 1 | 555 | cmp.ne pKStk,pUStk=r0,r0 // A set pKStk <- 0, pUStk <- 1 |
556 | br.call.sptk.many b7=ia64_syscall_setup // B | 556 | br.call.sptk.many b7=ia64_syscall_setup // B |
557 | ;; | 557 | ;; |
558 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 558 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE |
559 | // mov.m r30=ar.itc is called in advance | 559 | // mov.m r30=ar.itc is called in advance |
560 | add r16=TI_AC_STAMP+IA64_TASK_SIZE,r2 | 560 | add r16=TI_AC_STAMP+IA64_TASK_SIZE,r2 |
561 | add r17=TI_AC_LEAVE+IA64_TASK_SIZE,r2 | 561 | add r17=TI_AC_LEAVE+IA64_TASK_SIZE,r2 |
diff --git a/arch/ia64/kernel/head.S b/arch/ia64/kernel/head.S index 4738ff7bd66a..9be4e497f3d3 100644 --- a/arch/ia64/kernel/head.S +++ b/arch/ia64/kernel/head.S | |||
@@ -1073,7 +1073,7 @@ END(ia64_native_sched_clock) | |||
1073 | sched_clock = ia64_native_sched_clock | 1073 | sched_clock = ia64_native_sched_clock |
1074 | #endif | 1074 | #endif |
1075 | 1075 | ||
1076 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 1076 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE |
1077 | GLOBAL_ENTRY(cycle_to_cputime) | 1077 | GLOBAL_ENTRY(cycle_to_cputime) |
1078 | alloc r16=ar.pfs,1,0,0,0 | 1078 | alloc r16=ar.pfs,1,0,0,0 |
1079 | addl r8=THIS_CPU(ia64_cpu_info) + IA64_CPUINFO_NSEC_PER_CYC_OFFSET,r0 | 1079 | addl r8=THIS_CPU(ia64_cpu_info) + IA64_CPUINFO_NSEC_PER_CYC_OFFSET,r0 |
@@ -1091,7 +1091,7 @@ GLOBAL_ENTRY(cycle_to_cputime) | |||
1091 | shrp r8=r9,r8,IA64_NSEC_PER_CYC_SHIFT | 1091 | shrp r8=r9,r8,IA64_NSEC_PER_CYC_SHIFT |
1092 | br.ret.sptk.many rp | 1092 | br.ret.sptk.many rp |
1093 | END(cycle_to_cputime) | 1093 | END(cycle_to_cputime) |
1094 | #endif /* CONFIG_VIRT_CPU_ACCOUNTING */ | 1094 | #endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */ |
1095 | 1095 | ||
1096 | #ifdef CONFIG_IA64_BRL_EMU | 1096 | #ifdef CONFIG_IA64_BRL_EMU |
1097 | 1097 | ||
diff --git a/arch/ia64/kernel/ivt.S b/arch/ia64/kernel/ivt.S index fa25689fc453..689ffcaa284e 100644 --- a/arch/ia64/kernel/ivt.S +++ b/arch/ia64/kernel/ivt.S | |||
@@ -784,7 +784,7 @@ ENTRY(break_fault) | |||
784 | 784 | ||
785 | (p8) adds r28=16,r28 // A switch cr.iip to next bundle | 785 | (p8) adds r28=16,r28 // A switch cr.iip to next bundle |
786 | (p9) adds r8=1,r8 // A increment ei to next slot | 786 | (p9) adds r8=1,r8 // A increment ei to next slot |
787 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 787 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE |
788 | ;; | 788 | ;; |
789 | mov b6=r30 // I0 setup syscall handler branch reg early | 789 | mov b6=r30 // I0 setup syscall handler branch reg early |
790 | #else | 790 | #else |
@@ -801,7 +801,7 @@ ENTRY(break_fault) | |||
801 | // | 801 | // |
802 | /////////////////////////////////////////////////////////////////////// | 802 | /////////////////////////////////////////////////////////////////////// |
803 | st1 [r16]=r0 // M2|3 clear current->thread.on_ustack flag | 803 | st1 [r16]=r0 // M2|3 clear current->thread.on_ustack flag |
804 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 804 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE |
805 | MOV_FROM_ITC(p0, p14, r30, r18) // M get cycle for accounting | 805 | MOV_FROM_ITC(p0, p14, r30, r18) // M get cycle for accounting |
806 | #else | 806 | #else |
807 | mov b6=r30 // I0 setup syscall handler branch reg early | 807 | mov b6=r30 // I0 setup syscall handler branch reg early |
@@ -817,7 +817,7 @@ ENTRY(break_fault) | |||
817 | cmp.eq p14,p0=r9,r0 // A are syscalls being traced/audited? | 817 | cmp.eq p14,p0=r9,r0 // A are syscalls being traced/audited? |
818 | br.call.sptk.many b7=ia64_syscall_setup // B | 818 | br.call.sptk.many b7=ia64_syscall_setup // B |
819 | 1: | 819 | 1: |
820 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 820 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE |
821 | // mov.m r30=ar.itc is called in advance, and r13 is current | 821 | // mov.m r30=ar.itc is called in advance, and r13 is current |
822 | add r16=TI_AC_STAMP+IA64_TASK_SIZE,r13 // A | 822 | add r16=TI_AC_STAMP+IA64_TASK_SIZE,r13 // A |
823 | add r17=TI_AC_LEAVE+IA64_TASK_SIZE,r13 // A | 823 | add r17=TI_AC_LEAVE+IA64_TASK_SIZE,r13 // A |
@@ -1043,7 +1043,7 @@ END(ia64_syscall_setup) | |||
1043 | DBG_FAULT(16) | 1043 | DBG_FAULT(16) |
1044 | FAULT(16) | 1044 | FAULT(16) |
1045 | 1045 | ||
1046 | #if defined(CONFIG_VIRT_CPU_ACCOUNTING) && defined(__IA64_ASM_PARAVIRTUALIZED_NATIVE) | 1046 | #if defined(CONFIG_VIRT_CPU_ACCOUNTING_NATIVE) && defined(__IA64_ASM_PARAVIRTUALIZED_NATIVE) |
1047 | /* | 1047 | /* |
1048 | * There is no particular reason for this code to be here, other than | 1048 | * There is no particular reason for this code to be here, other than |
1049 | * that there happens to be space here that would go unused otherwise. | 1049 | * that there happens to be space here that would go unused otherwise. |
diff --git a/arch/ia64/kernel/minstate.h b/arch/ia64/kernel/minstate.h index d56753a11636..cc82a7d744c9 100644 --- a/arch/ia64/kernel/minstate.h +++ b/arch/ia64/kernel/minstate.h | |||
@@ -4,7 +4,7 @@ | |||
4 | #include "entry.h" | 4 | #include "entry.h" |
5 | #include "paravirt_inst.h" | 5 | #include "paravirt_inst.h" |
6 | 6 | ||
7 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 7 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE |
8 | /* read ar.itc in advance, and use it before leaving bank 0 */ | 8 | /* read ar.itc in advance, and use it before leaving bank 0 */ |
9 | #define ACCOUNT_GET_STAMP \ | 9 | #define ACCOUNT_GET_STAMP \ |
10 | (pUStk) mov.m r20=ar.itc; | 10 | (pUStk) mov.m r20=ar.itc; |
diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c index 88a794536bc0..fbaac1afb844 100644 --- a/arch/ia64/kernel/time.c +++ b/arch/ia64/kernel/time.c | |||
@@ -77,7 +77,7 @@ static struct clocksource clocksource_itc = { | |||
77 | }; | 77 | }; |
78 | static struct clocksource *itc_clocksource; | 78 | static struct clocksource *itc_clocksource; |
79 | 79 | ||
80 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 80 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE |
81 | 81 | ||
82 | #include <linux/kernel_stat.h> | 82 | #include <linux/kernel_stat.h> |
83 | 83 | ||
@@ -136,13 +136,14 @@ void vtime_account_system(struct task_struct *tsk) | |||
136 | 136 | ||
137 | account_system_time(tsk, 0, delta, delta); | 137 | account_system_time(tsk, 0, delta, delta); |
138 | } | 138 | } |
139 | EXPORT_SYMBOL_GPL(vtime_account_system); | ||
139 | 140 | ||
140 | void vtime_account_idle(struct task_struct *tsk) | 141 | void vtime_account_idle(struct task_struct *tsk) |
141 | { | 142 | { |
142 | account_idle_time(vtime_delta(tsk)); | 143 | account_idle_time(vtime_delta(tsk)); |
143 | } | 144 | } |
144 | 145 | ||
145 | #endif /* CONFIG_VIRT_CPU_ACCOUNTING */ | 146 | #endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */ |
146 | 147 | ||
147 | static irqreturn_t | 148 | static irqreturn_t |
148 | timer_interrupt (int irq, void *dev_id) | 149 | timer_interrupt (int irq, void *dev_id) |
diff --git a/arch/m68k/include/asm/processor.h b/arch/m68k/include/asm/processor.h index ae700f49e51d..b0768a657920 100644 --- a/arch/m68k/include/asm/processor.h +++ b/arch/m68k/include/asm/processor.h | |||
@@ -130,7 +130,6 @@ extern int handle_kernel_fault(struct pt_regs *regs); | |||
130 | #define start_thread(_regs, _pc, _usp) \ | 130 | #define start_thread(_regs, _pc, _usp) \ |
131 | do { \ | 131 | do { \ |
132 | (_regs)->pc = (_pc); \ | 132 | (_regs)->pc = (_pc); \ |
133 | ((struct switch_stack *)(_regs))[-1].a6 = 0; \ | ||
134 | setframeformat(_regs); \ | 133 | setframeformat(_regs); \ |
135 | if (current->mm) \ | 134 | if (current->mm) \ |
136 | (_regs)->d5 = current->mm->start_data; \ | 135 | (_regs)->d5 = current->mm->start_data; \ |
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 2ac626ab9d43..9becc44d9d7a 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig | |||
@@ -4,7 +4,6 @@ config MIPS | |||
4 | select HAVE_GENERIC_DMA_COHERENT | 4 | select HAVE_GENERIC_DMA_COHERENT |
5 | select HAVE_IDE | 5 | select HAVE_IDE |
6 | select HAVE_OPROFILE | 6 | select HAVE_OPROFILE |
7 | select HAVE_IRQ_WORK | ||
8 | select HAVE_PERF_EVENTS | 7 | select HAVE_PERF_EVENTS |
9 | select PERF_USE_VMALLOC | 8 | select PERF_USE_VMALLOC |
10 | select HAVE_ARCH_KGDB | 9 | select HAVE_ARCH_KGDB |
@@ -2161,7 +2160,6 @@ source "mm/Kconfig" | |||
2161 | config SMP | 2160 | config SMP |
2162 | bool "Multi-Processing support" | 2161 | bool "Multi-Processing support" |
2163 | depends on SYS_SUPPORTS_SMP | 2162 | depends on SYS_SUPPORTS_SMP |
2164 | select IRQ_PER_CPU | ||
2165 | select USE_GENERIC_SMP_HELPERS | 2163 | select USE_GENERIC_SMP_HELPERS |
2166 | help | 2164 | help |
2167 | This enables support for systems with more than one CPU. If you have | 2165 | This enables support for systems with more than one CPU. If you have |
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index b77feffbadea..a32e34ecda9e 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig | |||
@@ -9,14 +9,12 @@ config PARISC | |||
9 | select RTC_DRV_GENERIC | 9 | select RTC_DRV_GENERIC |
10 | select INIT_ALL_POSSIBLE | 10 | select INIT_ALL_POSSIBLE |
11 | select BUG | 11 | select BUG |
12 | select HAVE_IRQ_WORK | ||
13 | select HAVE_PERF_EVENTS | 12 | select HAVE_PERF_EVENTS |
14 | select GENERIC_ATOMIC64 if !64BIT | 13 | select GENERIC_ATOMIC64 if !64BIT |
15 | select HAVE_GENERIC_HARDIRQS | 14 | select HAVE_GENERIC_HARDIRQS |
16 | select BROKEN_RODATA | 15 | select BROKEN_RODATA |
17 | select GENERIC_IRQ_PROBE | 16 | select GENERIC_IRQ_PROBE |
18 | select GENERIC_PCI_IOMAP | 17 | select GENERIC_PCI_IOMAP |
19 | select IRQ_PER_CPU | ||
20 | select ARCH_HAVE_NMI_SAFE_CMPXCHG | 18 | select ARCH_HAVE_NMI_SAFE_CMPXCHG |
21 | select GENERIC_SMP_IDLE_THREAD | 19 | select GENERIC_SMP_IDLE_THREAD |
22 | select GENERIC_STRNCPY_FROM_USER | 20 | select GENERIC_STRNCPY_FROM_USER |
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 17903f1f356b..561ccca7b1a7 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig | |||
@@ -118,14 +118,12 @@ config PPC | |||
118 | select HAVE_SYSCALL_WRAPPERS if PPC64 | 118 | select HAVE_SYSCALL_WRAPPERS if PPC64 |
119 | select GENERIC_ATOMIC64 if PPC32 | 119 | select GENERIC_ATOMIC64 if PPC32 |
120 | select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE | 120 | select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE |
121 | select HAVE_IRQ_WORK | ||
122 | select HAVE_PERF_EVENTS | 121 | select HAVE_PERF_EVENTS |
123 | select HAVE_REGS_AND_STACK_ACCESS_API | 122 | select HAVE_REGS_AND_STACK_ACCESS_API |
124 | select HAVE_HW_BREAKPOINT if PERF_EVENTS && PPC_BOOK3S_64 | 123 | select HAVE_HW_BREAKPOINT if PERF_EVENTS && PPC_BOOK3S_64 |
125 | select HAVE_GENERIC_HARDIRQS | 124 | select HAVE_GENERIC_HARDIRQS |
126 | select ARCH_WANT_IPC_PARSE_VERSION | 125 | select ARCH_WANT_IPC_PARSE_VERSION |
127 | select SPARSE_IRQ | 126 | select SPARSE_IRQ |
128 | select IRQ_PER_CPU | ||
129 | select IRQ_DOMAIN | 127 | select IRQ_DOMAIN |
130 | select GENERIC_IRQ_SHOW | 128 | select GENERIC_IRQ_SHOW |
131 | select GENERIC_IRQ_SHOW_LEVEL | 129 | select GENERIC_IRQ_SHOW_LEVEL |
diff --git a/arch/powerpc/configs/chroma_defconfig b/arch/powerpc/configs/chroma_defconfig index 29bb11ec6c64..4f35fc462385 100644 --- a/arch/powerpc/configs/chroma_defconfig +++ b/arch/powerpc/configs/chroma_defconfig | |||
@@ -1,6 +1,6 @@ | |||
1 | CONFIG_PPC64=y | 1 | CONFIG_PPC64=y |
2 | CONFIG_PPC_BOOK3E_64=y | 2 | CONFIG_PPC_BOOK3E_64=y |
3 | # CONFIG_VIRT_CPU_ACCOUNTING is not set | 3 | # CONFIG_VIRT_CPU_ACCOUNTING_NATIVE is not set |
4 | CONFIG_SMP=y | 4 | CONFIG_SMP=y |
5 | CONFIG_NR_CPUS=256 | 5 | CONFIG_NR_CPUS=256 |
6 | CONFIG_EXPERIMENTAL=y | 6 | CONFIG_EXPERIMENTAL=y |
diff --git a/arch/powerpc/configs/corenet64_smp_defconfig b/arch/powerpc/configs/corenet64_smp_defconfig index 88fa5c46f66f..f7df8362911f 100644 --- a/arch/powerpc/configs/corenet64_smp_defconfig +++ b/arch/powerpc/configs/corenet64_smp_defconfig | |||
@@ -1,6 +1,6 @@ | |||
1 | CONFIG_PPC64=y | 1 | CONFIG_PPC64=y |
2 | CONFIG_PPC_BOOK3E_64=y | 2 | CONFIG_PPC_BOOK3E_64=y |
3 | # CONFIG_VIRT_CPU_ACCOUNTING is not set | 3 | # CONFIG_VIRT_CPU_ACCOUNTING_NATIVE is not set |
4 | CONFIG_SMP=y | 4 | CONFIG_SMP=y |
5 | CONFIG_NR_CPUS=2 | 5 | CONFIG_NR_CPUS=2 |
6 | CONFIG_EXPERIMENTAL=y | 6 | CONFIG_EXPERIMENTAL=y |
diff --git a/arch/powerpc/configs/pasemi_defconfig b/arch/powerpc/configs/pasemi_defconfig index 840a2c2d0430..bcedeea0df89 100644 --- a/arch/powerpc/configs/pasemi_defconfig +++ b/arch/powerpc/configs/pasemi_defconfig | |||
@@ -1,6 +1,6 @@ | |||
1 | CONFIG_PPC64=y | 1 | CONFIG_PPC64=y |
2 | CONFIG_ALTIVEC=y | 2 | CONFIG_ALTIVEC=y |
3 | # CONFIG_VIRT_CPU_ACCOUNTING is not set | 3 | # CONFIG_VIRT_CPU_ACCOUNTING_NATIVE is not set |
4 | CONFIG_SMP=y | 4 | CONFIG_SMP=y |
5 | CONFIG_NR_CPUS=2 | 5 | CONFIG_NR_CPUS=2 |
6 | CONFIG_EXPERIMENTAL=y | 6 | CONFIG_EXPERIMENTAL=y |
diff --git a/arch/powerpc/include/asm/cputime.h b/arch/powerpc/include/asm/cputime.h index 483733bd06d4..607559ab271f 100644 --- a/arch/powerpc/include/asm/cputime.h +++ b/arch/powerpc/include/asm/cputime.h | |||
@@ -8,7 +8,7 @@ | |||
8 | * as published by the Free Software Foundation; either version | 8 | * as published by the Free Software Foundation; either version |
9 | * 2 of the License, or (at your option) any later version. | 9 | * 2 of the License, or (at your option) any later version. |
10 | * | 10 | * |
11 | * If we have CONFIG_VIRT_CPU_ACCOUNTING, we measure cpu time in | 11 | * If we have CONFIG_VIRT_CPU_ACCOUNTING_NATIVE, we measure cpu time in |
12 | * the same units as the timebase. Otherwise we measure cpu time | 12 | * the same units as the timebase. Otherwise we measure cpu time |
13 | * in jiffies using the generic definitions. | 13 | * in jiffies using the generic definitions. |
14 | */ | 14 | */ |
@@ -16,7 +16,7 @@ | |||
16 | #ifndef __POWERPC_CPUTIME_H | 16 | #ifndef __POWERPC_CPUTIME_H |
17 | #define __POWERPC_CPUTIME_H | 17 | #define __POWERPC_CPUTIME_H |
18 | 18 | ||
19 | #ifndef CONFIG_VIRT_CPU_ACCOUNTING | 19 | #ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE |
20 | #include <asm-generic/cputime.h> | 20 | #include <asm-generic/cputime.h> |
21 | #ifdef __KERNEL__ | 21 | #ifdef __KERNEL__ |
22 | static inline void setup_cputime_one_jiffy(void) { } | 22 | static inline void setup_cputime_one_jiffy(void) { } |
@@ -231,5 +231,5 @@ static inline cputime_t clock_t_to_cputime(const unsigned long clk) | |||
231 | static inline void arch_vtime_task_switch(struct task_struct *tsk) { } | 231 | static inline void arch_vtime_task_switch(struct task_struct *tsk) { } |
232 | 232 | ||
233 | #endif /* __KERNEL__ */ | 233 | #endif /* __KERNEL__ */ |
234 | #endif /* CONFIG_VIRT_CPU_ACCOUNTING */ | 234 | #endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */ |
235 | #endif /* __POWERPC_CPUTIME_H */ | 235 | #endif /* __POWERPC_CPUTIME_H */ |
diff --git a/arch/powerpc/include/asm/lppaca.h b/arch/powerpc/include/asm/lppaca.h index 531fe0c3108f..b1e7f2af1016 100644 --- a/arch/powerpc/include/asm/lppaca.h +++ b/arch/powerpc/include/asm/lppaca.h | |||
@@ -145,7 +145,7 @@ struct dtl_entry { | |||
145 | extern struct kmem_cache *dtl_cache; | 145 | extern struct kmem_cache *dtl_cache; |
146 | 146 | ||
147 | /* | 147 | /* |
148 | * When CONFIG_VIRT_CPU_ACCOUNTING = y, the cpu accounting code controls | 148 | * When CONFIG_VIRT_CPU_ACCOUNTING_NATIVE = y, the cpu accounting code controls |
149 | * reading from the dispatch trace log. If other code wants to consume | 149 | * reading from the dispatch trace log. If other code wants to consume |
150 | * DTL entries, it can set this pointer to a function that will get | 150 | * DTL entries, it can set this pointer to a function that will get |
151 | * called once for each DTL entry that gets processed. | 151 | * called once for each DTL entry that gets processed. |
diff --git a/arch/powerpc/include/asm/perf_event_server.h b/arch/powerpc/include/asm/perf_event_server.h index 9710be3a2d17..136bba62efa4 100644 --- a/arch/powerpc/include/asm/perf_event_server.h +++ b/arch/powerpc/include/asm/perf_event_server.h | |||
@@ -11,6 +11,7 @@ | |||
11 | 11 | ||
12 | #include <linux/types.h> | 12 | #include <linux/types.h> |
13 | #include <asm/hw_irq.h> | 13 | #include <asm/hw_irq.h> |
14 | #include <linux/device.h> | ||
14 | 15 | ||
15 | #define MAX_HWEVENTS 8 | 16 | #define MAX_HWEVENTS 8 |
16 | #define MAX_EVENT_ALTERNATIVES 8 | 17 | #define MAX_EVENT_ALTERNATIVES 8 |
@@ -35,6 +36,7 @@ struct power_pmu { | |||
35 | void (*disable_pmc)(unsigned int pmc, unsigned long mmcr[]); | 36 | void (*disable_pmc)(unsigned int pmc, unsigned long mmcr[]); |
36 | int (*limited_pmc_event)(u64 event_id); | 37 | int (*limited_pmc_event)(u64 event_id); |
37 | u32 flags; | 38 | u32 flags; |
39 | const struct attribute_group **attr_groups; | ||
38 | int n_generic; | 40 | int n_generic; |
39 | int *generic_events; | 41 | int *generic_events; |
40 | int (*cache_events)[PERF_COUNT_HW_CACHE_MAX] | 42 | int (*cache_events)[PERF_COUNT_HW_CACHE_MAX] |
@@ -109,3 +111,27 @@ extern unsigned long perf_instruction_pointer(struct pt_regs *regs); | |||
109 | * If an event_id is not subject to the constraint expressed by a particular | 111 | * If an event_id is not subject to the constraint expressed by a particular |
110 | * field, then it will have 0 in both the mask and value for that field. | 112 | * field, then it will have 0 in both the mask and value for that field. |
111 | */ | 113 | */ |
114 | |||
115 | extern ssize_t power_events_sysfs_show(struct device *dev, | ||
116 | struct device_attribute *attr, char *page); | ||
117 | |||
118 | /* | ||
119 | * EVENT_VAR() is same as PMU_EVENT_VAR with a suffix. | ||
120 | * | ||
121 | * Having a suffix allows us to have aliases in sysfs - eg: the generic | ||
122 | * event 'cpu-cycles' can have two entries in sysfs: 'cpu-cycles' and | ||
123 | * 'PM_CYC' where the latter is the name by which the event is known in | ||
124 | * POWER CPU specification. | ||
125 | */ | ||
126 | #define EVENT_VAR(_id, _suffix) event_attr_##_id##_suffix | ||
127 | #define EVENT_PTR(_id, _suffix) &EVENT_VAR(_id, _suffix).attr.attr | ||
128 | |||
129 | #define EVENT_ATTR(_name, _id, _suffix) \ | ||
130 | PMU_EVENT_ATTR(_name, EVENT_VAR(_id, _suffix), PME_PM_##_id, \ | ||
131 | power_events_sysfs_show) | ||
132 | |||
133 | #define GENERIC_EVENT_ATTR(_name, _id) EVENT_ATTR(_name, _id, _g) | ||
134 | #define GENERIC_EVENT_PTR(_id) EVENT_PTR(_id, _g) | ||
135 | |||
136 | #define POWER_EVENT_ATTR(_name, _id) EVENT_ATTR(PM_##_name, _id, _p) | ||
137 | #define POWER_EVENT_PTR(_id) EVENT_PTR(_id, _p) | ||
diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h index ea2a86e8ff95..2d0e1f5d8339 100644 --- a/arch/powerpc/include/asm/ppc_asm.h +++ b/arch/powerpc/include/asm/ppc_asm.h | |||
@@ -24,7 +24,7 @@ | |||
24 | * user_time and system_time fields in the paca. | 24 | * user_time and system_time fields in the paca. |
25 | */ | 25 | */ |
26 | 26 | ||
27 | #ifndef CONFIG_VIRT_CPU_ACCOUNTING | 27 | #ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE |
28 | #define ACCOUNT_CPU_USER_ENTRY(ra, rb) | 28 | #define ACCOUNT_CPU_USER_ENTRY(ra, rb) |
29 | #define ACCOUNT_CPU_USER_EXIT(ra, rb) | 29 | #define ACCOUNT_CPU_USER_EXIT(ra, rb) |
30 | #define ACCOUNT_STOLEN_TIME | 30 | #define ACCOUNT_STOLEN_TIME |
@@ -70,7 +70,7 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR) | |||
70 | 70 | ||
71 | #endif /* CONFIG_PPC_SPLPAR */ | 71 | #endif /* CONFIG_PPC_SPLPAR */ |
72 | 72 | ||
73 | #endif /* CONFIG_VIRT_CPU_ACCOUNTING */ | 73 | #endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */ |
74 | 74 | ||
75 | /* | 75 | /* |
76 | * Macros for storing registers into and loading registers from | 76 | * Macros for storing registers into and loading registers from |
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 3d990d3bd8ba..ac057013f9fd 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S | |||
@@ -94,7 +94,7 @@ system_call_common: | |||
94 | addi r9,r1,STACK_FRAME_OVERHEAD | 94 | addi r9,r1,STACK_FRAME_OVERHEAD |
95 | ld r11,exception_marker@toc(r2) | 95 | ld r11,exception_marker@toc(r2) |
96 | std r11,-16(r9) /* "regshere" marker */ | 96 | std r11,-16(r9) /* "regshere" marker */ |
97 | #if defined(CONFIG_VIRT_CPU_ACCOUNTING) && defined(CONFIG_PPC_SPLPAR) | 97 | #if defined(CONFIG_VIRT_CPU_ACCOUNTING_NATIVE) && defined(CONFIG_PPC_SPLPAR) |
98 | BEGIN_FW_FTR_SECTION | 98 | BEGIN_FW_FTR_SECTION |
99 | beq 33f | 99 | beq 33f |
100 | /* if from user, see if there are any DTL entries to process */ | 100 | /* if from user, see if there are any DTL entries to process */ |
@@ -110,7 +110,7 @@ BEGIN_FW_FTR_SECTION | |||
110 | addi r9,r1,STACK_FRAME_OVERHEAD | 110 | addi r9,r1,STACK_FRAME_OVERHEAD |
111 | 33: | 111 | 33: |
112 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR) | 112 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR) |
113 | #endif /* CONFIG_VIRT_CPU_ACCOUNTING && CONFIG_PPC_SPLPAR */ | 113 | #endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE && CONFIG_PPC_SPLPAR */ |
114 | 114 | ||
115 | /* | 115 | /* |
116 | * A syscall should always be called with interrupts enabled | 116 | * A syscall should always be called with interrupts enabled |
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 127361e093f4..f77fa22754bc 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c | |||
@@ -143,7 +143,7 @@ EXPORT_SYMBOL_GPL(ppc_proc_freq); | |||
143 | unsigned long ppc_tb_freq; | 143 | unsigned long ppc_tb_freq; |
144 | EXPORT_SYMBOL_GPL(ppc_tb_freq); | 144 | EXPORT_SYMBOL_GPL(ppc_tb_freq); |
145 | 145 | ||
146 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 146 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE |
147 | /* | 147 | /* |
148 | * Factors for converting from cputime_t (timebase ticks) to | 148 | * Factors for converting from cputime_t (timebase ticks) to |
149 | * jiffies, microseconds, seconds, and clock_t (1/USER_HZ seconds). | 149 | * jiffies, microseconds, seconds, and clock_t (1/USER_HZ seconds). |
@@ -347,6 +347,7 @@ void vtime_account_system(struct task_struct *tsk) | |||
347 | if (stolen) | 347 | if (stolen) |
348 | account_steal_time(stolen); | 348 | account_steal_time(stolen); |
349 | } | 349 | } |
350 | EXPORT_SYMBOL_GPL(vtime_account_system); | ||
350 | 351 | ||
351 | void vtime_account_idle(struct task_struct *tsk) | 352 | void vtime_account_idle(struct task_struct *tsk) |
352 | { | 353 | { |
@@ -377,7 +378,7 @@ void vtime_account_user(struct task_struct *tsk) | |||
377 | account_user_time(tsk, utime, utimescaled); | 378 | account_user_time(tsk, utime, utimescaled); |
378 | } | 379 | } |
379 | 380 | ||
380 | #else /* ! CONFIG_VIRT_CPU_ACCOUNTING */ | 381 | #else /* ! CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */ |
381 | #define calc_cputime_factors() | 382 | #define calc_cputime_factors() |
382 | #endif | 383 | #endif |
383 | 384 | ||
@@ -668,7 +669,7 @@ int update_persistent_clock(struct timespec now) | |||
668 | struct rtc_time tm; | 669 | struct rtc_time tm; |
669 | 670 | ||
670 | if (!ppc_md.set_rtc_time) | 671 | if (!ppc_md.set_rtc_time) |
671 | return 0; | 672 | return -ENODEV; |
672 | 673 | ||
673 | to_tm(now.tv_sec + 1 + timezone_offset, &tm); | 674 | to_tm(now.tv_sec + 1 + timezone_offset, &tm); |
674 | tm.tm_year -= 1900; | 675 | tm.tm_year -= 1900; |
diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c index aa2465e21f1a..fa476d50791f 100644 --- a/arch/powerpc/perf/core-book3s.c +++ b/arch/powerpc/perf/core-book3s.c | |||
@@ -1305,6 +1305,16 @@ static int power_pmu_event_idx(struct perf_event *event) | |||
1305 | return event->hw.idx; | 1305 | return event->hw.idx; |
1306 | } | 1306 | } |
1307 | 1307 | ||
1308 | ssize_t power_events_sysfs_show(struct device *dev, | ||
1309 | struct device_attribute *attr, char *page) | ||
1310 | { | ||
1311 | struct perf_pmu_events_attr *pmu_attr; | ||
1312 | |||
1313 | pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr); | ||
1314 | |||
1315 | return sprintf(page, "event=0x%02llx\n", pmu_attr->id); | ||
1316 | } | ||
1317 | |||
1308 | struct pmu power_pmu = { | 1318 | struct pmu power_pmu = { |
1309 | .pmu_enable = power_pmu_enable, | 1319 | .pmu_enable = power_pmu_enable, |
1310 | .pmu_disable = power_pmu_disable, | 1320 | .pmu_disable = power_pmu_disable, |
@@ -1537,6 +1547,8 @@ int __cpuinit register_power_pmu(struct power_pmu *pmu) | |||
1537 | pr_info("%s performance monitor hardware support registered\n", | 1547 | pr_info("%s performance monitor hardware support registered\n", |
1538 | pmu->name); | 1548 | pmu->name); |
1539 | 1549 | ||
1550 | power_pmu.attr_groups = ppmu->attr_groups; | ||
1551 | |||
1540 | #ifdef MSR_HV | 1552 | #ifdef MSR_HV |
1541 | /* | 1553 | /* |
1542 | * Use FCHV to ignore kernel events if MSR.HV is set. | 1554 | * Use FCHV to ignore kernel events if MSR.HV is set. |
diff --git a/arch/powerpc/perf/power7-pmu.c b/arch/powerpc/perf/power7-pmu.c index 2ee01e38d5e2..b554879bd31e 100644 --- a/arch/powerpc/perf/power7-pmu.c +++ b/arch/powerpc/perf/power7-pmu.c | |||
@@ -51,6 +51,18 @@ | |||
51 | #define MMCR1_PMCSEL_MSK 0xff | 51 | #define MMCR1_PMCSEL_MSK 0xff |
52 | 52 | ||
53 | /* | 53 | /* |
54 | * Power7 event codes. | ||
55 | */ | ||
56 | #define PME_PM_CYC 0x1e | ||
57 | #define PME_PM_GCT_NOSLOT_CYC 0x100f8 | ||
58 | #define PME_PM_CMPLU_STALL 0x4000a | ||
59 | #define PME_PM_INST_CMPL 0x2 | ||
60 | #define PME_PM_LD_REF_L1 0xc880 | ||
61 | #define PME_PM_LD_MISS_L1 0x400f0 | ||
62 | #define PME_PM_BRU_FIN 0x10068 | ||
63 | #define PME_PM_BRU_MPRED 0x400f6 | ||
64 | |||
65 | /* | ||
54 | * Layout of constraint bits: | 66 | * Layout of constraint bits: |
55 | * 6666555555555544444444443333333333222222222211111111110000000000 | 67 | * 6666555555555544444444443333333333222222222211111111110000000000 |
56 | * 3210987654321098765432109876543210987654321098765432109876543210 | 68 | * 3210987654321098765432109876543210987654321098765432109876543210 |
@@ -307,14 +319,14 @@ static void power7_disable_pmc(unsigned int pmc, unsigned long mmcr[]) | |||
307 | } | 319 | } |
308 | 320 | ||
309 | static int power7_generic_events[] = { | 321 | static int power7_generic_events[] = { |
310 | [PERF_COUNT_HW_CPU_CYCLES] = 0x1e, | 322 | [PERF_COUNT_HW_CPU_CYCLES] = PME_PM_CYC, |
311 | [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 0x100f8, /* GCT_NOSLOT_CYC */ | 323 | [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = PME_PM_GCT_NOSLOT_CYC, |
312 | [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x4000a, /* CMPLU_STALL */ | 324 | [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = PME_PM_CMPLU_STALL, |
313 | [PERF_COUNT_HW_INSTRUCTIONS] = 2, | 325 | [PERF_COUNT_HW_INSTRUCTIONS] = PME_PM_INST_CMPL, |
314 | [PERF_COUNT_HW_CACHE_REFERENCES] = 0xc880, /* LD_REF_L1_LSU*/ | 326 | [PERF_COUNT_HW_CACHE_REFERENCES] = PME_PM_LD_REF_L1, |
315 | [PERF_COUNT_HW_CACHE_MISSES] = 0x400f0, /* LD_MISS_L1 */ | 327 | [PERF_COUNT_HW_CACHE_MISSES] = PME_PM_LD_MISS_L1, |
316 | [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x10068, /* BRU_FIN */ | 328 | [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = PME_PM_BRU_FIN, |
317 | [PERF_COUNT_HW_BRANCH_MISSES] = 0x400f6, /* BR_MPRED */ | 329 | [PERF_COUNT_HW_BRANCH_MISSES] = PME_PM_BRU_MPRED, |
318 | }; | 330 | }; |
319 | 331 | ||
320 | #define C(x) PERF_COUNT_HW_CACHE_##x | 332 | #define C(x) PERF_COUNT_HW_CACHE_##x |
@@ -362,6 +374,57 @@ static int power7_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = { | |||
362 | }, | 374 | }, |
363 | }; | 375 | }; |
364 | 376 | ||
377 | |||
378 | GENERIC_EVENT_ATTR(cpu-cycles, CYC); | ||
379 | GENERIC_EVENT_ATTR(stalled-cycles-frontend, GCT_NOSLOT_CYC); | ||
380 | GENERIC_EVENT_ATTR(stalled-cycles-backend, CMPLU_STALL); | ||
381 | GENERIC_EVENT_ATTR(instructions, INST_CMPL); | ||
382 | GENERIC_EVENT_ATTR(cache-references, LD_REF_L1); | ||
383 | GENERIC_EVENT_ATTR(cache-misses, LD_MISS_L1); | ||
384 | GENERIC_EVENT_ATTR(branch-instructions, BRU_FIN); | ||
385 | GENERIC_EVENT_ATTR(branch-misses, BRU_MPRED); | ||
386 | |||
387 | POWER_EVENT_ATTR(CYC, CYC); | ||
388 | POWER_EVENT_ATTR(GCT_NOSLOT_CYC, GCT_NOSLOT_CYC); | ||
389 | POWER_EVENT_ATTR(CMPLU_STALL, CMPLU_STALL); | ||
390 | POWER_EVENT_ATTR(INST_CMPL, INST_CMPL); | ||
391 | POWER_EVENT_ATTR(LD_REF_L1, LD_REF_L1); | ||
392 | POWER_EVENT_ATTR(LD_MISS_L1, LD_MISS_L1); | ||
393 | POWER_EVENT_ATTR(BRU_FIN, BRU_FIN) | ||
394 | POWER_EVENT_ATTR(BRU_MPRED, BRU_MPRED); | ||
395 | |||
396 | static struct attribute *power7_events_attr[] = { | ||
397 | GENERIC_EVENT_PTR(CYC), | ||
398 | GENERIC_EVENT_PTR(GCT_NOSLOT_CYC), | ||
399 | GENERIC_EVENT_PTR(CMPLU_STALL), | ||
400 | GENERIC_EVENT_PTR(INST_CMPL), | ||
401 | GENERIC_EVENT_PTR(LD_REF_L1), | ||
402 | GENERIC_EVENT_PTR(LD_MISS_L1), | ||
403 | GENERIC_EVENT_PTR(BRU_FIN), | ||
404 | GENERIC_EVENT_PTR(BRU_MPRED), | ||
405 | |||
406 | POWER_EVENT_PTR(CYC), | ||
407 | POWER_EVENT_PTR(GCT_NOSLOT_CYC), | ||
408 | POWER_EVENT_PTR(CMPLU_STALL), | ||
409 | POWER_EVENT_PTR(INST_CMPL), | ||
410 | POWER_EVENT_PTR(LD_REF_L1), | ||
411 | POWER_EVENT_PTR(LD_MISS_L1), | ||
412 | POWER_EVENT_PTR(BRU_FIN), | ||
413 | POWER_EVENT_PTR(BRU_MPRED), | ||
414 | NULL | ||
415 | }; | ||
416 | |||
417 | |||
418 | static struct attribute_group power7_pmu_events_group = { | ||
419 | .name = "events", | ||
420 | .attrs = power7_events_attr, | ||
421 | }; | ||
422 | |||
423 | static const struct attribute_group *power7_pmu_attr_groups[] = { | ||
424 | &power7_pmu_events_group, | ||
425 | NULL, | ||
426 | }; | ||
427 | |||
365 | static struct power_pmu power7_pmu = { | 428 | static struct power_pmu power7_pmu = { |
366 | .name = "POWER7", | 429 | .name = "POWER7", |
367 | .n_counter = 6, | 430 | .n_counter = 6, |
@@ -373,6 +436,7 @@ static struct power_pmu power7_pmu = { | |||
373 | .get_alternatives = power7_get_alternatives, | 436 | .get_alternatives = power7_get_alternatives, |
374 | .disable_pmc = power7_disable_pmc, | 437 | .disable_pmc = power7_disable_pmc, |
375 | .flags = PPMU_ALT_SIPR, | 438 | .flags = PPMU_ALT_SIPR, |
439 | .attr_groups = power7_pmu_attr_groups, | ||
376 | .n_generic = ARRAY_SIZE(power7_generic_events), | 440 | .n_generic = ARRAY_SIZE(power7_generic_events), |
377 | .generic_events = power7_generic_events, | 441 | .generic_events = power7_generic_events, |
378 | .cache_events = &power7_cache_events, | 442 | .cache_events = &power7_cache_events, |
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index 25db92a8e1cf..49318385d4fa 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c | |||
@@ -24,6 +24,7 @@ | |||
24 | 24 | ||
25 | #include <linux/errno.h> | 25 | #include <linux/errno.h> |
26 | #include <linux/sched.h> | 26 | #include <linux/sched.h> |
27 | #include <linux/sched/rt.h> | ||
27 | #include <linux/kernel.h> | 28 | #include <linux/kernel.h> |
28 | #include <linux/mm.h> | 29 | #include <linux/mm.h> |
29 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
diff --git a/arch/powerpc/platforms/pseries/dtl.c b/arch/powerpc/platforms/pseries/dtl.c index a7648543c59e..0cc0ac07a55d 100644 --- a/arch/powerpc/platforms/pseries/dtl.c +++ b/arch/powerpc/platforms/pseries/dtl.c | |||
@@ -57,7 +57,7 @@ static u8 dtl_event_mask = 0x7; | |||
57 | */ | 57 | */ |
58 | static int dtl_buf_entries = N_DISPATCH_LOG; | 58 | static int dtl_buf_entries = N_DISPATCH_LOG; |
59 | 59 | ||
60 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 60 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE |
61 | struct dtl_ring { | 61 | struct dtl_ring { |
62 | u64 write_index; | 62 | u64 write_index; |
63 | struct dtl_entry *write_ptr; | 63 | struct dtl_entry *write_ptr; |
@@ -142,7 +142,7 @@ static u64 dtl_current_index(struct dtl *dtl) | |||
142 | return per_cpu(dtl_rings, dtl->cpu).write_index; | 142 | return per_cpu(dtl_rings, dtl->cpu).write_index; |
143 | } | 143 | } |
144 | 144 | ||
145 | #else /* CONFIG_VIRT_CPU_ACCOUNTING */ | 145 | #else /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */ |
146 | 146 | ||
147 | static int dtl_start(struct dtl *dtl) | 147 | static int dtl_start(struct dtl *dtl) |
148 | { | 148 | { |
@@ -188,7 +188,7 @@ static u64 dtl_current_index(struct dtl *dtl) | |||
188 | { | 188 | { |
189 | return lppaca_of(dtl->cpu).dtl_idx; | 189 | return lppaca_of(dtl->cpu).dtl_idx; |
190 | } | 190 | } |
191 | #endif /* CONFIG_VIRT_CPU_ACCOUNTING */ | 191 | #endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */ |
192 | 192 | ||
193 | static int dtl_enable(struct dtl *dtl) | 193 | static int dtl_enable(struct dtl *dtl) |
194 | { | 194 | { |
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index ca55882465d6..527e12c9573b 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c | |||
@@ -281,7 +281,7 @@ static struct notifier_block pci_dn_reconfig_nb = { | |||
281 | 281 | ||
282 | struct kmem_cache *dtl_cache; | 282 | struct kmem_cache *dtl_cache; |
283 | 283 | ||
284 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 284 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE |
285 | /* | 285 | /* |
286 | * Allocate space for the dispatch trace log for all possible cpus | 286 | * Allocate space for the dispatch trace log for all possible cpus |
287 | * and register the buffers with the hypervisor. This is used for | 287 | * and register the buffers with the hypervisor. This is used for |
@@ -332,12 +332,12 @@ static int alloc_dispatch_logs(void) | |||
332 | 332 | ||
333 | return 0; | 333 | return 0; |
334 | } | 334 | } |
335 | #else /* !CONFIG_VIRT_CPU_ACCOUNTING */ | 335 | #else /* !CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */ |
336 | static inline int alloc_dispatch_logs(void) | 336 | static inline int alloc_dispatch_logs(void) |
337 | { | 337 | { |
338 | return 0; | 338 | return 0; |
339 | } | 339 | } |
340 | #endif /* CONFIG_VIRT_CPU_ACCOUNTING */ | 340 | #endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */ |
341 | 341 | ||
342 | static int alloc_dispatch_log_kmem_cache(void) | 342 | static int alloc_dispatch_log_kmem_cache(void) |
343 | { | 343 | { |
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index b5ea38c25647..c15ba7d1be64 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig | |||
@@ -78,7 +78,6 @@ config S390 | |||
78 | select HAVE_KVM if 64BIT | 78 | select HAVE_KVM if 64BIT |
79 | select HAVE_ARCH_TRACEHOOK | 79 | select HAVE_ARCH_TRACEHOOK |
80 | select INIT_ALL_POSSIBLE | 80 | select INIT_ALL_POSSIBLE |
81 | select HAVE_IRQ_WORK | ||
82 | select HAVE_PERF_EVENTS | 81 | select HAVE_PERF_EVENTS |
83 | select ARCH_HAVE_NMI_SAFE_CMPXCHG | 82 | select ARCH_HAVE_NMI_SAFE_CMPXCHG |
84 | select HAVE_DEBUG_KMEMLEAK | 83 | select HAVE_DEBUG_KMEMLEAK |
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index a5f4f5a1d24b..0aa98db8a80d 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c | |||
@@ -120,6 +120,9 @@ static int s390_next_ktime(ktime_t expires, | |||
120 | nsecs = ktime_to_ns(ktime_add(timespec_to_ktime(ts), expires)); | 120 | nsecs = ktime_to_ns(ktime_add(timespec_to_ktime(ts), expires)); |
121 | do_div(nsecs, 125); | 121 | do_div(nsecs, 125); |
122 | S390_lowcore.clock_comparator = sched_clock_base_cc + (nsecs << 9); | 122 | S390_lowcore.clock_comparator = sched_clock_base_cc + (nsecs << 9); |
123 | /* Program the maximum value if we have an overflow (== year 2042) */ | ||
124 | if (unlikely(S390_lowcore.clock_comparator < sched_clock_base_cc)) | ||
125 | S390_lowcore.clock_comparator = -1ULL; | ||
123 | set_clock_comparator(S390_lowcore.clock_comparator); | 126 | set_clock_comparator(S390_lowcore.clock_comparator); |
124 | return 0; | 127 | return 0; |
125 | } | 128 | } |
diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index e84b8b68444a..ce9cc5aa2033 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c | |||
@@ -127,7 +127,7 @@ void vtime_account_user(struct task_struct *tsk) | |||
127 | * Update process times based on virtual cpu times stored by entry.S | 127 | * Update process times based on virtual cpu times stored by entry.S |
128 | * to the lowcore fields user_timer, system_timer & steal_clock. | 128 | * to the lowcore fields user_timer, system_timer & steal_clock. |
129 | */ | 129 | */ |
130 | void vtime_account(struct task_struct *tsk) | 130 | void vtime_account_irq_enter(struct task_struct *tsk) |
131 | { | 131 | { |
132 | struct thread_info *ti = task_thread_info(tsk); | 132 | struct thread_info *ti = task_thread_info(tsk); |
133 | u64 timer, system; | 133 | u64 timer, system; |
@@ -145,10 +145,10 @@ void vtime_account(struct task_struct *tsk) | |||
145 | 145 | ||
146 | virt_timer_forward(system); | 146 | virt_timer_forward(system); |
147 | } | 147 | } |
148 | EXPORT_SYMBOL_GPL(vtime_account); | 148 | EXPORT_SYMBOL_GPL(vtime_account_irq_enter); |
149 | 149 | ||
150 | void vtime_account_system(struct task_struct *tsk) | 150 | void vtime_account_system(struct task_struct *tsk) |
151 | __attribute__((alias("vtime_account"))); | 151 | __attribute__((alias("vtime_account_irq_enter"))); |
152 | EXPORT_SYMBOL_GPL(vtime_account_system); | 152 | EXPORT_SYMBOL_GPL(vtime_account_system); |
153 | 153 | ||
154 | void __kprobes vtime_stop_cpu(void) | 154 | void __kprobes vtime_stop_cpu(void) |
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index babc2b826c5c..9c833c585871 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig | |||
@@ -11,7 +11,6 @@ config SUPERH | |||
11 | select HAVE_ARCH_TRACEHOOK | 11 | select HAVE_ARCH_TRACEHOOK |
12 | select HAVE_DMA_API_DEBUG | 12 | select HAVE_DMA_API_DEBUG |
13 | select HAVE_DMA_ATTRS | 13 | select HAVE_DMA_ATTRS |
14 | select HAVE_IRQ_WORK | ||
15 | select HAVE_PERF_EVENTS | 14 | select HAVE_PERF_EVENTS |
16 | select HAVE_DEBUG_BUGVERBOSE | 15 | select HAVE_DEBUG_BUGVERBOSE |
17 | select ARCH_HAVE_CUSTOM_GPIO_H | 16 | select ARCH_HAVE_CUSTOM_GPIO_H |
@@ -91,9 +90,6 @@ config GENERIC_CSUM | |||
91 | config GENERIC_HWEIGHT | 90 | config GENERIC_HWEIGHT |
92 | def_bool y | 91 | def_bool y |
93 | 92 | ||
94 | config IRQ_PER_CPU | ||
95 | def_bool y | ||
96 | |||
97 | config GENERIC_GPIO | 93 | config GENERIC_GPIO |
98 | def_bool n | 94 | def_bool n |
99 | 95 | ||
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 9f2edb5c5551..9bff3db17c8c 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig | |||
@@ -23,7 +23,6 @@ config SPARC | |||
23 | select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE | 23 | select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE |
24 | select RTC_CLASS | 24 | select RTC_CLASS |
25 | select RTC_DRV_M48T59 | 25 | select RTC_DRV_M48T59 |
26 | select HAVE_IRQ_WORK | ||
27 | select HAVE_DMA_ATTRS | 26 | select HAVE_DMA_ATTRS |
28 | select HAVE_DMA_API_DEBUG | 27 | select HAVE_DMA_API_DEBUG |
29 | select HAVE_ARCH_JUMP_LABEL | 28 | select HAVE_ARCH_JUMP_LABEL |
@@ -61,6 +60,7 @@ config SPARC64 | |||
61 | select HAVE_MEMBLOCK | 60 | select HAVE_MEMBLOCK |
62 | select HAVE_MEMBLOCK_NODE_MAP | 61 | select HAVE_MEMBLOCK_NODE_MAP |
63 | select HAVE_SYSCALL_WRAPPERS | 62 | select HAVE_SYSCALL_WRAPPERS |
63 | select HAVE_ARCH_TRANSPARENT_HUGEPAGE | ||
64 | select HAVE_DYNAMIC_FTRACE | 64 | select HAVE_DYNAMIC_FTRACE |
65 | select HAVE_FTRACE_MCOUNT_RECORD | 65 | select HAVE_FTRACE_MCOUNT_RECORD |
66 | select HAVE_SYSCALL_TRACEPOINTS | 66 | select HAVE_SYSCALL_TRACEPOINTS |
diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h index 7870be0f5adc..08fcce90316b 100644 --- a/arch/sparc/include/asm/pgtable_64.h +++ b/arch/sparc/include/asm/pgtable_64.h | |||
@@ -71,7 +71,6 @@ | |||
71 | #define PMD_PADDR _AC(0xfffffffe,UL) | 71 | #define PMD_PADDR _AC(0xfffffffe,UL) |
72 | #define PMD_PADDR_SHIFT _AC(11,UL) | 72 | #define PMD_PADDR_SHIFT _AC(11,UL) |
73 | 73 | ||
74 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | ||
75 | #define PMD_ISHUGE _AC(0x00000001,UL) | 74 | #define PMD_ISHUGE _AC(0x00000001,UL) |
76 | 75 | ||
77 | /* This is the PMD layout when PMD_ISHUGE is set. With 4MB huge | 76 | /* This is the PMD layout when PMD_ISHUGE is set. With 4MB huge |
@@ -86,7 +85,6 @@ | |||
86 | #define PMD_HUGE_ACCESSED _AC(0x00000080,UL) | 85 | #define PMD_HUGE_ACCESSED _AC(0x00000080,UL) |
87 | #define PMD_HUGE_EXEC _AC(0x00000040,UL) | 86 | #define PMD_HUGE_EXEC _AC(0x00000040,UL) |
88 | #define PMD_HUGE_SPLITTING _AC(0x00000020,UL) | 87 | #define PMD_HUGE_SPLITTING _AC(0x00000020,UL) |
89 | #endif | ||
90 | 88 | ||
91 | /* PGDs point to PMD tables which are 8K aligned. */ | 89 | /* PGDs point to PMD tables which are 8K aligned. */ |
92 | #define PGD_PADDR _AC(0xfffffffc,UL) | 90 | #define PGD_PADDR _AC(0xfffffffc,UL) |
@@ -628,6 +626,12 @@ static inline unsigned long pte_special(pte_t pte) | |||
628 | return pte_val(pte) & _PAGE_SPECIAL; | 626 | return pte_val(pte) & _PAGE_SPECIAL; |
629 | } | 627 | } |
630 | 628 | ||
629 | static inline int pmd_large(pmd_t pmd) | ||
630 | { | ||
631 | return (pmd_val(pmd) & (PMD_ISHUGE | PMD_HUGE_PRESENT)) == | ||
632 | (PMD_ISHUGE | PMD_HUGE_PRESENT); | ||
633 | } | ||
634 | |||
631 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | 635 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE |
632 | static inline int pmd_young(pmd_t pmd) | 636 | static inline int pmd_young(pmd_t pmd) |
633 | { | 637 | { |
@@ -646,12 +650,6 @@ static inline unsigned long pmd_pfn(pmd_t pmd) | |||
646 | return val >> (PAGE_SHIFT - PMD_PADDR_SHIFT); | 650 | return val >> (PAGE_SHIFT - PMD_PADDR_SHIFT); |
647 | } | 651 | } |
648 | 652 | ||
649 | static inline int pmd_large(pmd_t pmd) | ||
650 | { | ||
651 | return (pmd_val(pmd) & (PMD_ISHUGE | PMD_HUGE_PRESENT)) == | ||
652 | (PMD_ISHUGE | PMD_HUGE_PRESENT); | ||
653 | } | ||
654 | |||
655 | static inline int pmd_trans_splitting(pmd_t pmd) | 653 | static inline int pmd_trans_splitting(pmd_t pmd) |
656 | { | 654 | { |
657 | return (pmd_val(pmd) & (PMD_ISHUGE|PMD_HUGE_SPLITTING)) == | 655 | return (pmd_val(pmd) & (PMD_ISHUGE|PMD_HUGE_SPLITTING)) == |
diff --git a/arch/sparc/kernel/sbus.c b/arch/sparc/kernel/sbus.c index 1271b3a27d4e..be5bdf93c767 100644 --- a/arch/sparc/kernel/sbus.c +++ b/arch/sparc/kernel/sbus.c | |||
@@ -554,10 +554,8 @@ static void __init sbus_iommu_init(struct platform_device *op) | |||
554 | regs = pr->phys_addr; | 554 | regs = pr->phys_addr; |
555 | 555 | ||
556 | iommu = kzalloc(sizeof(*iommu), GFP_ATOMIC); | 556 | iommu = kzalloc(sizeof(*iommu), GFP_ATOMIC); |
557 | if (!iommu) | ||
558 | goto fatal_memory_error; | ||
559 | strbuf = kzalloc(sizeof(*strbuf), GFP_ATOMIC); | 557 | strbuf = kzalloc(sizeof(*strbuf), GFP_ATOMIC); |
560 | if (!strbuf) | 558 | if (!iommu || !strbuf) |
561 | goto fatal_memory_error; | 559 | goto fatal_memory_error; |
562 | 560 | ||
563 | op->dev.archdata.iommu = iommu; | 561 | op->dev.archdata.iommu = iommu; |
@@ -656,6 +654,8 @@ static void __init sbus_iommu_init(struct platform_device *op) | |||
656 | return; | 654 | return; |
657 | 655 | ||
658 | fatal_memory_error: | 656 | fatal_memory_error: |
657 | kfree(iommu); | ||
658 | kfree(strbuf); | ||
659 | prom_printf("sbus_iommu_init: Fatal memory allocation error.\n"); | 659 | prom_printf("sbus_iommu_init: Fatal memory allocation error.\n"); |
660 | } | 660 | } |
661 | 661 | ||
diff --git a/arch/sparc/mm/gup.c b/arch/sparc/mm/gup.c index 42c55df3aec3..01ee23dd724d 100644 --- a/arch/sparc/mm/gup.c +++ b/arch/sparc/mm/gup.c | |||
@@ -66,6 +66,56 @@ static noinline int gup_pte_range(pmd_t pmd, unsigned long addr, | |||
66 | return 1; | 66 | return 1; |
67 | } | 67 | } |
68 | 68 | ||
69 | static int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr, | ||
70 | unsigned long end, int write, struct page **pages, | ||
71 | int *nr) | ||
72 | { | ||
73 | struct page *head, *page, *tail; | ||
74 | u32 mask; | ||
75 | int refs; | ||
76 | |||
77 | mask = PMD_HUGE_PRESENT; | ||
78 | if (write) | ||
79 | mask |= PMD_HUGE_WRITE; | ||
80 | if ((pmd_val(pmd) & mask) != mask) | ||
81 | return 0; | ||
82 | |||
83 | refs = 0; | ||
84 | head = pmd_page(pmd); | ||
85 | page = head + ((addr & ~PMD_MASK) >> PAGE_SHIFT); | ||
86 | tail = page; | ||
87 | do { | ||
88 | VM_BUG_ON(compound_head(page) != head); | ||
89 | pages[*nr] = page; | ||
90 | (*nr)++; | ||
91 | page++; | ||
92 | refs++; | ||
93 | } while (addr += PAGE_SIZE, addr != end); | ||
94 | |||
95 | if (!page_cache_add_speculative(head, refs)) { | ||
96 | *nr -= refs; | ||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | if (unlikely(pmd_val(pmd) != pmd_val(*pmdp))) { | ||
101 | *nr -= refs; | ||
102 | while (refs--) | ||
103 | put_page(head); | ||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | /* Any tail page need their mapcount reference taken before we | ||
108 | * return. | ||
109 | */ | ||
110 | while (refs--) { | ||
111 | if (PageTail(tail)) | ||
112 | get_huge_page_tail(tail); | ||
113 | tail++; | ||
114 | } | ||
115 | |||
116 | return 1; | ||
117 | } | ||
118 | |||
69 | static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end, | 119 | static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end, |
70 | int write, struct page **pages, int *nr) | 120 | int write, struct page **pages, int *nr) |
71 | { | 121 | { |
@@ -77,9 +127,14 @@ static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end, | |||
77 | pmd_t pmd = *pmdp; | 127 | pmd_t pmd = *pmdp; |
78 | 128 | ||
79 | next = pmd_addr_end(addr, end); | 129 | next = pmd_addr_end(addr, end); |
80 | if (pmd_none(pmd)) | 130 | if (pmd_none(pmd) || pmd_trans_splitting(pmd)) |
81 | return 0; | 131 | return 0; |
82 | if (!gup_pte_range(pmd, addr, next, write, pages, nr)) | 132 | if (unlikely(pmd_large(pmd))) { |
133 | if (!gup_huge_pmd(pmdp, pmd, addr, next, | ||
134 | write, pages, nr)) | ||
135 | return 0; | ||
136 | } else if (!gup_pte_range(pmd, addr, next, write, | ||
137 | pages, nr)) | ||
83 | return 0; | 138 | return 0; |
84 | } while (pmdp++, addr = next, addr != end); | 139 | } while (pmdp++, addr = next, addr != end); |
85 | 140 | ||
diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig index 875d008828b8..1bb7ad4aeff4 100644 --- a/arch/tile/Kconfig +++ b/arch/tile/Kconfig | |||
@@ -140,6 +140,8 @@ config ARCH_DEFCONFIG | |||
140 | 140 | ||
141 | source "init/Kconfig" | 141 | source "init/Kconfig" |
142 | 142 | ||
143 | source "kernel/Kconfig.freezer" | ||
144 | |||
143 | menu "Tilera-specific configuration" | 145 | menu "Tilera-specific configuration" |
144 | 146 | ||
145 | config NR_CPUS | 147 | config NR_CPUS |
diff --git a/arch/tile/include/asm/io.h b/arch/tile/include/asm/io.h index 2a9b293fece6..31672918064c 100644 --- a/arch/tile/include/asm/io.h +++ b/arch/tile/include/asm/io.h | |||
@@ -250,7 +250,9 @@ static inline void writeq(u64 val, unsigned long addr) | |||
250 | #define iowrite32 writel | 250 | #define iowrite32 writel |
251 | #define iowrite64 writeq | 251 | #define iowrite64 writeq |
252 | 252 | ||
253 | static inline void memset_io(void *dst, int val, size_t len) | 253 | #if CHIP_HAS_MMIO() || defined(CONFIG_PCI) |
254 | |||
255 | static inline void memset_io(volatile void *dst, int val, size_t len) | ||
254 | { | 256 | { |
255 | int x; | 257 | int x; |
256 | BUG_ON((unsigned long)dst & 0x3); | 258 | BUG_ON((unsigned long)dst & 0x3); |
@@ -277,6 +279,8 @@ static inline void memcpy_toio(volatile void __iomem *dst, const void *src, | |||
277 | writel(*(u32 *)(src + x), dst + x); | 279 | writel(*(u32 *)(src + x), dst + x); |
278 | } | 280 | } |
279 | 281 | ||
282 | #endif | ||
283 | |||
280 | /* | 284 | /* |
281 | * The Tile architecture does not support IOPORT, even with PCI. | 285 | * The Tile architecture does not support IOPORT, even with PCI. |
282 | * Unfortunately we can't yet simply not declare these methods, | 286 | * Unfortunately we can't yet simply not declare these methods, |
diff --git a/arch/tile/include/asm/irqflags.h b/arch/tile/include/asm/irqflags.h index b4e96fef2cf8..241c0bb60b12 100644 --- a/arch/tile/include/asm/irqflags.h +++ b/arch/tile/include/asm/irqflags.h | |||
@@ -18,32 +18,20 @@ | |||
18 | #include <arch/interrupts.h> | 18 | #include <arch/interrupts.h> |
19 | #include <arch/chip.h> | 19 | #include <arch/chip.h> |
20 | 20 | ||
21 | #if !defined(__tilegx__) && defined(__ASSEMBLY__) | ||
22 | |||
23 | /* | 21 | /* |
24 | * The set of interrupts we want to allow when interrupts are nominally | 22 | * The set of interrupts we want to allow when interrupts are nominally |
25 | * disabled. The remainder are effectively "NMI" interrupts from | 23 | * disabled. The remainder are effectively "NMI" interrupts from |
26 | * the point of view of the generic Linux code. Note that synchronous | 24 | * the point of view of the generic Linux code. Note that synchronous |
27 | * interrupts (aka "non-queued") are not blocked by the mask in any case. | 25 | * interrupts (aka "non-queued") are not blocked by the mask in any case. |
28 | */ | 26 | */ |
29 | #if CHIP_HAS_AUX_PERF_COUNTERS() | ||
30 | #define LINUX_MASKABLE_INTERRUPTS_HI \ | ||
31 | (~(INT_MASK_HI(INT_PERF_COUNT) | INT_MASK_HI(INT_AUX_PERF_COUNT))) | ||
32 | #else | ||
33 | #define LINUX_MASKABLE_INTERRUPTS_HI \ | ||
34 | (~(INT_MASK_HI(INT_PERF_COUNT))) | ||
35 | #endif | ||
36 | |||
37 | #else | ||
38 | |||
39 | #if CHIP_HAS_AUX_PERF_COUNTERS() | ||
40 | #define LINUX_MASKABLE_INTERRUPTS \ | ||
41 | (~(INT_MASK(INT_PERF_COUNT) | INT_MASK(INT_AUX_PERF_COUNT))) | ||
42 | #else | ||
43 | #define LINUX_MASKABLE_INTERRUPTS \ | 27 | #define LINUX_MASKABLE_INTERRUPTS \ |
44 | (~(INT_MASK(INT_PERF_COUNT))) | 28 | (~((_AC(1,ULL) << INT_PERF_COUNT) | (_AC(1,ULL) << INT_AUX_PERF_COUNT))) |
45 | #endif | ||
46 | 29 | ||
30 | #if CHIP_HAS_SPLIT_INTR_MASK() | ||
31 | /* The same macro, but for the two 32-bit SPRs separately. */ | ||
32 | #define LINUX_MASKABLE_INTERRUPTS_LO (-1) | ||
33 | #define LINUX_MASKABLE_INTERRUPTS_HI \ | ||
34 | (~((1 << (INT_PERF_COUNT - 32)) | (1 << (INT_AUX_PERF_COUNT - 32)))) | ||
47 | #endif | 35 | #endif |
48 | 36 | ||
49 | #ifndef __ASSEMBLY__ | 37 | #ifndef __ASSEMBLY__ |
@@ -126,7 +114,7 @@ | |||
126 | * to know our current state. | 114 | * to know our current state. |
127 | */ | 115 | */ |
128 | DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask); | 116 | DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask); |
129 | #define INITIAL_INTERRUPTS_ENABLED INT_MASK(INT_MEM_ERROR) | 117 | #define INITIAL_INTERRUPTS_ENABLED (1ULL << INT_MEM_ERROR) |
130 | 118 | ||
131 | /* Disable interrupts. */ | 119 | /* Disable interrupts. */ |
132 | #define arch_local_irq_disable() \ | 120 | #define arch_local_irq_disable() \ |
@@ -165,7 +153,7 @@ DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask); | |||
165 | 153 | ||
166 | /* Prevent the given interrupt from being enabled next time we enable irqs. */ | 154 | /* Prevent the given interrupt from being enabled next time we enable irqs. */ |
167 | #define arch_local_irq_mask(interrupt) \ | 155 | #define arch_local_irq_mask(interrupt) \ |
168 | (__get_cpu_var(interrupts_enabled_mask) &= ~INT_MASK(interrupt)) | 156 | (__get_cpu_var(interrupts_enabled_mask) &= ~(1ULL << (interrupt))) |
169 | 157 | ||
170 | /* Prevent the given interrupt from being enabled immediately. */ | 158 | /* Prevent the given interrupt from being enabled immediately. */ |
171 | #define arch_local_irq_mask_now(interrupt) do { \ | 159 | #define arch_local_irq_mask_now(interrupt) do { \ |
@@ -175,7 +163,7 @@ DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask); | |||
175 | 163 | ||
176 | /* Allow the given interrupt to be enabled next time we enable irqs. */ | 164 | /* Allow the given interrupt to be enabled next time we enable irqs. */ |
177 | #define arch_local_irq_unmask(interrupt) \ | 165 | #define arch_local_irq_unmask(interrupt) \ |
178 | (__get_cpu_var(interrupts_enabled_mask) |= INT_MASK(interrupt)) | 166 | (__get_cpu_var(interrupts_enabled_mask) |= (1ULL << (interrupt))) |
179 | 167 | ||
180 | /* Allow the given interrupt to be enabled immediately, if !irqs_disabled. */ | 168 | /* Allow the given interrupt to be enabled immediately, if !irqs_disabled. */ |
181 | #define arch_local_irq_unmask_now(interrupt) do { \ | 169 | #define arch_local_irq_unmask_now(interrupt) do { \ |
@@ -250,7 +238,7 @@ DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask); | |||
250 | /* Disable interrupts. */ | 238 | /* Disable interrupts. */ |
251 | #define IRQ_DISABLE(tmp0, tmp1) \ | 239 | #define IRQ_DISABLE(tmp0, tmp1) \ |
252 | { \ | 240 | { \ |
253 | movei tmp0, -1; \ | 241 | movei tmp0, LINUX_MASKABLE_INTERRUPTS_LO; \ |
254 | moveli tmp1, lo16(LINUX_MASKABLE_INTERRUPTS_HI) \ | 242 | moveli tmp1, lo16(LINUX_MASKABLE_INTERRUPTS_HI) \ |
255 | }; \ | 243 | }; \ |
256 | { \ | 244 | { \ |
diff --git a/arch/tile/include/uapi/arch/interrupts_32.h b/arch/tile/include/uapi/arch/interrupts_32.h index 96b5710505b6..2efe3f68b2d6 100644 --- a/arch/tile/include/uapi/arch/interrupts_32.h +++ b/arch/tile/include/uapi/arch/interrupts_32.h | |||
@@ -15,6 +15,7 @@ | |||
15 | #ifndef __ARCH_INTERRUPTS_H__ | 15 | #ifndef __ARCH_INTERRUPTS_H__ |
16 | #define __ARCH_INTERRUPTS_H__ | 16 | #define __ARCH_INTERRUPTS_H__ |
17 | 17 | ||
18 | #ifndef __KERNEL__ | ||
18 | /** Mask for an interrupt. */ | 19 | /** Mask for an interrupt. */ |
19 | /* Note: must handle breaking interrupts into high and low words manually. */ | 20 | /* Note: must handle breaking interrupts into high and low words manually. */ |
20 | #define INT_MASK_LO(intno) (1 << (intno)) | 21 | #define INT_MASK_LO(intno) (1 << (intno)) |
@@ -23,6 +24,7 @@ | |||
23 | #ifndef __ASSEMBLER__ | 24 | #ifndef __ASSEMBLER__ |
24 | #define INT_MASK(intno) (1ULL << (intno)) | 25 | #define INT_MASK(intno) (1ULL << (intno)) |
25 | #endif | 26 | #endif |
27 | #endif | ||
26 | 28 | ||
27 | 29 | ||
28 | /** Where a given interrupt executes */ | 30 | /** Where a given interrupt executes */ |
@@ -92,216 +94,216 @@ | |||
92 | 94 | ||
93 | #ifndef __ASSEMBLER__ | 95 | #ifndef __ASSEMBLER__ |
94 | #define QUEUED_INTERRUPTS ( \ | 96 | #define QUEUED_INTERRUPTS ( \ |
95 | INT_MASK(INT_MEM_ERROR) | \ | 97 | (1ULL << INT_MEM_ERROR) | \ |
96 | INT_MASK(INT_DMATLB_MISS) | \ | 98 | (1ULL << INT_DMATLB_MISS) | \ |
97 | INT_MASK(INT_DMATLB_ACCESS) | \ | 99 | (1ULL << INT_DMATLB_ACCESS) | \ |
98 | INT_MASK(INT_SNITLB_MISS) | \ | 100 | (1ULL << INT_SNITLB_MISS) | \ |
99 | INT_MASK(INT_SN_NOTIFY) | \ | 101 | (1ULL << INT_SN_NOTIFY) | \ |
100 | INT_MASK(INT_SN_FIREWALL) | \ | 102 | (1ULL << INT_SN_FIREWALL) | \ |
101 | INT_MASK(INT_IDN_FIREWALL) | \ | 103 | (1ULL << INT_IDN_FIREWALL) | \ |
102 | INT_MASK(INT_UDN_FIREWALL) | \ | 104 | (1ULL << INT_UDN_FIREWALL) | \ |
103 | INT_MASK(INT_TILE_TIMER) | \ | 105 | (1ULL << INT_TILE_TIMER) | \ |
104 | INT_MASK(INT_IDN_TIMER) | \ | 106 | (1ULL << INT_IDN_TIMER) | \ |
105 | INT_MASK(INT_UDN_TIMER) | \ | 107 | (1ULL << INT_UDN_TIMER) | \ |
106 | INT_MASK(INT_DMA_NOTIFY) | \ | 108 | (1ULL << INT_DMA_NOTIFY) | \ |
107 | INT_MASK(INT_IDN_CA) | \ | 109 | (1ULL << INT_IDN_CA) | \ |
108 | INT_MASK(INT_UDN_CA) | \ | 110 | (1ULL << INT_UDN_CA) | \ |
109 | INT_MASK(INT_IDN_AVAIL) | \ | 111 | (1ULL << INT_IDN_AVAIL) | \ |
110 | INT_MASK(INT_UDN_AVAIL) | \ | 112 | (1ULL << INT_UDN_AVAIL) | \ |
111 | INT_MASK(INT_PERF_COUNT) | \ | 113 | (1ULL << INT_PERF_COUNT) | \ |
112 | INT_MASK(INT_INTCTRL_3) | \ | 114 | (1ULL << INT_INTCTRL_3) | \ |
113 | INT_MASK(INT_INTCTRL_2) | \ | 115 | (1ULL << INT_INTCTRL_2) | \ |
114 | INT_MASK(INT_INTCTRL_1) | \ | 116 | (1ULL << INT_INTCTRL_1) | \ |
115 | INT_MASK(INT_INTCTRL_0) | \ | 117 | (1ULL << INT_INTCTRL_0) | \ |
116 | INT_MASK(INT_BOOT_ACCESS) | \ | 118 | (1ULL << INT_BOOT_ACCESS) | \ |
117 | INT_MASK(INT_WORLD_ACCESS) | \ | 119 | (1ULL << INT_WORLD_ACCESS) | \ |
118 | INT_MASK(INT_I_ASID) | \ | 120 | (1ULL << INT_I_ASID) | \ |
119 | INT_MASK(INT_D_ASID) | \ | 121 | (1ULL << INT_D_ASID) | \ |
120 | INT_MASK(INT_DMA_ASID) | \ | 122 | (1ULL << INT_DMA_ASID) | \ |
121 | INT_MASK(INT_SNI_ASID) | \ | 123 | (1ULL << INT_SNI_ASID) | \ |
122 | INT_MASK(INT_DMA_CPL) | \ | 124 | (1ULL << INT_DMA_CPL) | \ |
123 | INT_MASK(INT_SN_CPL) | \ | 125 | (1ULL << INT_SN_CPL) | \ |
124 | INT_MASK(INT_DOUBLE_FAULT) | \ | 126 | (1ULL << INT_DOUBLE_FAULT) | \ |
125 | INT_MASK(INT_AUX_PERF_COUNT) | \ | 127 | (1ULL << INT_AUX_PERF_COUNT) | \ |
126 | 0) | 128 | 0) |
127 | #define NONQUEUED_INTERRUPTS ( \ | 129 | #define NONQUEUED_INTERRUPTS ( \ |
128 | INT_MASK(INT_ITLB_MISS) | \ | 130 | (1ULL << INT_ITLB_MISS) | \ |
129 | INT_MASK(INT_ILL) | \ | 131 | (1ULL << INT_ILL) | \ |
130 | INT_MASK(INT_GPV) | \ | 132 | (1ULL << INT_GPV) | \ |
131 | INT_MASK(INT_SN_ACCESS) | \ | 133 | (1ULL << INT_SN_ACCESS) | \ |
132 | INT_MASK(INT_IDN_ACCESS) | \ | 134 | (1ULL << INT_IDN_ACCESS) | \ |
133 | INT_MASK(INT_UDN_ACCESS) | \ | 135 | (1ULL << INT_UDN_ACCESS) | \ |
134 | INT_MASK(INT_IDN_REFILL) | \ | 136 | (1ULL << INT_IDN_REFILL) | \ |
135 | INT_MASK(INT_UDN_REFILL) | \ | 137 | (1ULL << INT_UDN_REFILL) | \ |
136 | INT_MASK(INT_IDN_COMPLETE) | \ | 138 | (1ULL << INT_IDN_COMPLETE) | \ |
137 | INT_MASK(INT_UDN_COMPLETE) | \ | 139 | (1ULL << INT_UDN_COMPLETE) | \ |
138 | INT_MASK(INT_SWINT_3) | \ | 140 | (1ULL << INT_SWINT_3) | \ |
139 | INT_MASK(INT_SWINT_2) | \ | 141 | (1ULL << INT_SWINT_2) | \ |
140 | INT_MASK(INT_SWINT_1) | \ | 142 | (1ULL << INT_SWINT_1) | \ |
141 | INT_MASK(INT_SWINT_0) | \ | 143 | (1ULL << INT_SWINT_0) | \ |
142 | INT_MASK(INT_UNALIGN_DATA) | \ | 144 | (1ULL << INT_UNALIGN_DATA) | \ |
143 | INT_MASK(INT_DTLB_MISS) | \ | 145 | (1ULL << INT_DTLB_MISS) | \ |
144 | INT_MASK(INT_DTLB_ACCESS) | \ | 146 | (1ULL << INT_DTLB_ACCESS) | \ |
145 | INT_MASK(INT_SN_STATIC_ACCESS) | \ | 147 | (1ULL << INT_SN_STATIC_ACCESS) | \ |
146 | 0) | 148 | 0) |
147 | #define CRITICAL_MASKED_INTERRUPTS ( \ | 149 | #define CRITICAL_MASKED_INTERRUPTS ( \ |
148 | INT_MASK(INT_MEM_ERROR) | \ | 150 | (1ULL << INT_MEM_ERROR) | \ |
149 | INT_MASK(INT_DMATLB_MISS) | \ | 151 | (1ULL << INT_DMATLB_MISS) | \ |
150 | INT_MASK(INT_DMATLB_ACCESS) | \ | 152 | (1ULL << INT_DMATLB_ACCESS) | \ |
151 | INT_MASK(INT_SNITLB_MISS) | \ | 153 | (1ULL << INT_SNITLB_MISS) | \ |
152 | INT_MASK(INT_SN_NOTIFY) | \ | 154 | (1ULL << INT_SN_NOTIFY) | \ |
153 | INT_MASK(INT_SN_FIREWALL) | \ | 155 | (1ULL << INT_SN_FIREWALL) | \ |
154 | INT_MASK(INT_IDN_FIREWALL) | \ | 156 | (1ULL << INT_IDN_FIREWALL) | \ |
155 | INT_MASK(INT_UDN_FIREWALL) | \ | 157 | (1ULL << INT_UDN_FIREWALL) | \ |
156 | INT_MASK(INT_TILE_TIMER) | \ | 158 | (1ULL << INT_TILE_TIMER) | \ |
157 | INT_MASK(INT_IDN_TIMER) | \ | 159 | (1ULL << INT_IDN_TIMER) | \ |
158 | INT_MASK(INT_UDN_TIMER) | \ | 160 | (1ULL << INT_UDN_TIMER) | \ |
159 | INT_MASK(INT_DMA_NOTIFY) | \ | 161 | (1ULL << INT_DMA_NOTIFY) | \ |
160 | INT_MASK(INT_IDN_CA) | \ | 162 | (1ULL << INT_IDN_CA) | \ |
161 | INT_MASK(INT_UDN_CA) | \ | 163 | (1ULL << INT_UDN_CA) | \ |
162 | INT_MASK(INT_IDN_AVAIL) | \ | 164 | (1ULL << INT_IDN_AVAIL) | \ |
163 | INT_MASK(INT_UDN_AVAIL) | \ | 165 | (1ULL << INT_UDN_AVAIL) | \ |
164 | INT_MASK(INT_PERF_COUNT) | \ | 166 | (1ULL << INT_PERF_COUNT) | \ |
165 | INT_MASK(INT_INTCTRL_3) | \ | 167 | (1ULL << INT_INTCTRL_3) | \ |
166 | INT_MASK(INT_INTCTRL_2) | \ | 168 | (1ULL << INT_INTCTRL_2) | \ |
167 | INT_MASK(INT_INTCTRL_1) | \ | 169 | (1ULL << INT_INTCTRL_1) | \ |
168 | INT_MASK(INT_INTCTRL_0) | \ | 170 | (1ULL << INT_INTCTRL_0) | \ |
169 | INT_MASK(INT_AUX_PERF_COUNT) | \ | 171 | (1ULL << INT_AUX_PERF_COUNT) | \ |
170 | 0) | 172 | 0) |
171 | #define CRITICAL_UNMASKED_INTERRUPTS ( \ | 173 | #define CRITICAL_UNMASKED_INTERRUPTS ( \ |
172 | INT_MASK(INT_ITLB_MISS) | \ | 174 | (1ULL << INT_ITLB_MISS) | \ |
173 | INT_MASK(INT_ILL) | \ | 175 | (1ULL << INT_ILL) | \ |
174 | INT_MASK(INT_GPV) | \ | 176 | (1ULL << INT_GPV) | \ |
175 | INT_MASK(INT_SN_ACCESS) | \ | 177 | (1ULL << INT_SN_ACCESS) | \ |
176 | INT_MASK(INT_IDN_ACCESS) | \ | 178 | (1ULL << INT_IDN_ACCESS) | \ |
177 | INT_MASK(INT_UDN_ACCESS) | \ | 179 | (1ULL << INT_UDN_ACCESS) | \ |
178 | INT_MASK(INT_IDN_REFILL) | \ | 180 | (1ULL << INT_IDN_REFILL) | \ |
179 | INT_MASK(INT_UDN_REFILL) | \ | 181 | (1ULL << INT_UDN_REFILL) | \ |
180 | INT_MASK(INT_IDN_COMPLETE) | \ | 182 | (1ULL << INT_IDN_COMPLETE) | \ |
181 | INT_MASK(INT_UDN_COMPLETE) | \ | 183 | (1ULL << INT_UDN_COMPLETE) | \ |
182 | INT_MASK(INT_SWINT_3) | \ | 184 | (1ULL << INT_SWINT_3) | \ |
183 | INT_MASK(INT_SWINT_2) | \ | 185 | (1ULL << INT_SWINT_2) | \ |
184 | INT_MASK(INT_SWINT_1) | \ | 186 | (1ULL << INT_SWINT_1) | \ |
185 | INT_MASK(INT_SWINT_0) | \ | 187 | (1ULL << INT_SWINT_0) | \ |
186 | INT_MASK(INT_UNALIGN_DATA) | \ | 188 | (1ULL << INT_UNALIGN_DATA) | \ |
187 | INT_MASK(INT_DTLB_MISS) | \ | 189 | (1ULL << INT_DTLB_MISS) | \ |
188 | INT_MASK(INT_DTLB_ACCESS) | \ | 190 | (1ULL << INT_DTLB_ACCESS) | \ |
189 | INT_MASK(INT_BOOT_ACCESS) | \ | 191 | (1ULL << INT_BOOT_ACCESS) | \ |
190 | INT_MASK(INT_WORLD_ACCESS) | \ | 192 | (1ULL << INT_WORLD_ACCESS) | \ |
191 | INT_MASK(INT_I_ASID) | \ | 193 | (1ULL << INT_I_ASID) | \ |
192 | INT_MASK(INT_D_ASID) | \ | 194 | (1ULL << INT_D_ASID) | \ |
193 | INT_MASK(INT_DMA_ASID) | \ | 195 | (1ULL << INT_DMA_ASID) | \ |
194 | INT_MASK(INT_SNI_ASID) | \ | 196 | (1ULL << INT_SNI_ASID) | \ |
195 | INT_MASK(INT_DMA_CPL) | \ | 197 | (1ULL << INT_DMA_CPL) | \ |
196 | INT_MASK(INT_SN_CPL) | \ | 198 | (1ULL << INT_SN_CPL) | \ |
197 | INT_MASK(INT_DOUBLE_FAULT) | \ | 199 | (1ULL << INT_DOUBLE_FAULT) | \ |
198 | INT_MASK(INT_SN_STATIC_ACCESS) | \ | 200 | (1ULL << INT_SN_STATIC_ACCESS) | \ |
199 | 0) | 201 | 0) |
200 | #define MASKABLE_INTERRUPTS ( \ | 202 | #define MASKABLE_INTERRUPTS ( \ |
201 | INT_MASK(INT_MEM_ERROR) | \ | 203 | (1ULL << INT_MEM_ERROR) | \ |
202 | INT_MASK(INT_IDN_REFILL) | \ | 204 | (1ULL << INT_IDN_REFILL) | \ |
203 | INT_MASK(INT_UDN_REFILL) | \ | 205 | (1ULL << INT_UDN_REFILL) | \ |
204 | INT_MASK(INT_IDN_COMPLETE) | \ | 206 | (1ULL << INT_IDN_COMPLETE) | \ |
205 | INT_MASK(INT_UDN_COMPLETE) | \ | 207 | (1ULL << INT_UDN_COMPLETE) | \ |
206 | INT_MASK(INT_DMATLB_MISS) | \ | 208 | (1ULL << INT_DMATLB_MISS) | \ |
207 | INT_MASK(INT_DMATLB_ACCESS) | \ | 209 | (1ULL << INT_DMATLB_ACCESS) | \ |
208 | INT_MASK(INT_SNITLB_MISS) | \ | 210 | (1ULL << INT_SNITLB_MISS) | \ |
209 | INT_MASK(INT_SN_NOTIFY) | \ | 211 | (1ULL << INT_SN_NOTIFY) | \ |
210 | INT_MASK(INT_SN_FIREWALL) | \ | 212 | (1ULL << INT_SN_FIREWALL) | \ |
211 | INT_MASK(INT_IDN_FIREWALL) | \ | 213 | (1ULL << INT_IDN_FIREWALL) | \ |
212 | INT_MASK(INT_UDN_FIREWALL) | \ | 214 | (1ULL << INT_UDN_FIREWALL) | \ |
213 | INT_MASK(INT_TILE_TIMER) | \ | 215 | (1ULL << INT_TILE_TIMER) | \ |
214 | INT_MASK(INT_IDN_TIMER) | \ | 216 | (1ULL << INT_IDN_TIMER) | \ |
215 | INT_MASK(INT_UDN_TIMER) | \ | 217 | (1ULL << INT_UDN_TIMER) | \ |
216 | INT_MASK(INT_DMA_NOTIFY) | \ | 218 | (1ULL << INT_DMA_NOTIFY) | \ |
217 | INT_MASK(INT_IDN_CA) | \ | 219 | (1ULL << INT_IDN_CA) | \ |
218 | INT_MASK(INT_UDN_CA) | \ | 220 | (1ULL << INT_UDN_CA) | \ |
219 | INT_MASK(INT_IDN_AVAIL) | \ | 221 | (1ULL << INT_IDN_AVAIL) | \ |
220 | INT_MASK(INT_UDN_AVAIL) | \ | 222 | (1ULL << INT_UDN_AVAIL) | \ |
221 | INT_MASK(INT_PERF_COUNT) | \ | 223 | (1ULL << INT_PERF_COUNT) | \ |
222 | INT_MASK(INT_INTCTRL_3) | \ | 224 | (1ULL << INT_INTCTRL_3) | \ |
223 | INT_MASK(INT_INTCTRL_2) | \ | 225 | (1ULL << INT_INTCTRL_2) | \ |
224 | INT_MASK(INT_INTCTRL_1) | \ | 226 | (1ULL << INT_INTCTRL_1) | \ |
225 | INT_MASK(INT_INTCTRL_0) | \ | 227 | (1ULL << INT_INTCTRL_0) | \ |
226 | INT_MASK(INT_AUX_PERF_COUNT) | \ | 228 | (1ULL << INT_AUX_PERF_COUNT) | \ |
227 | 0) | 229 | 0) |
228 | #define UNMASKABLE_INTERRUPTS ( \ | 230 | #define UNMASKABLE_INTERRUPTS ( \ |
229 | INT_MASK(INT_ITLB_MISS) | \ | 231 | (1ULL << INT_ITLB_MISS) | \ |
230 | INT_MASK(INT_ILL) | \ | 232 | (1ULL << INT_ILL) | \ |
231 | INT_MASK(INT_GPV) | \ | 233 | (1ULL << INT_GPV) | \ |
232 | INT_MASK(INT_SN_ACCESS) | \ | 234 | (1ULL << INT_SN_ACCESS) | \ |
233 | INT_MASK(INT_IDN_ACCESS) | \ | 235 | (1ULL << INT_IDN_ACCESS) | \ |
234 | INT_MASK(INT_UDN_ACCESS) | \ | 236 | (1ULL << INT_UDN_ACCESS) | \ |
235 | INT_MASK(INT_SWINT_3) | \ | 237 | (1ULL << INT_SWINT_3) | \ |
236 | INT_MASK(INT_SWINT_2) | \ | 238 | (1ULL << INT_SWINT_2) | \ |
237 | INT_MASK(INT_SWINT_1) | \ | 239 | (1ULL << INT_SWINT_1) | \ |
238 | INT_MASK(INT_SWINT_0) | \ | 240 | (1ULL << INT_SWINT_0) | \ |
239 | INT_MASK(INT_UNALIGN_DATA) | \ | 241 | (1ULL << INT_UNALIGN_DATA) | \ |
240 | INT_MASK(INT_DTLB_MISS) | \ | 242 | (1ULL << INT_DTLB_MISS) | \ |
241 | INT_MASK(INT_DTLB_ACCESS) | \ | 243 | (1ULL << INT_DTLB_ACCESS) | \ |
242 | INT_MASK(INT_BOOT_ACCESS) | \ | 244 | (1ULL << INT_BOOT_ACCESS) | \ |
243 | INT_MASK(INT_WORLD_ACCESS) | \ | 245 | (1ULL << INT_WORLD_ACCESS) | \ |
244 | INT_MASK(INT_I_ASID) | \ | 246 | (1ULL << INT_I_ASID) | \ |
245 | INT_MASK(INT_D_ASID) | \ | 247 | (1ULL << INT_D_ASID) | \ |
246 | INT_MASK(INT_DMA_ASID) | \ | 248 | (1ULL << INT_DMA_ASID) | \ |
247 | INT_MASK(INT_SNI_ASID) | \ | 249 | (1ULL << INT_SNI_ASID) | \ |
248 | INT_MASK(INT_DMA_CPL) | \ | 250 | (1ULL << INT_DMA_CPL) | \ |
249 | INT_MASK(INT_SN_CPL) | \ | 251 | (1ULL << INT_SN_CPL) | \ |
250 | INT_MASK(INT_DOUBLE_FAULT) | \ | 252 | (1ULL << INT_DOUBLE_FAULT) | \ |
251 | INT_MASK(INT_SN_STATIC_ACCESS) | \ | 253 | (1ULL << INT_SN_STATIC_ACCESS) | \ |
252 | 0) | 254 | 0) |
253 | #define SYNC_INTERRUPTS ( \ | 255 | #define SYNC_INTERRUPTS ( \ |
254 | INT_MASK(INT_ITLB_MISS) | \ | 256 | (1ULL << INT_ITLB_MISS) | \ |
255 | INT_MASK(INT_ILL) | \ | 257 | (1ULL << INT_ILL) | \ |
256 | INT_MASK(INT_GPV) | \ | 258 | (1ULL << INT_GPV) | \ |
257 | INT_MASK(INT_SN_ACCESS) | \ | 259 | (1ULL << INT_SN_ACCESS) | \ |
258 | INT_MASK(INT_IDN_ACCESS) | \ | 260 | (1ULL << INT_IDN_ACCESS) | \ |
259 | INT_MASK(INT_UDN_ACCESS) | \ | 261 | (1ULL << INT_UDN_ACCESS) | \ |
260 | INT_MASK(INT_IDN_REFILL) | \ | 262 | (1ULL << INT_IDN_REFILL) | \ |
261 | INT_MASK(INT_UDN_REFILL) | \ | 263 | (1ULL << INT_UDN_REFILL) | \ |
262 | INT_MASK(INT_IDN_COMPLETE) | \ | 264 | (1ULL << INT_IDN_COMPLETE) | \ |
263 | INT_MASK(INT_UDN_COMPLETE) | \ | 265 | (1ULL << INT_UDN_COMPLETE) | \ |
264 | INT_MASK(INT_SWINT_3) | \ | 266 | (1ULL << INT_SWINT_3) | \ |
265 | INT_MASK(INT_SWINT_2) | \ | 267 | (1ULL << INT_SWINT_2) | \ |
266 | INT_MASK(INT_SWINT_1) | \ | 268 | (1ULL << INT_SWINT_1) | \ |
267 | INT_MASK(INT_SWINT_0) | \ | 269 | (1ULL << INT_SWINT_0) | \ |
268 | INT_MASK(INT_UNALIGN_DATA) | \ | 270 | (1ULL << INT_UNALIGN_DATA) | \ |
269 | INT_MASK(INT_DTLB_MISS) | \ | 271 | (1ULL << INT_DTLB_MISS) | \ |
270 | INT_MASK(INT_DTLB_ACCESS) | \ | 272 | (1ULL << INT_DTLB_ACCESS) | \ |
271 | INT_MASK(INT_SN_STATIC_ACCESS) | \ | 273 | (1ULL << INT_SN_STATIC_ACCESS) | \ |
272 | 0) | 274 | 0) |
273 | #define NON_SYNC_INTERRUPTS ( \ | 275 | #define NON_SYNC_INTERRUPTS ( \ |
274 | INT_MASK(INT_MEM_ERROR) | \ | 276 | (1ULL << INT_MEM_ERROR) | \ |
275 | INT_MASK(INT_DMATLB_MISS) | \ | 277 | (1ULL << INT_DMATLB_MISS) | \ |
276 | INT_MASK(INT_DMATLB_ACCESS) | \ | 278 | (1ULL << INT_DMATLB_ACCESS) | \ |
277 | INT_MASK(INT_SNITLB_MISS) | \ | 279 | (1ULL << INT_SNITLB_MISS) | \ |
278 | INT_MASK(INT_SN_NOTIFY) | \ | 280 | (1ULL << INT_SN_NOTIFY) | \ |
279 | INT_MASK(INT_SN_FIREWALL) | \ | 281 | (1ULL << INT_SN_FIREWALL) | \ |
280 | INT_MASK(INT_IDN_FIREWALL) | \ | 282 | (1ULL << INT_IDN_FIREWALL) | \ |
281 | INT_MASK(INT_UDN_FIREWALL) | \ | 283 | (1ULL << INT_UDN_FIREWALL) | \ |
282 | INT_MASK(INT_TILE_TIMER) | \ | 284 | (1ULL << INT_TILE_TIMER) | \ |
283 | INT_MASK(INT_IDN_TIMER) | \ | 285 | (1ULL << INT_IDN_TIMER) | \ |
284 | INT_MASK(INT_UDN_TIMER) | \ | 286 | (1ULL << INT_UDN_TIMER) | \ |
285 | INT_MASK(INT_DMA_NOTIFY) | \ | 287 | (1ULL << INT_DMA_NOTIFY) | \ |
286 | INT_MASK(INT_IDN_CA) | \ | 288 | (1ULL << INT_IDN_CA) | \ |
287 | INT_MASK(INT_UDN_CA) | \ | 289 | (1ULL << INT_UDN_CA) | \ |
288 | INT_MASK(INT_IDN_AVAIL) | \ | 290 | (1ULL << INT_IDN_AVAIL) | \ |
289 | INT_MASK(INT_UDN_AVAIL) | \ | 291 | (1ULL << INT_UDN_AVAIL) | \ |
290 | INT_MASK(INT_PERF_COUNT) | \ | 292 | (1ULL << INT_PERF_COUNT) | \ |
291 | INT_MASK(INT_INTCTRL_3) | \ | 293 | (1ULL << INT_INTCTRL_3) | \ |
292 | INT_MASK(INT_INTCTRL_2) | \ | 294 | (1ULL << INT_INTCTRL_2) | \ |
293 | INT_MASK(INT_INTCTRL_1) | \ | 295 | (1ULL << INT_INTCTRL_1) | \ |
294 | INT_MASK(INT_INTCTRL_0) | \ | 296 | (1ULL << INT_INTCTRL_0) | \ |
295 | INT_MASK(INT_BOOT_ACCESS) | \ | 297 | (1ULL << INT_BOOT_ACCESS) | \ |
296 | INT_MASK(INT_WORLD_ACCESS) | \ | 298 | (1ULL << INT_WORLD_ACCESS) | \ |
297 | INT_MASK(INT_I_ASID) | \ | 299 | (1ULL << INT_I_ASID) | \ |
298 | INT_MASK(INT_D_ASID) | \ | 300 | (1ULL << INT_D_ASID) | \ |
299 | INT_MASK(INT_DMA_ASID) | \ | 301 | (1ULL << INT_DMA_ASID) | \ |
300 | INT_MASK(INT_SNI_ASID) | \ | 302 | (1ULL << INT_SNI_ASID) | \ |
301 | INT_MASK(INT_DMA_CPL) | \ | 303 | (1ULL << INT_DMA_CPL) | \ |
302 | INT_MASK(INT_SN_CPL) | \ | 304 | (1ULL << INT_SN_CPL) | \ |
303 | INT_MASK(INT_DOUBLE_FAULT) | \ | 305 | (1ULL << INT_DOUBLE_FAULT) | \ |
304 | INT_MASK(INT_AUX_PERF_COUNT) | \ | 306 | (1ULL << INT_AUX_PERF_COUNT) | \ |
305 | 0) | 307 | 0) |
306 | #endif /* !__ASSEMBLER__ */ | 308 | #endif /* !__ASSEMBLER__ */ |
307 | #endif /* !__ARCH_INTERRUPTS_H__ */ | 309 | #endif /* !__ARCH_INTERRUPTS_H__ */ |
diff --git a/arch/tile/include/uapi/arch/interrupts_64.h b/arch/tile/include/uapi/arch/interrupts_64.h index 5bb58b2e4e6f..13c9f9182348 100644 --- a/arch/tile/include/uapi/arch/interrupts_64.h +++ b/arch/tile/include/uapi/arch/interrupts_64.h | |||
@@ -15,6 +15,7 @@ | |||
15 | #ifndef __ARCH_INTERRUPTS_H__ | 15 | #ifndef __ARCH_INTERRUPTS_H__ |
16 | #define __ARCH_INTERRUPTS_H__ | 16 | #define __ARCH_INTERRUPTS_H__ |
17 | 17 | ||
18 | #ifndef __KERNEL__ | ||
18 | /** Mask for an interrupt. */ | 19 | /** Mask for an interrupt. */ |
19 | #ifdef __ASSEMBLER__ | 20 | #ifdef __ASSEMBLER__ |
20 | /* Note: must handle breaking interrupts into high and low words manually. */ | 21 | /* Note: must handle breaking interrupts into high and low words manually. */ |
@@ -22,6 +23,7 @@ | |||
22 | #else | 23 | #else |
23 | #define INT_MASK(intno) (1ULL << (intno)) | 24 | #define INT_MASK(intno) (1ULL << (intno)) |
24 | #endif | 25 | #endif |
26 | #endif | ||
25 | 27 | ||
26 | 28 | ||
27 | /** Where a given interrupt executes */ | 29 | /** Where a given interrupt executes */ |
@@ -85,192 +87,192 @@ | |||
85 | 87 | ||
86 | #ifndef __ASSEMBLER__ | 88 | #ifndef __ASSEMBLER__ |
87 | #define QUEUED_INTERRUPTS ( \ | 89 | #define QUEUED_INTERRUPTS ( \ |
88 | INT_MASK(INT_MEM_ERROR) | \ | 90 | (1ULL << INT_MEM_ERROR) | \ |
89 | INT_MASK(INT_IDN_COMPLETE) | \ | 91 | (1ULL << INT_IDN_COMPLETE) | \ |
90 | INT_MASK(INT_UDN_COMPLETE) | \ | 92 | (1ULL << INT_UDN_COMPLETE) | \ |
91 | INT_MASK(INT_IDN_FIREWALL) | \ | 93 | (1ULL << INT_IDN_FIREWALL) | \ |
92 | INT_MASK(INT_UDN_FIREWALL) | \ | 94 | (1ULL << INT_UDN_FIREWALL) | \ |
93 | INT_MASK(INT_TILE_TIMER) | \ | 95 | (1ULL << INT_TILE_TIMER) | \ |
94 | INT_MASK(INT_AUX_TILE_TIMER) | \ | 96 | (1ULL << INT_AUX_TILE_TIMER) | \ |
95 | INT_MASK(INT_IDN_TIMER) | \ | 97 | (1ULL << INT_IDN_TIMER) | \ |
96 | INT_MASK(INT_UDN_TIMER) | \ | 98 | (1ULL << INT_UDN_TIMER) | \ |
97 | INT_MASK(INT_IDN_AVAIL) | \ | 99 | (1ULL << INT_IDN_AVAIL) | \ |
98 | INT_MASK(INT_UDN_AVAIL) | \ | 100 | (1ULL << INT_UDN_AVAIL) | \ |
99 | INT_MASK(INT_IPI_3) | \ | 101 | (1ULL << INT_IPI_3) | \ |
100 | INT_MASK(INT_IPI_2) | \ | 102 | (1ULL << INT_IPI_2) | \ |
101 | INT_MASK(INT_IPI_1) | \ | 103 | (1ULL << INT_IPI_1) | \ |
102 | INT_MASK(INT_IPI_0) | \ | 104 | (1ULL << INT_IPI_0) | \ |
103 | INT_MASK(INT_PERF_COUNT) | \ | 105 | (1ULL << INT_PERF_COUNT) | \ |
104 | INT_MASK(INT_AUX_PERF_COUNT) | \ | 106 | (1ULL << INT_AUX_PERF_COUNT) | \ |
105 | INT_MASK(INT_INTCTRL_3) | \ | 107 | (1ULL << INT_INTCTRL_3) | \ |
106 | INT_MASK(INT_INTCTRL_2) | \ | 108 | (1ULL << INT_INTCTRL_2) | \ |
107 | INT_MASK(INT_INTCTRL_1) | \ | 109 | (1ULL << INT_INTCTRL_1) | \ |
108 | INT_MASK(INT_INTCTRL_0) | \ | 110 | (1ULL << INT_INTCTRL_0) | \ |
109 | INT_MASK(INT_BOOT_ACCESS) | \ | 111 | (1ULL << INT_BOOT_ACCESS) | \ |
110 | INT_MASK(INT_WORLD_ACCESS) | \ | 112 | (1ULL << INT_WORLD_ACCESS) | \ |
111 | INT_MASK(INT_I_ASID) | \ | 113 | (1ULL << INT_I_ASID) | \ |
112 | INT_MASK(INT_D_ASID) | \ | 114 | (1ULL << INT_D_ASID) | \ |
113 | INT_MASK(INT_DOUBLE_FAULT) | \ | 115 | (1ULL << INT_DOUBLE_FAULT) | \ |
114 | 0) | 116 | 0) |
115 | #define NONQUEUED_INTERRUPTS ( \ | 117 | #define NONQUEUED_INTERRUPTS ( \ |
116 | INT_MASK(INT_SINGLE_STEP_3) | \ | 118 | (1ULL << INT_SINGLE_STEP_3) | \ |
117 | INT_MASK(INT_SINGLE_STEP_2) | \ | 119 | (1ULL << INT_SINGLE_STEP_2) | \ |
118 | INT_MASK(INT_SINGLE_STEP_1) | \ | 120 | (1ULL << INT_SINGLE_STEP_1) | \ |
119 | INT_MASK(INT_SINGLE_STEP_0) | \ | 121 | (1ULL << INT_SINGLE_STEP_0) | \ |
120 | INT_MASK(INT_ITLB_MISS) | \ | 122 | (1ULL << INT_ITLB_MISS) | \ |
121 | INT_MASK(INT_ILL) | \ | 123 | (1ULL << INT_ILL) | \ |
122 | INT_MASK(INT_GPV) | \ | 124 | (1ULL << INT_GPV) | \ |
123 | INT_MASK(INT_IDN_ACCESS) | \ | 125 | (1ULL << INT_IDN_ACCESS) | \ |
124 | INT_MASK(INT_UDN_ACCESS) | \ | 126 | (1ULL << INT_UDN_ACCESS) | \ |
125 | INT_MASK(INT_SWINT_3) | \ | 127 | (1ULL << INT_SWINT_3) | \ |
126 | INT_MASK(INT_SWINT_2) | \ | 128 | (1ULL << INT_SWINT_2) | \ |
127 | INT_MASK(INT_SWINT_1) | \ | 129 | (1ULL << INT_SWINT_1) | \ |
128 | INT_MASK(INT_SWINT_0) | \ | 130 | (1ULL << INT_SWINT_0) | \ |
129 | INT_MASK(INT_ILL_TRANS) | \ | 131 | (1ULL << INT_ILL_TRANS) | \ |
130 | INT_MASK(INT_UNALIGN_DATA) | \ | 132 | (1ULL << INT_UNALIGN_DATA) | \ |
131 | INT_MASK(INT_DTLB_MISS) | \ | 133 | (1ULL << INT_DTLB_MISS) | \ |
132 | INT_MASK(INT_DTLB_ACCESS) | \ | 134 | (1ULL << INT_DTLB_ACCESS) | \ |
133 | 0) | 135 | 0) |
134 | #define CRITICAL_MASKED_INTERRUPTS ( \ | 136 | #define CRITICAL_MASKED_INTERRUPTS ( \ |
135 | INT_MASK(INT_MEM_ERROR) | \ | 137 | (1ULL << INT_MEM_ERROR) | \ |
136 | INT_MASK(INT_SINGLE_STEP_3) | \ | 138 | (1ULL << INT_SINGLE_STEP_3) | \ |
137 | INT_MASK(INT_SINGLE_STEP_2) | \ | 139 | (1ULL << INT_SINGLE_STEP_2) | \ |
138 | INT_MASK(INT_SINGLE_STEP_1) | \ | 140 | (1ULL << INT_SINGLE_STEP_1) | \ |
139 | INT_MASK(INT_SINGLE_STEP_0) | \ | 141 | (1ULL << INT_SINGLE_STEP_0) | \ |
140 | INT_MASK(INT_IDN_COMPLETE) | \ | 142 | (1ULL << INT_IDN_COMPLETE) | \ |
141 | INT_MASK(INT_UDN_COMPLETE) | \ | 143 | (1ULL << INT_UDN_COMPLETE) | \ |
142 | INT_MASK(INT_IDN_FIREWALL) | \ | 144 | (1ULL << INT_IDN_FIREWALL) | \ |
143 | INT_MASK(INT_UDN_FIREWALL) | \ | 145 | (1ULL << INT_UDN_FIREWALL) | \ |
144 | INT_MASK(INT_TILE_TIMER) | \ | 146 | (1ULL << INT_TILE_TIMER) | \ |
145 | INT_MASK(INT_AUX_TILE_TIMER) | \ | 147 | (1ULL << INT_AUX_TILE_TIMER) | \ |
146 | INT_MASK(INT_IDN_TIMER) | \ | 148 | (1ULL << INT_IDN_TIMER) | \ |
147 | INT_MASK(INT_UDN_TIMER) | \ | 149 | (1ULL << INT_UDN_TIMER) | \ |
148 | INT_MASK(INT_IDN_AVAIL) | \ | 150 | (1ULL << INT_IDN_AVAIL) | \ |
149 | INT_MASK(INT_UDN_AVAIL) | \ | 151 | (1ULL << INT_UDN_AVAIL) | \ |
150 | INT_MASK(INT_IPI_3) | \ | 152 | (1ULL << INT_IPI_3) | \ |
151 | INT_MASK(INT_IPI_2) | \ | 153 | (1ULL << INT_IPI_2) | \ |
152 | INT_MASK(INT_IPI_1) | \ | 154 | (1ULL << INT_IPI_1) | \ |
153 | INT_MASK(INT_IPI_0) | \ | 155 | (1ULL << INT_IPI_0) | \ |
154 | INT_MASK(INT_PERF_COUNT) | \ | 156 | (1ULL << INT_PERF_COUNT) | \ |
155 | INT_MASK(INT_AUX_PERF_COUNT) | \ | 157 | (1ULL << INT_AUX_PERF_COUNT) | \ |
156 | INT_MASK(INT_INTCTRL_3) | \ | 158 | (1ULL << INT_INTCTRL_3) | \ |
157 | INT_MASK(INT_INTCTRL_2) | \ | 159 | (1ULL << INT_INTCTRL_2) | \ |
158 | INT_MASK(INT_INTCTRL_1) | \ | 160 | (1ULL << INT_INTCTRL_1) | \ |
159 | INT_MASK(INT_INTCTRL_0) | \ | 161 | (1ULL << INT_INTCTRL_0) | \ |
160 | 0) | 162 | 0) |
161 | #define CRITICAL_UNMASKED_INTERRUPTS ( \ | 163 | #define CRITICAL_UNMASKED_INTERRUPTS ( \ |
162 | INT_MASK(INT_ITLB_MISS) | \ | 164 | (1ULL << INT_ITLB_MISS) | \ |
163 | INT_MASK(INT_ILL) | \ | 165 | (1ULL << INT_ILL) | \ |
164 | INT_MASK(INT_GPV) | \ | 166 | (1ULL << INT_GPV) | \ |
165 | INT_MASK(INT_IDN_ACCESS) | \ | 167 | (1ULL << INT_IDN_ACCESS) | \ |
166 | INT_MASK(INT_UDN_ACCESS) | \ | 168 | (1ULL << INT_UDN_ACCESS) | \ |
167 | INT_MASK(INT_SWINT_3) | \ | 169 | (1ULL << INT_SWINT_3) | \ |
168 | INT_MASK(INT_SWINT_2) | \ | 170 | (1ULL << INT_SWINT_2) | \ |
169 | INT_MASK(INT_SWINT_1) | \ | 171 | (1ULL << INT_SWINT_1) | \ |
170 | INT_MASK(INT_SWINT_0) | \ | 172 | (1ULL << INT_SWINT_0) | \ |
171 | INT_MASK(INT_ILL_TRANS) | \ | 173 | (1ULL << INT_ILL_TRANS) | \ |
172 | INT_MASK(INT_UNALIGN_DATA) | \ | 174 | (1ULL << INT_UNALIGN_DATA) | \ |
173 | INT_MASK(INT_DTLB_MISS) | \ | 175 | (1ULL << INT_DTLB_MISS) | \ |
174 | INT_MASK(INT_DTLB_ACCESS) | \ | 176 | (1ULL << INT_DTLB_ACCESS) | \ |
175 | INT_MASK(INT_BOOT_ACCESS) | \ | 177 | (1ULL << INT_BOOT_ACCESS) | \ |
176 | INT_MASK(INT_WORLD_ACCESS) | \ | 178 | (1ULL << INT_WORLD_ACCESS) | \ |
177 | INT_MASK(INT_I_ASID) | \ | 179 | (1ULL << INT_I_ASID) | \ |
178 | INT_MASK(INT_D_ASID) | \ | 180 | (1ULL << INT_D_ASID) | \ |
179 | INT_MASK(INT_DOUBLE_FAULT) | \ | 181 | (1ULL << INT_DOUBLE_FAULT) | \ |
180 | 0) | 182 | 0) |
181 | #define MASKABLE_INTERRUPTS ( \ | 183 | #define MASKABLE_INTERRUPTS ( \ |
182 | INT_MASK(INT_MEM_ERROR) | \ | 184 | (1ULL << INT_MEM_ERROR) | \ |
183 | INT_MASK(INT_SINGLE_STEP_3) | \ | 185 | (1ULL << INT_SINGLE_STEP_3) | \ |
184 | INT_MASK(INT_SINGLE_STEP_2) | \ | 186 | (1ULL << INT_SINGLE_STEP_2) | \ |
185 | INT_MASK(INT_SINGLE_STEP_1) | \ | 187 | (1ULL << INT_SINGLE_STEP_1) | \ |
186 | INT_MASK(INT_SINGLE_STEP_0) | \ | 188 | (1ULL << INT_SINGLE_STEP_0) | \ |
187 | INT_MASK(INT_IDN_COMPLETE) | \ | 189 | (1ULL << INT_IDN_COMPLETE) | \ |
188 | INT_MASK(INT_UDN_COMPLETE) | \ | 190 | (1ULL << INT_UDN_COMPLETE) | \ |
189 | INT_MASK(INT_IDN_FIREWALL) | \ | 191 | (1ULL << INT_IDN_FIREWALL) | \ |
190 | INT_MASK(INT_UDN_FIREWALL) | \ | 192 | (1ULL << INT_UDN_FIREWALL) | \ |
191 | INT_MASK(INT_TILE_TIMER) | \ | 193 | (1ULL << INT_TILE_TIMER) | \ |
192 | INT_MASK(INT_AUX_TILE_TIMER) | \ | 194 | (1ULL << INT_AUX_TILE_TIMER) | \ |
193 | INT_MASK(INT_IDN_TIMER) | \ | 195 | (1ULL << INT_IDN_TIMER) | \ |
194 | INT_MASK(INT_UDN_TIMER) | \ | 196 | (1ULL << INT_UDN_TIMER) | \ |
195 | INT_MASK(INT_IDN_AVAIL) | \ | 197 | (1ULL << INT_IDN_AVAIL) | \ |
196 | INT_MASK(INT_UDN_AVAIL) | \ | 198 | (1ULL << INT_UDN_AVAIL) | \ |
197 | INT_MASK(INT_IPI_3) | \ | 199 | (1ULL << INT_IPI_3) | \ |
198 | INT_MASK(INT_IPI_2) | \ | 200 | (1ULL << INT_IPI_2) | \ |
199 | INT_MASK(INT_IPI_1) | \ | 201 | (1ULL << INT_IPI_1) | \ |
200 | INT_MASK(INT_IPI_0) | \ | 202 | (1ULL << INT_IPI_0) | \ |
201 | INT_MASK(INT_PERF_COUNT) | \ | 203 | (1ULL << INT_PERF_COUNT) | \ |
202 | INT_MASK(INT_AUX_PERF_COUNT) | \ | 204 | (1ULL << INT_AUX_PERF_COUNT) | \ |
203 | INT_MASK(INT_INTCTRL_3) | \ | 205 | (1ULL << INT_INTCTRL_3) | \ |
204 | INT_MASK(INT_INTCTRL_2) | \ | 206 | (1ULL << INT_INTCTRL_2) | \ |
205 | INT_MASK(INT_INTCTRL_1) | \ | 207 | (1ULL << INT_INTCTRL_1) | \ |
206 | INT_MASK(INT_INTCTRL_0) | \ | 208 | (1ULL << INT_INTCTRL_0) | \ |
207 | 0) | 209 | 0) |
208 | #define UNMASKABLE_INTERRUPTS ( \ | 210 | #define UNMASKABLE_INTERRUPTS ( \ |
209 | INT_MASK(INT_ITLB_MISS) | \ | 211 | (1ULL << INT_ITLB_MISS) | \ |
210 | INT_MASK(INT_ILL) | \ | 212 | (1ULL << INT_ILL) | \ |
211 | INT_MASK(INT_GPV) | \ | 213 | (1ULL << INT_GPV) | \ |
212 | INT_MASK(INT_IDN_ACCESS) | \ | 214 | (1ULL << INT_IDN_ACCESS) | \ |
213 | INT_MASK(INT_UDN_ACCESS) | \ | 215 | (1ULL << INT_UDN_ACCESS) | \ |
214 | INT_MASK(INT_SWINT_3) | \ | 216 | (1ULL << INT_SWINT_3) | \ |
215 | INT_MASK(INT_SWINT_2) | \ | 217 | (1ULL << INT_SWINT_2) | \ |
216 | INT_MASK(INT_SWINT_1) | \ | 218 | (1ULL << INT_SWINT_1) | \ |
217 | INT_MASK(INT_SWINT_0) | \ | 219 | (1ULL << INT_SWINT_0) | \ |
218 | INT_MASK(INT_ILL_TRANS) | \ | 220 | (1ULL << INT_ILL_TRANS) | \ |
219 | INT_MASK(INT_UNALIGN_DATA) | \ | 221 | (1ULL << INT_UNALIGN_DATA) | \ |
220 | INT_MASK(INT_DTLB_MISS) | \ | 222 | (1ULL << INT_DTLB_MISS) | \ |
221 | INT_MASK(INT_DTLB_ACCESS) | \ | 223 | (1ULL << INT_DTLB_ACCESS) | \ |
222 | INT_MASK(INT_BOOT_ACCESS) | \ | 224 | (1ULL << INT_BOOT_ACCESS) | \ |
223 | INT_MASK(INT_WORLD_ACCESS) | \ | 225 | (1ULL << INT_WORLD_ACCESS) | \ |
224 | INT_MASK(INT_I_ASID) | \ | 226 | (1ULL << INT_I_ASID) | \ |
225 | INT_MASK(INT_D_ASID) | \ | 227 | (1ULL << INT_D_ASID) | \ |
226 | INT_MASK(INT_DOUBLE_FAULT) | \ | 228 | (1ULL << INT_DOUBLE_FAULT) | \ |
227 | 0) | 229 | 0) |
228 | #define SYNC_INTERRUPTS ( \ | 230 | #define SYNC_INTERRUPTS ( \ |
229 | INT_MASK(INT_SINGLE_STEP_3) | \ | 231 | (1ULL << INT_SINGLE_STEP_3) | \ |
230 | INT_MASK(INT_SINGLE_STEP_2) | \ | 232 | (1ULL << INT_SINGLE_STEP_2) | \ |
231 | INT_MASK(INT_SINGLE_STEP_1) | \ | 233 | (1ULL << INT_SINGLE_STEP_1) | \ |
232 | INT_MASK(INT_SINGLE_STEP_0) | \ | 234 | (1ULL << INT_SINGLE_STEP_0) | \ |
233 | INT_MASK(INT_IDN_COMPLETE) | \ | 235 | (1ULL << INT_IDN_COMPLETE) | \ |
234 | INT_MASK(INT_UDN_COMPLETE) | \ | 236 | (1ULL << INT_UDN_COMPLETE) | \ |
235 | INT_MASK(INT_ITLB_MISS) | \ | 237 | (1ULL << INT_ITLB_MISS) | \ |
236 | INT_MASK(INT_ILL) | \ | 238 | (1ULL << INT_ILL) | \ |
237 | INT_MASK(INT_GPV) | \ | 239 | (1ULL << INT_GPV) | \ |
238 | INT_MASK(INT_IDN_ACCESS) | \ | 240 | (1ULL << INT_IDN_ACCESS) | \ |
239 | INT_MASK(INT_UDN_ACCESS) | \ | 241 | (1ULL << INT_UDN_ACCESS) | \ |
240 | INT_MASK(INT_SWINT_3) | \ | 242 | (1ULL << INT_SWINT_3) | \ |
241 | INT_MASK(INT_SWINT_2) | \ | 243 | (1ULL << INT_SWINT_2) | \ |
242 | INT_MASK(INT_SWINT_1) | \ | 244 | (1ULL << INT_SWINT_1) | \ |
243 | INT_MASK(INT_SWINT_0) | \ | 245 | (1ULL << INT_SWINT_0) | \ |
244 | INT_MASK(INT_ILL_TRANS) | \ | 246 | (1ULL << INT_ILL_TRANS) | \ |
245 | INT_MASK(INT_UNALIGN_DATA) | \ | 247 | (1ULL << INT_UNALIGN_DATA) | \ |
246 | INT_MASK(INT_DTLB_MISS) | \ | 248 | (1ULL << INT_DTLB_MISS) | \ |
247 | INT_MASK(INT_DTLB_ACCESS) | \ | 249 | (1ULL << INT_DTLB_ACCESS) | \ |
248 | 0) | 250 | 0) |
249 | #define NON_SYNC_INTERRUPTS ( \ | 251 | #define NON_SYNC_INTERRUPTS ( \ |
250 | INT_MASK(INT_MEM_ERROR) | \ | 252 | (1ULL << INT_MEM_ERROR) | \ |
251 | INT_MASK(INT_IDN_FIREWALL) | \ | 253 | (1ULL << INT_IDN_FIREWALL) | \ |
252 | INT_MASK(INT_UDN_FIREWALL) | \ | 254 | (1ULL << INT_UDN_FIREWALL) | \ |
253 | INT_MASK(INT_TILE_TIMER) | \ | 255 | (1ULL << INT_TILE_TIMER) | \ |
254 | INT_MASK(INT_AUX_TILE_TIMER) | \ | 256 | (1ULL << INT_AUX_TILE_TIMER) | \ |
255 | INT_MASK(INT_IDN_TIMER) | \ | 257 | (1ULL << INT_IDN_TIMER) | \ |
256 | INT_MASK(INT_UDN_TIMER) | \ | 258 | (1ULL << INT_UDN_TIMER) | \ |
257 | INT_MASK(INT_IDN_AVAIL) | \ | 259 | (1ULL << INT_IDN_AVAIL) | \ |
258 | INT_MASK(INT_UDN_AVAIL) | \ | 260 | (1ULL << INT_UDN_AVAIL) | \ |
259 | INT_MASK(INT_IPI_3) | \ | 261 | (1ULL << INT_IPI_3) | \ |
260 | INT_MASK(INT_IPI_2) | \ | 262 | (1ULL << INT_IPI_2) | \ |
261 | INT_MASK(INT_IPI_1) | \ | 263 | (1ULL << INT_IPI_1) | \ |
262 | INT_MASK(INT_IPI_0) | \ | 264 | (1ULL << INT_IPI_0) | \ |
263 | INT_MASK(INT_PERF_COUNT) | \ | 265 | (1ULL << INT_PERF_COUNT) | \ |
264 | INT_MASK(INT_AUX_PERF_COUNT) | \ | 266 | (1ULL << INT_AUX_PERF_COUNT) | \ |
265 | INT_MASK(INT_INTCTRL_3) | \ | 267 | (1ULL << INT_INTCTRL_3) | \ |
266 | INT_MASK(INT_INTCTRL_2) | \ | 268 | (1ULL << INT_INTCTRL_2) | \ |
267 | INT_MASK(INT_INTCTRL_1) | \ | 269 | (1ULL << INT_INTCTRL_1) | \ |
268 | INT_MASK(INT_INTCTRL_0) | \ | 270 | (1ULL << INT_INTCTRL_0) | \ |
269 | INT_MASK(INT_BOOT_ACCESS) | \ | 271 | (1ULL << INT_BOOT_ACCESS) | \ |
270 | INT_MASK(INT_WORLD_ACCESS) | \ | 272 | (1ULL << INT_WORLD_ACCESS) | \ |
271 | INT_MASK(INT_I_ASID) | \ | 273 | (1ULL << INT_I_ASID) | \ |
272 | INT_MASK(INT_D_ASID) | \ | 274 | (1ULL << INT_D_ASID) | \ |
273 | INT_MASK(INT_DOUBLE_FAULT) | \ | 275 | (1ULL << INT_DOUBLE_FAULT) | \ |
274 | 0) | 276 | 0) |
275 | #endif /* !__ASSEMBLER__ */ | 277 | #endif /* !__ASSEMBLER__ */ |
276 | #endif /* !__ARCH_INTERRUPTS_H__ */ | 278 | #endif /* !__ARCH_INTERRUPTS_H__ */ |
diff --git a/arch/tile/kernel/intvec_64.S b/arch/tile/kernel/intvec_64.S index 54bc9a6678e8..4ea080902654 100644 --- a/arch/tile/kernel/intvec_64.S +++ b/arch/tile/kernel/intvec_64.S | |||
@@ -1035,7 +1035,9 @@ handle_syscall: | |||
1035 | /* Ensure that the syscall number is within the legal range. */ | 1035 | /* Ensure that the syscall number is within the legal range. */ |
1036 | { | 1036 | { |
1037 | moveli r20, hw2(sys_call_table) | 1037 | moveli r20, hw2(sys_call_table) |
1038 | #ifdef CONFIG_COMPAT | ||
1038 | blbs r30, .Lcompat_syscall | 1039 | blbs r30, .Lcompat_syscall |
1040 | #endif | ||
1039 | } | 1041 | } |
1040 | { | 1042 | { |
1041 | cmpltu r21, TREG_SYSCALL_NR_NAME, r21 | 1043 | cmpltu r21, TREG_SYSCALL_NR_NAME, r21 |
@@ -1093,6 +1095,7 @@ handle_syscall: | |||
1093 | j .Lresume_userspace /* jump into middle of interrupt_return */ | 1095 | j .Lresume_userspace /* jump into middle of interrupt_return */ |
1094 | } | 1096 | } |
1095 | 1097 | ||
1098 | #ifdef CONFIG_COMPAT | ||
1096 | .Lcompat_syscall: | 1099 | .Lcompat_syscall: |
1097 | /* | 1100 | /* |
1098 | * Load the base of the compat syscall table in r20, and | 1101 | * Load the base of the compat syscall table in r20, and |
@@ -1117,6 +1120,7 @@ handle_syscall: | |||
1117 | { move r15, r4; addxi r4, r4, 0 } | 1120 | { move r15, r4; addxi r4, r4, 0 } |
1118 | { move r16, r5; addxi r5, r5, 0 } | 1121 | { move r16, r5; addxi r5, r5, 0 } |
1119 | j .Lload_syscall_pointer | 1122 | j .Lload_syscall_pointer |
1123 | #endif | ||
1120 | 1124 | ||
1121 | .Linvalid_syscall: | 1125 | .Linvalid_syscall: |
1122 | /* Report an invalid syscall back to the user program */ | 1126 | /* Report an invalid syscall back to the user program */ |
diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c index 0e5661e7d00d..caf93ae11793 100644 --- a/arch/tile/kernel/process.c +++ b/arch/tile/kernel/process.c | |||
@@ -159,7 +159,7 @@ static void save_arch_state(struct thread_struct *t); | |||
159 | int copy_thread(unsigned long clone_flags, unsigned long sp, | 159 | int copy_thread(unsigned long clone_flags, unsigned long sp, |
160 | unsigned long arg, struct task_struct *p) | 160 | unsigned long arg, struct task_struct *p) |
161 | { | 161 | { |
162 | struct pt_regs *childregs = task_pt_regs(p), *regs = current_pt_regs(); | 162 | struct pt_regs *childregs = task_pt_regs(p); |
163 | unsigned long ksp; | 163 | unsigned long ksp; |
164 | unsigned long *callee_regs; | 164 | unsigned long *callee_regs; |
165 | 165 | ||
diff --git a/arch/tile/kernel/reboot.c b/arch/tile/kernel/reboot.c index baa3d905fee2..d1b5c913ae72 100644 --- a/arch/tile/kernel/reboot.c +++ b/arch/tile/kernel/reboot.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/reboot.h> | 16 | #include <linux/reboot.h> |
17 | #include <linux/smp.h> | 17 | #include <linux/smp.h> |
18 | #include <linux/pm.h> | 18 | #include <linux/pm.h> |
19 | #include <linux/export.h> | ||
19 | #include <asm/page.h> | 20 | #include <asm/page.h> |
20 | #include <asm/setup.h> | 21 | #include <asm/setup.h> |
21 | #include <hv/hypervisor.h> | 22 | #include <hv/hypervisor.h> |
@@ -49,3 +50,4 @@ void machine_restart(char *cmd) | |||
49 | 50 | ||
50 | /* No interesting distinction to be made here. */ | 51 | /* No interesting distinction to be made here. */ |
51 | void (*pm_power_off)(void) = NULL; | 52 | void (*pm_power_off)(void) = NULL; |
53 | EXPORT_SYMBOL(pm_power_off); | ||
diff --git a/arch/tile/kernel/setup.c b/arch/tile/kernel/setup.c index 6a649a4462d3..d1e15f7b59c6 100644 --- a/arch/tile/kernel/setup.c +++ b/arch/tile/kernel/setup.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/timex.h> | 31 | #include <linux/timex.h> |
32 | #include <linux/hugetlb.h> | 32 | #include <linux/hugetlb.h> |
33 | #include <linux/start_kernel.h> | 33 | #include <linux/start_kernel.h> |
34 | #include <linux/screen_info.h> | ||
34 | #include <asm/setup.h> | 35 | #include <asm/setup.h> |
35 | #include <asm/sections.h> | 36 | #include <asm/sections.h> |
36 | #include <asm/cacheflush.h> | 37 | #include <asm/cacheflush.h> |
@@ -49,6 +50,10 @@ static inline int ABS(int x) { return x >= 0 ? x : -x; } | |||
49 | /* Chip information */ | 50 | /* Chip information */ |
50 | char chip_model[64] __write_once; | 51 | char chip_model[64] __write_once; |
51 | 52 | ||
53 | #ifdef CONFIG_VT | ||
54 | struct screen_info screen_info; | ||
55 | #endif | ||
56 | |||
52 | struct pglist_data node_data[MAX_NUMNODES] __read_mostly; | 57 | struct pglist_data node_data[MAX_NUMNODES] __read_mostly; |
53 | EXPORT_SYMBOL(node_data); | 58 | EXPORT_SYMBOL(node_data); |
54 | 59 | ||
diff --git a/arch/tile/kernel/stack.c b/arch/tile/kernel/stack.c index b2f44c28dda6..ed258b8ae320 100644 --- a/arch/tile/kernel/stack.c +++ b/arch/tile/kernel/stack.c | |||
@@ -112,7 +112,7 @@ static struct pt_regs *valid_fault_handler(struct KBacktraceIterator* kbt) | |||
112 | p->pc, p->sp, p->ex1); | 112 | p->pc, p->sp, p->ex1); |
113 | p = NULL; | 113 | p = NULL; |
114 | } | 114 | } |
115 | if (!kbt->profile || (INT_MASK(p->faultnum) & QUEUED_INTERRUPTS) == 0) | 115 | if (!kbt->profile || ((1ULL << p->faultnum) & QUEUED_INTERRUPTS) == 0) |
116 | return p; | 116 | return p; |
117 | return NULL; | 117 | return NULL; |
118 | } | 118 | } |
@@ -484,6 +484,7 @@ void save_stack_trace(struct stack_trace *trace) | |||
484 | { | 484 | { |
485 | save_stack_trace_tsk(NULL, trace); | 485 | save_stack_trace_tsk(NULL, trace); |
486 | } | 486 | } |
487 | EXPORT_SYMBOL_GPL(save_stack_trace); | ||
487 | 488 | ||
488 | #endif | 489 | #endif |
489 | 490 | ||
diff --git a/arch/tile/lib/cacheflush.c b/arch/tile/lib/cacheflush.c index db4fb89e12d8..8f8ad814b139 100644 --- a/arch/tile/lib/cacheflush.c +++ b/arch/tile/lib/cacheflush.c | |||
@@ -12,6 +12,7 @@ | |||
12 | * more details. | 12 | * more details. |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/export.h> | ||
15 | #include <asm/page.h> | 16 | #include <asm/page.h> |
16 | #include <asm/cacheflush.h> | 17 | #include <asm/cacheflush.h> |
17 | #include <arch/icache.h> | 18 | #include <arch/icache.h> |
@@ -165,3 +166,4 @@ void finv_buffer_remote(void *buffer, size_t size, int hfh) | |||
165 | __insn_mtspr(SPR_DSTREAM_PF, old_dstream_pf); | 166 | __insn_mtspr(SPR_DSTREAM_PF, old_dstream_pf); |
166 | #endif | 167 | #endif |
167 | } | 168 | } |
169 | EXPORT_SYMBOL_GPL(finv_buffer_remote); | ||
diff --git a/arch/tile/lib/cpumask.c b/arch/tile/lib/cpumask.c index fdc403614d12..75947edccb26 100644 --- a/arch/tile/lib/cpumask.c +++ b/arch/tile/lib/cpumask.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/ctype.h> | 16 | #include <linux/ctype.h> |
17 | #include <linux/errno.h> | 17 | #include <linux/errno.h> |
18 | #include <linux/smp.h> | 18 | #include <linux/smp.h> |
19 | #include <linux/export.h> | ||
19 | 20 | ||
20 | /* | 21 | /* |
21 | * Allow cropping out bits beyond the end of the array. | 22 | * Allow cropping out bits beyond the end of the array. |
@@ -50,3 +51,4 @@ int bitmap_parselist_crop(const char *bp, unsigned long *maskp, int nmaskbits) | |||
50 | } while (*bp != '\0' && *bp != '\n'); | 51 | } while (*bp != '\0' && *bp != '\n'); |
51 | return 0; | 52 | return 0; |
52 | } | 53 | } |
54 | EXPORT_SYMBOL(bitmap_parselist_crop); | ||
diff --git a/arch/tile/lib/exports.c b/arch/tile/lib/exports.c index dd5f0a33fdaf..4385cb6fa00a 100644 --- a/arch/tile/lib/exports.c +++ b/arch/tile/lib/exports.c | |||
@@ -55,6 +55,8 @@ EXPORT_SYMBOL(hv_dev_poll_cancel); | |||
55 | EXPORT_SYMBOL(hv_dev_close); | 55 | EXPORT_SYMBOL(hv_dev_close); |
56 | EXPORT_SYMBOL(hv_sysconf); | 56 | EXPORT_SYMBOL(hv_sysconf); |
57 | EXPORT_SYMBOL(hv_confstr); | 57 | EXPORT_SYMBOL(hv_confstr); |
58 | EXPORT_SYMBOL(hv_get_rtc); | ||
59 | EXPORT_SYMBOL(hv_set_rtc); | ||
58 | 60 | ||
59 | /* libgcc.a */ | 61 | /* libgcc.a */ |
60 | uint32_t __udivsi3(uint32_t dividend, uint32_t divisor); | 62 | uint32_t __udivsi3(uint32_t dividend, uint32_t divisor); |
diff --git a/arch/tile/mm/homecache.c b/arch/tile/mm/homecache.c index 5f7868dcd6d4..1ae911939a18 100644 --- a/arch/tile/mm/homecache.c +++ b/arch/tile/mm/homecache.c | |||
@@ -408,6 +408,7 @@ void homecache_change_page_home(struct page *page, int order, int home) | |||
408 | __set_pte(ptep, pte_set_home(pteval, home)); | 408 | __set_pte(ptep, pte_set_home(pteval, home)); |
409 | } | 409 | } |
410 | } | 410 | } |
411 | EXPORT_SYMBOL(homecache_change_page_home); | ||
411 | 412 | ||
412 | struct page *homecache_alloc_pages(gfp_t gfp_mask, | 413 | struct page *homecache_alloc_pages(gfp_t gfp_mask, |
413 | unsigned int order, int home) | 414 | unsigned int order, int home) |
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 225543bf45a5..260857a53b87 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
@@ -1,7 +1,7 @@ | |||
1 | # Select 32 or 64 bit | 1 | # Select 32 or 64 bit |
2 | config 64BIT | 2 | config 64BIT |
3 | bool "64-bit kernel" if ARCH = "x86" | 3 | bool "64-bit kernel" if ARCH = "x86" |
4 | default ARCH = "x86_64" | 4 | default ARCH != "i386" |
5 | ---help--- | 5 | ---help--- |
6 | Say yes to build a 64-bit kernel - formerly known as x86_64 | 6 | Say yes to build a 64-bit kernel - formerly known as x86_64 |
7 | Say no to build a 32-bit kernel - formerly known as i386 | 7 | Say no to build a 32-bit kernel - formerly known as i386 |
@@ -28,7 +28,6 @@ config X86 | |||
28 | select HAVE_OPROFILE | 28 | select HAVE_OPROFILE |
29 | select HAVE_PCSPKR_PLATFORM | 29 | select HAVE_PCSPKR_PLATFORM |
30 | select HAVE_PERF_EVENTS | 30 | select HAVE_PERF_EVENTS |
31 | select HAVE_IRQ_WORK | ||
32 | select HAVE_IOREMAP_PROT | 31 | select HAVE_IOREMAP_PROT |
33 | select HAVE_KPROBES | 32 | select HAVE_KPROBES |
34 | select HAVE_MEMBLOCK | 33 | select HAVE_MEMBLOCK |
@@ -40,10 +39,12 @@ config X86 | |||
40 | select HAVE_DMA_CONTIGUOUS if !SWIOTLB | 39 | select HAVE_DMA_CONTIGUOUS if !SWIOTLB |
41 | select HAVE_KRETPROBES | 40 | select HAVE_KRETPROBES |
42 | select HAVE_OPTPROBES | 41 | select HAVE_OPTPROBES |
42 | select HAVE_KPROBES_ON_FTRACE | ||
43 | select HAVE_FTRACE_MCOUNT_RECORD | 43 | select HAVE_FTRACE_MCOUNT_RECORD |
44 | select HAVE_FENTRY if X86_64 | 44 | select HAVE_FENTRY if X86_64 |
45 | select HAVE_C_RECORDMCOUNT | 45 | select HAVE_C_RECORDMCOUNT |
46 | select HAVE_DYNAMIC_FTRACE | 46 | select HAVE_DYNAMIC_FTRACE |
47 | select HAVE_DYNAMIC_FTRACE_WITH_REGS | ||
47 | select HAVE_FUNCTION_TRACER | 48 | select HAVE_FUNCTION_TRACER |
48 | select HAVE_FUNCTION_GRAPH_TRACER | 49 | select HAVE_FUNCTION_GRAPH_TRACER |
49 | select HAVE_FUNCTION_GRAPH_FP_TEST | 50 | select HAVE_FUNCTION_GRAPH_FP_TEST |
@@ -106,6 +107,7 @@ config X86 | |||
106 | select GENERIC_CLOCKEVENTS_BROADCAST if X86_64 || (X86_32 && X86_LOCAL_APIC) | 107 | select GENERIC_CLOCKEVENTS_BROADCAST if X86_64 || (X86_32 && X86_LOCAL_APIC) |
107 | select GENERIC_TIME_VSYSCALL if X86_64 | 108 | select GENERIC_TIME_VSYSCALL if X86_64 |
108 | select KTIME_SCALAR if X86_32 | 109 | select KTIME_SCALAR if X86_32 |
110 | select ALWAYS_USE_PERSISTENT_CLOCK | ||
109 | select GENERIC_STRNCPY_FROM_USER | 111 | select GENERIC_STRNCPY_FROM_USER |
110 | select GENERIC_STRNLEN_USER | 112 | select GENERIC_STRNLEN_USER |
111 | select HAVE_CONTEXT_TRACKING if X86_64 | 113 | select HAVE_CONTEXT_TRACKING if X86_64 |
@@ -114,6 +116,7 @@ config X86 | |||
114 | select MODULES_USE_ELF_RELA if X86_64 | 116 | select MODULES_USE_ELF_RELA if X86_64 |
115 | select CLONE_BACKWARDS if X86_32 | 117 | select CLONE_BACKWARDS if X86_32 |
116 | select GENERIC_SIGALTSTACK | 118 | select GENERIC_SIGALTSTACK |
119 | select ARCH_USE_BUILTIN_BSWAP | ||
117 | 120 | ||
118 | config INSTRUCTION_DECODER | 121 | config INSTRUCTION_DECODER |
119 | def_bool y | 122 | def_bool y |
@@ -320,6 +323,10 @@ config X86_BIGSMP | |||
320 | ---help--- | 323 | ---help--- |
321 | This option is needed for the systems that have more than 8 CPUs | 324 | This option is needed for the systems that have more than 8 CPUs |
322 | 325 | ||
326 | config GOLDFISH | ||
327 | def_bool y | ||
328 | depends on X86_GOLDFISH | ||
329 | |||
323 | if X86_32 | 330 | if X86_32 |
324 | config X86_EXTENDED_PLATFORM | 331 | config X86_EXTENDED_PLATFORM |
325 | bool "Support for extended (non-PC) x86 platforms" | 332 | bool "Support for extended (non-PC) x86 platforms" |
@@ -402,6 +409,14 @@ config X86_UV | |||
402 | # Following is an alphabetically sorted list of 32 bit extended platforms | 409 | # Following is an alphabetically sorted list of 32 bit extended platforms |
403 | # Please maintain the alphabetic order if and when there are additions | 410 | # Please maintain the alphabetic order if and when there are additions |
404 | 411 | ||
412 | config X86_GOLDFISH | ||
413 | bool "Goldfish (Virtual Platform)" | ||
414 | depends on X86_32 | ||
415 | ---help--- | ||
416 | Enable support for the Goldfish virtual platform used primarily | ||
417 | for Android development. Unless you are building for the Android | ||
418 | Goldfish emulator say N here. | ||
419 | |||
405 | config X86_INTEL_CE | 420 | config X86_INTEL_CE |
406 | bool "CE4100 TV platform" | 421 | bool "CE4100 TV platform" |
407 | depends on PCI | 422 | depends on PCI |
@@ -2188,6 +2203,15 @@ config GEOS | |||
2188 | ---help--- | 2203 | ---help--- |
2189 | This option enables system support for the Traverse Technologies GEOS. | 2204 | This option enables system support for the Traverse Technologies GEOS. |
2190 | 2205 | ||
2206 | config TS5500 | ||
2207 | bool "Technologic Systems TS-5500 platform support" | ||
2208 | depends on MELAN | ||
2209 | select CHECK_SIGNATURE | ||
2210 | select NEW_LEDS | ||
2211 | select LEDS_CLASS | ||
2212 | ---help--- | ||
2213 | This option enables system support for the Technologic Systems TS-5500. | ||
2214 | |||
2191 | endif # X86_32 | 2215 | endif # X86_32 |
2192 | 2216 | ||
2193 | config AMD_NB | 2217 | config AMD_NB |
diff --git a/arch/x86/Makefile b/arch/x86/Makefile index e71fc4279aab..5c477260294f 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile | |||
@@ -2,7 +2,11 @@ | |||
2 | 2 | ||
3 | # select defconfig based on actual architecture | 3 | # select defconfig based on actual architecture |
4 | ifeq ($(ARCH),x86) | 4 | ifeq ($(ARCH),x86) |
5 | ifeq ($(shell uname -m),x86_64) | ||
6 | KBUILD_DEFCONFIG := x86_64_defconfig | ||
7 | else | ||
5 | KBUILD_DEFCONFIG := i386_defconfig | 8 | KBUILD_DEFCONFIG := i386_defconfig |
9 | endif | ||
6 | else | 10 | else |
7 | KBUILD_DEFCONFIG := $(ARCH)_defconfig | 11 | KBUILD_DEFCONFIG := $(ARCH)_defconfig |
8 | endif | 12 | endif |
diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c index 88f7ff6da404..7cb56c6ca351 100644 --- a/arch/x86/boot/compressed/misc.c +++ b/arch/x86/boot/compressed/misc.c | |||
@@ -325,6 +325,8 @@ asmlinkage void decompress_kernel(void *rmode, memptr heap, | |||
325 | { | 325 | { |
326 | real_mode = rmode; | 326 | real_mode = rmode; |
327 | 327 | ||
328 | sanitize_boot_params(real_mode); | ||
329 | |||
328 | if (real_mode->screen_info.orig_video_mode == 7) { | 330 | if (real_mode->screen_info.orig_video_mode == 7) { |
329 | vidmem = (char *) 0xb0000; | 331 | vidmem = (char *) 0xb0000; |
330 | vidport = 0x3b4; | 332 | vidport = 0x3b4; |
diff --git a/arch/x86/boot/compressed/misc.h b/arch/x86/boot/compressed/misc.h index 0e6dc0ee0eea..674019d8e235 100644 --- a/arch/x86/boot/compressed/misc.h +++ b/arch/x86/boot/compressed/misc.h | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <asm/page.h> | 18 | #include <asm/page.h> |
19 | #include <asm/boot.h> | 19 | #include <asm/boot.h> |
20 | #include <asm/bootparam.h> | 20 | #include <asm/bootparam.h> |
21 | #include <asm/bootparam_utils.h> | ||
21 | 22 | ||
22 | #define BOOT_BOOT_H | 23 | #define BOOT_BOOT_H |
23 | #include "../ctype.h" | 24 | #include "../ctype.h" |
diff --git a/arch/x86/configs/i386_defconfig b/arch/x86/configs/i386_defconfig index 5598547281a7..94447086e551 100644 --- a/arch/x86/configs/i386_defconfig +++ b/arch/x86/configs/i386_defconfig | |||
@@ -1,3 +1,4 @@ | |||
1 | # CONFIG_64BIT is not set | ||
1 | CONFIG_EXPERIMENTAL=y | 2 | CONFIG_EXPERIMENTAL=y |
2 | # CONFIG_LOCALVERSION_AUTO is not set | 3 | # CONFIG_LOCALVERSION_AUTO is not set |
3 | CONFIG_SYSVIPC=y | 4 | CONFIG_SYSVIPC=y |
diff --git a/arch/x86/include/asm/amd_nb.h b/arch/x86/include/asm/amd_nb.h index b3341e9cd8fd..a54ee1d054d9 100644 --- a/arch/x86/include/asm/amd_nb.h +++ b/arch/x86/include/asm/amd_nb.h | |||
@@ -81,6 +81,23 @@ static inline struct amd_northbridge *node_to_amd_nb(int node) | |||
81 | return (node < amd_northbridges.num) ? &amd_northbridges.nb[node] : NULL; | 81 | return (node < amd_northbridges.num) ? &amd_northbridges.nb[node] : NULL; |
82 | } | 82 | } |
83 | 83 | ||
84 | static inline u16 amd_get_node_id(struct pci_dev *pdev) | ||
85 | { | ||
86 | struct pci_dev *misc; | ||
87 | int i; | ||
88 | |||
89 | for (i = 0; i != amd_nb_num(); i++) { | ||
90 | misc = node_to_amd_nb(i)->misc; | ||
91 | |||
92 | if (pci_domain_nr(misc->bus) == pci_domain_nr(pdev->bus) && | ||
93 | PCI_SLOT(misc->devfn) == PCI_SLOT(pdev->devfn)) | ||
94 | return i; | ||
95 | } | ||
96 | |||
97 | WARN(1, "Unable to find AMD Northbridge id for %s\n", pci_name(pdev)); | ||
98 | return 0; | ||
99 | } | ||
100 | |||
84 | #else | 101 | #else |
85 | 102 | ||
86 | #define amd_nb_num(x) 0 | 103 | #define amd_nb_num(x) 0 |
diff --git a/arch/x86/include/asm/bootparam_utils.h b/arch/x86/include/asm/bootparam_utils.h new file mode 100644 index 000000000000..5b5e9cb774b5 --- /dev/null +++ b/arch/x86/include/asm/bootparam_utils.h | |||
@@ -0,0 +1,38 @@ | |||
1 | #ifndef _ASM_X86_BOOTPARAM_UTILS_H | ||
2 | #define _ASM_X86_BOOTPARAM_UTILS_H | ||
3 | |||
4 | #include <asm/bootparam.h> | ||
5 | |||
6 | /* | ||
7 | * This file is included from multiple environments. Do not | ||
8 | * add completing #includes to make it standalone. | ||
9 | */ | ||
10 | |||
11 | /* | ||
12 | * Deal with bootloaders which fail to initialize unknown fields in | ||
13 | * boot_params to zero. The list fields in this list are taken from | ||
14 | * analysis of kexec-tools; if other broken bootloaders initialize a | ||
15 | * different set of fields we will need to figure out how to disambiguate. | ||
16 | * | ||
17 | */ | ||
18 | static void sanitize_boot_params(struct boot_params *boot_params) | ||
19 | { | ||
20 | if (boot_params->sentinel) { | ||
21 | /*fields in boot_params are not valid, clear them */ | ||
22 | memset(&boot_params->olpc_ofw_header, 0, | ||
23 | (char *)&boot_params->alt_mem_k - | ||
24 | (char *)&boot_params->olpc_ofw_header); | ||
25 | memset(&boot_params->kbd_status, 0, | ||
26 | (char *)&boot_params->hdr - | ||
27 | (char *)&boot_params->kbd_status); | ||
28 | memset(&boot_params->_pad7[0], 0, | ||
29 | (char *)&boot_params->edd_mbr_sig_buffer[0] - | ||
30 | (char *)&boot_params->_pad7[0]); | ||
31 | memset(&boot_params->_pad8[0], 0, | ||
32 | (char *)&boot_params->eddbuf[0] - | ||
33 | (char *)&boot_params->_pad8[0]); | ||
34 | memset(&boot_params->_pad9[0], 0, sizeof(boot_params->_pad9)); | ||
35 | } | ||
36 | } | ||
37 | |||
38 | #endif /* _ASM_X86_BOOTPARAM_UTILS_H */ | ||
diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h index 2d9075e863a0..93fe929d1cee 100644 --- a/arch/x86/include/asm/cpufeature.h +++ b/arch/x86/include/asm/cpufeature.h | |||
@@ -167,6 +167,7 @@ | |||
167 | #define X86_FEATURE_TBM (6*32+21) /* trailing bit manipulations */ | 167 | #define X86_FEATURE_TBM (6*32+21) /* trailing bit manipulations */ |
168 | #define X86_FEATURE_TOPOEXT (6*32+22) /* topology extensions CPUID leafs */ | 168 | #define X86_FEATURE_TOPOEXT (6*32+22) /* topology extensions CPUID leafs */ |
169 | #define X86_FEATURE_PERFCTR_CORE (6*32+23) /* core performance counter extensions */ | 169 | #define X86_FEATURE_PERFCTR_CORE (6*32+23) /* core performance counter extensions */ |
170 | #define X86_FEATURE_PERFCTR_NB (6*32+24) /* NB performance counter extensions */ | ||
170 | 171 | ||
171 | /* | 172 | /* |
172 | * Auxiliary flags: Linux defined - For features scattered in various | 173 | * Auxiliary flags: Linux defined - For features scattered in various |
@@ -309,6 +310,7 @@ extern const char * const x86_power_flags[32]; | |||
309 | #define cpu_has_hypervisor boot_cpu_has(X86_FEATURE_HYPERVISOR) | 310 | #define cpu_has_hypervisor boot_cpu_has(X86_FEATURE_HYPERVISOR) |
310 | #define cpu_has_pclmulqdq boot_cpu_has(X86_FEATURE_PCLMULQDQ) | 311 | #define cpu_has_pclmulqdq boot_cpu_has(X86_FEATURE_PCLMULQDQ) |
311 | #define cpu_has_perfctr_core boot_cpu_has(X86_FEATURE_PERFCTR_CORE) | 312 | #define cpu_has_perfctr_core boot_cpu_has(X86_FEATURE_PERFCTR_CORE) |
313 | #define cpu_has_perfctr_nb boot_cpu_has(X86_FEATURE_PERFCTR_NB) | ||
312 | #define cpu_has_cx8 boot_cpu_has(X86_FEATURE_CX8) | 314 | #define cpu_has_cx8 boot_cpu_has(X86_FEATURE_CX8) |
313 | #define cpu_has_cx16 boot_cpu_has(X86_FEATURE_CX16) | 315 | #define cpu_has_cx16 boot_cpu_has(X86_FEATURE_CX16) |
314 | #define cpu_has_eager_fpu boot_cpu_has(X86_FEATURE_EAGER_FPU) | 316 | #define cpu_has_eager_fpu boot_cpu_has(X86_FEATURE_EAGER_FPU) |
diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h index 9a25b522d377..86cb51e1ca96 100644 --- a/arch/x86/include/asm/ftrace.h +++ b/arch/x86/include/asm/ftrace.h | |||
@@ -44,7 +44,6 @@ | |||
44 | 44 | ||
45 | #ifdef CONFIG_DYNAMIC_FTRACE | 45 | #ifdef CONFIG_DYNAMIC_FTRACE |
46 | #define ARCH_SUPPORTS_FTRACE_OPS 1 | 46 | #define ARCH_SUPPORTS_FTRACE_OPS 1 |
47 | #define ARCH_SUPPORTS_FTRACE_SAVE_REGS | ||
48 | #endif | 47 | #endif |
49 | 48 | ||
50 | #ifndef __ASSEMBLY__ | 49 | #ifndef __ASSEMBLY__ |
diff --git a/arch/x86/include/asm/hpet.h b/arch/x86/include/asm/hpet.h index 434e2106cc87..b18df579c0e9 100644 --- a/arch/x86/include/asm/hpet.h +++ b/arch/x86/include/asm/hpet.h | |||
@@ -80,9 +80,9 @@ extern void hpet_msi_write(struct hpet_dev *hdev, struct msi_msg *msg); | |||
80 | extern void hpet_msi_read(struct hpet_dev *hdev, struct msi_msg *msg); | 80 | extern void hpet_msi_read(struct hpet_dev *hdev, struct msi_msg *msg); |
81 | 81 | ||
82 | #ifdef CONFIG_PCI_MSI | 82 | #ifdef CONFIG_PCI_MSI |
83 | extern int arch_setup_hpet_msi(unsigned int irq, unsigned int id); | 83 | extern int default_setup_hpet_msi(unsigned int irq, unsigned int id); |
84 | #else | 84 | #else |
85 | static inline int arch_setup_hpet_msi(unsigned int irq, unsigned int id) | 85 | static inline int default_setup_hpet_msi(unsigned int irq, unsigned int id) |
86 | { | 86 | { |
87 | return -EINVAL; | 87 | return -EINVAL; |
88 | } | 88 | } |
@@ -111,6 +111,7 @@ extern void hpet_unregister_irq_handler(rtc_irq_handler handler); | |||
111 | static inline int hpet_enable(void) { return 0; } | 111 | static inline int hpet_enable(void) { return 0; } |
112 | static inline int is_hpet_enabled(void) { return 0; } | 112 | static inline int is_hpet_enabled(void) { return 0; } |
113 | #define hpet_readl(a) 0 | 113 | #define hpet_readl(a) 0 |
114 | #define default_setup_hpet_msi NULL | ||
114 | 115 | ||
115 | #endif | 116 | #endif |
116 | #endif /* _ASM_X86_HPET_H */ | 117 | #endif /* _ASM_X86_HPET_H */ |
diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h index eb92a6ed2be7..10a78c3d3d5a 100644 --- a/arch/x86/include/asm/hw_irq.h +++ b/arch/x86/include/asm/hw_irq.h | |||
@@ -101,6 +101,7 @@ static inline void set_io_apic_irq_attr(struct io_apic_irq_attr *irq_attr, | |||
101 | irq_attr->polarity = polarity; | 101 | irq_attr->polarity = polarity; |
102 | } | 102 | } |
103 | 103 | ||
104 | /* Intel specific interrupt remapping information */ | ||
104 | struct irq_2_iommu { | 105 | struct irq_2_iommu { |
105 | struct intel_iommu *iommu; | 106 | struct intel_iommu *iommu; |
106 | u16 irte_index; | 107 | u16 irte_index; |
@@ -108,6 +109,12 @@ struct irq_2_iommu { | |||
108 | u8 irte_mask; | 109 | u8 irte_mask; |
109 | }; | 110 | }; |
110 | 111 | ||
112 | /* AMD specific interrupt remapping information */ | ||
113 | struct irq_2_irte { | ||
114 | u16 devid; /* Device ID for IRTE table */ | ||
115 | u16 index; /* Index into IRTE table*/ | ||
116 | }; | ||
117 | |||
111 | /* | 118 | /* |
112 | * This is performance-critical, we want to do it O(1) | 119 | * This is performance-critical, we want to do it O(1) |
113 | * | 120 | * |
@@ -120,7 +127,11 @@ struct irq_cfg { | |||
120 | u8 vector; | 127 | u8 vector; |
121 | u8 move_in_progress : 1; | 128 | u8 move_in_progress : 1; |
122 | #ifdef CONFIG_IRQ_REMAP | 129 | #ifdef CONFIG_IRQ_REMAP |
123 | struct irq_2_iommu irq_2_iommu; | 130 | u8 remapped : 1; |
131 | union { | ||
132 | struct irq_2_iommu irq_2_iommu; | ||
133 | struct irq_2_irte irq_2_irte; | ||
134 | }; | ||
124 | #endif | 135 | #endif |
125 | }; | 136 | }; |
126 | 137 | ||
diff --git a/arch/x86/include/asm/hypervisor.h b/arch/x86/include/asm/hypervisor.h index b518c7509933..86095ed14135 100644 --- a/arch/x86/include/asm/hypervisor.h +++ b/arch/x86/include/asm/hypervisor.h | |||
@@ -25,6 +25,7 @@ | |||
25 | 25 | ||
26 | extern void init_hypervisor(struct cpuinfo_x86 *c); | 26 | extern void init_hypervisor(struct cpuinfo_x86 *c); |
27 | extern void init_hypervisor_platform(void); | 27 | extern void init_hypervisor_platform(void); |
28 | extern bool hypervisor_x2apic_available(void); | ||
28 | 29 | ||
29 | /* | 30 | /* |
30 | * x86 hypervisor information | 31 | * x86 hypervisor information |
@@ -41,6 +42,9 @@ struct hypervisor_x86 { | |||
41 | 42 | ||
42 | /* Platform setup (run once per boot) */ | 43 | /* Platform setup (run once per boot) */ |
43 | void (*init_platform)(void); | 44 | void (*init_platform)(void); |
45 | |||
46 | /* X2APIC detection (run once per boot) */ | ||
47 | bool (*x2apic_available)(void); | ||
44 | }; | 48 | }; |
45 | 49 | ||
46 | extern const struct hypervisor_x86 *x86_hyper; | 50 | extern const struct hypervisor_x86 *x86_hyper; |
@@ -51,13 +55,4 @@ extern const struct hypervisor_x86 x86_hyper_ms_hyperv; | |||
51 | extern const struct hypervisor_x86 x86_hyper_xen_hvm; | 55 | extern const struct hypervisor_x86 x86_hyper_xen_hvm; |
52 | extern const struct hypervisor_x86 x86_hyper_kvm; | 56 | extern const struct hypervisor_x86 x86_hyper_kvm; |
53 | 57 | ||
54 | static inline bool hypervisor_x2apic_available(void) | ||
55 | { | ||
56 | if (kvm_para_available()) | ||
57 | return true; | ||
58 | if (xen_x2apic_para_available()) | ||
59 | return true; | ||
60 | return false; | ||
61 | } | ||
62 | |||
63 | #endif | 58 | #endif |
diff --git a/arch/x86/include/asm/io_apic.h b/arch/x86/include/asm/io_apic.h index 73d8c5398ea9..459e50a424d1 100644 --- a/arch/x86/include/asm/io_apic.h +++ b/arch/x86/include/asm/io_apic.h | |||
@@ -144,11 +144,24 @@ extern int timer_through_8259; | |||
144 | (mp_irq_entries && !skip_ioapic_setup && io_apic_irqs) | 144 | (mp_irq_entries && !skip_ioapic_setup && io_apic_irqs) |
145 | 145 | ||
146 | struct io_apic_irq_attr; | 146 | struct io_apic_irq_attr; |
147 | struct irq_cfg; | ||
147 | extern int io_apic_set_pci_routing(struct device *dev, int irq, | 148 | extern int io_apic_set_pci_routing(struct device *dev, int irq, |
148 | struct io_apic_irq_attr *irq_attr); | 149 | struct io_apic_irq_attr *irq_attr); |
149 | void setup_IO_APIC_irq_extra(u32 gsi); | 150 | void setup_IO_APIC_irq_extra(u32 gsi); |
150 | extern void ioapic_insert_resources(void); | 151 | extern void ioapic_insert_resources(void); |
151 | 152 | ||
153 | extern int native_setup_ioapic_entry(int, struct IO_APIC_route_entry *, | ||
154 | unsigned int, int, | ||
155 | struct io_apic_irq_attr *); | ||
156 | extern int native_setup_ioapic_entry(int, struct IO_APIC_route_entry *, | ||
157 | unsigned int, int, | ||
158 | struct io_apic_irq_attr *); | ||
159 | extern void eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg); | ||
160 | |||
161 | extern void native_compose_msi_msg(struct pci_dev *pdev, | ||
162 | unsigned int irq, unsigned int dest, | ||
163 | struct msi_msg *msg, u8 hpet_id); | ||
164 | extern void native_eoi_ioapic_pin(int apic, int pin, int vector); | ||
152 | int io_apic_setup_irq_pin_once(unsigned int irq, int node, struct io_apic_irq_attr *attr); | 165 | int io_apic_setup_irq_pin_once(unsigned int irq, int node, struct io_apic_irq_attr *attr); |
153 | 166 | ||
154 | extern int save_ioapic_entries(void); | 167 | extern int save_ioapic_entries(void); |
@@ -179,6 +192,12 @@ extern void __init native_io_apic_init_mappings(void); | |||
179 | extern unsigned int native_io_apic_read(unsigned int apic, unsigned int reg); | 192 | extern unsigned int native_io_apic_read(unsigned int apic, unsigned int reg); |
180 | extern void native_io_apic_write(unsigned int apic, unsigned int reg, unsigned int val); | 193 | extern void native_io_apic_write(unsigned int apic, unsigned int reg, unsigned int val); |
181 | extern void native_io_apic_modify(unsigned int apic, unsigned int reg, unsigned int val); | 194 | extern void native_io_apic_modify(unsigned int apic, unsigned int reg, unsigned int val); |
195 | extern void native_disable_io_apic(void); | ||
196 | extern void native_io_apic_print_entries(unsigned int apic, unsigned int nr_entries); | ||
197 | extern void intel_ir_io_apic_print_entries(unsigned int apic, unsigned int nr_entries); | ||
198 | extern int native_ioapic_set_affinity(struct irq_data *, | ||
199 | const struct cpumask *, | ||
200 | bool); | ||
182 | 201 | ||
183 | static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg) | 202 | static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg) |
184 | { | 203 | { |
@@ -193,6 +212,9 @@ static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned | |||
193 | { | 212 | { |
194 | x86_io_apic_ops.modify(apic, reg, value); | 213 | x86_io_apic_ops.modify(apic, reg, value); |
195 | } | 214 | } |
215 | |||
216 | extern void io_apic_eoi(unsigned int apic, unsigned int vector); | ||
217 | |||
196 | #else /* !CONFIG_X86_IO_APIC */ | 218 | #else /* !CONFIG_X86_IO_APIC */ |
197 | 219 | ||
198 | #define io_apic_assign_pci_irqs 0 | 220 | #define io_apic_assign_pci_irqs 0 |
@@ -223,6 +245,12 @@ static inline void disable_ioapic_support(void) { } | |||
223 | #define native_io_apic_read NULL | 245 | #define native_io_apic_read NULL |
224 | #define native_io_apic_write NULL | 246 | #define native_io_apic_write NULL |
225 | #define native_io_apic_modify NULL | 247 | #define native_io_apic_modify NULL |
248 | #define native_disable_io_apic NULL | ||
249 | #define native_io_apic_print_entries NULL | ||
250 | #define native_ioapic_set_affinity NULL | ||
251 | #define native_setup_ioapic_entry NULL | ||
252 | #define native_compose_msi_msg NULL | ||
253 | #define native_eoi_ioapic_pin NULL | ||
226 | #endif | 254 | #endif |
227 | 255 | ||
228 | #endif /* _ASM_X86_IO_APIC_H */ | 256 | #endif /* _ASM_X86_IO_APIC_H */ |
diff --git a/arch/x86/include/asm/irq_remapping.h b/arch/x86/include/asm/irq_remapping.h index 5fb9bbbd2f14..95fd3527f632 100644 --- a/arch/x86/include/asm/irq_remapping.h +++ b/arch/x86/include/asm/irq_remapping.h | |||
@@ -26,8 +26,6 @@ | |||
26 | 26 | ||
27 | #ifdef CONFIG_IRQ_REMAP | 27 | #ifdef CONFIG_IRQ_REMAP |
28 | 28 | ||
29 | extern int irq_remapping_enabled; | ||
30 | |||
31 | extern void setup_irq_remapping_ops(void); | 29 | extern void setup_irq_remapping_ops(void); |
32 | extern int irq_remapping_supported(void); | 30 | extern int irq_remapping_supported(void); |
33 | extern int irq_remapping_prepare(void); | 31 | extern int irq_remapping_prepare(void); |
@@ -40,21 +38,19 @@ extern int setup_ioapic_remapped_entry(int irq, | |||
40 | unsigned int destination, | 38 | unsigned int destination, |
41 | int vector, | 39 | int vector, |
42 | struct io_apic_irq_attr *attr); | 40 | struct io_apic_irq_attr *attr); |
43 | extern int set_remapped_irq_affinity(struct irq_data *data, | ||
44 | const struct cpumask *mask, | ||
45 | bool force); | ||
46 | extern void free_remapped_irq(int irq); | 41 | extern void free_remapped_irq(int irq); |
47 | extern void compose_remapped_msi_msg(struct pci_dev *pdev, | 42 | extern void compose_remapped_msi_msg(struct pci_dev *pdev, |
48 | unsigned int irq, unsigned int dest, | 43 | unsigned int irq, unsigned int dest, |
49 | struct msi_msg *msg, u8 hpet_id); | 44 | struct msi_msg *msg, u8 hpet_id); |
50 | extern int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec); | ||
51 | extern int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq, | ||
52 | int index, int sub_handle); | ||
53 | extern int setup_hpet_msi_remapped(unsigned int irq, unsigned int id); | 45 | extern int setup_hpet_msi_remapped(unsigned int irq, unsigned int id); |
46 | extern void panic_if_irq_remap(const char *msg); | ||
47 | extern bool setup_remapped_irq(int irq, | ||
48 | struct irq_cfg *cfg, | ||
49 | struct irq_chip *chip); | ||
54 | 50 | ||
55 | #else /* CONFIG_IRQ_REMAP */ | 51 | void irq_remap_modify_chip_defaults(struct irq_chip *chip); |
56 | 52 | ||
57 | #define irq_remapping_enabled 0 | 53 | #else /* CONFIG_IRQ_REMAP */ |
58 | 54 | ||
59 | static inline void setup_irq_remapping_ops(void) { } | 55 | static inline void setup_irq_remapping_ops(void) { } |
60 | static inline int irq_remapping_supported(void) { return 0; } | 56 | static inline int irq_remapping_supported(void) { return 0; } |
@@ -71,30 +67,30 @@ static inline int setup_ioapic_remapped_entry(int irq, | |||
71 | { | 67 | { |
72 | return -ENODEV; | 68 | return -ENODEV; |
73 | } | 69 | } |
74 | static inline int set_remapped_irq_affinity(struct irq_data *data, | ||
75 | const struct cpumask *mask, | ||
76 | bool force) | ||
77 | { | ||
78 | return 0; | ||
79 | } | ||
80 | static inline void free_remapped_irq(int irq) { } | 70 | static inline void free_remapped_irq(int irq) { } |
81 | static inline void compose_remapped_msi_msg(struct pci_dev *pdev, | 71 | static inline void compose_remapped_msi_msg(struct pci_dev *pdev, |
82 | unsigned int irq, unsigned int dest, | 72 | unsigned int irq, unsigned int dest, |
83 | struct msi_msg *msg, u8 hpet_id) | 73 | struct msi_msg *msg, u8 hpet_id) |
84 | { | 74 | { |
85 | } | 75 | } |
86 | static inline int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec) | 76 | static inline int setup_hpet_msi_remapped(unsigned int irq, unsigned int id) |
87 | { | 77 | { |
88 | return -ENODEV; | 78 | return -ENODEV; |
89 | } | 79 | } |
90 | static inline int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq, | 80 | |
91 | int index, int sub_handle) | 81 | static inline void panic_if_irq_remap(const char *msg) |
82 | { | ||
83 | } | ||
84 | |||
85 | static inline void irq_remap_modify_chip_defaults(struct irq_chip *chip) | ||
92 | { | 86 | { |
93 | return -ENODEV; | ||
94 | } | 87 | } |
95 | static inline int setup_hpet_msi_remapped(unsigned int irq, unsigned int id) | 88 | |
89 | static inline bool setup_remapped_irq(int irq, | ||
90 | struct irq_cfg *cfg, | ||
91 | struct irq_chip *chip) | ||
96 | { | 92 | { |
97 | return -ENODEV; | 93 | return false; |
98 | } | 94 | } |
99 | #endif /* CONFIG_IRQ_REMAP */ | 95 | #endif /* CONFIG_IRQ_REMAP */ |
100 | 96 | ||
diff --git a/arch/x86/include/asm/irq_vectors.h b/arch/x86/include/asm/irq_vectors.h index 1508e518c7e3..aac5fa62a86c 100644 --- a/arch/x86/include/asm/irq_vectors.h +++ b/arch/x86/include/asm/irq_vectors.h | |||
@@ -109,8 +109,8 @@ | |||
109 | 109 | ||
110 | #define UV_BAU_MESSAGE 0xf5 | 110 | #define UV_BAU_MESSAGE 0xf5 |
111 | 111 | ||
112 | /* Xen vector callback to receive events in a HVM domain */ | 112 | /* Vector on which hypervisor callbacks will be delivered */ |
113 | #define XEN_HVM_EVTCHN_CALLBACK 0xf3 | 113 | #define HYPERVISOR_CALLBACK_VECTOR 0xf3 |
114 | 114 | ||
115 | /* | 115 | /* |
116 | * Local APIC timer IRQ vector is on a different priority level, | 116 | * Local APIC timer IRQ vector is on a different priority level, |
diff --git a/arch/x86/include/asm/kvm_para.h b/arch/x86/include/asm/kvm_para.h index 5ed1f16187be..65231e173baf 100644 --- a/arch/x86/include/asm/kvm_para.h +++ b/arch/x86/include/asm/kvm_para.h | |||
@@ -85,13 +85,13 @@ static inline long kvm_hypercall4(unsigned int nr, unsigned long p1, | |||
85 | return ret; | 85 | return ret; |
86 | } | 86 | } |
87 | 87 | ||
88 | static inline int kvm_para_available(void) | 88 | static inline bool kvm_para_available(void) |
89 | { | 89 | { |
90 | unsigned int eax, ebx, ecx, edx; | 90 | unsigned int eax, ebx, ecx, edx; |
91 | char signature[13]; | 91 | char signature[13]; |
92 | 92 | ||
93 | if (boot_cpu_data.cpuid_level < 0) | 93 | if (boot_cpu_data.cpuid_level < 0) |
94 | return 0; /* So we don't blow up on old processors */ | 94 | return false; /* So we don't blow up on old processors */ |
95 | 95 | ||
96 | if (cpu_has_hypervisor) { | 96 | if (cpu_has_hypervisor) { |
97 | cpuid(KVM_CPUID_SIGNATURE, &eax, &ebx, &ecx, &edx); | 97 | cpuid(KVM_CPUID_SIGNATURE, &eax, &ebx, &ecx, &edx); |
@@ -101,10 +101,10 @@ static inline int kvm_para_available(void) | |||
101 | signature[12] = 0; | 101 | signature[12] = 0; |
102 | 102 | ||
103 | if (strcmp(signature, "KVMKVMKVM") == 0) | 103 | if (strcmp(signature, "KVMKVMKVM") == 0) |
104 | return 1; | 104 | return true; |
105 | } | 105 | } |
106 | 106 | ||
107 | return 0; | 107 | return false; |
108 | } | 108 | } |
109 | 109 | ||
110 | static inline unsigned int kvm_arch_para_features(void) | 110 | static inline unsigned int kvm_arch_para_features(void) |
diff --git a/arch/x86/include/asm/linkage.h b/arch/x86/include/asm/linkage.h index 48142971b25d..79327e9483a3 100644 --- a/arch/x86/include/asm/linkage.h +++ b/arch/x86/include/asm/linkage.h | |||
@@ -27,20 +27,20 @@ | |||
27 | #define __asmlinkage_protect0(ret) \ | 27 | #define __asmlinkage_protect0(ret) \ |
28 | __asmlinkage_protect_n(ret) | 28 | __asmlinkage_protect_n(ret) |
29 | #define __asmlinkage_protect1(ret, arg1) \ | 29 | #define __asmlinkage_protect1(ret, arg1) \ |
30 | __asmlinkage_protect_n(ret, "g" (arg1)) | 30 | __asmlinkage_protect_n(ret, "m" (arg1)) |
31 | #define __asmlinkage_protect2(ret, arg1, arg2) \ | 31 | #define __asmlinkage_protect2(ret, arg1, arg2) \ |
32 | __asmlinkage_protect_n(ret, "g" (arg1), "g" (arg2)) | 32 | __asmlinkage_protect_n(ret, "m" (arg1), "m" (arg2)) |
33 | #define __asmlinkage_protect3(ret, arg1, arg2, arg3) \ | 33 | #define __asmlinkage_protect3(ret, arg1, arg2, arg3) \ |
34 | __asmlinkage_protect_n(ret, "g" (arg1), "g" (arg2), "g" (arg3)) | 34 | __asmlinkage_protect_n(ret, "m" (arg1), "m" (arg2), "m" (arg3)) |
35 | #define __asmlinkage_protect4(ret, arg1, arg2, arg3, arg4) \ | 35 | #define __asmlinkage_protect4(ret, arg1, arg2, arg3, arg4) \ |
36 | __asmlinkage_protect_n(ret, "g" (arg1), "g" (arg2), "g" (arg3), \ | 36 | __asmlinkage_protect_n(ret, "m" (arg1), "m" (arg2), "m" (arg3), \ |
37 | "g" (arg4)) | 37 | "m" (arg4)) |
38 | #define __asmlinkage_protect5(ret, arg1, arg2, arg3, arg4, arg5) \ | 38 | #define __asmlinkage_protect5(ret, arg1, arg2, arg3, arg4, arg5) \ |
39 | __asmlinkage_protect_n(ret, "g" (arg1), "g" (arg2), "g" (arg3), \ | 39 | __asmlinkage_protect_n(ret, "m" (arg1), "m" (arg2), "m" (arg3), \ |
40 | "g" (arg4), "g" (arg5)) | 40 | "m" (arg4), "m" (arg5)) |
41 | #define __asmlinkage_protect6(ret, arg1, arg2, arg3, arg4, arg5, arg6) \ | 41 | #define __asmlinkage_protect6(ret, arg1, arg2, arg3, arg4, arg5, arg6) \ |
42 | __asmlinkage_protect_n(ret, "g" (arg1), "g" (arg2), "g" (arg3), \ | 42 | __asmlinkage_protect_n(ret, "m" (arg1), "m" (arg2), "m" (arg3), \ |
43 | "g" (arg4), "g" (arg5), "g" (arg6)) | 43 | "m" (arg4), "m" (arg5), "m" (arg6)) |
44 | 44 | ||
45 | #endif /* CONFIG_X86_32 */ | 45 | #endif /* CONFIG_X86_32 */ |
46 | 46 | ||
diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h index ecdfee60ee4a..f4076af1f4ed 100644 --- a/arch/x86/include/asm/mce.h +++ b/arch/x86/include/asm/mce.h | |||
@@ -3,6 +3,90 @@ | |||
3 | 3 | ||
4 | #include <uapi/asm/mce.h> | 4 | #include <uapi/asm/mce.h> |
5 | 5 | ||
6 | /* | ||
7 | * Machine Check support for x86 | ||
8 | */ | ||
9 | |||
10 | /* MCG_CAP register defines */ | ||
11 | #define MCG_BANKCNT_MASK 0xff /* Number of Banks */ | ||
12 | #define MCG_CTL_P (1ULL<<8) /* MCG_CTL register available */ | ||
13 | #define MCG_EXT_P (1ULL<<9) /* Extended registers available */ | ||
14 | #define MCG_CMCI_P (1ULL<<10) /* CMCI supported */ | ||
15 | #define MCG_EXT_CNT_MASK 0xff0000 /* Number of Extended registers */ | ||
16 | #define MCG_EXT_CNT_SHIFT 16 | ||
17 | #define MCG_EXT_CNT(c) (((c) & MCG_EXT_CNT_MASK) >> MCG_EXT_CNT_SHIFT) | ||
18 | #define MCG_SER_P (1ULL<<24) /* MCA recovery/new status bits */ | ||
19 | |||
20 | /* MCG_STATUS register defines */ | ||
21 | #define MCG_STATUS_RIPV (1ULL<<0) /* restart ip valid */ | ||
22 | #define MCG_STATUS_EIPV (1ULL<<1) /* ip points to correct instruction */ | ||
23 | #define MCG_STATUS_MCIP (1ULL<<2) /* machine check in progress */ | ||
24 | |||
25 | /* MCi_STATUS register defines */ | ||
26 | #define MCI_STATUS_VAL (1ULL<<63) /* valid error */ | ||
27 | #define MCI_STATUS_OVER (1ULL<<62) /* previous errors lost */ | ||
28 | #define MCI_STATUS_UC (1ULL<<61) /* uncorrected error */ | ||
29 | #define MCI_STATUS_EN (1ULL<<60) /* error enabled */ | ||
30 | #define MCI_STATUS_MISCV (1ULL<<59) /* misc error reg. valid */ | ||
31 | #define MCI_STATUS_ADDRV (1ULL<<58) /* addr reg. valid */ | ||
32 | #define MCI_STATUS_PCC (1ULL<<57) /* processor context corrupt */ | ||
33 | #define MCI_STATUS_S (1ULL<<56) /* Signaled machine check */ | ||
34 | #define MCI_STATUS_AR (1ULL<<55) /* Action required */ | ||
35 | #define MCACOD 0xffff /* MCA Error Code */ | ||
36 | |||
37 | /* Architecturally defined codes from SDM Vol. 3B Chapter 15 */ | ||
38 | #define MCACOD_SCRUB 0x00C0 /* 0xC0-0xCF Memory Scrubbing */ | ||
39 | #define MCACOD_SCRUBMSK 0xfff0 | ||
40 | #define MCACOD_L3WB 0x017A /* L3 Explicit Writeback */ | ||
41 | #define MCACOD_DATA 0x0134 /* Data Load */ | ||
42 | #define MCACOD_INSTR 0x0150 /* Instruction Fetch */ | ||
43 | |||
44 | /* MCi_MISC register defines */ | ||
45 | #define MCI_MISC_ADDR_LSB(m) ((m) & 0x3f) | ||
46 | #define MCI_MISC_ADDR_MODE(m) (((m) >> 6) & 7) | ||
47 | #define MCI_MISC_ADDR_SEGOFF 0 /* segment offset */ | ||
48 | #define MCI_MISC_ADDR_LINEAR 1 /* linear address */ | ||
49 | #define MCI_MISC_ADDR_PHYS 2 /* physical address */ | ||
50 | #define MCI_MISC_ADDR_MEM 3 /* memory address */ | ||
51 | #define MCI_MISC_ADDR_GENERIC 7 /* generic */ | ||
52 | |||
53 | /* CTL2 register defines */ | ||
54 | #define MCI_CTL2_CMCI_EN (1ULL << 30) | ||
55 | #define MCI_CTL2_CMCI_THRESHOLD_MASK 0x7fffULL | ||
56 | |||
57 | #define MCJ_CTX_MASK 3 | ||
58 | #define MCJ_CTX(flags) ((flags) & MCJ_CTX_MASK) | ||
59 | #define MCJ_CTX_RANDOM 0 /* inject context: random */ | ||
60 | #define MCJ_CTX_PROCESS 0x1 /* inject context: process */ | ||
61 | #define MCJ_CTX_IRQ 0x2 /* inject context: IRQ */ | ||
62 | #define MCJ_NMI_BROADCAST 0x4 /* do NMI broadcasting */ | ||
63 | #define MCJ_EXCEPTION 0x8 /* raise as exception */ | ||
64 | #define MCJ_IRQ_BRAODCAST 0x10 /* do IRQ broadcasting */ | ||
65 | |||
66 | #define MCE_OVERFLOW 0 /* bit 0 in flags means overflow */ | ||
67 | |||
68 | /* Software defined banks */ | ||
69 | #define MCE_EXTENDED_BANK 128 | ||
70 | #define MCE_THERMAL_BANK (MCE_EXTENDED_BANK + 0) | ||
71 | #define K8_MCE_THRESHOLD_BASE (MCE_EXTENDED_BANK + 1) | ||
72 | |||
73 | #define MCE_LOG_LEN 32 | ||
74 | #define MCE_LOG_SIGNATURE "MACHINECHECK" | ||
75 | |||
76 | /* | ||
77 | * This structure contains all data related to the MCE log. Also | ||
78 | * carries a signature to make it easier to find from external | ||
79 | * debugging tools. Each entry is only valid when its finished flag | ||
80 | * is set. | ||
81 | */ | ||
82 | struct mce_log { | ||
83 | char signature[12]; /* "MACHINECHECK" */ | ||
84 | unsigned len; /* = MCE_LOG_LEN */ | ||
85 | unsigned next; | ||
86 | unsigned flags; | ||
87 | unsigned recordlen; /* length of struct mce */ | ||
88 | struct mce entry[MCE_LOG_LEN]; | ||
89 | }; | ||
6 | 90 | ||
7 | struct mca_config { | 91 | struct mca_config { |
8 | bool dont_log_ce; | 92 | bool dont_log_ce; |
diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h index 79ce5685ab64..c2934be2446a 100644 --- a/arch/x86/include/asm/mshyperv.h +++ b/arch/x86/include/asm/mshyperv.h | |||
@@ -11,4 +11,8 @@ struct ms_hyperv_info { | |||
11 | 11 | ||
12 | extern struct ms_hyperv_info ms_hyperv; | 12 | extern struct ms_hyperv_info ms_hyperv; |
13 | 13 | ||
14 | void hyperv_callback_vector(void); | ||
15 | void hyperv_vector_handler(struct pt_regs *regs); | ||
16 | void hv_register_vmbus_handler(int irq, irq_handler_t handler); | ||
17 | |||
14 | #endif | 18 | #endif |
diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h index dba7805176bf..c28fd02f4bf7 100644 --- a/arch/x86/include/asm/pci.h +++ b/arch/x86/include/asm/pci.h | |||
@@ -121,9 +121,12 @@ static inline void x86_restore_msi_irqs(struct pci_dev *dev, int irq) | |||
121 | #define arch_teardown_msi_irq x86_teardown_msi_irq | 121 | #define arch_teardown_msi_irq x86_teardown_msi_irq |
122 | #define arch_restore_msi_irqs x86_restore_msi_irqs | 122 | #define arch_restore_msi_irqs x86_restore_msi_irqs |
123 | /* implemented in arch/x86/kernel/apic/io_apic. */ | 123 | /* implemented in arch/x86/kernel/apic/io_apic. */ |
124 | struct msi_desc; | ||
124 | int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type); | 125 | int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type); |
125 | void native_teardown_msi_irq(unsigned int irq); | 126 | void native_teardown_msi_irq(unsigned int irq); |
126 | void native_restore_msi_irqs(struct pci_dev *dev, int irq); | 127 | void native_restore_msi_irqs(struct pci_dev *dev, int irq); |
128 | int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, | ||
129 | unsigned int irq_base, unsigned int irq_offset); | ||
127 | /* default to the implementation in drivers/lib/msi.c */ | 130 | /* default to the implementation in drivers/lib/msi.c */ |
128 | #define HAVE_DEFAULT_MSI_TEARDOWN_IRQS | 131 | #define HAVE_DEFAULT_MSI_TEARDOWN_IRQS |
129 | #define HAVE_DEFAULT_MSI_RESTORE_IRQS | 132 | #define HAVE_DEFAULT_MSI_RESTORE_IRQS |
diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h index 4fabcdf1cfa7..57cb63402213 100644 --- a/arch/x86/include/asm/perf_event.h +++ b/arch/x86/include/asm/perf_event.h | |||
@@ -29,8 +29,13 @@ | |||
29 | #define ARCH_PERFMON_EVENTSEL_INV (1ULL << 23) | 29 | #define ARCH_PERFMON_EVENTSEL_INV (1ULL << 23) |
30 | #define ARCH_PERFMON_EVENTSEL_CMASK 0xFF000000ULL | 30 | #define ARCH_PERFMON_EVENTSEL_CMASK 0xFF000000ULL |
31 | 31 | ||
32 | #define AMD_PERFMON_EVENTSEL_GUESTONLY (1ULL << 40) | 32 | #define AMD64_EVENTSEL_INT_CORE_ENABLE (1ULL << 36) |
33 | #define AMD_PERFMON_EVENTSEL_HOSTONLY (1ULL << 41) | 33 | #define AMD64_EVENTSEL_GUESTONLY (1ULL << 40) |
34 | #define AMD64_EVENTSEL_HOSTONLY (1ULL << 41) | ||
35 | |||
36 | #define AMD64_EVENTSEL_INT_CORE_SEL_SHIFT 37 | ||
37 | #define AMD64_EVENTSEL_INT_CORE_SEL_MASK \ | ||
38 | (0xFULL << AMD64_EVENTSEL_INT_CORE_SEL_SHIFT) | ||
34 | 39 | ||
35 | #define AMD64_EVENTSEL_EVENT \ | 40 | #define AMD64_EVENTSEL_EVENT \ |
36 | (ARCH_PERFMON_EVENTSEL_EVENT | (0x0FULL << 32)) | 41 | (ARCH_PERFMON_EVENTSEL_EVENT | (0x0FULL << 32)) |
@@ -46,8 +51,12 @@ | |||
46 | #define AMD64_RAW_EVENT_MASK \ | 51 | #define AMD64_RAW_EVENT_MASK \ |
47 | (X86_RAW_EVENT_MASK | \ | 52 | (X86_RAW_EVENT_MASK | \ |
48 | AMD64_EVENTSEL_EVENT) | 53 | AMD64_EVENTSEL_EVENT) |
54 | #define AMD64_RAW_EVENT_MASK_NB \ | ||
55 | (AMD64_EVENTSEL_EVENT | \ | ||
56 | ARCH_PERFMON_EVENTSEL_UMASK) | ||
49 | #define AMD64_NUM_COUNTERS 4 | 57 | #define AMD64_NUM_COUNTERS 4 |
50 | #define AMD64_NUM_COUNTERS_CORE 6 | 58 | #define AMD64_NUM_COUNTERS_CORE 6 |
59 | #define AMD64_NUM_COUNTERS_NB 4 | ||
51 | 60 | ||
52 | #define ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL 0x3c | 61 | #define ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL 0x3c |
53 | #define ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK (0x00 << 8) | 62 | #define ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK (0x00 << 8) |
diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h index 5199db2923d3..fc304279b559 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h | |||
@@ -142,6 +142,11 @@ static inline unsigned long pmd_pfn(pmd_t pmd) | |||
142 | return (pmd_val(pmd) & PTE_PFN_MASK) >> PAGE_SHIFT; | 142 | return (pmd_val(pmd) & PTE_PFN_MASK) >> PAGE_SHIFT; |
143 | } | 143 | } |
144 | 144 | ||
145 | static inline unsigned long pud_pfn(pud_t pud) | ||
146 | { | ||
147 | return (pud_val(pud) & PTE_PFN_MASK) >> PAGE_SHIFT; | ||
148 | } | ||
149 | |||
145 | #define pte_page(pte) pfn_to_page(pte_pfn(pte)) | 150 | #define pte_page(pte) pfn_to_page(pte_pfn(pte)) |
146 | 151 | ||
147 | static inline int pmd_large(pmd_t pte) | 152 | static inline int pmd_large(pmd_t pte) |
@@ -781,6 +786,18 @@ static inline void clone_pgd_range(pgd_t *dst, pgd_t *src, int count) | |||
781 | memcpy(dst, src, count * sizeof(pgd_t)); | 786 | memcpy(dst, src, count * sizeof(pgd_t)); |
782 | } | 787 | } |
783 | 788 | ||
789 | /* | ||
790 | * The x86 doesn't have any external MMU info: the kernel page | ||
791 | * tables contain all the necessary information. | ||
792 | */ | ||
793 | static inline void update_mmu_cache(struct vm_area_struct *vma, | ||
794 | unsigned long addr, pte_t *ptep) | ||
795 | { | ||
796 | } | ||
797 | static inline void update_mmu_cache_pmd(struct vm_area_struct *vma, | ||
798 | unsigned long addr, pmd_t *pmd) | ||
799 | { | ||
800 | } | ||
784 | 801 | ||
785 | #include <asm-generic/pgtable.h> | 802 | #include <asm-generic/pgtable.h> |
786 | #endif /* __ASSEMBLY__ */ | 803 | #endif /* __ASSEMBLY__ */ |
diff --git a/arch/x86/include/asm/pgtable_32.h b/arch/x86/include/asm/pgtable_32.h index 8faa215a503e..9ee322103c6d 100644 --- a/arch/x86/include/asm/pgtable_32.h +++ b/arch/x86/include/asm/pgtable_32.h | |||
@@ -66,13 +66,6 @@ do { \ | |||
66 | __flush_tlb_one((vaddr)); \ | 66 | __flush_tlb_one((vaddr)); \ |
67 | } while (0) | 67 | } while (0) |
68 | 68 | ||
69 | /* | ||
70 | * The i386 doesn't have any external MMU info: the kernel page | ||
71 | * tables contain all the necessary information. | ||
72 | */ | ||
73 | #define update_mmu_cache(vma, address, ptep) do { } while (0) | ||
74 | #define update_mmu_cache_pmd(vma, address, pmd) do { } while (0) | ||
75 | |||
76 | #endif /* !__ASSEMBLY__ */ | 69 | #endif /* !__ASSEMBLY__ */ |
77 | 70 | ||
78 | /* | 71 | /* |
diff --git a/arch/x86/include/asm/pgtable_64.h b/arch/x86/include/asm/pgtable_64.h index 47356f9df82e..615b0c78449f 100644 --- a/arch/x86/include/asm/pgtable_64.h +++ b/arch/x86/include/asm/pgtable_64.h | |||
@@ -142,9 +142,6 @@ static inline int pgd_large(pgd_t pgd) { return 0; } | |||
142 | #define pte_offset_map(dir, address) pte_offset_kernel((dir), (address)) | 142 | #define pte_offset_map(dir, address) pte_offset_kernel((dir), (address)) |
143 | #define pte_unmap(pte) ((void)(pte))/* NOP */ | 143 | #define pte_unmap(pte) ((void)(pte))/* NOP */ |
144 | 144 | ||
145 | #define update_mmu_cache(vma, address, ptep) do { } while (0) | ||
146 | #define update_mmu_cache_pmd(vma, address, pmd) do { } while (0) | ||
147 | |||
148 | /* Encode and de-code a swap entry */ | 145 | /* Encode and de-code a swap entry */ |
149 | #if _PAGE_BIT_FILE < _PAGE_BIT_PROTNONE | 146 | #if _PAGE_BIT_FILE < _PAGE_BIT_PROTNONE |
150 | #define SWP_TYPE_BITS (_PAGE_BIT_FILE - _PAGE_BIT_PRESENT - 1) | 147 | #define SWP_TYPE_BITS (_PAGE_BIT_FILE - _PAGE_BIT_PRESENT - 1) |
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 888184b2fc85..cf500543f6ff 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h | |||
@@ -943,7 +943,7 @@ extern void start_thread(struct pt_regs *regs, unsigned long new_ip, | |||
943 | extern int get_tsc_mode(unsigned long adr); | 943 | extern int get_tsc_mode(unsigned long adr); |
944 | extern int set_tsc_mode(unsigned int val); | 944 | extern int set_tsc_mode(unsigned int val); |
945 | 945 | ||
946 | extern int amd_get_nb_id(int cpu); | 946 | extern u16 amd_get_nb_id(int cpu); |
947 | 947 | ||
948 | struct aperfmperf { | 948 | struct aperfmperf { |
949 | u64 aperf, mperf; | 949 | u64 aperf, mperf; |
diff --git a/arch/x86/include/asm/required-features.h b/arch/x86/include/asm/required-features.h index 6c7fc25f2c34..5c6e4fb370f5 100644 --- a/arch/x86/include/asm/required-features.h +++ b/arch/x86/include/asm/required-features.h | |||
@@ -47,6 +47,12 @@ | |||
47 | # define NEED_NOPL 0 | 47 | # define NEED_NOPL 0 |
48 | #endif | 48 | #endif |
49 | 49 | ||
50 | #ifdef CONFIG_MATOM | ||
51 | # define NEED_MOVBE (1<<(X86_FEATURE_MOVBE & 31)) | ||
52 | #else | ||
53 | # define NEED_MOVBE 0 | ||
54 | #endif | ||
55 | |||
50 | #ifdef CONFIG_X86_64 | 56 | #ifdef CONFIG_X86_64 |
51 | #ifdef CONFIG_PARAVIRT | 57 | #ifdef CONFIG_PARAVIRT |
52 | /* Paravirtualized systems may not have PSE or PGE available */ | 58 | /* Paravirtualized systems may not have PSE or PGE available */ |
@@ -80,7 +86,7 @@ | |||
80 | 86 | ||
81 | #define REQUIRED_MASK2 0 | 87 | #define REQUIRED_MASK2 0 |
82 | #define REQUIRED_MASK3 (NEED_NOPL) | 88 | #define REQUIRED_MASK3 (NEED_NOPL) |
83 | #define REQUIRED_MASK4 0 | 89 | #define REQUIRED_MASK4 (NEED_MOVBE) |
84 | #define REQUIRED_MASK5 0 | 90 | #define REQUIRED_MASK5 0 |
85 | #define REQUIRED_MASK6 0 | 91 | #define REQUIRED_MASK6 0 |
86 | #define REQUIRED_MASK7 0 | 92 | #define REQUIRED_MASK7 0 |
diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h index 57693498519c..7669941cc9d2 100644 --- a/arch/x86/include/asm/x86_init.h +++ b/arch/x86/include/asm/x86_init.h | |||
@@ -181,19 +181,38 @@ struct x86_platform_ops { | |||
181 | }; | 181 | }; |
182 | 182 | ||
183 | struct pci_dev; | 183 | struct pci_dev; |
184 | struct msi_msg; | ||
184 | 185 | ||
185 | struct x86_msi_ops { | 186 | struct x86_msi_ops { |
186 | int (*setup_msi_irqs)(struct pci_dev *dev, int nvec, int type); | 187 | int (*setup_msi_irqs)(struct pci_dev *dev, int nvec, int type); |
188 | void (*compose_msi_msg)(struct pci_dev *dev, unsigned int irq, | ||
189 | unsigned int dest, struct msi_msg *msg, | ||
190 | u8 hpet_id); | ||
187 | void (*teardown_msi_irq)(unsigned int irq); | 191 | void (*teardown_msi_irq)(unsigned int irq); |
188 | void (*teardown_msi_irqs)(struct pci_dev *dev); | 192 | void (*teardown_msi_irqs)(struct pci_dev *dev); |
189 | void (*restore_msi_irqs)(struct pci_dev *dev, int irq); | 193 | void (*restore_msi_irqs)(struct pci_dev *dev, int irq); |
194 | int (*setup_hpet_msi)(unsigned int irq, unsigned int id); | ||
190 | }; | 195 | }; |
191 | 196 | ||
197 | struct IO_APIC_route_entry; | ||
198 | struct io_apic_irq_attr; | ||
199 | struct irq_data; | ||
200 | struct cpumask; | ||
201 | |||
192 | struct x86_io_apic_ops { | 202 | struct x86_io_apic_ops { |
193 | void (*init) (void); | 203 | void (*init) (void); |
194 | unsigned int (*read) (unsigned int apic, unsigned int reg); | 204 | unsigned int (*read) (unsigned int apic, unsigned int reg); |
195 | void (*write) (unsigned int apic, unsigned int reg, unsigned int value); | 205 | void (*write) (unsigned int apic, unsigned int reg, unsigned int value); |
196 | void (*modify)(unsigned int apic, unsigned int reg, unsigned int value); | 206 | void (*modify) (unsigned int apic, unsigned int reg, unsigned int value); |
207 | void (*disable)(void); | ||
208 | void (*print_entries)(unsigned int apic, unsigned int nr_entries); | ||
209 | int (*set_affinity)(struct irq_data *data, | ||
210 | const struct cpumask *mask, | ||
211 | bool force); | ||
212 | int (*setup_entry)(int irq, struct IO_APIC_route_entry *entry, | ||
213 | unsigned int destination, int vector, | ||
214 | struct io_apic_irq_attr *attr); | ||
215 | void (*eoi_ioapic_pin)(int apic, int pin, int vector); | ||
197 | }; | 216 | }; |
198 | 217 | ||
199 | extern struct x86_init_ops x86_init; | 218 | extern struct x86_init_ops x86_init; |
diff --git a/arch/x86/include/asm/xor.h b/arch/x86/include/asm/xor.h index f8fde90bc45e..d8829751b3f8 100644 --- a/arch/x86/include/asm/xor.h +++ b/arch/x86/include/asm/xor.h | |||
@@ -1,10 +1,499 @@ | |||
1 | #ifdef CONFIG_KMEMCHECK | 1 | #ifdef CONFIG_KMEMCHECK |
2 | /* kmemcheck doesn't handle MMX/SSE/SSE2 instructions */ | 2 | /* kmemcheck doesn't handle MMX/SSE/SSE2 instructions */ |
3 | # include <asm-generic/xor.h> | 3 | # include <asm-generic/xor.h> |
4 | #elif !defined(_ASM_X86_XOR_H) | ||
5 | #define _ASM_X86_XOR_H | ||
6 | |||
7 | /* | ||
8 | * Optimized RAID-5 checksumming functions for SSE. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2, or (at your option) | ||
13 | * any later version. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * (for example /usr/src/linux/COPYING); if not, write to the Free | ||
17 | * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
18 | */ | ||
19 | |||
20 | /* | ||
21 | * Cache avoiding checksumming functions utilizing KNI instructions | ||
22 | * Copyright (C) 1999 Zach Brown (with obvious credit due Ingo) | ||
23 | */ | ||
24 | |||
25 | /* | ||
26 | * Based on | ||
27 | * High-speed RAID5 checksumming functions utilizing SSE instructions. | ||
28 | * Copyright (C) 1998 Ingo Molnar. | ||
29 | */ | ||
30 | |||
31 | /* | ||
32 | * x86-64 changes / gcc fixes from Andi Kleen. | ||
33 | * Copyright 2002 Andi Kleen, SuSE Labs. | ||
34 | * | ||
35 | * This hasn't been optimized for the hammer yet, but there are likely | ||
36 | * no advantages to be gotten from x86-64 here anyways. | ||
37 | */ | ||
38 | |||
39 | #include <asm/i387.h> | ||
40 | |||
41 | #ifdef CONFIG_X86_32 | ||
42 | /* reduce register pressure */ | ||
43 | # define XOR_CONSTANT_CONSTRAINT "i" | ||
4 | #else | 44 | #else |
45 | # define XOR_CONSTANT_CONSTRAINT "re" | ||
46 | #endif | ||
47 | |||
48 | #define OFFS(x) "16*("#x")" | ||
49 | #define PF_OFFS(x) "256+16*("#x")" | ||
50 | #define PF0(x) " prefetchnta "PF_OFFS(x)"(%[p1]) ;\n" | ||
51 | #define LD(x, y) " movaps "OFFS(x)"(%[p1]), %%xmm"#y" ;\n" | ||
52 | #define ST(x, y) " movaps %%xmm"#y", "OFFS(x)"(%[p1]) ;\n" | ||
53 | #define PF1(x) " prefetchnta "PF_OFFS(x)"(%[p2]) ;\n" | ||
54 | #define PF2(x) " prefetchnta "PF_OFFS(x)"(%[p3]) ;\n" | ||
55 | #define PF3(x) " prefetchnta "PF_OFFS(x)"(%[p4]) ;\n" | ||
56 | #define PF4(x) " prefetchnta "PF_OFFS(x)"(%[p5]) ;\n" | ||
57 | #define XO1(x, y) " xorps "OFFS(x)"(%[p2]), %%xmm"#y" ;\n" | ||
58 | #define XO2(x, y) " xorps "OFFS(x)"(%[p3]), %%xmm"#y" ;\n" | ||
59 | #define XO3(x, y) " xorps "OFFS(x)"(%[p4]), %%xmm"#y" ;\n" | ||
60 | #define XO4(x, y) " xorps "OFFS(x)"(%[p5]), %%xmm"#y" ;\n" | ||
61 | #define NOP(x) | ||
62 | |||
63 | #define BLK64(pf, op, i) \ | ||
64 | pf(i) \ | ||
65 | op(i, 0) \ | ||
66 | op(i + 1, 1) \ | ||
67 | op(i + 2, 2) \ | ||
68 | op(i + 3, 3) | ||
69 | |||
70 | static void | ||
71 | xor_sse_2(unsigned long bytes, unsigned long *p1, unsigned long *p2) | ||
72 | { | ||
73 | unsigned long lines = bytes >> 8; | ||
74 | |||
75 | kernel_fpu_begin(); | ||
76 | |||
77 | asm volatile( | ||
78 | #undef BLOCK | ||
79 | #define BLOCK(i) \ | ||
80 | LD(i, 0) \ | ||
81 | LD(i + 1, 1) \ | ||
82 | PF1(i) \ | ||
83 | PF1(i + 2) \ | ||
84 | LD(i + 2, 2) \ | ||
85 | LD(i + 3, 3) \ | ||
86 | PF0(i + 4) \ | ||
87 | PF0(i + 6) \ | ||
88 | XO1(i, 0) \ | ||
89 | XO1(i + 1, 1) \ | ||
90 | XO1(i + 2, 2) \ | ||
91 | XO1(i + 3, 3) \ | ||
92 | ST(i, 0) \ | ||
93 | ST(i + 1, 1) \ | ||
94 | ST(i + 2, 2) \ | ||
95 | ST(i + 3, 3) \ | ||
96 | |||
97 | |||
98 | PF0(0) | ||
99 | PF0(2) | ||
100 | |||
101 | " .align 32 ;\n" | ||
102 | " 1: ;\n" | ||
103 | |||
104 | BLOCK(0) | ||
105 | BLOCK(4) | ||
106 | BLOCK(8) | ||
107 | BLOCK(12) | ||
108 | |||
109 | " add %[inc], %[p1] ;\n" | ||
110 | " add %[inc], %[p2] ;\n" | ||
111 | " dec %[cnt] ;\n" | ||
112 | " jnz 1b ;\n" | ||
113 | : [cnt] "+r" (lines), | ||
114 | [p1] "+r" (p1), [p2] "+r" (p2) | ||
115 | : [inc] XOR_CONSTANT_CONSTRAINT (256UL) | ||
116 | : "memory"); | ||
117 | |||
118 | kernel_fpu_end(); | ||
119 | } | ||
120 | |||
121 | static void | ||
122 | xor_sse_2_pf64(unsigned long bytes, unsigned long *p1, unsigned long *p2) | ||
123 | { | ||
124 | unsigned long lines = bytes >> 8; | ||
125 | |||
126 | kernel_fpu_begin(); | ||
127 | |||
128 | asm volatile( | ||
129 | #undef BLOCK | ||
130 | #define BLOCK(i) \ | ||
131 | BLK64(PF0, LD, i) \ | ||
132 | BLK64(PF1, XO1, i) \ | ||
133 | BLK64(NOP, ST, i) \ | ||
134 | |||
135 | " .align 32 ;\n" | ||
136 | " 1: ;\n" | ||
137 | |||
138 | BLOCK(0) | ||
139 | BLOCK(4) | ||
140 | BLOCK(8) | ||
141 | BLOCK(12) | ||
142 | |||
143 | " add %[inc], %[p1] ;\n" | ||
144 | " add %[inc], %[p2] ;\n" | ||
145 | " dec %[cnt] ;\n" | ||
146 | " jnz 1b ;\n" | ||
147 | : [cnt] "+r" (lines), | ||
148 | [p1] "+r" (p1), [p2] "+r" (p2) | ||
149 | : [inc] XOR_CONSTANT_CONSTRAINT (256UL) | ||
150 | : "memory"); | ||
151 | |||
152 | kernel_fpu_end(); | ||
153 | } | ||
154 | |||
155 | static void | ||
156 | xor_sse_3(unsigned long bytes, unsigned long *p1, unsigned long *p2, | ||
157 | unsigned long *p3) | ||
158 | { | ||
159 | unsigned long lines = bytes >> 8; | ||
160 | |||
161 | kernel_fpu_begin(); | ||
162 | |||
163 | asm volatile( | ||
164 | #undef BLOCK | ||
165 | #define BLOCK(i) \ | ||
166 | PF1(i) \ | ||
167 | PF1(i + 2) \ | ||
168 | LD(i, 0) \ | ||
169 | LD(i + 1, 1) \ | ||
170 | LD(i + 2, 2) \ | ||
171 | LD(i + 3, 3) \ | ||
172 | PF2(i) \ | ||
173 | PF2(i + 2) \ | ||
174 | PF0(i + 4) \ | ||
175 | PF0(i + 6) \ | ||
176 | XO1(i, 0) \ | ||
177 | XO1(i + 1, 1) \ | ||
178 | XO1(i + 2, 2) \ | ||
179 | XO1(i + 3, 3) \ | ||
180 | XO2(i, 0) \ | ||
181 | XO2(i + 1, 1) \ | ||
182 | XO2(i + 2, 2) \ | ||
183 | XO2(i + 3, 3) \ | ||
184 | ST(i, 0) \ | ||
185 | ST(i + 1, 1) \ | ||
186 | ST(i + 2, 2) \ | ||
187 | ST(i + 3, 3) \ | ||
188 | |||
189 | |||
190 | PF0(0) | ||
191 | PF0(2) | ||
192 | |||
193 | " .align 32 ;\n" | ||
194 | " 1: ;\n" | ||
195 | |||
196 | BLOCK(0) | ||
197 | BLOCK(4) | ||
198 | BLOCK(8) | ||
199 | BLOCK(12) | ||
200 | |||
201 | " add %[inc], %[p1] ;\n" | ||
202 | " add %[inc], %[p2] ;\n" | ||
203 | " add %[inc], %[p3] ;\n" | ||
204 | " dec %[cnt] ;\n" | ||
205 | " jnz 1b ;\n" | ||
206 | : [cnt] "+r" (lines), | ||
207 | [p1] "+r" (p1), [p2] "+r" (p2), [p3] "+r" (p3) | ||
208 | : [inc] XOR_CONSTANT_CONSTRAINT (256UL) | ||
209 | : "memory"); | ||
210 | |||
211 | kernel_fpu_end(); | ||
212 | } | ||
213 | |||
214 | static void | ||
215 | xor_sse_3_pf64(unsigned long bytes, unsigned long *p1, unsigned long *p2, | ||
216 | unsigned long *p3) | ||
217 | { | ||
218 | unsigned long lines = bytes >> 8; | ||
219 | |||
220 | kernel_fpu_begin(); | ||
221 | |||
222 | asm volatile( | ||
223 | #undef BLOCK | ||
224 | #define BLOCK(i) \ | ||
225 | BLK64(PF0, LD, i) \ | ||
226 | BLK64(PF1, XO1, i) \ | ||
227 | BLK64(PF2, XO2, i) \ | ||
228 | BLK64(NOP, ST, i) \ | ||
229 | |||
230 | " .align 32 ;\n" | ||
231 | " 1: ;\n" | ||
232 | |||
233 | BLOCK(0) | ||
234 | BLOCK(4) | ||
235 | BLOCK(8) | ||
236 | BLOCK(12) | ||
237 | |||
238 | " add %[inc], %[p1] ;\n" | ||
239 | " add %[inc], %[p2] ;\n" | ||
240 | " add %[inc], %[p3] ;\n" | ||
241 | " dec %[cnt] ;\n" | ||
242 | " jnz 1b ;\n" | ||
243 | : [cnt] "+r" (lines), | ||
244 | [p1] "+r" (p1), [p2] "+r" (p2), [p3] "+r" (p3) | ||
245 | : [inc] XOR_CONSTANT_CONSTRAINT (256UL) | ||
246 | : "memory"); | ||
247 | |||
248 | kernel_fpu_end(); | ||
249 | } | ||
250 | |||
251 | static void | ||
252 | xor_sse_4(unsigned long bytes, unsigned long *p1, unsigned long *p2, | ||
253 | unsigned long *p3, unsigned long *p4) | ||
254 | { | ||
255 | unsigned long lines = bytes >> 8; | ||
256 | |||
257 | kernel_fpu_begin(); | ||
258 | |||
259 | asm volatile( | ||
260 | #undef BLOCK | ||
261 | #define BLOCK(i) \ | ||
262 | PF1(i) \ | ||
263 | PF1(i + 2) \ | ||
264 | LD(i, 0) \ | ||
265 | LD(i + 1, 1) \ | ||
266 | LD(i + 2, 2) \ | ||
267 | LD(i + 3, 3) \ | ||
268 | PF2(i) \ | ||
269 | PF2(i + 2) \ | ||
270 | XO1(i, 0) \ | ||
271 | XO1(i + 1, 1) \ | ||
272 | XO1(i + 2, 2) \ | ||
273 | XO1(i + 3, 3) \ | ||
274 | PF3(i) \ | ||
275 | PF3(i + 2) \ | ||
276 | PF0(i + 4) \ | ||
277 | PF0(i + 6) \ | ||
278 | XO2(i, 0) \ | ||
279 | XO2(i + 1, 1) \ | ||
280 | XO2(i + 2, 2) \ | ||
281 | XO2(i + 3, 3) \ | ||
282 | XO3(i, 0) \ | ||
283 | XO3(i + 1, 1) \ | ||
284 | XO3(i + 2, 2) \ | ||
285 | XO3(i + 3, 3) \ | ||
286 | ST(i, 0) \ | ||
287 | ST(i + 1, 1) \ | ||
288 | ST(i + 2, 2) \ | ||
289 | ST(i + 3, 3) \ | ||
290 | |||
291 | |||
292 | PF0(0) | ||
293 | PF0(2) | ||
294 | |||
295 | " .align 32 ;\n" | ||
296 | " 1: ;\n" | ||
297 | |||
298 | BLOCK(0) | ||
299 | BLOCK(4) | ||
300 | BLOCK(8) | ||
301 | BLOCK(12) | ||
302 | |||
303 | " add %[inc], %[p1] ;\n" | ||
304 | " add %[inc], %[p2] ;\n" | ||
305 | " add %[inc], %[p3] ;\n" | ||
306 | " add %[inc], %[p4] ;\n" | ||
307 | " dec %[cnt] ;\n" | ||
308 | " jnz 1b ;\n" | ||
309 | : [cnt] "+r" (lines), [p1] "+r" (p1), | ||
310 | [p2] "+r" (p2), [p3] "+r" (p3), [p4] "+r" (p4) | ||
311 | : [inc] XOR_CONSTANT_CONSTRAINT (256UL) | ||
312 | : "memory"); | ||
313 | |||
314 | kernel_fpu_end(); | ||
315 | } | ||
316 | |||
317 | static void | ||
318 | xor_sse_4_pf64(unsigned long bytes, unsigned long *p1, unsigned long *p2, | ||
319 | unsigned long *p3, unsigned long *p4) | ||
320 | { | ||
321 | unsigned long lines = bytes >> 8; | ||
322 | |||
323 | kernel_fpu_begin(); | ||
324 | |||
325 | asm volatile( | ||
326 | #undef BLOCK | ||
327 | #define BLOCK(i) \ | ||
328 | BLK64(PF0, LD, i) \ | ||
329 | BLK64(PF1, XO1, i) \ | ||
330 | BLK64(PF2, XO2, i) \ | ||
331 | BLK64(PF3, XO3, i) \ | ||
332 | BLK64(NOP, ST, i) \ | ||
333 | |||
334 | " .align 32 ;\n" | ||
335 | " 1: ;\n" | ||
336 | |||
337 | BLOCK(0) | ||
338 | BLOCK(4) | ||
339 | BLOCK(8) | ||
340 | BLOCK(12) | ||
341 | |||
342 | " add %[inc], %[p1] ;\n" | ||
343 | " add %[inc], %[p2] ;\n" | ||
344 | " add %[inc], %[p3] ;\n" | ||
345 | " add %[inc], %[p4] ;\n" | ||
346 | " dec %[cnt] ;\n" | ||
347 | " jnz 1b ;\n" | ||
348 | : [cnt] "+r" (lines), [p1] "+r" (p1), | ||
349 | [p2] "+r" (p2), [p3] "+r" (p3), [p4] "+r" (p4) | ||
350 | : [inc] XOR_CONSTANT_CONSTRAINT (256UL) | ||
351 | : "memory"); | ||
352 | |||
353 | kernel_fpu_end(); | ||
354 | } | ||
355 | |||
356 | static void | ||
357 | xor_sse_5(unsigned long bytes, unsigned long *p1, unsigned long *p2, | ||
358 | unsigned long *p3, unsigned long *p4, unsigned long *p5) | ||
359 | { | ||
360 | unsigned long lines = bytes >> 8; | ||
361 | |||
362 | kernel_fpu_begin(); | ||
363 | |||
364 | asm volatile( | ||
365 | #undef BLOCK | ||
366 | #define BLOCK(i) \ | ||
367 | PF1(i) \ | ||
368 | PF1(i + 2) \ | ||
369 | LD(i, 0) \ | ||
370 | LD(i + 1, 1) \ | ||
371 | LD(i + 2, 2) \ | ||
372 | LD(i + 3, 3) \ | ||
373 | PF2(i) \ | ||
374 | PF2(i + 2) \ | ||
375 | XO1(i, 0) \ | ||
376 | XO1(i + 1, 1) \ | ||
377 | XO1(i + 2, 2) \ | ||
378 | XO1(i + 3, 3) \ | ||
379 | PF3(i) \ | ||
380 | PF3(i + 2) \ | ||
381 | XO2(i, 0) \ | ||
382 | XO2(i + 1, 1) \ | ||
383 | XO2(i + 2, 2) \ | ||
384 | XO2(i + 3, 3) \ | ||
385 | PF4(i) \ | ||
386 | PF4(i + 2) \ | ||
387 | PF0(i + 4) \ | ||
388 | PF0(i + 6) \ | ||
389 | XO3(i, 0) \ | ||
390 | XO3(i + 1, 1) \ | ||
391 | XO3(i + 2, 2) \ | ||
392 | XO3(i + 3, 3) \ | ||
393 | XO4(i, 0) \ | ||
394 | XO4(i + 1, 1) \ | ||
395 | XO4(i + 2, 2) \ | ||
396 | XO4(i + 3, 3) \ | ||
397 | ST(i, 0) \ | ||
398 | ST(i + 1, 1) \ | ||
399 | ST(i + 2, 2) \ | ||
400 | ST(i + 3, 3) \ | ||
401 | |||
402 | |||
403 | PF0(0) | ||
404 | PF0(2) | ||
405 | |||
406 | " .align 32 ;\n" | ||
407 | " 1: ;\n" | ||
408 | |||
409 | BLOCK(0) | ||
410 | BLOCK(4) | ||
411 | BLOCK(8) | ||
412 | BLOCK(12) | ||
413 | |||
414 | " add %[inc], %[p1] ;\n" | ||
415 | " add %[inc], %[p2] ;\n" | ||
416 | " add %[inc], %[p3] ;\n" | ||
417 | " add %[inc], %[p4] ;\n" | ||
418 | " add %[inc], %[p5] ;\n" | ||
419 | " dec %[cnt] ;\n" | ||
420 | " jnz 1b ;\n" | ||
421 | : [cnt] "+r" (lines), [p1] "+r" (p1), [p2] "+r" (p2), | ||
422 | [p3] "+r" (p3), [p4] "+r" (p4), [p5] "+r" (p5) | ||
423 | : [inc] XOR_CONSTANT_CONSTRAINT (256UL) | ||
424 | : "memory"); | ||
425 | |||
426 | kernel_fpu_end(); | ||
427 | } | ||
428 | |||
429 | static void | ||
430 | xor_sse_5_pf64(unsigned long bytes, unsigned long *p1, unsigned long *p2, | ||
431 | unsigned long *p3, unsigned long *p4, unsigned long *p5) | ||
432 | { | ||
433 | unsigned long lines = bytes >> 8; | ||
434 | |||
435 | kernel_fpu_begin(); | ||
436 | |||
437 | asm volatile( | ||
438 | #undef BLOCK | ||
439 | #define BLOCK(i) \ | ||
440 | BLK64(PF0, LD, i) \ | ||
441 | BLK64(PF1, XO1, i) \ | ||
442 | BLK64(PF2, XO2, i) \ | ||
443 | BLK64(PF3, XO3, i) \ | ||
444 | BLK64(PF4, XO4, i) \ | ||
445 | BLK64(NOP, ST, i) \ | ||
446 | |||
447 | " .align 32 ;\n" | ||
448 | " 1: ;\n" | ||
449 | |||
450 | BLOCK(0) | ||
451 | BLOCK(4) | ||
452 | BLOCK(8) | ||
453 | BLOCK(12) | ||
454 | |||
455 | " add %[inc], %[p1] ;\n" | ||
456 | " add %[inc], %[p2] ;\n" | ||
457 | " add %[inc], %[p3] ;\n" | ||
458 | " add %[inc], %[p4] ;\n" | ||
459 | " add %[inc], %[p5] ;\n" | ||
460 | " dec %[cnt] ;\n" | ||
461 | " jnz 1b ;\n" | ||
462 | : [cnt] "+r" (lines), [p1] "+r" (p1), [p2] "+r" (p2), | ||
463 | [p3] "+r" (p3), [p4] "+r" (p4), [p5] "+r" (p5) | ||
464 | : [inc] XOR_CONSTANT_CONSTRAINT (256UL) | ||
465 | : "memory"); | ||
466 | |||
467 | kernel_fpu_end(); | ||
468 | } | ||
469 | |||
470 | static struct xor_block_template xor_block_sse_pf64 = { | ||
471 | .name = "prefetch64-sse", | ||
472 | .do_2 = xor_sse_2_pf64, | ||
473 | .do_3 = xor_sse_3_pf64, | ||
474 | .do_4 = xor_sse_4_pf64, | ||
475 | .do_5 = xor_sse_5_pf64, | ||
476 | }; | ||
477 | |||
478 | #undef LD | ||
479 | #undef XO1 | ||
480 | #undef XO2 | ||
481 | #undef XO3 | ||
482 | #undef XO4 | ||
483 | #undef ST | ||
484 | #undef NOP | ||
485 | #undef BLK64 | ||
486 | #undef BLOCK | ||
487 | |||
488 | #undef XOR_CONSTANT_CONSTRAINT | ||
489 | |||
5 | #ifdef CONFIG_X86_32 | 490 | #ifdef CONFIG_X86_32 |
6 | # include <asm/xor_32.h> | 491 | # include <asm/xor_32.h> |
7 | #else | 492 | #else |
8 | # include <asm/xor_64.h> | 493 | # include <asm/xor_64.h> |
9 | #endif | 494 | #endif |
10 | #endif | 495 | |
496 | #define XOR_SELECT_TEMPLATE(FASTEST) \ | ||
497 | AVX_SELECT(FASTEST) | ||
498 | |||
499 | #endif /* _ASM_X86_XOR_H */ | ||
diff --git a/arch/x86/include/asm/xor_32.h b/arch/x86/include/asm/xor_32.h index f79cb7ec0e06..ce05722e3c68 100644 --- a/arch/x86/include/asm/xor_32.h +++ b/arch/x86/include/asm/xor_32.h | |||
@@ -2,7 +2,7 @@ | |||
2 | #define _ASM_X86_XOR_32_H | 2 | #define _ASM_X86_XOR_32_H |
3 | 3 | ||
4 | /* | 4 | /* |
5 | * Optimized RAID-5 checksumming functions for MMX and SSE. | 5 | * Optimized RAID-5 checksumming functions for MMX. |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
@@ -529,290 +529,6 @@ static struct xor_block_template xor_block_p5_mmx = { | |||
529 | .do_5 = xor_p5_mmx_5, | 529 | .do_5 = xor_p5_mmx_5, |
530 | }; | 530 | }; |
531 | 531 | ||
532 | /* | ||
533 | * Cache avoiding checksumming functions utilizing KNI instructions | ||
534 | * Copyright (C) 1999 Zach Brown (with obvious credit due Ingo) | ||
535 | */ | ||
536 | |||
537 | #define OFFS(x) "16*("#x")" | ||
538 | #define PF_OFFS(x) "256+16*("#x")" | ||
539 | #define PF0(x) " prefetchnta "PF_OFFS(x)"(%1) ;\n" | ||
540 | #define LD(x, y) " movaps "OFFS(x)"(%1), %%xmm"#y" ;\n" | ||
541 | #define ST(x, y) " movaps %%xmm"#y", "OFFS(x)"(%1) ;\n" | ||
542 | #define PF1(x) " prefetchnta "PF_OFFS(x)"(%2) ;\n" | ||
543 | #define PF2(x) " prefetchnta "PF_OFFS(x)"(%3) ;\n" | ||
544 | #define PF3(x) " prefetchnta "PF_OFFS(x)"(%4) ;\n" | ||
545 | #define PF4(x) " prefetchnta "PF_OFFS(x)"(%5) ;\n" | ||
546 | #define PF5(x) " prefetchnta "PF_OFFS(x)"(%6) ;\n" | ||
547 | #define XO1(x, y) " xorps "OFFS(x)"(%2), %%xmm"#y" ;\n" | ||
548 | #define XO2(x, y) " xorps "OFFS(x)"(%3), %%xmm"#y" ;\n" | ||
549 | #define XO3(x, y) " xorps "OFFS(x)"(%4), %%xmm"#y" ;\n" | ||
550 | #define XO4(x, y) " xorps "OFFS(x)"(%5), %%xmm"#y" ;\n" | ||
551 | #define XO5(x, y) " xorps "OFFS(x)"(%6), %%xmm"#y" ;\n" | ||
552 | |||
553 | |||
554 | static void | ||
555 | xor_sse_2(unsigned long bytes, unsigned long *p1, unsigned long *p2) | ||
556 | { | ||
557 | unsigned long lines = bytes >> 8; | ||
558 | |||
559 | kernel_fpu_begin(); | ||
560 | |||
561 | asm volatile( | ||
562 | #undef BLOCK | ||
563 | #define BLOCK(i) \ | ||
564 | LD(i, 0) \ | ||
565 | LD(i + 1, 1) \ | ||
566 | PF1(i) \ | ||
567 | PF1(i + 2) \ | ||
568 | LD(i + 2, 2) \ | ||
569 | LD(i + 3, 3) \ | ||
570 | PF0(i + 4) \ | ||
571 | PF0(i + 6) \ | ||
572 | XO1(i, 0) \ | ||
573 | XO1(i + 1, 1) \ | ||
574 | XO1(i + 2, 2) \ | ||
575 | XO1(i + 3, 3) \ | ||
576 | ST(i, 0) \ | ||
577 | ST(i + 1, 1) \ | ||
578 | ST(i + 2, 2) \ | ||
579 | ST(i + 3, 3) \ | ||
580 | |||
581 | |||
582 | PF0(0) | ||
583 | PF0(2) | ||
584 | |||
585 | " .align 32 ;\n" | ||
586 | " 1: ;\n" | ||
587 | |||
588 | BLOCK(0) | ||
589 | BLOCK(4) | ||
590 | BLOCK(8) | ||
591 | BLOCK(12) | ||
592 | |||
593 | " addl $256, %1 ;\n" | ||
594 | " addl $256, %2 ;\n" | ||
595 | " decl %0 ;\n" | ||
596 | " jnz 1b ;\n" | ||
597 | : "+r" (lines), | ||
598 | "+r" (p1), "+r" (p2) | ||
599 | : | ||
600 | : "memory"); | ||
601 | |||
602 | kernel_fpu_end(); | ||
603 | } | ||
604 | |||
605 | static void | ||
606 | xor_sse_3(unsigned long bytes, unsigned long *p1, unsigned long *p2, | ||
607 | unsigned long *p3) | ||
608 | { | ||
609 | unsigned long lines = bytes >> 8; | ||
610 | |||
611 | kernel_fpu_begin(); | ||
612 | |||
613 | asm volatile( | ||
614 | #undef BLOCK | ||
615 | #define BLOCK(i) \ | ||
616 | PF1(i) \ | ||
617 | PF1(i + 2) \ | ||
618 | LD(i,0) \ | ||
619 | LD(i + 1, 1) \ | ||
620 | LD(i + 2, 2) \ | ||
621 | LD(i + 3, 3) \ | ||
622 | PF2(i) \ | ||
623 | PF2(i + 2) \ | ||
624 | PF0(i + 4) \ | ||
625 | PF0(i + 6) \ | ||
626 | XO1(i,0) \ | ||
627 | XO1(i + 1, 1) \ | ||
628 | XO1(i + 2, 2) \ | ||
629 | XO1(i + 3, 3) \ | ||
630 | XO2(i,0) \ | ||
631 | XO2(i + 1, 1) \ | ||
632 | XO2(i + 2, 2) \ | ||
633 | XO2(i + 3, 3) \ | ||
634 | ST(i,0) \ | ||
635 | ST(i + 1, 1) \ | ||
636 | ST(i + 2, 2) \ | ||
637 | ST(i + 3, 3) \ | ||
638 | |||
639 | |||
640 | PF0(0) | ||
641 | PF0(2) | ||
642 | |||
643 | " .align 32 ;\n" | ||
644 | " 1: ;\n" | ||
645 | |||
646 | BLOCK(0) | ||
647 | BLOCK(4) | ||
648 | BLOCK(8) | ||
649 | BLOCK(12) | ||
650 | |||
651 | " addl $256, %1 ;\n" | ||
652 | " addl $256, %2 ;\n" | ||
653 | " addl $256, %3 ;\n" | ||
654 | " decl %0 ;\n" | ||
655 | " jnz 1b ;\n" | ||
656 | : "+r" (lines), | ||
657 | "+r" (p1), "+r"(p2), "+r"(p3) | ||
658 | : | ||
659 | : "memory" ); | ||
660 | |||
661 | kernel_fpu_end(); | ||
662 | } | ||
663 | |||
664 | static void | ||
665 | xor_sse_4(unsigned long bytes, unsigned long *p1, unsigned long *p2, | ||
666 | unsigned long *p3, unsigned long *p4) | ||
667 | { | ||
668 | unsigned long lines = bytes >> 8; | ||
669 | |||
670 | kernel_fpu_begin(); | ||
671 | |||
672 | asm volatile( | ||
673 | #undef BLOCK | ||
674 | #define BLOCK(i) \ | ||
675 | PF1(i) \ | ||
676 | PF1(i + 2) \ | ||
677 | LD(i,0) \ | ||
678 | LD(i + 1, 1) \ | ||
679 | LD(i + 2, 2) \ | ||
680 | LD(i + 3, 3) \ | ||
681 | PF2(i) \ | ||
682 | PF2(i + 2) \ | ||
683 | XO1(i,0) \ | ||
684 | XO1(i + 1, 1) \ | ||
685 | XO1(i + 2, 2) \ | ||
686 | XO1(i + 3, 3) \ | ||
687 | PF3(i) \ | ||
688 | PF3(i + 2) \ | ||
689 | PF0(i + 4) \ | ||
690 | PF0(i + 6) \ | ||
691 | XO2(i,0) \ | ||
692 | XO2(i + 1, 1) \ | ||
693 | XO2(i + 2, 2) \ | ||
694 | XO2(i + 3, 3) \ | ||
695 | XO3(i,0) \ | ||
696 | XO3(i + 1, 1) \ | ||
697 | XO3(i + 2, 2) \ | ||
698 | XO3(i + 3, 3) \ | ||
699 | ST(i,0) \ | ||
700 | ST(i + 1, 1) \ | ||
701 | ST(i + 2, 2) \ | ||
702 | ST(i + 3, 3) \ | ||
703 | |||
704 | |||
705 | PF0(0) | ||
706 | PF0(2) | ||
707 | |||
708 | " .align 32 ;\n" | ||
709 | " 1: ;\n" | ||
710 | |||
711 | BLOCK(0) | ||
712 | BLOCK(4) | ||
713 | BLOCK(8) | ||
714 | BLOCK(12) | ||
715 | |||
716 | " addl $256, %1 ;\n" | ||
717 | " addl $256, %2 ;\n" | ||
718 | " addl $256, %3 ;\n" | ||
719 | " addl $256, %4 ;\n" | ||
720 | " decl %0 ;\n" | ||
721 | " jnz 1b ;\n" | ||
722 | : "+r" (lines), | ||
723 | "+r" (p1), "+r" (p2), "+r" (p3), "+r" (p4) | ||
724 | : | ||
725 | : "memory" ); | ||
726 | |||
727 | kernel_fpu_end(); | ||
728 | } | ||
729 | |||
730 | static void | ||
731 | xor_sse_5(unsigned long bytes, unsigned long *p1, unsigned long *p2, | ||
732 | unsigned long *p3, unsigned long *p4, unsigned long *p5) | ||
733 | { | ||
734 | unsigned long lines = bytes >> 8; | ||
735 | |||
736 | kernel_fpu_begin(); | ||
737 | |||
738 | /* Make sure GCC forgets anything it knows about p4 or p5, | ||
739 | such that it won't pass to the asm volatile below a | ||
740 | register that is shared with any other variable. That's | ||
741 | because we modify p4 and p5 there, but we can't mark them | ||
742 | as read/write, otherwise we'd overflow the 10-asm-operands | ||
743 | limit of GCC < 3.1. */ | ||
744 | asm("" : "+r" (p4), "+r" (p5)); | ||
745 | |||
746 | asm volatile( | ||
747 | #undef BLOCK | ||
748 | #define BLOCK(i) \ | ||
749 | PF1(i) \ | ||
750 | PF1(i + 2) \ | ||
751 | LD(i,0) \ | ||
752 | LD(i + 1, 1) \ | ||
753 | LD(i + 2, 2) \ | ||
754 | LD(i + 3, 3) \ | ||
755 | PF2(i) \ | ||
756 | PF2(i + 2) \ | ||
757 | XO1(i,0) \ | ||
758 | XO1(i + 1, 1) \ | ||
759 | XO1(i + 2, 2) \ | ||
760 | XO1(i + 3, 3) \ | ||
761 | PF3(i) \ | ||
762 | PF3(i + 2) \ | ||
763 | XO2(i,0) \ | ||
764 | XO2(i + 1, 1) \ | ||
765 | XO2(i + 2, 2) \ | ||
766 | XO2(i + 3, 3) \ | ||
767 | PF4(i) \ | ||
768 | PF4(i + 2) \ | ||
769 | PF0(i + 4) \ | ||
770 | PF0(i + 6) \ | ||
771 | XO3(i,0) \ | ||
772 | XO3(i + 1, 1) \ | ||
773 | XO3(i + 2, 2) \ | ||
774 | XO3(i + 3, 3) \ | ||
775 | XO4(i,0) \ | ||
776 | XO4(i + 1, 1) \ | ||
777 | XO4(i + 2, 2) \ | ||
778 | XO4(i + 3, 3) \ | ||
779 | ST(i,0) \ | ||
780 | ST(i + 1, 1) \ | ||
781 | ST(i + 2, 2) \ | ||
782 | ST(i + 3, 3) \ | ||
783 | |||
784 | |||
785 | PF0(0) | ||
786 | PF0(2) | ||
787 | |||
788 | " .align 32 ;\n" | ||
789 | " 1: ;\n" | ||
790 | |||
791 | BLOCK(0) | ||
792 | BLOCK(4) | ||
793 | BLOCK(8) | ||
794 | BLOCK(12) | ||
795 | |||
796 | " addl $256, %1 ;\n" | ||
797 | " addl $256, %2 ;\n" | ||
798 | " addl $256, %3 ;\n" | ||
799 | " addl $256, %4 ;\n" | ||
800 | " addl $256, %5 ;\n" | ||
801 | " decl %0 ;\n" | ||
802 | " jnz 1b ;\n" | ||
803 | : "+r" (lines), | ||
804 | "+r" (p1), "+r" (p2), "+r" (p3) | ||
805 | : "r" (p4), "r" (p5) | ||
806 | : "memory"); | ||
807 | |||
808 | /* p4 and p5 were modified, and now the variables are dead. | ||
809 | Clobber them just to be sure nobody does something stupid | ||
810 | like assuming they have some legal value. */ | ||
811 | asm("" : "=r" (p4), "=r" (p5)); | ||
812 | |||
813 | kernel_fpu_end(); | ||
814 | } | ||
815 | |||
816 | static struct xor_block_template xor_block_pIII_sse = { | 532 | static struct xor_block_template xor_block_pIII_sse = { |
817 | .name = "pIII_sse", | 533 | .name = "pIII_sse", |
818 | .do_2 = xor_sse_2, | 534 | .do_2 = xor_sse_2, |
@@ -827,26 +543,25 @@ static struct xor_block_template xor_block_pIII_sse = { | |||
827 | /* Also try the generic routines. */ | 543 | /* Also try the generic routines. */ |
828 | #include <asm-generic/xor.h> | 544 | #include <asm-generic/xor.h> |
829 | 545 | ||
546 | /* We force the use of the SSE xor block because it can write around L2. | ||
547 | We may also be able to load into the L1 only depending on how the cpu | ||
548 | deals with a load to a line that is being prefetched. */ | ||
830 | #undef XOR_TRY_TEMPLATES | 549 | #undef XOR_TRY_TEMPLATES |
831 | #define XOR_TRY_TEMPLATES \ | 550 | #define XOR_TRY_TEMPLATES \ |
832 | do { \ | 551 | do { \ |
833 | xor_speed(&xor_block_8regs); \ | ||
834 | xor_speed(&xor_block_8regs_p); \ | ||
835 | xor_speed(&xor_block_32regs); \ | ||
836 | xor_speed(&xor_block_32regs_p); \ | ||
837 | AVX_XOR_SPEED; \ | 552 | AVX_XOR_SPEED; \ |
838 | if (cpu_has_xmm) \ | 553 | if (cpu_has_xmm) { \ |
839 | xor_speed(&xor_block_pIII_sse); \ | 554 | xor_speed(&xor_block_pIII_sse); \ |
840 | if (cpu_has_mmx) { \ | 555 | xor_speed(&xor_block_sse_pf64); \ |
556 | } else if (cpu_has_mmx) { \ | ||
841 | xor_speed(&xor_block_pII_mmx); \ | 557 | xor_speed(&xor_block_pII_mmx); \ |
842 | xor_speed(&xor_block_p5_mmx); \ | 558 | xor_speed(&xor_block_p5_mmx); \ |
559 | } else { \ | ||
560 | xor_speed(&xor_block_8regs); \ | ||
561 | xor_speed(&xor_block_8regs_p); \ | ||
562 | xor_speed(&xor_block_32regs); \ | ||
563 | xor_speed(&xor_block_32regs_p); \ | ||
843 | } \ | 564 | } \ |
844 | } while (0) | 565 | } while (0) |
845 | 566 | ||
846 | /* We force the use of the SSE xor block because it can write around L2. | ||
847 | We may also be able to load into the L1 only depending on how the cpu | ||
848 | deals with a load to a line that is being prefetched. */ | ||
849 | #define XOR_SELECT_TEMPLATE(FASTEST) \ | ||
850 | AVX_SELECT(cpu_has_xmm ? &xor_block_pIII_sse : FASTEST) | ||
851 | |||
852 | #endif /* _ASM_X86_XOR_32_H */ | 567 | #endif /* _ASM_X86_XOR_32_H */ |
diff --git a/arch/x86/include/asm/xor_64.h b/arch/x86/include/asm/xor_64.h index 87ac522c4af5..546f1e3b87cc 100644 --- a/arch/x86/include/asm/xor_64.h +++ b/arch/x86/include/asm/xor_64.h | |||
@@ -1,301 +1,6 @@ | |||
1 | #ifndef _ASM_X86_XOR_64_H | 1 | #ifndef _ASM_X86_XOR_64_H |
2 | #define _ASM_X86_XOR_64_H | 2 | #define _ASM_X86_XOR_64_H |
3 | 3 | ||
4 | /* | ||
5 | * Optimized RAID-5 checksumming functions for MMX and SSE. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2, or (at your option) | ||
10 | * any later version. | ||
11 | * | ||
12 | * You should have received a copy of the GNU General Public License | ||
13 | * (for example /usr/src/linux/COPYING); if not, write to the Free | ||
14 | * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
15 | */ | ||
16 | |||
17 | |||
18 | /* | ||
19 | * Cache avoiding checksumming functions utilizing KNI instructions | ||
20 | * Copyright (C) 1999 Zach Brown (with obvious credit due Ingo) | ||
21 | */ | ||
22 | |||
23 | /* | ||
24 | * Based on | ||
25 | * High-speed RAID5 checksumming functions utilizing SSE instructions. | ||
26 | * Copyright (C) 1998 Ingo Molnar. | ||
27 | */ | ||
28 | |||
29 | /* | ||
30 | * x86-64 changes / gcc fixes from Andi Kleen. | ||
31 | * Copyright 2002 Andi Kleen, SuSE Labs. | ||
32 | * | ||
33 | * This hasn't been optimized for the hammer yet, but there are likely | ||
34 | * no advantages to be gotten from x86-64 here anyways. | ||
35 | */ | ||
36 | |||
37 | #include <asm/i387.h> | ||
38 | |||
39 | #define OFFS(x) "16*("#x")" | ||
40 | #define PF_OFFS(x) "256+16*("#x")" | ||
41 | #define PF0(x) " prefetchnta "PF_OFFS(x)"(%[p1]) ;\n" | ||
42 | #define LD(x, y) " movaps "OFFS(x)"(%[p1]), %%xmm"#y" ;\n" | ||
43 | #define ST(x, y) " movaps %%xmm"#y", "OFFS(x)"(%[p1]) ;\n" | ||
44 | #define PF1(x) " prefetchnta "PF_OFFS(x)"(%[p2]) ;\n" | ||
45 | #define PF2(x) " prefetchnta "PF_OFFS(x)"(%[p3]) ;\n" | ||
46 | #define PF3(x) " prefetchnta "PF_OFFS(x)"(%[p4]) ;\n" | ||
47 | #define PF4(x) " prefetchnta "PF_OFFS(x)"(%[p5]) ;\n" | ||
48 | #define PF5(x) " prefetchnta "PF_OFFS(x)"(%[p6]) ;\n" | ||
49 | #define XO1(x, y) " xorps "OFFS(x)"(%[p2]), %%xmm"#y" ;\n" | ||
50 | #define XO2(x, y) " xorps "OFFS(x)"(%[p3]), %%xmm"#y" ;\n" | ||
51 | #define XO3(x, y) " xorps "OFFS(x)"(%[p4]), %%xmm"#y" ;\n" | ||
52 | #define XO4(x, y) " xorps "OFFS(x)"(%[p5]), %%xmm"#y" ;\n" | ||
53 | #define XO5(x, y) " xorps "OFFS(x)"(%[p6]), %%xmm"#y" ;\n" | ||
54 | |||
55 | |||
56 | static void | ||
57 | xor_sse_2(unsigned long bytes, unsigned long *p1, unsigned long *p2) | ||
58 | { | ||
59 | unsigned int lines = bytes >> 8; | ||
60 | |||
61 | kernel_fpu_begin(); | ||
62 | |||
63 | asm volatile( | ||
64 | #undef BLOCK | ||
65 | #define BLOCK(i) \ | ||
66 | LD(i, 0) \ | ||
67 | LD(i + 1, 1) \ | ||
68 | PF1(i) \ | ||
69 | PF1(i + 2) \ | ||
70 | LD(i + 2, 2) \ | ||
71 | LD(i + 3, 3) \ | ||
72 | PF0(i + 4) \ | ||
73 | PF0(i + 6) \ | ||
74 | XO1(i, 0) \ | ||
75 | XO1(i + 1, 1) \ | ||
76 | XO1(i + 2, 2) \ | ||
77 | XO1(i + 3, 3) \ | ||
78 | ST(i, 0) \ | ||
79 | ST(i + 1, 1) \ | ||
80 | ST(i + 2, 2) \ | ||
81 | ST(i + 3, 3) \ | ||
82 | |||
83 | |||
84 | PF0(0) | ||
85 | PF0(2) | ||
86 | |||
87 | " .align 32 ;\n" | ||
88 | " 1: ;\n" | ||
89 | |||
90 | BLOCK(0) | ||
91 | BLOCK(4) | ||
92 | BLOCK(8) | ||
93 | BLOCK(12) | ||
94 | |||
95 | " addq %[inc], %[p1] ;\n" | ||
96 | " addq %[inc], %[p2] ;\n" | ||
97 | " decl %[cnt] ; jnz 1b" | ||
98 | : [p1] "+r" (p1), [p2] "+r" (p2), [cnt] "+r" (lines) | ||
99 | : [inc] "r" (256UL) | ||
100 | : "memory"); | ||
101 | |||
102 | kernel_fpu_end(); | ||
103 | } | ||
104 | |||
105 | static void | ||
106 | xor_sse_3(unsigned long bytes, unsigned long *p1, unsigned long *p2, | ||
107 | unsigned long *p3) | ||
108 | { | ||
109 | unsigned int lines = bytes >> 8; | ||
110 | |||
111 | kernel_fpu_begin(); | ||
112 | asm volatile( | ||
113 | #undef BLOCK | ||
114 | #define BLOCK(i) \ | ||
115 | PF1(i) \ | ||
116 | PF1(i + 2) \ | ||
117 | LD(i, 0) \ | ||
118 | LD(i + 1, 1) \ | ||
119 | LD(i + 2, 2) \ | ||
120 | LD(i + 3, 3) \ | ||
121 | PF2(i) \ | ||
122 | PF2(i + 2) \ | ||
123 | PF0(i + 4) \ | ||
124 | PF0(i + 6) \ | ||
125 | XO1(i, 0) \ | ||
126 | XO1(i + 1, 1) \ | ||
127 | XO1(i + 2, 2) \ | ||
128 | XO1(i + 3, 3) \ | ||
129 | XO2(i, 0) \ | ||
130 | XO2(i + 1, 1) \ | ||
131 | XO2(i + 2, 2) \ | ||
132 | XO2(i + 3, 3) \ | ||
133 | ST(i, 0) \ | ||
134 | ST(i + 1, 1) \ | ||
135 | ST(i + 2, 2) \ | ||
136 | ST(i + 3, 3) \ | ||
137 | |||
138 | |||
139 | PF0(0) | ||
140 | PF0(2) | ||
141 | |||
142 | " .align 32 ;\n" | ||
143 | " 1: ;\n" | ||
144 | |||
145 | BLOCK(0) | ||
146 | BLOCK(4) | ||
147 | BLOCK(8) | ||
148 | BLOCK(12) | ||
149 | |||
150 | " addq %[inc], %[p1] ;\n" | ||
151 | " addq %[inc], %[p2] ;\n" | ||
152 | " addq %[inc], %[p3] ;\n" | ||
153 | " decl %[cnt] ; jnz 1b" | ||
154 | : [cnt] "+r" (lines), | ||
155 | [p1] "+r" (p1), [p2] "+r" (p2), [p3] "+r" (p3) | ||
156 | : [inc] "r" (256UL) | ||
157 | : "memory"); | ||
158 | kernel_fpu_end(); | ||
159 | } | ||
160 | |||
161 | static void | ||
162 | xor_sse_4(unsigned long bytes, unsigned long *p1, unsigned long *p2, | ||
163 | unsigned long *p3, unsigned long *p4) | ||
164 | { | ||
165 | unsigned int lines = bytes >> 8; | ||
166 | |||
167 | kernel_fpu_begin(); | ||
168 | |||
169 | asm volatile( | ||
170 | #undef BLOCK | ||
171 | #define BLOCK(i) \ | ||
172 | PF1(i) \ | ||
173 | PF1(i + 2) \ | ||
174 | LD(i, 0) \ | ||
175 | LD(i + 1, 1) \ | ||
176 | LD(i + 2, 2) \ | ||
177 | LD(i + 3, 3) \ | ||
178 | PF2(i) \ | ||
179 | PF2(i + 2) \ | ||
180 | XO1(i, 0) \ | ||
181 | XO1(i + 1, 1) \ | ||
182 | XO1(i + 2, 2) \ | ||
183 | XO1(i + 3, 3) \ | ||
184 | PF3(i) \ | ||
185 | PF3(i + 2) \ | ||
186 | PF0(i + 4) \ | ||
187 | PF0(i + 6) \ | ||
188 | XO2(i, 0) \ | ||
189 | XO2(i + 1, 1) \ | ||
190 | XO2(i + 2, 2) \ | ||
191 | XO2(i + 3, 3) \ | ||
192 | XO3(i, 0) \ | ||
193 | XO3(i + 1, 1) \ | ||
194 | XO3(i + 2, 2) \ | ||
195 | XO3(i + 3, 3) \ | ||
196 | ST(i, 0) \ | ||
197 | ST(i + 1, 1) \ | ||
198 | ST(i + 2, 2) \ | ||
199 | ST(i + 3, 3) \ | ||
200 | |||
201 | |||
202 | PF0(0) | ||
203 | PF0(2) | ||
204 | |||
205 | " .align 32 ;\n" | ||
206 | " 1: ;\n" | ||
207 | |||
208 | BLOCK(0) | ||
209 | BLOCK(4) | ||
210 | BLOCK(8) | ||
211 | BLOCK(12) | ||
212 | |||
213 | " addq %[inc], %[p1] ;\n" | ||
214 | " addq %[inc], %[p2] ;\n" | ||
215 | " addq %[inc], %[p3] ;\n" | ||
216 | " addq %[inc], %[p4] ;\n" | ||
217 | " decl %[cnt] ; jnz 1b" | ||
218 | : [cnt] "+c" (lines), | ||
219 | [p1] "+r" (p1), [p2] "+r" (p2), [p3] "+r" (p3), [p4] "+r" (p4) | ||
220 | : [inc] "r" (256UL) | ||
221 | : "memory" ); | ||
222 | |||
223 | kernel_fpu_end(); | ||
224 | } | ||
225 | |||
226 | static void | ||
227 | xor_sse_5(unsigned long bytes, unsigned long *p1, unsigned long *p2, | ||
228 | unsigned long *p3, unsigned long *p4, unsigned long *p5) | ||
229 | { | ||
230 | unsigned int lines = bytes >> 8; | ||
231 | |||
232 | kernel_fpu_begin(); | ||
233 | |||
234 | asm volatile( | ||
235 | #undef BLOCK | ||
236 | #define BLOCK(i) \ | ||
237 | PF1(i) \ | ||
238 | PF1(i + 2) \ | ||
239 | LD(i, 0) \ | ||
240 | LD(i + 1, 1) \ | ||
241 | LD(i + 2, 2) \ | ||
242 | LD(i + 3, 3) \ | ||
243 | PF2(i) \ | ||
244 | PF2(i + 2) \ | ||
245 | XO1(i, 0) \ | ||
246 | XO1(i + 1, 1) \ | ||
247 | XO1(i + 2, 2) \ | ||
248 | XO1(i + 3, 3) \ | ||
249 | PF3(i) \ | ||
250 | PF3(i + 2) \ | ||
251 | XO2(i, 0) \ | ||
252 | XO2(i + 1, 1) \ | ||
253 | XO2(i + 2, 2) \ | ||
254 | XO2(i + 3, 3) \ | ||
255 | PF4(i) \ | ||
256 | PF4(i + 2) \ | ||
257 | PF0(i + 4) \ | ||
258 | PF0(i + 6) \ | ||
259 | XO3(i, 0) \ | ||
260 | XO3(i + 1, 1) \ | ||
261 | XO3(i + 2, 2) \ | ||
262 | XO3(i + 3, 3) \ | ||
263 | XO4(i, 0) \ | ||
264 | XO4(i + 1, 1) \ | ||
265 | XO4(i + 2, 2) \ | ||
266 | XO4(i + 3, 3) \ | ||
267 | ST(i, 0) \ | ||
268 | ST(i + 1, 1) \ | ||
269 | ST(i + 2, 2) \ | ||
270 | ST(i + 3, 3) \ | ||
271 | |||
272 | |||
273 | PF0(0) | ||
274 | PF0(2) | ||
275 | |||
276 | " .align 32 ;\n" | ||
277 | " 1: ;\n" | ||
278 | |||
279 | BLOCK(0) | ||
280 | BLOCK(4) | ||
281 | BLOCK(8) | ||
282 | BLOCK(12) | ||
283 | |||
284 | " addq %[inc], %[p1] ;\n" | ||
285 | " addq %[inc], %[p2] ;\n" | ||
286 | " addq %[inc], %[p3] ;\n" | ||
287 | " addq %[inc], %[p4] ;\n" | ||
288 | " addq %[inc], %[p5] ;\n" | ||
289 | " decl %[cnt] ; jnz 1b" | ||
290 | : [cnt] "+c" (lines), | ||
291 | [p1] "+r" (p1), [p2] "+r" (p2), [p3] "+r" (p3), [p4] "+r" (p4), | ||
292 | [p5] "+r" (p5) | ||
293 | : [inc] "r" (256UL) | ||
294 | : "memory"); | ||
295 | |||
296 | kernel_fpu_end(); | ||
297 | } | ||
298 | |||
299 | static struct xor_block_template xor_block_sse = { | 4 | static struct xor_block_template xor_block_sse = { |
300 | .name = "generic_sse", | 5 | .name = "generic_sse", |
301 | .do_2 = xor_sse_2, | 6 | .do_2 = xor_sse_2, |
@@ -308,17 +13,15 @@ static struct xor_block_template xor_block_sse = { | |||
308 | /* Also try the AVX routines */ | 13 | /* Also try the AVX routines */ |
309 | #include <asm/xor_avx.h> | 14 | #include <asm/xor_avx.h> |
310 | 15 | ||
16 | /* We force the use of the SSE xor block because it can write around L2. | ||
17 | We may also be able to load into the L1 only depending on how the cpu | ||
18 | deals with a load to a line that is being prefetched. */ | ||
311 | #undef XOR_TRY_TEMPLATES | 19 | #undef XOR_TRY_TEMPLATES |
312 | #define XOR_TRY_TEMPLATES \ | 20 | #define XOR_TRY_TEMPLATES \ |
313 | do { \ | 21 | do { \ |
314 | AVX_XOR_SPEED; \ | 22 | AVX_XOR_SPEED; \ |
23 | xor_speed(&xor_block_sse_pf64); \ | ||
315 | xor_speed(&xor_block_sse); \ | 24 | xor_speed(&xor_block_sse); \ |
316 | } while (0) | 25 | } while (0) |
317 | 26 | ||
318 | /* We force the use of the SSE xor block because it can write around L2. | ||
319 | We may also be able to load into the L1 only depending on how the cpu | ||
320 | deals with a load to a line that is being prefetched. */ | ||
321 | #define XOR_SELECT_TEMPLATE(FASTEST) \ | ||
322 | AVX_SELECT(&xor_block_sse) | ||
323 | |||
324 | #endif /* _ASM_X86_XOR_64_H */ | 27 | #endif /* _ASM_X86_XOR_64_H */ |
diff --git a/arch/x86/include/uapi/asm/mce.h b/arch/x86/include/uapi/asm/mce.h index 58c829871c31..a0eab85ce7b8 100644 --- a/arch/x86/include/uapi/asm/mce.h +++ b/arch/x86/include/uapi/asm/mce.h | |||
@@ -4,66 +4,6 @@ | |||
4 | #include <linux/types.h> | 4 | #include <linux/types.h> |
5 | #include <asm/ioctls.h> | 5 | #include <asm/ioctls.h> |
6 | 6 | ||
7 | /* | ||
8 | * Machine Check support for x86 | ||
9 | */ | ||
10 | |||
11 | /* MCG_CAP register defines */ | ||
12 | #define MCG_BANKCNT_MASK 0xff /* Number of Banks */ | ||
13 | #define MCG_CTL_P (1ULL<<8) /* MCG_CTL register available */ | ||
14 | #define MCG_EXT_P (1ULL<<9) /* Extended registers available */ | ||
15 | #define MCG_CMCI_P (1ULL<<10) /* CMCI supported */ | ||
16 | #define MCG_EXT_CNT_MASK 0xff0000 /* Number of Extended registers */ | ||
17 | #define MCG_EXT_CNT_SHIFT 16 | ||
18 | #define MCG_EXT_CNT(c) (((c) & MCG_EXT_CNT_MASK) >> MCG_EXT_CNT_SHIFT) | ||
19 | #define MCG_SER_P (1ULL<<24) /* MCA recovery/new status bits */ | ||
20 | |||
21 | /* MCG_STATUS register defines */ | ||
22 | #define MCG_STATUS_RIPV (1ULL<<0) /* restart ip valid */ | ||
23 | #define MCG_STATUS_EIPV (1ULL<<1) /* ip points to correct instruction */ | ||
24 | #define MCG_STATUS_MCIP (1ULL<<2) /* machine check in progress */ | ||
25 | |||
26 | /* MCi_STATUS register defines */ | ||
27 | #define MCI_STATUS_VAL (1ULL<<63) /* valid error */ | ||
28 | #define MCI_STATUS_OVER (1ULL<<62) /* previous errors lost */ | ||
29 | #define MCI_STATUS_UC (1ULL<<61) /* uncorrected error */ | ||
30 | #define MCI_STATUS_EN (1ULL<<60) /* error enabled */ | ||
31 | #define MCI_STATUS_MISCV (1ULL<<59) /* misc error reg. valid */ | ||
32 | #define MCI_STATUS_ADDRV (1ULL<<58) /* addr reg. valid */ | ||
33 | #define MCI_STATUS_PCC (1ULL<<57) /* processor context corrupt */ | ||
34 | #define MCI_STATUS_S (1ULL<<56) /* Signaled machine check */ | ||
35 | #define MCI_STATUS_AR (1ULL<<55) /* Action required */ | ||
36 | #define MCACOD 0xffff /* MCA Error Code */ | ||
37 | |||
38 | /* Architecturally defined codes from SDM Vol. 3B Chapter 15 */ | ||
39 | #define MCACOD_SCRUB 0x00C0 /* 0xC0-0xCF Memory Scrubbing */ | ||
40 | #define MCACOD_SCRUBMSK 0xfff0 | ||
41 | #define MCACOD_L3WB 0x017A /* L3 Explicit Writeback */ | ||
42 | #define MCACOD_DATA 0x0134 /* Data Load */ | ||
43 | #define MCACOD_INSTR 0x0150 /* Instruction Fetch */ | ||
44 | |||
45 | /* MCi_MISC register defines */ | ||
46 | #define MCI_MISC_ADDR_LSB(m) ((m) & 0x3f) | ||
47 | #define MCI_MISC_ADDR_MODE(m) (((m) >> 6) & 7) | ||
48 | #define MCI_MISC_ADDR_SEGOFF 0 /* segment offset */ | ||
49 | #define MCI_MISC_ADDR_LINEAR 1 /* linear address */ | ||
50 | #define MCI_MISC_ADDR_PHYS 2 /* physical address */ | ||
51 | #define MCI_MISC_ADDR_MEM 3 /* memory address */ | ||
52 | #define MCI_MISC_ADDR_GENERIC 7 /* generic */ | ||
53 | |||
54 | /* CTL2 register defines */ | ||
55 | #define MCI_CTL2_CMCI_EN (1ULL << 30) | ||
56 | #define MCI_CTL2_CMCI_THRESHOLD_MASK 0x7fffULL | ||
57 | |||
58 | #define MCJ_CTX_MASK 3 | ||
59 | #define MCJ_CTX(flags) ((flags) & MCJ_CTX_MASK) | ||
60 | #define MCJ_CTX_RANDOM 0 /* inject context: random */ | ||
61 | #define MCJ_CTX_PROCESS 0x1 /* inject context: process */ | ||
62 | #define MCJ_CTX_IRQ 0x2 /* inject context: IRQ */ | ||
63 | #define MCJ_NMI_BROADCAST 0x4 /* do NMI broadcasting */ | ||
64 | #define MCJ_EXCEPTION 0x8 /* raise as exception */ | ||
65 | #define MCJ_IRQ_BRAODCAST 0x10 /* do IRQ broadcasting */ | ||
66 | |||
67 | /* Fields are zero when not available */ | 7 | /* Fields are zero when not available */ |
68 | struct mce { | 8 | struct mce { |
69 | __u64 status; | 9 | __u64 status; |
@@ -87,35 +27,8 @@ struct mce { | |||
87 | __u64 mcgcap; /* MCGCAP MSR: machine check capabilities of CPU */ | 27 | __u64 mcgcap; /* MCGCAP MSR: machine check capabilities of CPU */ |
88 | }; | 28 | }; |
89 | 29 | ||
90 | /* | ||
91 | * This structure contains all data related to the MCE log. Also | ||
92 | * carries a signature to make it easier to find from external | ||
93 | * debugging tools. Each entry is only valid when its finished flag | ||
94 | * is set. | ||
95 | */ | ||
96 | |||
97 | #define MCE_LOG_LEN 32 | ||
98 | |||
99 | struct mce_log { | ||
100 | char signature[12]; /* "MACHINECHECK" */ | ||
101 | unsigned len; /* = MCE_LOG_LEN */ | ||
102 | unsigned next; | ||
103 | unsigned flags; | ||
104 | unsigned recordlen; /* length of struct mce */ | ||
105 | struct mce entry[MCE_LOG_LEN]; | ||
106 | }; | ||
107 | |||
108 | #define MCE_OVERFLOW 0 /* bit 0 in flags means overflow */ | ||
109 | |||
110 | #define MCE_LOG_SIGNATURE "MACHINECHECK" | ||
111 | |||
112 | #define MCE_GET_RECORD_LEN _IOR('M', 1, int) | 30 | #define MCE_GET_RECORD_LEN _IOR('M', 1, int) |
113 | #define MCE_GET_LOG_LEN _IOR('M', 2, int) | 31 | #define MCE_GET_LOG_LEN _IOR('M', 2, int) |
114 | #define MCE_GETCLEAR_FLAGS _IOR('M', 3, int) | 32 | #define MCE_GETCLEAR_FLAGS _IOR('M', 3, int) |
115 | 33 | ||
116 | /* Software defined banks */ | ||
117 | #define MCE_EXTENDED_BANK 128 | ||
118 | #define MCE_THERMAL_BANK MCE_EXTENDED_BANK + 0 | ||
119 | #define K8_MCE_THRESHOLD_BASE (MCE_EXTENDED_BANK + 1) | ||
120 | |||
121 | #endif /* _UAPI_ASM_X86_MCE_H */ | 34 | #endif /* _UAPI_ASM_X86_MCE_H */ |
diff --git a/arch/x86/include/uapi/asm/msr-index.h b/arch/x86/include/uapi/asm/msr-index.h index 433a59fb1a74..075a40255591 100644 --- a/arch/x86/include/uapi/asm/msr-index.h +++ b/arch/x86/include/uapi/asm/msr-index.h | |||
@@ -194,6 +194,8 @@ | |||
194 | /* Fam 15h MSRs */ | 194 | /* Fam 15h MSRs */ |
195 | #define MSR_F15H_PERF_CTL 0xc0010200 | 195 | #define MSR_F15H_PERF_CTL 0xc0010200 |
196 | #define MSR_F15H_PERF_CTR 0xc0010201 | 196 | #define MSR_F15H_PERF_CTR 0xc0010201 |
197 | #define MSR_F15H_NB_PERF_CTL 0xc0010240 | ||
198 | #define MSR_F15H_NB_PERF_CTR 0xc0010241 | ||
197 | 199 | ||
198 | /* Fam 10h MSRs */ | 200 | /* Fam 10h MSRs */ |
199 | #define MSR_FAM10H_MMIO_CONF_BASE 0xc0010058 | 201 | #define MSR_FAM10H_MMIO_CONF_BASE 0xc0010058 |
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 34e923a53762..ac3b3d002833 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile | |||
@@ -65,8 +65,7 @@ obj-$(CONFIG_X86_TSC) += trace_clock.o | |||
65 | obj-$(CONFIG_KEXEC) += machine_kexec_$(BITS).o | 65 | obj-$(CONFIG_KEXEC) += machine_kexec_$(BITS).o |
66 | obj-$(CONFIG_KEXEC) += relocate_kernel_$(BITS).o crash.o | 66 | obj-$(CONFIG_KEXEC) += relocate_kernel_$(BITS).o crash.o |
67 | obj-$(CONFIG_CRASH_DUMP) += crash_dump_$(BITS).o | 67 | obj-$(CONFIG_CRASH_DUMP) += crash_dump_$(BITS).o |
68 | obj-$(CONFIG_KPROBES) += kprobes.o | 68 | obj-y += kprobes/ |
69 | obj-$(CONFIG_OPTPROBES) += kprobes-opt.o | ||
70 | obj-$(CONFIG_MODULES) += module.o | 69 | obj-$(CONFIG_MODULES) += module.o |
71 | obj-$(CONFIG_DOUBLEFAULT) += doublefault_32.o | 70 | obj-$(CONFIG_DOUBLEFAULT) += doublefault_32.o |
72 | obj-$(CONFIG_KGDB) += kgdb.o | 71 | obj-$(CONFIG_KGDB) += kgdb.o |
diff --git a/arch/x86/kernel/apb_timer.c b/arch/x86/kernel/apb_timer.c index afdc3f756dea..c9876efecafb 100644 --- a/arch/x86/kernel/apb_timer.c +++ b/arch/x86/kernel/apb_timer.c | |||
@@ -240,7 +240,7 @@ static int apbt_cpuhp_notify(struct notifier_block *n, | |||
240 | dw_apb_clockevent_pause(adev->timer); | 240 | dw_apb_clockevent_pause(adev->timer); |
241 | if (system_state == SYSTEM_RUNNING) { | 241 | if (system_state == SYSTEM_RUNNING) { |
242 | pr_debug("skipping APBT CPU %lu offline\n", cpu); | 242 | pr_debug("skipping APBT CPU %lu offline\n", cpu); |
243 | } else if (adev) { | 243 | } else { |
244 | pr_debug("APBT clockevent for cpu %lu offline\n", cpu); | 244 | pr_debug("APBT clockevent for cpu %lu offline\n", cpu); |
245 | dw_apb_clockevent_stop(adev->timer); | 245 | dw_apb_clockevent_stop(adev->timer); |
246 | } | 246 | } |
@@ -311,7 +311,6 @@ void __init apbt_time_init(void) | |||
311 | #ifdef CONFIG_SMP | 311 | #ifdef CONFIG_SMP |
312 | int i; | 312 | int i; |
313 | struct sfi_timer_table_entry *p_mtmr; | 313 | struct sfi_timer_table_entry *p_mtmr; |
314 | unsigned int percpu_timer; | ||
315 | struct apbt_dev *adev; | 314 | struct apbt_dev *adev; |
316 | #endif | 315 | #endif |
317 | 316 | ||
@@ -346,13 +345,10 @@ void __init apbt_time_init(void) | |||
346 | return; | 345 | return; |
347 | } | 346 | } |
348 | pr_debug("%s: %d CPUs online\n", __func__, num_online_cpus()); | 347 | pr_debug("%s: %d CPUs online\n", __func__, num_online_cpus()); |
349 | if (num_possible_cpus() <= sfi_mtimer_num) { | 348 | if (num_possible_cpus() <= sfi_mtimer_num) |
350 | percpu_timer = 1; | ||
351 | apbt_num_timers_used = num_possible_cpus(); | 349 | apbt_num_timers_used = num_possible_cpus(); |
352 | } else { | 350 | else |
353 | percpu_timer = 0; | ||
354 | apbt_num_timers_used = 1; | 351 | apbt_num_timers_used = 1; |
355 | } | ||
356 | pr_debug("%s: %d APB timers used\n", __func__, apbt_num_timers_used); | 352 | pr_debug("%s: %d APB timers used\n", __func__, apbt_num_timers_used); |
357 | 353 | ||
358 | /* here we set up per CPU timer data structure */ | 354 | /* here we set up per CPU timer data structure */ |
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index b994cc84aa7e..a5b4dce1b7ac 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c | |||
@@ -1477,8 +1477,7 @@ void __init bsp_end_local_APIC_setup(void) | |||
1477 | * Now that local APIC setup is completed for BP, configure the fault | 1477 | * Now that local APIC setup is completed for BP, configure the fault |
1478 | * handling for interrupt remapping. | 1478 | * handling for interrupt remapping. |
1479 | */ | 1479 | */ |
1480 | if (irq_remapping_enabled) | 1480 | irq_remap_enable_fault_handling(); |
1481 | irq_remap_enable_fault_handling(); | ||
1482 | 1481 | ||
1483 | } | 1482 | } |
1484 | 1483 | ||
@@ -2251,8 +2250,7 @@ static int lapic_suspend(void) | |||
2251 | local_irq_save(flags); | 2250 | local_irq_save(flags); |
2252 | disable_local_APIC(); | 2251 | disable_local_APIC(); |
2253 | 2252 | ||
2254 | if (irq_remapping_enabled) | 2253 | irq_remapping_disable(); |
2255 | irq_remapping_disable(); | ||
2256 | 2254 | ||
2257 | local_irq_restore(flags); | 2255 | local_irq_restore(flags); |
2258 | return 0; | 2256 | return 0; |
@@ -2268,16 +2266,15 @@ static void lapic_resume(void) | |||
2268 | return; | 2266 | return; |
2269 | 2267 | ||
2270 | local_irq_save(flags); | 2268 | local_irq_save(flags); |
2271 | if (irq_remapping_enabled) { | 2269 | |
2272 | /* | 2270 | /* |
2273 | * IO-APIC and PIC have their own resume routines. | 2271 | * IO-APIC and PIC have their own resume routines. |
2274 | * We just mask them here to make sure the interrupt | 2272 | * We just mask them here to make sure the interrupt |
2275 | * subsystem is completely quiet while we enable x2apic | 2273 | * subsystem is completely quiet while we enable x2apic |
2276 | * and interrupt-remapping. | 2274 | * and interrupt-remapping. |
2277 | */ | 2275 | */ |
2278 | mask_ioapic_entries(); | 2276 | mask_ioapic_entries(); |
2279 | legacy_pic->mask_all(); | 2277 | legacy_pic->mask_all(); |
2280 | } | ||
2281 | 2278 | ||
2282 | if (x2apic_mode) | 2279 | if (x2apic_mode) |
2283 | enable_x2apic(); | 2280 | enable_x2apic(); |
@@ -2320,8 +2317,7 @@ static void lapic_resume(void) | |||
2320 | apic_write(APIC_ESR, 0); | 2317 | apic_write(APIC_ESR, 0); |
2321 | apic_read(APIC_ESR); | 2318 | apic_read(APIC_ESR); |
2322 | 2319 | ||
2323 | if (irq_remapping_enabled) | 2320 | irq_remapping_reenable(x2apic_mode); |
2324 | irq_remapping_reenable(x2apic_mode); | ||
2325 | 2321 | ||
2326 | local_irq_restore(flags); | 2322 | local_irq_restore(flags); |
2327 | } | 2323 | } |
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index b739d398bb29..9ed796ccc32c 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c | |||
@@ -68,22 +68,6 @@ | |||
68 | #define for_each_irq_pin(entry, head) \ | 68 | #define for_each_irq_pin(entry, head) \ |
69 | for (entry = head; entry; entry = entry->next) | 69 | for (entry = head; entry; entry = entry->next) |
70 | 70 | ||
71 | #ifdef CONFIG_IRQ_REMAP | ||
72 | static void irq_remap_modify_chip_defaults(struct irq_chip *chip); | ||
73 | static inline bool irq_remapped(struct irq_cfg *cfg) | ||
74 | { | ||
75 | return cfg->irq_2_iommu.iommu != NULL; | ||
76 | } | ||
77 | #else | ||
78 | static inline bool irq_remapped(struct irq_cfg *cfg) | ||
79 | { | ||
80 | return false; | ||
81 | } | ||
82 | static inline void irq_remap_modify_chip_defaults(struct irq_chip *chip) | ||
83 | { | ||
84 | } | ||
85 | #endif | ||
86 | |||
87 | /* | 71 | /* |
88 | * Is the SiS APIC rmw bug present ? | 72 | * Is the SiS APIC rmw bug present ? |
89 | * -1 = don't know, 0 = no, 1 = yes | 73 | * -1 = don't know, 0 = no, 1 = yes |
@@ -300,9 +284,9 @@ static struct irq_cfg *alloc_irq_and_cfg_at(unsigned int at, int node) | |||
300 | return cfg; | 284 | return cfg; |
301 | } | 285 | } |
302 | 286 | ||
303 | static int alloc_irq_from(unsigned int from, int node) | 287 | static int alloc_irqs_from(unsigned int from, unsigned int count, int node) |
304 | { | 288 | { |
305 | return irq_alloc_desc_from(from, node); | 289 | return irq_alloc_descs_from(from, count, node); |
306 | } | 290 | } |
307 | 291 | ||
308 | static void free_irq_at(unsigned int at, struct irq_cfg *cfg) | 292 | static void free_irq_at(unsigned int at, struct irq_cfg *cfg) |
@@ -326,7 +310,7 @@ static __attribute_const__ struct io_apic __iomem *io_apic_base(int idx) | |||
326 | + (mpc_ioapic_addr(idx) & ~PAGE_MASK); | 310 | + (mpc_ioapic_addr(idx) & ~PAGE_MASK); |
327 | } | 311 | } |
328 | 312 | ||
329 | static inline void io_apic_eoi(unsigned int apic, unsigned int vector) | 313 | void io_apic_eoi(unsigned int apic, unsigned int vector) |
330 | { | 314 | { |
331 | struct io_apic __iomem *io_apic = io_apic_base(apic); | 315 | struct io_apic __iomem *io_apic = io_apic_base(apic); |
332 | writel(vector, &io_apic->eoi); | 316 | writel(vector, &io_apic->eoi); |
@@ -573,19 +557,10 @@ static void unmask_ioapic_irq(struct irq_data *data) | |||
573 | * Otherwise, we simulate the EOI message manually by changing the trigger | 557 | * Otherwise, we simulate the EOI message manually by changing the trigger |
574 | * mode to edge and then back to level, with RTE being masked during this. | 558 | * mode to edge and then back to level, with RTE being masked during this. |
575 | */ | 559 | */ |
576 | static void __eoi_ioapic_pin(int apic, int pin, int vector, struct irq_cfg *cfg) | 560 | void native_eoi_ioapic_pin(int apic, int pin, int vector) |
577 | { | 561 | { |
578 | if (mpc_ioapic_ver(apic) >= 0x20) { | 562 | if (mpc_ioapic_ver(apic) >= 0x20) { |
579 | /* | 563 | io_apic_eoi(apic, vector); |
580 | * Intr-remapping uses pin number as the virtual vector | ||
581 | * in the RTE. Actual vector is programmed in | ||
582 | * intr-remapping table entry. Hence for the io-apic | ||
583 | * EOI we use the pin number. | ||
584 | */ | ||
585 | if (cfg && irq_remapped(cfg)) | ||
586 | io_apic_eoi(apic, pin); | ||
587 | else | ||
588 | io_apic_eoi(apic, vector); | ||
589 | } else { | 564 | } else { |
590 | struct IO_APIC_route_entry entry, entry1; | 565 | struct IO_APIC_route_entry entry, entry1; |
591 | 566 | ||
@@ -606,14 +581,15 @@ static void __eoi_ioapic_pin(int apic, int pin, int vector, struct irq_cfg *cfg) | |||
606 | } | 581 | } |
607 | } | 582 | } |
608 | 583 | ||
609 | static void eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg) | 584 | void eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg) |
610 | { | 585 | { |
611 | struct irq_pin_list *entry; | 586 | struct irq_pin_list *entry; |
612 | unsigned long flags; | 587 | unsigned long flags; |
613 | 588 | ||
614 | raw_spin_lock_irqsave(&ioapic_lock, flags); | 589 | raw_spin_lock_irqsave(&ioapic_lock, flags); |
615 | for_each_irq_pin(entry, cfg->irq_2_pin) | 590 | for_each_irq_pin(entry, cfg->irq_2_pin) |
616 | __eoi_ioapic_pin(entry->apic, entry->pin, cfg->vector, cfg); | 591 | x86_io_apic_ops.eoi_ioapic_pin(entry->apic, entry->pin, |
592 | cfg->vector); | ||
617 | raw_spin_unlock_irqrestore(&ioapic_lock, flags); | 593 | raw_spin_unlock_irqrestore(&ioapic_lock, flags); |
618 | } | 594 | } |
619 | 595 | ||
@@ -650,7 +626,7 @@ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) | |||
650 | } | 626 | } |
651 | 627 | ||
652 | raw_spin_lock_irqsave(&ioapic_lock, flags); | 628 | raw_spin_lock_irqsave(&ioapic_lock, flags); |
653 | __eoi_ioapic_pin(apic, pin, entry.vector, NULL); | 629 | x86_io_apic_ops.eoi_ioapic_pin(apic, pin, entry.vector); |
654 | raw_spin_unlock_irqrestore(&ioapic_lock, flags); | 630 | raw_spin_unlock_irqrestore(&ioapic_lock, flags); |
655 | } | 631 | } |
656 | 632 | ||
@@ -1304,25 +1280,18 @@ static void ioapic_register_intr(unsigned int irq, struct irq_cfg *cfg, | |||
1304 | fasteoi = false; | 1280 | fasteoi = false; |
1305 | } | 1281 | } |
1306 | 1282 | ||
1307 | if (irq_remapped(cfg)) { | 1283 | if (setup_remapped_irq(irq, cfg, chip)) |
1308 | irq_set_status_flags(irq, IRQ_MOVE_PCNTXT); | ||
1309 | irq_remap_modify_chip_defaults(chip); | ||
1310 | fasteoi = trigger != 0; | 1284 | fasteoi = trigger != 0; |
1311 | } | ||
1312 | 1285 | ||
1313 | hdl = fasteoi ? handle_fasteoi_irq : handle_edge_irq; | 1286 | hdl = fasteoi ? handle_fasteoi_irq : handle_edge_irq; |
1314 | irq_set_chip_and_handler_name(irq, chip, hdl, | 1287 | irq_set_chip_and_handler_name(irq, chip, hdl, |
1315 | fasteoi ? "fasteoi" : "edge"); | 1288 | fasteoi ? "fasteoi" : "edge"); |
1316 | } | 1289 | } |
1317 | 1290 | ||
1318 | static int setup_ioapic_entry(int irq, struct IO_APIC_route_entry *entry, | 1291 | int native_setup_ioapic_entry(int irq, struct IO_APIC_route_entry *entry, |
1319 | unsigned int destination, int vector, | 1292 | unsigned int destination, int vector, |
1320 | struct io_apic_irq_attr *attr) | 1293 | struct io_apic_irq_attr *attr) |
1321 | { | 1294 | { |
1322 | if (irq_remapping_enabled) | ||
1323 | return setup_ioapic_remapped_entry(irq, entry, destination, | ||
1324 | vector, attr); | ||
1325 | |||
1326 | memset(entry, 0, sizeof(*entry)); | 1295 | memset(entry, 0, sizeof(*entry)); |
1327 | 1296 | ||
1328 | entry->delivery_mode = apic->irq_delivery_mode; | 1297 | entry->delivery_mode = apic->irq_delivery_mode; |
@@ -1370,8 +1339,8 @@ static void setup_ioapic_irq(unsigned int irq, struct irq_cfg *cfg, | |||
1370 | attr->ioapic, mpc_ioapic_id(attr->ioapic), attr->ioapic_pin, | 1339 | attr->ioapic, mpc_ioapic_id(attr->ioapic), attr->ioapic_pin, |
1371 | cfg->vector, irq, attr->trigger, attr->polarity, dest); | 1340 | cfg->vector, irq, attr->trigger, attr->polarity, dest); |
1372 | 1341 | ||
1373 | if (setup_ioapic_entry(irq, &entry, dest, cfg->vector, attr)) { | 1342 | if (x86_io_apic_ops.setup_entry(irq, &entry, dest, cfg->vector, attr)) { |
1374 | pr_warn("Failed to setup ioapic entry for ioapic %d, pin %d\n", | 1343 | pr_warn("Failed to setup ioapic entry for ioapic %d, pin %d\n", |
1375 | mpc_ioapic_id(attr->ioapic), attr->ioapic_pin); | 1344 | mpc_ioapic_id(attr->ioapic), attr->ioapic_pin); |
1376 | __clear_irq_vector(irq, cfg); | 1345 | __clear_irq_vector(irq, cfg); |
1377 | 1346 | ||
@@ -1479,9 +1448,6 @@ static void __init setup_timer_IRQ0_pin(unsigned int ioapic_idx, | |||
1479 | struct IO_APIC_route_entry entry; | 1448 | struct IO_APIC_route_entry entry; |
1480 | unsigned int dest; | 1449 | unsigned int dest; |
1481 | 1450 | ||
1482 | if (irq_remapping_enabled) | ||
1483 | return; | ||
1484 | |||
1485 | memset(&entry, 0, sizeof(entry)); | 1451 | memset(&entry, 0, sizeof(entry)); |
1486 | 1452 | ||
1487 | /* | 1453 | /* |
@@ -1513,9 +1479,63 @@ static void __init setup_timer_IRQ0_pin(unsigned int ioapic_idx, | |||
1513 | ioapic_write_entry(ioapic_idx, pin, entry); | 1479 | ioapic_write_entry(ioapic_idx, pin, entry); |
1514 | } | 1480 | } |
1515 | 1481 | ||
1516 | __apicdebuginit(void) print_IO_APIC(int ioapic_idx) | 1482 | void native_io_apic_print_entries(unsigned int apic, unsigned int nr_entries) |
1517 | { | 1483 | { |
1518 | int i; | 1484 | int i; |
1485 | |||
1486 | pr_debug(" NR Dst Mask Trig IRR Pol Stat Dmod Deli Vect:\n"); | ||
1487 | |||
1488 | for (i = 0; i <= nr_entries; i++) { | ||
1489 | struct IO_APIC_route_entry entry; | ||
1490 | |||
1491 | entry = ioapic_read_entry(apic, i); | ||
1492 | |||
1493 | pr_debug(" %02x %02X ", i, entry.dest); | ||
1494 | pr_cont("%1d %1d %1d %1d %1d " | ||
1495 | "%1d %1d %02X\n", | ||
1496 | entry.mask, | ||
1497 | entry.trigger, | ||
1498 | entry.irr, | ||
1499 | entry.polarity, | ||
1500 | entry.delivery_status, | ||
1501 | entry.dest_mode, | ||
1502 | entry.delivery_mode, | ||
1503 | entry.vector); | ||
1504 | } | ||
1505 | } | ||
1506 | |||
1507 | void intel_ir_io_apic_print_entries(unsigned int apic, | ||
1508 | unsigned int nr_entries) | ||
1509 | { | ||
1510 | int i; | ||
1511 | |||
1512 | pr_debug(" NR Indx Fmt Mask Trig IRR Pol Stat Indx2 Zero Vect:\n"); | ||
1513 | |||
1514 | for (i = 0; i <= nr_entries; i++) { | ||
1515 | struct IR_IO_APIC_route_entry *ir_entry; | ||
1516 | struct IO_APIC_route_entry entry; | ||
1517 | |||
1518 | entry = ioapic_read_entry(apic, i); | ||
1519 | |||
1520 | ir_entry = (struct IR_IO_APIC_route_entry *)&entry; | ||
1521 | |||
1522 | pr_debug(" %02x %04X ", i, ir_entry->index); | ||
1523 | pr_cont("%1d %1d %1d %1d %1d " | ||
1524 | "%1d %1d %X %02X\n", | ||
1525 | ir_entry->format, | ||
1526 | ir_entry->mask, | ||
1527 | ir_entry->trigger, | ||
1528 | ir_entry->irr, | ||
1529 | ir_entry->polarity, | ||
1530 | ir_entry->delivery_status, | ||
1531 | ir_entry->index2, | ||
1532 | ir_entry->zero, | ||
1533 | ir_entry->vector); | ||
1534 | } | ||
1535 | } | ||
1536 | |||
1537 | __apicdebuginit(void) print_IO_APIC(int ioapic_idx) | ||
1538 | { | ||
1519 | union IO_APIC_reg_00 reg_00; | 1539 | union IO_APIC_reg_00 reg_00; |
1520 | union IO_APIC_reg_01 reg_01; | 1540 | union IO_APIC_reg_01 reg_01; |
1521 | union IO_APIC_reg_02 reg_02; | 1541 | union IO_APIC_reg_02 reg_02; |
@@ -1568,58 +1588,7 @@ __apicdebuginit(void) print_IO_APIC(int ioapic_idx) | |||
1568 | 1588 | ||
1569 | printk(KERN_DEBUG ".... IRQ redirection table:\n"); | 1589 | printk(KERN_DEBUG ".... IRQ redirection table:\n"); |
1570 | 1590 | ||
1571 | if (irq_remapping_enabled) { | 1591 | x86_io_apic_ops.print_entries(ioapic_idx, reg_01.bits.entries); |
1572 | printk(KERN_DEBUG " NR Indx Fmt Mask Trig IRR" | ||
1573 | " Pol Stat Indx2 Zero Vect:\n"); | ||
1574 | } else { | ||
1575 | printk(KERN_DEBUG " NR Dst Mask Trig IRR Pol" | ||
1576 | " Stat Dmod Deli Vect:\n"); | ||
1577 | } | ||
1578 | |||
1579 | for (i = 0; i <= reg_01.bits.entries; i++) { | ||
1580 | if (irq_remapping_enabled) { | ||
1581 | struct IO_APIC_route_entry entry; | ||
1582 | struct IR_IO_APIC_route_entry *ir_entry; | ||
1583 | |||
1584 | entry = ioapic_read_entry(ioapic_idx, i); | ||
1585 | ir_entry = (struct IR_IO_APIC_route_entry *) &entry; | ||
1586 | printk(KERN_DEBUG " %02x %04X ", | ||
1587 | i, | ||
1588 | ir_entry->index | ||
1589 | ); | ||
1590 | pr_cont("%1d %1d %1d %1d %1d " | ||
1591 | "%1d %1d %X %02X\n", | ||
1592 | ir_entry->format, | ||
1593 | ir_entry->mask, | ||
1594 | ir_entry->trigger, | ||
1595 | ir_entry->irr, | ||
1596 | ir_entry->polarity, | ||
1597 | ir_entry->delivery_status, | ||
1598 | ir_entry->index2, | ||
1599 | ir_entry->zero, | ||
1600 | ir_entry->vector | ||
1601 | ); | ||
1602 | } else { | ||
1603 | struct IO_APIC_route_entry entry; | ||
1604 | |||
1605 | entry = ioapic_read_entry(ioapic_idx, i); | ||
1606 | printk(KERN_DEBUG " %02x %02X ", | ||
1607 | i, | ||
1608 | entry.dest | ||
1609 | ); | ||
1610 | pr_cont("%1d %1d %1d %1d %1d " | ||
1611 | "%1d %1d %02X\n", | ||
1612 | entry.mask, | ||
1613 | entry.trigger, | ||
1614 | entry.irr, | ||
1615 | entry.polarity, | ||
1616 | entry.delivery_status, | ||
1617 | entry.dest_mode, | ||
1618 | entry.delivery_mode, | ||
1619 | entry.vector | ||
1620 | ); | ||
1621 | } | ||
1622 | } | ||
1623 | } | 1592 | } |
1624 | 1593 | ||
1625 | __apicdebuginit(void) print_IO_APICs(void) | 1594 | __apicdebuginit(void) print_IO_APICs(void) |
@@ -1921,30 +1890,14 @@ void __init enable_IO_APIC(void) | |||
1921 | clear_IO_APIC(); | 1890 | clear_IO_APIC(); |
1922 | } | 1891 | } |
1923 | 1892 | ||
1924 | /* | 1893 | void native_disable_io_apic(void) |
1925 | * Not an __init, needed by the reboot code | ||
1926 | */ | ||
1927 | void disable_IO_APIC(void) | ||
1928 | { | 1894 | { |
1929 | /* | 1895 | /* |
1930 | * Clear the IO-APIC before rebooting: | ||
1931 | */ | ||
1932 | clear_IO_APIC(); | ||
1933 | |||
1934 | if (!legacy_pic->nr_legacy_irqs) | ||
1935 | return; | ||
1936 | |||
1937 | /* | ||
1938 | * If the i8259 is routed through an IOAPIC | 1896 | * If the i8259 is routed through an IOAPIC |
1939 | * Put that IOAPIC in virtual wire mode | 1897 | * Put that IOAPIC in virtual wire mode |
1940 | * so legacy interrupts can be delivered. | 1898 | * so legacy interrupts can be delivered. |
1941 | * | ||
1942 | * With interrupt-remapping, for now we will use virtual wire A mode, | ||
1943 | * as virtual wire B is little complex (need to configure both | ||
1944 | * IOAPIC RTE as well as interrupt-remapping table entry). | ||
1945 | * As this gets called during crash dump, keep this simple for now. | ||
1946 | */ | 1899 | */ |
1947 | if (ioapic_i8259.pin != -1 && !irq_remapping_enabled) { | 1900 | if (ioapic_i8259.pin != -1) { |
1948 | struct IO_APIC_route_entry entry; | 1901 | struct IO_APIC_route_entry entry; |
1949 | 1902 | ||
1950 | memset(&entry, 0, sizeof(entry)); | 1903 | memset(&entry, 0, sizeof(entry)); |
@@ -1964,12 +1917,25 @@ void disable_IO_APIC(void) | |||
1964 | ioapic_write_entry(ioapic_i8259.apic, ioapic_i8259.pin, entry); | 1917 | ioapic_write_entry(ioapic_i8259.apic, ioapic_i8259.pin, entry); |
1965 | } | 1918 | } |
1966 | 1919 | ||
1920 | if (cpu_has_apic || apic_from_smp_config()) | ||
1921 | disconnect_bsp_APIC(ioapic_i8259.pin != -1); | ||
1922 | |||
1923 | } | ||
1924 | |||
1925 | /* | ||
1926 | * Not an __init, needed by the reboot code | ||
1927 | */ | ||
1928 | void disable_IO_APIC(void) | ||
1929 | { | ||
1967 | /* | 1930 | /* |
1968 | * Use virtual wire A mode when interrupt remapping is enabled. | 1931 | * Clear the IO-APIC before rebooting: |
1969 | */ | 1932 | */ |
1970 | if (cpu_has_apic || apic_from_smp_config()) | 1933 | clear_IO_APIC(); |
1971 | disconnect_bsp_APIC(!irq_remapping_enabled && | 1934 | |
1972 | ioapic_i8259.pin != -1); | 1935 | if (!legacy_pic->nr_legacy_irqs) |
1936 | return; | ||
1937 | |||
1938 | x86_io_apic_ops.disable(); | ||
1973 | } | 1939 | } |
1974 | 1940 | ||
1975 | #ifdef CONFIG_X86_32 | 1941 | #ifdef CONFIG_X86_32 |
@@ -2322,12 +2288,8 @@ static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, struct irq | |||
2322 | 2288 | ||
2323 | apic = entry->apic; | 2289 | apic = entry->apic; |
2324 | pin = entry->pin; | 2290 | pin = entry->pin; |
2325 | /* | 2291 | |
2326 | * With interrupt-remapping, destination information comes | 2292 | io_apic_write(apic, 0x11 + pin*2, dest); |
2327 | * from interrupt-remapping table entry. | ||
2328 | */ | ||
2329 | if (!irq_remapped(cfg)) | ||
2330 | io_apic_write(apic, 0x11 + pin*2, dest); | ||
2331 | reg = io_apic_read(apic, 0x10 + pin*2); | 2293 | reg = io_apic_read(apic, 0x10 + pin*2); |
2332 | reg &= ~IO_APIC_REDIR_VECTOR_MASK; | 2294 | reg &= ~IO_APIC_REDIR_VECTOR_MASK; |
2333 | reg |= vector; | 2295 | reg |= vector; |
@@ -2369,9 +2331,10 @@ int __ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask, | |||
2369 | return 0; | 2331 | return 0; |
2370 | } | 2332 | } |
2371 | 2333 | ||
2372 | static int | 2334 | |
2373 | ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask, | 2335 | int native_ioapic_set_affinity(struct irq_data *data, |
2374 | bool force) | 2336 | const struct cpumask *mask, |
2337 | bool force) | ||
2375 | { | 2338 | { |
2376 | unsigned int dest, irq = data->irq; | 2339 | unsigned int dest, irq = data->irq; |
2377 | unsigned long flags; | 2340 | unsigned long flags; |
@@ -2548,33 +2511,6 @@ static void ack_apic_level(struct irq_data *data) | |||
2548 | ioapic_irqd_unmask(data, cfg, masked); | 2511 | ioapic_irqd_unmask(data, cfg, masked); |
2549 | } | 2512 | } |
2550 | 2513 | ||
2551 | #ifdef CONFIG_IRQ_REMAP | ||
2552 | static void ir_ack_apic_edge(struct irq_data *data) | ||
2553 | { | ||
2554 | ack_APIC_irq(); | ||
2555 | } | ||
2556 | |||
2557 | static void ir_ack_apic_level(struct irq_data *data) | ||
2558 | { | ||
2559 | ack_APIC_irq(); | ||
2560 | eoi_ioapic_irq(data->irq, data->chip_data); | ||
2561 | } | ||
2562 | |||
2563 | static void ir_print_prefix(struct irq_data *data, struct seq_file *p) | ||
2564 | { | ||
2565 | seq_printf(p, " IR-%s", data->chip->name); | ||
2566 | } | ||
2567 | |||
2568 | static void irq_remap_modify_chip_defaults(struct irq_chip *chip) | ||
2569 | { | ||
2570 | chip->irq_print_chip = ir_print_prefix; | ||
2571 | chip->irq_ack = ir_ack_apic_edge; | ||
2572 | chip->irq_eoi = ir_ack_apic_level; | ||
2573 | |||
2574 | chip->irq_set_affinity = set_remapped_irq_affinity; | ||
2575 | } | ||
2576 | #endif /* CONFIG_IRQ_REMAP */ | ||
2577 | |||
2578 | static struct irq_chip ioapic_chip __read_mostly = { | 2514 | static struct irq_chip ioapic_chip __read_mostly = { |
2579 | .name = "IO-APIC", | 2515 | .name = "IO-APIC", |
2580 | .irq_startup = startup_ioapic_irq, | 2516 | .irq_startup = startup_ioapic_irq, |
@@ -2582,7 +2518,7 @@ static struct irq_chip ioapic_chip __read_mostly = { | |||
2582 | .irq_unmask = unmask_ioapic_irq, | 2518 | .irq_unmask = unmask_ioapic_irq, |
2583 | .irq_ack = ack_apic_edge, | 2519 | .irq_ack = ack_apic_edge, |
2584 | .irq_eoi = ack_apic_level, | 2520 | .irq_eoi = ack_apic_level, |
2585 | .irq_set_affinity = ioapic_set_affinity, | 2521 | .irq_set_affinity = native_ioapic_set_affinity, |
2586 | .irq_retrigger = ioapic_retrigger_irq, | 2522 | .irq_retrigger = ioapic_retrigger_irq, |
2587 | }; | 2523 | }; |
2588 | 2524 | ||
@@ -2781,8 +2717,7 @@ static inline void __init check_timer(void) | |||
2781 | * 8259A. | 2717 | * 8259A. |
2782 | */ | 2718 | */ |
2783 | if (pin1 == -1) { | 2719 | if (pin1 == -1) { |
2784 | if (irq_remapping_enabled) | 2720 | panic_if_irq_remap("BIOS bug: timer not connected to IO-APIC"); |
2785 | panic("BIOS bug: timer not connected to IO-APIC"); | ||
2786 | pin1 = pin2; | 2721 | pin1 = pin2; |
2787 | apic1 = apic2; | 2722 | apic1 = apic2; |
2788 | no_pin1 = 1; | 2723 | no_pin1 = 1; |
@@ -2814,8 +2749,7 @@ static inline void __init check_timer(void) | |||
2814 | clear_IO_APIC_pin(0, pin1); | 2749 | clear_IO_APIC_pin(0, pin1); |
2815 | goto out; | 2750 | goto out; |
2816 | } | 2751 | } |
2817 | if (irq_remapping_enabled) | 2752 | panic_if_irq_remap("timer doesn't work through Interrupt-remapped IO-APIC"); |
2818 | panic("timer doesn't work through Interrupt-remapped IO-APIC"); | ||
2819 | local_irq_disable(); | 2753 | local_irq_disable(); |
2820 | clear_IO_APIC_pin(apic1, pin1); | 2754 | clear_IO_APIC_pin(apic1, pin1); |
2821 | if (!no_pin1) | 2755 | if (!no_pin1) |
@@ -2982,37 +2916,58 @@ device_initcall(ioapic_init_ops); | |||
2982 | /* | 2916 | /* |
2983 | * Dynamic irq allocate and deallocation | 2917 | * Dynamic irq allocate and deallocation |
2984 | */ | 2918 | */ |
2985 | unsigned int create_irq_nr(unsigned int from, int node) | 2919 | unsigned int __create_irqs(unsigned int from, unsigned int count, int node) |
2986 | { | 2920 | { |
2987 | struct irq_cfg *cfg; | 2921 | struct irq_cfg **cfg; |
2988 | unsigned long flags; | 2922 | unsigned long flags; |
2989 | unsigned int ret = 0; | 2923 | int irq, i; |
2990 | int irq; | ||
2991 | 2924 | ||
2992 | if (from < nr_irqs_gsi) | 2925 | if (from < nr_irqs_gsi) |
2993 | from = nr_irqs_gsi; | 2926 | from = nr_irqs_gsi; |
2994 | 2927 | ||
2995 | irq = alloc_irq_from(from, node); | 2928 | cfg = kzalloc_node(count * sizeof(cfg[0]), GFP_KERNEL, node); |
2996 | if (irq < 0) | 2929 | if (!cfg) |
2997 | return 0; | ||
2998 | cfg = alloc_irq_cfg(irq, node); | ||
2999 | if (!cfg) { | ||
3000 | free_irq_at(irq, NULL); | ||
3001 | return 0; | 2930 | return 0; |
2931 | |||
2932 | irq = alloc_irqs_from(from, count, node); | ||
2933 | if (irq < 0) | ||
2934 | goto out_cfgs; | ||
2935 | |||
2936 | for (i = 0; i < count; i++) { | ||
2937 | cfg[i] = alloc_irq_cfg(irq + i, node); | ||
2938 | if (!cfg[i]) | ||
2939 | goto out_irqs; | ||
3002 | } | 2940 | } |
3003 | 2941 | ||
3004 | raw_spin_lock_irqsave(&vector_lock, flags); | 2942 | raw_spin_lock_irqsave(&vector_lock, flags); |
3005 | if (!__assign_irq_vector(irq, cfg, apic->target_cpus())) | 2943 | for (i = 0; i < count; i++) |
3006 | ret = irq; | 2944 | if (__assign_irq_vector(irq + i, cfg[i], apic->target_cpus())) |
2945 | goto out_vecs; | ||
3007 | raw_spin_unlock_irqrestore(&vector_lock, flags); | 2946 | raw_spin_unlock_irqrestore(&vector_lock, flags); |
3008 | 2947 | ||
3009 | if (ret) { | 2948 | for (i = 0; i < count; i++) { |
3010 | irq_set_chip_data(irq, cfg); | 2949 | irq_set_chip_data(irq + i, cfg[i]); |
3011 | irq_clear_status_flags(irq, IRQ_NOREQUEST); | 2950 | irq_clear_status_flags(irq + i, IRQ_NOREQUEST); |
3012 | } else { | ||
3013 | free_irq_at(irq, cfg); | ||
3014 | } | 2951 | } |
3015 | return ret; | 2952 | |
2953 | kfree(cfg); | ||
2954 | return irq; | ||
2955 | |||
2956 | out_vecs: | ||
2957 | for (i--; i >= 0; i--) | ||
2958 | __clear_irq_vector(irq + i, cfg[i]); | ||
2959 | raw_spin_unlock_irqrestore(&vector_lock, flags); | ||
2960 | out_irqs: | ||
2961 | for (i = 0; i < count; i++) | ||
2962 | free_irq_at(irq + i, cfg[i]); | ||
2963 | out_cfgs: | ||
2964 | kfree(cfg); | ||
2965 | return 0; | ||
2966 | } | ||
2967 | |||
2968 | unsigned int create_irq_nr(unsigned int from, int node) | ||
2969 | { | ||
2970 | return __create_irqs(from, 1, node); | ||
3016 | } | 2971 | } |
3017 | 2972 | ||
3018 | int create_irq(void) | 2973 | int create_irq(void) |
@@ -3037,48 +2992,35 @@ void destroy_irq(unsigned int irq) | |||
3037 | 2992 | ||
3038 | irq_set_status_flags(irq, IRQ_NOREQUEST|IRQ_NOPROBE); | 2993 | irq_set_status_flags(irq, IRQ_NOREQUEST|IRQ_NOPROBE); |
3039 | 2994 | ||
3040 | if (irq_remapped(cfg)) | 2995 | free_remapped_irq(irq); |
3041 | free_remapped_irq(irq); | 2996 | |
3042 | raw_spin_lock_irqsave(&vector_lock, flags); | 2997 | raw_spin_lock_irqsave(&vector_lock, flags); |
3043 | __clear_irq_vector(irq, cfg); | 2998 | __clear_irq_vector(irq, cfg); |
3044 | raw_spin_unlock_irqrestore(&vector_lock, flags); | 2999 | raw_spin_unlock_irqrestore(&vector_lock, flags); |
3045 | free_irq_at(irq, cfg); | 3000 | free_irq_at(irq, cfg); |
3046 | } | 3001 | } |
3047 | 3002 | ||
3003 | void destroy_irqs(unsigned int irq, unsigned int count) | ||
3004 | { | ||
3005 | unsigned int i; | ||
3006 | |||
3007 | for (i = 0; i < count; i++) | ||
3008 | destroy_irq(irq + i); | ||
3009 | } | ||
3010 | |||
3048 | /* | 3011 | /* |
3049 | * MSI message composition | 3012 | * MSI message composition |
3050 | */ | 3013 | */ |
3051 | #ifdef CONFIG_PCI_MSI | 3014 | void native_compose_msi_msg(struct pci_dev *pdev, |
3052 | static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, | 3015 | unsigned int irq, unsigned int dest, |
3053 | struct msi_msg *msg, u8 hpet_id) | 3016 | struct msi_msg *msg, u8 hpet_id) |
3054 | { | 3017 | { |
3055 | struct irq_cfg *cfg; | 3018 | struct irq_cfg *cfg = irq_cfg(irq); |
3056 | int err; | ||
3057 | unsigned dest; | ||
3058 | |||
3059 | if (disable_apic) | ||
3060 | return -ENXIO; | ||
3061 | |||
3062 | cfg = irq_cfg(irq); | ||
3063 | err = assign_irq_vector(irq, cfg, apic->target_cpus()); | ||
3064 | if (err) | ||
3065 | return err; | ||
3066 | 3019 | ||
3067 | err = apic->cpu_mask_to_apicid_and(cfg->domain, | 3020 | msg->address_hi = MSI_ADDR_BASE_HI; |
3068 | apic->target_cpus(), &dest); | ||
3069 | if (err) | ||
3070 | return err; | ||
3071 | |||
3072 | if (irq_remapped(cfg)) { | ||
3073 | compose_remapped_msi_msg(pdev, irq, dest, msg, hpet_id); | ||
3074 | return err; | ||
3075 | } | ||
3076 | 3021 | ||
3077 | if (x2apic_enabled()) | 3022 | if (x2apic_enabled()) |
3078 | msg->address_hi = MSI_ADDR_BASE_HI | | 3023 | msg->address_hi |= MSI_ADDR_EXT_DEST_ID(dest); |
3079 | MSI_ADDR_EXT_DEST_ID(dest); | ||
3080 | else | ||
3081 | msg->address_hi = MSI_ADDR_BASE_HI; | ||
3082 | 3024 | ||
3083 | msg->address_lo = | 3025 | msg->address_lo = |
3084 | MSI_ADDR_BASE_LO | | 3026 | MSI_ADDR_BASE_LO | |
@@ -3097,8 +3039,32 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, | |||
3097 | MSI_DATA_DELIVERY_FIXED: | 3039 | MSI_DATA_DELIVERY_FIXED: |
3098 | MSI_DATA_DELIVERY_LOWPRI) | | 3040 | MSI_DATA_DELIVERY_LOWPRI) | |
3099 | MSI_DATA_VECTOR(cfg->vector); | 3041 | MSI_DATA_VECTOR(cfg->vector); |
3042 | } | ||
3100 | 3043 | ||
3101 | return err; | 3044 | #ifdef CONFIG_PCI_MSI |
3045 | static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, | ||
3046 | struct msi_msg *msg, u8 hpet_id) | ||
3047 | { | ||
3048 | struct irq_cfg *cfg; | ||
3049 | int err; | ||
3050 | unsigned dest; | ||
3051 | |||
3052 | if (disable_apic) | ||
3053 | return -ENXIO; | ||
3054 | |||
3055 | cfg = irq_cfg(irq); | ||
3056 | err = assign_irq_vector(irq, cfg, apic->target_cpus()); | ||
3057 | if (err) | ||
3058 | return err; | ||
3059 | |||
3060 | err = apic->cpu_mask_to_apicid_and(cfg->domain, | ||
3061 | apic->target_cpus(), &dest); | ||
3062 | if (err) | ||
3063 | return err; | ||
3064 | |||
3065 | x86_msi.compose_msi_msg(pdev, irq, dest, msg, hpet_id); | ||
3066 | |||
3067 | return 0; | ||
3102 | } | 3068 | } |
3103 | 3069 | ||
3104 | static int | 3070 | static int |
@@ -3136,23 +3102,28 @@ static struct irq_chip msi_chip = { | |||
3136 | .irq_retrigger = ioapic_retrigger_irq, | 3102 | .irq_retrigger = ioapic_retrigger_irq, |
3137 | }; | 3103 | }; |
3138 | 3104 | ||
3139 | static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int irq) | 3105 | int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, |
3106 | unsigned int irq_base, unsigned int irq_offset) | ||
3140 | { | 3107 | { |
3141 | struct irq_chip *chip = &msi_chip; | 3108 | struct irq_chip *chip = &msi_chip; |
3142 | struct msi_msg msg; | 3109 | struct msi_msg msg; |
3110 | unsigned int irq = irq_base + irq_offset; | ||
3143 | int ret; | 3111 | int ret; |
3144 | 3112 | ||
3145 | ret = msi_compose_msg(dev, irq, &msg, -1); | 3113 | ret = msi_compose_msg(dev, irq, &msg, -1); |
3146 | if (ret < 0) | 3114 | if (ret < 0) |
3147 | return ret; | 3115 | return ret; |
3148 | 3116 | ||
3149 | irq_set_msi_desc(irq, msidesc); | 3117 | irq_set_msi_desc_off(irq_base, irq_offset, msidesc); |
3150 | write_msi_msg(irq, &msg); | ||
3151 | 3118 | ||
3152 | if (irq_remapped(irq_get_chip_data(irq))) { | 3119 | /* |
3153 | irq_set_status_flags(irq, IRQ_MOVE_PCNTXT); | 3120 | * MSI-X message is written per-IRQ, the offset is always 0. |
3154 | irq_remap_modify_chip_defaults(chip); | 3121 | * MSI message denotes a contiguous group of IRQs, written for 0th IRQ. |
3155 | } | 3122 | */ |
3123 | if (!irq_offset) | ||
3124 | write_msi_msg(irq, &msg); | ||
3125 | |||
3126 | setup_remapped_irq(irq, irq_get_chip_data(irq), chip); | ||
3156 | 3127 | ||
3157 | irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge"); | 3128 | irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge"); |
3158 | 3129 | ||
@@ -3163,46 +3134,26 @@ static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int irq) | |||
3163 | 3134 | ||
3164 | int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | 3135 | int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) |
3165 | { | 3136 | { |
3166 | int node, ret, sub_handle, index = 0; | ||
3167 | unsigned int irq, irq_want; | 3137 | unsigned int irq, irq_want; |
3168 | struct msi_desc *msidesc; | 3138 | struct msi_desc *msidesc; |
3139 | int node, ret; | ||
3169 | 3140 | ||
3170 | /* x86 doesn't support multiple MSI yet */ | 3141 | /* Multiple MSI vectors only supported with interrupt remapping */ |
3171 | if (type == PCI_CAP_ID_MSI && nvec > 1) | 3142 | if (type == PCI_CAP_ID_MSI && nvec > 1) |
3172 | return 1; | 3143 | return 1; |
3173 | 3144 | ||
3174 | node = dev_to_node(&dev->dev); | 3145 | node = dev_to_node(&dev->dev); |
3175 | irq_want = nr_irqs_gsi; | 3146 | irq_want = nr_irqs_gsi; |
3176 | sub_handle = 0; | ||
3177 | list_for_each_entry(msidesc, &dev->msi_list, list) { | 3147 | list_for_each_entry(msidesc, &dev->msi_list, list) { |
3178 | irq = create_irq_nr(irq_want, node); | 3148 | irq = create_irq_nr(irq_want, node); |
3179 | if (irq == 0) | 3149 | if (irq == 0) |
3180 | return -1; | 3150 | return -ENOSPC; |
3151 | |||
3181 | irq_want = irq + 1; | 3152 | irq_want = irq + 1; |
3182 | if (!irq_remapping_enabled) | ||
3183 | goto no_ir; | ||
3184 | 3153 | ||
3185 | if (!sub_handle) { | 3154 | ret = setup_msi_irq(dev, msidesc, irq, 0); |
3186 | /* | ||
3187 | * allocate the consecutive block of IRTE's | ||
3188 | * for 'nvec' | ||
3189 | */ | ||
3190 | index = msi_alloc_remapped_irq(dev, irq, nvec); | ||
3191 | if (index < 0) { | ||
3192 | ret = index; | ||
3193 | goto error; | ||
3194 | } | ||
3195 | } else { | ||
3196 | ret = msi_setup_remapped_irq(dev, irq, index, | ||
3197 | sub_handle); | ||
3198 | if (ret < 0) | ||
3199 | goto error; | ||
3200 | } | ||
3201 | no_ir: | ||
3202 | ret = setup_msi_irq(dev, msidesc, irq); | ||
3203 | if (ret < 0) | 3155 | if (ret < 0) |
3204 | goto error; | 3156 | goto error; |
3205 | sub_handle++; | ||
3206 | } | 3157 | } |
3207 | return 0; | 3158 | return 0; |
3208 | 3159 | ||
@@ -3298,26 +3249,19 @@ static struct irq_chip hpet_msi_type = { | |||
3298 | .irq_retrigger = ioapic_retrigger_irq, | 3249 | .irq_retrigger = ioapic_retrigger_irq, |
3299 | }; | 3250 | }; |
3300 | 3251 | ||
3301 | int arch_setup_hpet_msi(unsigned int irq, unsigned int id) | 3252 | int default_setup_hpet_msi(unsigned int irq, unsigned int id) |
3302 | { | 3253 | { |
3303 | struct irq_chip *chip = &hpet_msi_type; | 3254 | struct irq_chip *chip = &hpet_msi_type; |
3304 | struct msi_msg msg; | 3255 | struct msi_msg msg; |
3305 | int ret; | 3256 | int ret; |
3306 | 3257 | ||
3307 | if (irq_remapping_enabled) { | ||
3308 | ret = setup_hpet_msi_remapped(irq, id); | ||
3309 | if (ret) | ||
3310 | return ret; | ||
3311 | } | ||
3312 | |||
3313 | ret = msi_compose_msg(NULL, irq, &msg, id); | 3258 | ret = msi_compose_msg(NULL, irq, &msg, id); |
3314 | if (ret < 0) | 3259 | if (ret < 0) |
3315 | return ret; | 3260 | return ret; |
3316 | 3261 | ||
3317 | hpet_msi_write(irq_get_handler_data(irq), &msg); | 3262 | hpet_msi_write(irq_get_handler_data(irq), &msg); |
3318 | irq_set_status_flags(irq, IRQ_MOVE_PCNTXT); | 3263 | irq_set_status_flags(irq, IRQ_MOVE_PCNTXT); |
3319 | if (irq_remapped(irq_get_chip_data(irq))) | 3264 | setup_remapped_irq(irq, irq_get_chip_data(irq), chip); |
3320 | irq_remap_modify_chip_defaults(chip); | ||
3321 | 3265 | ||
3322 | irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge"); | 3266 | irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge"); |
3323 | return 0; | 3267 | return 0; |
@@ -3683,10 +3627,7 @@ void __init setup_ioapic_dest(void) | |||
3683 | else | 3627 | else |
3684 | mask = apic->target_cpus(); | 3628 | mask = apic->target_cpus(); |
3685 | 3629 | ||
3686 | if (irq_remapping_enabled) | 3630 | x86_io_apic_ops.set_affinity(idata, mask, false); |
3687 | set_remapped_irq_affinity(idata, mask, false); | ||
3688 | else | ||
3689 | ioapic_set_affinity(idata, mask, false); | ||
3690 | } | 3631 | } |
3691 | 3632 | ||
3692 | } | 3633 | } |
diff --git a/arch/x86/kernel/apic/ipi.c b/arch/x86/kernel/apic/ipi.c index cce91bf26676..7434d8556d09 100644 --- a/arch/x86/kernel/apic/ipi.c +++ b/arch/x86/kernel/apic/ipi.c | |||
@@ -106,7 +106,7 @@ void default_send_IPI_mask_logical(const struct cpumask *cpumask, int vector) | |||
106 | unsigned long mask = cpumask_bits(cpumask)[0]; | 106 | unsigned long mask = cpumask_bits(cpumask)[0]; |
107 | unsigned long flags; | 107 | unsigned long flags; |
108 | 108 | ||
109 | if (WARN_ONCE(!mask, "empty IPI mask")) | 109 | if (!mask) |
110 | return; | 110 | return; |
111 | 111 | ||
112 | local_irq_save(flags); | 112 | local_irq_save(flags); |
diff --git a/arch/x86/kernel/apic/x2apic_phys.c b/arch/x86/kernel/apic/x2apic_phys.c index e03a1e180e81..562a76d433c8 100644 --- a/arch/x86/kernel/apic/x2apic_phys.c +++ b/arch/x86/kernel/apic/x2apic_phys.c | |||
@@ -20,18 +20,19 @@ static int set_x2apic_phys_mode(char *arg) | |||
20 | } | 20 | } |
21 | early_param("x2apic_phys", set_x2apic_phys_mode); | 21 | early_param("x2apic_phys", set_x2apic_phys_mode); |
22 | 22 | ||
23 | static int x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id) | 23 | static bool x2apic_fadt_phys(void) |
24 | { | 24 | { |
25 | if (x2apic_phys) | 25 | if ((acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID) && |
26 | return x2apic_enabled(); | 26 | (acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL)) { |
27 | else if ((acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID) && | ||
28 | (acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL) && | ||
29 | x2apic_enabled()) { | ||
30 | printk(KERN_DEBUG "System requires x2apic physical mode\n"); | 27 | printk(KERN_DEBUG "System requires x2apic physical mode\n"); |
31 | return 1; | 28 | return true; |
32 | } | 29 | } |
33 | else | 30 | return false; |
34 | return 0; | 31 | } |
32 | |||
33 | static int x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id) | ||
34 | { | ||
35 | return x2apic_enabled() && (x2apic_phys || x2apic_fadt_phys()); | ||
35 | } | 36 | } |
36 | 37 | ||
37 | static void | 38 | static void |
@@ -82,7 +83,7 @@ static void init_x2apic_ldr(void) | |||
82 | 83 | ||
83 | static int x2apic_phys_probe(void) | 84 | static int x2apic_phys_probe(void) |
84 | { | 85 | { |
85 | if (x2apic_mode && x2apic_phys) | 86 | if (x2apic_mode && (x2apic_phys || x2apic_fadt_phys())) |
86 | return 1; | 87 | return 1; |
87 | 88 | ||
88 | return apic == &apic_x2apic_phys; | 89 | return apic == &apic_x2apic_phys; |
diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c index d65464e43503..8d7012b7f402 100644 --- a/arch/x86/kernel/apm_32.c +++ b/arch/x86/kernel/apm_32.c | |||
@@ -899,6 +899,7 @@ static void apm_cpu_idle(void) | |||
899 | static int use_apm_idle; /* = 0 */ | 899 | static int use_apm_idle; /* = 0 */ |
900 | static unsigned int last_jiffies; /* = 0 */ | 900 | static unsigned int last_jiffies; /* = 0 */ |
901 | static unsigned int last_stime; /* = 0 */ | 901 | static unsigned int last_stime; /* = 0 */ |
902 | cputime_t stime; | ||
902 | 903 | ||
903 | int apm_idle_done = 0; | 904 | int apm_idle_done = 0; |
904 | unsigned int jiffies_since_last_check = jiffies - last_jiffies; | 905 | unsigned int jiffies_since_last_check = jiffies - last_jiffies; |
@@ -906,23 +907,23 @@ static void apm_cpu_idle(void) | |||
906 | 907 | ||
907 | WARN_ONCE(1, "deprecated apm_cpu_idle will be deleted in 2012"); | 908 | WARN_ONCE(1, "deprecated apm_cpu_idle will be deleted in 2012"); |
908 | recalc: | 909 | recalc: |
910 | task_cputime(current, NULL, &stime); | ||
909 | if (jiffies_since_last_check > IDLE_CALC_LIMIT) { | 911 | if (jiffies_since_last_check > IDLE_CALC_LIMIT) { |
910 | use_apm_idle = 0; | 912 | use_apm_idle = 0; |
911 | last_jiffies = jiffies; | ||
912 | last_stime = current->stime; | ||
913 | } else if (jiffies_since_last_check > idle_period) { | 913 | } else if (jiffies_since_last_check > idle_period) { |
914 | unsigned int idle_percentage; | 914 | unsigned int idle_percentage; |
915 | 915 | ||
916 | idle_percentage = current->stime - last_stime; | 916 | idle_percentage = stime - last_stime; |
917 | idle_percentage *= 100; | 917 | idle_percentage *= 100; |
918 | idle_percentage /= jiffies_since_last_check; | 918 | idle_percentage /= jiffies_since_last_check; |
919 | use_apm_idle = (idle_percentage > idle_threshold); | 919 | use_apm_idle = (idle_percentage > idle_threshold); |
920 | if (apm_info.forbid_idle) | 920 | if (apm_info.forbid_idle) |
921 | use_apm_idle = 0; | 921 | use_apm_idle = 0; |
922 | last_jiffies = jiffies; | ||
923 | last_stime = current->stime; | ||
924 | } | 922 | } |
925 | 923 | ||
924 | last_jiffies = jiffies; | ||
925 | last_stime = stime; | ||
926 | |||
926 | bucket = IDLE_LEAKY_MAX; | 927 | bucket = IDLE_LEAKY_MAX; |
927 | 928 | ||
928 | while (!need_resched()) { | 929 | while (!need_resched()) { |
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 15239fffd6fe..782c456eaa01 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c | |||
@@ -364,9 +364,9 @@ static void __cpuinit amd_detect_cmp(struct cpuinfo_x86 *c) | |||
364 | #endif | 364 | #endif |
365 | } | 365 | } |
366 | 366 | ||
367 | int amd_get_nb_id(int cpu) | 367 | u16 amd_get_nb_id(int cpu) |
368 | { | 368 | { |
369 | int id = 0; | 369 | u16 id = 0; |
370 | #ifdef CONFIG_SMP | 370 | #ifdef CONFIG_SMP |
371 | id = per_cpu(cpu_llc_id, cpu); | 371 | id = per_cpu(cpu_llc_id, cpu); |
372 | #endif | 372 | #endif |
diff --git a/arch/x86/kernel/cpu/hypervisor.c b/arch/x86/kernel/cpu/hypervisor.c index a8f8fa9769d6..1e7e84a02eba 100644 --- a/arch/x86/kernel/cpu/hypervisor.c +++ b/arch/x86/kernel/cpu/hypervisor.c | |||
@@ -79,3 +79,10 @@ void __init init_hypervisor_platform(void) | |||
79 | if (x86_hyper->init_platform) | 79 | if (x86_hyper->init_platform) |
80 | x86_hyper->init_platform(); | 80 | x86_hyper->init_platform(); |
81 | } | 81 | } |
82 | |||
83 | bool __init hypervisor_x2apic_available(void) | ||
84 | { | ||
85 | return x86_hyper && | ||
86 | x86_hyper->x2apic_available && | ||
87 | x86_hyper->x2apic_available(); | ||
88 | } | ||
diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c index 84c1309c4c0c..7c6f7d548c0f 100644 --- a/arch/x86/kernel/cpu/intel_cacheinfo.c +++ b/arch/x86/kernel/cpu/intel_cacheinfo.c | |||
@@ -1226,7 +1226,7 @@ static struct notifier_block __cpuinitdata cacheinfo_cpu_notifier = { | |||
1226 | .notifier_call = cacheinfo_cpu_callback, | 1226 | .notifier_call = cacheinfo_cpu_callback, |
1227 | }; | 1227 | }; |
1228 | 1228 | ||
1229 | static int __cpuinit cache_sysfs_init(void) | 1229 | static int __init cache_sysfs_init(void) |
1230 | { | 1230 | { |
1231 | int i; | 1231 | int i; |
1232 | 1232 | ||
diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c index 0a630dd4b620..a7d26d83fb70 100644 --- a/arch/x86/kernel/cpu/mshyperv.c +++ b/arch/x86/kernel/cpu/mshyperv.c | |||
@@ -14,10 +14,15 @@ | |||
14 | #include <linux/time.h> | 14 | #include <linux/time.h> |
15 | #include <linux/clocksource.h> | 15 | #include <linux/clocksource.h> |
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/hardirq.h> | ||
18 | #include <linux/interrupt.h> | ||
17 | #include <asm/processor.h> | 19 | #include <asm/processor.h> |
18 | #include <asm/hypervisor.h> | 20 | #include <asm/hypervisor.h> |
19 | #include <asm/hyperv.h> | 21 | #include <asm/hyperv.h> |
20 | #include <asm/mshyperv.h> | 22 | #include <asm/mshyperv.h> |
23 | #include <asm/desc.h> | ||
24 | #include <asm/idle.h> | ||
25 | #include <asm/irq_regs.h> | ||
21 | 26 | ||
22 | struct ms_hyperv_info ms_hyperv; | 27 | struct ms_hyperv_info ms_hyperv; |
23 | EXPORT_SYMBOL_GPL(ms_hyperv); | 28 | EXPORT_SYMBOL_GPL(ms_hyperv); |
@@ -30,6 +35,13 @@ static bool __init ms_hyperv_platform(void) | |||
30 | if (!boot_cpu_has(X86_FEATURE_HYPERVISOR)) | 35 | if (!boot_cpu_has(X86_FEATURE_HYPERVISOR)) |
31 | return false; | 36 | return false; |
32 | 37 | ||
38 | /* | ||
39 | * Xen emulates Hyper-V to support enlightened Windows. | ||
40 | * Check to see first if we are on a Xen Hypervisor. | ||
41 | */ | ||
42 | if (xen_cpuid_base()) | ||
43 | return false; | ||
44 | |||
33 | cpuid(HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS, | 45 | cpuid(HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS, |
34 | &eax, &hyp_signature[0], &hyp_signature[1], &hyp_signature[2]); | 46 | &eax, &hyp_signature[0], &hyp_signature[1], &hyp_signature[2]); |
35 | 47 | ||
@@ -68,7 +80,14 @@ static void __init ms_hyperv_init_platform(void) | |||
68 | printk(KERN_INFO "HyperV: features 0x%x, hints 0x%x\n", | 80 | printk(KERN_INFO "HyperV: features 0x%x, hints 0x%x\n", |
69 | ms_hyperv.features, ms_hyperv.hints); | 81 | ms_hyperv.features, ms_hyperv.hints); |
70 | 82 | ||
71 | clocksource_register_hz(&hyperv_cs, NSEC_PER_SEC/100); | 83 | if (ms_hyperv.features & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE) |
84 | clocksource_register_hz(&hyperv_cs, NSEC_PER_SEC/100); | ||
85 | #if IS_ENABLED(CONFIG_HYPERV) | ||
86 | /* | ||
87 | * Setup the IDT for hypervisor callback. | ||
88 | */ | ||
89 | alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, hyperv_callback_vector); | ||
90 | #endif | ||
72 | } | 91 | } |
73 | 92 | ||
74 | const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = { | 93 | const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = { |
@@ -77,3 +96,36 @@ const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = { | |||
77 | .init_platform = ms_hyperv_init_platform, | 96 | .init_platform = ms_hyperv_init_platform, |
78 | }; | 97 | }; |
79 | EXPORT_SYMBOL(x86_hyper_ms_hyperv); | 98 | EXPORT_SYMBOL(x86_hyper_ms_hyperv); |
99 | |||
100 | #if IS_ENABLED(CONFIG_HYPERV) | ||
101 | static int vmbus_irq = -1; | ||
102 | static irq_handler_t vmbus_isr; | ||
103 | |||
104 | void hv_register_vmbus_handler(int irq, irq_handler_t handler) | ||
105 | { | ||
106 | vmbus_irq = irq; | ||
107 | vmbus_isr = handler; | ||
108 | } | ||
109 | |||
110 | void hyperv_vector_handler(struct pt_regs *regs) | ||
111 | { | ||
112 | struct pt_regs *old_regs = set_irq_regs(regs); | ||
113 | struct irq_desc *desc; | ||
114 | |||
115 | irq_enter(); | ||
116 | exit_idle(); | ||
117 | |||
118 | desc = irq_to_desc(vmbus_irq); | ||
119 | |||
120 | if (desc) | ||
121 | generic_handle_irq_desc(vmbus_irq, desc); | ||
122 | |||
123 | irq_exit(); | ||
124 | set_irq_regs(old_regs); | ||
125 | } | ||
126 | #else | ||
127 | void hv_register_vmbus_handler(int irq, irq_handler_t handler) | ||
128 | { | ||
129 | } | ||
130 | #endif | ||
131 | EXPORT_SYMBOL_GPL(hv_register_vmbus_handler); | ||
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 6774c17a5576..bf0f01aea994 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c | |||
@@ -829,7 +829,7 @@ static inline void x86_assign_hw_event(struct perf_event *event, | |||
829 | } else { | 829 | } else { |
830 | hwc->config_base = x86_pmu_config_addr(hwc->idx); | 830 | hwc->config_base = x86_pmu_config_addr(hwc->idx); |
831 | hwc->event_base = x86_pmu_event_addr(hwc->idx); | 831 | hwc->event_base = x86_pmu_event_addr(hwc->idx); |
832 | hwc->event_base_rdpmc = hwc->idx; | 832 | hwc->event_base_rdpmc = x86_pmu_rdpmc_index(hwc->idx); |
833 | } | 833 | } |
834 | } | 834 | } |
835 | 835 | ||
@@ -1310,11 +1310,6 @@ static struct attribute_group x86_pmu_format_group = { | |||
1310 | .attrs = NULL, | 1310 | .attrs = NULL, |
1311 | }; | 1311 | }; |
1312 | 1312 | ||
1313 | struct perf_pmu_events_attr { | ||
1314 | struct device_attribute attr; | ||
1315 | u64 id; | ||
1316 | }; | ||
1317 | |||
1318 | /* | 1313 | /* |
1319 | * Remove all undefined events (x86_pmu.event_map(id) == 0) | 1314 | * Remove all undefined events (x86_pmu.event_map(id) == 0) |
1320 | * out of events_attr attributes. | 1315 | * out of events_attr attributes. |
@@ -1348,11 +1343,9 @@ static ssize_t events_sysfs_show(struct device *dev, struct device_attribute *at | |||
1348 | #define EVENT_VAR(_id) event_attr_##_id | 1343 | #define EVENT_VAR(_id) event_attr_##_id |
1349 | #define EVENT_PTR(_id) &event_attr_##_id.attr.attr | 1344 | #define EVENT_PTR(_id) &event_attr_##_id.attr.attr |
1350 | 1345 | ||
1351 | #define EVENT_ATTR(_name, _id) \ | 1346 | #define EVENT_ATTR(_name, _id) \ |
1352 | static struct perf_pmu_events_attr EVENT_VAR(_id) = { \ | 1347 | PMU_EVENT_ATTR(_name, EVENT_VAR(_id), PERF_COUNT_HW_##_id, \ |
1353 | .attr = __ATTR(_name, 0444, events_sysfs_show, NULL), \ | 1348 | events_sysfs_show) |
1354 | .id = PERF_COUNT_HW_##_id, \ | ||
1355 | }; | ||
1356 | 1349 | ||
1357 | EVENT_ATTR(cpu-cycles, CPU_CYCLES ); | 1350 | EVENT_ATTR(cpu-cycles, CPU_CYCLES ); |
1358 | EVENT_ATTR(instructions, INSTRUCTIONS ); | 1351 | EVENT_ATTR(instructions, INSTRUCTIONS ); |
diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h index 115c1ea97746..7f5c75c2afdd 100644 --- a/arch/x86/kernel/cpu/perf_event.h +++ b/arch/x86/kernel/cpu/perf_event.h | |||
@@ -325,6 +325,8 @@ struct x86_pmu { | |||
325 | int (*schedule_events)(struct cpu_hw_events *cpuc, int n, int *assign); | 325 | int (*schedule_events)(struct cpu_hw_events *cpuc, int n, int *assign); |
326 | unsigned eventsel; | 326 | unsigned eventsel; |
327 | unsigned perfctr; | 327 | unsigned perfctr; |
328 | int (*addr_offset)(int index, bool eventsel); | ||
329 | int (*rdpmc_index)(int index); | ||
328 | u64 (*event_map)(int); | 330 | u64 (*event_map)(int); |
329 | int max_events; | 331 | int max_events; |
330 | int num_counters; | 332 | int num_counters; |
@@ -446,28 +448,21 @@ extern u64 __read_mostly hw_cache_extra_regs | |||
446 | 448 | ||
447 | u64 x86_perf_event_update(struct perf_event *event); | 449 | u64 x86_perf_event_update(struct perf_event *event); |
448 | 450 | ||
449 | static inline int x86_pmu_addr_offset(int index) | 451 | static inline unsigned int x86_pmu_config_addr(int index) |
450 | { | 452 | { |
451 | int offset; | 453 | return x86_pmu.eventsel + (x86_pmu.addr_offset ? |
452 | 454 | x86_pmu.addr_offset(index, true) : index); | |
453 | /* offset = X86_FEATURE_PERFCTR_CORE ? index << 1 : index */ | ||
454 | alternative_io(ASM_NOP2, | ||
455 | "shll $1, %%eax", | ||
456 | X86_FEATURE_PERFCTR_CORE, | ||
457 | "=a" (offset), | ||
458 | "a" (index)); | ||
459 | |||
460 | return offset; | ||
461 | } | 455 | } |
462 | 456 | ||
463 | static inline unsigned int x86_pmu_config_addr(int index) | 457 | static inline unsigned int x86_pmu_event_addr(int index) |
464 | { | 458 | { |
465 | return x86_pmu.eventsel + x86_pmu_addr_offset(index); | 459 | return x86_pmu.perfctr + (x86_pmu.addr_offset ? |
460 | x86_pmu.addr_offset(index, false) : index); | ||
466 | } | 461 | } |
467 | 462 | ||
468 | static inline unsigned int x86_pmu_event_addr(int index) | 463 | static inline int x86_pmu_rdpmc_index(int index) |
469 | { | 464 | { |
470 | return x86_pmu.perfctr + x86_pmu_addr_offset(index); | 465 | return x86_pmu.rdpmc_index ? x86_pmu.rdpmc_index(index) : index; |
471 | } | 466 | } |
472 | 467 | ||
473 | int x86_setup_perfctr(struct perf_event *event); | 468 | int x86_setup_perfctr(struct perf_event *event); |
diff --git a/arch/x86/kernel/cpu/perf_event_amd.c b/arch/x86/kernel/cpu/perf_event_amd.c index c93bc4e813a0..dfdab42aed27 100644 --- a/arch/x86/kernel/cpu/perf_event_amd.c +++ b/arch/x86/kernel/cpu/perf_event_amd.c | |||
@@ -132,21 +132,102 @@ static u64 amd_pmu_event_map(int hw_event) | |||
132 | return amd_perfmon_event_map[hw_event]; | 132 | return amd_perfmon_event_map[hw_event]; |
133 | } | 133 | } |
134 | 134 | ||
135 | static int amd_pmu_hw_config(struct perf_event *event) | 135 | static struct event_constraint *amd_nb_event_constraint; |
136 | |||
137 | /* | ||
138 | * Previously calculated offsets | ||
139 | */ | ||
140 | static unsigned int event_offsets[X86_PMC_IDX_MAX] __read_mostly; | ||
141 | static unsigned int count_offsets[X86_PMC_IDX_MAX] __read_mostly; | ||
142 | static unsigned int rdpmc_indexes[X86_PMC_IDX_MAX] __read_mostly; | ||
143 | |||
144 | /* | ||
145 | * Legacy CPUs: | ||
146 | * 4 counters starting at 0xc0010000 each offset by 1 | ||
147 | * | ||
148 | * CPUs with core performance counter extensions: | ||
149 | * 6 counters starting at 0xc0010200 each offset by 2 | ||
150 | * | ||
151 | * CPUs with north bridge performance counter extensions: | ||
152 | * 4 additional counters starting at 0xc0010240 each offset by 2 | ||
153 | * (indexed right above either one of the above core counters) | ||
154 | */ | ||
155 | static inline int amd_pmu_addr_offset(int index, bool eventsel) | ||
136 | { | 156 | { |
137 | int ret; | 157 | int offset, first, base; |
138 | 158 | ||
139 | /* pass precise event sampling to ibs: */ | 159 | if (!index) |
140 | if (event->attr.precise_ip && get_ibs_caps()) | 160 | return index; |
141 | return -ENOENT; | 161 | |
162 | if (eventsel) | ||
163 | offset = event_offsets[index]; | ||
164 | else | ||
165 | offset = count_offsets[index]; | ||
166 | |||
167 | if (offset) | ||
168 | return offset; | ||
169 | |||
170 | if (amd_nb_event_constraint && | ||
171 | test_bit(index, amd_nb_event_constraint->idxmsk)) { | ||
172 | /* | ||
173 | * calculate the offset of NB counters with respect to | ||
174 | * base eventsel or perfctr | ||
175 | */ | ||
176 | |||
177 | first = find_first_bit(amd_nb_event_constraint->idxmsk, | ||
178 | X86_PMC_IDX_MAX); | ||
179 | |||
180 | if (eventsel) | ||
181 | base = MSR_F15H_NB_PERF_CTL - x86_pmu.eventsel; | ||
182 | else | ||
183 | base = MSR_F15H_NB_PERF_CTR - x86_pmu.perfctr; | ||
184 | |||
185 | offset = base + ((index - first) << 1); | ||
186 | } else if (!cpu_has_perfctr_core) | ||
187 | offset = index; | ||
188 | else | ||
189 | offset = index << 1; | ||
190 | |||
191 | if (eventsel) | ||
192 | event_offsets[index] = offset; | ||
193 | else | ||
194 | count_offsets[index] = offset; | ||
195 | |||
196 | return offset; | ||
197 | } | ||
198 | |||
199 | static inline int amd_pmu_rdpmc_index(int index) | ||
200 | { | ||
201 | int ret, first; | ||
202 | |||
203 | if (!index) | ||
204 | return index; | ||
205 | |||
206 | ret = rdpmc_indexes[index]; | ||
142 | 207 | ||
143 | ret = x86_pmu_hw_config(event); | ||
144 | if (ret) | 208 | if (ret) |
145 | return ret; | 209 | return ret; |
146 | 210 | ||
147 | if (has_branch_stack(event)) | 211 | if (amd_nb_event_constraint && |
148 | return -EOPNOTSUPP; | 212 | test_bit(index, amd_nb_event_constraint->idxmsk)) { |
213 | /* | ||
214 | * according to the mnual, ECX value of the NB counters is | ||
215 | * the index of the NB counter (0, 1, 2 or 3) plus 6 | ||
216 | */ | ||
217 | |||
218 | first = find_first_bit(amd_nb_event_constraint->idxmsk, | ||
219 | X86_PMC_IDX_MAX); | ||
220 | ret = index - first + 6; | ||
221 | } else | ||
222 | ret = index; | ||
223 | |||
224 | rdpmc_indexes[index] = ret; | ||
225 | |||
226 | return ret; | ||
227 | } | ||
149 | 228 | ||
229 | static int amd_core_hw_config(struct perf_event *event) | ||
230 | { | ||
150 | if (event->attr.exclude_host && event->attr.exclude_guest) | 231 | if (event->attr.exclude_host && event->attr.exclude_guest) |
151 | /* | 232 | /* |
152 | * When HO == GO == 1 the hardware treats that as GO == HO == 0 | 233 | * When HO == GO == 1 the hardware treats that as GO == HO == 0 |
@@ -156,14 +237,37 @@ static int amd_pmu_hw_config(struct perf_event *event) | |||
156 | event->hw.config &= ~(ARCH_PERFMON_EVENTSEL_USR | | 237 | event->hw.config &= ~(ARCH_PERFMON_EVENTSEL_USR | |
157 | ARCH_PERFMON_EVENTSEL_OS); | 238 | ARCH_PERFMON_EVENTSEL_OS); |
158 | else if (event->attr.exclude_host) | 239 | else if (event->attr.exclude_host) |
159 | event->hw.config |= AMD_PERFMON_EVENTSEL_GUESTONLY; | 240 | event->hw.config |= AMD64_EVENTSEL_GUESTONLY; |
160 | else if (event->attr.exclude_guest) | 241 | else if (event->attr.exclude_guest) |
161 | event->hw.config |= AMD_PERFMON_EVENTSEL_HOSTONLY; | 242 | event->hw.config |= AMD64_EVENTSEL_HOSTONLY; |
243 | |||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | /* | ||
248 | * NB counters do not support the following event select bits: | ||
249 | * Host/Guest only | ||
250 | * Counter mask | ||
251 | * Invert counter mask | ||
252 | * Edge detect | ||
253 | * OS/User mode | ||
254 | */ | ||
255 | static int amd_nb_hw_config(struct perf_event *event) | ||
256 | { | ||
257 | /* for NB, we only allow system wide counting mode */ | ||
258 | if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK) | ||
259 | return -EINVAL; | ||
260 | |||
261 | if (event->attr.exclude_user || event->attr.exclude_kernel || | ||
262 | event->attr.exclude_host || event->attr.exclude_guest) | ||
263 | return -EINVAL; | ||
162 | 264 | ||
163 | if (event->attr.type != PERF_TYPE_RAW) | 265 | event->hw.config &= ~(ARCH_PERFMON_EVENTSEL_USR | |
164 | return 0; | 266 | ARCH_PERFMON_EVENTSEL_OS); |
165 | 267 | ||
166 | event->hw.config |= event->attr.config & AMD64_RAW_EVENT_MASK; | 268 | if (event->hw.config & ~(AMD64_RAW_EVENT_MASK_NB | |
269 | ARCH_PERFMON_EVENTSEL_INT)) | ||
270 | return -EINVAL; | ||
167 | 271 | ||
168 | return 0; | 272 | return 0; |
169 | } | 273 | } |
@@ -181,6 +285,11 @@ static inline int amd_is_nb_event(struct hw_perf_event *hwc) | |||
181 | return (hwc->config & 0xe0) == 0xe0; | 285 | return (hwc->config & 0xe0) == 0xe0; |
182 | } | 286 | } |
183 | 287 | ||
288 | static inline int amd_is_perfctr_nb_event(struct hw_perf_event *hwc) | ||
289 | { | ||
290 | return amd_nb_event_constraint && amd_is_nb_event(hwc); | ||
291 | } | ||
292 | |||
184 | static inline int amd_has_nb(struct cpu_hw_events *cpuc) | 293 | static inline int amd_has_nb(struct cpu_hw_events *cpuc) |
185 | { | 294 | { |
186 | struct amd_nb *nb = cpuc->amd_nb; | 295 | struct amd_nb *nb = cpuc->amd_nb; |
@@ -188,20 +297,37 @@ static inline int amd_has_nb(struct cpu_hw_events *cpuc) | |||
188 | return nb && nb->nb_id != -1; | 297 | return nb && nb->nb_id != -1; |
189 | } | 298 | } |
190 | 299 | ||
191 | static void amd_put_event_constraints(struct cpu_hw_events *cpuc, | 300 | static int amd_pmu_hw_config(struct perf_event *event) |
192 | struct perf_event *event) | 301 | { |
302 | int ret; | ||
303 | |||
304 | /* pass precise event sampling to ibs: */ | ||
305 | if (event->attr.precise_ip && get_ibs_caps()) | ||
306 | return -ENOENT; | ||
307 | |||
308 | if (has_branch_stack(event)) | ||
309 | return -EOPNOTSUPP; | ||
310 | |||
311 | ret = x86_pmu_hw_config(event); | ||
312 | if (ret) | ||
313 | return ret; | ||
314 | |||
315 | if (event->attr.type == PERF_TYPE_RAW) | ||
316 | event->hw.config |= event->attr.config & AMD64_RAW_EVENT_MASK; | ||
317 | |||
318 | if (amd_is_perfctr_nb_event(&event->hw)) | ||
319 | return amd_nb_hw_config(event); | ||
320 | |||
321 | return amd_core_hw_config(event); | ||
322 | } | ||
323 | |||
324 | static void __amd_put_nb_event_constraints(struct cpu_hw_events *cpuc, | ||
325 | struct perf_event *event) | ||
193 | { | 326 | { |
194 | struct hw_perf_event *hwc = &event->hw; | ||
195 | struct amd_nb *nb = cpuc->amd_nb; | 327 | struct amd_nb *nb = cpuc->amd_nb; |
196 | int i; | 328 | int i; |
197 | 329 | ||
198 | /* | 330 | /* |
199 | * only care about NB events | ||
200 | */ | ||
201 | if (!(amd_has_nb(cpuc) && amd_is_nb_event(hwc))) | ||
202 | return; | ||
203 | |||
204 | /* | ||
205 | * need to scan whole list because event may not have | 331 | * need to scan whole list because event may not have |
206 | * been assigned during scheduling | 332 | * been assigned during scheduling |
207 | * | 333 | * |
@@ -215,6 +341,19 @@ static void amd_put_event_constraints(struct cpu_hw_events *cpuc, | |||
215 | } | 341 | } |
216 | } | 342 | } |
217 | 343 | ||
344 | static void amd_nb_interrupt_hw_config(struct hw_perf_event *hwc) | ||
345 | { | ||
346 | int core_id = cpu_data(smp_processor_id()).cpu_core_id; | ||
347 | |||
348 | /* deliver interrupts only to this core */ | ||
349 | if (hwc->config & ARCH_PERFMON_EVENTSEL_INT) { | ||
350 | hwc->config |= AMD64_EVENTSEL_INT_CORE_ENABLE; | ||
351 | hwc->config &= ~AMD64_EVENTSEL_INT_CORE_SEL_MASK; | ||
352 | hwc->config |= (u64)(core_id) << | ||
353 | AMD64_EVENTSEL_INT_CORE_SEL_SHIFT; | ||
354 | } | ||
355 | } | ||
356 | |||
218 | /* | 357 | /* |
219 | * AMD64 NorthBridge events need special treatment because | 358 | * AMD64 NorthBridge events need special treatment because |
220 | * counter access needs to be synchronized across all cores | 359 | * counter access needs to be synchronized across all cores |
@@ -247,24 +386,24 @@ static void amd_put_event_constraints(struct cpu_hw_events *cpuc, | |||
247 | * | 386 | * |
248 | * Given that resources are allocated (cmpxchg), they must be | 387 | * Given that resources are allocated (cmpxchg), they must be |
249 | * eventually freed for others to use. This is accomplished by | 388 | * eventually freed for others to use. This is accomplished by |
250 | * calling amd_put_event_constraints(). | 389 | * calling __amd_put_nb_event_constraints() |
251 | * | 390 | * |
252 | * Non NB events are not impacted by this restriction. | 391 | * Non NB events are not impacted by this restriction. |
253 | */ | 392 | */ |
254 | static struct event_constraint * | 393 | static struct event_constraint * |
255 | amd_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event) | 394 | __amd_get_nb_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event, |
395 | struct event_constraint *c) | ||
256 | { | 396 | { |
257 | struct hw_perf_event *hwc = &event->hw; | 397 | struct hw_perf_event *hwc = &event->hw; |
258 | struct amd_nb *nb = cpuc->amd_nb; | 398 | struct amd_nb *nb = cpuc->amd_nb; |
259 | struct perf_event *old = NULL; | 399 | struct perf_event *old; |
260 | int max = x86_pmu.num_counters; | 400 | int idx, new = -1; |
261 | int i, j, k = -1; | ||
262 | 401 | ||
263 | /* | 402 | if (!c) |
264 | * if not NB event or no NB, then no constraints | 403 | c = &unconstrained; |
265 | */ | 404 | |
266 | if (!(amd_has_nb(cpuc) && amd_is_nb_event(hwc))) | 405 | if (cpuc->is_fake) |
267 | return &unconstrained; | 406 | return c; |
268 | 407 | ||
269 | /* | 408 | /* |
270 | * detect if already present, if so reuse | 409 | * detect if already present, if so reuse |
@@ -276,48 +415,36 @@ amd_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event) | |||
276 | * because of successive calls to x86_schedule_events() from | 415 | * because of successive calls to x86_schedule_events() from |
277 | * hw_perf_group_sched_in() without hw_perf_enable() | 416 | * hw_perf_group_sched_in() without hw_perf_enable() |
278 | */ | 417 | */ |
279 | for (i = 0; i < max; i++) { | 418 | for_each_set_bit(idx, c->idxmsk, x86_pmu.num_counters) { |
280 | /* | 419 | if (new == -1 || hwc->idx == idx) |
281 | * keep track of first free slot | 420 | /* assign free slot, prefer hwc->idx */ |
282 | */ | 421 | old = cmpxchg(nb->owners + idx, NULL, event); |
283 | if (k == -1 && !nb->owners[i]) | 422 | else if (nb->owners[idx] == event) |
284 | k = i; | 423 | /* event already present */ |
424 | old = event; | ||
425 | else | ||
426 | continue; | ||
427 | |||
428 | if (old && old != event) | ||
429 | continue; | ||
430 | |||
431 | /* reassign to this slot */ | ||
432 | if (new != -1) | ||
433 | cmpxchg(nb->owners + new, event, NULL); | ||
434 | new = idx; | ||
285 | 435 | ||
286 | /* already present, reuse */ | 436 | /* already present, reuse */ |
287 | if (nb->owners[i] == event) | 437 | if (old == event) |
288 | goto done; | ||
289 | } | ||
290 | /* | ||
291 | * not present, so grab a new slot | ||
292 | * starting either at: | ||
293 | */ | ||
294 | if (hwc->idx != -1) { | ||
295 | /* previous assignment */ | ||
296 | i = hwc->idx; | ||
297 | } else if (k != -1) { | ||
298 | /* start from free slot found */ | ||
299 | i = k; | ||
300 | } else { | ||
301 | /* | ||
302 | * event not found, no slot found in | ||
303 | * first pass, try again from the | ||
304 | * beginning | ||
305 | */ | ||
306 | i = 0; | ||
307 | } | ||
308 | j = i; | ||
309 | do { | ||
310 | old = cmpxchg(nb->owners+i, NULL, event); | ||
311 | if (!old) | ||
312 | break; | 438 | break; |
313 | if (++i == max) | 439 | } |
314 | i = 0; | 440 | |
315 | } while (i != j); | 441 | if (new == -1) |
316 | done: | 442 | return &emptyconstraint; |
317 | if (!old) | 443 | |
318 | return &nb->event_constraints[i]; | 444 | if (amd_is_perfctr_nb_event(hwc)) |
319 | 445 | amd_nb_interrupt_hw_config(hwc); | |
320 | return &emptyconstraint; | 446 | |
447 | return &nb->event_constraints[new]; | ||
321 | } | 448 | } |
322 | 449 | ||
323 | static struct amd_nb *amd_alloc_nb(int cpu) | 450 | static struct amd_nb *amd_alloc_nb(int cpu) |
@@ -364,7 +491,7 @@ static void amd_pmu_cpu_starting(int cpu) | |||
364 | struct amd_nb *nb; | 491 | struct amd_nb *nb; |
365 | int i, nb_id; | 492 | int i, nb_id; |
366 | 493 | ||
367 | cpuc->perf_ctr_virt_mask = AMD_PERFMON_EVENTSEL_HOSTONLY; | 494 | cpuc->perf_ctr_virt_mask = AMD64_EVENTSEL_HOSTONLY; |
368 | 495 | ||
369 | if (boot_cpu_data.x86_max_cores < 2) | 496 | if (boot_cpu_data.x86_max_cores < 2) |
370 | return; | 497 | return; |
@@ -407,6 +534,26 @@ static void amd_pmu_cpu_dead(int cpu) | |||
407 | } | 534 | } |
408 | } | 535 | } |
409 | 536 | ||
537 | static struct event_constraint * | ||
538 | amd_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event) | ||
539 | { | ||
540 | /* | ||
541 | * if not NB event or no NB, then no constraints | ||
542 | */ | ||
543 | if (!(amd_has_nb(cpuc) && amd_is_nb_event(&event->hw))) | ||
544 | return &unconstrained; | ||
545 | |||
546 | return __amd_get_nb_event_constraints(cpuc, event, | ||
547 | amd_nb_event_constraint); | ||
548 | } | ||
549 | |||
550 | static void amd_put_event_constraints(struct cpu_hw_events *cpuc, | ||
551 | struct perf_event *event) | ||
552 | { | ||
553 | if (amd_has_nb(cpuc) && amd_is_nb_event(&event->hw)) | ||
554 | __amd_put_nb_event_constraints(cpuc, event); | ||
555 | } | ||
556 | |||
410 | PMU_FORMAT_ATTR(event, "config:0-7,32-35"); | 557 | PMU_FORMAT_ATTR(event, "config:0-7,32-35"); |
411 | PMU_FORMAT_ATTR(umask, "config:8-15" ); | 558 | PMU_FORMAT_ATTR(umask, "config:8-15" ); |
412 | PMU_FORMAT_ATTR(edge, "config:18" ); | 559 | PMU_FORMAT_ATTR(edge, "config:18" ); |
@@ -496,6 +643,9 @@ static struct event_constraint amd_f15_PMC30 = EVENT_CONSTRAINT_OVERLAP(0, 0x09, | |||
496 | static struct event_constraint amd_f15_PMC50 = EVENT_CONSTRAINT(0, 0x3F, 0); | 643 | static struct event_constraint amd_f15_PMC50 = EVENT_CONSTRAINT(0, 0x3F, 0); |
497 | static struct event_constraint amd_f15_PMC53 = EVENT_CONSTRAINT(0, 0x38, 0); | 644 | static struct event_constraint amd_f15_PMC53 = EVENT_CONSTRAINT(0, 0x38, 0); |
498 | 645 | ||
646 | static struct event_constraint amd_NBPMC96 = EVENT_CONSTRAINT(0, 0x3C0, 0); | ||
647 | static struct event_constraint amd_NBPMC74 = EVENT_CONSTRAINT(0, 0xF0, 0); | ||
648 | |||
499 | static struct event_constraint * | 649 | static struct event_constraint * |
500 | amd_get_event_constraints_f15h(struct cpu_hw_events *cpuc, struct perf_event *event) | 650 | amd_get_event_constraints_f15h(struct cpu_hw_events *cpuc, struct perf_event *event) |
501 | { | 651 | { |
@@ -561,8 +711,8 @@ amd_get_event_constraints_f15h(struct cpu_hw_events *cpuc, struct perf_event *ev | |||
561 | return &amd_f15_PMC20; | 711 | return &amd_f15_PMC20; |
562 | } | 712 | } |
563 | case AMD_EVENT_NB: | 713 | case AMD_EVENT_NB: |
564 | /* not yet implemented */ | 714 | return __amd_get_nb_event_constraints(cpuc, event, |
565 | return &emptyconstraint; | 715 | amd_nb_event_constraint); |
566 | default: | 716 | default: |
567 | return &emptyconstraint; | 717 | return &emptyconstraint; |
568 | } | 718 | } |
@@ -587,6 +737,8 @@ static __initconst const struct x86_pmu amd_pmu = { | |||
587 | .schedule_events = x86_schedule_events, | 737 | .schedule_events = x86_schedule_events, |
588 | .eventsel = MSR_K7_EVNTSEL0, | 738 | .eventsel = MSR_K7_EVNTSEL0, |
589 | .perfctr = MSR_K7_PERFCTR0, | 739 | .perfctr = MSR_K7_PERFCTR0, |
740 | .addr_offset = amd_pmu_addr_offset, | ||
741 | .rdpmc_index = amd_pmu_rdpmc_index, | ||
590 | .event_map = amd_pmu_event_map, | 742 | .event_map = amd_pmu_event_map, |
591 | .max_events = ARRAY_SIZE(amd_perfmon_event_map), | 743 | .max_events = ARRAY_SIZE(amd_perfmon_event_map), |
592 | .num_counters = AMD64_NUM_COUNTERS, | 744 | .num_counters = AMD64_NUM_COUNTERS, |
@@ -608,7 +760,7 @@ static __initconst const struct x86_pmu amd_pmu = { | |||
608 | 760 | ||
609 | static int setup_event_constraints(void) | 761 | static int setup_event_constraints(void) |
610 | { | 762 | { |
611 | if (boot_cpu_data.x86 >= 0x15) | 763 | if (boot_cpu_data.x86 == 0x15) |
612 | x86_pmu.get_event_constraints = amd_get_event_constraints_f15h; | 764 | x86_pmu.get_event_constraints = amd_get_event_constraints_f15h; |
613 | return 0; | 765 | return 0; |
614 | } | 766 | } |
@@ -638,6 +790,23 @@ static int setup_perfctr_core(void) | |||
638 | return 0; | 790 | return 0; |
639 | } | 791 | } |
640 | 792 | ||
793 | static int setup_perfctr_nb(void) | ||
794 | { | ||
795 | if (!cpu_has_perfctr_nb) | ||
796 | return -ENODEV; | ||
797 | |||
798 | x86_pmu.num_counters += AMD64_NUM_COUNTERS_NB; | ||
799 | |||
800 | if (cpu_has_perfctr_core) | ||
801 | amd_nb_event_constraint = &amd_NBPMC96; | ||
802 | else | ||
803 | amd_nb_event_constraint = &amd_NBPMC74; | ||
804 | |||
805 | printk(KERN_INFO "perf: AMD northbridge performance counters detected\n"); | ||
806 | |||
807 | return 0; | ||
808 | } | ||
809 | |||
641 | __init int amd_pmu_init(void) | 810 | __init int amd_pmu_init(void) |
642 | { | 811 | { |
643 | /* Performance-monitoring supported from K7 and later: */ | 812 | /* Performance-monitoring supported from K7 and later: */ |
@@ -648,6 +817,7 @@ __init int amd_pmu_init(void) | |||
648 | 817 | ||
649 | setup_event_constraints(); | 818 | setup_event_constraints(); |
650 | setup_perfctr_core(); | 819 | setup_perfctr_core(); |
820 | setup_perfctr_nb(); | ||
651 | 821 | ||
652 | /* Events are common for all AMDs */ | 822 | /* Events are common for all AMDs */ |
653 | memcpy(hw_cache_event_ids, amd_hw_cache_event_ids, | 823 | memcpy(hw_cache_event_ids, amd_hw_cache_event_ids, |
@@ -678,7 +848,7 @@ void amd_pmu_disable_virt(void) | |||
678 | * SVM is disabled the Guest-only bits still gets set and the counter | 848 | * SVM is disabled the Guest-only bits still gets set and the counter |
679 | * will not count anything. | 849 | * will not count anything. |
680 | */ | 850 | */ |
681 | cpuc->perf_ctr_virt_mask = AMD_PERFMON_EVENTSEL_HOSTONLY; | 851 | cpuc->perf_ctr_virt_mask = AMD64_EVENTSEL_HOSTONLY; |
682 | 852 | ||
683 | /* Reload all events */ | 853 | /* Reload all events */ |
684 | x86_pmu_disable_all(); | 854 | x86_pmu_disable_all(); |
diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c index d22d0c4edcfd..03a36321ec54 100644 --- a/arch/x86/kernel/cpu/vmware.c +++ b/arch/x86/kernel/cpu/vmware.c | |||
@@ -33,6 +33,9 @@ | |||
33 | 33 | ||
34 | #define VMWARE_PORT_CMD_GETVERSION 10 | 34 | #define VMWARE_PORT_CMD_GETVERSION 10 |
35 | #define VMWARE_PORT_CMD_GETHZ 45 | 35 | #define VMWARE_PORT_CMD_GETHZ 45 |
36 | #define VMWARE_PORT_CMD_GETVCPU_INFO 68 | ||
37 | #define VMWARE_PORT_CMD_LEGACY_X2APIC 3 | ||
38 | #define VMWARE_PORT_CMD_VCPU_RESERVED 31 | ||
36 | 39 | ||
37 | #define VMWARE_PORT(cmd, eax, ebx, ecx, edx) \ | 40 | #define VMWARE_PORT(cmd, eax, ebx, ecx, edx) \ |
38 | __asm__("inl (%%dx)" : \ | 41 | __asm__("inl (%%dx)" : \ |
@@ -125,10 +128,20 @@ static void __cpuinit vmware_set_cpu_features(struct cpuinfo_x86 *c) | |||
125 | set_cpu_cap(c, X86_FEATURE_TSC_RELIABLE); | 128 | set_cpu_cap(c, X86_FEATURE_TSC_RELIABLE); |
126 | } | 129 | } |
127 | 130 | ||
131 | /* Checks if hypervisor supports x2apic without VT-D interrupt remapping. */ | ||
132 | static bool __init vmware_legacy_x2apic_available(void) | ||
133 | { | ||
134 | uint32_t eax, ebx, ecx, edx; | ||
135 | VMWARE_PORT(GETVCPU_INFO, eax, ebx, ecx, edx); | ||
136 | return (eax & (1 << VMWARE_PORT_CMD_VCPU_RESERVED)) == 0 && | ||
137 | (eax & (1 << VMWARE_PORT_CMD_LEGACY_X2APIC)) != 0; | ||
138 | } | ||
139 | |||
128 | const __refconst struct hypervisor_x86 x86_hyper_vmware = { | 140 | const __refconst struct hypervisor_x86 x86_hyper_vmware = { |
129 | .name = "VMware", | 141 | .name = "VMware", |
130 | .detect = vmware_platform, | 142 | .detect = vmware_platform, |
131 | .set_cpu_features = vmware_set_cpu_features, | 143 | .set_cpu_features = vmware_set_cpu_features, |
132 | .init_platform = vmware_platform_setup, | 144 | .init_platform = vmware_platform_setup, |
145 | .x2apic_available = vmware_legacy_x2apic_available, | ||
133 | }; | 146 | }; |
134 | EXPORT_SYMBOL(x86_hyper_vmware); | 147 | EXPORT_SYMBOL(x86_hyper_vmware); |
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S index 6ed91d9980e2..8831176aa5ef 100644 --- a/arch/x86/kernel/entry_32.S +++ b/arch/x86/kernel/entry_32.S | |||
@@ -1091,11 +1091,18 @@ ENTRY(xen_failsafe_callback) | |||
1091 | _ASM_EXTABLE(4b,9b) | 1091 | _ASM_EXTABLE(4b,9b) |
1092 | ENDPROC(xen_failsafe_callback) | 1092 | ENDPROC(xen_failsafe_callback) |
1093 | 1093 | ||
1094 | BUILD_INTERRUPT3(xen_hvm_callback_vector, XEN_HVM_EVTCHN_CALLBACK, | 1094 | BUILD_INTERRUPT3(xen_hvm_callback_vector, HYPERVISOR_CALLBACK_VECTOR, |
1095 | xen_evtchn_do_upcall) | 1095 | xen_evtchn_do_upcall) |
1096 | 1096 | ||
1097 | #endif /* CONFIG_XEN */ | 1097 | #endif /* CONFIG_XEN */ |
1098 | 1098 | ||
1099 | #if IS_ENABLED(CONFIG_HYPERV) | ||
1100 | |||
1101 | BUILD_INTERRUPT3(hyperv_callback_vector, HYPERVISOR_CALLBACK_VECTOR, | ||
1102 | hyperv_vector_handler) | ||
1103 | |||
1104 | #endif /* CONFIG_HYPERV */ | ||
1105 | |||
1099 | #ifdef CONFIG_FUNCTION_TRACER | 1106 | #ifdef CONFIG_FUNCTION_TRACER |
1100 | #ifdef CONFIG_DYNAMIC_FTRACE | 1107 | #ifdef CONFIG_DYNAMIC_FTRACE |
1101 | 1108 | ||
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index cb3c591339aa..048f2240f8e6 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S | |||
@@ -1454,11 +1454,16 @@ ENTRY(xen_failsafe_callback) | |||
1454 | CFI_ENDPROC | 1454 | CFI_ENDPROC |
1455 | END(xen_failsafe_callback) | 1455 | END(xen_failsafe_callback) |
1456 | 1456 | ||
1457 | apicinterrupt XEN_HVM_EVTCHN_CALLBACK \ | 1457 | apicinterrupt HYPERVISOR_CALLBACK_VECTOR \ |
1458 | xen_hvm_callback_vector xen_evtchn_do_upcall | 1458 | xen_hvm_callback_vector xen_evtchn_do_upcall |
1459 | 1459 | ||
1460 | #endif /* CONFIG_XEN */ | 1460 | #endif /* CONFIG_XEN */ |
1461 | 1461 | ||
1462 | #if IS_ENABLED(CONFIG_HYPERV) | ||
1463 | apicinterrupt HYPERVISOR_CALLBACK_VECTOR \ | ||
1464 | hyperv_callback_vector hyperv_vector_handler | ||
1465 | #endif /* CONFIG_HYPERV */ | ||
1466 | |||
1462 | /* | 1467 | /* |
1463 | * Some functions should be protected against kprobes | 1468 | * Some functions should be protected against kprobes |
1464 | */ | 1469 | */ |
diff --git a/arch/x86/kernel/head32.c b/arch/x86/kernel/head32.c index c18f59d10101..6773c918b8cc 100644 --- a/arch/x86/kernel/head32.c +++ b/arch/x86/kernel/head32.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <asm/io_apic.h> | 18 | #include <asm/io_apic.h> |
19 | #include <asm/bios_ebda.h> | 19 | #include <asm/bios_ebda.h> |
20 | #include <asm/tlbflush.h> | 20 | #include <asm/tlbflush.h> |
21 | #include <asm/bootparam_utils.h> | ||
21 | 22 | ||
22 | static void __init i386_default_early_setup(void) | 23 | static void __init i386_default_early_setup(void) |
23 | { | 24 | { |
@@ -30,6 +31,8 @@ static void __init i386_default_early_setup(void) | |||
30 | 31 | ||
31 | void __init i386_start_kernel(void) | 32 | void __init i386_start_kernel(void) |
32 | { | 33 | { |
34 | sanitize_boot_params(&boot_params); | ||
35 | |||
33 | memblock_reserve(__pa_symbol(&_text), | 36 | memblock_reserve(__pa_symbol(&_text), |
34 | __pa_symbol(&__bss_stop) - __pa_symbol(&_text)); | 37 | __pa_symbol(&__bss_stop) - __pa_symbol(&_text)); |
35 | 38 | ||
diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c index 037df57a99ac..849fc9e63c2f 100644 --- a/arch/x86/kernel/head64.c +++ b/arch/x86/kernel/head64.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <asm/kdebug.h> | 25 | #include <asm/kdebug.h> |
26 | #include <asm/e820.h> | 26 | #include <asm/e820.h> |
27 | #include <asm/bios_ebda.h> | 27 | #include <asm/bios_ebda.h> |
28 | #include <asm/bootparam_utils.h> | ||
28 | 29 | ||
29 | static void __init zap_identity_mappings(void) | 30 | static void __init zap_identity_mappings(void) |
30 | { | 31 | { |
@@ -46,6 +47,7 @@ static void __init copy_bootdata(char *real_mode_data) | |||
46 | char * command_line; | 47 | char * command_line; |
47 | 48 | ||
48 | memcpy(&boot_params, real_mode_data, sizeof boot_params); | 49 | memcpy(&boot_params, real_mode_data, sizeof boot_params); |
50 | sanitize_boot_params(&boot_params); | ||
49 | if (boot_params.hdr.cmd_line_ptr) { | 51 | if (boot_params.hdr.cmd_line_ptr) { |
50 | command_line = __va(boot_params.hdr.cmd_line_ptr); | 52 | command_line = __va(boot_params.hdr.cmd_line_ptr); |
51 | memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE); | 53 | memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE); |
diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S index c8932c79e78b..3c3f58a0808f 100644 --- a/arch/x86/kernel/head_32.S +++ b/arch/x86/kernel/head_32.S | |||
@@ -307,36 +307,45 @@ default_entry: | |||
307 | movl %eax,%cr0 | 307 | movl %eax,%cr0 |
308 | 308 | ||
309 | /* | 309 | /* |
310 | * New page tables may be in 4Mbyte page mode and may | 310 | * We want to start out with EFLAGS unambiguously cleared. Some BIOSes leave |
311 | * be using the global pages. | 311 | * bits like NT set. This would confuse the debugger if this code is traced. So |
312 | * initialize them properly now before switching to protected mode. That means | ||
313 | * DF in particular (even though we have cleared it earlier after copying the | ||
314 | * command line) because GCC expects it. | ||
315 | */ | ||
316 | pushl $0 | ||
317 | popfl | ||
318 | |||
319 | /* | ||
320 | * New page tables may be in 4Mbyte page mode and may be using the global pages. | ||
312 | * | 321 | * |
313 | * NOTE! If we are on a 486 we may have no cr4 at all! | 322 | * NOTE! If we are on a 486 we may have no cr4 at all! Specifically, cr4 exists |
314 | * Specifically, cr4 exists if and only if CPUID exists | 323 | * if and only if CPUID exists and has flags other than the FPU flag set. |
315 | * and has flags other than the FPU flag set. | ||
316 | */ | 324 | */ |
325 | movl $-1,pa(X86_CPUID) # preset CPUID level | ||
317 | movl $X86_EFLAGS_ID,%ecx | 326 | movl $X86_EFLAGS_ID,%ecx |
318 | pushl %ecx | 327 | pushl %ecx |
319 | popfl | 328 | popfl # set EFLAGS=ID |
320 | pushfl | 329 | pushfl |
321 | popl %eax | 330 | popl %eax # get EFLAGS |
322 | pushl $0 | 331 | testl $X86_EFLAGS_ID,%eax # did EFLAGS.ID remained set? |
323 | popfl | 332 | jz enable_paging # hw disallowed setting of ID bit |
324 | pushfl | 333 | # which means no CPUID and no CR4 |
325 | popl %edx | 334 | |
326 | xorl %edx,%eax | 335 | xorl %eax,%eax |
327 | testl %ecx,%eax | 336 | cpuid |
328 | jz 6f # No ID flag = no CPUID = no CR4 | 337 | movl %eax,pa(X86_CPUID) # save largest std CPUID function |
329 | 338 | ||
330 | movl $1,%eax | 339 | movl $1,%eax |
331 | cpuid | 340 | cpuid |
332 | andl $~1,%edx # Ignore CPUID.FPU | 341 | andl $~1,%edx # Ignore CPUID.FPU |
333 | jz 6f # No flags or only CPUID.FPU = no CR4 | 342 | jz enable_paging # No flags or only CPUID.FPU = no CR4 |
334 | 343 | ||
335 | movl pa(mmu_cr4_features),%eax | 344 | movl pa(mmu_cr4_features),%eax |
336 | movl %eax,%cr4 | 345 | movl %eax,%cr4 |
337 | 346 | ||
338 | testb $X86_CR4_PAE, %al # check if PAE is enabled | 347 | testb $X86_CR4_PAE, %al # check if PAE is enabled |
339 | jz 6f | 348 | jz enable_paging |
340 | 349 | ||
341 | /* Check if extended functions are implemented */ | 350 | /* Check if extended functions are implemented */ |
342 | movl $0x80000000, %eax | 351 | movl $0x80000000, %eax |
@@ -344,7 +353,7 @@ default_entry: | |||
344 | /* Value must be in the range 0x80000001 to 0x8000ffff */ | 353 | /* Value must be in the range 0x80000001 to 0x8000ffff */ |
345 | subl $0x80000001, %eax | 354 | subl $0x80000001, %eax |
346 | cmpl $(0x8000ffff-0x80000001), %eax | 355 | cmpl $(0x8000ffff-0x80000001), %eax |
347 | ja 6f | 356 | ja enable_paging |
348 | 357 | ||
349 | /* Clear bogus XD_DISABLE bits */ | 358 | /* Clear bogus XD_DISABLE bits */ |
350 | call verify_cpu | 359 | call verify_cpu |
@@ -353,7 +362,7 @@ default_entry: | |||
353 | cpuid | 362 | cpuid |
354 | /* Execute Disable bit supported? */ | 363 | /* Execute Disable bit supported? */ |
355 | btl $(X86_FEATURE_NX & 31), %edx | 364 | btl $(X86_FEATURE_NX & 31), %edx |
356 | jnc 6f | 365 | jnc enable_paging |
357 | 366 | ||
358 | /* Setup EFER (Extended Feature Enable Register) */ | 367 | /* Setup EFER (Extended Feature Enable Register) */ |
359 | movl $MSR_EFER, %ecx | 368 | movl $MSR_EFER, %ecx |
@@ -363,7 +372,7 @@ default_entry: | |||
363 | /* Make changes effective */ | 372 | /* Make changes effective */ |
364 | wrmsr | 373 | wrmsr |
365 | 374 | ||
366 | 6: | 375 | enable_paging: |
367 | 376 | ||
368 | /* | 377 | /* |
369 | * Enable paging | 378 | * Enable paging |
@@ -378,14 +387,6 @@ default_entry: | |||
378 | addl $__PAGE_OFFSET, %esp | 387 | addl $__PAGE_OFFSET, %esp |
379 | 388 | ||
380 | /* | 389 | /* |
381 | * Initialize eflags. Some BIOS's leave bits like NT set. This would | ||
382 | * confuse the debugger if this code is traced. | ||
383 | * XXX - best to initialize before switching to protected mode. | ||
384 | */ | ||
385 | pushl $0 | ||
386 | popfl | ||
387 | |||
388 | /* | ||
389 | * start system 32-bit setup. We need to re-do some of the things done | 390 | * start system 32-bit setup. We need to re-do some of the things done |
390 | * in 16-bit mode for the "real" operations. | 391 | * in 16-bit mode for the "real" operations. |
391 | */ | 392 | */ |
@@ -394,31 +395,11 @@ default_entry: | |||
394 | jz 1f # Did we do this already? | 395 | jz 1f # Did we do this already? |
395 | call *%eax | 396 | call *%eax |
396 | 1: | 397 | 1: |
397 | 398 | ||
398 | /* check if it is 486 or 386. */ | ||
399 | /* | 399 | /* |
400 | * XXX - this does a lot of unnecessary setup. Alignment checks don't | 400 | * Check if it is 486 |
401 | * apply at our cpl of 0 and the stack ought to be aligned already, and | ||
402 | * we don't need to preserve eflags. | ||
403 | */ | 401 | */ |
404 | movl $-1,X86_CPUID # -1 for no CPUID initially | 402 | cmpl $-1,X86_CPUID |
405 | movb $3,X86 # at least 386 | ||
406 | pushfl # push EFLAGS | ||
407 | popl %eax # get EFLAGS | ||
408 | movl %eax,%ecx # save original EFLAGS | ||
409 | xorl $0x240000,%eax # flip AC and ID bits in EFLAGS | ||
410 | pushl %eax # copy to EFLAGS | ||
411 | popfl # set EFLAGS | ||
412 | pushfl # get new EFLAGS | ||
413 | popl %eax # put it in eax | ||
414 | xorl %ecx,%eax # change in flags | ||
415 | pushl %ecx # restore original EFLAGS | ||
416 | popfl | ||
417 | testl $0x40000,%eax # check if AC bit changed | ||
418 | je is386 | ||
419 | |||
420 | movb $4,X86 # at least 486 | ||
421 | testl $0x200000,%eax # check if ID bit changed | ||
422 | je is486 | 403 | je is486 |
423 | 404 | ||
424 | /* get vendor info */ | 405 | /* get vendor info */ |
@@ -444,11 +425,10 @@ default_entry: | |||
444 | movb %cl,X86_MASK | 425 | movb %cl,X86_MASK |
445 | movl %edx,X86_CAPABILITY | 426 | movl %edx,X86_CAPABILITY |
446 | 427 | ||
447 | is486: movl $0x50022,%ecx # set AM, WP, NE and MP | 428 | is486: |
448 | jmp 2f | 429 | movb $4,X86 |
449 | 430 | movl $0x50022,%ecx # set AM, WP, NE and MP | |
450 | is386: movl $2,%ecx # set MP | 431 | movl %cr0,%eax |
451 | 2: movl %cr0,%eax | ||
452 | andl $0x80000011,%eax # Save PG,PE,ET | 432 | andl $0x80000011,%eax # Save PG,PE,ET |
453 | orl %ecx,%eax | 433 | orl %ecx,%eax |
454 | movl %eax,%cr0 | 434 | movl %eax,%cr0 |
@@ -473,7 +453,6 @@ is386: movl $2,%ecx # set MP | |||
473 | xorl %eax,%eax # Clear LDT | 453 | xorl %eax,%eax # Clear LDT |
474 | lldt %ax | 454 | lldt %ax |
475 | 455 | ||
476 | cld # gcc2 wants the direction flag cleared at all times | ||
477 | pushl $0 # fake return address for unwinder | 456 | pushl $0 # fake return address for unwinder |
478 | jmp *(initial_code) | 457 | jmp *(initial_code) |
479 | 458 | ||
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index e28670f9a589..da85a8e830a1 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c | |||
@@ -478,7 +478,7 @@ static int hpet_msi_next_event(unsigned long delta, | |||
478 | 478 | ||
479 | static int hpet_setup_msi_irq(unsigned int irq) | 479 | static int hpet_setup_msi_irq(unsigned int irq) |
480 | { | 480 | { |
481 | if (arch_setup_hpet_msi(irq, hpet_blockid)) { | 481 | if (x86_msi.setup_hpet_msi(irq, hpet_blockid)) { |
482 | destroy_irq(irq); | 482 | destroy_irq(irq); |
483 | return -EINVAL; | 483 | return -EINVAL; |
484 | } | 484 | } |
diff --git a/arch/x86/kernel/kprobes/Makefile b/arch/x86/kernel/kprobes/Makefile new file mode 100644 index 000000000000..0d33169cc1a2 --- /dev/null +++ b/arch/x86/kernel/kprobes/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | # | ||
2 | # Makefile for kernel probes | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_KPROBES) += core.o | ||
6 | obj-$(CONFIG_OPTPROBES) += opt.o | ||
7 | obj-$(CONFIG_KPROBES_ON_FTRACE) += ftrace.o | ||
diff --git a/arch/x86/kernel/kprobes-common.h b/arch/x86/kernel/kprobes/common.h index 3230b68ef29a..2e9d4b5af036 100644 --- a/arch/x86/kernel/kprobes-common.h +++ b/arch/x86/kernel/kprobes/common.h | |||
@@ -99,4 +99,15 @@ static inline unsigned long __recover_optprobed_insn(kprobe_opcode_t *buf, unsig | |||
99 | return addr; | 99 | return addr; |
100 | } | 100 | } |
101 | #endif | 101 | #endif |
102 | |||
103 | #ifdef CONFIG_KPROBES_ON_FTRACE | ||
104 | extern int skip_singlestep(struct kprobe *p, struct pt_regs *regs, | ||
105 | struct kprobe_ctlblk *kcb); | ||
106 | #else | ||
107 | static inline int skip_singlestep(struct kprobe *p, struct pt_regs *regs, | ||
108 | struct kprobe_ctlblk *kcb) | ||
109 | { | ||
110 | return 0; | ||
111 | } | ||
112 | #endif | ||
102 | #endif | 113 | #endif |
diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes/core.c index 57916c0d3cf6..e124554598ee 100644 --- a/arch/x86/kernel/kprobes.c +++ b/arch/x86/kernel/kprobes/core.c | |||
@@ -58,7 +58,7 @@ | |||
58 | #include <asm/insn.h> | 58 | #include <asm/insn.h> |
59 | #include <asm/debugreg.h> | 59 | #include <asm/debugreg.h> |
60 | 60 | ||
61 | #include "kprobes-common.h" | 61 | #include "common.h" |
62 | 62 | ||
63 | void jprobe_return_end(void); | 63 | void jprobe_return_end(void); |
64 | 64 | ||
@@ -78,7 +78,7 @@ DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); | |||
78 | * Groups, and some special opcodes can not boost. | 78 | * Groups, and some special opcodes can not boost. |
79 | * This is non-const and volatile to keep gcc from statically | 79 | * This is non-const and volatile to keep gcc from statically |
80 | * optimizing it out, as variable_test_bit makes gcc think only | 80 | * optimizing it out, as variable_test_bit makes gcc think only |
81 | * *(unsigned long*) is used. | 81 | * *(unsigned long*) is used. |
82 | */ | 82 | */ |
83 | static volatile u32 twobyte_is_boostable[256 / 32] = { | 83 | static volatile u32 twobyte_is_boostable[256 / 32] = { |
84 | /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ | 84 | /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ |
@@ -117,7 +117,7 @@ static void __kprobes __synthesize_relative_insn(void *from, void *to, u8 op) | |||
117 | struct __arch_relative_insn { | 117 | struct __arch_relative_insn { |
118 | u8 op; | 118 | u8 op; |
119 | s32 raddr; | 119 | s32 raddr; |
120 | } __attribute__((packed)) *insn; | 120 | } __packed *insn; |
121 | 121 | ||
122 | insn = (struct __arch_relative_insn *)from; | 122 | insn = (struct __arch_relative_insn *)from; |
123 | insn->raddr = (s32)((long)(to) - ((long)(from) + 5)); | 123 | insn->raddr = (s32)((long)(to) - ((long)(from) + 5)); |
@@ -541,23 +541,6 @@ reenter_kprobe(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb | |||
541 | return 1; | 541 | return 1; |
542 | } | 542 | } |
543 | 543 | ||
544 | #ifdef KPROBES_CAN_USE_FTRACE | ||
545 | static void __kprobes skip_singlestep(struct kprobe *p, struct pt_regs *regs, | ||
546 | struct kprobe_ctlblk *kcb) | ||
547 | { | ||
548 | /* | ||
549 | * Emulate singlestep (and also recover regs->ip) | ||
550 | * as if there is a 5byte nop | ||
551 | */ | ||
552 | regs->ip = (unsigned long)p->addr + MCOUNT_INSN_SIZE; | ||
553 | if (unlikely(p->post_handler)) { | ||
554 | kcb->kprobe_status = KPROBE_HIT_SSDONE; | ||
555 | p->post_handler(p, regs, 0); | ||
556 | } | ||
557 | __this_cpu_write(current_kprobe, NULL); | ||
558 | } | ||
559 | #endif | ||
560 | |||
561 | /* | 544 | /* |
562 | * Interrupts are disabled on entry as trap3 is an interrupt gate and they | 545 | * Interrupts are disabled on entry as trap3 is an interrupt gate and they |
563 | * remain disabled throughout this function. | 546 | * remain disabled throughout this function. |
@@ -616,13 +599,8 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) | |||
616 | } else if (kprobe_running()) { | 599 | } else if (kprobe_running()) { |
617 | p = __this_cpu_read(current_kprobe); | 600 | p = __this_cpu_read(current_kprobe); |
618 | if (p->break_handler && p->break_handler(p, regs)) { | 601 | if (p->break_handler && p->break_handler(p, regs)) { |
619 | #ifdef KPROBES_CAN_USE_FTRACE | 602 | if (!skip_singlestep(p, regs, kcb)) |
620 | if (kprobe_ftrace(p)) { | 603 | setup_singlestep(p, regs, kcb, 0); |
621 | skip_singlestep(p, regs, kcb); | ||
622 | return 1; | ||
623 | } | ||
624 | #endif | ||
625 | setup_singlestep(p, regs, kcb, 0); | ||
626 | return 1; | 604 | return 1; |
627 | } | 605 | } |
628 | } /* else: not a kprobe fault; let the kernel handle it */ | 606 | } /* else: not a kprobe fault; let the kernel handle it */ |
@@ -1075,50 +1053,6 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) | |||
1075 | return 0; | 1053 | return 0; |
1076 | } | 1054 | } |
1077 | 1055 | ||
1078 | #ifdef KPROBES_CAN_USE_FTRACE | ||
1079 | /* Ftrace callback handler for kprobes */ | ||
1080 | void __kprobes kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip, | ||
1081 | struct ftrace_ops *ops, struct pt_regs *regs) | ||
1082 | { | ||
1083 | struct kprobe *p; | ||
1084 | struct kprobe_ctlblk *kcb; | ||
1085 | unsigned long flags; | ||
1086 | |||
1087 | /* Disable irq for emulating a breakpoint and avoiding preempt */ | ||
1088 | local_irq_save(flags); | ||
1089 | |||
1090 | p = get_kprobe((kprobe_opcode_t *)ip); | ||
1091 | if (unlikely(!p) || kprobe_disabled(p)) | ||
1092 | goto end; | ||
1093 | |||
1094 | kcb = get_kprobe_ctlblk(); | ||
1095 | if (kprobe_running()) { | ||
1096 | kprobes_inc_nmissed_count(p); | ||
1097 | } else { | ||
1098 | /* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */ | ||
1099 | regs->ip = ip + sizeof(kprobe_opcode_t); | ||
1100 | |||
1101 | __this_cpu_write(current_kprobe, p); | ||
1102 | kcb->kprobe_status = KPROBE_HIT_ACTIVE; | ||
1103 | if (!p->pre_handler || !p->pre_handler(p, regs)) | ||
1104 | skip_singlestep(p, regs, kcb); | ||
1105 | /* | ||
1106 | * If pre_handler returns !0, it sets regs->ip and | ||
1107 | * resets current kprobe. | ||
1108 | */ | ||
1109 | } | ||
1110 | end: | ||
1111 | local_irq_restore(flags); | ||
1112 | } | ||
1113 | |||
1114 | int __kprobes arch_prepare_kprobe_ftrace(struct kprobe *p) | ||
1115 | { | ||
1116 | p->ainsn.insn = NULL; | ||
1117 | p->ainsn.boostable = -1; | ||
1118 | return 0; | ||
1119 | } | ||
1120 | #endif | ||
1121 | |||
1122 | int __init arch_init_kprobes(void) | 1056 | int __init arch_init_kprobes(void) |
1123 | { | 1057 | { |
1124 | return arch_init_optprobes(); | 1058 | return arch_init_optprobes(); |
diff --git a/arch/x86/kernel/kprobes/ftrace.c b/arch/x86/kernel/kprobes/ftrace.c new file mode 100644 index 000000000000..23ef5c556f06 --- /dev/null +++ b/arch/x86/kernel/kprobes/ftrace.c | |||
@@ -0,0 +1,93 @@ | |||
1 | /* | ||
2 | * Dynamic Ftrace based Kprobes Optimization | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
17 | * | ||
18 | * Copyright (C) Hitachi Ltd., 2012 | ||
19 | */ | ||
20 | #include <linux/kprobes.h> | ||
21 | #include <linux/ptrace.h> | ||
22 | #include <linux/hardirq.h> | ||
23 | #include <linux/preempt.h> | ||
24 | #include <linux/ftrace.h> | ||
25 | |||
26 | #include "common.h" | ||
27 | |||
28 | static int __skip_singlestep(struct kprobe *p, struct pt_regs *regs, | ||
29 | struct kprobe_ctlblk *kcb) | ||
30 | { | ||
31 | /* | ||
32 | * Emulate singlestep (and also recover regs->ip) | ||
33 | * as if there is a 5byte nop | ||
34 | */ | ||
35 | regs->ip = (unsigned long)p->addr + MCOUNT_INSN_SIZE; | ||
36 | if (unlikely(p->post_handler)) { | ||
37 | kcb->kprobe_status = KPROBE_HIT_SSDONE; | ||
38 | p->post_handler(p, regs, 0); | ||
39 | } | ||
40 | __this_cpu_write(current_kprobe, NULL); | ||
41 | return 1; | ||
42 | } | ||
43 | |||
44 | int __kprobes skip_singlestep(struct kprobe *p, struct pt_regs *regs, | ||
45 | struct kprobe_ctlblk *kcb) | ||
46 | { | ||
47 | if (kprobe_ftrace(p)) | ||
48 | return __skip_singlestep(p, regs, kcb); | ||
49 | else | ||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | /* Ftrace callback handler for kprobes */ | ||
54 | void __kprobes kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip, | ||
55 | struct ftrace_ops *ops, struct pt_regs *regs) | ||
56 | { | ||
57 | struct kprobe *p; | ||
58 | struct kprobe_ctlblk *kcb; | ||
59 | unsigned long flags; | ||
60 | |||
61 | /* Disable irq for emulating a breakpoint and avoiding preempt */ | ||
62 | local_irq_save(flags); | ||
63 | |||
64 | p = get_kprobe((kprobe_opcode_t *)ip); | ||
65 | if (unlikely(!p) || kprobe_disabled(p)) | ||
66 | goto end; | ||
67 | |||
68 | kcb = get_kprobe_ctlblk(); | ||
69 | if (kprobe_running()) { | ||
70 | kprobes_inc_nmissed_count(p); | ||
71 | } else { | ||
72 | /* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */ | ||
73 | regs->ip = ip + sizeof(kprobe_opcode_t); | ||
74 | |||
75 | __this_cpu_write(current_kprobe, p); | ||
76 | kcb->kprobe_status = KPROBE_HIT_ACTIVE; | ||
77 | if (!p->pre_handler || !p->pre_handler(p, regs)) | ||
78 | __skip_singlestep(p, regs, kcb); | ||
79 | /* | ||
80 | * If pre_handler returns !0, it sets regs->ip and | ||
81 | * resets current kprobe. | ||
82 | */ | ||
83 | } | ||
84 | end: | ||
85 | local_irq_restore(flags); | ||
86 | } | ||
87 | |||
88 | int __kprobes arch_prepare_kprobe_ftrace(struct kprobe *p) | ||
89 | { | ||
90 | p->ainsn.insn = NULL; | ||
91 | p->ainsn.boostable = -1; | ||
92 | return 0; | ||
93 | } | ||
diff --git a/arch/x86/kernel/kprobes-opt.c b/arch/x86/kernel/kprobes/opt.c index c5e410eed403..76dc6f095724 100644 --- a/arch/x86/kernel/kprobes-opt.c +++ b/arch/x86/kernel/kprobes/opt.c | |||
@@ -37,7 +37,7 @@ | |||
37 | #include <asm/insn.h> | 37 | #include <asm/insn.h> |
38 | #include <asm/debugreg.h> | 38 | #include <asm/debugreg.h> |
39 | 39 | ||
40 | #include "kprobes-common.h" | 40 | #include "common.h" |
41 | 41 | ||
42 | unsigned long __recover_optprobed_insn(kprobe_opcode_t *buf, unsigned long addr) | 42 | unsigned long __recover_optprobed_insn(kprobe_opcode_t *buf, unsigned long addr) |
43 | { | 43 | { |
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index 9c2bd8bd4b4c..2b44ea5f269d 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c | |||
@@ -505,6 +505,7 @@ static bool __init kvm_detect(void) | |||
505 | const struct hypervisor_x86 x86_hyper_kvm __refconst = { | 505 | const struct hypervisor_x86 x86_hyper_kvm __refconst = { |
506 | .name = "KVM", | 506 | .name = "KVM", |
507 | .detect = kvm_detect, | 507 | .detect = kvm_detect, |
508 | .x2apic_available = kvm_para_available, | ||
508 | }; | 509 | }; |
509 | EXPORT_SYMBOL_GPL(x86_hyper_kvm); | 510 | EXPORT_SYMBOL_GPL(x86_hyper_kvm); |
510 | 511 | ||
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index b629bbe0d9bd..29a8120e6fe8 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c | |||
@@ -22,7 +22,7 @@ | |||
22 | #include <linux/perf_event.h> | 22 | #include <linux/perf_event.h> |
23 | #include <linux/hw_breakpoint.h> | 23 | #include <linux/hw_breakpoint.h> |
24 | #include <linux/rcupdate.h> | 24 | #include <linux/rcupdate.h> |
25 | #include <linux/module.h> | 25 | #include <linux/export.h> |
26 | #include <linux/context_tracking.h> | 26 | #include <linux/context_tracking.h> |
27 | 27 | ||
28 | #include <asm/uaccess.h> | 28 | #include <asm/uaccess.h> |
diff --git a/arch/x86/kernel/rtc.c b/arch/x86/kernel/rtc.c index 801602b5d745..2e8f3d3b5641 100644 --- a/arch/x86/kernel/rtc.c +++ b/arch/x86/kernel/rtc.c | |||
@@ -149,7 +149,6 @@ unsigned long mach_get_cmos_time(void) | |||
149 | if (century) { | 149 | if (century) { |
150 | century = bcd2bin(century); | 150 | century = bcd2bin(century); |
151 | year += century * 100; | 151 | year += century * 100; |
152 | printk(KERN_INFO "Extended CMOS year: %d\n", century * 100); | ||
153 | } else | 152 | } else |
154 | year += CMOS_YEARS_OFFS; | 153 | year += CMOS_YEARS_OFFS; |
155 | 154 | ||
diff --git a/arch/x86/kernel/sys_x86_64.c b/arch/x86/kernel/sys_x86_64.c index 97ef74b88e0f..dbded5aedb81 100644 --- a/arch/x86/kernel/sys_x86_64.c +++ b/arch/x86/kernel/sys_x86_64.c | |||
@@ -157,7 +157,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, | |||
157 | if (flags & MAP_FIXED) | 157 | if (flags & MAP_FIXED) |
158 | return addr; | 158 | return addr; |
159 | 159 | ||
160 | /* for MAP_32BIT mappings we force the legact mmap base */ | 160 | /* for MAP_32BIT mappings we force the legacy mmap base */ |
161 | if (!test_thread_flag(TIF_ADDR32) && (flags & MAP_32BIT)) | 161 | if (!test_thread_flag(TIF_ADDR32) && (flags & MAP_32BIT)) |
162 | goto bottomup; | 162 | goto bottomup; |
163 | 163 | ||
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index 06ccb5073a3f..4b9ea101fe3b 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c | |||
@@ -623,7 +623,8 @@ static void set_cyc2ns_scale(unsigned long cpu_khz, int cpu) | |||
623 | ns_now = __cycles_2_ns(tsc_now); | 623 | ns_now = __cycles_2_ns(tsc_now); |
624 | 624 | ||
625 | if (cpu_khz) { | 625 | if (cpu_khz) { |
626 | *scale = (NSEC_PER_MSEC << CYC2NS_SCALE_FACTOR)/cpu_khz; | 626 | *scale = ((NSEC_PER_MSEC << CYC2NS_SCALE_FACTOR) + |
627 | cpu_khz / 2) / cpu_khz; | ||
627 | *offset = ns_now - mult_frac(tsc_now, *scale, | 628 | *offset = ns_now - mult_frac(tsc_now, *scale, |
628 | (1UL << CYC2NS_SCALE_FACTOR)); | 629 | (1UL << CYC2NS_SCALE_FACTOR)); |
629 | } | 630 | } |
diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c index c71025b67462..0ba4cfb4f412 100644 --- a/arch/x86/kernel/uprobes.c +++ b/arch/x86/kernel/uprobes.c | |||
@@ -680,8 +680,10 @@ static bool __skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) | |||
680 | if (auprobe->insn[i] == 0x66) | 680 | if (auprobe->insn[i] == 0x66) |
681 | continue; | 681 | continue; |
682 | 682 | ||
683 | if (auprobe->insn[i] == 0x90) | 683 | if (auprobe->insn[i] == 0x90) { |
684 | regs->ip += i + 1; | ||
684 | return true; | 685 | return true; |
686 | } | ||
685 | 687 | ||
686 | break; | 688 | break; |
687 | } | 689 | } |
diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c index 7a3d075a814a..d065d67c2672 100644 --- a/arch/x86/kernel/x86_init.c +++ b/arch/x86/kernel/x86_init.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <asm/time.h> | 19 | #include <asm/time.h> |
20 | #include <asm/irq.h> | 20 | #include <asm/irq.h> |
21 | #include <asm/io_apic.h> | 21 | #include <asm/io_apic.h> |
22 | #include <asm/hpet.h> | ||
22 | #include <asm/pat.h> | 23 | #include <asm/pat.h> |
23 | #include <asm/tsc.h> | 24 | #include <asm/tsc.h> |
24 | #include <asm/iommu.h> | 25 | #include <asm/iommu.h> |
@@ -111,15 +112,22 @@ struct x86_platform_ops x86_platform = { | |||
111 | 112 | ||
112 | EXPORT_SYMBOL_GPL(x86_platform); | 113 | EXPORT_SYMBOL_GPL(x86_platform); |
113 | struct x86_msi_ops x86_msi = { | 114 | struct x86_msi_ops x86_msi = { |
114 | .setup_msi_irqs = native_setup_msi_irqs, | 115 | .setup_msi_irqs = native_setup_msi_irqs, |
115 | .teardown_msi_irq = native_teardown_msi_irq, | 116 | .compose_msi_msg = native_compose_msi_msg, |
116 | .teardown_msi_irqs = default_teardown_msi_irqs, | 117 | .teardown_msi_irq = native_teardown_msi_irq, |
117 | .restore_msi_irqs = default_restore_msi_irqs, | 118 | .teardown_msi_irqs = default_teardown_msi_irqs, |
119 | .restore_msi_irqs = default_restore_msi_irqs, | ||
120 | .setup_hpet_msi = default_setup_hpet_msi, | ||
118 | }; | 121 | }; |
119 | 122 | ||
120 | struct x86_io_apic_ops x86_io_apic_ops = { | 123 | struct x86_io_apic_ops x86_io_apic_ops = { |
121 | .init = native_io_apic_init_mappings, | 124 | .init = native_io_apic_init_mappings, |
122 | .read = native_io_apic_read, | 125 | .read = native_io_apic_read, |
123 | .write = native_io_apic_write, | 126 | .write = native_io_apic_write, |
124 | .modify = native_io_apic_modify, | 127 | .modify = native_io_apic_modify, |
128 | .disable = native_disable_io_apic, | ||
129 | .print_entries = native_io_apic_print_entries, | ||
130 | .set_affinity = native_ioapic_set_affinity, | ||
131 | .setup_entry = native_setup_ioapic_entry, | ||
132 | .eoi_ioapic_pin = native_eoi_ioapic_pin, | ||
125 | }; | 133 | }; |
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 027088f2f7dd..fb674fd3fc22 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c | |||
@@ -748,13 +748,15 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code, | |||
748 | return; | 748 | return; |
749 | } | 749 | } |
750 | #endif | 750 | #endif |
751 | /* Kernel addresses are always protection faults: */ | ||
752 | if (address >= TASK_SIZE) | ||
753 | error_code |= PF_PROT; | ||
751 | 754 | ||
752 | if (unlikely(show_unhandled_signals)) | 755 | if (likely(show_unhandled_signals)) |
753 | show_signal_msg(regs, error_code, address, tsk); | 756 | show_signal_msg(regs, error_code, address, tsk); |
754 | 757 | ||
755 | /* Kernel addresses are always protection faults: */ | ||
756 | tsk->thread.cr2 = address; | 758 | tsk->thread.cr2 = address; |
757 | tsk->thread.error_code = error_code | (address >= TASK_SIZE); | 759 | tsk->thread.error_code = error_code; |
758 | tsk->thread.trap_nr = X86_TRAP_PF; | 760 | tsk->thread.trap_nr = X86_TRAP_PF; |
759 | 761 | ||
760 | force_sig_info_fault(SIGSEGV, si_code, address, tsk, 0); | 762 | force_sig_info_fault(SIGSEGV, si_code, address, tsk, 0); |
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index 2ead3c8a4c84..d6eeead43758 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c | |||
@@ -605,7 +605,7 @@ kernel_physical_mapping_init(unsigned long start, | |||
605 | } | 605 | } |
606 | 606 | ||
607 | if (pgd_changed) | 607 | if (pgd_changed) |
608 | sync_global_pgds(addr, end); | 608 | sync_global_pgds(addr, end - 1); |
609 | 609 | ||
610 | __flush_tlb_all(); | 610 | __flush_tlb_all(); |
611 | 611 | ||
@@ -831,6 +831,9 @@ int kern_addr_valid(unsigned long addr) | |||
831 | if (pud_none(*pud)) | 831 | if (pud_none(*pud)) |
832 | return 0; | 832 | return 0; |
833 | 833 | ||
834 | if (pud_large(*pud)) | ||
835 | return pfn_valid(pud_pfn(*pud)); | ||
836 | |||
834 | pmd = pmd_offset(pud, addr); | 837 | pmd = pmd_offset(pud, addr); |
835 | if (pmd_none(*pmd)) | 838 | if (pmd_none(*pmd)) |
836 | return 0; | 839 | return 0; |
@@ -981,7 +984,7 @@ vmemmap_populate(struct page *start_page, unsigned long size, int node) | |||
981 | } | 984 | } |
982 | 985 | ||
983 | } | 986 | } |
984 | sync_global_pgds((unsigned long)start_page, end); | 987 | sync_global_pgds((unsigned long)start_page, end - 1); |
985 | return 0; | 988 | return 0; |
986 | } | 989 | } |
987 | 990 | ||
diff --git a/arch/x86/mm/memtest.c b/arch/x86/mm/memtest.c index c80b9fb95734..8dabbed409ee 100644 --- a/arch/x86/mm/memtest.c +++ b/arch/x86/mm/memtest.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <linux/memblock.h> | 9 | #include <linux/memblock.h> |
10 | 10 | ||
11 | static u64 patterns[] __initdata = { | 11 | static u64 patterns[] __initdata = { |
12 | /* The first entry has to be 0 to leave memtest with zeroed memory */ | ||
12 | 0, | 13 | 0, |
13 | 0xffffffffffffffffULL, | 14 | 0xffffffffffffffffULL, |
14 | 0x5555555555555555ULL, | 15 | 0x5555555555555555ULL, |
@@ -110,15 +111,8 @@ void __init early_memtest(unsigned long start, unsigned long end) | |||
110 | return; | 111 | return; |
111 | 112 | ||
112 | printk(KERN_INFO "early_memtest: # of tests: %d\n", memtest_pattern); | 113 | printk(KERN_INFO "early_memtest: # of tests: %d\n", memtest_pattern); |
113 | for (i = 0; i < memtest_pattern; i++) { | 114 | for (i = memtest_pattern-1; i < UINT_MAX; --i) { |
114 | idx = i % ARRAY_SIZE(patterns); | 115 | idx = i % ARRAY_SIZE(patterns); |
115 | do_one_pass(patterns[idx], start, end); | 116 | do_one_pass(patterns[idx], start, end); |
116 | } | 117 | } |
117 | |||
118 | if (idx > 0) { | ||
119 | printk(KERN_INFO "early_memtest: wipe out " | ||
120 | "test pattern from memory\n"); | ||
121 | /* additional test with pattern 0 will do this */ | ||
122 | do_one_pass(0, start, end); | ||
123 | } | ||
124 | } | 118 | } |
diff --git a/arch/x86/mm/srat.c b/arch/x86/mm/srat.c index 4ddf497ca65b..cdd0da9dd530 100644 --- a/arch/x86/mm/srat.c +++ b/arch/x86/mm/srat.c | |||
@@ -149,39 +149,40 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) | |||
149 | int node, pxm; | 149 | int node, pxm; |
150 | 150 | ||
151 | if (srat_disabled()) | 151 | if (srat_disabled()) |
152 | return -1; | 152 | goto out_err; |
153 | if (ma->header.length != sizeof(struct acpi_srat_mem_affinity)) { | 153 | if (ma->header.length != sizeof(struct acpi_srat_mem_affinity)) |
154 | bad_srat(); | 154 | goto out_err_bad_srat; |
155 | return -1; | ||
156 | } | ||
157 | if ((ma->flags & ACPI_SRAT_MEM_ENABLED) == 0) | 155 | if ((ma->flags & ACPI_SRAT_MEM_ENABLED) == 0) |
158 | return -1; | 156 | goto out_err; |
159 | |||
160 | if ((ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) && !save_add_info()) | 157 | if ((ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) && !save_add_info()) |
161 | return -1; | 158 | goto out_err; |
159 | |||
162 | start = ma->base_address; | 160 | start = ma->base_address; |
163 | end = start + ma->length; | 161 | end = start + ma->length; |
164 | pxm = ma->proximity_domain; | 162 | pxm = ma->proximity_domain; |
165 | if (acpi_srat_revision <= 1) | 163 | if (acpi_srat_revision <= 1) |
166 | pxm &= 0xff; | 164 | pxm &= 0xff; |
165 | |||
167 | node = setup_node(pxm); | 166 | node = setup_node(pxm); |
168 | if (node < 0) { | 167 | if (node < 0) { |
169 | printk(KERN_ERR "SRAT: Too many proximity domains.\n"); | 168 | printk(KERN_ERR "SRAT: Too many proximity domains.\n"); |
170 | bad_srat(); | 169 | goto out_err_bad_srat; |
171 | return -1; | ||
172 | } | 170 | } |
173 | 171 | ||
174 | if (numa_add_memblk(node, start, end) < 0) { | 172 | if (numa_add_memblk(node, start, end) < 0) |
175 | bad_srat(); | 173 | goto out_err_bad_srat; |
176 | return -1; | ||
177 | } | ||
178 | 174 | ||
179 | node_set(node, numa_nodes_parsed); | 175 | node_set(node, numa_nodes_parsed); |
180 | 176 | ||
181 | printk(KERN_INFO "SRAT: Node %u PXM %u [mem %#010Lx-%#010Lx]\n", | 177 | printk(KERN_INFO "SRAT: Node %u PXM %u [mem %#010Lx-%#010Lx]\n", |
182 | node, pxm, | 178 | node, pxm, |
183 | (unsigned long long) start, (unsigned long long) end - 1); | 179 | (unsigned long long) start, (unsigned long long) end - 1); |
180 | |||
184 | return 0; | 181 | return 0; |
182 | out_err_bad_srat: | ||
183 | bad_srat(); | ||
184 | out_err: | ||
185 | return -1; | ||
185 | } | 186 | } |
186 | 187 | ||
187 | void __init acpi_numa_arch_fixup(void) {} | 188 | void __init acpi_numa_arch_fixup(void) {} |
diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c index 13a6b29e2e5d..282375f13c7e 100644 --- a/arch/x86/mm/tlb.c +++ b/arch/x86/mm/tlb.c | |||
@@ -335,7 +335,7 @@ static const struct file_operations fops_tlbflush = { | |||
335 | .llseek = default_llseek, | 335 | .llseek = default_llseek, |
336 | }; | 336 | }; |
337 | 337 | ||
338 | static int __cpuinit create_tlb_flushall_shift(void) | 338 | static int __init create_tlb_flushall_shift(void) |
339 | { | 339 | { |
340 | debugfs_create_file("tlb_flushall_shift", S_IRUSR | S_IWUSR, | 340 | debugfs_create_file("tlb_flushall_shift", S_IRUSR | S_IWUSR, |
341 | arch_debugfs_dir, NULL, &fops_tlbflush); | 341 | arch_debugfs_dir, NULL, &fops_tlbflush); |
diff --git a/arch/x86/platform/Makefile b/arch/x86/platform/Makefile index 8d874396cb29..01e0231a113e 100644 --- a/arch/x86/platform/Makefile +++ b/arch/x86/platform/Makefile | |||
@@ -2,10 +2,12 @@ | |||
2 | obj-y += ce4100/ | 2 | obj-y += ce4100/ |
3 | obj-y += efi/ | 3 | obj-y += efi/ |
4 | obj-y += geode/ | 4 | obj-y += geode/ |
5 | obj-y += goldfish/ | ||
5 | obj-y += iris/ | 6 | obj-y += iris/ |
6 | obj-y += mrst/ | 7 | obj-y += mrst/ |
7 | obj-y += olpc/ | 8 | obj-y += olpc/ |
8 | obj-y += scx200/ | 9 | obj-y += scx200/ |
9 | obj-y += sfi/ | 10 | obj-y += sfi/ |
11 | obj-y += ts5500/ | ||
10 | obj-y += visws/ | 12 | obj-y += visws/ |
11 | obj-y += uv/ | 13 | obj-y += uv/ |
diff --git a/arch/x86/platform/efi/efi-bgrt.c b/arch/x86/platform/efi/efi-bgrt.c index d9c1b95af17c..7145ec63c520 100644 --- a/arch/x86/platform/efi/efi-bgrt.c +++ b/arch/x86/platform/efi/efi-bgrt.c | |||
@@ -11,20 +11,21 @@ | |||
11 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
12 | */ | 12 | */ |
13 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
14 | #include <linux/init.h> | ||
14 | #include <linux/acpi.h> | 15 | #include <linux/acpi.h> |
15 | #include <linux/efi.h> | 16 | #include <linux/efi.h> |
16 | #include <linux/efi-bgrt.h> | 17 | #include <linux/efi-bgrt.h> |
17 | 18 | ||
18 | struct acpi_table_bgrt *bgrt_tab; | 19 | struct acpi_table_bgrt *bgrt_tab; |
19 | void *bgrt_image; | 20 | void *__initdata bgrt_image; |
20 | size_t bgrt_image_size; | 21 | size_t __initdata bgrt_image_size; |
21 | 22 | ||
22 | struct bmp_header { | 23 | struct bmp_header { |
23 | u16 id; | 24 | u16 id; |
24 | u32 size; | 25 | u32 size; |
25 | } __packed; | 26 | } __packed; |
26 | 27 | ||
27 | void efi_bgrt_init(void) | 28 | void __init efi_bgrt_init(void) |
28 | { | 29 | { |
29 | acpi_status status; | 30 | acpi_status status; |
30 | void __iomem *image; | 31 | void __iomem *image; |
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 77cf0090c0a3..928bf837040a 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c | |||
@@ -87,7 +87,7 @@ EXPORT_SYMBOL(efi_enabled); | |||
87 | 87 | ||
88 | static int __init setup_noefi(char *arg) | 88 | static int __init setup_noefi(char *arg) |
89 | { | 89 | { |
90 | clear_bit(EFI_BOOT, &x86_efi_facility); | 90 | clear_bit(EFI_RUNTIME_SERVICES, &x86_efi_facility); |
91 | return 0; | 91 | return 0; |
92 | } | 92 | } |
93 | early_param("noefi", setup_noefi); | 93 | early_param("noefi", setup_noefi); |
diff --git a/arch/x86/platform/goldfish/Makefile b/arch/x86/platform/goldfish/Makefile new file mode 100644 index 000000000000..f030b532fdf3 --- /dev/null +++ b/arch/x86/platform/goldfish/Makefile | |||
@@ -0,0 +1 @@ | |||
obj-$(CONFIG_GOLDFISH) += goldfish.o | |||
diff --git a/arch/x86/platform/goldfish/goldfish.c b/arch/x86/platform/goldfish/goldfish.c new file mode 100644 index 000000000000..1693107a518e --- /dev/null +++ b/arch/x86/platform/goldfish/goldfish.c | |||
@@ -0,0 +1,51 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007 Google, Inc. | ||
3 | * Copyright (C) 2011 Intel, Inc. | ||
4 | * Copyright (C) 2013 Intel, Inc. | ||
5 | * | ||
6 | * This software is licensed under the terms of the GNU General Public | ||
7 | * License version 2, as published by the Free Software Foundation, and | ||
8 | * may be copied, distributed, and modified under those terms. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/irq.h> | ||
19 | #include <linux/platform_device.h> | ||
20 | |||
21 | /* | ||
22 | * Where in virtual device memory the IO devices (timers, system controllers | ||
23 | * and so on) | ||
24 | */ | ||
25 | |||
26 | #define GOLDFISH_PDEV_BUS_BASE (0xff001000) | ||
27 | #define GOLDFISH_PDEV_BUS_END (0xff7fffff) | ||
28 | #define GOLDFISH_PDEV_BUS_IRQ (4) | ||
29 | |||
30 | #define GOLDFISH_TTY_BASE (0x2000) | ||
31 | |||
32 | static struct resource goldfish_pdev_bus_resources[] = { | ||
33 | { | ||
34 | .start = GOLDFISH_PDEV_BUS_BASE, | ||
35 | .end = GOLDFISH_PDEV_BUS_END, | ||
36 | .flags = IORESOURCE_MEM, | ||
37 | }, | ||
38 | { | ||
39 | .start = GOLDFISH_PDEV_BUS_IRQ, | ||
40 | .end = GOLDFISH_PDEV_BUS_IRQ, | ||
41 | .flags = IORESOURCE_IRQ, | ||
42 | } | ||
43 | }; | ||
44 | |||
45 | static int __init goldfish_init(void) | ||
46 | { | ||
47 | platform_device_register_simple("goldfish_pdev_bus", -1, | ||
48 | goldfish_pdev_bus_resources, 2); | ||
49 | return 0; | ||
50 | } | ||
51 | device_initcall(goldfish_init); | ||
diff --git a/arch/x86/platform/sfi/sfi.c b/arch/x86/platform/sfi/sfi.c index 7785b72ecc3a..bcd1a703e3e6 100644 --- a/arch/x86/platform/sfi/sfi.c +++ b/arch/x86/platform/sfi/sfi.c | |||
@@ -35,7 +35,7 @@ | |||
35 | static unsigned long sfi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE; | 35 | static unsigned long sfi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE; |
36 | 36 | ||
37 | /* All CPUs enumerated by SFI must be present and enabled */ | 37 | /* All CPUs enumerated by SFI must be present and enabled */ |
38 | static void __cpuinit mp_sfi_register_lapic(u8 id) | 38 | static void __init mp_sfi_register_lapic(u8 id) |
39 | { | 39 | { |
40 | if (MAX_LOCAL_APIC - id <= 0) { | 40 | if (MAX_LOCAL_APIC - id <= 0) { |
41 | pr_warning("Processor #%d invalid (max %d)\n", | 41 | pr_warning("Processor #%d invalid (max %d)\n", |
diff --git a/arch/x86/platform/ts5500/Makefile b/arch/x86/platform/ts5500/Makefile new file mode 100644 index 000000000000..c54e348c96a7 --- /dev/null +++ b/arch/x86/platform/ts5500/Makefile | |||
@@ -0,0 +1 @@ | |||
obj-$(CONFIG_TS5500) += ts5500.o | |||
diff --git a/arch/x86/platform/ts5500/ts5500.c b/arch/x86/platform/ts5500/ts5500.c new file mode 100644 index 000000000000..39febb214e8c --- /dev/null +++ b/arch/x86/platform/ts5500/ts5500.c | |||
@@ -0,0 +1,339 @@ | |||
1 | /* | ||
2 | * Technologic Systems TS-5500 Single Board Computer support | ||
3 | * | ||
4 | * Copyright (C) 2013 Savoir-faire Linux Inc. | ||
5 | * Vivien Didelot <vivien.didelot@savoirfairelinux.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it under | ||
8 | * the terms of the GNU General Public License as published by the Free Software | ||
9 | * Foundation; either version 2 of the License, or (at your option) any later | ||
10 | * version. | ||
11 | * | ||
12 | * | ||
13 | * This driver registers the Technologic Systems TS-5500 Single Board Computer | ||
14 | * (SBC) and its devices, and exposes information to userspace such as jumpers' | ||
15 | * state or available options. For further information about sysfs entries, see | ||
16 | * Documentation/ABI/testing/sysfs-platform-ts5500. | ||
17 | * | ||
18 | * This code actually supports the TS-5500 platform, but it may be extended to | ||
19 | * support similar Technologic Systems x86-based platforms, such as the TS-5600. | ||
20 | */ | ||
21 | |||
22 | #include <linux/delay.h> | ||
23 | #include <linux/io.h> | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/leds.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/platform_data/gpio-ts5500.h> | ||
28 | #include <linux/platform_data/max197.h> | ||
29 | #include <linux/platform_device.h> | ||
30 | #include <linux/slab.h> | ||
31 | |||
32 | /* Product code register */ | ||
33 | #define TS5500_PRODUCT_CODE_ADDR 0x74 | ||
34 | #define TS5500_PRODUCT_CODE 0x60 /* TS-5500 product code */ | ||
35 | |||
36 | /* SRAM/RS-485/ADC options, and RS-485 RTS/Automatic RS-485 flags register */ | ||
37 | #define TS5500_SRAM_RS485_ADC_ADDR 0x75 | ||
38 | #define TS5500_SRAM BIT(0) /* SRAM option */ | ||
39 | #define TS5500_RS485 BIT(1) /* RS-485 option */ | ||
40 | #define TS5500_ADC BIT(2) /* A/D converter option */ | ||
41 | #define TS5500_RS485_RTS BIT(6) /* RTS for RS-485 */ | ||
42 | #define TS5500_RS485_AUTO BIT(7) /* Automatic RS-485 */ | ||
43 | |||
44 | /* External Reset/Industrial Temperature Range options register */ | ||
45 | #define TS5500_ERESET_ITR_ADDR 0x76 | ||
46 | #define TS5500_ERESET BIT(0) /* External Reset option */ | ||
47 | #define TS5500_ITR BIT(1) /* Indust. Temp. Range option */ | ||
48 | |||
49 | /* LED/Jumpers register */ | ||
50 | #define TS5500_LED_JP_ADDR 0x77 | ||
51 | #define TS5500_LED BIT(0) /* LED flag */ | ||
52 | #define TS5500_JP1 BIT(1) /* Automatic CMOS */ | ||
53 | #define TS5500_JP2 BIT(2) /* Enable Serial Console */ | ||
54 | #define TS5500_JP3 BIT(3) /* Write Enable Drive A */ | ||
55 | #define TS5500_JP4 BIT(4) /* Fast Console (115K baud) */ | ||
56 | #define TS5500_JP5 BIT(5) /* User Jumper */ | ||
57 | #define TS5500_JP6 BIT(6) /* Console on COM1 (req. JP2) */ | ||
58 | #define TS5500_JP7 BIT(7) /* Undocumented (Unused) */ | ||
59 | |||
60 | /* A/D Converter registers */ | ||
61 | #define TS5500_ADC_CONV_BUSY_ADDR 0x195 /* Conversion state register */ | ||
62 | #define TS5500_ADC_CONV_BUSY BIT(0) | ||
63 | #define TS5500_ADC_CONV_INIT_LSB_ADDR 0x196 /* Start conv. / LSB register */ | ||
64 | #define TS5500_ADC_CONV_MSB_ADDR 0x197 /* MSB register */ | ||
65 | #define TS5500_ADC_CONV_DELAY 12 /* usec */ | ||
66 | |||
67 | /** | ||
68 | * struct ts5500_sbc - TS-5500 board description | ||
69 | * @id: Board product ID. | ||
70 | * @sram: Flag for SRAM option. | ||
71 | * @rs485: Flag for RS-485 option. | ||
72 | * @adc: Flag for Analog/Digital converter option. | ||
73 | * @ereset: Flag for External Reset option. | ||
74 | * @itr: Flag for Industrial Temperature Range option. | ||
75 | * @jumpers: Bitfield for jumpers' state. | ||
76 | */ | ||
77 | struct ts5500_sbc { | ||
78 | int id; | ||
79 | bool sram; | ||
80 | bool rs485; | ||
81 | bool adc; | ||
82 | bool ereset; | ||
83 | bool itr; | ||
84 | u8 jumpers; | ||
85 | }; | ||
86 | |||
87 | /* Board signatures in BIOS shadow RAM */ | ||
88 | static const struct { | ||
89 | const char * const string; | ||
90 | const ssize_t offset; | ||
91 | } ts5500_signatures[] __initdata = { | ||
92 | { "TS-5x00 AMD Elan", 0xb14 }, | ||
93 | }; | ||
94 | |||
95 | static int __init ts5500_check_signature(void) | ||
96 | { | ||
97 | void __iomem *bios; | ||
98 | int i, ret = -ENODEV; | ||
99 | |||
100 | bios = ioremap(0xf0000, 0x10000); | ||
101 | if (!bios) | ||
102 | return -ENOMEM; | ||
103 | |||
104 | for (i = 0; i < ARRAY_SIZE(ts5500_signatures); i++) { | ||
105 | if (check_signature(bios + ts5500_signatures[i].offset, | ||
106 | ts5500_signatures[i].string, | ||
107 | strlen(ts5500_signatures[i].string))) { | ||
108 | ret = 0; | ||
109 | break; | ||
110 | } | ||
111 | } | ||
112 | |||
113 | iounmap(bios); | ||
114 | return ret; | ||
115 | } | ||
116 | |||
117 | static int __init ts5500_detect_config(struct ts5500_sbc *sbc) | ||
118 | { | ||
119 | u8 tmp; | ||
120 | int ret = 0; | ||
121 | |||
122 | if (!request_region(TS5500_PRODUCT_CODE_ADDR, 4, "ts5500")) | ||
123 | return -EBUSY; | ||
124 | |||
125 | tmp = inb(TS5500_PRODUCT_CODE_ADDR); | ||
126 | if (tmp != TS5500_PRODUCT_CODE) { | ||
127 | pr_err("This platform is not a TS-5500 (found ID 0x%x)\n", tmp); | ||
128 | ret = -ENODEV; | ||
129 | goto cleanup; | ||
130 | } | ||
131 | sbc->id = tmp; | ||
132 | |||
133 | tmp = inb(TS5500_SRAM_RS485_ADC_ADDR); | ||
134 | sbc->sram = tmp & TS5500_SRAM; | ||
135 | sbc->rs485 = tmp & TS5500_RS485; | ||
136 | sbc->adc = tmp & TS5500_ADC; | ||
137 | |||
138 | tmp = inb(TS5500_ERESET_ITR_ADDR); | ||
139 | sbc->ereset = tmp & TS5500_ERESET; | ||
140 | sbc->itr = tmp & TS5500_ITR; | ||
141 | |||
142 | tmp = inb(TS5500_LED_JP_ADDR); | ||
143 | sbc->jumpers = tmp & ~TS5500_LED; | ||
144 | |||
145 | cleanup: | ||
146 | release_region(TS5500_PRODUCT_CODE_ADDR, 4); | ||
147 | return ret; | ||
148 | } | ||
149 | |||
150 | static ssize_t ts5500_show_id(struct device *dev, | ||
151 | struct device_attribute *attr, char *buf) | ||
152 | { | ||
153 | struct ts5500_sbc *sbc = dev_get_drvdata(dev); | ||
154 | |||
155 | return sprintf(buf, "0x%.2x\n", sbc->id); | ||
156 | } | ||
157 | |||
158 | static ssize_t ts5500_show_jumpers(struct device *dev, | ||
159 | struct device_attribute *attr, | ||
160 | char *buf) | ||
161 | { | ||
162 | struct ts5500_sbc *sbc = dev_get_drvdata(dev); | ||
163 | |||
164 | return sprintf(buf, "0x%.2x\n", sbc->jumpers >> 1); | ||
165 | } | ||
166 | |||
167 | #define TS5500_SHOW(field) \ | ||
168 | static ssize_t ts5500_show_##field(struct device *dev, \ | ||
169 | struct device_attribute *attr, \ | ||
170 | char *buf) \ | ||
171 | { \ | ||
172 | struct ts5500_sbc *sbc = dev_get_drvdata(dev); \ | ||
173 | return sprintf(buf, "%d\n", sbc->field); \ | ||
174 | } | ||
175 | |||
176 | TS5500_SHOW(sram) | ||
177 | TS5500_SHOW(rs485) | ||
178 | TS5500_SHOW(adc) | ||
179 | TS5500_SHOW(ereset) | ||
180 | TS5500_SHOW(itr) | ||
181 | |||
182 | static DEVICE_ATTR(id, S_IRUGO, ts5500_show_id, NULL); | ||
183 | static DEVICE_ATTR(jumpers, S_IRUGO, ts5500_show_jumpers, NULL); | ||
184 | static DEVICE_ATTR(sram, S_IRUGO, ts5500_show_sram, NULL); | ||
185 | static DEVICE_ATTR(rs485, S_IRUGO, ts5500_show_rs485, NULL); | ||
186 | static DEVICE_ATTR(adc, S_IRUGO, ts5500_show_adc, NULL); | ||
187 | static DEVICE_ATTR(ereset, S_IRUGO, ts5500_show_ereset, NULL); | ||
188 | static DEVICE_ATTR(itr, S_IRUGO, ts5500_show_itr, NULL); | ||
189 | |||
190 | static struct attribute *ts5500_attributes[] = { | ||
191 | &dev_attr_id.attr, | ||
192 | &dev_attr_jumpers.attr, | ||
193 | &dev_attr_sram.attr, | ||
194 | &dev_attr_rs485.attr, | ||
195 | &dev_attr_adc.attr, | ||
196 | &dev_attr_ereset.attr, | ||
197 | &dev_attr_itr.attr, | ||
198 | NULL | ||
199 | }; | ||
200 | |||
201 | static const struct attribute_group ts5500_attr_group = { | ||
202 | .attrs = ts5500_attributes, | ||
203 | }; | ||
204 | |||
205 | static struct resource ts5500_dio1_resource[] = { | ||
206 | DEFINE_RES_IRQ_NAMED(7, "DIO1 interrupt"), | ||
207 | }; | ||
208 | |||
209 | static struct platform_device ts5500_dio1_pdev = { | ||
210 | .name = "ts5500-dio1", | ||
211 | .id = -1, | ||
212 | .resource = ts5500_dio1_resource, | ||
213 | .num_resources = 1, | ||
214 | }; | ||
215 | |||
216 | static struct resource ts5500_dio2_resource[] = { | ||
217 | DEFINE_RES_IRQ_NAMED(6, "DIO2 interrupt"), | ||
218 | }; | ||
219 | |||
220 | static struct platform_device ts5500_dio2_pdev = { | ||
221 | .name = "ts5500-dio2", | ||
222 | .id = -1, | ||
223 | .resource = ts5500_dio2_resource, | ||
224 | .num_resources = 1, | ||
225 | }; | ||
226 | |||
227 | static void ts5500_led_set(struct led_classdev *led_cdev, | ||
228 | enum led_brightness brightness) | ||
229 | { | ||
230 | outb(!!brightness, TS5500_LED_JP_ADDR); | ||
231 | } | ||
232 | |||
233 | static enum led_brightness ts5500_led_get(struct led_classdev *led_cdev) | ||
234 | { | ||
235 | return (inb(TS5500_LED_JP_ADDR) & TS5500_LED) ? LED_FULL : LED_OFF; | ||
236 | } | ||
237 | |||
238 | static struct led_classdev ts5500_led_cdev = { | ||
239 | .name = "ts5500:green:", | ||
240 | .brightness_set = ts5500_led_set, | ||
241 | .brightness_get = ts5500_led_get, | ||
242 | }; | ||
243 | |||
244 | static int ts5500_adc_convert(u8 ctrl) | ||
245 | { | ||
246 | u8 lsb, msb; | ||
247 | |||
248 | /* Start conversion (ensure the 3 MSB are set to 0) */ | ||
249 | outb(ctrl & 0x1f, TS5500_ADC_CONV_INIT_LSB_ADDR); | ||
250 | |||
251 | /* | ||
252 | * The platform has CPLD logic driving the A/D converter. | ||
253 | * The conversion must complete within 11 microseconds, | ||
254 | * otherwise we have to re-initiate a conversion. | ||
255 | */ | ||
256 | udelay(TS5500_ADC_CONV_DELAY); | ||
257 | if (inb(TS5500_ADC_CONV_BUSY_ADDR) & TS5500_ADC_CONV_BUSY) | ||
258 | return -EBUSY; | ||
259 | |||
260 | /* Read the raw data */ | ||
261 | lsb = inb(TS5500_ADC_CONV_INIT_LSB_ADDR); | ||
262 | msb = inb(TS5500_ADC_CONV_MSB_ADDR); | ||
263 | |||
264 | return (msb << 8) | lsb; | ||
265 | } | ||
266 | |||
267 | static struct max197_platform_data ts5500_adc_pdata = { | ||
268 | .convert = ts5500_adc_convert, | ||
269 | }; | ||
270 | |||
271 | static struct platform_device ts5500_adc_pdev = { | ||
272 | .name = "max197", | ||
273 | .id = -1, | ||
274 | .dev = { | ||
275 | .platform_data = &ts5500_adc_pdata, | ||
276 | }, | ||
277 | }; | ||
278 | |||
279 | static int __init ts5500_init(void) | ||
280 | { | ||
281 | struct platform_device *pdev; | ||
282 | struct ts5500_sbc *sbc; | ||
283 | int err; | ||
284 | |||
285 | /* | ||
286 | * There is no DMI available or PCI bridge subvendor info, | ||
287 | * only the BIOS provides a 16-bit identification call. | ||
288 | * It is safer to find a signature in the BIOS shadow RAM. | ||
289 | */ | ||
290 | err = ts5500_check_signature(); | ||
291 | if (err) | ||
292 | return err; | ||
293 | |||
294 | pdev = platform_device_register_simple("ts5500", -1, NULL, 0); | ||
295 | if (IS_ERR(pdev)) | ||
296 | return PTR_ERR(pdev); | ||
297 | |||
298 | sbc = devm_kzalloc(&pdev->dev, sizeof(struct ts5500_sbc), GFP_KERNEL); | ||
299 | if (!sbc) { | ||
300 | err = -ENOMEM; | ||
301 | goto error; | ||
302 | } | ||
303 | |||
304 | err = ts5500_detect_config(sbc); | ||
305 | if (err) | ||
306 | goto error; | ||
307 | |||
308 | platform_set_drvdata(pdev, sbc); | ||
309 | |||
310 | err = sysfs_create_group(&pdev->dev.kobj, &ts5500_attr_group); | ||
311 | if (err) | ||
312 | goto error; | ||
313 | |||
314 | ts5500_dio1_pdev.dev.parent = &pdev->dev; | ||
315 | if (platform_device_register(&ts5500_dio1_pdev)) | ||
316 | dev_warn(&pdev->dev, "DIO1 block registration failed\n"); | ||
317 | ts5500_dio2_pdev.dev.parent = &pdev->dev; | ||
318 | if (platform_device_register(&ts5500_dio2_pdev)) | ||
319 | dev_warn(&pdev->dev, "DIO2 block registration failed\n"); | ||
320 | |||
321 | if (led_classdev_register(&pdev->dev, &ts5500_led_cdev)) | ||
322 | dev_warn(&pdev->dev, "LED registration failed\n"); | ||
323 | |||
324 | if (sbc->adc) { | ||
325 | ts5500_adc_pdev.dev.parent = &pdev->dev; | ||
326 | if (platform_device_register(&ts5500_adc_pdev)) | ||
327 | dev_warn(&pdev->dev, "ADC registration failed\n"); | ||
328 | } | ||
329 | |||
330 | return 0; | ||
331 | error: | ||
332 | platform_device_unregister(pdev); | ||
333 | return err; | ||
334 | } | ||
335 | device_initcall(ts5500_init); | ||
336 | |||
337 | MODULE_LICENSE("GPL"); | ||
338 | MODULE_AUTHOR("Savoir-faire Linux Inc. <kernel@savoirfairelinux.com>"); | ||
339 | MODULE_DESCRIPTION("Technologic Systems TS-5500 platform driver"); | ||
diff --git a/arch/x86/platform/uv/tlb_uv.c b/arch/x86/platform/uv/tlb_uv.c index dbbdca5f508c..0f92173a12b6 100644 --- a/arch/x86/platform/uv/tlb_uv.c +++ b/arch/x86/platform/uv/tlb_uv.c | |||
@@ -1467,7 +1467,7 @@ static ssize_t ptc_proc_write(struct file *file, const char __user *user, | |||
1467 | } | 1467 | } |
1468 | 1468 | ||
1469 | if (input_arg == 0) { | 1469 | if (input_arg == 0) { |
1470 | elements = sizeof(stat_description)/sizeof(*stat_description); | 1470 | elements = ARRAY_SIZE(stat_description); |
1471 | printk(KERN_DEBUG "# cpu: cpu number\n"); | 1471 | printk(KERN_DEBUG "# cpu: cpu number\n"); |
1472 | printk(KERN_DEBUG "Sender statistics:\n"); | 1472 | printk(KERN_DEBUG "Sender statistics:\n"); |
1473 | for (i = 0; i < elements; i++) | 1473 | for (i = 0; i < elements; i++) |
@@ -1508,7 +1508,7 @@ static int parse_tunables_write(struct bau_control *bcp, char *instr, | |||
1508 | char *q; | 1508 | char *q; |
1509 | int cnt = 0; | 1509 | int cnt = 0; |
1510 | int val; | 1510 | int val; |
1511 | int e = sizeof(tunables) / sizeof(*tunables); | 1511 | int e = ARRAY_SIZE(tunables); |
1512 | 1512 | ||
1513 | p = instr + strspn(instr, WHITESPACE); | 1513 | p = instr + strspn(instr, WHITESPACE); |
1514 | q = p; | 1514 | q = p; |
diff --git a/arch/x86/um/fault.c b/arch/x86/um/fault.c index 8784ab30d91b..84ac7f7b0257 100644 --- a/arch/x86/um/fault.c +++ b/arch/x86/um/fault.c | |||
@@ -20,7 +20,7 @@ int arch_fixup(unsigned long address, struct uml_pt_regs *regs) | |||
20 | const struct exception_table_entry *fixup; | 20 | const struct exception_table_entry *fixup; |
21 | 21 | ||
22 | fixup = search_exception_tables(address); | 22 | fixup = search_exception_tables(address); |
23 | if (fixup != 0) { | 23 | if (fixup) { |
24 | UPT_IP(regs) = fixup->fixup; | 24 | UPT_IP(regs) = fixup->fixup; |
25 | return 1; | 25 | return 1; |
26 | } | 26 | } |
diff --git a/arch/x86/vdso/vclock_gettime.c b/arch/x86/vdso/vclock_gettime.c index 205ad328aa52..c74436e687bf 100644 --- a/arch/x86/vdso/vclock_gettime.c +++ b/arch/x86/vdso/vclock_gettime.c | |||
@@ -60,7 +60,7 @@ notrace static cycle_t vread_tsc(void) | |||
60 | 60 | ||
61 | static notrace cycle_t vread_hpet(void) | 61 | static notrace cycle_t vread_hpet(void) |
62 | { | 62 | { |
63 | return readl((const void __iomem *)fix_to_virt(VSYSCALL_HPET) + 0xf0); | 63 | return readl((const void __iomem *)fix_to_virt(VSYSCALL_HPET) + HPET_COUNTER); |
64 | } | 64 | } |
65 | 65 | ||
66 | #ifdef CONFIG_PARAVIRT_CLOCK | 66 | #ifdef CONFIG_PARAVIRT_CLOCK |
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 138e5667409a..39928d16be3b 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c | |||
@@ -1517,72 +1517,51 @@ asmlinkage void __init xen_start_kernel(void) | |||
1517 | #endif | 1517 | #endif |
1518 | } | 1518 | } |
1519 | 1519 | ||
1520 | #ifdef CONFIG_XEN_PVHVM | 1520 | void __ref xen_hvm_init_shared_info(void) |
1521 | #define HVM_SHARED_INFO_ADDR 0xFE700000UL | ||
1522 | static struct shared_info *xen_hvm_shared_info; | ||
1523 | static unsigned long xen_hvm_sip_phys; | ||
1524 | static int xen_major, xen_minor; | ||
1525 | |||
1526 | static void xen_hvm_connect_shared_info(unsigned long pfn) | ||
1527 | { | 1521 | { |
1522 | int cpu; | ||
1528 | struct xen_add_to_physmap xatp; | 1523 | struct xen_add_to_physmap xatp; |
1524 | static struct shared_info *shared_info_page = 0; | ||
1529 | 1525 | ||
1526 | if (!shared_info_page) | ||
1527 | shared_info_page = (struct shared_info *) | ||
1528 | extend_brk(PAGE_SIZE, PAGE_SIZE); | ||
1530 | xatp.domid = DOMID_SELF; | 1529 | xatp.domid = DOMID_SELF; |
1531 | xatp.idx = 0; | 1530 | xatp.idx = 0; |
1532 | xatp.space = XENMAPSPACE_shared_info; | 1531 | xatp.space = XENMAPSPACE_shared_info; |
1533 | xatp.gpfn = pfn; | 1532 | xatp.gpfn = __pa(shared_info_page) >> PAGE_SHIFT; |
1534 | if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp)) | 1533 | if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp)) |
1535 | BUG(); | 1534 | BUG(); |
1536 | 1535 | ||
1537 | } | 1536 | HYPERVISOR_shared_info = (struct shared_info *)shared_info_page; |
1538 | static void __init xen_hvm_set_shared_info(struct shared_info *sip) | ||
1539 | { | ||
1540 | int cpu; | ||
1541 | |||
1542 | HYPERVISOR_shared_info = sip; | ||
1543 | 1537 | ||
1544 | /* xen_vcpu is a pointer to the vcpu_info struct in the shared_info | 1538 | /* xen_vcpu is a pointer to the vcpu_info struct in the shared_info |
1545 | * page, we use it in the event channel upcall and in some pvclock | 1539 | * page, we use it in the event channel upcall and in some pvclock |
1546 | * related functions. We don't need the vcpu_info placement | 1540 | * related functions. We don't need the vcpu_info placement |
1547 | * optimizations because we don't use any pv_mmu or pv_irq op on | 1541 | * optimizations because we don't use any pv_mmu or pv_irq op on |
1548 | * HVM. */ | 1542 | * HVM. |
1549 | for_each_online_cpu(cpu) | 1543 | * When xen_hvm_init_shared_info is run at boot time only vcpu 0 is |
1544 | * online but xen_hvm_init_shared_info is run at resume time too and | ||
1545 | * in that case multiple vcpus might be online. */ | ||
1546 | for_each_online_cpu(cpu) { | ||
1550 | per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu]; | 1547 | per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu]; |
1551 | } | ||
1552 | |||
1553 | /* Reconnect the shared_info pfn to a (new) mfn */ | ||
1554 | void xen_hvm_resume_shared_info(void) | ||
1555 | { | ||
1556 | xen_hvm_connect_shared_info(xen_hvm_sip_phys >> PAGE_SHIFT); | ||
1557 | } | ||
1558 | |||
1559 | /* Xen tools prior to Xen 4 do not provide a E820_Reserved area for guest usage. | ||
1560 | * On these old tools the shared info page will be placed in E820_Ram. | ||
1561 | * Xen 4 provides a E820_Reserved area at 0xFC000000, and this code expects | ||
1562 | * that nothing is mapped up to HVM_SHARED_INFO_ADDR. | ||
1563 | * Xen 4.3+ provides an explicit 1MB area at HVM_SHARED_INFO_ADDR which is used | ||
1564 | * here for the shared info page. */ | ||
1565 | static void __init xen_hvm_init_shared_info(void) | ||
1566 | { | ||
1567 | if (xen_major < 4) { | ||
1568 | xen_hvm_shared_info = extend_brk(PAGE_SIZE, PAGE_SIZE); | ||
1569 | xen_hvm_sip_phys = __pa(xen_hvm_shared_info); | ||
1570 | } else { | ||
1571 | xen_hvm_sip_phys = HVM_SHARED_INFO_ADDR; | ||
1572 | set_fixmap(FIX_PARAVIRT_BOOTMAP, xen_hvm_sip_phys); | ||
1573 | xen_hvm_shared_info = | ||
1574 | (struct shared_info *)fix_to_virt(FIX_PARAVIRT_BOOTMAP); | ||
1575 | } | 1548 | } |
1576 | xen_hvm_connect_shared_info(xen_hvm_sip_phys >> PAGE_SHIFT); | ||
1577 | xen_hvm_set_shared_info(xen_hvm_shared_info); | ||
1578 | } | 1549 | } |
1579 | 1550 | ||
1551 | #ifdef CONFIG_XEN_PVHVM | ||
1580 | static void __init init_hvm_pv_info(void) | 1552 | static void __init init_hvm_pv_info(void) |
1581 | { | 1553 | { |
1582 | uint32_t ecx, edx, pages, msr, base; | 1554 | int major, minor; |
1555 | uint32_t eax, ebx, ecx, edx, pages, msr, base; | ||
1583 | u64 pfn; | 1556 | u64 pfn; |
1584 | 1557 | ||
1585 | base = xen_cpuid_base(); | 1558 | base = xen_cpuid_base(); |
1559 | cpuid(base + 1, &eax, &ebx, &ecx, &edx); | ||
1560 | |||
1561 | major = eax >> 16; | ||
1562 | minor = eax & 0xffff; | ||
1563 | printk(KERN_INFO "Xen version %d.%d.\n", major, minor); | ||
1564 | |||
1586 | cpuid(base + 2, &pages, &msr, &ecx, &edx); | 1565 | cpuid(base + 2, &pages, &msr, &ecx, &edx); |
1587 | 1566 | ||
1588 | pfn = __pa(hypercall_page); | 1567 | pfn = __pa(hypercall_page); |
@@ -1633,22 +1612,12 @@ static void __init xen_hvm_guest_init(void) | |||
1633 | 1612 | ||
1634 | static bool __init xen_hvm_platform(void) | 1613 | static bool __init xen_hvm_platform(void) |
1635 | { | 1614 | { |
1636 | uint32_t eax, ebx, ecx, edx, base; | ||
1637 | |||
1638 | if (xen_pv_domain()) | 1615 | if (xen_pv_domain()) |
1639 | return false; | 1616 | return false; |
1640 | 1617 | ||
1641 | base = xen_cpuid_base(); | 1618 | if (!xen_cpuid_base()) |
1642 | if (!base) | ||
1643 | return false; | 1619 | return false; |
1644 | 1620 | ||
1645 | cpuid(base + 1, &eax, &ebx, &ecx, &edx); | ||
1646 | |||
1647 | xen_major = eax >> 16; | ||
1648 | xen_minor = eax & 0xffff; | ||
1649 | |||
1650 | printk(KERN_INFO "Xen version %d.%d.\n", xen_major, xen_minor); | ||
1651 | |||
1652 | return true; | 1621 | return true; |
1653 | } | 1622 | } |
1654 | 1623 | ||
@@ -1668,6 +1637,7 @@ const struct hypervisor_x86 x86_hyper_xen_hvm __refconst = { | |||
1668 | .name = "Xen HVM", | 1637 | .name = "Xen HVM", |
1669 | .detect = xen_hvm_platform, | 1638 | .detect = xen_hvm_platform, |
1670 | .init_platform = xen_hvm_guest_init, | 1639 | .init_platform = xen_hvm_guest_init, |
1640 | .x2apic_available = xen_x2apic_para_available, | ||
1671 | }; | 1641 | }; |
1672 | EXPORT_SYMBOL(x86_hyper_xen_hvm); | 1642 | EXPORT_SYMBOL(x86_hyper_xen_hvm); |
1673 | #endif | 1643 | #endif |
diff --git a/arch/x86/xen/suspend.c b/arch/x86/xen/suspend.c index ae8a00c39de4..45329c8c226e 100644 --- a/arch/x86/xen/suspend.c +++ b/arch/x86/xen/suspend.c | |||
@@ -30,7 +30,7 @@ void xen_arch_hvm_post_suspend(int suspend_cancelled) | |||
30 | { | 30 | { |
31 | #ifdef CONFIG_XEN_PVHVM | 31 | #ifdef CONFIG_XEN_PVHVM |
32 | int cpu; | 32 | int cpu; |
33 | xen_hvm_resume_shared_info(); | 33 | xen_hvm_init_shared_info(); |
34 | xen_callback_vector(); | 34 | xen_callback_vector(); |
35 | xen_unplug_emulated_devices(); | 35 | xen_unplug_emulated_devices(); |
36 | if (xen_feature(XENFEAT_hvm_safe_pvclock)) { | 36 | if (xen_feature(XENFEAT_hvm_safe_pvclock)) { |
diff --git a/arch/x86/xen/xen-asm_32.S b/arch/x86/xen/xen-asm_32.S index f9643fc50de5..33ca6e42a4ca 100644 --- a/arch/x86/xen/xen-asm_32.S +++ b/arch/x86/xen/xen-asm_32.S | |||
@@ -89,11 +89,11 @@ ENTRY(xen_iret) | |||
89 | */ | 89 | */ |
90 | #ifdef CONFIG_SMP | 90 | #ifdef CONFIG_SMP |
91 | GET_THREAD_INFO(%eax) | 91 | GET_THREAD_INFO(%eax) |
92 | movl TI_cpu(%eax), %eax | 92 | movl %ss:TI_cpu(%eax), %eax |
93 | movl __per_cpu_offset(,%eax,4), %eax | 93 | movl %ss:__per_cpu_offset(,%eax,4), %eax |
94 | mov xen_vcpu(%eax), %eax | 94 | mov %ss:xen_vcpu(%eax), %eax |
95 | #else | 95 | #else |
96 | movl xen_vcpu, %eax | 96 | movl %ss:xen_vcpu, %eax |
97 | #endif | 97 | #endif |
98 | 98 | ||
99 | /* check IF state we're restoring */ | 99 | /* check IF state we're restoring */ |
@@ -106,11 +106,11 @@ ENTRY(xen_iret) | |||
106 | * resuming the code, so we don't have to be worried about | 106 | * resuming the code, so we don't have to be worried about |
107 | * being preempted to another CPU. | 107 | * being preempted to another CPU. |
108 | */ | 108 | */ |
109 | setz XEN_vcpu_info_mask(%eax) | 109 | setz %ss:XEN_vcpu_info_mask(%eax) |
110 | xen_iret_start_crit: | 110 | xen_iret_start_crit: |
111 | 111 | ||
112 | /* check for unmasked and pending */ | 112 | /* check for unmasked and pending */ |
113 | cmpw $0x0001, XEN_vcpu_info_pending(%eax) | 113 | cmpw $0x0001, %ss:XEN_vcpu_info_pending(%eax) |
114 | 114 | ||
115 | /* | 115 | /* |
116 | * If there's something pending, mask events again so we can | 116 | * If there's something pending, mask events again so we can |
@@ -118,7 +118,7 @@ xen_iret_start_crit: | |||
118 | * touch XEN_vcpu_info_mask. | 118 | * touch XEN_vcpu_info_mask. |
119 | */ | 119 | */ |
120 | jne 1f | 120 | jne 1f |
121 | movb $1, XEN_vcpu_info_mask(%eax) | 121 | movb $1, %ss:XEN_vcpu_info_mask(%eax) |
122 | 122 | ||
123 | 1: popl %eax | 123 | 1: popl %eax |
124 | 124 | ||
diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h index d2e73d19d366..a95b41744ad0 100644 --- a/arch/x86/xen/xen-ops.h +++ b/arch/x86/xen/xen-ops.h | |||
@@ -40,7 +40,7 @@ void xen_enable_syscall(void); | |||
40 | void xen_vcpu_restore(void); | 40 | void xen_vcpu_restore(void); |
41 | 41 | ||
42 | void xen_callback_vector(void); | 42 | void xen_callback_vector(void); |
43 | void xen_hvm_resume_shared_info(void); | 43 | void xen_hvm_init_shared_info(void); |
44 | void xen_unplug_emulated_devices(void); | 44 | void xen_unplug_emulated_devices(void); |
45 | 45 | ||
46 | void __init xen_build_dynamic_phys_to_machine(void); | 46 | void __init xen_build_dynamic_phys_to_machine(void); |
diff --git a/block/blk-exec.c b/block/blk-exec.c index 74638ec234c8..c88202f973d9 100644 --- a/block/blk-exec.c +++ b/block/blk-exec.c | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <linux/module.h> | 5 | #include <linux/module.h> |
6 | #include <linux/bio.h> | 6 | #include <linux/bio.h> |
7 | #include <linux/blkdev.h> | 7 | #include <linux/blkdev.h> |
8 | #include <linux/sched/sysctl.h> | ||
8 | 9 | ||
9 | #include "blk.h" | 10 | #include "blk.h" |
10 | 11 | ||
diff --git a/drivers/acpi/apei/cper.c b/drivers/acpi/apei/cper.c index e6defd86b424..1e5d8a40101e 100644 --- a/drivers/acpi/apei/cper.c +++ b/drivers/acpi/apei/cper.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/time.h> | 29 | #include <linux/time.h> |
30 | #include <linux/cper.h> | 30 | #include <linux/cper.h> |
31 | #include <linux/acpi.h> | 31 | #include <linux/acpi.h> |
32 | #include <linux/pci.h> | ||
32 | #include <linux/aer.h> | 33 | #include <linux/aer.h> |
33 | 34 | ||
34 | /* | 35 | /* |
@@ -249,6 +250,10 @@ static const char *cper_pcie_port_type_strs[] = { | |||
249 | static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie, | 250 | static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie, |
250 | const struct acpi_hest_generic_data *gdata) | 251 | const struct acpi_hest_generic_data *gdata) |
251 | { | 252 | { |
253 | #ifdef CONFIG_ACPI_APEI_PCIEAER | ||
254 | struct pci_dev *dev; | ||
255 | #endif | ||
256 | |||
252 | if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE) | 257 | if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE) |
253 | printk("%s""port_type: %d, %s\n", pfx, pcie->port_type, | 258 | printk("%s""port_type: %d, %s\n", pfx, pcie->port_type, |
254 | pcie->port_type < ARRAY_SIZE(cper_pcie_port_type_strs) ? | 259 | pcie->port_type < ARRAY_SIZE(cper_pcie_port_type_strs) ? |
@@ -281,10 +286,18 @@ static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie, | |||
281 | "%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n", | 286 | "%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n", |
282 | pfx, pcie->bridge.secondary_status, pcie->bridge.control); | 287 | pfx, pcie->bridge.secondary_status, pcie->bridge.control); |
283 | #ifdef CONFIG_ACPI_APEI_PCIEAER | 288 | #ifdef CONFIG_ACPI_APEI_PCIEAER |
284 | if (pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) { | 289 | dev = pci_get_domain_bus_and_slot(pcie->device_id.segment, |
285 | struct aer_capability_regs *aer_regs = (void *)pcie->aer_info; | 290 | pcie->device_id.bus, pcie->device_id.function); |
286 | cper_print_aer(pfx, gdata->error_severity, aer_regs); | 291 | if (!dev) { |
292 | pr_err("PCI AER Cannot get PCI device %04x:%02x:%02x.%d\n", | ||
293 | pcie->device_id.segment, pcie->device_id.bus, | ||
294 | pcie->device_id.slot, pcie->device_id.function); | ||
295 | return; | ||
287 | } | 296 | } |
297 | if (pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) | ||
298 | cper_print_aer(pfx, dev, gdata->error_severity, | ||
299 | (struct aer_capability_regs *) pcie->aer_info); | ||
300 | pci_dev_put(dev); | ||
288 | #endif | 301 | #endif |
289 | } | 302 | } |
290 | 303 | ||
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 497912732566..495aeed26779 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c | |||
@@ -1061,6 +1061,86 @@ static inline void ahci_gtf_filter_workaround(struct ata_host *host) | |||
1061 | {} | 1061 | {} |
1062 | #endif | 1062 | #endif |
1063 | 1063 | ||
1064 | int ahci_init_interrupts(struct pci_dev *pdev, struct ahci_host_priv *hpriv) | ||
1065 | { | ||
1066 | int rc; | ||
1067 | unsigned int maxvec; | ||
1068 | |||
1069 | if (!(hpriv->flags & AHCI_HFLAG_NO_MSI)) { | ||
1070 | rc = pci_enable_msi_block_auto(pdev, &maxvec); | ||
1071 | if (rc > 0) { | ||
1072 | if ((rc == maxvec) || (rc == 1)) | ||
1073 | return rc; | ||
1074 | /* | ||
1075 | * Assume that advantage of multipe MSIs is negated, | ||
1076 | * so fallback to single MSI mode to save resources | ||
1077 | */ | ||
1078 | pci_disable_msi(pdev); | ||
1079 | if (!pci_enable_msi(pdev)) | ||
1080 | return 1; | ||
1081 | } | ||
1082 | } | ||
1083 | |||
1084 | pci_intx(pdev, 1); | ||
1085 | return 0; | ||
1086 | } | ||
1087 | |||
1088 | /** | ||
1089 | * ahci_host_activate - start AHCI host, request IRQs and register it | ||
1090 | * @host: target ATA host | ||
1091 | * @irq: base IRQ number to request | ||
1092 | * @n_msis: number of MSIs allocated for this host | ||
1093 | * @irq_handler: irq_handler used when requesting IRQs | ||
1094 | * @irq_flags: irq_flags used when requesting IRQs | ||
1095 | * | ||
1096 | * Similar to ata_host_activate, but requests IRQs according to AHCI-1.1 | ||
1097 | * when multiple MSIs were allocated. That is one MSI per port, starting | ||
1098 | * from @irq. | ||
1099 | * | ||
1100 | * LOCKING: | ||
1101 | * Inherited from calling layer (may sleep). | ||
1102 | * | ||
1103 | * RETURNS: | ||
1104 | * 0 on success, -errno otherwise. | ||
1105 | */ | ||
1106 | int ahci_host_activate(struct ata_host *host, int irq, unsigned int n_msis) | ||
1107 | { | ||
1108 | int i, rc; | ||
1109 | |||
1110 | /* Sharing Last Message among several ports is not supported */ | ||
1111 | if (n_msis < host->n_ports) | ||
1112 | return -EINVAL; | ||
1113 | |||
1114 | rc = ata_host_start(host); | ||
1115 | if (rc) | ||
1116 | return rc; | ||
1117 | |||
1118 | for (i = 0; i < host->n_ports; i++) { | ||
1119 | rc = devm_request_threaded_irq(host->dev, | ||
1120 | irq + i, ahci_hw_interrupt, ahci_thread_fn, IRQF_SHARED, | ||
1121 | dev_driver_string(host->dev), host->ports[i]); | ||
1122 | if (rc) | ||
1123 | goto out_free_irqs; | ||
1124 | } | ||
1125 | |||
1126 | for (i = 0; i < host->n_ports; i++) | ||
1127 | ata_port_desc(host->ports[i], "irq %d", irq + i); | ||
1128 | |||
1129 | rc = ata_host_register(host, &ahci_sht); | ||
1130 | if (rc) | ||
1131 | goto out_free_all_irqs; | ||
1132 | |||
1133 | return 0; | ||
1134 | |||
1135 | out_free_all_irqs: | ||
1136 | i = host->n_ports; | ||
1137 | out_free_irqs: | ||
1138 | for (i--; i >= 0; i--) | ||
1139 | devm_free_irq(host->dev, irq + i, host->ports[i]); | ||
1140 | |||
1141 | return rc; | ||
1142 | } | ||
1143 | |||
1064 | static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | 1144 | static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) |
1065 | { | 1145 | { |
1066 | unsigned int board_id = ent->driver_data; | 1146 | unsigned int board_id = ent->driver_data; |
@@ -1069,7 +1149,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1069 | struct device *dev = &pdev->dev; | 1149 | struct device *dev = &pdev->dev; |
1070 | struct ahci_host_priv *hpriv; | 1150 | struct ahci_host_priv *hpriv; |
1071 | struct ata_host *host; | 1151 | struct ata_host *host; |
1072 | int n_ports, i, rc; | 1152 | int n_ports, n_msis, i, rc; |
1073 | int ahci_pci_bar = AHCI_PCI_BAR_STANDARD; | 1153 | int ahci_pci_bar = AHCI_PCI_BAR_STANDARD; |
1074 | 1154 | ||
1075 | VPRINTK("ENTER\n"); | 1155 | VPRINTK("ENTER\n"); |
@@ -1156,11 +1236,12 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1156 | if (ahci_sb600_enable_64bit(pdev)) | 1236 | if (ahci_sb600_enable_64bit(pdev)) |
1157 | hpriv->flags &= ~AHCI_HFLAG_32BIT_ONLY; | 1237 | hpriv->flags &= ~AHCI_HFLAG_32BIT_ONLY; |
1158 | 1238 | ||
1159 | if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev)) | ||
1160 | pci_intx(pdev, 1); | ||
1161 | |||
1162 | hpriv->mmio = pcim_iomap_table(pdev)[ahci_pci_bar]; | 1239 | hpriv->mmio = pcim_iomap_table(pdev)[ahci_pci_bar]; |
1163 | 1240 | ||
1241 | n_msis = ahci_init_interrupts(pdev, hpriv); | ||
1242 | if (n_msis > 1) | ||
1243 | hpriv->flags |= AHCI_HFLAG_MULTI_MSI; | ||
1244 | |||
1164 | /* save initial config */ | 1245 | /* save initial config */ |
1165 | ahci_pci_save_initial_config(pdev, hpriv); | 1246 | ahci_pci_save_initial_config(pdev, hpriv); |
1166 | 1247 | ||
@@ -1256,6 +1337,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1256 | ahci_pci_print_info(host); | 1337 | ahci_pci_print_info(host); |
1257 | 1338 | ||
1258 | pci_set_master(pdev); | 1339 | pci_set_master(pdev); |
1340 | |||
1341 | if (hpriv->flags & AHCI_HFLAG_MULTI_MSI) | ||
1342 | return ahci_host_activate(host, pdev->irq, n_msis); | ||
1343 | |||
1259 | return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED, | 1344 | return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED, |
1260 | &ahci_sht); | 1345 | &ahci_sht); |
1261 | } | 1346 | } |
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 9be471200a07..b830e6c9fe49 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h | |||
@@ -231,6 +231,7 @@ enum { | |||
231 | AHCI_HFLAG_DELAY_ENGINE = (1 << 15), /* do not start engine on | 231 | AHCI_HFLAG_DELAY_ENGINE = (1 << 15), /* do not start engine on |
232 | port start (wait until | 232 | port start (wait until |
233 | error-handling stage) */ | 233 | error-handling stage) */ |
234 | AHCI_HFLAG_MULTI_MSI = (1 << 16), /* multiple PCI MSIs */ | ||
234 | 235 | ||
235 | /* ap->flags bits */ | 236 | /* ap->flags bits */ |
236 | 237 | ||
@@ -297,6 +298,8 @@ struct ahci_port_priv { | |||
297 | unsigned int ncq_saw_d2h:1; | 298 | unsigned int ncq_saw_d2h:1; |
298 | unsigned int ncq_saw_dmas:1; | 299 | unsigned int ncq_saw_dmas:1; |
299 | unsigned int ncq_saw_sdb:1; | 300 | unsigned int ncq_saw_sdb:1; |
301 | u32 intr_status; /* interrupts to handle */ | ||
302 | spinlock_t lock; /* protects parent ata_port */ | ||
300 | u32 intr_mask; /* interrupts to enable */ | 303 | u32 intr_mask; /* interrupts to enable */ |
301 | bool fbs_supported; /* set iff FBS is supported */ | 304 | bool fbs_supported; /* set iff FBS is supported */ |
302 | bool fbs_enabled; /* set iff FBS is enabled */ | 305 | bool fbs_enabled; /* set iff FBS is enabled */ |
@@ -359,7 +362,10 @@ void ahci_set_em_messages(struct ahci_host_priv *hpriv, | |||
359 | struct ata_port_info *pi); | 362 | struct ata_port_info *pi); |
360 | int ahci_reset_em(struct ata_host *host); | 363 | int ahci_reset_em(struct ata_host *host); |
361 | irqreturn_t ahci_interrupt(int irq, void *dev_instance); | 364 | irqreturn_t ahci_interrupt(int irq, void *dev_instance); |
365 | irqreturn_t ahci_hw_interrupt(int irq, void *dev_instance); | ||
366 | irqreturn_t ahci_thread_fn(int irq, void *dev_instance); | ||
362 | void ahci_print_info(struct ata_host *host, const char *scc_s); | 367 | void ahci_print_info(struct ata_host *host, const char *scc_s); |
368 | int ahci_host_activate(struct ata_host *host, int irq, unsigned int n_msis); | ||
363 | 369 | ||
364 | static inline void __iomem *__ahci_port_base(struct ata_host *host, | 370 | static inline void __iomem *__ahci_port_base(struct ata_host *host, |
365 | unsigned int port_no) | 371 | unsigned int port_no) |
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 6cd7805e47ca..34c82167b962 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c | |||
@@ -1655,19 +1655,16 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) | |||
1655 | ata_port_abort(ap); | 1655 | ata_port_abort(ap); |
1656 | } | 1656 | } |
1657 | 1657 | ||
1658 | static void ahci_port_intr(struct ata_port *ap) | 1658 | static void ahci_handle_port_interrupt(struct ata_port *ap, |
1659 | void __iomem *port_mmio, u32 status) | ||
1659 | { | 1660 | { |
1660 | void __iomem *port_mmio = ahci_port_base(ap); | ||
1661 | struct ata_eh_info *ehi = &ap->link.eh_info; | 1661 | struct ata_eh_info *ehi = &ap->link.eh_info; |
1662 | struct ahci_port_priv *pp = ap->private_data; | 1662 | struct ahci_port_priv *pp = ap->private_data; |
1663 | struct ahci_host_priv *hpriv = ap->host->private_data; | 1663 | struct ahci_host_priv *hpriv = ap->host->private_data; |
1664 | int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING); | 1664 | int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING); |
1665 | u32 status, qc_active = 0; | 1665 | u32 qc_active = 0; |
1666 | int rc; | 1666 | int rc; |
1667 | 1667 | ||
1668 | status = readl(port_mmio + PORT_IRQ_STAT); | ||
1669 | writel(status, port_mmio + PORT_IRQ_STAT); | ||
1670 | |||
1671 | /* ignore BAD_PMP while resetting */ | 1668 | /* ignore BAD_PMP while resetting */ |
1672 | if (unlikely(resetting)) | 1669 | if (unlikely(resetting)) |
1673 | status &= ~PORT_IRQ_BAD_PMP; | 1670 | status &= ~PORT_IRQ_BAD_PMP; |
@@ -1743,6 +1740,107 @@ static void ahci_port_intr(struct ata_port *ap) | |||
1743 | } | 1740 | } |
1744 | } | 1741 | } |
1745 | 1742 | ||
1743 | void ahci_port_intr(struct ata_port *ap) | ||
1744 | { | ||
1745 | void __iomem *port_mmio = ahci_port_base(ap); | ||
1746 | u32 status; | ||
1747 | |||
1748 | status = readl(port_mmio + PORT_IRQ_STAT); | ||
1749 | writel(status, port_mmio + PORT_IRQ_STAT); | ||
1750 | |||
1751 | ahci_handle_port_interrupt(ap, port_mmio, status); | ||
1752 | } | ||
1753 | |||
1754 | irqreturn_t ahci_thread_fn(int irq, void *dev_instance) | ||
1755 | { | ||
1756 | struct ata_port *ap = dev_instance; | ||
1757 | struct ahci_port_priv *pp = ap->private_data; | ||
1758 | void __iomem *port_mmio = ahci_port_base(ap); | ||
1759 | unsigned long flags; | ||
1760 | u32 status; | ||
1761 | |||
1762 | spin_lock_irqsave(&ap->host->lock, flags); | ||
1763 | status = pp->intr_status; | ||
1764 | if (status) | ||
1765 | pp->intr_status = 0; | ||
1766 | spin_unlock_irqrestore(&ap->host->lock, flags); | ||
1767 | |||
1768 | spin_lock_bh(ap->lock); | ||
1769 | ahci_handle_port_interrupt(ap, port_mmio, status); | ||
1770 | spin_unlock_bh(ap->lock); | ||
1771 | |||
1772 | return IRQ_HANDLED; | ||
1773 | } | ||
1774 | EXPORT_SYMBOL_GPL(ahci_thread_fn); | ||
1775 | |||
1776 | void ahci_hw_port_interrupt(struct ata_port *ap) | ||
1777 | { | ||
1778 | void __iomem *port_mmio = ahci_port_base(ap); | ||
1779 | struct ahci_port_priv *pp = ap->private_data; | ||
1780 | u32 status; | ||
1781 | |||
1782 | status = readl(port_mmio + PORT_IRQ_STAT); | ||
1783 | writel(status, port_mmio + PORT_IRQ_STAT); | ||
1784 | |||
1785 | pp->intr_status |= status; | ||
1786 | } | ||
1787 | |||
1788 | irqreturn_t ahci_hw_interrupt(int irq, void *dev_instance) | ||
1789 | { | ||
1790 | struct ata_port *ap_this = dev_instance; | ||
1791 | struct ahci_port_priv *pp = ap_this->private_data; | ||
1792 | struct ata_host *host = ap_this->host; | ||
1793 | struct ahci_host_priv *hpriv = host->private_data; | ||
1794 | void __iomem *mmio = hpriv->mmio; | ||
1795 | unsigned int i; | ||
1796 | u32 irq_stat, irq_masked; | ||
1797 | |||
1798 | VPRINTK("ENTER\n"); | ||
1799 | |||
1800 | spin_lock(&host->lock); | ||
1801 | |||
1802 | irq_stat = readl(mmio + HOST_IRQ_STAT); | ||
1803 | |||
1804 | if (!irq_stat) { | ||
1805 | u32 status = pp->intr_status; | ||
1806 | |||
1807 | spin_unlock(&host->lock); | ||
1808 | |||
1809 | VPRINTK("EXIT\n"); | ||
1810 | |||
1811 | return status ? IRQ_WAKE_THREAD : IRQ_NONE; | ||
1812 | } | ||
1813 | |||
1814 | irq_masked = irq_stat & hpriv->port_map; | ||
1815 | |||
1816 | for (i = 0; i < host->n_ports; i++) { | ||
1817 | struct ata_port *ap; | ||
1818 | |||
1819 | if (!(irq_masked & (1 << i))) | ||
1820 | continue; | ||
1821 | |||
1822 | ap = host->ports[i]; | ||
1823 | if (ap) { | ||
1824 | ahci_hw_port_interrupt(ap); | ||
1825 | VPRINTK("port %u\n", i); | ||
1826 | } else { | ||
1827 | VPRINTK("port %u (no irq)\n", i); | ||
1828 | if (ata_ratelimit()) | ||
1829 | dev_warn(host->dev, | ||
1830 | "interrupt on disabled port %u\n", i); | ||
1831 | } | ||
1832 | } | ||
1833 | |||
1834 | writel(irq_stat, mmio + HOST_IRQ_STAT); | ||
1835 | |||
1836 | spin_unlock(&host->lock); | ||
1837 | |||
1838 | VPRINTK("EXIT\n"); | ||
1839 | |||
1840 | return IRQ_WAKE_THREAD; | ||
1841 | } | ||
1842 | EXPORT_SYMBOL_GPL(ahci_hw_interrupt); | ||
1843 | |||
1746 | irqreturn_t ahci_interrupt(int irq, void *dev_instance) | 1844 | irqreturn_t ahci_interrupt(int irq, void *dev_instance) |
1747 | { | 1845 | { |
1748 | struct ata_host *host = dev_instance; | 1846 | struct ata_host *host = dev_instance; |
@@ -2196,6 +2294,14 @@ static int ahci_port_start(struct ata_port *ap) | |||
2196 | */ | 2294 | */ |
2197 | pp->intr_mask = DEF_PORT_IRQ; | 2295 | pp->intr_mask = DEF_PORT_IRQ; |
2198 | 2296 | ||
2297 | /* | ||
2298 | * Switch to per-port locking in case each port has its own MSI vector. | ||
2299 | */ | ||
2300 | if ((hpriv->flags & AHCI_HFLAG_MULTI_MSI)) { | ||
2301 | spin_lock_init(&pp->lock); | ||
2302 | ap->lock = &pp->lock; | ||
2303 | } | ||
2304 | |||
2199 | ap->private_data = pp; | 2305 | ap->private_data = pp; |
2200 | 2306 | ||
2201 | /* engage engines, captain */ | 2307 | /* engage engines, captain */ |
diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c index 564156a8e572..5814deb6963d 100644 --- a/drivers/block/sunvdc.c +++ b/drivers/block/sunvdc.c | |||
@@ -461,7 +461,7 @@ static int generic_request(struct vdc_port *port, u8 op, void *buf, int len) | |||
461 | int op_len, err; | 461 | int op_len, err; |
462 | void *req_buf; | 462 | void *req_buf; |
463 | 463 | ||
464 | if (!(((u64)1 << ((u64)op - 1)) & port->operations)) | 464 | if (!(((u64)1 << (u64)op) & port->operations)) |
465 | return -EOPNOTSUPP; | 465 | return -EOPNOTSUPP; |
466 | 466 | ||
467 | switch (op) { | 467 | switch (op) { |
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index ad8bf2aa629d..2d3f8825e8b8 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c | |||
@@ -31,7 +31,7 @@ static struct ecc_settings **ecc_stngs; | |||
31 | * | 31 | * |
32 | *FIXME: Produce a better mapping/linearisation. | 32 | *FIXME: Produce a better mapping/linearisation. |
33 | */ | 33 | */ |
34 | struct scrubrate { | 34 | static const struct scrubrate { |
35 | u32 scrubval; /* bit pattern for scrub rate */ | 35 | u32 scrubval; /* bit pattern for scrub rate */ |
36 | u32 bandwidth; /* bandwidth consumed (bytes/sec) */ | 36 | u32 bandwidth; /* bandwidth consumed (bytes/sec) */ |
37 | } scrubrates[] = { | 37 | } scrubrates[] = { |
@@ -239,7 +239,7 @@ static int amd64_get_scrub_rate(struct mem_ctl_info *mci) | |||
239 | * DRAM base/limit associated with node_id | 239 | * DRAM base/limit associated with node_id |
240 | */ | 240 | */ |
241 | static bool amd64_base_limit_match(struct amd64_pvt *pvt, u64 sys_addr, | 241 | static bool amd64_base_limit_match(struct amd64_pvt *pvt, u64 sys_addr, |
242 | unsigned nid) | 242 | u8 nid) |
243 | { | 243 | { |
244 | u64 addr; | 244 | u64 addr; |
245 | 245 | ||
@@ -265,7 +265,7 @@ static struct mem_ctl_info *find_mc_by_sys_addr(struct mem_ctl_info *mci, | |||
265 | u64 sys_addr) | 265 | u64 sys_addr) |
266 | { | 266 | { |
267 | struct amd64_pvt *pvt; | 267 | struct amd64_pvt *pvt; |
268 | unsigned node_id; | 268 | u8 node_id; |
269 | u32 intlv_en, bits; | 269 | u32 intlv_en, bits; |
270 | 270 | ||
271 | /* | 271 | /* |
@@ -939,7 +939,8 @@ static u64 get_error_address(struct mce *m) | |||
939 | struct amd64_pvt *pvt; | 939 | struct amd64_pvt *pvt; |
940 | u64 cc6_base, tmp_addr; | 940 | u64 cc6_base, tmp_addr; |
941 | u32 tmp; | 941 | u32 tmp; |
942 | u8 mce_nid, intlv_en; | 942 | u16 mce_nid; |
943 | u8 intlv_en; | ||
943 | 944 | ||
944 | if ((addr & GENMASK(24, 47)) >> 24 != 0x00fdf7) | 945 | if ((addr & GENMASK(24, 47)) >> 24 != 0x00fdf7) |
945 | return addr; | 946 | return addr; |
@@ -979,10 +980,29 @@ static u64 get_error_address(struct mce *m) | |||
979 | return addr; | 980 | return addr; |
980 | } | 981 | } |
981 | 982 | ||
983 | static struct pci_dev *pci_get_related_function(unsigned int vendor, | ||
984 | unsigned int device, | ||
985 | struct pci_dev *related) | ||
986 | { | ||
987 | struct pci_dev *dev = NULL; | ||
988 | |||
989 | while ((dev = pci_get_device(vendor, device, dev))) { | ||
990 | if (pci_domain_nr(dev->bus) == pci_domain_nr(related->bus) && | ||
991 | (dev->bus->number == related->bus->number) && | ||
992 | (PCI_SLOT(dev->devfn) == PCI_SLOT(related->devfn))) | ||
993 | break; | ||
994 | } | ||
995 | |||
996 | return dev; | ||
997 | } | ||
998 | |||
982 | static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range) | 999 | static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range) |
983 | { | 1000 | { |
1001 | struct amd_northbridge *nb; | ||
1002 | struct pci_dev *misc, *f1 = NULL; | ||
984 | struct cpuinfo_x86 *c = &boot_cpu_data; | 1003 | struct cpuinfo_x86 *c = &boot_cpu_data; |
985 | int off = range << 3; | 1004 | int off = range << 3; |
1005 | u32 llim; | ||
986 | 1006 | ||
987 | amd64_read_pci_cfg(pvt->F1, DRAM_BASE_LO + off, &pvt->ranges[range].base.lo); | 1007 | amd64_read_pci_cfg(pvt->F1, DRAM_BASE_LO + off, &pvt->ranges[range].base.lo); |
988 | amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_LO + off, &pvt->ranges[range].lim.lo); | 1008 | amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_LO + off, &pvt->ranges[range].lim.lo); |
@@ -996,30 +1016,32 @@ static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range) | |||
996 | amd64_read_pci_cfg(pvt->F1, DRAM_BASE_HI + off, &pvt->ranges[range].base.hi); | 1016 | amd64_read_pci_cfg(pvt->F1, DRAM_BASE_HI + off, &pvt->ranges[range].base.hi); |
997 | amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_HI + off, &pvt->ranges[range].lim.hi); | 1017 | amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_HI + off, &pvt->ranges[range].lim.hi); |
998 | 1018 | ||
999 | /* Factor in CC6 save area by reading dst node's limit reg */ | 1019 | /* F15h: factor in CC6 save area by reading dst node's limit reg */ |
1000 | if (c->x86 == 0x15) { | 1020 | if (c->x86 != 0x15) |
1001 | struct pci_dev *f1 = NULL; | 1021 | return; |
1002 | u8 nid = dram_dst_node(pvt, range); | ||
1003 | u32 llim; | ||
1004 | 1022 | ||
1005 | f1 = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0x18 + nid, 1)); | 1023 | nb = node_to_amd_nb(dram_dst_node(pvt, range)); |
1006 | if (WARN_ON(!f1)) | 1024 | if (WARN_ON(!nb)) |
1007 | return; | 1025 | return; |
1008 | 1026 | ||
1009 | amd64_read_pci_cfg(f1, DRAM_LOCAL_NODE_LIM, &llim); | 1027 | misc = nb->misc; |
1028 | f1 = pci_get_related_function(misc->vendor, PCI_DEVICE_ID_AMD_15H_NB_F1, misc); | ||
1029 | if (WARN_ON(!f1)) | ||
1030 | return; | ||
1010 | 1031 | ||
1011 | pvt->ranges[range].lim.lo &= GENMASK(0, 15); | 1032 | amd64_read_pci_cfg(f1, DRAM_LOCAL_NODE_LIM, &llim); |
1012 | 1033 | ||
1013 | /* {[39:27],111b} */ | 1034 | pvt->ranges[range].lim.lo &= GENMASK(0, 15); |
1014 | pvt->ranges[range].lim.lo |= ((llim & 0x1fff) << 3 | 0x7) << 16; | ||
1015 | 1035 | ||
1016 | pvt->ranges[range].lim.hi &= GENMASK(0, 7); | 1036 | /* {[39:27],111b} */ |
1037 | pvt->ranges[range].lim.lo |= ((llim & 0x1fff) << 3 | 0x7) << 16; | ||
1017 | 1038 | ||
1018 | /* [47:40] */ | 1039 | pvt->ranges[range].lim.hi &= GENMASK(0, 7); |
1019 | pvt->ranges[range].lim.hi |= llim >> 13; | ||
1020 | 1040 | ||
1021 | pci_dev_put(f1); | 1041 | /* [47:40] */ |
1022 | } | 1042 | pvt->ranges[range].lim.hi |= llim >> 13; |
1043 | |||
1044 | pci_dev_put(f1); | ||
1023 | } | 1045 | } |
1024 | 1046 | ||
1025 | static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr, | 1047 | static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr, |
@@ -1305,7 +1327,7 @@ static u8 f1x_determine_channel(struct amd64_pvt *pvt, u64 sys_addr, | |||
1305 | } | 1327 | } |
1306 | 1328 | ||
1307 | /* Convert the sys_addr to the normalized DCT address */ | 1329 | /* Convert the sys_addr to the normalized DCT address */ |
1308 | static u64 f1x_get_norm_dct_addr(struct amd64_pvt *pvt, unsigned range, | 1330 | static u64 f1x_get_norm_dct_addr(struct amd64_pvt *pvt, u8 range, |
1309 | u64 sys_addr, bool hi_rng, | 1331 | u64 sys_addr, bool hi_rng, |
1310 | u32 dct_sel_base_addr) | 1332 | u32 dct_sel_base_addr) |
1311 | { | 1333 | { |
@@ -1381,7 +1403,7 @@ static int f10_process_possible_spare(struct amd64_pvt *pvt, u8 dct, int csrow) | |||
1381 | * -EINVAL: NOT FOUND | 1403 | * -EINVAL: NOT FOUND |
1382 | * 0..csrow = Chip-Select Row | 1404 | * 0..csrow = Chip-Select Row |
1383 | */ | 1405 | */ |
1384 | static int f1x_lookup_addr_in_dct(u64 in_addr, u32 nid, u8 dct) | 1406 | static int f1x_lookup_addr_in_dct(u64 in_addr, u8 nid, u8 dct) |
1385 | { | 1407 | { |
1386 | struct mem_ctl_info *mci; | 1408 | struct mem_ctl_info *mci; |
1387 | struct amd64_pvt *pvt; | 1409 | struct amd64_pvt *pvt; |
@@ -1672,23 +1694,6 @@ static struct amd64_family_type amd64_family_types[] = { | |||
1672 | }, | 1694 | }, |
1673 | }; | 1695 | }; |
1674 | 1696 | ||
1675 | static struct pci_dev *pci_get_related_function(unsigned int vendor, | ||
1676 | unsigned int device, | ||
1677 | struct pci_dev *related) | ||
1678 | { | ||
1679 | struct pci_dev *dev = NULL; | ||
1680 | |||
1681 | dev = pci_get_device(vendor, device, dev); | ||
1682 | while (dev) { | ||
1683 | if ((dev->bus->number == related->bus->number) && | ||
1684 | (PCI_SLOT(dev->devfn) == PCI_SLOT(related->devfn))) | ||
1685 | break; | ||
1686 | dev = pci_get_device(vendor, device, dev); | ||
1687 | } | ||
1688 | |||
1689 | return dev; | ||
1690 | } | ||
1691 | |||
1692 | /* | 1697 | /* |
1693 | * These are tables of eigenvectors (one per line) which can be used for the | 1698 | * These are tables of eigenvectors (one per line) which can be used for the |
1694 | * construction of the syndrome tables. The modified syndrome search algorithm | 1699 | * construction of the syndrome tables. The modified syndrome search algorithm |
@@ -1696,7 +1701,7 @@ static struct pci_dev *pci_get_related_function(unsigned int vendor, | |||
1696 | * | 1701 | * |
1697 | * Algorithm courtesy of Ross LaFetra from AMD. | 1702 | * Algorithm courtesy of Ross LaFetra from AMD. |
1698 | */ | 1703 | */ |
1699 | static u16 x4_vectors[] = { | 1704 | static const u16 x4_vectors[] = { |
1700 | 0x2f57, 0x1afe, 0x66cc, 0xdd88, | 1705 | 0x2f57, 0x1afe, 0x66cc, 0xdd88, |
1701 | 0x11eb, 0x3396, 0x7f4c, 0xeac8, | 1706 | 0x11eb, 0x3396, 0x7f4c, 0xeac8, |
1702 | 0x0001, 0x0002, 0x0004, 0x0008, | 1707 | 0x0001, 0x0002, 0x0004, 0x0008, |
@@ -1735,7 +1740,7 @@ static u16 x4_vectors[] = { | |||
1735 | 0x19a9, 0x2efe, 0xb5cc, 0x6f88, | 1740 | 0x19a9, 0x2efe, 0xb5cc, 0x6f88, |
1736 | }; | 1741 | }; |
1737 | 1742 | ||
1738 | static u16 x8_vectors[] = { | 1743 | static const u16 x8_vectors[] = { |
1739 | 0x0145, 0x028a, 0x2374, 0x43c8, 0xa1f0, 0x0520, 0x0a40, 0x1480, | 1744 | 0x0145, 0x028a, 0x2374, 0x43c8, 0xa1f0, 0x0520, 0x0a40, 0x1480, |
1740 | 0x0211, 0x0422, 0x0844, 0x1088, 0x01b0, 0x44e0, 0x23c0, 0xed80, | 1745 | 0x0211, 0x0422, 0x0844, 0x1088, 0x01b0, 0x44e0, 0x23c0, 0xed80, |
1741 | 0x1011, 0x0116, 0x022c, 0x0458, 0x08b0, 0x8c60, 0x2740, 0x4e80, | 1746 | 0x1011, 0x0116, 0x022c, 0x0458, 0x08b0, 0x8c60, 0x2740, 0x4e80, |
@@ -1757,7 +1762,7 @@ static u16 x8_vectors[] = { | |||
1757 | 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000, | 1762 | 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000, |
1758 | }; | 1763 | }; |
1759 | 1764 | ||
1760 | static int decode_syndrome(u16 syndrome, u16 *vectors, unsigned num_vecs, | 1765 | static int decode_syndrome(u16 syndrome, const u16 *vectors, unsigned num_vecs, |
1761 | unsigned v_dim) | 1766 | unsigned v_dim) |
1762 | { | 1767 | { |
1763 | unsigned int i, err_sym; | 1768 | unsigned int i, err_sym; |
@@ -2181,7 +2186,7 @@ static int init_csrows(struct mem_ctl_info *mci) | |||
2181 | } | 2186 | } |
2182 | 2187 | ||
2183 | /* get all cores on this DCT */ | 2188 | /* get all cores on this DCT */ |
2184 | static void get_cpus_on_this_dct_cpumask(struct cpumask *mask, unsigned nid) | 2189 | static void get_cpus_on_this_dct_cpumask(struct cpumask *mask, u16 nid) |
2185 | { | 2190 | { |
2186 | int cpu; | 2191 | int cpu; |
2187 | 2192 | ||
@@ -2191,7 +2196,7 @@ static void get_cpus_on_this_dct_cpumask(struct cpumask *mask, unsigned nid) | |||
2191 | } | 2196 | } |
2192 | 2197 | ||
2193 | /* check MCG_CTL on all the cpus on this node */ | 2198 | /* check MCG_CTL on all the cpus on this node */ |
2194 | static bool amd64_nb_mce_bank_enabled_on_node(unsigned nid) | 2199 | static bool amd64_nb_mce_bank_enabled_on_node(u16 nid) |
2195 | { | 2200 | { |
2196 | cpumask_var_t mask; | 2201 | cpumask_var_t mask; |
2197 | int cpu, nbe; | 2202 | int cpu, nbe; |
@@ -2224,7 +2229,7 @@ out: | |||
2224 | return ret; | 2229 | return ret; |
2225 | } | 2230 | } |
2226 | 2231 | ||
2227 | static int toggle_ecc_err_reporting(struct ecc_settings *s, u8 nid, bool on) | 2232 | static int toggle_ecc_err_reporting(struct ecc_settings *s, u16 nid, bool on) |
2228 | { | 2233 | { |
2229 | cpumask_var_t cmask; | 2234 | cpumask_var_t cmask; |
2230 | int cpu; | 2235 | int cpu; |
@@ -2262,7 +2267,7 @@ static int toggle_ecc_err_reporting(struct ecc_settings *s, u8 nid, bool on) | |||
2262 | return 0; | 2267 | return 0; |
2263 | } | 2268 | } |
2264 | 2269 | ||
2265 | static bool enable_ecc_error_reporting(struct ecc_settings *s, u8 nid, | 2270 | static bool enable_ecc_error_reporting(struct ecc_settings *s, u16 nid, |
2266 | struct pci_dev *F3) | 2271 | struct pci_dev *F3) |
2267 | { | 2272 | { |
2268 | bool ret = true; | 2273 | bool ret = true; |
@@ -2314,7 +2319,7 @@ static bool enable_ecc_error_reporting(struct ecc_settings *s, u8 nid, | |||
2314 | return ret; | 2319 | return ret; |
2315 | } | 2320 | } |
2316 | 2321 | ||
2317 | static void restore_ecc_error_reporting(struct ecc_settings *s, u8 nid, | 2322 | static void restore_ecc_error_reporting(struct ecc_settings *s, u16 nid, |
2318 | struct pci_dev *F3) | 2323 | struct pci_dev *F3) |
2319 | { | 2324 | { |
2320 | u32 value, mask = 0x3; /* UECC/CECC enable */ | 2325 | u32 value, mask = 0x3; /* UECC/CECC enable */ |
@@ -2353,7 +2358,7 @@ static const char *ecc_msg = | |||
2353 | "'ecc_enable_override'.\n" | 2358 | "'ecc_enable_override'.\n" |
2354 | " (Note that use of the override may cause unknown side effects.)\n"; | 2359 | " (Note that use of the override may cause unknown side effects.)\n"; |
2355 | 2360 | ||
2356 | static bool ecc_enabled(struct pci_dev *F3, u8 nid) | 2361 | static bool ecc_enabled(struct pci_dev *F3, u16 nid) |
2357 | { | 2362 | { |
2358 | u32 value; | 2363 | u32 value; |
2359 | u8 ecc_en = 0; | 2364 | u8 ecc_en = 0; |
@@ -2474,7 +2479,7 @@ static int amd64_init_one_instance(struct pci_dev *F2) | |||
2474 | struct mem_ctl_info *mci = NULL; | 2479 | struct mem_ctl_info *mci = NULL; |
2475 | struct edac_mc_layer layers[2]; | 2480 | struct edac_mc_layer layers[2]; |
2476 | int err = 0, ret; | 2481 | int err = 0, ret; |
2477 | u8 nid = get_node_id(F2); | 2482 | u16 nid = amd_get_node_id(F2); |
2478 | 2483 | ||
2479 | ret = -ENOMEM; | 2484 | ret = -ENOMEM; |
2480 | pvt = kzalloc(sizeof(struct amd64_pvt), GFP_KERNEL); | 2485 | pvt = kzalloc(sizeof(struct amd64_pvt), GFP_KERNEL); |
@@ -2566,7 +2571,7 @@ err_ret: | |||
2566 | static int amd64_probe_one_instance(struct pci_dev *pdev, | 2571 | static int amd64_probe_one_instance(struct pci_dev *pdev, |
2567 | const struct pci_device_id *mc_type) | 2572 | const struct pci_device_id *mc_type) |
2568 | { | 2573 | { |
2569 | u8 nid = get_node_id(pdev); | 2574 | u16 nid = amd_get_node_id(pdev); |
2570 | struct pci_dev *F3 = node_to_amd_nb(nid)->misc; | 2575 | struct pci_dev *F3 = node_to_amd_nb(nid)->misc; |
2571 | struct ecc_settings *s; | 2576 | struct ecc_settings *s; |
2572 | int ret = 0; | 2577 | int ret = 0; |
@@ -2616,7 +2621,7 @@ static void amd64_remove_one_instance(struct pci_dev *pdev) | |||
2616 | { | 2621 | { |
2617 | struct mem_ctl_info *mci; | 2622 | struct mem_ctl_info *mci; |
2618 | struct amd64_pvt *pvt; | 2623 | struct amd64_pvt *pvt; |
2619 | u8 nid = get_node_id(pdev); | 2624 | u16 nid = amd_get_node_id(pdev); |
2620 | struct pci_dev *F3 = node_to_amd_nb(nid)->misc; | 2625 | struct pci_dev *F3 = node_to_amd_nb(nid)->misc; |
2621 | struct ecc_settings *s = ecc_stngs[nid]; | 2626 | struct ecc_settings *s = ecc_stngs[nid]; |
2622 | 2627 | ||
diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index e864f407806c..35637d83f235 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h | |||
@@ -292,12 +292,6 @@ | |||
292 | /* MSRs */ | 292 | /* MSRs */ |
293 | #define MSR_MCGCTL_NBE BIT(4) | 293 | #define MSR_MCGCTL_NBE BIT(4) |
294 | 294 | ||
295 | /* AMD sets the first MC device at device ID 0x18. */ | ||
296 | static inline u8 get_node_id(struct pci_dev *pdev) | ||
297 | { | ||
298 | return PCI_SLOT(pdev->devfn) - 0x18; | ||
299 | } | ||
300 | |||
301 | enum amd_families { | 295 | enum amd_families { |
302 | K8_CPUS = 0, | 296 | K8_CPUS = 0, |
303 | F10_CPUS, | 297 | F10_CPUS, |
@@ -340,7 +334,7 @@ struct amd64_pvt { | |||
340 | /* pci_device handles which we utilize */ | 334 | /* pci_device handles which we utilize */ |
341 | struct pci_dev *F1, *F2, *F3; | 335 | struct pci_dev *F1, *F2, *F3; |
342 | 336 | ||
343 | unsigned mc_node_id; /* MC index of this MC node */ | 337 | u16 mc_node_id; /* MC index of this MC node */ |
344 | int ext_model; /* extended model value of this node */ | 338 | int ext_model; /* extended model value of this node */ |
345 | int channel_count; | 339 | int channel_count; |
346 | 340 | ||
@@ -393,7 +387,7 @@ struct err_info { | |||
393 | u32 offset; | 387 | u32 offset; |
394 | }; | 388 | }; |
395 | 389 | ||
396 | static inline u64 get_dram_base(struct amd64_pvt *pvt, unsigned i) | 390 | static inline u64 get_dram_base(struct amd64_pvt *pvt, u8 i) |
397 | { | 391 | { |
398 | u64 addr = ((u64)pvt->ranges[i].base.lo & 0xffff0000) << 8; | 392 | u64 addr = ((u64)pvt->ranges[i].base.lo & 0xffff0000) << 8; |
399 | 393 | ||
@@ -403,7 +397,7 @@ static inline u64 get_dram_base(struct amd64_pvt *pvt, unsigned i) | |||
403 | return (((u64)pvt->ranges[i].base.hi & 0x000000ff) << 40) | addr; | 397 | return (((u64)pvt->ranges[i].base.hi & 0x000000ff) << 40) | addr; |
404 | } | 398 | } |
405 | 399 | ||
406 | static inline u64 get_dram_limit(struct amd64_pvt *pvt, unsigned i) | 400 | static inline u64 get_dram_limit(struct amd64_pvt *pvt, u8 i) |
407 | { | 401 | { |
408 | u64 lim = (((u64)pvt->ranges[i].lim.lo & 0xffff0000) << 8) | 0x00ffffff; | 402 | u64 lim = (((u64)pvt->ranges[i].lim.lo & 0xffff0000) << 8) | 0x00ffffff; |
409 | 403 | ||
diff --git a/drivers/gpu/drm/nouveau/core/core/falcon.c b/drivers/gpu/drm/nouveau/core/core/falcon.c index 6b0843c33877..e05c15777588 100644 --- a/drivers/gpu/drm/nouveau/core/core/falcon.c +++ b/drivers/gpu/drm/nouveau/core/core/falcon.c | |||
@@ -73,8 +73,11 @@ _nouveau_falcon_init(struct nouveau_object *object) | |||
73 | nv_debug(falcon, "data limit: %d\n", falcon->data.limit); | 73 | nv_debug(falcon, "data limit: %d\n", falcon->data.limit); |
74 | 74 | ||
75 | /* wait for 'uc halted' to be signalled before continuing */ | 75 | /* wait for 'uc halted' to be signalled before continuing */ |
76 | if (falcon->secret) { | 76 | if (falcon->secret && falcon->version < 4) { |
77 | nv_wait(falcon, 0x008, 0x00000010, 0x00000010); | 77 | if (!falcon->version) |
78 | nv_wait(falcon, 0x008, 0x00000010, 0x00000010); | ||
79 | else | ||
80 | nv_wait(falcon, 0x180, 0x80000000, 0); | ||
78 | nv_wo32(falcon, 0x004, 0x00000010); | 81 | nv_wo32(falcon, 0x004, 0x00000010); |
79 | } | 82 | } |
80 | 83 | ||
diff --git a/drivers/gpu/drm/nouveau/core/core/subdev.c b/drivers/gpu/drm/nouveau/core/core/subdev.c index f74c30aa33a0..48f06378d3f9 100644 --- a/drivers/gpu/drm/nouveau/core/core/subdev.c +++ b/drivers/gpu/drm/nouveau/core/core/subdev.c | |||
@@ -99,7 +99,7 @@ nouveau_subdev_create_(struct nouveau_object *parent, | |||
99 | if (ret) | 99 | if (ret) |
100 | return ret; | 100 | return ret; |
101 | 101 | ||
102 | mutex_init(&subdev->mutex); | 102 | __mutex_init(&subdev->mutex, subname, &oclass->lock_class_key); |
103 | subdev->name = subname; | 103 | subdev->name = subname; |
104 | 104 | ||
105 | if (parent) { | 105 | if (parent) { |
diff --git a/drivers/gpu/drm/nouveau/core/include/core/object.h b/drivers/gpu/drm/nouveau/core/include/core/object.h index 5982935ee23a..106bb19fdd9a 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/object.h +++ b/drivers/gpu/drm/nouveau/core/include/core/object.h | |||
@@ -50,10 +50,13 @@ int nouveau_object_fini(struct nouveau_object *, bool suspend); | |||
50 | 50 | ||
51 | extern struct nouveau_ofuncs nouveau_object_ofuncs; | 51 | extern struct nouveau_ofuncs nouveau_object_ofuncs; |
52 | 52 | ||
53 | /* Don't allocate dynamically, because lockdep needs lock_class_keys to be in | ||
54 | * ".data". */ | ||
53 | struct nouveau_oclass { | 55 | struct nouveau_oclass { |
54 | u32 handle; | 56 | u32 handle; |
55 | struct nouveau_ofuncs *ofuncs; | 57 | struct nouveau_ofuncs * const ofuncs; |
56 | struct nouveau_omthds *omthds; | 58 | struct nouveau_omthds * const omthds; |
59 | struct lock_class_key lock_class_key; | ||
57 | }; | 60 | }; |
58 | 61 | ||
59 | #define nv_oclass(o) nv_object(o)->oclass | 62 | #define nv_oclass(o) nv_object(o)->oclass |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/base.c b/drivers/gpu/drm/nouveau/core/subdev/fb/base.c index d6d16007ec1a..d62045f454b2 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/base.c | |||
@@ -86,8 +86,8 @@ nouveau_fb_preinit(struct nouveau_fb *pfb) | |||
86 | return ret; | 86 | return ret; |
87 | } | 87 | } |
88 | 88 | ||
89 | if (!nouveau_mm_initialised(&pfb->tags) && tags) { | 89 | if (!nouveau_mm_initialised(&pfb->tags)) { |
90 | ret = nouveau_mm_init(&pfb->tags, 0, ++tags, 1); | 90 | ret = nouveau_mm_init(&pfb->tags, 0, tags ? ++tags : 0, 1); |
91 | if (ret) | 91 | if (ret) |
92 | return ret; | 92 | return ret; |
93 | } | 93 | } |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c index 487cb8c6c204..eac236ed19b2 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c | |||
@@ -99,7 +99,7 @@ nv50_fb_vram_init(struct nouveau_fb *pfb) | |||
99 | struct nouveau_bios *bios = nouveau_bios(device); | 99 | struct nouveau_bios *bios = nouveau_bios(device); |
100 | const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */ | 100 | const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */ |
101 | const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */ | 101 | const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */ |
102 | u32 size; | 102 | u32 size, tags = 0; |
103 | int ret; | 103 | int ret; |
104 | 104 | ||
105 | pfb->ram.size = nv_rd32(pfb, 0x10020c); | 105 | pfb->ram.size = nv_rd32(pfb, 0x10020c); |
@@ -140,10 +140,11 @@ nv50_fb_vram_init(struct nouveau_fb *pfb) | |||
140 | return ret; | 140 | return ret; |
141 | 141 | ||
142 | pfb->ram.ranks = (nv_rd32(pfb, 0x100200) & 0x4) ? 2 : 1; | 142 | pfb->ram.ranks = (nv_rd32(pfb, 0x100200) & 0x4) ? 2 : 1; |
143 | tags = nv_rd32(pfb, 0x100320); | ||
143 | break; | 144 | break; |
144 | } | 145 | } |
145 | 146 | ||
146 | return nv_rd32(pfb, 0x100320); | 147 | return tags; |
147 | } | 148 | } |
148 | 149 | ||
149 | static int | 150 | static int |
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 69d7b1d0b9d6..1699a9083a2f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c | |||
@@ -28,6 +28,7 @@ | |||
28 | */ | 28 | */ |
29 | 29 | ||
30 | #include <core/engine.h> | 30 | #include <core/engine.h> |
31 | #include <linux/swiotlb.h> | ||
31 | 32 | ||
32 | #include <subdev/fb.h> | 33 | #include <subdev/fb.h> |
33 | #include <subdev/vm.h> | 34 | #include <subdev/vm.h> |
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 8b090f1eb51d..5e7aef23825a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c | |||
@@ -245,6 +245,8 @@ static int nouveau_drm_probe(struct pci_dev *pdev, | |||
245 | return 0; | 245 | return 0; |
246 | } | 246 | } |
247 | 247 | ||
248 | static struct lock_class_key drm_client_lock_class_key; | ||
249 | |||
248 | static int | 250 | static int |
249 | nouveau_drm_load(struct drm_device *dev, unsigned long flags) | 251 | nouveau_drm_load(struct drm_device *dev, unsigned long flags) |
250 | { | 252 | { |
@@ -256,6 +258,7 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) | |||
256 | ret = nouveau_cli_create(pdev, "DRM", sizeof(*drm), (void**)&drm); | 258 | ret = nouveau_cli_create(pdev, "DRM", sizeof(*drm), (void**)&drm); |
257 | if (ret) | 259 | if (ret) |
258 | return ret; | 260 | return ret; |
261 | lockdep_set_class(&drm->client.mutex, &drm_client_lock_class_key); | ||
259 | 262 | ||
260 | dev->dev_private = drm; | 263 | dev->dev_private = drm; |
261 | drm->dev = dev; | 264 | drm->dev = dev; |
diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c index 7a445666e71f..ee4cff534f10 100644 --- a/drivers/gpu/drm/radeon/evergreen_cs.c +++ b/drivers/gpu/drm/radeon/evergreen_cs.c | |||
@@ -2909,14 +2909,14 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) | |||
2909 | return -EINVAL; | 2909 | return -EINVAL; |
2910 | } | 2910 | } |
2911 | if (tiled) { | 2911 | if (tiled) { |
2912 | dst_offset = ib[idx+1]; | 2912 | dst_offset = radeon_get_ib_value(p, idx+1); |
2913 | dst_offset <<= 8; | 2913 | dst_offset <<= 8; |
2914 | 2914 | ||
2915 | ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8); | 2915 | ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8); |
2916 | p->idx += count + 7; | 2916 | p->idx += count + 7; |
2917 | } else { | 2917 | } else { |
2918 | dst_offset = ib[idx+1]; | 2918 | dst_offset = radeon_get_ib_value(p, idx+1); |
2919 | dst_offset |= ((u64)(ib[idx+2] & 0xff)) << 32; | 2919 | dst_offset |= ((u64)(radeon_get_ib_value(p, idx+2) & 0xff)) << 32; |
2920 | 2920 | ||
2921 | ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc); | 2921 | ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc); |
2922 | ib[idx+2] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff; | 2922 | ib[idx+2] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff; |
@@ -2954,12 +2954,12 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) | |||
2954 | DRM_ERROR("bad L2T, frame to fields DMA_PACKET_COPY\n"); | 2954 | DRM_ERROR("bad L2T, frame to fields DMA_PACKET_COPY\n"); |
2955 | return -EINVAL; | 2955 | return -EINVAL; |
2956 | } | 2956 | } |
2957 | dst_offset = ib[idx+1]; | 2957 | dst_offset = radeon_get_ib_value(p, idx+1); |
2958 | dst_offset <<= 8; | 2958 | dst_offset <<= 8; |
2959 | dst2_offset = ib[idx+2]; | 2959 | dst2_offset = radeon_get_ib_value(p, idx+2); |
2960 | dst2_offset <<= 8; | 2960 | dst2_offset <<= 8; |
2961 | src_offset = ib[idx+8]; | 2961 | src_offset = radeon_get_ib_value(p, idx+8); |
2962 | src_offset |= ((u64)(ib[idx+9] & 0xff)) << 32; | 2962 | src_offset |= ((u64)(radeon_get_ib_value(p, idx+9) & 0xff)) << 32; |
2963 | if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) { | 2963 | if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) { |
2964 | dev_warn(p->dev, "DMA L2T, frame to fields src buffer too small (%llu %lu)\n", | 2964 | dev_warn(p->dev, "DMA L2T, frame to fields src buffer too small (%llu %lu)\n", |
2965 | src_offset + (count * 4), radeon_bo_size(src_reloc->robj)); | 2965 | src_offset + (count * 4), radeon_bo_size(src_reloc->robj)); |
@@ -3014,12 +3014,12 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) | |||
3014 | DRM_ERROR("bad L2T, broadcast DMA_PACKET_COPY\n"); | 3014 | DRM_ERROR("bad L2T, broadcast DMA_PACKET_COPY\n"); |
3015 | return -EINVAL; | 3015 | return -EINVAL; |
3016 | } | 3016 | } |
3017 | dst_offset = ib[idx+1]; | 3017 | dst_offset = radeon_get_ib_value(p, idx+1); |
3018 | dst_offset <<= 8; | 3018 | dst_offset <<= 8; |
3019 | dst2_offset = ib[idx+2]; | 3019 | dst2_offset = radeon_get_ib_value(p, idx+2); |
3020 | dst2_offset <<= 8; | 3020 | dst2_offset <<= 8; |
3021 | src_offset = ib[idx+8]; | 3021 | src_offset = radeon_get_ib_value(p, idx+8); |
3022 | src_offset |= ((u64)(ib[idx+9] & 0xff)) << 32; | 3022 | src_offset |= ((u64)(radeon_get_ib_value(p, idx+9) & 0xff)) << 32; |
3023 | if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) { | 3023 | if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) { |
3024 | dev_warn(p->dev, "DMA L2T, broadcast src buffer too small (%llu %lu)\n", | 3024 | dev_warn(p->dev, "DMA L2T, broadcast src buffer too small (%llu %lu)\n", |
3025 | src_offset + (count * 4), radeon_bo_size(src_reloc->robj)); | 3025 | src_offset + (count * 4), radeon_bo_size(src_reloc->robj)); |
@@ -3046,22 +3046,22 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) | |||
3046 | /* detile bit */ | 3046 | /* detile bit */ |
3047 | if (idx_value & (1 << 31)) { | 3047 | if (idx_value & (1 << 31)) { |
3048 | /* tiled src, linear dst */ | 3048 | /* tiled src, linear dst */ |
3049 | src_offset = ib[idx+1]; | 3049 | src_offset = radeon_get_ib_value(p, idx+1); |
3050 | src_offset <<= 8; | 3050 | src_offset <<= 8; |
3051 | ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset >> 8); | 3051 | ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset >> 8); |
3052 | 3052 | ||
3053 | dst_offset = ib[idx+7]; | 3053 | dst_offset = radeon_get_ib_value(p, idx+7); |
3054 | dst_offset |= ((u64)(ib[idx+8] & 0xff)) << 32; | 3054 | dst_offset |= ((u64)(radeon_get_ib_value(p, idx+8) & 0xff)) << 32; |
3055 | ib[idx+7] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc); | 3055 | ib[idx+7] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc); |
3056 | ib[idx+8] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff; | 3056 | ib[idx+8] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff; |
3057 | } else { | 3057 | } else { |
3058 | /* linear src, tiled dst */ | 3058 | /* linear src, tiled dst */ |
3059 | src_offset = ib[idx+7]; | 3059 | src_offset = radeon_get_ib_value(p, idx+7); |
3060 | src_offset |= ((u64)(ib[idx+8] & 0xff)) << 32; | 3060 | src_offset |= ((u64)(radeon_get_ib_value(p, idx+8) & 0xff)) << 32; |
3061 | ib[idx+7] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc); | 3061 | ib[idx+7] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc); |
3062 | ib[idx+8] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff; | 3062 | ib[idx+8] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff; |
3063 | 3063 | ||
3064 | dst_offset = ib[idx+1]; | 3064 | dst_offset = radeon_get_ib_value(p, idx+1); |
3065 | dst_offset <<= 8; | 3065 | dst_offset <<= 8; |
3066 | ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8); | 3066 | ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8); |
3067 | } | 3067 | } |
@@ -3098,12 +3098,12 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) | |||
3098 | DRM_ERROR("bad L2T, broadcast DMA_PACKET_COPY\n"); | 3098 | DRM_ERROR("bad L2T, broadcast DMA_PACKET_COPY\n"); |
3099 | return -EINVAL; | 3099 | return -EINVAL; |
3100 | } | 3100 | } |
3101 | dst_offset = ib[idx+1]; | 3101 | dst_offset = radeon_get_ib_value(p, idx+1); |
3102 | dst_offset <<= 8; | 3102 | dst_offset <<= 8; |
3103 | dst2_offset = ib[idx+2]; | 3103 | dst2_offset = radeon_get_ib_value(p, idx+2); |
3104 | dst2_offset <<= 8; | 3104 | dst2_offset <<= 8; |
3105 | src_offset = ib[idx+8]; | 3105 | src_offset = radeon_get_ib_value(p, idx+8); |
3106 | src_offset |= ((u64)(ib[idx+9] & 0xff)) << 32; | 3106 | src_offset |= ((u64)(radeon_get_ib_value(p, idx+9) & 0xff)) << 32; |
3107 | if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) { | 3107 | if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) { |
3108 | dev_warn(p->dev, "DMA L2T, broadcast src buffer too small (%llu %lu)\n", | 3108 | dev_warn(p->dev, "DMA L2T, broadcast src buffer too small (%llu %lu)\n", |
3109 | src_offset + (count * 4), radeon_bo_size(src_reloc->robj)); | 3109 | src_offset + (count * 4), radeon_bo_size(src_reloc->robj)); |
@@ -3135,22 +3135,22 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) | |||
3135 | /* detile bit */ | 3135 | /* detile bit */ |
3136 | if (idx_value & (1 << 31)) { | 3136 | if (idx_value & (1 << 31)) { |
3137 | /* tiled src, linear dst */ | 3137 | /* tiled src, linear dst */ |
3138 | src_offset = ib[idx+1]; | 3138 | src_offset = radeon_get_ib_value(p, idx+1); |
3139 | src_offset <<= 8; | 3139 | src_offset <<= 8; |
3140 | ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset >> 8); | 3140 | ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset >> 8); |
3141 | 3141 | ||
3142 | dst_offset = ib[idx+7]; | 3142 | dst_offset = radeon_get_ib_value(p, idx+7); |
3143 | dst_offset |= ((u64)(ib[idx+8] & 0xff)) << 32; | 3143 | dst_offset |= ((u64)(radeon_get_ib_value(p, idx+8) & 0xff)) << 32; |
3144 | ib[idx+7] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc); | 3144 | ib[idx+7] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc); |
3145 | ib[idx+8] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff; | 3145 | ib[idx+8] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff; |
3146 | } else { | 3146 | } else { |
3147 | /* linear src, tiled dst */ | 3147 | /* linear src, tiled dst */ |
3148 | src_offset = ib[idx+7]; | 3148 | src_offset = radeon_get_ib_value(p, idx+7); |
3149 | src_offset |= ((u64)(ib[idx+8] & 0xff)) << 32; | 3149 | src_offset |= ((u64)(radeon_get_ib_value(p, idx+8) & 0xff)) << 32; |
3150 | ib[idx+7] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc); | 3150 | ib[idx+7] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc); |
3151 | ib[idx+8] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff; | 3151 | ib[idx+8] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff; |
3152 | 3152 | ||
3153 | dst_offset = ib[idx+1]; | 3153 | dst_offset = radeon_get_ib_value(p, idx+1); |
3154 | dst_offset <<= 8; | 3154 | dst_offset <<= 8; |
3155 | ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8); | 3155 | ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8); |
3156 | } | 3156 | } |
@@ -3176,10 +3176,10 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) | |||
3176 | switch (misc) { | 3176 | switch (misc) { |
3177 | case 0: | 3177 | case 0: |
3178 | /* L2L, byte */ | 3178 | /* L2L, byte */ |
3179 | src_offset = ib[idx+2]; | 3179 | src_offset = radeon_get_ib_value(p, idx+2); |
3180 | src_offset |= ((u64)(ib[idx+4] & 0xff)) << 32; | 3180 | src_offset |= ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32; |
3181 | dst_offset = ib[idx+1]; | 3181 | dst_offset = radeon_get_ib_value(p, idx+1); |
3182 | dst_offset |= ((u64)(ib[idx+3] & 0xff)) << 32; | 3182 | dst_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0xff)) << 32; |
3183 | if ((src_offset + count) > radeon_bo_size(src_reloc->robj)) { | 3183 | if ((src_offset + count) > radeon_bo_size(src_reloc->robj)) { |
3184 | dev_warn(p->dev, "DMA L2L, byte src buffer too small (%llu %lu)\n", | 3184 | dev_warn(p->dev, "DMA L2L, byte src buffer too small (%llu %lu)\n", |
3185 | src_offset + count, radeon_bo_size(src_reloc->robj)); | 3185 | src_offset + count, radeon_bo_size(src_reloc->robj)); |
@@ -3216,12 +3216,12 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) | |||
3216 | DRM_ERROR("bad L2L, dw, broadcast DMA_PACKET_COPY\n"); | 3216 | DRM_ERROR("bad L2L, dw, broadcast DMA_PACKET_COPY\n"); |
3217 | return -EINVAL; | 3217 | return -EINVAL; |
3218 | } | 3218 | } |
3219 | dst_offset = ib[idx+1]; | 3219 | dst_offset = radeon_get_ib_value(p, idx+1); |
3220 | dst_offset |= ((u64)(ib[idx+4] & 0xff)) << 32; | 3220 | dst_offset |= ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32; |
3221 | dst2_offset = ib[idx+2]; | 3221 | dst2_offset = radeon_get_ib_value(p, idx+2); |
3222 | dst2_offset |= ((u64)(ib[idx+5] & 0xff)) << 32; | 3222 | dst2_offset |= ((u64)(radeon_get_ib_value(p, idx+5) & 0xff)) << 32; |
3223 | src_offset = ib[idx+3]; | 3223 | src_offset = radeon_get_ib_value(p, idx+3); |
3224 | src_offset |= ((u64)(ib[idx+6] & 0xff)) << 32; | 3224 | src_offset |= ((u64)(radeon_get_ib_value(p, idx+6) & 0xff)) << 32; |
3225 | if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) { | 3225 | if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) { |
3226 | dev_warn(p->dev, "DMA L2L, dw, broadcast src buffer too small (%llu %lu)\n", | 3226 | dev_warn(p->dev, "DMA L2L, dw, broadcast src buffer too small (%llu %lu)\n", |
3227 | src_offset + (count * 4), radeon_bo_size(src_reloc->robj)); | 3227 | src_offset + (count * 4), radeon_bo_size(src_reloc->robj)); |
@@ -3251,10 +3251,10 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) | |||
3251 | } | 3251 | } |
3252 | } else { | 3252 | } else { |
3253 | /* L2L, dw */ | 3253 | /* L2L, dw */ |
3254 | src_offset = ib[idx+2]; | 3254 | src_offset = radeon_get_ib_value(p, idx+2); |
3255 | src_offset |= ((u64)(ib[idx+4] & 0xff)) << 32; | 3255 | src_offset |= ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32; |
3256 | dst_offset = ib[idx+1]; | 3256 | dst_offset = radeon_get_ib_value(p, idx+1); |
3257 | dst_offset |= ((u64)(ib[idx+3] & 0xff)) << 32; | 3257 | dst_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0xff)) << 32; |
3258 | if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) { | 3258 | if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) { |
3259 | dev_warn(p->dev, "DMA L2L, dw src buffer too small (%llu %lu)\n", | 3259 | dev_warn(p->dev, "DMA L2L, dw src buffer too small (%llu %lu)\n", |
3260 | src_offset + (count * 4), radeon_bo_size(src_reloc->robj)); | 3260 | src_offset + (count * 4), radeon_bo_size(src_reloc->robj)); |
@@ -3279,8 +3279,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p) | |||
3279 | DRM_ERROR("bad DMA_PACKET_CONSTANT_FILL\n"); | 3279 | DRM_ERROR("bad DMA_PACKET_CONSTANT_FILL\n"); |
3280 | return -EINVAL; | 3280 | return -EINVAL; |
3281 | } | 3281 | } |
3282 | dst_offset = ib[idx+1]; | 3282 | dst_offset = radeon_get_ib_value(p, idx+1); |
3283 | dst_offset |= ((u64)(ib[idx+3] & 0x00ff0000)) << 16; | 3283 | dst_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0x00ff0000)) << 16; |
3284 | if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) { | 3284 | if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) { |
3285 | dev_warn(p->dev, "DMA constant fill buffer too small (%llu %lu)\n", | 3285 | dev_warn(p->dev, "DMA constant fill buffer too small (%llu %lu)\n", |
3286 | dst_offset, radeon_bo_size(dst_reloc->robj)); | 3286 | dst_offset, radeon_bo_size(dst_reloc->robj)); |
diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index 69ec24ab8d63..9b2512bf1a46 100644 --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c | |||
@@ -2623,14 +2623,14 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p) | |||
2623 | return -EINVAL; | 2623 | return -EINVAL; |
2624 | } | 2624 | } |
2625 | if (tiled) { | 2625 | if (tiled) { |
2626 | dst_offset = ib[idx+1]; | 2626 | dst_offset = radeon_get_ib_value(p, idx+1); |
2627 | dst_offset <<= 8; | 2627 | dst_offset <<= 8; |
2628 | 2628 | ||
2629 | ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8); | 2629 | ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8); |
2630 | p->idx += count + 5; | 2630 | p->idx += count + 5; |
2631 | } else { | 2631 | } else { |
2632 | dst_offset = ib[idx+1]; | 2632 | dst_offset = radeon_get_ib_value(p, idx+1); |
2633 | dst_offset |= ((u64)(ib[idx+2] & 0xff)) << 32; | 2633 | dst_offset |= ((u64)(radeon_get_ib_value(p, idx+2) & 0xff)) << 32; |
2634 | 2634 | ||
2635 | ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc); | 2635 | ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc); |
2636 | ib[idx+2] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff; | 2636 | ib[idx+2] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff; |
@@ -2658,32 +2658,32 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p) | |||
2658 | /* detile bit */ | 2658 | /* detile bit */ |
2659 | if (idx_value & (1 << 31)) { | 2659 | if (idx_value & (1 << 31)) { |
2660 | /* tiled src, linear dst */ | 2660 | /* tiled src, linear dst */ |
2661 | src_offset = ib[idx+1]; | 2661 | src_offset = radeon_get_ib_value(p, idx+1); |
2662 | src_offset <<= 8; | 2662 | src_offset <<= 8; |
2663 | ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset >> 8); | 2663 | ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset >> 8); |
2664 | 2664 | ||
2665 | dst_offset = ib[idx+5]; | 2665 | dst_offset = radeon_get_ib_value(p, idx+5); |
2666 | dst_offset |= ((u64)(ib[idx+6] & 0xff)) << 32; | 2666 | dst_offset |= ((u64)(radeon_get_ib_value(p, idx+6) & 0xff)) << 32; |
2667 | ib[idx+5] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc); | 2667 | ib[idx+5] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc); |
2668 | ib[idx+6] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff; | 2668 | ib[idx+6] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff; |
2669 | } else { | 2669 | } else { |
2670 | /* linear src, tiled dst */ | 2670 | /* linear src, tiled dst */ |
2671 | src_offset = ib[idx+5]; | 2671 | src_offset = radeon_get_ib_value(p, idx+5); |
2672 | src_offset |= ((u64)(ib[idx+6] & 0xff)) << 32; | 2672 | src_offset |= ((u64)(radeon_get_ib_value(p, idx+6) & 0xff)) << 32; |
2673 | ib[idx+5] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc); | 2673 | ib[idx+5] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc); |
2674 | ib[idx+6] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff; | 2674 | ib[idx+6] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff; |
2675 | 2675 | ||
2676 | dst_offset = ib[idx+1]; | 2676 | dst_offset = radeon_get_ib_value(p, idx+1); |
2677 | dst_offset <<= 8; | 2677 | dst_offset <<= 8; |
2678 | ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8); | 2678 | ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8); |
2679 | } | 2679 | } |
2680 | p->idx += 7; | 2680 | p->idx += 7; |
2681 | } else { | 2681 | } else { |
2682 | if (p->family >= CHIP_RV770) { | 2682 | if (p->family >= CHIP_RV770) { |
2683 | src_offset = ib[idx+2]; | 2683 | src_offset = radeon_get_ib_value(p, idx+2); |
2684 | src_offset |= ((u64)(ib[idx+4] & 0xff)) << 32; | 2684 | src_offset |= ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32; |
2685 | dst_offset = ib[idx+1]; | 2685 | dst_offset = radeon_get_ib_value(p, idx+1); |
2686 | dst_offset |= ((u64)(ib[idx+3] & 0xff)) << 32; | 2686 | dst_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0xff)) << 32; |
2687 | 2687 | ||
2688 | ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc); | 2688 | ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc); |
2689 | ib[idx+2] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc); | 2689 | ib[idx+2] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc); |
@@ -2691,10 +2691,10 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p) | |||
2691 | ib[idx+4] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff; | 2691 | ib[idx+4] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff; |
2692 | p->idx += 5; | 2692 | p->idx += 5; |
2693 | } else { | 2693 | } else { |
2694 | src_offset = ib[idx+2]; | 2694 | src_offset = radeon_get_ib_value(p, idx+2); |
2695 | src_offset |= ((u64)(ib[idx+3] & 0xff)) << 32; | 2695 | src_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0xff)) << 32; |
2696 | dst_offset = ib[idx+1]; | 2696 | dst_offset = radeon_get_ib_value(p, idx+1); |
2697 | dst_offset |= ((u64)(ib[idx+3] & 0xff0000)) << 16; | 2697 | dst_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0xff0000)) << 16; |
2698 | 2698 | ||
2699 | ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc); | 2699 | ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc); |
2700 | ib[idx+2] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc); | 2700 | ib[idx+2] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc); |
@@ -2724,8 +2724,8 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p) | |||
2724 | DRM_ERROR("bad DMA_PACKET_WRITE\n"); | 2724 | DRM_ERROR("bad DMA_PACKET_WRITE\n"); |
2725 | return -EINVAL; | 2725 | return -EINVAL; |
2726 | } | 2726 | } |
2727 | dst_offset = ib[idx+1]; | 2727 | dst_offset = radeon_get_ib_value(p, idx+1); |
2728 | dst_offset |= ((u64)(ib[idx+3] & 0x00ff0000)) << 16; | 2728 | dst_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0x00ff0000)) << 16; |
2729 | if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) { | 2729 | if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) { |
2730 | dev_warn(p->dev, "DMA constant fill buffer too small (%llu %lu)\n", | 2730 | dev_warn(p->dev, "DMA constant fill buffer too small (%llu %lu)\n", |
2731 | dst_offset + (count * 4), radeon_bo_size(dst_reloc->robj)); | 2731 | dst_offset + (count * 4), radeon_bo_size(dst_reloc->robj)); |
diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index 1d8ff2f850ba..93f760e27a92 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <drm/radeon_drm.h> | 38 | #include <drm/radeon_drm.h> |
39 | #include <linux/seq_file.h> | 39 | #include <linux/seq_file.h> |
40 | #include <linux/slab.h> | 40 | #include <linux/slab.h> |
41 | #include <linux/swiotlb.h> | ||
41 | #include "radeon_reg.h" | 42 | #include "radeon_reg.h" |
42 | #include "radeon.h" | 43 | #include "radeon.h" |
43 | 44 | ||
diff --git a/drivers/hv/Kconfig b/drivers/hv/Kconfig index b38ef6d8d049..64630f15f181 100644 --- a/drivers/hv/Kconfig +++ b/drivers/hv/Kconfig | |||
@@ -2,7 +2,7 @@ menu "Microsoft Hyper-V guest support" | |||
2 | 2 | ||
3 | config HYPERV | 3 | config HYPERV |
4 | tristate "Microsoft Hyper-V client drivers" | 4 | tristate "Microsoft Hyper-V client drivers" |
5 | depends on X86 && ACPI && PCI | 5 | depends on X86 && ACPI && PCI && X86_LOCAL_APIC |
6 | help | 6 | help |
7 | Select this option to run Linux as a Hyper-V client operating | 7 | Select this option to run Linux as a Hyper-V client operating |
8 | system. | 8 | system. |
diff --git a/drivers/input/input.c b/drivers/input/input.c index ce01332f7b3a..c04469928925 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c | |||
@@ -1785,12 +1785,13 @@ static void devm_input_device_release(struct device *dev, void *res) | |||
1785 | * its driver (or binding fails). Once managed input device is allocated, | 1785 | * its driver (or binding fails). Once managed input device is allocated, |
1786 | * it is ready to be set up and registered in the same fashion as regular | 1786 | * it is ready to be set up and registered in the same fashion as regular |
1787 | * input device. There are no special devm_input_device_[un]register() | 1787 | * input device. There are no special devm_input_device_[un]register() |
1788 | * variants, regular ones work with both managed and unmanaged devices. | 1788 | * variants, regular ones work with both managed and unmanaged devices, |
1789 | * should you need them. In most cases however, managed input device need | ||
1790 | * not be explicitly unregistered or freed. | ||
1789 | * | 1791 | * |
1790 | * NOTE: the owner device is set up as parent of input device and users | 1792 | * NOTE: the owner device is set up as parent of input device and users |
1791 | * should not override it. | 1793 | * should not override it. |
1792 | */ | 1794 | */ |
1793 | |||
1794 | struct input_dev *devm_input_allocate_device(struct device *dev) | 1795 | struct input_dev *devm_input_allocate_device(struct device *dev) |
1795 | { | 1796 | { |
1796 | struct input_dev *input; | 1797 | struct input_dev *input; |
@@ -2004,6 +2005,17 @@ static void devm_input_device_unregister(struct device *dev, void *res) | |||
2004 | * Once device has been successfully registered it can be unregistered | 2005 | * Once device has been successfully registered it can be unregistered |
2005 | * with input_unregister_device(); input_free_device() should not be | 2006 | * with input_unregister_device(); input_free_device() should not be |
2006 | * called in this case. | 2007 | * called in this case. |
2008 | * | ||
2009 | * Note that this function is also used to register managed input devices | ||
2010 | * (ones allocated with devm_input_allocate_device()). Such managed input | ||
2011 | * devices need not be explicitly unregistered or freed, their tear down | ||
2012 | * is controlled by the devres infrastructure. It is also worth noting | ||
2013 | * that tear down of managed input devices is internally a 2-step process: | ||
2014 | * registered managed input device is first unregistered, but stays in | ||
2015 | * memory and can still handle input_event() calls (although events will | ||
2016 | * not be delivered anywhere). The freeing of managed input device will | ||
2017 | * happen later, when devres stack is unwound to the point where device | ||
2018 | * allocation was made. | ||
2007 | */ | 2019 | */ |
2008 | int input_register_device(struct input_dev *dev) | 2020 | int input_register_device(struct input_dev *dev) |
2009 | { | 2021 | { |
diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c index 358cd7ee905b..7cd74e29cbc8 100644 --- a/drivers/input/joystick/analog.c +++ b/drivers/input/joystick/analog.c | |||
@@ -162,7 +162,7 @@ static unsigned int get_time_pit(void) | |||
162 | #define GET_TIME(x) do { x = get_cycles(); } while (0) | 162 | #define GET_TIME(x) do { x = get_cycles(); } while (0) |
163 | #define DELTA(x,y) ((y)-(x)) | 163 | #define DELTA(x,y) ((y)-(x)) |
164 | #define TIME_NAME "PCC" | 164 | #define TIME_NAME "PCC" |
165 | #elif defined(CONFIG_MN10300) | 165 | #elif defined(CONFIG_MN10300) || defined(CONFIG_TILE) |
166 | #define GET_TIME(x) do { x = get_cycles(); } while (0) | 166 | #define GET_TIME(x) do { x = get_cycles(); } while (0) |
167 | #define DELTA(x, y) ((x) - (y)) | 167 | #define DELTA(x, y) ((x) - (y)) |
168 | #define TIME_NAME "TSC" | 168 | #define TIME_NAME "TSC" |
diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c index 93c812662134..0de23f41b2d3 100644 --- a/drivers/input/keyboard/lm8323.c +++ b/drivers/input/keyboard/lm8323.c | |||
@@ -398,7 +398,7 @@ static irqreturn_t lm8323_irq(int irq, void *_lm) | |||
398 | lm8323_configure(lm); | 398 | lm8323_configure(lm); |
399 | } | 399 | } |
400 | for (i = 0; i < LM8323_NUM_PWMS; i++) { | 400 | for (i = 0; i < LM8323_NUM_PWMS; i++) { |
401 | if (ints & (1 << (INT_PWM1 + i))) { | 401 | if (ints & (INT_PWM1 << i)) { |
402 | dev_vdbg(&lm->client->dev, | 402 | dev_vdbg(&lm->client->dev, |
403 | "pwm%d engine completed\n", i); | 403 | "pwm%d engine completed\n", i); |
404 | pwm_done(&lm->pwm[i]); | 404 | pwm_done(&lm->pwm[i]); |
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c index f92d34f45a1c..aaf23aeae2ea 100644 --- a/drivers/input/tablet/wacom_sys.c +++ b/drivers/input/tablet/wacom_sys.c | |||
@@ -553,10 +553,10 @@ static int wacom_set_device_mode(struct usb_interface *intf, int report_id, int | |||
553 | if (!rep_data) | 553 | if (!rep_data) |
554 | return error; | 554 | return error; |
555 | 555 | ||
556 | rep_data[0] = report_id; | ||
557 | rep_data[1] = mode; | ||
558 | |||
559 | do { | 556 | do { |
557 | rep_data[0] = report_id; | ||
558 | rep_data[1] = mode; | ||
559 | |||
560 | error = wacom_set_report(intf, WAC_HID_FEATURE_REPORT, | 560 | error = wacom_set_report(intf, WAC_HID_FEATURE_REPORT, |
561 | report_id, rep_data, length, 1); | 561 | report_id, rep_data, length, 1); |
562 | if (error >= 0) | 562 | if (error >= 0) |
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index c1c74e030a58..d33eaaf783ad 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c | |||
@@ -4017,10 +4017,10 @@ static int alloc_irq_index(struct irq_cfg *cfg, u16 devid, int count) | |||
4017 | 4017 | ||
4018 | index -= count - 1; | 4018 | index -= count - 1; |
4019 | 4019 | ||
4020 | cfg->remapped = 1; | ||
4020 | irte_info = &cfg->irq_2_iommu; | 4021 | irte_info = &cfg->irq_2_iommu; |
4021 | irte_info->sub_handle = devid; | 4022 | irte_info->sub_handle = devid; |
4022 | irte_info->irte_index = index; | 4023 | irte_info->irte_index = index; |
4023 | irte_info->iommu = (void *)cfg; | ||
4024 | 4024 | ||
4025 | goto out; | 4025 | goto out; |
4026 | } | 4026 | } |
@@ -4127,9 +4127,9 @@ static int setup_ioapic_entry(int irq, struct IO_APIC_route_entry *entry, | |||
4127 | index = attr->ioapic_pin; | 4127 | index = attr->ioapic_pin; |
4128 | 4128 | ||
4129 | /* Setup IRQ remapping info */ | 4129 | /* Setup IRQ remapping info */ |
4130 | cfg->remapped = 1; | ||
4130 | irte_info->sub_handle = devid; | 4131 | irte_info->sub_handle = devid; |
4131 | irte_info->irte_index = index; | 4132 | irte_info->irte_index = index; |
4132 | irte_info->iommu = (void *)cfg; | ||
4133 | 4133 | ||
4134 | /* Setup IRTE for IOMMU */ | 4134 | /* Setup IRTE for IOMMU */ |
4135 | irte.val = 0; | 4135 | irte.val = 0; |
@@ -4288,9 +4288,9 @@ static int msi_setup_irq(struct pci_dev *pdev, unsigned int irq, | |||
4288 | devid = get_device_id(&pdev->dev); | 4288 | devid = get_device_id(&pdev->dev); |
4289 | irte_info = &cfg->irq_2_iommu; | 4289 | irte_info = &cfg->irq_2_iommu; |
4290 | 4290 | ||
4291 | cfg->remapped = 1; | ||
4291 | irte_info->sub_handle = devid; | 4292 | irte_info->sub_handle = devid; |
4292 | irte_info->irte_index = index + offset; | 4293 | irte_info->irte_index = index + offset; |
4293 | irte_info->iommu = (void *)cfg; | ||
4294 | 4294 | ||
4295 | return 0; | 4295 | return 0; |
4296 | } | 4296 | } |
@@ -4314,9 +4314,9 @@ static int setup_hpet_msi(unsigned int irq, unsigned int id) | |||
4314 | if (index < 0) | 4314 | if (index < 0) |
4315 | return index; | 4315 | return index; |
4316 | 4316 | ||
4317 | cfg->remapped = 1; | ||
4317 | irte_info->sub_handle = devid; | 4318 | irte_info->sub_handle = devid; |
4318 | irte_info->irte_index = index; | 4319 | irte_info->irte_index = index; |
4319 | irte_info->iommu = (void *)cfg; | ||
4320 | 4320 | ||
4321 | return 0; | 4321 | return 0; |
4322 | } | 4322 | } |
diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index 86e2f4a62b9a..174bb654453d 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c | |||
@@ -41,6 +41,8 @@ | |||
41 | #include <asm/irq_remapping.h> | 41 | #include <asm/irq_remapping.h> |
42 | #include <asm/iommu_table.h> | 42 | #include <asm/iommu_table.h> |
43 | 43 | ||
44 | #include "irq_remapping.h" | ||
45 | |||
44 | /* No locks are needed as DMA remapping hardware unit | 46 | /* No locks are needed as DMA remapping hardware unit |
45 | * list is constructed at boot time and hotplug of | 47 | * list is constructed at boot time and hotplug of |
46 | * these units are not supported by the architecture. | 48 | * these units are not supported by the architecture. |
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index eca28014ef3e..43d5c8b8e7ad 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c | |||
@@ -46,6 +46,8 @@ | |||
46 | #include <asm/cacheflush.h> | 46 | #include <asm/cacheflush.h> |
47 | #include <asm/iommu.h> | 47 | #include <asm/iommu.h> |
48 | 48 | ||
49 | #include "irq_remapping.h" | ||
50 | |||
49 | #define ROOT_SIZE VTD_PAGE_SIZE | 51 | #define ROOT_SIZE VTD_PAGE_SIZE |
50 | #define CONTEXT_SIZE VTD_PAGE_SIZE | 52 | #define CONTEXT_SIZE VTD_PAGE_SIZE |
51 | 53 | ||
diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c index af8904de1d44..f3b8f23b5d8f 100644 --- a/drivers/iommu/intel_irq_remapping.c +++ b/drivers/iommu/intel_irq_remapping.c | |||
@@ -68,6 +68,7 @@ static int alloc_irte(struct intel_iommu *iommu, int irq, u16 count) | |||
68 | { | 68 | { |
69 | struct ir_table *table = iommu->ir_table; | 69 | struct ir_table *table = iommu->ir_table; |
70 | struct irq_2_iommu *irq_iommu = irq_2_iommu(irq); | 70 | struct irq_2_iommu *irq_iommu = irq_2_iommu(irq); |
71 | struct irq_cfg *cfg = irq_get_chip_data(irq); | ||
71 | u16 index, start_index; | 72 | u16 index, start_index; |
72 | unsigned int mask = 0; | 73 | unsigned int mask = 0; |
73 | unsigned long flags; | 74 | unsigned long flags; |
@@ -115,6 +116,7 @@ static int alloc_irte(struct intel_iommu *iommu, int irq, u16 count) | |||
115 | for (i = index; i < index + count; i++) | 116 | for (i = index; i < index + count; i++) |
116 | table->base[i].present = 1; | 117 | table->base[i].present = 1; |
117 | 118 | ||
119 | cfg->remapped = 1; | ||
118 | irq_iommu->iommu = iommu; | 120 | irq_iommu->iommu = iommu; |
119 | irq_iommu->irte_index = index; | 121 | irq_iommu->irte_index = index; |
120 | irq_iommu->sub_handle = 0; | 122 | irq_iommu->sub_handle = 0; |
@@ -155,6 +157,7 @@ static int map_irq_to_irte_handle(int irq, u16 *sub_handle) | |||
155 | static int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle) | 157 | static int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle) |
156 | { | 158 | { |
157 | struct irq_2_iommu *irq_iommu = irq_2_iommu(irq); | 159 | struct irq_2_iommu *irq_iommu = irq_2_iommu(irq); |
160 | struct irq_cfg *cfg = irq_get_chip_data(irq); | ||
158 | unsigned long flags; | 161 | unsigned long flags; |
159 | 162 | ||
160 | if (!irq_iommu) | 163 | if (!irq_iommu) |
@@ -162,6 +165,7 @@ static int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subha | |||
162 | 165 | ||
163 | raw_spin_lock_irqsave(&irq_2_ir_lock, flags); | 166 | raw_spin_lock_irqsave(&irq_2_ir_lock, flags); |
164 | 167 | ||
168 | cfg->remapped = 1; | ||
165 | irq_iommu->iommu = iommu; | 169 | irq_iommu->iommu = iommu; |
166 | irq_iommu->irte_index = index; | 170 | irq_iommu->irte_index = index; |
167 | irq_iommu->sub_handle = subhandle; | 171 | irq_iommu->sub_handle = subhandle; |
@@ -425,11 +429,22 @@ static void iommu_set_irq_remapping(struct intel_iommu *iommu, int mode) | |||
425 | 429 | ||
426 | /* Enable interrupt-remapping */ | 430 | /* Enable interrupt-remapping */ |
427 | iommu->gcmd |= DMA_GCMD_IRE; | 431 | iommu->gcmd |= DMA_GCMD_IRE; |
432 | iommu->gcmd &= ~DMA_GCMD_CFI; /* Block compatibility-format MSIs */ | ||
428 | writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG); | 433 | writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG); |
429 | 434 | ||
430 | IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, | 435 | IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, |
431 | readl, (sts & DMA_GSTS_IRES), sts); | 436 | readl, (sts & DMA_GSTS_IRES), sts); |
432 | 437 | ||
438 | /* | ||
439 | * With CFI clear in the Global Command register, we should be | ||
440 | * protected from dangerous (i.e. compatibility) interrupts | ||
441 | * regardless of x2apic status. Check just to be sure. | ||
442 | */ | ||
443 | if (sts & DMA_GSTS_CFIS) | ||
444 | WARN(1, KERN_WARNING | ||
445 | "Compatibility-format IRQs enabled despite intr remapping;\n" | ||
446 | "you are vulnerable to IRQ injection.\n"); | ||
447 | |||
433 | raw_spin_unlock_irqrestore(&iommu->register_lock, flags); | 448 | raw_spin_unlock_irqrestore(&iommu->register_lock, flags); |
434 | } | 449 | } |
435 | 450 | ||
@@ -526,20 +541,24 @@ static int __init intel_irq_remapping_supported(void) | |||
526 | static int __init intel_enable_irq_remapping(void) | 541 | static int __init intel_enable_irq_remapping(void) |
527 | { | 542 | { |
528 | struct dmar_drhd_unit *drhd; | 543 | struct dmar_drhd_unit *drhd; |
544 | bool x2apic_present; | ||
529 | int setup = 0; | 545 | int setup = 0; |
530 | int eim = 0; | 546 | int eim = 0; |
531 | 547 | ||
548 | x2apic_present = x2apic_supported(); | ||
549 | |||
532 | if (parse_ioapics_under_ir() != 1) { | 550 | if (parse_ioapics_under_ir() != 1) { |
533 | printk(KERN_INFO "Not enable interrupt remapping\n"); | 551 | printk(KERN_INFO "Not enable interrupt remapping\n"); |
534 | return -1; | 552 | goto error; |
535 | } | 553 | } |
536 | 554 | ||
537 | if (x2apic_supported()) { | 555 | if (x2apic_present) { |
538 | eim = !dmar_x2apic_optout(); | 556 | eim = !dmar_x2apic_optout(); |
539 | WARN(!eim, KERN_WARNING | 557 | if (!eim) |
540 | "Your BIOS is broken and requested that x2apic be disabled\n" | 558 | printk(KERN_WARNING |
541 | "This will leave your machine vulnerable to irq-injection attacks\n" | 559 | "Your BIOS is broken and requested that x2apic be disabled.\n" |
542 | "Use 'intremap=no_x2apic_optout' to override BIOS request\n"); | 560 | "This will slightly decrease performance.\n" |
561 | "Use 'intremap=no_x2apic_optout' to override BIOS request.\n"); | ||
543 | } | 562 | } |
544 | 563 | ||
545 | for_each_drhd_unit(drhd) { | 564 | for_each_drhd_unit(drhd) { |
@@ -578,7 +597,7 @@ static int __init intel_enable_irq_remapping(void) | |||
578 | if (eim && !ecap_eim_support(iommu->ecap)) { | 597 | if (eim && !ecap_eim_support(iommu->ecap)) { |
579 | printk(KERN_INFO "DRHD %Lx: EIM not supported by DRHD, " | 598 | printk(KERN_INFO "DRHD %Lx: EIM not supported by DRHD, " |
580 | " ecap %Lx\n", drhd->reg_base_addr, iommu->ecap); | 599 | " ecap %Lx\n", drhd->reg_base_addr, iommu->ecap); |
581 | return -1; | 600 | goto error; |
582 | } | 601 | } |
583 | } | 602 | } |
584 | 603 | ||
@@ -594,7 +613,7 @@ static int __init intel_enable_irq_remapping(void) | |||
594 | printk(KERN_ERR "DRHD %Lx: failed to enable queued, " | 613 | printk(KERN_ERR "DRHD %Lx: failed to enable queued, " |
595 | " invalidation, ecap %Lx, ret %d\n", | 614 | " invalidation, ecap %Lx, ret %d\n", |
596 | drhd->reg_base_addr, iommu->ecap, ret); | 615 | drhd->reg_base_addr, iommu->ecap, ret); |
597 | return -1; | 616 | goto error; |
598 | } | 617 | } |
599 | } | 618 | } |
600 | 619 | ||
@@ -617,6 +636,14 @@ static int __init intel_enable_irq_remapping(void) | |||
617 | goto error; | 636 | goto error; |
618 | 637 | ||
619 | irq_remapping_enabled = 1; | 638 | irq_remapping_enabled = 1; |
639 | |||
640 | /* | ||
641 | * VT-d has a different layout for IO-APIC entries when | ||
642 | * interrupt remapping is enabled. So it needs a special routine | ||
643 | * to print IO-APIC entries for debugging purposes too. | ||
644 | */ | ||
645 | x86_io_apic_ops.print_entries = intel_ir_io_apic_print_entries; | ||
646 | |||
620 | pr_info("Enabled IRQ remapping in %s mode\n", eim ? "x2apic" : "xapic"); | 647 | pr_info("Enabled IRQ remapping in %s mode\n", eim ? "x2apic" : "xapic"); |
621 | 648 | ||
622 | return eim ? IRQ_REMAP_X2APIC_MODE : IRQ_REMAP_XAPIC_MODE; | 649 | return eim ? IRQ_REMAP_X2APIC_MODE : IRQ_REMAP_XAPIC_MODE; |
@@ -625,6 +652,11 @@ error: | |||
625 | /* | 652 | /* |
626 | * handle error condition gracefully here! | 653 | * handle error condition gracefully here! |
627 | */ | 654 | */ |
655 | |||
656 | if (x2apic_present) | ||
657 | WARN(1, KERN_WARNING | ||
658 | "Failed to enable irq remapping. You are vulnerable to irq-injection attacks.\n"); | ||
659 | |||
628 | return -1; | 660 | return -1; |
629 | } | 661 | } |
630 | 662 | ||
diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c index faf85d6e33fe..d56f8c17c5fe 100644 --- a/drivers/iommu/irq_remapping.c +++ b/drivers/iommu/irq_remapping.c | |||
@@ -1,11 +1,18 @@ | |||
1 | #include <linux/seq_file.h> | ||
2 | #include <linux/cpumask.h> | ||
1 | #include <linux/kernel.h> | 3 | #include <linux/kernel.h> |
2 | #include <linux/string.h> | 4 | #include <linux/string.h> |
3 | #include <linux/cpumask.h> | 5 | #include <linux/cpumask.h> |
4 | #include <linux/errno.h> | 6 | #include <linux/errno.h> |
5 | #include <linux/msi.h> | 7 | #include <linux/msi.h> |
8 | #include <linux/irq.h> | ||
9 | #include <linux/pci.h> | ||
6 | 10 | ||
7 | #include <asm/hw_irq.h> | 11 | #include <asm/hw_irq.h> |
8 | #include <asm/irq_remapping.h> | 12 | #include <asm/irq_remapping.h> |
13 | #include <asm/processor.h> | ||
14 | #include <asm/x86_init.h> | ||
15 | #include <asm/apic.h> | ||
9 | 16 | ||
10 | #include "irq_remapping.h" | 17 | #include "irq_remapping.h" |
11 | 18 | ||
@@ -17,6 +24,152 @@ int no_x2apic_optout; | |||
17 | 24 | ||
18 | static struct irq_remap_ops *remap_ops; | 25 | static struct irq_remap_ops *remap_ops; |
19 | 26 | ||
27 | static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec); | ||
28 | static int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq, | ||
29 | int index, int sub_handle); | ||
30 | static int set_remapped_irq_affinity(struct irq_data *data, | ||
31 | const struct cpumask *mask, | ||
32 | bool force); | ||
33 | |||
34 | static bool irq_remapped(struct irq_cfg *cfg) | ||
35 | { | ||
36 | return (cfg->remapped == 1); | ||
37 | } | ||
38 | |||
39 | static void irq_remapping_disable_io_apic(void) | ||
40 | { | ||
41 | /* | ||
42 | * With interrupt-remapping, for now we will use virtual wire A | ||
43 | * mode, as virtual wire B is little complex (need to configure | ||
44 | * both IOAPIC RTE as well as interrupt-remapping table entry). | ||
45 | * As this gets called during crash dump, keep this simple for | ||
46 | * now. | ||
47 | */ | ||
48 | if (cpu_has_apic || apic_from_smp_config()) | ||
49 | disconnect_bsp_APIC(0); | ||
50 | } | ||
51 | |||
52 | static int do_setup_msi_irqs(struct pci_dev *dev, int nvec) | ||
53 | { | ||
54 | int node, ret, sub_handle, index = 0; | ||
55 | unsigned int irq; | ||
56 | struct msi_desc *msidesc; | ||
57 | |||
58 | nvec = __roundup_pow_of_two(nvec); | ||
59 | |||
60 | WARN_ON(!list_is_singular(&dev->msi_list)); | ||
61 | msidesc = list_entry(dev->msi_list.next, struct msi_desc, list); | ||
62 | WARN_ON(msidesc->irq); | ||
63 | WARN_ON(msidesc->msi_attrib.multiple); | ||
64 | |||
65 | node = dev_to_node(&dev->dev); | ||
66 | irq = __create_irqs(get_nr_irqs_gsi(), nvec, node); | ||
67 | if (irq == 0) | ||
68 | return -ENOSPC; | ||
69 | |||
70 | msidesc->msi_attrib.multiple = ilog2(nvec); | ||
71 | for (sub_handle = 0; sub_handle < nvec; sub_handle++) { | ||
72 | if (!sub_handle) { | ||
73 | index = msi_alloc_remapped_irq(dev, irq, nvec); | ||
74 | if (index < 0) { | ||
75 | ret = index; | ||
76 | goto error; | ||
77 | } | ||
78 | } else { | ||
79 | ret = msi_setup_remapped_irq(dev, irq + sub_handle, | ||
80 | index, sub_handle); | ||
81 | if (ret < 0) | ||
82 | goto error; | ||
83 | } | ||
84 | ret = setup_msi_irq(dev, msidesc, irq, sub_handle); | ||
85 | if (ret < 0) | ||
86 | goto error; | ||
87 | } | ||
88 | return 0; | ||
89 | |||
90 | error: | ||
91 | destroy_irqs(irq, nvec); | ||
92 | |||
93 | /* | ||
94 | * Restore altered MSI descriptor fields and prevent just destroyed | ||
95 | * IRQs from tearing down again in default_teardown_msi_irqs() | ||
96 | */ | ||
97 | msidesc->irq = 0; | ||
98 | msidesc->msi_attrib.multiple = 0; | ||
99 | |||
100 | return ret; | ||
101 | } | ||
102 | |||
103 | static int do_setup_msix_irqs(struct pci_dev *dev, int nvec) | ||
104 | { | ||
105 | int node, ret, sub_handle, index = 0; | ||
106 | struct msi_desc *msidesc; | ||
107 | unsigned int irq; | ||
108 | |||
109 | node = dev_to_node(&dev->dev); | ||
110 | irq = get_nr_irqs_gsi(); | ||
111 | sub_handle = 0; | ||
112 | |||
113 | list_for_each_entry(msidesc, &dev->msi_list, list) { | ||
114 | |||
115 | irq = create_irq_nr(irq, node); | ||
116 | if (irq == 0) | ||
117 | return -1; | ||
118 | |||
119 | if (sub_handle == 0) | ||
120 | ret = index = msi_alloc_remapped_irq(dev, irq, nvec); | ||
121 | else | ||
122 | ret = msi_setup_remapped_irq(dev, irq, index, sub_handle); | ||
123 | |||
124 | if (ret < 0) | ||
125 | goto error; | ||
126 | |||
127 | ret = setup_msi_irq(dev, msidesc, irq, 0); | ||
128 | if (ret < 0) | ||
129 | goto error; | ||
130 | |||
131 | sub_handle += 1; | ||
132 | irq += 1; | ||
133 | } | ||
134 | |||
135 | return 0; | ||
136 | |||
137 | error: | ||
138 | destroy_irq(irq); | ||
139 | return ret; | ||
140 | } | ||
141 | |||
142 | static int irq_remapping_setup_msi_irqs(struct pci_dev *dev, | ||
143 | int nvec, int type) | ||
144 | { | ||
145 | if (type == PCI_CAP_ID_MSI) | ||
146 | return do_setup_msi_irqs(dev, nvec); | ||
147 | else | ||
148 | return do_setup_msix_irqs(dev, nvec); | ||
149 | } | ||
150 | |||
151 | void eoi_ioapic_pin_remapped(int apic, int pin, int vector) | ||
152 | { | ||
153 | /* | ||
154 | * Intr-remapping uses pin number as the virtual vector | ||
155 | * in the RTE. Actual vector is programmed in | ||
156 | * intr-remapping table entry. Hence for the io-apic | ||
157 | * EOI we use the pin number. | ||
158 | */ | ||
159 | io_apic_eoi(apic, pin); | ||
160 | } | ||
161 | |||
162 | static void __init irq_remapping_modify_x86_ops(void) | ||
163 | { | ||
164 | x86_io_apic_ops.disable = irq_remapping_disable_io_apic; | ||
165 | x86_io_apic_ops.set_affinity = set_remapped_irq_affinity; | ||
166 | x86_io_apic_ops.setup_entry = setup_ioapic_remapped_entry; | ||
167 | x86_io_apic_ops.eoi_ioapic_pin = eoi_ioapic_pin_remapped; | ||
168 | x86_msi.setup_msi_irqs = irq_remapping_setup_msi_irqs; | ||
169 | x86_msi.setup_hpet_msi = setup_hpet_msi_remapped; | ||
170 | x86_msi.compose_msi_msg = compose_remapped_msi_msg; | ||
171 | } | ||
172 | |||
20 | static __init int setup_nointremap(char *str) | 173 | static __init int setup_nointremap(char *str) |
21 | { | 174 | { |
22 | disable_irq_remap = 1; | 175 | disable_irq_remap = 1; |
@@ -79,15 +232,24 @@ int __init irq_remapping_prepare(void) | |||
79 | 232 | ||
80 | int __init irq_remapping_enable(void) | 233 | int __init irq_remapping_enable(void) |
81 | { | 234 | { |
235 | int ret; | ||
236 | |||
82 | if (!remap_ops || !remap_ops->enable) | 237 | if (!remap_ops || !remap_ops->enable) |
83 | return -ENODEV; | 238 | return -ENODEV; |
84 | 239 | ||
85 | return remap_ops->enable(); | 240 | ret = remap_ops->enable(); |
241 | |||
242 | if (irq_remapping_enabled) | ||
243 | irq_remapping_modify_x86_ops(); | ||
244 | |||
245 | return ret; | ||
86 | } | 246 | } |
87 | 247 | ||
88 | void irq_remapping_disable(void) | 248 | void irq_remapping_disable(void) |
89 | { | 249 | { |
90 | if (!remap_ops || !remap_ops->disable) | 250 | if (!irq_remapping_enabled || |
251 | !remap_ops || | ||
252 | !remap_ops->disable) | ||
91 | return; | 253 | return; |
92 | 254 | ||
93 | remap_ops->disable(); | 255 | remap_ops->disable(); |
@@ -95,7 +257,9 @@ void irq_remapping_disable(void) | |||
95 | 257 | ||
96 | int irq_remapping_reenable(int mode) | 258 | int irq_remapping_reenable(int mode) |
97 | { | 259 | { |
98 | if (!remap_ops || !remap_ops->reenable) | 260 | if (!irq_remapping_enabled || |
261 | !remap_ops || | ||
262 | !remap_ops->reenable) | ||
99 | return 0; | 263 | return 0; |
100 | 264 | ||
101 | return remap_ops->reenable(mode); | 265 | return remap_ops->reenable(mode); |
@@ -103,6 +267,9 @@ int irq_remapping_reenable(int mode) | |||
103 | 267 | ||
104 | int __init irq_remap_enable_fault_handling(void) | 268 | int __init irq_remap_enable_fault_handling(void) |
105 | { | 269 | { |
270 | if (!irq_remapping_enabled) | ||
271 | return 0; | ||
272 | |||
106 | if (!remap_ops || !remap_ops->enable_faulting) | 273 | if (!remap_ops || !remap_ops->enable_faulting) |
107 | return -ENODEV; | 274 | return -ENODEV; |
108 | 275 | ||
@@ -133,23 +300,28 @@ int set_remapped_irq_affinity(struct irq_data *data, const struct cpumask *mask, | |||
133 | 300 | ||
134 | void free_remapped_irq(int irq) | 301 | void free_remapped_irq(int irq) |
135 | { | 302 | { |
303 | struct irq_cfg *cfg = irq_get_chip_data(irq); | ||
304 | |||
136 | if (!remap_ops || !remap_ops->free_irq) | 305 | if (!remap_ops || !remap_ops->free_irq) |
137 | return; | 306 | return; |
138 | 307 | ||
139 | remap_ops->free_irq(irq); | 308 | if (irq_remapped(cfg)) |
309 | remap_ops->free_irq(irq); | ||
140 | } | 310 | } |
141 | 311 | ||
142 | void compose_remapped_msi_msg(struct pci_dev *pdev, | 312 | void compose_remapped_msi_msg(struct pci_dev *pdev, |
143 | unsigned int irq, unsigned int dest, | 313 | unsigned int irq, unsigned int dest, |
144 | struct msi_msg *msg, u8 hpet_id) | 314 | struct msi_msg *msg, u8 hpet_id) |
145 | { | 315 | { |
146 | if (!remap_ops || !remap_ops->compose_msi_msg) | 316 | struct irq_cfg *cfg = irq_get_chip_data(irq); |
147 | return; | ||
148 | 317 | ||
149 | remap_ops->compose_msi_msg(pdev, irq, dest, msg, hpet_id); | 318 | if (!irq_remapped(cfg)) |
319 | native_compose_msi_msg(pdev, irq, dest, msg, hpet_id); | ||
320 | else if (remap_ops && remap_ops->compose_msi_msg) | ||
321 | remap_ops->compose_msi_msg(pdev, irq, dest, msg, hpet_id); | ||
150 | } | 322 | } |
151 | 323 | ||
152 | int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec) | 324 | static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec) |
153 | { | 325 | { |
154 | if (!remap_ops || !remap_ops->msi_alloc_irq) | 326 | if (!remap_ops || !remap_ops->msi_alloc_irq) |
155 | return -ENODEV; | 327 | return -ENODEV; |
@@ -157,8 +329,8 @@ int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec) | |||
157 | return remap_ops->msi_alloc_irq(pdev, irq, nvec); | 329 | return remap_ops->msi_alloc_irq(pdev, irq, nvec); |
158 | } | 330 | } |
159 | 331 | ||
160 | int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq, | 332 | static int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq, |
161 | int index, int sub_handle) | 333 | int index, int sub_handle) |
162 | { | 334 | { |
163 | if (!remap_ops || !remap_ops->msi_setup_irq) | 335 | if (!remap_ops || !remap_ops->msi_setup_irq) |
164 | return -ENODEV; | 336 | return -ENODEV; |
@@ -173,3 +345,42 @@ int setup_hpet_msi_remapped(unsigned int irq, unsigned int id) | |||
173 | 345 | ||
174 | return remap_ops->setup_hpet_msi(irq, id); | 346 | return remap_ops->setup_hpet_msi(irq, id); |
175 | } | 347 | } |
348 | |||
349 | void panic_if_irq_remap(const char *msg) | ||
350 | { | ||
351 | if (irq_remapping_enabled) | ||
352 | panic(msg); | ||
353 | } | ||
354 | |||
355 | static void ir_ack_apic_edge(struct irq_data *data) | ||
356 | { | ||
357 | ack_APIC_irq(); | ||
358 | } | ||
359 | |||
360 | static void ir_ack_apic_level(struct irq_data *data) | ||
361 | { | ||
362 | ack_APIC_irq(); | ||
363 | eoi_ioapic_irq(data->irq, data->chip_data); | ||
364 | } | ||
365 | |||
366 | static void ir_print_prefix(struct irq_data *data, struct seq_file *p) | ||
367 | { | ||
368 | seq_printf(p, " IR-%s", data->chip->name); | ||
369 | } | ||
370 | |||
371 | void irq_remap_modify_chip_defaults(struct irq_chip *chip) | ||
372 | { | ||
373 | chip->irq_print_chip = ir_print_prefix; | ||
374 | chip->irq_ack = ir_ack_apic_edge; | ||
375 | chip->irq_eoi = ir_ack_apic_level; | ||
376 | chip->irq_set_affinity = x86_io_apic_ops.set_affinity; | ||
377 | } | ||
378 | |||
379 | bool setup_remapped_irq(int irq, struct irq_cfg *cfg, struct irq_chip *chip) | ||
380 | { | ||
381 | if (!irq_remapped(cfg)) | ||
382 | return false; | ||
383 | irq_set_status_flags(irq, IRQ_MOVE_PCNTXT); | ||
384 | irq_remap_modify_chip_defaults(chip); | ||
385 | return true; | ||
386 | } | ||
diff --git a/drivers/iommu/irq_remapping.h b/drivers/iommu/irq_remapping.h index 95363acb583f..ecb637670405 100644 --- a/drivers/iommu/irq_remapping.h +++ b/drivers/iommu/irq_remapping.h | |||
@@ -34,6 +34,7 @@ struct msi_msg; | |||
34 | extern int disable_irq_remap; | 34 | extern int disable_irq_remap; |
35 | extern int disable_sourceid_checking; | 35 | extern int disable_sourceid_checking; |
36 | extern int no_x2apic_optout; | 36 | extern int no_x2apic_optout; |
37 | extern int irq_remapping_enabled; | ||
37 | 38 | ||
38 | struct irq_remap_ops { | 39 | struct irq_remap_ops { |
39 | /* Check whether Interrupt Remapping is supported */ | 40 | /* Check whether Interrupt Remapping is supported */ |
diff --git a/drivers/isdn/mISDN/stack.c b/drivers/isdn/mISDN/stack.c index 5f21f629b7ae..deda591f70b9 100644 --- a/drivers/isdn/mISDN/stack.c +++ b/drivers/isdn/mISDN/stack.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
19 | #include <linux/mISDNif.h> | 19 | #include <linux/mISDNif.h> |
20 | #include <linux/kthread.h> | 20 | #include <linux/kthread.h> |
21 | #include <linux/sched.h> | ||
21 | #include "core.h" | 22 | #include "core.h" |
22 | 23 | ||
23 | static u_int *debug; | 24 | static u_int *debug; |
@@ -202,6 +203,9 @@ static int | |||
202 | mISDNStackd(void *data) | 203 | mISDNStackd(void *data) |
203 | { | 204 | { |
204 | struct mISDNstack *st = data; | 205 | struct mISDNstack *st = data; |
206 | #ifdef MISDN_MSG_STATS | ||
207 | cputime_t utime, stime; | ||
208 | #endif | ||
205 | int err = 0; | 209 | int err = 0; |
206 | 210 | ||
207 | sigfillset(¤t->blocked); | 211 | sigfillset(¤t->blocked); |
@@ -303,9 +307,10 @@ mISDNStackd(void *data) | |||
303 | "msg %d sleep %d stopped\n", | 307 | "msg %d sleep %d stopped\n", |
304 | dev_name(&st->dev->dev), st->msg_cnt, st->sleep_cnt, | 308 | dev_name(&st->dev->dev), st->msg_cnt, st->sleep_cnt, |
305 | st->stopped_cnt); | 309 | st->stopped_cnt); |
310 | task_cputime(st->thread, &utime, &stime); | ||
306 | printk(KERN_DEBUG | 311 | printk(KERN_DEBUG |
307 | "mISDNStackd daemon for %s utime(%ld) stime(%ld)\n", | 312 | "mISDNStackd daemon for %s utime(%ld) stime(%ld)\n", |
308 | dev_name(&st->dev->dev), st->thread->utime, st->thread->stime); | 313 | dev_name(&st->dev->dev), utime, stime); |
309 | printk(KERN_DEBUG | 314 | printk(KERN_DEBUG |
310 | "mISDNStackd daemon for %s nvcsw(%ld) nivcsw(%ld)\n", | 315 | "mISDNStackd daemon for %s nvcsw(%ld) nivcsw(%ld)\n", |
311 | dev_name(&st->dev->dev), st->thread->nvcsw, st->thread->nivcsw); | 316 | dev_name(&st->dev->dev), st->thread->nvcsw, st->thread->nivcsw); |
diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 49d95040096a..0223ad255cb4 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c | |||
@@ -1820,7 +1820,7 @@ static int dvb_frontend_ioctl(struct file *file, | |||
1820 | struct dvb_frontend *fe = dvbdev->priv; | 1820 | struct dvb_frontend *fe = dvbdev->priv; |
1821 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | 1821 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
1822 | struct dvb_frontend_private *fepriv = fe->frontend_priv; | 1822 | struct dvb_frontend_private *fepriv = fe->frontend_priv; |
1823 | int err = -ENOTTY; | 1823 | int err = -EOPNOTSUPP; |
1824 | 1824 | ||
1825 | dev_dbg(fe->dvb->device, "%s: (%d)\n", __func__, _IOC_NR(cmd)); | 1825 | dev_dbg(fe->dvb->device, "%s: (%d)\n", __func__, _IOC_NR(cmd)); |
1826 | if (fepriv->exit != DVB_FE_NO_EXIT) | 1826 | if (fepriv->exit != DVB_FE_NO_EXIT) |
@@ -1938,7 +1938,7 @@ static int dvb_frontend_ioctl_properties(struct file *file, | |||
1938 | } | 1938 | } |
1939 | 1939 | ||
1940 | } else | 1940 | } else |
1941 | err = -ENOTTY; | 1941 | err = -EOPNOTSUPP; |
1942 | 1942 | ||
1943 | out: | 1943 | out: |
1944 | kfree(tvp); | 1944 | kfree(tvp); |
@@ -2071,7 +2071,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file, | |||
2071 | struct dvb_frontend *fe = dvbdev->priv; | 2071 | struct dvb_frontend *fe = dvbdev->priv; |
2072 | struct dvb_frontend_private *fepriv = fe->frontend_priv; | 2072 | struct dvb_frontend_private *fepriv = fe->frontend_priv; |
2073 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | 2073 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
2074 | int err = -ENOTTY; | 2074 | int err = -EOPNOTSUPP; |
2075 | 2075 | ||
2076 | switch (cmd) { | 2076 | switch (cmd) { |
2077 | case FE_GET_INFO: { | 2077 | case FE_GET_INFO: { |
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c index 56d3f697e0c7..0035c01660b6 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c | |||
@@ -21,7 +21,7 @@ | |||
21 | 21 | ||
22 | #include "atl1c.h" | 22 | #include "atl1c.h" |
23 | 23 | ||
24 | #define ATL1C_DRV_VERSION "1.0.1.0-NAPI" | 24 | #define ATL1C_DRV_VERSION "1.0.1.1-NAPI" |
25 | char atl1c_driver_name[] = "atl1c"; | 25 | char atl1c_driver_name[] = "atl1c"; |
26 | char atl1c_driver_version[] = ATL1C_DRV_VERSION; | 26 | char atl1c_driver_version[] = ATL1C_DRV_VERSION; |
27 | 27 | ||
@@ -1652,6 +1652,7 @@ static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter) | |||
1652 | u16 num_alloc = 0; | 1652 | u16 num_alloc = 0; |
1653 | u16 rfd_next_to_use, next_next; | 1653 | u16 rfd_next_to_use, next_next; |
1654 | struct atl1c_rx_free_desc *rfd_desc; | 1654 | struct atl1c_rx_free_desc *rfd_desc; |
1655 | dma_addr_t mapping; | ||
1655 | 1656 | ||
1656 | next_next = rfd_next_to_use = rfd_ring->next_to_use; | 1657 | next_next = rfd_next_to_use = rfd_ring->next_to_use; |
1657 | if (++next_next == rfd_ring->count) | 1658 | if (++next_next == rfd_ring->count) |
@@ -1678,9 +1679,18 @@ static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter) | |||
1678 | ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_BUSY); | 1679 | ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_BUSY); |
1679 | buffer_info->skb = skb; | 1680 | buffer_info->skb = skb; |
1680 | buffer_info->length = adapter->rx_buffer_len; | 1681 | buffer_info->length = adapter->rx_buffer_len; |
1681 | buffer_info->dma = pci_map_single(pdev, vir_addr, | 1682 | mapping = pci_map_single(pdev, vir_addr, |
1682 | buffer_info->length, | 1683 | buffer_info->length, |
1683 | PCI_DMA_FROMDEVICE); | 1684 | PCI_DMA_FROMDEVICE); |
1685 | if (unlikely(pci_dma_mapping_error(pdev, mapping))) { | ||
1686 | dev_kfree_skb(skb); | ||
1687 | buffer_info->skb = NULL; | ||
1688 | buffer_info->length = 0; | ||
1689 | ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_FREE); | ||
1690 | netif_warn(adapter, rx_err, adapter->netdev, "RX pci_map_single failed"); | ||
1691 | break; | ||
1692 | } | ||
1693 | buffer_info->dma = mapping; | ||
1684 | ATL1C_SET_PCIMAP_TYPE(buffer_info, ATL1C_PCIMAP_SINGLE, | 1694 | ATL1C_SET_PCIMAP_TYPE(buffer_info, ATL1C_PCIMAP_SINGLE, |
1685 | ATL1C_PCIMAP_FROMDEVICE); | 1695 | ATL1C_PCIMAP_FROMDEVICE); |
1686 | rfd_desc->buffer_addr = cpu_to_le64(buffer_info->dma); | 1696 | rfd_desc->buffer_addr = cpu_to_le64(buffer_info->dma); |
@@ -2015,7 +2025,29 @@ check_sum: | |||
2015 | return 0; | 2025 | return 0; |
2016 | } | 2026 | } |
2017 | 2027 | ||
2018 | static void atl1c_tx_map(struct atl1c_adapter *adapter, | 2028 | static void atl1c_tx_rollback(struct atl1c_adapter *adpt, |
2029 | struct atl1c_tpd_desc *first_tpd, | ||
2030 | enum atl1c_trans_queue type) | ||
2031 | { | ||
2032 | struct atl1c_tpd_ring *tpd_ring = &adpt->tpd_ring[type]; | ||
2033 | struct atl1c_buffer *buffer_info; | ||
2034 | struct atl1c_tpd_desc *tpd; | ||
2035 | u16 first_index, index; | ||
2036 | |||
2037 | first_index = first_tpd - (struct atl1c_tpd_desc *)tpd_ring->desc; | ||
2038 | index = first_index; | ||
2039 | while (index != tpd_ring->next_to_use) { | ||
2040 | tpd = ATL1C_TPD_DESC(tpd_ring, index); | ||
2041 | buffer_info = &tpd_ring->buffer_info[index]; | ||
2042 | atl1c_clean_buffer(adpt->pdev, buffer_info, 0); | ||
2043 | memset(tpd, 0, sizeof(struct atl1c_tpd_desc)); | ||
2044 | if (++index == tpd_ring->count) | ||
2045 | index = 0; | ||
2046 | } | ||
2047 | tpd_ring->next_to_use = first_index; | ||
2048 | } | ||
2049 | |||
2050 | static int atl1c_tx_map(struct atl1c_adapter *adapter, | ||
2019 | struct sk_buff *skb, struct atl1c_tpd_desc *tpd, | 2051 | struct sk_buff *skb, struct atl1c_tpd_desc *tpd, |
2020 | enum atl1c_trans_queue type) | 2052 | enum atl1c_trans_queue type) |
2021 | { | 2053 | { |
@@ -2040,7 +2072,10 @@ static void atl1c_tx_map(struct atl1c_adapter *adapter, | |||
2040 | buffer_info->length = map_len; | 2072 | buffer_info->length = map_len; |
2041 | buffer_info->dma = pci_map_single(adapter->pdev, | 2073 | buffer_info->dma = pci_map_single(adapter->pdev, |
2042 | skb->data, hdr_len, PCI_DMA_TODEVICE); | 2074 | skb->data, hdr_len, PCI_DMA_TODEVICE); |
2043 | ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_BUSY); | 2075 | if (unlikely(pci_dma_mapping_error(adapter->pdev, |
2076 | buffer_info->dma))) | ||
2077 | goto err_dma; | ||
2078 | |||
2044 | ATL1C_SET_PCIMAP_TYPE(buffer_info, ATL1C_PCIMAP_SINGLE, | 2079 | ATL1C_SET_PCIMAP_TYPE(buffer_info, ATL1C_PCIMAP_SINGLE, |
2045 | ATL1C_PCIMAP_TODEVICE); | 2080 | ATL1C_PCIMAP_TODEVICE); |
2046 | mapped_len += map_len; | 2081 | mapped_len += map_len; |
@@ -2062,6 +2097,10 @@ static void atl1c_tx_map(struct atl1c_adapter *adapter, | |||
2062 | buffer_info->dma = | 2097 | buffer_info->dma = |
2063 | pci_map_single(adapter->pdev, skb->data + mapped_len, | 2098 | pci_map_single(adapter->pdev, skb->data + mapped_len, |
2064 | buffer_info->length, PCI_DMA_TODEVICE); | 2099 | buffer_info->length, PCI_DMA_TODEVICE); |
2100 | if (unlikely(pci_dma_mapping_error(adapter->pdev, | ||
2101 | buffer_info->dma))) | ||
2102 | goto err_dma; | ||
2103 | |||
2065 | ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_BUSY); | 2104 | ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_BUSY); |
2066 | ATL1C_SET_PCIMAP_TYPE(buffer_info, ATL1C_PCIMAP_SINGLE, | 2105 | ATL1C_SET_PCIMAP_TYPE(buffer_info, ATL1C_PCIMAP_SINGLE, |
2067 | ATL1C_PCIMAP_TODEVICE); | 2106 | ATL1C_PCIMAP_TODEVICE); |
@@ -2083,6 +2122,9 @@ static void atl1c_tx_map(struct atl1c_adapter *adapter, | |||
2083 | frag, 0, | 2122 | frag, 0, |
2084 | buffer_info->length, | 2123 | buffer_info->length, |
2085 | DMA_TO_DEVICE); | 2124 | DMA_TO_DEVICE); |
2125 | if (dma_mapping_error(&adapter->pdev->dev, buffer_info->dma)) | ||
2126 | goto err_dma; | ||
2127 | |||
2086 | ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_BUSY); | 2128 | ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_BUSY); |
2087 | ATL1C_SET_PCIMAP_TYPE(buffer_info, ATL1C_PCIMAP_PAGE, | 2129 | ATL1C_SET_PCIMAP_TYPE(buffer_info, ATL1C_PCIMAP_PAGE, |
2088 | ATL1C_PCIMAP_TODEVICE); | 2130 | ATL1C_PCIMAP_TODEVICE); |
@@ -2095,6 +2137,13 @@ static void atl1c_tx_map(struct atl1c_adapter *adapter, | |||
2095 | /* The last buffer info contain the skb address, | 2137 | /* The last buffer info contain the skb address, |
2096 | so it will be free after unmap */ | 2138 | so it will be free after unmap */ |
2097 | buffer_info->skb = skb; | 2139 | buffer_info->skb = skb; |
2140 | |||
2141 | return 0; | ||
2142 | |||
2143 | err_dma: | ||
2144 | buffer_info->dma = 0; | ||
2145 | buffer_info->length = 0; | ||
2146 | return -1; | ||
2098 | } | 2147 | } |
2099 | 2148 | ||
2100 | static void atl1c_tx_queue(struct atl1c_adapter *adapter, struct sk_buff *skb, | 2149 | static void atl1c_tx_queue(struct atl1c_adapter *adapter, struct sk_buff *skb, |
@@ -2157,10 +2206,18 @@ static netdev_tx_t atl1c_xmit_frame(struct sk_buff *skb, | |||
2157 | if (skb_network_offset(skb) != ETH_HLEN) | 2206 | if (skb_network_offset(skb) != ETH_HLEN) |
2158 | tpd->word1 |= 1 << TPD_ETH_TYPE_SHIFT; /* Ethernet frame */ | 2207 | tpd->word1 |= 1 << TPD_ETH_TYPE_SHIFT; /* Ethernet frame */ |
2159 | 2208 | ||
2160 | atl1c_tx_map(adapter, skb, tpd, type); | 2209 | if (atl1c_tx_map(adapter, skb, tpd, type) < 0) { |
2161 | atl1c_tx_queue(adapter, skb, tpd, type); | 2210 | netif_info(adapter, tx_done, adapter->netdev, |
2211 | "tx-skb droppted due to dma error\n"); | ||
2212 | /* roll back tpd/buffer */ | ||
2213 | atl1c_tx_rollback(adapter, tpd, type); | ||
2214 | spin_unlock_irqrestore(&adapter->tx_lock, flags); | ||
2215 | dev_kfree_skb(skb); | ||
2216 | } else { | ||
2217 | atl1c_tx_queue(adapter, skb, tpd, type); | ||
2218 | spin_unlock_irqrestore(&adapter->tx_lock, flags); | ||
2219 | } | ||
2162 | 2220 | ||
2163 | spin_unlock_irqrestore(&adapter->tx_lock, flags); | ||
2164 | return NETDEV_TX_OK; | 2221 | return NETDEV_TX_OK; |
2165 | } | 2222 | } |
2166 | 2223 | ||
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index f771ddfba646..a5edac8df67b 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | |||
@@ -504,13 +504,11 @@ static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp, | |||
504 | skb_shinfo(skb)->gso_size = bnx2x_set_lro_mss(bp, | 504 | skb_shinfo(skb)->gso_size = bnx2x_set_lro_mss(bp, |
505 | tpa_info->parsing_flags, len_on_bd); | 505 | tpa_info->parsing_flags, len_on_bd); |
506 | 506 | ||
507 | /* set for GRO */ | 507 | skb_shinfo(skb)->gso_type = |
508 | if (fp->mode == TPA_MODE_GRO) | 508 | (GET_FLAG(tpa_info->parsing_flags, |
509 | skb_shinfo(skb)->gso_type = | 509 | PARSING_FLAGS_OVER_ETHERNET_PROTOCOL) == |
510 | (GET_FLAG(tpa_info->parsing_flags, | 510 | PRS_FLAG_OVERETH_IPV6) ? |
511 | PARSING_FLAGS_OVER_ETHERNET_PROTOCOL) == | 511 | SKB_GSO_TCPV6 : SKB_GSO_TCPV4; |
512 | PRS_FLAG_OVERETH_IPV6) ? | ||
513 | SKB_GSO_TCPV6 : SKB_GSO_TCPV4; | ||
514 | } | 512 | } |
515 | 513 | ||
516 | 514 | ||
diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index a9b0830fb39d..b9d4bb9530e5 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c | |||
@@ -693,6 +693,11 @@ static int macb_poll(struct napi_struct *napi, int budget) | |||
693 | * get notified when new packets arrive. | 693 | * get notified when new packets arrive. |
694 | */ | 694 | */ |
695 | macb_writel(bp, IER, MACB_RX_INT_FLAGS); | 695 | macb_writel(bp, IER, MACB_RX_INT_FLAGS); |
696 | |||
697 | /* Packets received while interrupts were disabled */ | ||
698 | status = macb_readl(bp, RSR); | ||
699 | if (unlikely(status)) | ||
700 | napi_reschedule(napi); | ||
696 | } | 701 | } |
697 | 702 | ||
698 | /* TODO: Handle errors */ | 703 | /* TODO: Handle errors */ |
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 20a5af6d87d0..b3e3294cfe53 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | |||
@@ -1401,6 +1401,7 @@ static void ixgbe_set_rsc_gso_size(struct ixgbe_ring *ring, | |||
1401 | /* set gso_size to avoid messing up TCP MSS */ | 1401 | /* set gso_size to avoid messing up TCP MSS */ |
1402 | skb_shinfo(skb)->gso_size = DIV_ROUND_UP((skb->len - hdr_len), | 1402 | skb_shinfo(skb)->gso_size = DIV_ROUND_UP((skb->len - hdr_len), |
1403 | IXGBE_CB(skb)->append_cnt); | 1403 | IXGBE_CB(skb)->append_cnt); |
1404 | skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4; | ||
1404 | } | 1405 | } |
1405 | 1406 | ||
1406 | static void ixgbe_update_rsc_stats(struct ixgbe_ring *rx_ring, | 1407 | static void ixgbe_update_rsc_stats(struct ixgbe_ring *rx_ring, |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c index 6f82812d0fab..09aa310b6194 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c | |||
@@ -986,8 +986,13 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter, | |||
986 | th->seq = htonl(seq_number); | 986 | th->seq = htonl(seq_number); |
987 | length = skb->len; | 987 | length = skb->len; |
988 | 988 | ||
989 | if (adapter->flags & QLCNIC_FW_LRO_MSS_CAP) | 989 | if (adapter->flags & QLCNIC_FW_LRO_MSS_CAP) { |
990 | skb_shinfo(skb)->gso_size = qlcnic_get_lro_sts_mss(sts_data1); | 990 | skb_shinfo(skb)->gso_size = qlcnic_get_lro_sts_mss(sts_data1); |
991 | if (skb->protocol == htons(ETH_P_IPV6)) | ||
992 | skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6; | ||
993 | else | ||
994 | skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4; | ||
995 | } | ||
991 | 996 | ||
992 | if (vid != 0xffff) | 997 | if (vid != 0xffff) |
993 | __vlan_hwaccel_put_tag(skb, vid); | 998 | __vlan_hwaccel_put_tag(skb, vid); |
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 11702324a071..998974f78742 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c | |||
@@ -450,7 +450,6 @@ enum rtl8168_registers { | |||
450 | #define PWM_EN (1 << 22) | 450 | #define PWM_EN (1 << 22) |
451 | #define RXDV_GATED_EN (1 << 19) | 451 | #define RXDV_GATED_EN (1 << 19) |
452 | #define EARLY_TALLY_EN (1 << 16) | 452 | #define EARLY_TALLY_EN (1 << 16) |
453 | #define FORCE_CLK (1 << 15) /* force clock request */ | ||
454 | }; | 453 | }; |
455 | 454 | ||
456 | enum rtl_register_content { | 455 | enum rtl_register_content { |
@@ -514,7 +513,6 @@ enum rtl_register_content { | |||
514 | PMEnable = (1 << 0), /* Power Management Enable */ | 513 | PMEnable = (1 << 0), /* Power Management Enable */ |
515 | 514 | ||
516 | /* Config2 register p. 25 */ | 515 | /* Config2 register p. 25 */ |
517 | ClkReqEn = (1 << 7), /* Clock Request Enable */ | ||
518 | MSIEnable = (1 << 5), /* 8169 only. Reserved in the 8168. */ | 516 | MSIEnable = (1 << 5), /* 8169 only. Reserved in the 8168. */ |
519 | PCI_Clock_66MHz = 0x01, | 517 | PCI_Clock_66MHz = 0x01, |
520 | PCI_Clock_33MHz = 0x00, | 518 | PCI_Clock_33MHz = 0x00, |
@@ -535,7 +533,6 @@ enum rtl_register_content { | |||
535 | Spi_en = (1 << 3), | 533 | Spi_en = (1 << 3), |
536 | LanWake = (1 << 1), /* LanWake enable/disable */ | 534 | LanWake = (1 << 1), /* LanWake enable/disable */ |
537 | PMEStatus = (1 << 0), /* PME status can be reset by PCI RST# */ | 535 | PMEStatus = (1 << 0), /* PME status can be reset by PCI RST# */ |
538 | ASPM_en = (1 << 0), /* ASPM enable */ | ||
539 | 536 | ||
540 | /* TBICSR p.28 */ | 537 | /* TBICSR p.28 */ |
541 | TBIReset = 0x80000000, | 538 | TBIReset = 0x80000000, |
@@ -684,7 +681,6 @@ enum features { | |||
684 | RTL_FEATURE_WOL = (1 << 0), | 681 | RTL_FEATURE_WOL = (1 << 0), |
685 | RTL_FEATURE_MSI = (1 << 1), | 682 | RTL_FEATURE_MSI = (1 << 1), |
686 | RTL_FEATURE_GMII = (1 << 2), | 683 | RTL_FEATURE_GMII = (1 << 2), |
687 | RTL_FEATURE_FW_LOADED = (1 << 3), | ||
688 | }; | 684 | }; |
689 | 685 | ||
690 | struct rtl8169_counters { | 686 | struct rtl8169_counters { |
@@ -2389,10 +2385,8 @@ static void rtl_apply_firmware(struct rtl8169_private *tp) | |||
2389 | struct rtl_fw *rtl_fw = tp->rtl_fw; | 2385 | struct rtl_fw *rtl_fw = tp->rtl_fw; |
2390 | 2386 | ||
2391 | /* TODO: release firmware once rtl_phy_write_fw signals failures. */ | 2387 | /* TODO: release firmware once rtl_phy_write_fw signals failures. */ |
2392 | if (!IS_ERR_OR_NULL(rtl_fw)) { | 2388 | if (!IS_ERR_OR_NULL(rtl_fw)) |
2393 | rtl_phy_write_fw(tp, rtl_fw); | 2389 | rtl_phy_write_fw(tp, rtl_fw); |
2394 | tp->features |= RTL_FEATURE_FW_LOADED; | ||
2395 | } | ||
2396 | } | 2390 | } |
2397 | 2391 | ||
2398 | static void rtl_apply_firmware_cond(struct rtl8169_private *tp, u8 reg, u16 val) | 2392 | static void rtl_apply_firmware_cond(struct rtl8169_private *tp, u8 reg, u16 val) |
@@ -2403,31 +2397,6 @@ static void rtl_apply_firmware_cond(struct rtl8169_private *tp, u8 reg, u16 val) | |||
2403 | rtl_apply_firmware(tp); | 2397 | rtl_apply_firmware(tp); |
2404 | } | 2398 | } |
2405 | 2399 | ||
2406 | static void r810x_aldps_disable(struct rtl8169_private *tp) | ||
2407 | { | ||
2408 | rtl_writephy(tp, 0x1f, 0x0000); | ||
2409 | rtl_writephy(tp, 0x18, 0x0310); | ||
2410 | msleep(100); | ||
2411 | } | ||
2412 | |||
2413 | static void r810x_aldps_enable(struct rtl8169_private *tp) | ||
2414 | { | ||
2415 | if (!(tp->features & RTL_FEATURE_FW_LOADED)) | ||
2416 | return; | ||
2417 | |||
2418 | rtl_writephy(tp, 0x1f, 0x0000); | ||
2419 | rtl_writephy(tp, 0x18, 0x8310); | ||
2420 | } | ||
2421 | |||
2422 | static void r8168_aldps_enable_1(struct rtl8169_private *tp) | ||
2423 | { | ||
2424 | if (!(tp->features & RTL_FEATURE_FW_LOADED)) | ||
2425 | return; | ||
2426 | |||
2427 | rtl_writephy(tp, 0x1f, 0x0000); | ||
2428 | rtl_w1w0_phy(tp, 0x15, 0x1000, 0x0000); | ||
2429 | } | ||
2430 | |||
2431 | static void rtl8169s_hw_phy_config(struct rtl8169_private *tp) | 2400 | static void rtl8169s_hw_phy_config(struct rtl8169_private *tp) |
2432 | { | 2401 | { |
2433 | static const struct phy_reg phy_reg_init[] = { | 2402 | static const struct phy_reg phy_reg_init[] = { |
@@ -3218,8 +3187,6 @@ static void rtl8168e_2_hw_phy_config(struct rtl8169_private *tp) | |||
3218 | rtl_w1w0_phy(tp, 0x10, 0x0000, 0x0400); | 3187 | rtl_w1w0_phy(tp, 0x10, 0x0000, 0x0400); |
3219 | rtl_writephy(tp, 0x1f, 0x0000); | 3188 | rtl_writephy(tp, 0x1f, 0x0000); |
3220 | 3189 | ||
3221 | r8168_aldps_enable_1(tp); | ||
3222 | |||
3223 | /* Broken BIOS workaround: feed GigaMAC registers with MAC address. */ | 3190 | /* Broken BIOS workaround: feed GigaMAC registers with MAC address. */ |
3224 | rtl_rar_exgmac_set(tp, tp->dev->dev_addr); | 3191 | rtl_rar_exgmac_set(tp, tp->dev->dev_addr); |
3225 | } | 3192 | } |
@@ -3294,8 +3261,6 @@ static void rtl8168f_1_hw_phy_config(struct rtl8169_private *tp) | |||
3294 | rtl_writephy(tp, 0x05, 0x8b85); | 3261 | rtl_writephy(tp, 0x05, 0x8b85); |
3295 | rtl_w1w0_phy(tp, 0x06, 0x4000, 0x0000); | 3262 | rtl_w1w0_phy(tp, 0x06, 0x4000, 0x0000); |
3296 | rtl_writephy(tp, 0x1f, 0x0000); | 3263 | rtl_writephy(tp, 0x1f, 0x0000); |
3297 | |||
3298 | r8168_aldps_enable_1(tp); | ||
3299 | } | 3264 | } |
3300 | 3265 | ||
3301 | static void rtl8168f_2_hw_phy_config(struct rtl8169_private *tp) | 3266 | static void rtl8168f_2_hw_phy_config(struct rtl8169_private *tp) |
@@ -3303,8 +3268,6 @@ static void rtl8168f_2_hw_phy_config(struct rtl8169_private *tp) | |||
3303 | rtl_apply_firmware(tp); | 3268 | rtl_apply_firmware(tp); |
3304 | 3269 | ||
3305 | rtl8168f_hw_phy_config(tp); | 3270 | rtl8168f_hw_phy_config(tp); |
3306 | |||
3307 | r8168_aldps_enable_1(tp); | ||
3308 | } | 3271 | } |
3309 | 3272 | ||
3310 | static void rtl8411_hw_phy_config(struct rtl8169_private *tp) | 3273 | static void rtl8411_hw_phy_config(struct rtl8169_private *tp) |
@@ -3402,8 +3365,6 @@ static void rtl8411_hw_phy_config(struct rtl8169_private *tp) | |||
3402 | rtl_w1w0_phy(tp, 0x19, 0x0000, 0x0001); | 3365 | rtl_w1w0_phy(tp, 0x19, 0x0000, 0x0001); |
3403 | rtl_w1w0_phy(tp, 0x10, 0x0000, 0x0400); | 3366 | rtl_w1w0_phy(tp, 0x10, 0x0000, 0x0400); |
3404 | rtl_writephy(tp, 0x1f, 0x0000); | 3367 | rtl_writephy(tp, 0x1f, 0x0000); |
3405 | |||
3406 | r8168_aldps_enable_1(tp); | ||
3407 | } | 3368 | } |
3408 | 3369 | ||
3409 | static void rtl8168g_1_hw_phy_config(struct rtl8169_private *tp) | 3370 | static void rtl8168g_1_hw_phy_config(struct rtl8169_private *tp) |
@@ -3489,19 +3450,21 @@ static void rtl8105e_hw_phy_config(struct rtl8169_private *tp) | |||
3489 | }; | 3450 | }; |
3490 | 3451 | ||
3491 | /* Disable ALDPS before ram code */ | 3452 | /* Disable ALDPS before ram code */ |
3492 | r810x_aldps_disable(tp); | 3453 | rtl_writephy(tp, 0x1f, 0x0000); |
3454 | rtl_writephy(tp, 0x18, 0x0310); | ||
3455 | msleep(100); | ||
3493 | 3456 | ||
3494 | rtl_apply_firmware(tp); | 3457 | rtl_apply_firmware(tp); |
3495 | 3458 | ||
3496 | rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init)); | 3459 | rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init)); |
3497 | |||
3498 | r810x_aldps_enable(tp); | ||
3499 | } | 3460 | } |
3500 | 3461 | ||
3501 | static void rtl8402_hw_phy_config(struct rtl8169_private *tp) | 3462 | static void rtl8402_hw_phy_config(struct rtl8169_private *tp) |
3502 | { | 3463 | { |
3503 | /* Disable ALDPS before setting firmware */ | 3464 | /* Disable ALDPS before setting firmware */ |
3504 | r810x_aldps_disable(tp); | 3465 | rtl_writephy(tp, 0x1f, 0x0000); |
3466 | rtl_writephy(tp, 0x18, 0x0310); | ||
3467 | msleep(20); | ||
3505 | 3468 | ||
3506 | rtl_apply_firmware(tp); | 3469 | rtl_apply_firmware(tp); |
3507 | 3470 | ||
@@ -3511,8 +3474,6 @@ static void rtl8402_hw_phy_config(struct rtl8169_private *tp) | |||
3511 | rtl_writephy(tp, 0x10, 0x401f); | 3474 | rtl_writephy(tp, 0x10, 0x401f); |
3512 | rtl_writephy(tp, 0x19, 0x7030); | 3475 | rtl_writephy(tp, 0x19, 0x7030); |
3513 | rtl_writephy(tp, 0x1f, 0x0000); | 3476 | rtl_writephy(tp, 0x1f, 0x0000); |
3514 | |||
3515 | r810x_aldps_enable(tp); | ||
3516 | } | 3477 | } |
3517 | 3478 | ||
3518 | static void rtl8106e_hw_phy_config(struct rtl8169_private *tp) | 3479 | static void rtl8106e_hw_phy_config(struct rtl8169_private *tp) |
@@ -3525,7 +3486,9 @@ static void rtl8106e_hw_phy_config(struct rtl8169_private *tp) | |||
3525 | }; | 3486 | }; |
3526 | 3487 | ||
3527 | /* Disable ALDPS before ram code */ | 3488 | /* Disable ALDPS before ram code */ |
3528 | r810x_aldps_disable(tp); | 3489 | rtl_writephy(tp, 0x1f, 0x0000); |
3490 | rtl_writephy(tp, 0x18, 0x0310); | ||
3491 | msleep(100); | ||
3529 | 3492 | ||
3530 | rtl_apply_firmware(tp); | 3493 | rtl_apply_firmware(tp); |
3531 | 3494 | ||
@@ -3533,8 +3496,6 @@ static void rtl8106e_hw_phy_config(struct rtl8169_private *tp) | |||
3533 | rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init)); | 3496 | rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init)); |
3534 | 3497 | ||
3535 | rtl_eri_write(tp, 0x1d0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC); | 3498 | rtl_eri_write(tp, 0x1d0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC); |
3536 | |||
3537 | r810x_aldps_enable(tp); | ||
3538 | } | 3499 | } |
3539 | 3500 | ||
3540 | static void rtl_hw_phy_config(struct net_device *dev) | 3501 | static void rtl_hw_phy_config(struct net_device *dev) |
@@ -5051,6 +5012,8 @@ static void rtl_hw_start_8168e_2(struct rtl8169_private *tp) | |||
5051 | 5012 | ||
5052 | RTL_W8(MaxTxPacketSize, EarlySize); | 5013 | RTL_W8(MaxTxPacketSize, EarlySize); |
5053 | 5014 | ||
5015 | rtl_disable_clock_request(pdev); | ||
5016 | |||
5054 | RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO); | 5017 | RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO); |
5055 | RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB); | 5018 | RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB); |
5056 | 5019 | ||
@@ -5059,8 +5022,7 @@ static void rtl_hw_start_8168e_2(struct rtl8169_private *tp) | |||
5059 | 5022 | ||
5060 | RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN); | 5023 | RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN); |
5061 | RTL_W32(MISC, RTL_R32(MISC) | PWM_EN); | 5024 | RTL_W32(MISC, RTL_R32(MISC) | PWM_EN); |
5062 | RTL_W8(Config5, (RTL_R8(Config5) & ~Spi_en) | ASPM_en); | 5025 | RTL_W8(Config5, RTL_R8(Config5) & ~Spi_en); |
5063 | RTL_W8(Config2, RTL_R8(Config2) | ClkReqEn); | ||
5064 | } | 5026 | } |
5065 | 5027 | ||
5066 | static void rtl_hw_start_8168f(struct rtl8169_private *tp) | 5028 | static void rtl_hw_start_8168f(struct rtl8169_private *tp) |
@@ -5085,12 +5047,13 @@ static void rtl_hw_start_8168f(struct rtl8169_private *tp) | |||
5085 | 5047 | ||
5086 | RTL_W8(MaxTxPacketSize, EarlySize); | 5048 | RTL_W8(MaxTxPacketSize, EarlySize); |
5087 | 5049 | ||
5050 | rtl_disable_clock_request(pdev); | ||
5051 | |||
5088 | RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO); | 5052 | RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO); |
5089 | RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB); | 5053 | RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB); |
5090 | RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN); | 5054 | RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN); |
5091 | RTL_W32(MISC, RTL_R32(MISC) | PWM_EN | FORCE_CLK); | 5055 | RTL_W32(MISC, RTL_R32(MISC) | PWM_EN); |
5092 | RTL_W8(Config5, (RTL_R8(Config5) & ~Spi_en) | ASPM_en); | 5056 | RTL_W8(Config5, RTL_R8(Config5) & ~Spi_en); |
5093 | RTL_W8(Config2, RTL_R8(Config2) | ClkReqEn); | ||
5094 | } | 5057 | } |
5095 | 5058 | ||
5096 | static void rtl_hw_start_8168f_1(struct rtl8169_private *tp) | 5059 | static void rtl_hw_start_8168f_1(struct rtl8169_private *tp) |
@@ -5147,10 +5110,8 @@ static void rtl_hw_start_8168g_1(struct rtl8169_private *tp) | |||
5147 | rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC); | 5110 | rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC); |
5148 | 5111 | ||
5149 | RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); | 5112 | RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); |
5150 | RTL_W32(MISC, (RTL_R32(MISC) | FORCE_CLK) & ~RXDV_GATED_EN); | 5113 | RTL_W32(MISC, RTL_R32(MISC) & ~RXDV_GATED_EN); |
5151 | RTL_W8(MaxTxPacketSize, EarlySize); | 5114 | RTL_W8(MaxTxPacketSize, EarlySize); |
5152 | RTL_W8(Config5, RTL_R8(Config5) | ASPM_en); | ||
5153 | RTL_W8(Config2, RTL_R8(Config2) | ClkReqEn); | ||
5154 | 5115 | ||
5155 | rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC); | 5116 | rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC); |
5156 | rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC); | 5117 | rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC); |
@@ -5366,9 +5327,6 @@ static void rtl_hw_start_8105e_1(struct rtl8169_private *tp) | |||
5366 | 5327 | ||
5367 | RTL_W8(MCU, RTL_R8(MCU) | EN_NDP | EN_OOB_RESET); | 5328 | RTL_W8(MCU, RTL_R8(MCU) | EN_NDP | EN_OOB_RESET); |
5368 | RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN); | 5329 | RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN); |
5369 | RTL_W8(Config5, RTL_R8(Config5) | ASPM_en); | ||
5370 | RTL_W8(Config2, RTL_R8(Config2) | ClkReqEn); | ||
5371 | RTL_W32(MISC, RTL_R32(MISC) | FORCE_CLK); | ||
5372 | 5330 | ||
5373 | rtl_ephy_init(tp, e_info_8105e_1, ARRAY_SIZE(e_info_8105e_1)); | 5331 | rtl_ephy_init(tp, e_info_8105e_1, ARRAY_SIZE(e_info_8105e_1)); |
5374 | } | 5332 | } |
@@ -5394,9 +5352,6 @@ static void rtl_hw_start_8402(struct rtl8169_private *tp) | |||
5394 | 5352 | ||
5395 | RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO); | 5353 | RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO); |
5396 | RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB); | 5354 | RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB); |
5397 | RTL_W8(Config5, RTL_R8(Config5) | ASPM_en); | ||
5398 | RTL_W8(Config2, RTL_R8(Config2) | ClkReqEn); | ||
5399 | RTL_W32(MISC, RTL_R32(MISC) | FORCE_CLK); | ||
5400 | 5355 | ||
5401 | rtl_ephy_init(tp, e_info_8402, ARRAY_SIZE(e_info_8402)); | 5356 | rtl_ephy_init(tp, e_info_8402, ARRAY_SIZE(e_info_8402)); |
5402 | 5357 | ||
@@ -5418,10 +5373,7 @@ static void rtl_hw_start_8106(struct rtl8169_private *tp) | |||
5418 | /* Force LAN exit from ASPM if Rx/Tx are not idle */ | 5373 | /* Force LAN exit from ASPM if Rx/Tx are not idle */ |
5419 | RTL_W32(FuncEvent, RTL_R32(FuncEvent) | 0x002800); | 5374 | RTL_W32(FuncEvent, RTL_R32(FuncEvent) | 0x002800); |
5420 | 5375 | ||
5421 | RTL_W32(MISC, | 5376 | RTL_W32(MISC, (RTL_R32(MISC) | DISABLE_LAN_EN) & ~EARLY_TALLY_EN); |
5422 | (RTL_R32(MISC) | DISABLE_LAN_EN | FORCE_CLK) & ~EARLY_TALLY_EN); | ||
5423 | RTL_W8(Config5, RTL_R8(Config5) | ASPM_en); | ||
5424 | RTL_W8(Config2, RTL_R8(Config2) | ClkReqEn); | ||
5425 | RTL_W8(MCU, RTL_R8(MCU) | EN_NDP | EN_OOB_RESET); | 5377 | RTL_W8(MCU, RTL_R8(MCU) | EN_NDP | EN_OOB_RESET); |
5426 | RTL_W8(DLLPR, RTL_R8(DLLPR) & ~PFM_EN); | 5378 | RTL_W8(DLLPR, RTL_R8(DLLPR) & ~PFM_EN); |
5427 | } | 5379 | } |
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index f07c0612abf6..b75f4b286895 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | |||
@@ -69,7 +69,7 @@ | |||
69 | 69 | ||
70 | #undef STMMAC_XMIT_DEBUG | 70 | #undef STMMAC_XMIT_DEBUG |
71 | /*#define STMMAC_XMIT_DEBUG*/ | 71 | /*#define STMMAC_XMIT_DEBUG*/ |
72 | #ifdef STMMAC_TX_DEBUG | 72 | #ifdef STMMAC_XMIT_DEBUG |
73 | #define TX_DBG(fmt, args...) printk(fmt, ## args) | 73 | #define TX_DBG(fmt, args...) printk(fmt, ## args) |
74 | #else | 74 | #else |
75 | #define TX_DBG(fmt, args...) do { } while (0) | 75 | #define TX_DBG(fmt, args...) do { } while (0) |
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c index 0376a5e6b2bf..0b9829fe3eea 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c | |||
@@ -188,8 +188,6 @@ int stmmac_mdio_register(struct net_device *ndev) | |||
188 | goto bus_register_fail; | 188 | goto bus_register_fail; |
189 | } | 189 | } |
190 | 190 | ||
191 | priv->mii = new_bus; | ||
192 | |||
193 | found = 0; | 191 | found = 0; |
194 | for (addr = 0; addr < PHY_MAX_ADDR; addr++) { | 192 | for (addr = 0; addr < PHY_MAX_ADDR; addr++) { |
195 | struct phy_device *phydev = new_bus->phy_map[addr]; | 193 | struct phy_device *phydev = new_bus->phy_map[addr]; |
@@ -237,8 +235,14 @@ int stmmac_mdio_register(struct net_device *ndev) | |||
237 | } | 235 | } |
238 | } | 236 | } |
239 | 237 | ||
240 | if (!found) | 238 | if (!found) { |
241 | pr_warning("%s: No PHY found\n", ndev->name); | 239 | pr_warning("%s: No PHY found\n", ndev->name); |
240 | mdiobus_unregister(new_bus); | ||
241 | mdiobus_free(new_bus); | ||
242 | return -ENODEV; | ||
243 | } | ||
244 | |||
245 | priv->mii = new_bus; | ||
242 | 246 | ||
243 | return 0; | 247 | return 0; |
244 | 248 | ||
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index c8e05e27f38c..19d903598b0d 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c | |||
@@ -411,6 +411,7 @@ static const struct usb_device_id products[] = { | |||
411 | }, | 411 | }, |
412 | 412 | ||
413 | /* 3. Combined interface devices matching on interface number */ | 413 | /* 3. Combined interface devices matching on interface number */ |
414 | {QMI_FIXED_INTF(0x0408, 0xea42, 4)}, /* Yota / Megafon M100-1 */ | ||
414 | {QMI_FIXED_INTF(0x12d1, 0x140c, 1)}, /* Huawei E173 */ | 415 | {QMI_FIXED_INTF(0x12d1, 0x140c, 1)}, /* Huawei E173 */ |
415 | {QMI_FIXED_INTF(0x19d2, 0x0002, 1)}, | 416 | {QMI_FIXED_INTF(0x19d2, 0x0002, 1)}, |
416 | {QMI_FIXED_INTF(0x19d2, 0x0012, 1)}, | 417 | {QMI_FIXED_INTF(0x19d2, 0x0012, 1)}, |
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 83564d36e801..a00a03ea4ec9 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c | |||
@@ -318,20 +318,20 @@ struct mwl8k_sta { | |||
318 | #define MWL8K_STA(_sta) ((struct mwl8k_sta *)&((_sta)->drv_priv)) | 318 | #define MWL8K_STA(_sta) ((struct mwl8k_sta *)&((_sta)->drv_priv)) |
319 | 319 | ||
320 | static const struct ieee80211_channel mwl8k_channels_24[] = { | 320 | static const struct ieee80211_channel mwl8k_channels_24[] = { |
321 | { .center_freq = 2412, .hw_value = 1, }, | 321 | { .band = IEEE80211_BAND_2GHZ, .center_freq = 2412, .hw_value = 1, }, |
322 | { .center_freq = 2417, .hw_value = 2, }, | 322 | { .band = IEEE80211_BAND_2GHZ, .center_freq = 2417, .hw_value = 2, }, |
323 | { .center_freq = 2422, .hw_value = 3, }, | 323 | { .band = IEEE80211_BAND_2GHZ, .center_freq = 2422, .hw_value = 3, }, |
324 | { .center_freq = 2427, .hw_value = 4, }, | 324 | { .band = IEEE80211_BAND_2GHZ, .center_freq = 2427, .hw_value = 4, }, |
325 | { .center_freq = 2432, .hw_value = 5, }, | 325 | { .band = IEEE80211_BAND_2GHZ, .center_freq = 2432, .hw_value = 5, }, |
326 | { .center_freq = 2437, .hw_value = 6, }, | 326 | { .band = IEEE80211_BAND_2GHZ, .center_freq = 2437, .hw_value = 6, }, |
327 | { .center_freq = 2442, .hw_value = 7, }, | 327 | { .band = IEEE80211_BAND_2GHZ, .center_freq = 2442, .hw_value = 7, }, |
328 | { .center_freq = 2447, .hw_value = 8, }, | 328 | { .band = IEEE80211_BAND_2GHZ, .center_freq = 2447, .hw_value = 8, }, |
329 | { .center_freq = 2452, .hw_value = 9, }, | 329 | { .band = IEEE80211_BAND_2GHZ, .center_freq = 2452, .hw_value = 9, }, |
330 | { .center_freq = 2457, .hw_value = 10, }, | 330 | { .band = IEEE80211_BAND_2GHZ, .center_freq = 2457, .hw_value = 10, }, |
331 | { .center_freq = 2462, .hw_value = 11, }, | 331 | { .band = IEEE80211_BAND_2GHZ, .center_freq = 2462, .hw_value = 11, }, |
332 | { .center_freq = 2467, .hw_value = 12, }, | 332 | { .band = IEEE80211_BAND_2GHZ, .center_freq = 2467, .hw_value = 12, }, |
333 | { .center_freq = 2472, .hw_value = 13, }, | 333 | { .band = IEEE80211_BAND_2GHZ, .center_freq = 2472, .hw_value = 13, }, |
334 | { .center_freq = 2484, .hw_value = 14, }, | 334 | { .band = IEEE80211_BAND_2GHZ, .center_freq = 2484, .hw_value = 14, }, |
335 | }; | 335 | }; |
336 | 336 | ||
337 | static const struct ieee80211_rate mwl8k_rates_24[] = { | 337 | static const struct ieee80211_rate mwl8k_rates_24[] = { |
@@ -352,10 +352,10 @@ static const struct ieee80211_rate mwl8k_rates_24[] = { | |||
352 | }; | 352 | }; |
353 | 353 | ||
354 | static const struct ieee80211_channel mwl8k_channels_50[] = { | 354 | static const struct ieee80211_channel mwl8k_channels_50[] = { |
355 | { .center_freq = 5180, .hw_value = 36, }, | 355 | { .band = IEEE80211_BAND_5GHZ, .center_freq = 5180, .hw_value = 36, }, |
356 | { .center_freq = 5200, .hw_value = 40, }, | 356 | { .band = IEEE80211_BAND_5GHZ, .center_freq = 5200, .hw_value = 40, }, |
357 | { .center_freq = 5220, .hw_value = 44, }, | 357 | { .band = IEEE80211_BAND_5GHZ, .center_freq = 5220, .hw_value = 44, }, |
358 | { .center_freq = 5240, .hw_value = 48, }, | 358 | { .band = IEEE80211_BAND_5GHZ, .center_freq = 5240, .hw_value = 48, }, |
359 | }; | 359 | }; |
360 | 360 | ||
361 | static const struct ieee80211_rate mwl8k_rates_50[] = { | 361 | static const struct ieee80211_rate mwl8k_rates_50[] = { |
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 5099636a6e5f..00cc78c7aa04 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c | |||
@@ -845,6 +845,32 @@ int pci_enable_msi_block(struct pci_dev *dev, unsigned int nvec) | |||
845 | } | 845 | } |
846 | EXPORT_SYMBOL(pci_enable_msi_block); | 846 | EXPORT_SYMBOL(pci_enable_msi_block); |
847 | 847 | ||
848 | int pci_enable_msi_block_auto(struct pci_dev *dev, unsigned int *maxvec) | ||
849 | { | ||
850 | int ret, pos, nvec; | ||
851 | u16 msgctl; | ||
852 | |||
853 | pos = pci_find_capability(dev, PCI_CAP_ID_MSI); | ||
854 | if (!pos) | ||
855 | return -EINVAL; | ||
856 | |||
857 | pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &msgctl); | ||
858 | ret = 1 << ((msgctl & PCI_MSI_FLAGS_QMASK) >> 1); | ||
859 | |||
860 | if (maxvec) | ||
861 | *maxvec = ret; | ||
862 | |||
863 | do { | ||
864 | nvec = ret; | ||
865 | ret = pci_enable_msi_block(dev, nvec); | ||
866 | } while (ret > 0); | ||
867 | |||
868 | if (ret < 0) | ||
869 | return ret; | ||
870 | return nvec; | ||
871 | } | ||
872 | EXPORT_SYMBOL(pci_enable_msi_block_auto); | ||
873 | |||
848 | void pci_msi_shutdown(struct pci_dev *dev) | 874 | void pci_msi_shutdown(struct pci_dev *dev) |
849 | { | 875 | { |
850 | struct msi_desc *desc; | 876 | struct msi_desc *desc; |
diff --git a/drivers/pci/pcie/aer/aerdrv_errprint.c b/drivers/pci/pcie/aer/aerdrv_errprint.c index 3ea51736f18d..5ab14251839d 100644 --- a/drivers/pci/pcie/aer/aerdrv_errprint.c +++ b/drivers/pci/pcie/aer/aerdrv_errprint.c | |||
@@ -23,6 +23,9 @@ | |||
23 | 23 | ||
24 | #include "aerdrv.h" | 24 | #include "aerdrv.h" |
25 | 25 | ||
26 | #define CREATE_TRACE_POINTS | ||
27 | #include <trace/events/ras.h> | ||
28 | |||
26 | #define AER_AGENT_RECEIVER 0 | 29 | #define AER_AGENT_RECEIVER 0 |
27 | #define AER_AGENT_REQUESTER 1 | 30 | #define AER_AGENT_REQUESTER 1 |
28 | #define AER_AGENT_COMPLETER 2 | 31 | #define AER_AGENT_COMPLETER 2 |
@@ -121,12 +124,11 @@ static const char *aer_agent_string[] = { | |||
121 | "Transmitter ID" | 124 | "Transmitter ID" |
122 | }; | 125 | }; |
123 | 126 | ||
124 | static void __aer_print_error(const char *prefix, | 127 | static void __aer_print_error(struct pci_dev *dev, |
125 | struct aer_err_info *info) | 128 | struct aer_err_info *info) |
126 | { | 129 | { |
127 | int i, status; | 130 | int i, status; |
128 | const char *errmsg = NULL; | 131 | const char *errmsg = NULL; |
129 | |||
130 | status = (info->status & ~info->mask); | 132 | status = (info->status & ~info->mask); |
131 | 133 | ||
132 | for (i = 0; i < 32; i++) { | 134 | for (i = 0; i < 32; i++) { |
@@ -141,26 +143,22 @@ static void __aer_print_error(const char *prefix, | |||
141 | aer_uncorrectable_error_string[i] : NULL; | 143 | aer_uncorrectable_error_string[i] : NULL; |
142 | 144 | ||
143 | if (errmsg) | 145 | if (errmsg) |
144 | printk("%s"" [%2d] %-22s%s\n", prefix, i, errmsg, | 146 | dev_err(&dev->dev, " [%2d] %-22s%s\n", i, errmsg, |
145 | info->first_error == i ? " (First)" : ""); | 147 | info->first_error == i ? " (First)" : ""); |
146 | else | 148 | else |
147 | printk("%s"" [%2d] Unknown Error Bit%s\n", prefix, i, | 149 | dev_err(&dev->dev, " [%2d] Unknown Error Bit%s\n", |
148 | info->first_error == i ? " (First)" : ""); | 150 | i, info->first_error == i ? " (First)" : ""); |
149 | } | 151 | } |
150 | } | 152 | } |
151 | 153 | ||
152 | void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) | 154 | void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) |
153 | { | 155 | { |
154 | int id = ((dev->bus->number << 8) | dev->devfn); | 156 | int id = ((dev->bus->number << 8) | dev->devfn); |
155 | char prefix[44]; | ||
156 | |||
157 | snprintf(prefix, sizeof(prefix), "%s%s %s: ", | ||
158 | (info->severity == AER_CORRECTABLE) ? KERN_WARNING : KERN_ERR, | ||
159 | dev_driver_string(&dev->dev), dev_name(&dev->dev)); | ||
160 | 157 | ||
161 | if (info->status == 0) { | 158 | if (info->status == 0) { |
162 | printk("%s""PCIe Bus Error: severity=%s, type=Unaccessible, " | 159 | dev_err(&dev->dev, |
163 | "id=%04x(Unregistered Agent ID)\n", prefix, | 160 | "PCIe Bus Error: severity=%s, type=Unaccessible, " |
161 | "id=%04x(Unregistered Agent ID)\n", | ||
164 | aer_error_severity_string[info->severity], id); | 162 | aer_error_severity_string[info->severity], id); |
165 | } else { | 163 | } else { |
166 | int layer, agent; | 164 | int layer, agent; |
@@ -168,22 +166,24 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) | |||
168 | layer = AER_GET_LAYER_ERROR(info->severity, info->status); | 166 | layer = AER_GET_LAYER_ERROR(info->severity, info->status); |
169 | agent = AER_GET_AGENT(info->severity, info->status); | 167 | agent = AER_GET_AGENT(info->severity, info->status); |
170 | 168 | ||
171 | printk("%s""PCIe Bus Error: severity=%s, type=%s, id=%04x(%s)\n", | 169 | dev_err(&dev->dev, |
172 | prefix, aer_error_severity_string[info->severity], | 170 | "PCIe Bus Error: severity=%s, type=%s, id=%04x(%s)\n", |
171 | aer_error_severity_string[info->severity], | ||
173 | aer_error_layer[layer], id, aer_agent_string[agent]); | 172 | aer_error_layer[layer], id, aer_agent_string[agent]); |
174 | 173 | ||
175 | printk("%s"" device [%04x:%04x] error status/mask=%08x/%08x\n", | 174 | dev_err(&dev->dev, |
176 | prefix, dev->vendor, dev->device, | 175 | " device [%04x:%04x] error status/mask=%08x/%08x\n", |
176 | dev->vendor, dev->device, | ||
177 | info->status, info->mask); | 177 | info->status, info->mask); |
178 | 178 | ||
179 | __aer_print_error(prefix, info); | 179 | __aer_print_error(dev, info); |
180 | 180 | ||
181 | if (info->tlp_header_valid) { | 181 | if (info->tlp_header_valid) { |
182 | unsigned char *tlp = (unsigned char *) &info->tlp; | 182 | unsigned char *tlp = (unsigned char *) &info->tlp; |
183 | printk("%s"" TLP Header:" | 183 | dev_err(&dev->dev, " TLP Header:" |
184 | " %02x%02x%02x%02x %02x%02x%02x%02x" | 184 | " %02x%02x%02x%02x %02x%02x%02x%02x" |
185 | " %02x%02x%02x%02x %02x%02x%02x%02x\n", | 185 | " %02x%02x%02x%02x %02x%02x%02x%02x\n", |
186 | prefix, *(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp, | 186 | *(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp, |
187 | *(tlp + 7), *(tlp + 6), *(tlp + 5), *(tlp + 4), | 187 | *(tlp + 7), *(tlp + 6), *(tlp + 5), *(tlp + 4), |
188 | *(tlp + 11), *(tlp + 10), *(tlp + 9), | 188 | *(tlp + 11), *(tlp + 10), *(tlp + 9), |
189 | *(tlp + 8), *(tlp + 15), *(tlp + 14), | 189 | *(tlp + 8), *(tlp + 15), *(tlp + 14), |
@@ -192,8 +192,11 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) | |||
192 | } | 192 | } |
193 | 193 | ||
194 | if (info->id && info->error_dev_num > 1 && info->id == id) | 194 | if (info->id && info->error_dev_num > 1 && info->id == id) |
195 | printk("%s"" Error of this Agent(%04x) is reported first\n", | 195 | dev_err(&dev->dev, |
196 | prefix, id); | 196 | " Error of this Agent(%04x) is reported first\n", |
197 | id); | ||
198 | trace_aer_event(dev_name(&dev->dev), (info->status & ~info->mask), | ||
199 | info->severity); | ||
197 | } | 200 | } |
198 | 201 | ||
199 | void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info) | 202 | void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info) |
@@ -217,7 +220,7 @@ int cper_severity_to_aer(int cper_severity) | |||
217 | } | 220 | } |
218 | EXPORT_SYMBOL_GPL(cper_severity_to_aer); | 221 | EXPORT_SYMBOL_GPL(cper_severity_to_aer); |
219 | 222 | ||
220 | void cper_print_aer(const char *prefix, int cper_severity, | 223 | void cper_print_aer(const char *prefix, struct pci_dev *dev, int cper_severity, |
221 | struct aer_capability_regs *aer) | 224 | struct aer_capability_regs *aer) |
222 | { | 225 | { |
223 | int aer_severity, layer, agent, status_strs_size, tlp_header_valid = 0; | 226 | int aer_severity, layer, agent, status_strs_size, tlp_header_valid = 0; |
@@ -239,25 +242,27 @@ void cper_print_aer(const char *prefix, int cper_severity, | |||
239 | } | 242 | } |
240 | layer = AER_GET_LAYER_ERROR(aer_severity, status); | 243 | layer = AER_GET_LAYER_ERROR(aer_severity, status); |
241 | agent = AER_GET_AGENT(aer_severity, status); | 244 | agent = AER_GET_AGENT(aer_severity, status); |
242 | printk("%s""aer_status: 0x%08x, aer_mask: 0x%08x\n", | 245 | dev_err(&dev->dev, "aer_status: 0x%08x, aer_mask: 0x%08x\n", |
243 | prefix, status, mask); | 246 | status, mask); |
244 | cper_print_bits(prefix, status, status_strs, status_strs_size); | 247 | cper_print_bits(prefix, status, status_strs, status_strs_size); |
245 | printk("%s""aer_layer=%s, aer_agent=%s\n", prefix, | 248 | dev_err(&dev->dev, "aer_layer=%s, aer_agent=%s\n", |
246 | aer_error_layer[layer], aer_agent_string[agent]); | 249 | aer_error_layer[layer], aer_agent_string[agent]); |
247 | if (aer_severity != AER_CORRECTABLE) | 250 | if (aer_severity != AER_CORRECTABLE) |
248 | printk("%s""aer_uncor_severity: 0x%08x\n", | 251 | dev_err(&dev->dev, "aer_uncor_severity: 0x%08x\n", |
249 | prefix, aer->uncor_severity); | 252 | aer->uncor_severity); |
250 | if (tlp_header_valid) { | 253 | if (tlp_header_valid) { |
251 | const unsigned char *tlp; | 254 | const unsigned char *tlp; |
252 | tlp = (const unsigned char *)&aer->header_log; | 255 | tlp = (const unsigned char *)&aer->header_log; |
253 | printk("%s""aer_tlp_header:" | 256 | dev_err(&dev->dev, "aer_tlp_header:" |
254 | " %02x%02x%02x%02x %02x%02x%02x%02x" | 257 | " %02x%02x%02x%02x %02x%02x%02x%02x" |
255 | " %02x%02x%02x%02x %02x%02x%02x%02x\n", | 258 | " %02x%02x%02x%02x %02x%02x%02x%02x\n", |
256 | prefix, *(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp, | 259 | *(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp, |
257 | *(tlp + 7), *(tlp + 6), *(tlp + 5), *(tlp + 4), | 260 | *(tlp + 7), *(tlp + 6), *(tlp + 5), *(tlp + 4), |
258 | *(tlp + 11), *(tlp + 10), *(tlp + 9), | 261 | *(tlp + 11), *(tlp + 10), *(tlp + 9), |
259 | *(tlp + 8), *(tlp + 15), *(tlp + 14), | 262 | *(tlp + 8), *(tlp + 15), *(tlp + 14), |
260 | *(tlp + 13), *(tlp + 12)); | 263 | *(tlp + 13), *(tlp + 12)); |
261 | } | 264 | } |
265 | trace_aer_event(dev_name(&dev->dev), (status & ~mask), | ||
266 | aer_severity); | ||
262 | } | 267 | } |
263 | #endif | 268 | #endif |
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index 7c0fd9252e6f..84954a726a94 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c | |||
@@ -19,6 +19,8 @@ static void pci_free_resources(struct pci_dev *dev) | |||
19 | 19 | ||
20 | static void pci_stop_dev(struct pci_dev *dev) | 20 | static void pci_stop_dev(struct pci_dev *dev) |
21 | { | 21 | { |
22 | pci_pme_active(dev, false); | ||
23 | |||
22 | if (dev->is_added) { | 24 | if (dev->is_added) { |
23 | pci_proc_detach_device(dev); | 25 | pci_proc_detach_device(dev); |
24 | pci_remove_sysfs_dev_files(dev); | 26 | pci_remove_sysfs_dev_files(dev); |
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 923a9da9c829..5e44eaabf457 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig | |||
@@ -20,14 +20,24 @@ if RTC_CLASS | |||
20 | config RTC_HCTOSYS | 20 | config RTC_HCTOSYS |
21 | bool "Set system time from RTC on startup and resume" | 21 | bool "Set system time from RTC on startup and resume" |
22 | default y | 22 | default y |
23 | depends on !ALWAYS_USE_PERSISTENT_CLOCK | ||
23 | help | 24 | help |
24 | If you say yes here, the system time (wall clock) will be set using | 25 | If you say yes here, the system time (wall clock) will be set using |
25 | the value read from a specified RTC device. This is useful to avoid | 26 | the value read from a specified RTC device. This is useful to avoid |
26 | unnecessary fsck runs at boot time, and to network better. | 27 | unnecessary fsck runs at boot time, and to network better. |
27 | 28 | ||
29 | config RTC_SYSTOHC | ||
30 | bool "Set the RTC time based on NTP synchronization" | ||
31 | default y | ||
32 | depends on !ALWAYS_USE_PERSISTENT_CLOCK | ||
33 | help | ||
34 | If you say yes here, the system time (wall clock) will be stored | ||
35 | in the RTC specified by RTC_HCTOSYS_DEVICE approximately every 11 | ||
36 | minutes if userspace reports synchronized NTP status. | ||
37 | |||
28 | config RTC_HCTOSYS_DEVICE | 38 | config RTC_HCTOSYS_DEVICE |
29 | string "RTC used to set the system time" | 39 | string "RTC used to set the system time" |
30 | depends on RTC_HCTOSYS = y | 40 | depends on RTC_HCTOSYS = y || RTC_SYSTOHC = y |
31 | default "rtc0" | 41 | default "rtc0" |
32 | help | 42 | help |
33 | The RTC device that will be used to (re)initialize the system | 43 | The RTC device that will be used to (re)initialize the system |
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 4418ef3f9ecc..ec2988b00a44 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile | |||
@@ -6,6 +6,7 @@ ccflags-$(CONFIG_RTC_DEBUG) := -DDEBUG | |||
6 | 6 | ||
7 | obj-$(CONFIG_RTC_LIB) += rtc-lib.o | 7 | obj-$(CONFIG_RTC_LIB) += rtc-lib.o |
8 | obj-$(CONFIG_RTC_HCTOSYS) += hctosys.o | 8 | obj-$(CONFIG_RTC_HCTOSYS) += hctosys.o |
9 | obj-$(CONFIG_RTC_SYSTOHC) += systohc.o | ||
9 | obj-$(CONFIG_RTC_CLASS) += rtc-core.o | 10 | obj-$(CONFIG_RTC_CLASS) += rtc-core.o |
10 | rtc-core-y := class.o interface.o | 11 | rtc-core-y := class.o interface.o |
11 | 12 | ||
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 5143629dedbd..26388f182594 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c | |||
@@ -50,6 +50,10 @@ static int rtc_suspend(struct device *dev, pm_message_t mesg) | |||
50 | struct rtc_device *rtc = to_rtc_device(dev); | 50 | struct rtc_device *rtc = to_rtc_device(dev); |
51 | struct rtc_time tm; | 51 | struct rtc_time tm; |
52 | struct timespec delta, delta_delta; | 52 | struct timespec delta, delta_delta; |
53 | |||
54 | if (has_persistent_clock()) | ||
55 | return 0; | ||
56 | |||
53 | if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) | 57 | if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) |
54 | return 0; | 58 | return 0; |
55 | 59 | ||
@@ -88,6 +92,9 @@ static int rtc_resume(struct device *dev) | |||
88 | struct timespec new_system, new_rtc; | 92 | struct timespec new_system, new_rtc; |
89 | struct timespec sleep_time; | 93 | struct timespec sleep_time; |
90 | 94 | ||
95 | if (has_persistent_clock()) | ||
96 | return 0; | ||
97 | |||
91 | rtc_hctosys_ret = -ENODEV; | 98 | rtc_hctosys_ret = -ENODEV; |
92 | if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) | 99 | if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) |
93 | return 0; | 100 | return 0; |
diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c index 10c1a3454e48..81c5077feff3 100644 --- a/drivers/rtc/rtc-pl031.c +++ b/drivers/rtc/rtc-pl031.c | |||
@@ -350,7 +350,9 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id) | |||
350 | /* Enable the clockwatch on ST Variants */ | 350 | /* Enable the clockwatch on ST Variants */ |
351 | if (vendor->clockwatch) | 351 | if (vendor->clockwatch) |
352 | data |= RTC_CR_CWEN; | 352 | data |= RTC_CR_CWEN; |
353 | writel(data | RTC_CR_EN, ldata->base + RTC_CR); | 353 | else |
354 | data |= RTC_CR_EN; | ||
355 | writel(data, ldata->base + RTC_CR); | ||
354 | 356 | ||
355 | /* | 357 | /* |
356 | * On ST PL031 variants, the RTC reset value does not provide correct | 358 | * On ST PL031 variants, the RTC reset value does not provide correct |
diff --git a/drivers/rtc/systohc.c b/drivers/rtc/systohc.c new file mode 100644 index 000000000000..bf3e242ccc5c --- /dev/null +++ b/drivers/rtc/systohc.c | |||
@@ -0,0 +1,44 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify it | ||
3 | * under the terms of the GNU General Public License version 2 as published by | ||
4 | * the Free Software Foundation. | ||
5 | * | ||
6 | */ | ||
7 | #include <linux/rtc.h> | ||
8 | #include <linux/time.h> | ||
9 | |||
10 | /** | ||
11 | * rtc_set_ntp_time - Save NTP synchronized time to the RTC | ||
12 | * @now: Current time of day | ||
13 | * | ||
14 | * Replacement for the NTP platform function update_persistent_clock | ||
15 | * that stores time for later retrieval by rtc_hctosys. | ||
16 | * | ||
17 | * Returns 0 on successful RTC update, -ENODEV if a RTC update is not | ||
18 | * possible at all, and various other -errno for specific temporary failure | ||
19 | * cases. | ||
20 | * | ||
21 | * If temporary failure is indicated the caller should try again 'soon' | ||
22 | */ | ||
23 | int rtc_set_ntp_time(struct timespec now) | ||
24 | { | ||
25 | struct rtc_device *rtc; | ||
26 | struct rtc_time tm; | ||
27 | int err = -ENODEV; | ||
28 | |||
29 | if (now.tv_nsec < (NSEC_PER_SEC >> 1)) | ||
30 | rtc_time_to_tm(now.tv_sec, &tm); | ||
31 | else | ||
32 | rtc_time_to_tm(now.tv_sec + 1, &tm); | ||
33 | |||
34 | rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE); | ||
35 | if (rtc) { | ||
36 | /* rtc_hctosys exclusively uses UTC, so we call set_time here, | ||
37 | * not set_mmss. */ | ||
38 | if (rtc->ops && (rtc->ops->set_time || rtc->ops->set_mmss)) | ||
39 | err = rtc_set_time(rtc, &tm); | ||
40 | rtc_class_close(rtc); | ||
41 | } | ||
42 | |||
43 | return err; | ||
44 | } | ||
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 19ee901577da..3a6083b386a1 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c | |||
@@ -33,7 +33,7 @@ | |||
33 | #include <linux/of_gpio.h> | 33 | #include <linux/of_gpio.h> |
34 | #include <linux/pm_runtime.h> | 34 | #include <linux/pm_runtime.h> |
35 | #include <linux/export.h> | 35 | #include <linux/export.h> |
36 | #include <linux/sched.h> | 36 | #include <linux/sched/rt.h> |
37 | #include <linux/delay.h> | 37 | #include <linux/delay.h> |
38 | #include <linux/kthread.h> | 38 | #include <linux/kthread.h> |
39 | #include <linux/ioport.h> | 39 | #include <linux/ioport.h> |
diff --git a/drivers/staging/csr/bh.c b/drivers/staging/csr/bh.c index 1a1f5c79822a..7b133597e923 100644 --- a/drivers/staging/csr/bh.c +++ b/drivers/staging/csr/bh.c | |||
@@ -15,7 +15,7 @@ | |||
15 | */ | 15 | */ |
16 | #include "csr_wifi_hip_unifi.h" | 16 | #include "csr_wifi_hip_unifi.h" |
17 | #include "unifi_priv.h" | 17 | #include "unifi_priv.h" |
18 | 18 | #include <linux/sched/rt.h> | |
19 | 19 | ||
20 | /* | 20 | /* |
21 | * --------------------------------------------------------------------------- | 21 | * --------------------------------------------------------------------------- |
diff --git a/drivers/staging/csr/unifi_sme.c b/drivers/staging/csr/unifi_sme.c index 7c6c4138fc76..49395da34b7f 100644 --- a/drivers/staging/csr/unifi_sme.c +++ b/drivers/staging/csr/unifi_sme.c | |||
@@ -15,7 +15,7 @@ | |||
15 | #include "unifi_priv.h" | 15 | #include "unifi_priv.h" |
16 | #include "csr_wifi_hip_unifi.h" | 16 | #include "csr_wifi_hip_unifi.h" |
17 | #include "csr_wifi_hip_conversions.h" | 17 | #include "csr_wifi_hip_conversions.h" |
18 | 18 | #include <linux/sched/rt.h> | |
19 | 19 | ||
20 | 20 | ||
21 | 21 | ||
diff --git a/drivers/staging/iio/trigger/Kconfig b/drivers/staging/iio/trigger/Kconfig index 7d3207559265..d44d3ad26fa5 100644 --- a/drivers/staging/iio/trigger/Kconfig +++ b/drivers/staging/iio/trigger/Kconfig | |||
@@ -21,7 +21,6 @@ config IIO_GPIO_TRIGGER | |||
21 | config IIO_SYSFS_TRIGGER | 21 | config IIO_SYSFS_TRIGGER |
22 | tristate "SYSFS trigger" | 22 | tristate "SYSFS trigger" |
23 | depends on SYSFS | 23 | depends on SYSFS |
24 | depends on HAVE_IRQ_WORK | ||
25 | select IRQ_WORK | 24 | select IRQ_WORK |
26 | help | 25 | help |
27 | Provides support for using SYSFS entry as IIO triggers. | 26 | Provides support for using SYSFS entry as IIO triggers. |
diff --git a/drivers/staging/omapdrm/Kconfig b/drivers/staging/omapdrm/Kconfig index b724a4131435..09f65dc3d2c8 100644 --- a/drivers/staging/omapdrm/Kconfig +++ b/drivers/staging/omapdrm/Kconfig | |||
@@ -3,8 +3,8 @@ config DRM_OMAP | |||
3 | tristate "OMAP DRM" | 3 | tristate "OMAP DRM" |
4 | depends on DRM && !CONFIG_FB_OMAP2 | 4 | depends on DRM && !CONFIG_FB_OMAP2 |
5 | depends on ARCH_OMAP2PLUS || ARCH_MULTIPLATFORM | 5 | depends on ARCH_OMAP2PLUS || ARCH_MULTIPLATFORM |
6 | depends on OMAP2_DSS | ||
6 | select DRM_KMS_HELPER | 7 | select DRM_KMS_HELPER |
7 | select OMAP2_DSS | ||
8 | select FB_SYS_FILLRECT | 8 | select FB_SYS_FILLRECT |
9 | select FB_SYS_COPYAREA | 9 | select FB_SYS_COPYAREA |
10 | select FB_SYS_IMAGEBLIT | 10 | select FB_SYS_IMAGEBLIT |
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index b3c4a250ff86..40e5b3919e27 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 15 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
16 | 16 | ||
17 | #include <linux/sched.h> | 17 | #include <linux/sched.h> |
18 | #include <linux/sched/rt.h> | ||
18 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
19 | #include <linux/mm.h> | 20 | #include <linux/mm.h> |
20 | #include <linux/fs.h> | 21 | #include <linux/fs.h> |
diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index 18688c12e30d..d7d66ef5cb58 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c | |||
@@ -538,6 +538,7 @@ static const enum dss_feat_id omap3630_dss_feat_list[] = { | |||
538 | FEAT_ALPHA_FIXED_ZORDER, | 538 | FEAT_ALPHA_FIXED_ZORDER, |
539 | FEAT_FIFO_MERGE, | 539 | FEAT_FIFO_MERGE, |
540 | FEAT_OMAP3_DSI_FIFO_BUG, | 540 | FEAT_OMAP3_DSI_FIFO_BUG, |
541 | FEAT_DPI_USES_VDDS_DSI, | ||
541 | }; | 542 | }; |
542 | 543 | ||
543 | static const enum dss_feat_id omap4430_es1_0_dss_feat_list[] = { | 544 | static const enum dss_feat_id omap4430_es1_0_dss_feat_list[] = { |
diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 74d77dfa5f63..22f77c5f6012 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c | |||
@@ -1787,7 +1787,7 @@ void xen_callback_vector(void) | |||
1787 | int rc; | 1787 | int rc; |
1788 | uint64_t callback_via; | 1788 | uint64_t callback_via; |
1789 | if (xen_have_vector_callback) { | 1789 | if (xen_have_vector_callback) { |
1790 | callback_via = HVM_CALLBACK_VECTOR(XEN_HVM_EVTCHN_CALLBACK); | 1790 | callback_via = HVM_CALLBACK_VECTOR(HYPERVISOR_CALLBACK_VECTOR); |
1791 | rc = xen_set_callback_via(callback_via); | 1791 | rc = xen_set_callback_via(callback_via); |
1792 | if (rc) { | 1792 | if (rc) { |
1793 | printk(KERN_ERR "Request for Xen HVM callback vector" | 1793 | printk(KERN_ERR "Request for Xen HVM callback vector" |
@@ -1798,8 +1798,9 @@ void xen_callback_vector(void) | |||
1798 | printk(KERN_INFO "Xen HVM callback vector for event delivery is " | 1798 | printk(KERN_INFO "Xen HVM callback vector for event delivery is " |
1799 | "enabled\n"); | 1799 | "enabled\n"); |
1800 | /* in the restore case the vector has already been allocated */ | 1800 | /* in the restore case the vector has already been allocated */ |
1801 | if (!test_bit(XEN_HVM_EVTCHN_CALLBACK, used_vectors)) | 1801 | if (!test_bit(HYPERVISOR_CALLBACK_VECTOR, used_vectors)) |
1802 | alloc_intr_gate(XEN_HVM_EVTCHN_CALLBACK, xen_hvm_callback_vector); | 1802 | alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, |
1803 | xen_hvm_callback_vector); | ||
1803 | } | 1804 | } |
1804 | } | 1805 | } |
1805 | #else | 1806 | #else |
diff --git a/drivers/xen/pcpu.c b/drivers/xen/pcpu.c index 067fcfa1723e..5a27a4599a4a 100644 --- a/drivers/xen/pcpu.c +++ b/drivers/xen/pcpu.c | |||
@@ -278,8 +278,7 @@ static int sync_pcpu(uint32_t cpu, uint32_t *max_cpu) | |||
278 | * Only those at cpu present map has its sys interface. | 278 | * Only those at cpu present map has its sys interface. |
279 | */ | 279 | */ |
280 | if (info->flags & XEN_PCPU_FLAGS_INVALID) { | 280 | if (info->flags & XEN_PCPU_FLAGS_INVALID) { |
281 | if (pcpu) | 281 | unregister_and_remove_pcpu(pcpu); |
282 | unregister_and_remove_pcpu(pcpu); | ||
283 | return 0; | 282 | return 0; |
284 | } | 283 | } |
285 | 284 | ||
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 0c42cdbabecf..49d0b43458b7 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/elf.h> | 33 | #include <linux/elf.h> |
34 | #include <linux/utsname.h> | 34 | #include <linux/utsname.h> |
35 | #include <linux/coredump.h> | 35 | #include <linux/coredump.h> |
36 | #include <linux/sched.h> | ||
36 | #include <asm/uaccess.h> | 37 | #include <asm/uaccess.h> |
37 | #include <asm/param.h> | 38 | #include <asm/param.h> |
38 | #include <asm/page.h> | 39 | #include <asm/page.h> |
@@ -1320,8 +1321,11 @@ static void fill_prstatus(struct elf_prstatus *prstatus, | |||
1320 | cputime_to_timeval(cputime.utime, &prstatus->pr_utime); | 1321 | cputime_to_timeval(cputime.utime, &prstatus->pr_utime); |
1321 | cputime_to_timeval(cputime.stime, &prstatus->pr_stime); | 1322 | cputime_to_timeval(cputime.stime, &prstatus->pr_stime); |
1322 | } else { | 1323 | } else { |
1323 | cputime_to_timeval(p->utime, &prstatus->pr_utime); | 1324 | cputime_t utime, stime; |
1324 | cputime_to_timeval(p->stime, &prstatus->pr_stime); | 1325 | |
1326 | task_cputime(p, &utime, &stime); | ||
1327 | cputime_to_timeval(utime, &prstatus->pr_utime); | ||
1328 | cputime_to_timeval(stime, &prstatus->pr_stime); | ||
1325 | } | 1329 | } |
1326 | cputime_to_timeval(p->signal->cutime, &prstatus->pr_cutime); | 1330 | cputime_to_timeval(p->signal->cutime, &prstatus->pr_cutime); |
1327 | cputime_to_timeval(p->signal->cstime, &prstatus->pr_cstime); | 1331 | cputime_to_timeval(p->signal->cstime, &prstatus->pr_cstime); |
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index dc84732e554f..cb240dd3b402 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c | |||
@@ -1375,8 +1375,11 @@ static void fill_prstatus(struct elf_prstatus *prstatus, | |||
1375 | cputime_to_timeval(cputime.utime, &prstatus->pr_utime); | 1375 | cputime_to_timeval(cputime.utime, &prstatus->pr_utime); |
1376 | cputime_to_timeval(cputime.stime, &prstatus->pr_stime); | 1376 | cputime_to_timeval(cputime.stime, &prstatus->pr_stime); |
1377 | } else { | 1377 | } else { |
1378 | cputime_to_timeval(p->utime, &prstatus->pr_utime); | 1378 | cputime_t utime, stime; |
1379 | cputime_to_timeval(p->stime, &prstatus->pr_stime); | 1379 | |
1380 | task_cputime(p, &utime, &stime); | ||
1381 | cputime_to_timeval(utime, &prstatus->pr_utime); | ||
1382 | cputime_to_timeval(stime, &prstatus->pr_stime); | ||
1380 | } | 1383 | } |
1381 | cputime_to_timeval(p->signal->cutime, &prstatus->pr_cutime); | 1384 | cputime_to_timeval(p->signal->cutime, &prstatus->pr_cutime); |
1382 | cputime_to_timeval(p->signal->cstime, &prstatus->pr_cstime); | 1385 | cputime_to_timeval(p->signal->cstime, &prstatus->pr_cstime); |
diff --git a/fs/proc/array.c b/fs/proc/array.c index 6a91e6ffbcbd..f7ed9ee46eb9 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c | |||
@@ -449,7 +449,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, | |||
449 | do { | 449 | do { |
450 | min_flt += t->min_flt; | 450 | min_flt += t->min_flt; |
451 | maj_flt += t->maj_flt; | 451 | maj_flt += t->maj_flt; |
452 | gtime += t->gtime; | 452 | gtime += task_gtime(t); |
453 | t = next_thread(t); | 453 | t = next_thread(t); |
454 | } while (t != task); | 454 | } while (t != task); |
455 | 455 | ||
@@ -472,7 +472,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, | |||
472 | min_flt = task->min_flt; | 472 | min_flt = task->min_flt; |
473 | maj_flt = task->maj_flt; | 473 | maj_flt = task->maj_flt; |
474 | task_cputime_adjusted(task, &utime, &stime); | 474 | task_cputime_adjusted(task, &utime, &stime); |
475 | gtime = task->gtime; | 475 | gtime = task_gtime(task); |
476 | } | 476 | } |
477 | 477 | ||
478 | /* scale priority and nice values from timeslices to -20..20 */ | 478 | /* scale priority and nice values from timeslices to -20..20 */ |
diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 7003e5266f25..288f068740f6 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c | |||
@@ -167,12 +167,16 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type, | |||
167 | static size_t ramoops_write_kmsg_hdr(struct persistent_ram_zone *prz) | 167 | static size_t ramoops_write_kmsg_hdr(struct persistent_ram_zone *prz) |
168 | { | 168 | { |
169 | char *hdr; | 169 | char *hdr; |
170 | struct timeval timestamp; | 170 | struct timespec timestamp; |
171 | size_t len; | 171 | size_t len; |
172 | 172 | ||
173 | do_gettimeofday(×tamp); | 173 | /* Report zeroed timestamp if called before timekeeping has resumed. */ |
174 | if (__getnstimeofday(×tamp)) { | ||
175 | timestamp.tv_sec = 0; | ||
176 | timestamp.tv_nsec = 0; | ||
177 | } | ||
174 | hdr = kasprintf(GFP_ATOMIC, RAMOOPS_KERNMSG_HDR "%lu.%lu\n", | 178 | hdr = kasprintf(GFP_ATOMIC, RAMOOPS_KERNMSG_HDR "%lu.%lu\n", |
175 | (long)timestamp.tv_sec, (long)timestamp.tv_usec); | 179 | (long)timestamp.tv_sec, (long)(timestamp.tv_nsec / 1000)); |
176 | WARN_ON_ONCE(!hdr); | 180 | WARN_ON_ONCE(!hdr); |
177 | len = hdr ? strlen(hdr) : 0; | 181 | len = hdr ? strlen(hdr) : 0; |
178 | persistent_ram_write(prz, hdr, len); | 182 | persistent_ram_write(prz, hdr, len); |
diff --git a/fs/select.c b/fs/select.c index 2ef72d965036..8c1c96c27062 100644 --- a/fs/select.c +++ b/fs/select.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/fs.h> | 26 | #include <linux/fs.h> |
27 | #include <linux/rcupdate.h> | 27 | #include <linux/rcupdate.h> |
28 | #include <linux/hrtimer.h> | 28 | #include <linux/hrtimer.h> |
29 | #include <linux/sched/rt.h> | ||
29 | 30 | ||
30 | #include <asm/uaccess.h> | 31 | #include <asm/uaccess.h> |
31 | 32 | ||
diff --git a/include/asm-generic/cputime.h b/include/asm-generic/cputime.h index 9a62937c56ca..51969436b8b8 100644 --- a/include/asm-generic/cputime.h +++ b/include/asm-generic/cputime.h | |||
@@ -4,66 +4,12 @@ | |||
4 | #include <linux/time.h> | 4 | #include <linux/time.h> |
5 | #include <linux/jiffies.h> | 5 | #include <linux/jiffies.h> |
6 | 6 | ||
7 | typedef unsigned long __nocast cputime_t; | 7 | #ifndef CONFIG_VIRT_CPU_ACCOUNTING |
8 | 8 | # include <asm-generic/cputime_jiffies.h> | |
9 | #define cputime_one_jiffy jiffies_to_cputime(1) | 9 | #endif |
10 | #define cputime_to_jiffies(__ct) (__force unsigned long)(__ct) | ||
11 | #define cputime_to_scaled(__ct) (__ct) | ||
12 | #define jiffies_to_cputime(__hz) (__force cputime_t)(__hz) | ||
13 | |||
14 | typedef u64 __nocast cputime64_t; | ||
15 | |||
16 | #define cputime64_to_jiffies64(__ct) (__force u64)(__ct) | ||
17 | #define jiffies64_to_cputime64(__jif) (__force cputime64_t)(__jif) | ||
18 | |||
19 | #define nsecs_to_cputime64(__ct) \ | ||
20 | jiffies64_to_cputime64(nsecs_to_jiffies64(__ct)) | ||
21 | |||
22 | |||
23 | /* | ||
24 | * Convert cputime to microseconds and back. | ||
25 | */ | ||
26 | #define cputime_to_usecs(__ct) \ | ||
27 | jiffies_to_usecs(cputime_to_jiffies(__ct)) | ||
28 | #define usecs_to_cputime(__usec) \ | ||
29 | jiffies_to_cputime(usecs_to_jiffies(__usec)) | ||
30 | #define usecs_to_cputime64(__usec) \ | ||
31 | jiffies64_to_cputime64(nsecs_to_jiffies64((__usec) * 1000)) | ||
32 | |||
33 | /* | ||
34 | * Convert cputime to seconds and back. | ||
35 | */ | ||
36 | #define cputime_to_secs(jif) (cputime_to_jiffies(jif) / HZ) | ||
37 | #define secs_to_cputime(sec) jiffies_to_cputime((sec) * HZ) | ||
38 | |||
39 | /* | ||
40 | * Convert cputime to timespec and back. | ||
41 | */ | ||
42 | #define timespec_to_cputime(__val) \ | ||
43 | jiffies_to_cputime(timespec_to_jiffies(__val)) | ||
44 | #define cputime_to_timespec(__ct,__val) \ | ||
45 | jiffies_to_timespec(cputime_to_jiffies(__ct),__val) | ||
46 | |||
47 | /* | ||
48 | * Convert cputime to timeval and back. | ||
49 | */ | ||
50 | #define timeval_to_cputime(__val) \ | ||
51 | jiffies_to_cputime(timeval_to_jiffies(__val)) | ||
52 | #define cputime_to_timeval(__ct,__val) \ | ||
53 | jiffies_to_timeval(cputime_to_jiffies(__ct),__val) | ||
54 | |||
55 | /* | ||
56 | * Convert cputime to clock and back. | ||
57 | */ | ||
58 | #define cputime_to_clock_t(__ct) \ | ||
59 | jiffies_to_clock_t(cputime_to_jiffies(__ct)) | ||
60 | #define clock_t_to_cputime(__x) \ | ||
61 | jiffies_to_cputime(clock_t_to_jiffies(__x)) | ||
62 | 10 | ||
63 | /* | 11 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN |
64 | * Convert cputime64 to clock. | 12 | # include <asm-generic/cputime_nsecs.h> |
65 | */ | 13 | #endif |
66 | #define cputime64_to_clock_t(__ct) \ | ||
67 | jiffies_64_to_clock_t(cputime64_to_jiffies64(__ct)) | ||
68 | 14 | ||
69 | #endif | 15 | #endif |
diff --git a/include/asm-generic/cputime_jiffies.h b/include/asm-generic/cputime_jiffies.h new file mode 100644 index 000000000000..272ecba9f588 --- /dev/null +++ b/include/asm-generic/cputime_jiffies.h | |||
@@ -0,0 +1,72 @@ | |||
1 | #ifndef _ASM_GENERIC_CPUTIME_JIFFIES_H | ||
2 | #define _ASM_GENERIC_CPUTIME_JIFFIES_H | ||
3 | |||
4 | typedef unsigned long __nocast cputime_t; | ||
5 | |||
6 | #define cputime_one_jiffy jiffies_to_cputime(1) | ||
7 | #define cputime_to_jiffies(__ct) (__force unsigned long)(__ct) | ||
8 | #define cputime_to_scaled(__ct) (__ct) | ||
9 | #define jiffies_to_cputime(__hz) (__force cputime_t)(__hz) | ||
10 | |||
11 | typedef u64 __nocast cputime64_t; | ||
12 | |||
13 | #define cputime64_to_jiffies64(__ct) (__force u64)(__ct) | ||
14 | #define jiffies64_to_cputime64(__jif) (__force cputime64_t)(__jif) | ||
15 | |||
16 | |||
17 | /* | ||
18 | * Convert nanoseconds to cputime | ||
19 | */ | ||
20 | #define nsecs_to_cputime64(__nsec) \ | ||
21 | jiffies64_to_cputime64(nsecs_to_jiffies64(__nsec)) | ||
22 | #define nsecs_to_cputime(__nsec) \ | ||
23 | jiffies_to_cputime(nsecs_to_jiffies(__nsec)) | ||
24 | |||
25 | |||
26 | /* | ||
27 | * Convert cputime to microseconds and back. | ||
28 | */ | ||
29 | #define cputime_to_usecs(__ct) \ | ||
30 | jiffies_to_usecs(cputime_to_jiffies(__ct)) | ||
31 | #define usecs_to_cputime(__usec) \ | ||
32 | jiffies_to_cputime(usecs_to_jiffies(__usec)) | ||
33 | #define usecs_to_cputime64(__usec) \ | ||
34 | jiffies64_to_cputime64(nsecs_to_jiffies64((__usec) * 1000)) | ||
35 | |||
36 | /* | ||
37 | * Convert cputime to seconds and back. | ||
38 | */ | ||
39 | #define cputime_to_secs(jif) (cputime_to_jiffies(jif) / HZ) | ||
40 | #define secs_to_cputime(sec) jiffies_to_cputime((sec) * HZ) | ||
41 | |||
42 | /* | ||
43 | * Convert cputime to timespec and back. | ||
44 | */ | ||
45 | #define timespec_to_cputime(__val) \ | ||
46 | jiffies_to_cputime(timespec_to_jiffies(__val)) | ||
47 | #define cputime_to_timespec(__ct,__val) \ | ||
48 | jiffies_to_timespec(cputime_to_jiffies(__ct),__val) | ||
49 | |||
50 | /* | ||
51 | * Convert cputime to timeval and back. | ||
52 | */ | ||
53 | #define timeval_to_cputime(__val) \ | ||
54 | jiffies_to_cputime(timeval_to_jiffies(__val)) | ||
55 | #define cputime_to_timeval(__ct,__val) \ | ||
56 | jiffies_to_timeval(cputime_to_jiffies(__ct),__val) | ||
57 | |||
58 | /* | ||
59 | * Convert cputime to clock and back. | ||
60 | */ | ||
61 | #define cputime_to_clock_t(__ct) \ | ||
62 | jiffies_to_clock_t(cputime_to_jiffies(__ct)) | ||
63 | #define clock_t_to_cputime(__x) \ | ||
64 | jiffies_to_cputime(clock_t_to_jiffies(__x)) | ||
65 | |||
66 | /* | ||
67 | * Convert cputime64 to clock. | ||
68 | */ | ||
69 | #define cputime64_to_clock_t(__ct) \ | ||
70 | jiffies_64_to_clock_t(cputime64_to_jiffies64(__ct)) | ||
71 | |||
72 | #endif | ||
diff --git a/include/asm-generic/cputime_nsecs.h b/include/asm-generic/cputime_nsecs.h new file mode 100644 index 000000000000..b6485cafb7bd --- /dev/null +++ b/include/asm-generic/cputime_nsecs.h | |||
@@ -0,0 +1,104 @@ | |||
1 | /* | ||
2 | * Definitions for measuring cputime in nsecs resolution. | ||
3 | * | ||
4 | * Based on <arch/ia64/include/asm/cputime.h> | ||
5 | * | ||
6 | * Copyright (C) 2007 FUJITSU LIMITED | ||
7 | * Copyright (C) 2007 Hidetoshi Seto <seto.hidetoshi@jp.fujitsu.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * as published by the Free Software Foundation; either version | ||
12 | * 2 of the License, or (at your option) any later version. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #ifndef _ASM_GENERIC_CPUTIME_NSECS_H | ||
17 | #define _ASM_GENERIC_CPUTIME_NSECS_H | ||
18 | |||
19 | typedef u64 __nocast cputime_t; | ||
20 | typedef u64 __nocast cputime64_t; | ||
21 | |||
22 | #define cputime_one_jiffy jiffies_to_cputime(1) | ||
23 | |||
24 | /* | ||
25 | * Convert cputime <-> jiffies (HZ) | ||
26 | */ | ||
27 | #define cputime_to_jiffies(__ct) \ | ||
28 | ((__force u64)(__ct) / (NSEC_PER_SEC / HZ)) | ||
29 | #define cputime_to_scaled(__ct) (__ct) | ||
30 | #define jiffies_to_cputime(__jif) \ | ||
31 | (__force cputime_t)((__jif) * (NSEC_PER_SEC / HZ)) | ||
32 | #define cputime64_to_jiffies64(__ct) \ | ||
33 | ((__force u64)(__ct) / (NSEC_PER_SEC / HZ)) | ||
34 | #define jiffies64_to_cputime64(__jif) \ | ||
35 | (__force cputime64_t)((__jif) * (NSEC_PER_SEC / HZ)) | ||
36 | |||
37 | |||
38 | /* | ||
39 | * Convert cputime <-> nanoseconds | ||
40 | */ | ||
41 | #define nsecs_to_cputime(__nsecs) ((__force u64)(__nsecs)) | ||
42 | |||
43 | |||
44 | /* | ||
45 | * Convert cputime <-> microseconds | ||
46 | */ | ||
47 | #define cputime_to_usecs(__ct) \ | ||
48 | ((__force u64)(__ct) / NSEC_PER_USEC) | ||
49 | #define usecs_to_cputime(__usecs) \ | ||
50 | (__force cputime_t)((__usecs) * NSEC_PER_USEC) | ||
51 | #define usecs_to_cputime64(__usecs) \ | ||
52 | (__force cputime64_t)((__usecs) * NSEC_PER_USEC) | ||
53 | |||
54 | /* | ||
55 | * Convert cputime <-> seconds | ||
56 | */ | ||
57 | #define cputime_to_secs(__ct) \ | ||
58 | ((__force u64)(__ct) / NSEC_PER_SEC) | ||
59 | #define secs_to_cputime(__secs) \ | ||
60 | (__force cputime_t)((__secs) * NSEC_PER_SEC) | ||
61 | |||
62 | /* | ||
63 | * Convert cputime <-> timespec (nsec) | ||
64 | */ | ||
65 | static inline cputime_t timespec_to_cputime(const struct timespec *val) | ||
66 | { | ||
67 | u64 ret = val->tv_sec * NSEC_PER_SEC + val->tv_nsec; | ||
68 | return (__force cputime_t) ret; | ||
69 | } | ||
70 | static inline void cputime_to_timespec(const cputime_t ct, struct timespec *val) | ||
71 | { | ||
72 | val->tv_sec = (__force u64) ct / NSEC_PER_SEC; | ||
73 | val->tv_nsec = (__force u64) ct % NSEC_PER_SEC; | ||
74 | } | ||
75 | |||
76 | /* | ||
77 | * Convert cputime <-> timeval (msec) | ||
78 | */ | ||
79 | static inline cputime_t timeval_to_cputime(struct timeval *val) | ||
80 | { | ||
81 | u64 ret = val->tv_sec * NSEC_PER_SEC + val->tv_usec * NSEC_PER_USEC; | ||
82 | return (__force cputime_t) ret; | ||
83 | } | ||
84 | static inline void cputime_to_timeval(const cputime_t ct, struct timeval *val) | ||
85 | { | ||
86 | val->tv_sec = (__force u64) ct / NSEC_PER_SEC; | ||
87 | val->tv_usec = ((__force u64) ct % NSEC_PER_SEC) / NSEC_PER_USEC; | ||
88 | } | ||
89 | |||
90 | /* | ||
91 | * Convert cputime <-> clock (USER_HZ) | ||
92 | */ | ||
93 | #define cputime_to_clock_t(__ct) \ | ||
94 | ((__force u64)(__ct) / (NSEC_PER_SEC / USER_HZ)) | ||
95 | #define clock_t_to_cputime(__x) \ | ||
96 | (__force cputime_t)((__x) * (NSEC_PER_SEC / USER_HZ)) | ||
97 | |||
98 | /* | ||
99 | * Convert cputime64 to clock. | ||
100 | */ | ||
101 | #define cputime64_to_clock_t(__ct) \ | ||
102 | cputime_to_clock_t((__force cputime_t)__ct) | ||
103 | |||
104 | #endif | ||
diff --git a/include/linux/aer.h b/include/linux/aer.h index 544abdb2238c..ec10e1b24c1c 100644 --- a/include/linux/aer.h +++ b/include/linux/aer.h | |||
@@ -49,8 +49,8 @@ static inline int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev) | |||
49 | } | 49 | } |
50 | #endif | 50 | #endif |
51 | 51 | ||
52 | extern void cper_print_aer(const char *prefix, int cper_severity, | 52 | extern void cper_print_aer(const char *prefix, struct pci_dev *dev, |
53 | struct aer_capability_regs *aer); | 53 | int cper_severity, struct aer_capability_regs *aer); |
54 | extern int cper_severity_to_aer(int cper_severity); | 54 | extern int cper_severity_to_aer(int cper_severity); |
55 | extern void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn, | 55 | extern void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn, |
56 | int severity); | 56 | int severity); |
diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h index 8a7096fcb01e..66346521cb65 100644 --- a/include/linux/clockchips.h +++ b/include/linux/clockchips.h | |||
@@ -161,6 +161,15 @@ clockevents_calc_mult_shift(struct clock_event_device *ce, u32 freq, u32 minsec) | |||
161 | extern void clockevents_suspend(void); | 161 | extern void clockevents_suspend(void); |
162 | extern void clockevents_resume(void); | 162 | extern void clockevents_resume(void); |
163 | 163 | ||
164 | #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST | ||
165 | #ifdef CONFIG_ARCH_HAS_TICK_BROADCAST | ||
166 | extern void tick_broadcast(const struct cpumask *mask); | ||
167 | #else | ||
168 | #define tick_broadcast NULL | ||
169 | #endif | ||
170 | extern int tick_receive_broadcast(void); | ||
171 | #endif | ||
172 | |||
164 | #ifdef CONFIG_GENERIC_CLOCKEVENTS | 173 | #ifdef CONFIG_GENERIC_CLOCKEVENTS |
165 | extern void clockevents_notify(unsigned long reason, void *arg); | 174 | extern void clockevents_notify(unsigned long reason, void *arg); |
166 | #else | 175 | #else |
diff --git a/include/linux/context_tracking.h b/include/linux/context_tracking.h index e24339ccb7f0..b28d161c1091 100644 --- a/include/linux/context_tracking.h +++ b/include/linux/context_tracking.h | |||
@@ -3,12 +3,40 @@ | |||
3 | 3 | ||
4 | #ifdef CONFIG_CONTEXT_TRACKING | 4 | #ifdef CONFIG_CONTEXT_TRACKING |
5 | #include <linux/sched.h> | 5 | #include <linux/sched.h> |
6 | #include <linux/percpu.h> | ||
7 | |||
8 | struct context_tracking { | ||
9 | /* | ||
10 | * When active is false, probes are unset in order | ||
11 | * to minimize overhead: TIF flags are cleared | ||
12 | * and calls to user_enter/exit are ignored. This | ||
13 | * may be further optimized using static keys. | ||
14 | */ | ||
15 | bool active; | ||
16 | enum { | ||
17 | IN_KERNEL = 0, | ||
18 | IN_USER, | ||
19 | } state; | ||
20 | }; | ||
21 | |||
22 | DECLARE_PER_CPU(struct context_tracking, context_tracking); | ||
23 | |||
24 | static inline bool context_tracking_in_user(void) | ||
25 | { | ||
26 | return __this_cpu_read(context_tracking.state) == IN_USER; | ||
27 | } | ||
28 | |||
29 | static inline bool context_tracking_active(void) | ||
30 | { | ||
31 | return __this_cpu_read(context_tracking.active); | ||
32 | } | ||
6 | 33 | ||
7 | extern void user_enter(void); | 34 | extern void user_enter(void); |
8 | extern void user_exit(void); | 35 | extern void user_exit(void); |
9 | extern void context_tracking_task_switch(struct task_struct *prev, | 36 | extern void context_tracking_task_switch(struct task_struct *prev, |
10 | struct task_struct *next); | 37 | struct task_struct *next); |
11 | #else | 38 | #else |
39 | static inline bool context_tracking_in_user(void) { return false; } | ||
12 | static inline void user_enter(void) { } | 40 | static inline void user_enter(void) { } |
13 | static inline void user_exit(void) { } | 41 | static inline void user_exit(void) { } |
14 | static inline void context_tracking_task_switch(struct task_struct *prev, | 42 | static inline void context_tracking_task_switch(struct task_struct *prev, |
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index 92691d85c320..e5ca8ef50e9b 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h | |||
@@ -74,7 +74,7 @@ typedef void (*ftrace_func_t)(unsigned long ip, unsigned long parent_ip, | |||
74 | * SAVE_REGS - The ftrace_ops wants regs saved at each function called | 74 | * SAVE_REGS - The ftrace_ops wants regs saved at each function called |
75 | * and passed to the callback. If this flag is set, but the | 75 | * and passed to the callback. If this flag is set, but the |
76 | * architecture does not support passing regs | 76 | * architecture does not support passing regs |
77 | * (ARCH_SUPPORTS_FTRACE_SAVE_REGS is not defined), then the | 77 | * (CONFIG_DYNAMIC_FTRACE_WITH_REGS is not defined), then the |
78 | * ftrace_ops will fail to register, unless the next flag | 78 | * ftrace_ops will fail to register, unless the next flag |
79 | * is set. | 79 | * is set. |
80 | * SAVE_REGS_IF_SUPPORTED - This is the same as SAVE_REGS, but if the | 80 | * SAVE_REGS_IF_SUPPORTED - This is the same as SAVE_REGS, but if the |
@@ -418,7 +418,7 @@ void ftrace_modify_all_code(int command); | |||
418 | #endif | 418 | #endif |
419 | 419 | ||
420 | #ifndef FTRACE_REGS_ADDR | 420 | #ifndef FTRACE_REGS_ADDR |
421 | #ifdef ARCH_SUPPORTS_FTRACE_SAVE_REGS | 421 | #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS |
422 | # define FTRACE_REGS_ADDR ((unsigned long)ftrace_regs_caller) | 422 | # define FTRACE_REGS_ADDR ((unsigned long)ftrace_regs_caller) |
423 | #else | 423 | #else |
424 | # define FTRACE_REGS_ADDR FTRACE_ADDR | 424 | # define FTRACE_REGS_ADDR FTRACE_ADDR |
@@ -480,7 +480,7 @@ extern int ftrace_make_nop(struct module *mod, | |||
480 | */ | 480 | */ |
481 | extern int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr); | 481 | extern int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr); |
482 | 482 | ||
483 | #ifdef ARCH_SUPPORTS_FTRACE_SAVE_REGS | 483 | #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS |
484 | /** | 484 | /** |
485 | * ftrace_modify_call - convert from one addr to another (no nop) | 485 | * ftrace_modify_call - convert from one addr to another (no nop) |
486 | * @rec: the mcount call site record | 486 | * @rec: the mcount call site record |
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index a3d489531d83..13a54d0bdfa8 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h | |||
@@ -49,7 +49,6 @@ struct trace_entry { | |||
49 | unsigned char flags; | 49 | unsigned char flags; |
50 | unsigned char preempt_count; | 50 | unsigned char preempt_count; |
51 | int pid; | 51 | int pid; |
52 | int padding; | ||
53 | }; | 52 | }; |
54 | 53 | ||
55 | #define FTRACE_MAX_EVENT \ | 54 | #define FTRACE_MAX_EVENT \ |
@@ -84,6 +83,9 @@ struct trace_iterator { | |||
84 | long idx; | 83 | long idx; |
85 | 84 | ||
86 | cpumask_var_t started; | 85 | cpumask_var_t started; |
86 | |||
87 | /* it's true when current open file is snapshot */ | ||
88 | bool snapshot; | ||
87 | }; | 89 | }; |
88 | 90 | ||
89 | enum trace_iter_flags { | 91 | enum trace_iter_flags { |
@@ -272,7 +274,7 @@ extern int trace_define_field(struct ftrace_event_call *call, const char *type, | |||
272 | extern int trace_add_event_call(struct ftrace_event_call *call); | 274 | extern int trace_add_event_call(struct ftrace_event_call *call); |
273 | extern void trace_remove_event_call(struct ftrace_event_call *call); | 275 | extern void trace_remove_event_call(struct ftrace_event_call *call); |
274 | 276 | ||
275 | #define is_signed_type(type) (((type)(-1)) < 0) | 277 | #define is_signed_type(type) (((type)(-1)) < (type)0) |
276 | 278 | ||
277 | int trace_set_clr_event(const char *system, const char *event, int set); | 279 | int trace_set_clr_event(const char *system, const char *event, int set); |
278 | 280 | ||
diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h index 624ef3f45c8e..29eb805ea4a6 100644 --- a/include/linux/hardirq.h +++ b/include/linux/hardirq.h | |||
@@ -153,7 +153,7 @@ extern void rcu_nmi_exit(void); | |||
153 | */ | 153 | */ |
154 | #define __irq_enter() \ | 154 | #define __irq_enter() \ |
155 | do { \ | 155 | do { \ |
156 | vtime_account_irq_enter(current); \ | 156 | account_irq_enter_time(current); \ |
157 | add_preempt_count(HARDIRQ_OFFSET); \ | 157 | add_preempt_count(HARDIRQ_OFFSET); \ |
158 | trace_hardirq_enter(); \ | 158 | trace_hardirq_enter(); \ |
159 | } while (0) | 159 | } while (0) |
@@ -169,7 +169,7 @@ extern void irq_enter(void); | |||
169 | #define __irq_exit() \ | 169 | #define __irq_exit() \ |
170 | do { \ | 170 | do { \ |
171 | trace_hardirq_exit(); \ | 171 | trace_hardirq_exit(); \ |
172 | vtime_account_irq_exit(current); \ | 172 | account_irq_exit_time(current); \ |
173 | sub_preempt_count(HARDIRQ_OFFSET); \ | 173 | sub_preempt_count(HARDIRQ_OFFSET); \ |
174 | } while (0) | 174 | } while (0) |
175 | 175 | ||
@@ -180,10 +180,10 @@ extern void irq_exit(void); | |||
180 | 180 | ||
181 | #define nmi_enter() \ | 181 | #define nmi_enter() \ |
182 | do { \ | 182 | do { \ |
183 | lockdep_off(); \ | ||
183 | ftrace_nmi_enter(); \ | 184 | ftrace_nmi_enter(); \ |
184 | BUG_ON(in_nmi()); \ | 185 | BUG_ON(in_nmi()); \ |
185 | add_preempt_count(NMI_OFFSET + HARDIRQ_OFFSET); \ | 186 | add_preempt_count(NMI_OFFSET + HARDIRQ_OFFSET); \ |
186 | lockdep_off(); \ | ||
187 | rcu_nmi_enter(); \ | 187 | rcu_nmi_enter(); \ |
188 | trace_hardirq_enter(); \ | 188 | trace_hardirq_enter(); \ |
189 | } while (0) | 189 | } while (0) |
@@ -192,10 +192,10 @@ extern void irq_exit(void); | |||
192 | do { \ | 192 | do { \ |
193 | trace_hardirq_exit(); \ | 193 | trace_hardirq_exit(); \ |
194 | rcu_nmi_exit(); \ | 194 | rcu_nmi_exit(); \ |
195 | lockdep_on(); \ | ||
196 | BUG_ON(!in_nmi()); \ | 195 | BUG_ON(!in_nmi()); \ |
197 | sub_preempt_count(NMI_OFFSET + HARDIRQ_OFFSET); \ | 196 | sub_preempt_count(NMI_OFFSET + HARDIRQ_OFFSET); \ |
198 | ftrace_nmi_exit(); \ | 197 | ftrace_nmi_exit(); \ |
198 | lockdep_on(); \ | ||
199 | } while (0) | 199 | } while (0) |
200 | 200 | ||
201 | #endif /* LINUX_HARDIRQ_H */ | 201 | #endif /* LINUX_HARDIRQ_H */ |
diff --git a/include/linux/init_task.h b/include/linux/init_task.h index 6d087c5f57f7..5cd0f0949927 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h | |||
@@ -10,7 +10,9 @@ | |||
10 | #include <linux/pid_namespace.h> | 10 | #include <linux/pid_namespace.h> |
11 | #include <linux/user_namespace.h> | 11 | #include <linux/user_namespace.h> |
12 | #include <linux/securebits.h> | 12 | #include <linux/securebits.h> |
13 | #include <linux/seqlock.h> | ||
13 | #include <net/net_namespace.h> | 14 | #include <net/net_namespace.h> |
15 | #include <linux/sched/rt.h> | ||
14 | 16 | ||
15 | #ifdef CONFIG_SMP | 17 | #ifdef CONFIG_SMP |
16 | # define INIT_PUSHABLE_TASKS(tsk) \ | 18 | # define INIT_PUSHABLE_TASKS(tsk) \ |
@@ -141,6 +143,15 @@ extern struct task_group root_task_group; | |||
141 | # define INIT_PERF_EVENTS(tsk) | 143 | # define INIT_PERF_EVENTS(tsk) |
142 | #endif | 144 | #endif |
143 | 145 | ||
146 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN | ||
147 | # define INIT_VTIME(tsk) \ | ||
148 | .vtime_seqlock = __SEQLOCK_UNLOCKED(tsk.vtime_seqlock), \ | ||
149 | .vtime_snap = 0, \ | ||
150 | .vtime_snap_whence = VTIME_SYS, | ||
151 | #else | ||
152 | # define INIT_VTIME(tsk) | ||
153 | #endif | ||
154 | |||
144 | #define INIT_TASK_COMM "swapper" | 155 | #define INIT_TASK_COMM "swapper" |
145 | 156 | ||
146 | /* | 157 | /* |
@@ -210,6 +221,7 @@ extern struct task_group root_task_group; | |||
210 | INIT_TRACE_RECURSION \ | 221 | INIT_TRACE_RECURSION \ |
211 | INIT_TASK_RCU_PREEMPT(tsk) \ | 222 | INIT_TASK_RCU_PREEMPT(tsk) \ |
212 | INIT_CPUSET_SEQ \ | 223 | INIT_CPUSET_SEQ \ |
224 | INIT_VTIME(tsk) \ | ||
213 | } | 225 | } |
214 | 226 | ||
215 | 227 | ||
diff --git a/include/linux/irq.h b/include/linux/irq.h index fdf2c4a238cc..bc4e06611958 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h | |||
@@ -509,8 +509,11 @@ static inline void irq_set_percpu_devid_flags(unsigned int irq) | |||
509 | 509 | ||
510 | /* Handle dynamic irq creation and destruction */ | 510 | /* Handle dynamic irq creation and destruction */ |
511 | extern unsigned int create_irq_nr(unsigned int irq_want, int node); | 511 | extern unsigned int create_irq_nr(unsigned int irq_want, int node); |
512 | extern unsigned int __create_irqs(unsigned int from, unsigned int count, | ||
513 | int node); | ||
512 | extern int create_irq(void); | 514 | extern int create_irq(void); |
513 | extern void destroy_irq(unsigned int irq); | 515 | extern void destroy_irq(unsigned int irq); |
516 | extern void destroy_irqs(unsigned int irq, unsigned int count); | ||
514 | 517 | ||
515 | /* | 518 | /* |
516 | * Dynamic irq helper functions. Obsolete. Use irq_alloc_desc* and | 519 | * Dynamic irq helper functions. Obsolete. Use irq_alloc_desc* and |
@@ -528,6 +531,8 @@ extern int irq_set_handler_data(unsigned int irq, void *data); | |||
528 | extern int irq_set_chip_data(unsigned int irq, void *data); | 531 | extern int irq_set_chip_data(unsigned int irq, void *data); |
529 | extern int irq_set_irq_type(unsigned int irq, unsigned int type); | 532 | extern int irq_set_irq_type(unsigned int irq, unsigned int type); |
530 | extern int irq_set_msi_desc(unsigned int irq, struct msi_desc *entry); | 533 | extern int irq_set_msi_desc(unsigned int irq, struct msi_desc *entry); |
534 | extern int irq_set_msi_desc_off(unsigned int irq_base, unsigned int irq_offset, | ||
535 | struct msi_desc *entry); | ||
531 | extern struct irq_data *irq_get_irq_data(unsigned int irq); | 536 | extern struct irq_data *irq_get_irq_data(unsigned int irq); |
532 | 537 | ||
533 | static inline struct irq_chip *irq_get_chip(unsigned int irq) | 538 | static inline struct irq_chip *irq_get_chip(unsigned int irq) |
@@ -590,6 +595,9 @@ int __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node, | |||
590 | #define irq_alloc_desc_from(from, node) \ | 595 | #define irq_alloc_desc_from(from, node) \ |
591 | irq_alloc_descs(-1, from, 1, node) | 596 | irq_alloc_descs(-1, from, 1, node) |
592 | 597 | ||
598 | #define irq_alloc_descs_from(from, cnt, node) \ | ||
599 | irq_alloc_descs(-1, from, cnt, node) | ||
600 | |||
593 | void irq_free_descs(unsigned int irq, unsigned int cnt); | 601 | void irq_free_descs(unsigned int irq, unsigned int cnt); |
594 | int irq_reserve_irqs(unsigned int from, unsigned int cnt); | 602 | int irq_reserve_irqs(unsigned int from, unsigned int cnt); |
595 | 603 | ||
diff --git a/include/linux/irq_work.h b/include/linux/irq_work.h index 6a9e8f5399e2..f5dbce50466e 100644 --- a/include/linux/irq_work.h +++ b/include/linux/irq_work.h | |||
@@ -3,6 +3,20 @@ | |||
3 | 3 | ||
4 | #include <linux/llist.h> | 4 | #include <linux/llist.h> |
5 | 5 | ||
6 | /* | ||
7 | * An entry can be in one of four states: | ||
8 | * | ||
9 | * free NULL, 0 -> {claimed} : free to be used | ||
10 | * claimed NULL, 3 -> {pending} : claimed to be enqueued | ||
11 | * pending next, 3 -> {busy} : queued, pending callback | ||
12 | * busy NULL, 2 -> {free, claimed} : callback in progress, can be claimed | ||
13 | */ | ||
14 | |||
15 | #define IRQ_WORK_PENDING 1UL | ||
16 | #define IRQ_WORK_BUSY 2UL | ||
17 | #define IRQ_WORK_FLAGS 3UL | ||
18 | #define IRQ_WORK_LAZY 4UL /* Doesn't want IPI, wait for tick */ | ||
19 | |||
6 | struct irq_work { | 20 | struct irq_work { |
7 | unsigned long flags; | 21 | unsigned long flags; |
8 | struct llist_node llnode; | 22 | struct llist_node llnode; |
@@ -16,8 +30,14 @@ void init_irq_work(struct irq_work *work, void (*func)(struct irq_work *)) | |||
16 | work->func = func; | 30 | work->func = func; |
17 | } | 31 | } |
18 | 32 | ||
19 | bool irq_work_queue(struct irq_work *work); | 33 | void irq_work_queue(struct irq_work *work); |
20 | void irq_work_run(void); | 34 | void irq_work_run(void); |
21 | void irq_work_sync(struct irq_work *work); | 35 | void irq_work_sync(struct irq_work *work); |
22 | 36 | ||
37 | #ifdef CONFIG_IRQ_WORK | ||
38 | bool irq_work_needs_cpu(void); | ||
39 | #else | ||
40 | static bool irq_work_needs_cpu(void) { return false; } | ||
41 | #endif | ||
42 | |||
23 | #endif /* _LINUX_IRQ_WORK_H */ | 43 | #endif /* _LINUX_IRQ_WORK_H */ |
diff --git a/include/linux/kernel_stat.h b/include/linux/kernel_stat.h index 66b70780e910..ed5f6ed6eb77 100644 --- a/include/linux/kernel_stat.h +++ b/include/linux/kernel_stat.h | |||
@@ -127,7 +127,7 @@ extern void account_system_time(struct task_struct *, int, cputime_t, cputime_t) | |||
127 | extern void account_steal_time(cputime_t); | 127 | extern void account_steal_time(cputime_t); |
128 | extern void account_idle_time(cputime_t); | 128 | extern void account_idle_time(cputime_t); |
129 | 129 | ||
130 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 130 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE |
131 | static inline void account_process_tick(struct task_struct *tsk, int user) | 131 | static inline void account_process_tick(struct task_struct *tsk, int user) |
132 | { | 132 | { |
133 | vtime_account_user(tsk); | 133 | vtime_account_user(tsk); |
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h index 23755ba42abc..4b6ef4d33cc2 100644 --- a/include/linux/kprobes.h +++ b/include/linux/kprobes.h | |||
@@ -49,16 +49,6 @@ | |||
49 | #define KPROBE_REENTER 0x00000004 | 49 | #define KPROBE_REENTER 0x00000004 |
50 | #define KPROBE_HIT_SSDONE 0x00000008 | 50 | #define KPROBE_HIT_SSDONE 0x00000008 |
51 | 51 | ||
52 | /* | ||
53 | * If function tracer is enabled and the arch supports full | ||
54 | * passing of pt_regs to function tracing, then kprobes can | ||
55 | * optimize on top of function tracing. | ||
56 | */ | ||
57 | #if defined(CONFIG_FUNCTION_TRACER) && defined(ARCH_SUPPORTS_FTRACE_SAVE_REGS) \ | ||
58 | && defined(ARCH_SUPPORTS_KPROBES_ON_FTRACE) | ||
59 | # define KPROBES_CAN_USE_FTRACE | ||
60 | #endif | ||
61 | |||
62 | /* Attach to insert probes on any functions which should be ignored*/ | 52 | /* Attach to insert probes on any functions which should be ignored*/ |
63 | #define __kprobes __attribute__((__section__(".kprobes.text"))) | 53 | #define __kprobes __attribute__((__section__(".kprobes.text"))) |
64 | 54 | ||
@@ -316,7 +306,7 @@ extern int proc_kprobes_optimization_handler(struct ctl_table *table, | |||
316 | #endif | 306 | #endif |
317 | 307 | ||
318 | #endif /* CONFIG_OPTPROBES */ | 308 | #endif /* CONFIG_OPTPROBES */ |
319 | #ifdef KPROBES_CAN_USE_FTRACE | 309 | #ifdef CONFIG_KPROBES_ON_FTRACE |
320 | extern void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip, | 310 | extern void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip, |
321 | struct ftrace_ops *ops, struct pt_regs *regs); | 311 | struct ftrace_ops *ops, struct pt_regs *regs); |
322 | extern int arch_prepare_kprobe_ftrace(struct kprobe *p); | 312 | extern int arch_prepare_kprobe_ftrace(struct kprobe *p); |
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 2c497ab0d03d..b7996a768eb2 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/rcupdate.h> | 22 | #include <linux/rcupdate.h> |
23 | #include <linux/ratelimit.h> | 23 | #include <linux/ratelimit.h> |
24 | #include <linux/err.h> | 24 | #include <linux/err.h> |
25 | #include <linux/irqflags.h> | ||
25 | #include <asm/signal.h> | 26 | #include <asm/signal.h> |
26 | 27 | ||
27 | #include <linux/kvm.h> | 28 | #include <linux/kvm.h> |
@@ -740,15 +741,52 @@ static inline int kvm_deassign_device(struct kvm *kvm, | |||
740 | } | 741 | } |
741 | #endif /* CONFIG_IOMMU_API */ | 742 | #endif /* CONFIG_IOMMU_API */ |
742 | 743 | ||
743 | static inline void kvm_guest_enter(void) | 744 | static inline void __guest_enter(void) |
744 | { | 745 | { |
745 | BUG_ON(preemptible()); | ||
746 | /* | 746 | /* |
747 | * This is running in ioctl context so we can avoid | 747 | * This is running in ioctl context so we can avoid |
748 | * the call to vtime_account() with its unnecessary idle check. | 748 | * the call to vtime_account() with its unnecessary idle check. |
749 | */ | 749 | */ |
750 | vtime_account_system_irqsafe(current); | 750 | vtime_account_system(current); |
751 | current->flags |= PF_VCPU; | 751 | current->flags |= PF_VCPU; |
752 | } | ||
753 | |||
754 | static inline void __guest_exit(void) | ||
755 | { | ||
756 | /* | ||
757 | * This is running in ioctl context so we can avoid | ||
758 | * the call to vtime_account() with its unnecessary idle check. | ||
759 | */ | ||
760 | vtime_account_system(current); | ||
761 | current->flags &= ~PF_VCPU; | ||
762 | } | ||
763 | |||
764 | #ifdef CONFIG_CONTEXT_TRACKING | ||
765 | extern void guest_enter(void); | ||
766 | extern void guest_exit(void); | ||
767 | |||
768 | #else /* !CONFIG_CONTEXT_TRACKING */ | ||
769 | static inline void guest_enter(void) | ||
770 | { | ||
771 | __guest_enter(); | ||
772 | } | ||
773 | |||
774 | static inline void guest_exit(void) | ||
775 | { | ||
776 | __guest_exit(); | ||
777 | } | ||
778 | #endif /* !CONFIG_CONTEXT_TRACKING */ | ||
779 | |||
780 | static inline void kvm_guest_enter(void) | ||
781 | { | ||
782 | unsigned long flags; | ||
783 | |||
784 | BUG_ON(preemptible()); | ||
785 | |||
786 | local_irq_save(flags); | ||
787 | guest_enter(); | ||
788 | local_irq_restore(flags); | ||
789 | |||
752 | /* KVM does not hold any references to rcu protected data when it | 790 | /* KVM does not hold any references to rcu protected data when it |
753 | * switches CPU into a guest mode. In fact switching to a guest mode | 791 | * switches CPU into a guest mode. In fact switching to a guest mode |
754 | * is very similar to exiting to userspase from rcu point of view. In | 792 | * is very similar to exiting to userspase from rcu point of view. In |
@@ -761,12 +799,11 @@ static inline void kvm_guest_enter(void) | |||
761 | 799 | ||
762 | static inline void kvm_guest_exit(void) | 800 | static inline void kvm_guest_exit(void) |
763 | { | 801 | { |
764 | /* | 802 | unsigned long flags; |
765 | * This is running in ioctl context so we can avoid | 803 | |
766 | * the call to vtime_account() with its unnecessary idle check. | 804 | local_irq_save(flags); |
767 | */ | 805 | guest_exit(); |
768 | vtime_account_system_irqsafe(current); | 806 | local_irq_restore(flags); |
769 | current->flags &= ~PF_VCPU; | ||
770 | } | 807 | } |
771 | 808 | ||
772 | /* | 809 | /* |
diff --git a/include/linux/pci.h b/include/linux/pci.h index 15472d691ee6..6fa4dd2a3b9e 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
@@ -1101,6 +1101,12 @@ static inline int pci_enable_msi_block(struct pci_dev *dev, unsigned int nvec) | |||
1101 | return -1; | 1101 | return -1; |
1102 | } | 1102 | } |
1103 | 1103 | ||
1104 | static inline int | ||
1105 | pci_enable_msi_block_auto(struct pci_dev *dev, unsigned int *maxvec) | ||
1106 | { | ||
1107 | return -1; | ||
1108 | } | ||
1109 | |||
1104 | static inline void pci_msi_shutdown(struct pci_dev *dev) | 1110 | static inline void pci_msi_shutdown(struct pci_dev *dev) |
1105 | { } | 1111 | { } |
1106 | static inline void pci_disable_msi(struct pci_dev *dev) | 1112 | static inline void pci_disable_msi(struct pci_dev *dev) |
@@ -1132,6 +1138,7 @@ static inline int pci_msi_enabled(void) | |||
1132 | } | 1138 | } |
1133 | #else | 1139 | #else |
1134 | extern int pci_enable_msi_block(struct pci_dev *dev, unsigned int nvec); | 1140 | extern int pci_enable_msi_block(struct pci_dev *dev, unsigned int nvec); |
1141 | extern int pci_enable_msi_block_auto(struct pci_dev *dev, unsigned int *maxvec); | ||
1135 | extern void pci_msi_shutdown(struct pci_dev *dev); | 1142 | extern void pci_msi_shutdown(struct pci_dev *dev); |
1136 | extern void pci_disable_msi(struct pci_dev *dev); | 1143 | extern void pci_disable_msi(struct pci_dev *dev); |
1137 | extern int pci_msix_table_size(struct pci_dev *dev); | 1144 | extern int pci_msix_table_size(struct pci_dev *dev); |
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 6bfb2faa0b19..e47ee462c2f2 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h | |||
@@ -135,16 +135,21 @@ struct hw_perf_event { | |||
135 | struct { /* software */ | 135 | struct { /* software */ |
136 | struct hrtimer hrtimer; | 136 | struct hrtimer hrtimer; |
137 | }; | 137 | }; |
138 | struct { /* tracepoint */ | ||
139 | struct task_struct *tp_target; | ||
140 | /* for tp_event->class */ | ||
141 | struct list_head tp_list; | ||
142 | }; | ||
138 | #ifdef CONFIG_HAVE_HW_BREAKPOINT | 143 | #ifdef CONFIG_HAVE_HW_BREAKPOINT |
139 | struct { /* breakpoint */ | 144 | struct { /* breakpoint */ |
140 | struct arch_hw_breakpoint info; | ||
141 | struct list_head bp_list; | ||
142 | /* | 145 | /* |
143 | * Crufty hack to avoid the chicken and egg | 146 | * Crufty hack to avoid the chicken and egg |
144 | * problem hw_breakpoint has with context | 147 | * problem hw_breakpoint has with context |
145 | * creation and event initalization. | 148 | * creation and event initalization. |
146 | */ | 149 | */ |
147 | struct task_struct *bp_target; | 150 | struct task_struct *bp_target; |
151 | struct arch_hw_breakpoint info; | ||
152 | struct list_head bp_list; | ||
148 | }; | 153 | }; |
149 | #endif | 154 | #endif |
150 | }; | 155 | }; |
@@ -817,6 +822,17 @@ do { \ | |||
817 | } while (0) | 822 | } while (0) |
818 | 823 | ||
819 | 824 | ||
825 | struct perf_pmu_events_attr { | ||
826 | struct device_attribute attr; | ||
827 | u64 id; | ||
828 | }; | ||
829 | |||
830 | #define PMU_EVENT_ATTR(_name, _var, _id, _show) \ | ||
831 | static struct perf_pmu_events_attr _var = { \ | ||
832 | .attr = __ATTR(_name, 0444, _show, NULL), \ | ||
833 | .id = _id, \ | ||
834 | }; | ||
835 | |||
820 | #define PMU_FORMAT_ATTR(_name, _format) \ | 836 | #define PMU_FORMAT_ATTR(_name, _format) \ |
821 | static ssize_t \ | 837 | static ssize_t \ |
822 | _name##_show(struct device *dev, \ | 838 | _name##_show(struct device *dev, \ |
diff --git a/include/linux/printk.h b/include/linux/printk.h index 9afc01e5a0a6..86c4b6294713 100644 --- a/include/linux/printk.h +++ b/include/linux/printk.h | |||
@@ -98,9 +98,6 @@ int no_printk(const char *fmt, ...) | |||
98 | extern asmlinkage __printf(1, 2) | 98 | extern asmlinkage __printf(1, 2) |
99 | void early_printk(const char *fmt, ...); | 99 | void early_printk(const char *fmt, ...); |
100 | 100 | ||
101 | extern int printk_needs_cpu(int cpu); | ||
102 | extern void printk_tick(void); | ||
103 | |||
104 | #ifdef CONFIG_PRINTK | 101 | #ifdef CONFIG_PRINTK |
105 | asmlinkage __printf(5, 0) | 102 | asmlinkage __printf(5, 0) |
106 | int vprintk_emit(int facility, int level, | 103 | int vprintk_emit(int facility, int level, |
diff --git a/include/linux/profile.h b/include/linux/profile.h index a0fc32279fc0..21123902366d 100644 --- a/include/linux/profile.h +++ b/include/linux/profile.h | |||
@@ -82,9 +82,6 @@ int task_handoff_unregister(struct notifier_block * n); | |||
82 | int profile_event_register(enum profile_type, struct notifier_block * n); | 82 | int profile_event_register(enum profile_type, struct notifier_block * n); |
83 | int profile_event_unregister(enum profile_type, struct notifier_block * n); | 83 | int profile_event_unregister(enum profile_type, struct notifier_block * n); |
84 | 84 | ||
85 | int register_timer_hook(int (*hook)(struct pt_regs *)); | ||
86 | void unregister_timer_hook(int (*hook)(struct pt_regs *)); | ||
87 | |||
88 | struct pt_regs; | 85 | struct pt_regs; |
89 | 86 | ||
90 | #else | 87 | #else |
@@ -135,16 +132,6 @@ static inline int profile_event_unregister(enum profile_type t, struct notifier_ | |||
135 | #define profile_handoff_task(a) (0) | 132 | #define profile_handoff_task(a) (0) |
136 | #define profile_munmap(a) do { } while (0) | 133 | #define profile_munmap(a) do { } while (0) |
137 | 134 | ||
138 | static inline int register_timer_hook(int (*hook)(struct pt_regs *)) | ||
139 | { | ||
140 | return -ENOSYS; | ||
141 | } | ||
142 | |||
143 | static inline void unregister_timer_hook(int (*hook)(struct pt_regs *)) | ||
144 | { | ||
145 | return; | ||
146 | } | ||
147 | |||
148 | #endif /* CONFIG_PROFILING */ | 135 | #endif /* CONFIG_PROFILING */ |
149 | 136 | ||
150 | #endif /* _LINUX_PROFILE_H */ | 137 | #endif /* _LINUX_PROFILE_H */ |
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 275aa3f1062d..b758ce17b309 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h | |||
@@ -53,7 +53,10 @@ extern int rcutorture_runnable; /* for sysctl */ | |||
53 | extern void rcutorture_record_test_transition(void); | 53 | extern void rcutorture_record_test_transition(void); |
54 | extern void rcutorture_record_progress(unsigned long vernum); | 54 | extern void rcutorture_record_progress(unsigned long vernum); |
55 | extern void do_trace_rcu_torture_read(char *rcutorturename, | 55 | extern void do_trace_rcu_torture_read(char *rcutorturename, |
56 | struct rcu_head *rhp); | 56 | struct rcu_head *rhp, |
57 | unsigned long secs, | ||
58 | unsigned long c_old, | ||
59 | unsigned long c); | ||
57 | #else | 60 | #else |
58 | static inline void rcutorture_record_test_transition(void) | 61 | static inline void rcutorture_record_test_transition(void) |
59 | { | 62 | { |
@@ -63,9 +66,13 @@ static inline void rcutorture_record_progress(unsigned long vernum) | |||
63 | } | 66 | } |
64 | #ifdef CONFIG_RCU_TRACE | 67 | #ifdef CONFIG_RCU_TRACE |
65 | extern void do_trace_rcu_torture_read(char *rcutorturename, | 68 | extern void do_trace_rcu_torture_read(char *rcutorturename, |
66 | struct rcu_head *rhp); | 69 | struct rcu_head *rhp, |
70 | unsigned long secs, | ||
71 | unsigned long c_old, | ||
72 | unsigned long c); | ||
67 | #else | 73 | #else |
68 | #define do_trace_rcu_torture_read(rcutorturename, rhp) do { } while (0) | 74 | #define do_trace_rcu_torture_read(rcutorturename, rhp, secs, c_old, c) \ |
75 | do { } while (0) | ||
69 | #endif | 76 | #endif |
70 | #endif | 77 | #endif |
71 | 78 | ||
@@ -749,7 +756,7 @@ static inline void rcu_preempt_sleep_check(void) | |||
749 | * preemptible RCU implementations (TREE_PREEMPT_RCU and TINY_PREEMPT_RCU) | 756 | * preemptible RCU implementations (TREE_PREEMPT_RCU and TINY_PREEMPT_RCU) |
750 | * in CONFIG_PREEMPT kernel builds, RCU read-side critical sections may | 757 | * in CONFIG_PREEMPT kernel builds, RCU read-side critical sections may |
751 | * be preempted, but explicit blocking is illegal. Finally, in preemptible | 758 | * be preempted, but explicit blocking is illegal. Finally, in preemptible |
752 | * RCU implementations in real-time (CONFIG_PREEMPT_RT) kernel builds, | 759 | * RCU implementations in real-time (with -rt patchset) kernel builds, |
753 | * RCU read-side critical sections may be preempted and they may also | 760 | * RCU read-side critical sections may be preempted and they may also |
754 | * block, but only when acquiring spinlocks that are subject to priority | 761 | * block, but only when acquiring spinlocks that are subject to priority |
755 | * inheritance. | 762 | * inheritance. |
diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h index 519777e3fa01..1342e69542f3 100644 --- a/include/linux/ring_buffer.h +++ b/include/linux/ring_buffer.h | |||
@@ -167,6 +167,7 @@ unsigned long ring_buffer_entries_cpu(struct ring_buffer *buffer, int cpu); | |||
167 | unsigned long ring_buffer_overrun_cpu(struct ring_buffer *buffer, int cpu); | 167 | unsigned long ring_buffer_overrun_cpu(struct ring_buffer *buffer, int cpu); |
168 | unsigned long ring_buffer_commit_overrun_cpu(struct ring_buffer *buffer, int cpu); | 168 | unsigned long ring_buffer_commit_overrun_cpu(struct ring_buffer *buffer, int cpu); |
169 | unsigned long ring_buffer_dropped_events_cpu(struct ring_buffer *buffer, int cpu); | 169 | unsigned long ring_buffer_dropped_events_cpu(struct ring_buffer *buffer, int cpu); |
170 | unsigned long ring_buffer_read_events_cpu(struct ring_buffer *buffer, int cpu); | ||
170 | 171 | ||
171 | u64 ring_buffer_time_stamp(struct ring_buffer *buffer, int cpu); | 172 | u64 ring_buffer_time_stamp(struct ring_buffer *buffer, int cpu); |
172 | void ring_buffer_normalize_time_stamp(struct ring_buffer *buffer, | 173 | void ring_buffer_normalize_time_stamp(struct ring_buffer *buffer, |
diff --git a/include/linux/rtc.h b/include/linux/rtc.h index 9531845c419f..11d05f9fe8b6 100644 --- a/include/linux/rtc.h +++ b/include/linux/rtc.h | |||
@@ -138,6 +138,7 @@ extern void rtc_device_unregister(struct rtc_device *rtc); | |||
138 | extern int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm); | 138 | extern int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm); |
139 | extern int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm); | 139 | extern int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm); |
140 | extern int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs); | 140 | extern int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs); |
141 | extern int rtc_set_ntp_time(struct timespec now); | ||
141 | int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm); | 142 | int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm); |
142 | extern int rtc_read_alarm(struct rtc_device *rtc, | 143 | extern int rtc_read_alarm(struct rtc_device *rtc, |
143 | struct rtc_wkalrm *alrm); | 144 | struct rtc_wkalrm *alrm); |
diff --git a/include/linux/sched.h b/include/linux/sched.h index d2112477ff5e..33cc42130371 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -304,19 +304,6 @@ static inline void lockup_detector_init(void) | |||
304 | } | 304 | } |
305 | #endif | 305 | #endif |
306 | 306 | ||
307 | #ifdef CONFIG_DETECT_HUNG_TASK | ||
308 | extern unsigned int sysctl_hung_task_panic; | ||
309 | extern unsigned long sysctl_hung_task_check_count; | ||
310 | extern unsigned long sysctl_hung_task_timeout_secs; | ||
311 | extern unsigned long sysctl_hung_task_warnings; | ||
312 | extern int proc_dohung_task_timeout_secs(struct ctl_table *table, int write, | ||
313 | void __user *buffer, | ||
314 | size_t *lenp, loff_t *ppos); | ||
315 | #else | ||
316 | /* Avoid need for ifdefs elsewhere in the code */ | ||
317 | enum { sysctl_hung_task_timeout_secs = 0 }; | ||
318 | #endif | ||
319 | |||
320 | /* Attach to any functions which should be ignored in wchan output. */ | 307 | /* Attach to any functions which should be ignored in wchan output. */ |
321 | #define __sched __attribute__((__section__(".sched.text"))) | 308 | #define __sched __attribute__((__section__(".sched.text"))) |
322 | 309 | ||
@@ -338,23 +325,6 @@ extern int mutex_spin_on_owner(struct mutex *lock, struct task_struct *owner); | |||
338 | struct nsproxy; | 325 | struct nsproxy; |
339 | struct user_namespace; | 326 | struct user_namespace; |
340 | 327 | ||
341 | /* | ||
342 | * Default maximum number of active map areas, this limits the number of vmas | ||
343 | * per mm struct. Users can overwrite this number by sysctl but there is a | ||
344 | * problem. | ||
345 | * | ||
346 | * When a program's coredump is generated as ELF format, a section is created | ||
347 | * per a vma. In ELF, the number of sections is represented in unsigned short. | ||
348 | * This means the number of sections should be smaller than 65535 at coredump. | ||
349 | * Because the kernel adds some informative sections to a image of program at | ||
350 | * generating coredump, we need some margin. The number of extra sections is | ||
351 | * 1-3 now and depends on arch. We use "5" as safe margin, here. | ||
352 | */ | ||
353 | #define MAPCOUNT_ELF_CORE_MARGIN (5) | ||
354 | #define DEFAULT_MAX_MAP_COUNT (USHRT_MAX - MAPCOUNT_ELF_CORE_MARGIN) | ||
355 | |||
356 | extern int sysctl_max_map_count; | ||
357 | |||
358 | #include <linux/aio.h> | 328 | #include <linux/aio.h> |
359 | 329 | ||
360 | #ifdef CONFIG_MMU | 330 | #ifdef CONFIG_MMU |
@@ -1194,6 +1164,7 @@ struct sched_entity { | |||
1194 | /* rq "owned" by this entity/group: */ | 1164 | /* rq "owned" by this entity/group: */ |
1195 | struct cfs_rq *my_q; | 1165 | struct cfs_rq *my_q; |
1196 | #endif | 1166 | #endif |
1167 | |||
1197 | /* | 1168 | /* |
1198 | * Load-tracking only depends on SMP, FAIR_GROUP_SCHED dependency below may be | 1169 | * Load-tracking only depends on SMP, FAIR_GROUP_SCHED dependency below may be |
1199 | * removed when useful for applications beyond shares distribution (e.g. | 1170 | * removed when useful for applications beyond shares distribution (e.g. |
@@ -1208,6 +1179,7 @@ struct sched_entity { | |||
1208 | struct sched_rt_entity { | 1179 | struct sched_rt_entity { |
1209 | struct list_head run_list; | 1180 | struct list_head run_list; |
1210 | unsigned long timeout; | 1181 | unsigned long timeout; |
1182 | unsigned long watchdog_stamp; | ||
1211 | unsigned int time_slice; | 1183 | unsigned int time_slice; |
1212 | 1184 | ||
1213 | struct sched_rt_entity *back; | 1185 | struct sched_rt_entity *back; |
@@ -1220,11 +1192,6 @@ struct sched_rt_entity { | |||
1220 | #endif | 1192 | #endif |
1221 | }; | 1193 | }; |
1222 | 1194 | ||
1223 | /* | ||
1224 | * default timeslice is 100 msecs (used only for SCHED_RR tasks). | ||
1225 | * Timeslices get refilled after they expire. | ||
1226 | */ | ||
1227 | #define RR_TIMESLICE (100 * HZ / 1000) | ||
1228 | 1195 | ||
1229 | struct rcu_node; | 1196 | struct rcu_node; |
1230 | 1197 | ||
@@ -1368,6 +1335,15 @@ struct task_struct { | |||
1368 | #ifndef CONFIG_VIRT_CPU_ACCOUNTING | 1335 | #ifndef CONFIG_VIRT_CPU_ACCOUNTING |
1369 | struct cputime prev_cputime; | 1336 | struct cputime prev_cputime; |
1370 | #endif | 1337 | #endif |
1338 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN | ||
1339 | seqlock_t vtime_seqlock; | ||
1340 | unsigned long long vtime_snap; | ||
1341 | enum { | ||
1342 | VTIME_SLEEPING = 0, | ||
1343 | VTIME_USER, | ||
1344 | VTIME_SYS, | ||
1345 | } vtime_snap_whence; | ||
1346 | #endif | ||
1371 | unsigned long nvcsw, nivcsw; /* context switch counts */ | 1347 | unsigned long nvcsw, nivcsw; /* context switch counts */ |
1372 | struct timespec start_time; /* monotonic time */ | 1348 | struct timespec start_time; /* monotonic time */ |
1373 | struct timespec real_start_time; /* boot based time */ | 1349 | struct timespec real_start_time; /* boot based time */ |
@@ -1622,37 +1598,6 @@ static inline void set_numabalancing_state(bool enabled) | |||
1622 | } | 1598 | } |
1623 | #endif | 1599 | #endif |
1624 | 1600 | ||
1625 | /* | ||
1626 | * Priority of a process goes from 0..MAX_PRIO-1, valid RT | ||
1627 | * priority is 0..MAX_RT_PRIO-1, and SCHED_NORMAL/SCHED_BATCH | ||
1628 | * tasks are in the range MAX_RT_PRIO..MAX_PRIO-1. Priority | ||
1629 | * values are inverted: lower p->prio value means higher priority. | ||
1630 | * | ||
1631 | * The MAX_USER_RT_PRIO value allows the actual maximum | ||
1632 | * RT priority to be separate from the value exported to | ||
1633 | * user-space. This allows kernel threads to set their | ||
1634 | * priority to a value higher than any user task. Note: | ||
1635 | * MAX_RT_PRIO must not be smaller than MAX_USER_RT_PRIO. | ||
1636 | */ | ||
1637 | |||
1638 | #define MAX_USER_RT_PRIO 100 | ||
1639 | #define MAX_RT_PRIO MAX_USER_RT_PRIO | ||
1640 | |||
1641 | #define MAX_PRIO (MAX_RT_PRIO + 40) | ||
1642 | #define DEFAULT_PRIO (MAX_RT_PRIO + 20) | ||
1643 | |||
1644 | static inline int rt_prio(int prio) | ||
1645 | { | ||
1646 | if (unlikely(prio < MAX_RT_PRIO)) | ||
1647 | return 1; | ||
1648 | return 0; | ||
1649 | } | ||
1650 | |||
1651 | static inline int rt_task(struct task_struct *p) | ||
1652 | { | ||
1653 | return rt_prio(p->prio); | ||
1654 | } | ||
1655 | |||
1656 | static inline struct pid *task_pid(struct task_struct *task) | 1601 | static inline struct pid *task_pid(struct task_struct *task) |
1657 | { | 1602 | { |
1658 | return task->pids[PIDTYPE_PID].pid; | 1603 | return task->pids[PIDTYPE_PID].pid; |
@@ -1792,6 +1737,37 @@ static inline void put_task_struct(struct task_struct *t) | |||
1792 | __put_task_struct(t); | 1737 | __put_task_struct(t); |
1793 | } | 1738 | } |
1794 | 1739 | ||
1740 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN | ||
1741 | extern void task_cputime(struct task_struct *t, | ||
1742 | cputime_t *utime, cputime_t *stime); | ||
1743 | extern void task_cputime_scaled(struct task_struct *t, | ||
1744 | cputime_t *utimescaled, cputime_t *stimescaled); | ||
1745 | extern cputime_t task_gtime(struct task_struct *t); | ||
1746 | #else | ||
1747 | static inline void task_cputime(struct task_struct *t, | ||
1748 | cputime_t *utime, cputime_t *stime) | ||
1749 | { | ||
1750 | if (utime) | ||
1751 | *utime = t->utime; | ||
1752 | if (stime) | ||
1753 | *stime = t->stime; | ||
1754 | } | ||
1755 | |||
1756 | static inline void task_cputime_scaled(struct task_struct *t, | ||
1757 | cputime_t *utimescaled, | ||
1758 | cputime_t *stimescaled) | ||
1759 | { | ||
1760 | if (utimescaled) | ||
1761 | *utimescaled = t->utimescaled; | ||
1762 | if (stimescaled) | ||
1763 | *stimescaled = t->stimescaled; | ||
1764 | } | ||
1765 | |||
1766 | static inline cputime_t task_gtime(struct task_struct *t) | ||
1767 | { | ||
1768 | return t->gtime; | ||
1769 | } | ||
1770 | #endif | ||
1795 | extern void task_cputime_adjusted(struct task_struct *p, cputime_t *ut, cputime_t *st); | 1771 | extern void task_cputime_adjusted(struct task_struct *p, cputime_t *ut, cputime_t *st); |
1796 | extern void thread_group_cputime_adjusted(struct task_struct *p, cputime_t *ut, cputime_t *st); | 1772 | extern void thread_group_cputime_adjusted(struct task_struct *p, cputime_t *ut, cputime_t *st); |
1797 | 1773 | ||
@@ -2033,58 +2009,7 @@ extern void wake_up_idle_cpu(int cpu); | |||
2033 | static inline void wake_up_idle_cpu(int cpu) { } | 2009 | static inline void wake_up_idle_cpu(int cpu) { } |
2034 | #endif | 2010 | #endif |
2035 | 2011 | ||
2036 | extern unsigned int sysctl_sched_latency; | ||
2037 | extern unsigned int sysctl_sched_min_granularity; | ||
2038 | extern unsigned int sysctl_sched_wakeup_granularity; | ||
2039 | extern unsigned int sysctl_sched_child_runs_first; | ||
2040 | |||
2041 | enum sched_tunable_scaling { | ||
2042 | SCHED_TUNABLESCALING_NONE, | ||
2043 | SCHED_TUNABLESCALING_LOG, | ||
2044 | SCHED_TUNABLESCALING_LINEAR, | ||
2045 | SCHED_TUNABLESCALING_END, | ||
2046 | }; | ||
2047 | extern enum sched_tunable_scaling sysctl_sched_tunable_scaling; | ||
2048 | |||
2049 | extern unsigned int sysctl_numa_balancing_scan_delay; | ||
2050 | extern unsigned int sysctl_numa_balancing_scan_period_min; | ||
2051 | extern unsigned int sysctl_numa_balancing_scan_period_max; | ||
2052 | extern unsigned int sysctl_numa_balancing_scan_period_reset; | ||
2053 | extern unsigned int sysctl_numa_balancing_scan_size; | ||
2054 | extern unsigned int sysctl_numa_balancing_settle_count; | ||
2055 | |||
2056 | #ifdef CONFIG_SCHED_DEBUG | ||
2057 | extern unsigned int sysctl_sched_migration_cost; | ||
2058 | extern unsigned int sysctl_sched_nr_migrate; | ||
2059 | extern unsigned int sysctl_sched_time_avg; | ||
2060 | extern unsigned int sysctl_timer_migration; | ||
2061 | extern unsigned int sysctl_sched_shares_window; | ||
2062 | |||
2063 | int sched_proc_update_handler(struct ctl_table *table, int write, | ||
2064 | void __user *buffer, size_t *length, | ||
2065 | loff_t *ppos); | ||
2066 | #endif | ||
2067 | #ifdef CONFIG_SCHED_DEBUG | ||
2068 | static inline unsigned int get_sysctl_timer_migration(void) | ||
2069 | { | ||
2070 | return sysctl_timer_migration; | ||
2071 | } | ||
2072 | #else | ||
2073 | static inline unsigned int get_sysctl_timer_migration(void) | ||
2074 | { | ||
2075 | return 1; | ||
2076 | } | ||
2077 | #endif | ||
2078 | extern unsigned int sysctl_sched_rt_period; | ||
2079 | extern int sysctl_sched_rt_runtime; | ||
2080 | |||
2081 | int sched_rt_handler(struct ctl_table *table, int write, | ||
2082 | void __user *buffer, size_t *lenp, | ||
2083 | loff_t *ppos); | ||
2084 | |||
2085 | #ifdef CONFIG_SCHED_AUTOGROUP | 2012 | #ifdef CONFIG_SCHED_AUTOGROUP |
2086 | extern unsigned int sysctl_sched_autogroup_enabled; | ||
2087 | |||
2088 | extern void sched_autogroup_create_attach(struct task_struct *p); | 2013 | extern void sched_autogroup_create_attach(struct task_struct *p); |
2089 | extern void sched_autogroup_detach(struct task_struct *p); | 2014 | extern void sched_autogroup_detach(struct task_struct *p); |
2090 | extern void sched_autogroup_fork(struct signal_struct *sig); | 2015 | extern void sched_autogroup_fork(struct signal_struct *sig); |
@@ -2100,30 +2025,6 @@ static inline void sched_autogroup_fork(struct signal_struct *sig) { } | |||
2100 | static inline void sched_autogroup_exit(struct signal_struct *sig) { } | 2025 | static inline void sched_autogroup_exit(struct signal_struct *sig) { } |
2101 | #endif | 2026 | #endif |
2102 | 2027 | ||
2103 | #ifdef CONFIG_CFS_BANDWIDTH | ||
2104 | extern unsigned int sysctl_sched_cfs_bandwidth_slice; | ||
2105 | #endif | ||
2106 | |||
2107 | #ifdef CONFIG_RT_MUTEXES | ||
2108 | extern int rt_mutex_getprio(struct task_struct *p); | ||
2109 | extern void rt_mutex_setprio(struct task_struct *p, int prio); | ||
2110 | extern void rt_mutex_adjust_pi(struct task_struct *p); | ||
2111 | static inline bool tsk_is_pi_blocked(struct task_struct *tsk) | ||
2112 | { | ||
2113 | return tsk->pi_blocked_on != NULL; | ||
2114 | } | ||
2115 | #else | ||
2116 | static inline int rt_mutex_getprio(struct task_struct *p) | ||
2117 | { | ||
2118 | return p->normal_prio; | ||
2119 | } | ||
2120 | # define rt_mutex_adjust_pi(p) do { } while (0) | ||
2121 | static inline bool tsk_is_pi_blocked(struct task_struct *tsk) | ||
2122 | { | ||
2123 | return false; | ||
2124 | } | ||
2125 | #endif | ||
2126 | |||
2127 | extern bool yield_to(struct task_struct *p, bool preempt); | 2028 | extern bool yield_to(struct task_struct *p, bool preempt); |
2128 | extern void set_user_nice(struct task_struct *p, long nice); | 2029 | extern void set_user_nice(struct task_struct *p, long nice); |
2129 | extern int task_prio(const struct task_struct *p); | 2030 | extern int task_prio(const struct task_struct *p); |
@@ -2753,8 +2654,6 @@ static inline void set_task_cpu(struct task_struct *p, unsigned int cpu) | |||
2753 | extern long sched_setaffinity(pid_t pid, const struct cpumask *new_mask); | 2654 | extern long sched_setaffinity(pid_t pid, const struct cpumask *new_mask); |
2754 | extern long sched_getaffinity(pid_t pid, struct cpumask *mask); | 2655 | extern long sched_getaffinity(pid_t pid, struct cpumask *mask); |
2755 | 2656 | ||
2756 | extern void normalize_rt_tasks(void); | ||
2757 | |||
2758 | #ifdef CONFIG_CGROUP_SCHED | 2657 | #ifdef CONFIG_CGROUP_SCHED |
2759 | 2658 | ||
2760 | extern struct task_group root_task_group; | 2659 | extern struct task_group root_task_group; |
diff --git a/include/linux/sched/rt.h b/include/linux/sched/rt.h new file mode 100644 index 000000000000..94e19ea28fc3 --- /dev/null +++ b/include/linux/sched/rt.h | |||
@@ -0,0 +1,58 @@ | |||
1 | #ifndef _SCHED_RT_H | ||
2 | #define _SCHED_RT_H | ||
3 | |||
4 | /* | ||
5 | * Priority of a process goes from 0..MAX_PRIO-1, valid RT | ||
6 | * priority is 0..MAX_RT_PRIO-1, and SCHED_NORMAL/SCHED_BATCH | ||
7 | * tasks are in the range MAX_RT_PRIO..MAX_PRIO-1. Priority | ||
8 | * values are inverted: lower p->prio value means higher priority. | ||
9 | * | ||
10 | * The MAX_USER_RT_PRIO value allows the actual maximum | ||
11 | * RT priority to be separate from the value exported to | ||
12 | * user-space. This allows kernel threads to set their | ||
13 | * priority to a value higher than any user task. Note: | ||
14 | * MAX_RT_PRIO must not be smaller than MAX_USER_RT_PRIO. | ||
15 | */ | ||
16 | |||
17 | #define MAX_USER_RT_PRIO 100 | ||
18 | #define MAX_RT_PRIO MAX_USER_RT_PRIO | ||
19 | |||
20 | #define MAX_PRIO (MAX_RT_PRIO + 40) | ||
21 | #define DEFAULT_PRIO (MAX_RT_PRIO + 20) | ||
22 | |||
23 | static inline int rt_prio(int prio) | ||
24 | { | ||
25 | if (unlikely(prio < MAX_RT_PRIO)) | ||
26 | return 1; | ||
27 | return 0; | ||
28 | } | ||
29 | |||
30 | static inline int rt_task(struct task_struct *p) | ||
31 | { | ||
32 | return rt_prio(p->prio); | ||
33 | } | ||
34 | |||
35 | #ifdef CONFIG_RT_MUTEXES | ||
36 | extern int rt_mutex_getprio(struct task_struct *p); | ||
37 | extern void rt_mutex_setprio(struct task_struct *p, int prio); | ||
38 | extern void rt_mutex_adjust_pi(struct task_struct *p); | ||
39 | static inline bool tsk_is_pi_blocked(struct task_struct *tsk) | ||
40 | { | ||
41 | return tsk->pi_blocked_on != NULL; | ||
42 | } | ||
43 | #else | ||
44 | static inline int rt_mutex_getprio(struct task_struct *p) | ||
45 | { | ||
46 | return p->normal_prio; | ||
47 | } | ||
48 | # define rt_mutex_adjust_pi(p) do { } while (0) | ||
49 | static inline bool tsk_is_pi_blocked(struct task_struct *tsk) | ||
50 | { | ||
51 | return false; | ||
52 | } | ||
53 | #endif | ||
54 | |||
55 | extern void normalize_rt_tasks(void); | ||
56 | |||
57 | |||
58 | #endif /* _SCHED_RT_H */ | ||
diff --git a/include/linux/sched/sysctl.h b/include/linux/sched/sysctl.h new file mode 100644 index 000000000000..d2bb0ae979d0 --- /dev/null +++ b/include/linux/sched/sysctl.h | |||
@@ -0,0 +1,110 @@ | |||
1 | #ifndef _SCHED_SYSCTL_H | ||
2 | #define _SCHED_SYSCTL_H | ||
3 | |||
4 | #ifdef CONFIG_DETECT_HUNG_TASK | ||
5 | extern unsigned int sysctl_hung_task_panic; | ||
6 | extern unsigned long sysctl_hung_task_check_count; | ||
7 | extern unsigned long sysctl_hung_task_timeout_secs; | ||
8 | extern unsigned long sysctl_hung_task_warnings; | ||
9 | extern int proc_dohung_task_timeout_secs(struct ctl_table *table, int write, | ||
10 | void __user *buffer, | ||
11 | size_t *lenp, loff_t *ppos); | ||
12 | #else | ||
13 | /* Avoid need for ifdefs elsewhere in the code */ | ||
14 | enum { sysctl_hung_task_timeout_secs = 0 }; | ||
15 | #endif | ||
16 | |||
17 | /* | ||
18 | * Default maximum number of active map areas, this limits the number of vmas | ||
19 | * per mm struct. Users can overwrite this number by sysctl but there is a | ||
20 | * problem. | ||
21 | * | ||
22 | * When a program's coredump is generated as ELF format, a section is created | ||
23 | * per a vma. In ELF, the number of sections is represented in unsigned short. | ||
24 | * This means the number of sections should be smaller than 65535 at coredump. | ||
25 | * Because the kernel adds some informative sections to a image of program at | ||
26 | * generating coredump, we need some margin. The number of extra sections is | ||
27 | * 1-3 now and depends on arch. We use "5" as safe margin, here. | ||
28 | */ | ||
29 | #define MAPCOUNT_ELF_CORE_MARGIN (5) | ||
30 | #define DEFAULT_MAX_MAP_COUNT (USHRT_MAX - MAPCOUNT_ELF_CORE_MARGIN) | ||
31 | |||
32 | extern int sysctl_max_map_count; | ||
33 | |||
34 | extern unsigned int sysctl_sched_latency; | ||
35 | extern unsigned int sysctl_sched_min_granularity; | ||
36 | extern unsigned int sysctl_sched_wakeup_granularity; | ||
37 | extern unsigned int sysctl_sched_child_runs_first; | ||
38 | |||
39 | enum sched_tunable_scaling { | ||
40 | SCHED_TUNABLESCALING_NONE, | ||
41 | SCHED_TUNABLESCALING_LOG, | ||
42 | SCHED_TUNABLESCALING_LINEAR, | ||
43 | SCHED_TUNABLESCALING_END, | ||
44 | }; | ||
45 | extern enum sched_tunable_scaling sysctl_sched_tunable_scaling; | ||
46 | |||
47 | extern unsigned int sysctl_numa_balancing_scan_delay; | ||
48 | extern unsigned int sysctl_numa_balancing_scan_period_min; | ||
49 | extern unsigned int sysctl_numa_balancing_scan_period_max; | ||
50 | extern unsigned int sysctl_numa_balancing_scan_period_reset; | ||
51 | extern unsigned int sysctl_numa_balancing_scan_size; | ||
52 | extern unsigned int sysctl_numa_balancing_settle_count; | ||
53 | |||
54 | #ifdef CONFIG_SCHED_DEBUG | ||
55 | extern unsigned int sysctl_sched_migration_cost; | ||
56 | extern unsigned int sysctl_sched_nr_migrate; | ||
57 | extern unsigned int sysctl_sched_time_avg; | ||
58 | extern unsigned int sysctl_timer_migration; | ||
59 | extern unsigned int sysctl_sched_shares_window; | ||
60 | |||
61 | int sched_proc_update_handler(struct ctl_table *table, int write, | ||
62 | void __user *buffer, size_t *length, | ||
63 | loff_t *ppos); | ||
64 | #endif | ||
65 | #ifdef CONFIG_SCHED_DEBUG | ||
66 | static inline unsigned int get_sysctl_timer_migration(void) | ||
67 | { | ||
68 | return sysctl_timer_migration; | ||
69 | } | ||
70 | #else | ||
71 | static inline unsigned int get_sysctl_timer_migration(void) | ||
72 | { | ||
73 | return 1; | ||
74 | } | ||
75 | #endif | ||
76 | |||
77 | /* | ||
78 | * control realtime throttling: | ||
79 | * | ||
80 | * /proc/sys/kernel/sched_rt_period_us | ||
81 | * /proc/sys/kernel/sched_rt_runtime_us | ||
82 | */ | ||
83 | extern unsigned int sysctl_sched_rt_period; | ||
84 | extern int sysctl_sched_rt_runtime; | ||
85 | |||
86 | #ifdef CONFIG_CFS_BANDWIDTH | ||
87 | extern unsigned int sysctl_sched_cfs_bandwidth_slice; | ||
88 | #endif | ||
89 | |||
90 | #ifdef CONFIG_SCHED_AUTOGROUP | ||
91 | extern unsigned int sysctl_sched_autogroup_enabled; | ||
92 | #endif | ||
93 | |||
94 | /* | ||
95 | * default timeslice is 100 msecs (used only for SCHED_RR tasks). | ||
96 | * Timeslices get refilled after they expire. | ||
97 | */ | ||
98 | #define RR_TIMESLICE (100 * HZ / 1000) | ||
99 | |||
100 | extern int sched_rr_timeslice; | ||
101 | |||
102 | extern int sched_rr_handler(struct ctl_table *table, int write, | ||
103 | void __user *buffer, size_t *lenp, | ||
104 | loff_t *ppos); | ||
105 | |||
106 | extern int sched_rt_handler(struct ctl_table *table, int write, | ||
107 | void __user *buffer, size_t *lenp, | ||
108 | loff_t *ppos); | ||
109 | |||
110 | #endif /* _SCHED_SYSCTL_H */ | ||
diff --git a/include/linux/smpboot.h b/include/linux/smpboot.h index e0106d8581d3..c65dee059913 100644 --- a/include/linux/smpboot.h +++ b/include/linux/smpboot.h | |||
@@ -14,6 +14,8 @@ struct smpboot_thread_data; | |||
14 | * @thread_should_run: Check whether the thread should run or not. Called with | 14 | * @thread_should_run: Check whether the thread should run or not. Called with |
15 | * preemption disabled. | 15 | * preemption disabled. |
16 | * @thread_fn: The associated thread function | 16 | * @thread_fn: The associated thread function |
17 | * @create: Optional setup function, called when the thread gets | ||
18 | * created (Not called from the thread context) | ||
17 | * @setup: Optional setup function, called when the thread gets | 19 | * @setup: Optional setup function, called when the thread gets |
18 | * operational the first time | 20 | * operational the first time |
19 | * @cleanup: Optional cleanup function, called when the thread | 21 | * @cleanup: Optional cleanup function, called when the thread |
@@ -22,6 +24,7 @@ struct smpboot_thread_data; | |||
22 | * parked (cpu offline) | 24 | * parked (cpu offline) |
23 | * @unpark: Optional unpark function, called when the thread is | 25 | * @unpark: Optional unpark function, called when the thread is |
24 | * unparked (cpu online) | 26 | * unparked (cpu online) |
27 | * @selfparking: Thread is not parked by the park function. | ||
25 | * @thread_comm: The base name of the thread | 28 | * @thread_comm: The base name of the thread |
26 | */ | 29 | */ |
27 | struct smp_hotplug_thread { | 30 | struct smp_hotplug_thread { |
@@ -29,10 +32,12 @@ struct smp_hotplug_thread { | |||
29 | struct list_head list; | 32 | struct list_head list; |
30 | int (*thread_should_run)(unsigned int cpu); | 33 | int (*thread_should_run)(unsigned int cpu); |
31 | void (*thread_fn)(unsigned int cpu); | 34 | void (*thread_fn)(unsigned int cpu); |
35 | void (*create)(unsigned int cpu); | ||
32 | void (*setup)(unsigned int cpu); | 36 | void (*setup)(unsigned int cpu); |
33 | void (*cleanup)(unsigned int cpu, bool online); | 37 | void (*cleanup)(unsigned int cpu, bool online); |
34 | void (*park)(unsigned int cpu); | 38 | void (*park)(unsigned int cpu); |
35 | void (*unpark)(unsigned int cpu); | 39 | void (*unpark)(unsigned int cpu); |
40 | bool selfparking; | ||
36 | const char *thread_comm; | 41 | const char *thread_comm; |
37 | }; | 42 | }; |
38 | 43 | ||
diff --git a/include/linux/srcu.h b/include/linux/srcu.h index 6eb691b08358..04f4121a23ae 100644 --- a/include/linux/srcu.h +++ b/include/linux/srcu.h | |||
@@ -151,30 +151,14 @@ void srcu_barrier(struct srcu_struct *sp); | |||
151 | * Checks debug_lockdep_rcu_enabled() to prevent false positives during boot | 151 | * Checks debug_lockdep_rcu_enabled() to prevent false positives during boot |
152 | * and while lockdep is disabled. | 152 | * and while lockdep is disabled. |
153 | * | 153 | * |
154 | * Note that if the CPU is in the idle loop from an RCU point of view | 154 | * Note that SRCU is based on its own statemachine and it doesn't |
155 | * (ie: that we are in the section between rcu_idle_enter() and | 155 | * relies on normal RCU, it can be called from the CPU which |
156 | * rcu_idle_exit()) then srcu_read_lock_held() returns false even if | 156 | * is in the idle loop from an RCU point of view or offline. |
157 | * the CPU did an srcu_read_lock(). The reason for this is that RCU | ||
158 | * ignores CPUs that are in such a section, considering these as in | ||
159 | * extended quiescent state, so such a CPU is effectively never in an | ||
160 | * RCU read-side critical section regardless of what RCU primitives it | ||
161 | * invokes. This state of affairs is required --- we need to keep an | ||
162 | * RCU-free window in idle where the CPU may possibly enter into low | ||
163 | * power mode. This way we can notice an extended quiescent state to | ||
164 | * other CPUs that started a grace period. Otherwise we would delay any | ||
165 | * grace period as long as we run in the idle task. | ||
166 | * | ||
167 | * Similarly, we avoid claiming an SRCU read lock held if the current | ||
168 | * CPU is offline. | ||
169 | */ | 157 | */ |
170 | static inline int srcu_read_lock_held(struct srcu_struct *sp) | 158 | static inline int srcu_read_lock_held(struct srcu_struct *sp) |
171 | { | 159 | { |
172 | if (!debug_lockdep_rcu_enabled()) | 160 | if (!debug_lockdep_rcu_enabled()) |
173 | return 1; | 161 | return 1; |
174 | if (rcu_is_cpu_idle()) | ||
175 | return 0; | ||
176 | if (!rcu_lockdep_current_cpu_online()) | ||
177 | return 0; | ||
178 | return lock_is_held(&sp->dep_map); | 162 | return lock_is_held(&sp->dep_map); |
179 | } | 163 | } |
180 | 164 | ||
@@ -236,8 +220,6 @@ static inline int srcu_read_lock(struct srcu_struct *sp) __acquires(sp) | |||
236 | int retval = __srcu_read_lock(sp); | 220 | int retval = __srcu_read_lock(sp); |
237 | 221 | ||
238 | rcu_lock_acquire(&(sp)->dep_map); | 222 | rcu_lock_acquire(&(sp)->dep_map); |
239 | rcu_lockdep_assert(!rcu_is_cpu_idle(), | ||
240 | "srcu_read_lock() used illegally while idle"); | ||
241 | return retval; | 223 | return retval; |
242 | } | 224 | } |
243 | 225 | ||
@@ -251,8 +233,6 @@ static inline int srcu_read_lock(struct srcu_struct *sp) __acquires(sp) | |||
251 | static inline void srcu_read_unlock(struct srcu_struct *sp, int idx) | 233 | static inline void srcu_read_unlock(struct srcu_struct *sp, int idx) |
252 | __releases(sp) | 234 | __releases(sp) |
253 | { | 235 | { |
254 | rcu_lockdep_assert(!rcu_is_cpu_idle(), | ||
255 | "srcu_read_unlock() used illegally while idle"); | ||
256 | rcu_lock_release(&(sp)->dep_map); | 236 | rcu_lock_release(&(sp)->dep_map); |
257 | __srcu_read_unlock(sp, idx); | 237 | __srcu_read_unlock(sp, idx); |
258 | } | 238 | } |
diff --git a/include/linux/tick.h b/include/linux/tick.h index 1a6567b48492..553272e6af55 100644 --- a/include/linux/tick.h +++ b/include/linux/tick.h | |||
@@ -8,6 +8,8 @@ | |||
8 | 8 | ||
9 | #include <linux/clockchips.h> | 9 | #include <linux/clockchips.h> |
10 | #include <linux/irqflags.h> | 10 | #include <linux/irqflags.h> |
11 | #include <linux/percpu.h> | ||
12 | #include <linux/hrtimer.h> | ||
11 | 13 | ||
12 | #ifdef CONFIG_GENERIC_CLOCKEVENTS | 14 | #ifdef CONFIG_GENERIC_CLOCKEVENTS |
13 | 15 | ||
@@ -122,13 +124,26 @@ static inline int tick_oneshot_mode_active(void) { return 0; } | |||
122 | #endif /* !CONFIG_GENERIC_CLOCKEVENTS */ | 124 | #endif /* !CONFIG_GENERIC_CLOCKEVENTS */ |
123 | 125 | ||
124 | # ifdef CONFIG_NO_HZ | 126 | # ifdef CONFIG_NO_HZ |
127 | DECLARE_PER_CPU(struct tick_sched, tick_cpu_sched); | ||
128 | |||
129 | static inline int tick_nohz_tick_stopped(void) | ||
130 | { | ||
131 | return __this_cpu_read(tick_cpu_sched.tick_stopped); | ||
132 | } | ||
133 | |||
125 | extern void tick_nohz_idle_enter(void); | 134 | extern void tick_nohz_idle_enter(void); |
126 | extern void tick_nohz_idle_exit(void); | 135 | extern void tick_nohz_idle_exit(void); |
127 | extern void tick_nohz_irq_exit(void); | 136 | extern void tick_nohz_irq_exit(void); |
128 | extern ktime_t tick_nohz_get_sleep_length(void); | 137 | extern ktime_t tick_nohz_get_sleep_length(void); |
129 | extern u64 get_cpu_idle_time_us(int cpu, u64 *last_update_time); | 138 | extern u64 get_cpu_idle_time_us(int cpu, u64 *last_update_time); |
130 | extern u64 get_cpu_iowait_time_us(int cpu, u64 *last_update_time); | 139 | extern u64 get_cpu_iowait_time_us(int cpu, u64 *last_update_time); |
131 | # else | 140 | |
141 | # else /* !CONFIG_NO_HZ */ | ||
142 | static inline int tick_nohz_tick_stopped(void) | ||
143 | { | ||
144 | return 0; | ||
145 | } | ||
146 | |||
132 | static inline void tick_nohz_idle_enter(void) { } | 147 | static inline void tick_nohz_idle_enter(void) { } |
133 | static inline void tick_nohz_idle_exit(void) { } | 148 | static inline void tick_nohz_idle_exit(void) { } |
134 | 149 | ||
diff --git a/include/linux/time.h b/include/linux/time.h index 4d358e9d10f1..a3ab6a814a9c 100644 --- a/include/linux/time.h +++ b/include/linux/time.h | |||
@@ -115,8 +115,20 @@ static inline bool timespec_valid_strict(const struct timespec *ts) | |||
115 | return true; | 115 | return true; |
116 | } | 116 | } |
117 | 117 | ||
118 | extern bool persistent_clock_exist; | ||
119 | |||
120 | #ifdef ALWAYS_USE_PERSISTENT_CLOCK | ||
121 | #define has_persistent_clock() true | ||
122 | #else | ||
123 | static inline bool has_persistent_clock(void) | ||
124 | { | ||
125 | return persistent_clock_exist; | ||
126 | } | ||
127 | #endif | ||
128 | |||
118 | extern void read_persistent_clock(struct timespec *ts); | 129 | extern void read_persistent_clock(struct timespec *ts); |
119 | extern void read_boot_clock(struct timespec *ts); | 130 | extern void read_boot_clock(struct timespec *ts); |
131 | extern int persistent_clock_is_local; | ||
120 | extern int update_persistent_clock(struct timespec now); | 132 | extern int update_persistent_clock(struct timespec now); |
121 | void timekeeping_init(void); | 133 | void timekeeping_init(void); |
122 | extern int timekeeping_suspended; | 134 | extern int timekeeping_suspended; |
@@ -158,6 +170,7 @@ extern int do_setitimer(int which, struct itimerval *value, | |||
158 | struct itimerval *ovalue); | 170 | struct itimerval *ovalue); |
159 | extern unsigned int alarm_setitimer(unsigned int seconds); | 171 | extern unsigned int alarm_setitimer(unsigned int seconds); |
160 | extern int do_getitimer(int which, struct itimerval *value); | 172 | extern int do_getitimer(int which, struct itimerval *value); |
173 | extern int __getnstimeofday(struct timespec *tv); | ||
161 | extern void getnstimeofday(struct timespec *tv); | 174 | extern void getnstimeofday(struct timespec *tv); |
162 | extern void getrawmonotonic(struct timespec *ts); | 175 | extern void getrawmonotonic(struct timespec *ts); |
163 | extern void getnstime_raw_and_real(struct timespec *ts_raw, | 176 | extern void getnstime_raw_and_real(struct timespec *ts_raw, |
diff --git a/include/linux/tsacct_kern.h b/include/linux/tsacct_kern.h index 44893e5ec8f7..3251965bf4cc 100644 --- a/include/linux/tsacct_kern.h +++ b/include/linux/tsacct_kern.h | |||
@@ -23,12 +23,15 @@ static inline void bacct_add_tsk(struct user_namespace *user_ns, | |||
23 | #ifdef CONFIG_TASK_XACCT | 23 | #ifdef CONFIG_TASK_XACCT |
24 | extern void xacct_add_tsk(struct taskstats *stats, struct task_struct *p); | 24 | extern void xacct_add_tsk(struct taskstats *stats, struct task_struct *p); |
25 | extern void acct_update_integrals(struct task_struct *tsk); | 25 | extern void acct_update_integrals(struct task_struct *tsk); |
26 | extern void acct_account_cputime(struct task_struct *tsk); | ||
26 | extern void acct_clear_integrals(struct task_struct *tsk); | 27 | extern void acct_clear_integrals(struct task_struct *tsk); |
27 | #else | 28 | #else |
28 | static inline void xacct_add_tsk(struct taskstats *stats, struct task_struct *p) | 29 | static inline void xacct_add_tsk(struct taskstats *stats, struct task_struct *p) |
29 | {} | 30 | {} |
30 | static inline void acct_update_integrals(struct task_struct *tsk) | 31 | static inline void acct_update_integrals(struct task_struct *tsk) |
31 | {} | 32 | {} |
33 | static inline void acct_account_cputime(struct task_struct *tsk) | ||
34 | {} | ||
32 | static inline void acct_clear_integrals(struct task_struct *tsk) | 35 | static inline void acct_clear_integrals(struct task_struct *tsk) |
33 | {} | 36 | {} |
34 | #endif /* CONFIG_TASK_XACCT */ | 37 | #endif /* CONFIG_TASK_XACCT */ |
diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h index 4f628a6fc5b4..02b83db8e2c5 100644 --- a/include/linux/uprobes.h +++ b/include/linux/uprobes.h | |||
@@ -35,13 +35,20 @@ struct inode; | |||
35 | # include <asm/uprobes.h> | 35 | # include <asm/uprobes.h> |
36 | #endif | 36 | #endif |
37 | 37 | ||
38 | #define UPROBE_HANDLER_REMOVE 1 | ||
39 | #define UPROBE_HANDLER_MASK 1 | ||
40 | |||
41 | enum uprobe_filter_ctx { | ||
42 | UPROBE_FILTER_REGISTER, | ||
43 | UPROBE_FILTER_UNREGISTER, | ||
44 | UPROBE_FILTER_MMAP, | ||
45 | }; | ||
46 | |||
38 | struct uprobe_consumer { | 47 | struct uprobe_consumer { |
39 | int (*handler)(struct uprobe_consumer *self, struct pt_regs *regs); | 48 | int (*handler)(struct uprobe_consumer *self, struct pt_regs *regs); |
40 | /* | 49 | bool (*filter)(struct uprobe_consumer *self, |
41 | * filter is optional; If a filter exists, handler is run | 50 | enum uprobe_filter_ctx ctx, |
42 | * if and only if filter returns true. | 51 | struct mm_struct *mm); |
43 | */ | ||
44 | bool (*filter)(struct uprobe_consumer *self, struct task_struct *task); | ||
45 | 52 | ||
46 | struct uprobe_consumer *next; | 53 | struct uprobe_consumer *next; |
47 | }; | 54 | }; |
@@ -94,6 +101,7 @@ extern int __weak set_swbp(struct arch_uprobe *aup, struct mm_struct *mm, unsign | |||
94 | extern int __weak set_orig_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr); | 101 | extern int __weak set_orig_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr); |
95 | extern bool __weak is_swbp_insn(uprobe_opcode_t *insn); | 102 | extern bool __weak is_swbp_insn(uprobe_opcode_t *insn); |
96 | extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc); | 103 | extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc); |
104 | extern int uprobe_apply(struct inode *inode, loff_t offset, struct uprobe_consumer *uc, bool); | ||
97 | extern void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc); | 105 | extern void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc); |
98 | extern int uprobe_mmap(struct vm_area_struct *vma); | 106 | extern int uprobe_mmap(struct vm_area_struct *vma); |
99 | extern void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end); | 107 | extern void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end); |
@@ -117,6 +125,11 @@ uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc) | |||
117 | { | 125 | { |
118 | return -ENOSYS; | 126 | return -ENOSYS; |
119 | } | 127 | } |
128 | static inline int | ||
129 | uprobe_apply(struct inode *inode, loff_t offset, struct uprobe_consumer *uc, bool add) | ||
130 | { | ||
131 | return -ENOSYS; | ||
132 | } | ||
120 | static inline void | 133 | static inline void |
121 | uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc) | 134 | uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc) |
122 | { | 135 | { |
diff --git a/include/linux/vtime.h b/include/linux/vtime.h index ae30ab58431a..71a5782d8c59 100644 --- a/include/linux/vtime.h +++ b/include/linux/vtime.h | |||
@@ -6,15 +6,46 @@ struct task_struct; | |||
6 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | 6 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING |
7 | extern void vtime_task_switch(struct task_struct *prev); | 7 | extern void vtime_task_switch(struct task_struct *prev); |
8 | extern void vtime_account_system(struct task_struct *tsk); | 8 | extern void vtime_account_system(struct task_struct *tsk); |
9 | extern void vtime_account_system_irqsafe(struct task_struct *tsk); | ||
10 | extern void vtime_account_idle(struct task_struct *tsk); | 9 | extern void vtime_account_idle(struct task_struct *tsk); |
11 | extern void vtime_account_user(struct task_struct *tsk); | 10 | extern void vtime_account_user(struct task_struct *tsk); |
12 | extern void vtime_account(struct task_struct *tsk); | 11 | extern void vtime_account_irq_enter(struct task_struct *tsk); |
13 | #else | 12 | |
13 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE | ||
14 | static inline bool vtime_accounting_enabled(void) { return true; } | ||
15 | #endif | ||
16 | |||
17 | #else /* !CONFIG_VIRT_CPU_ACCOUNTING */ | ||
18 | |||
14 | static inline void vtime_task_switch(struct task_struct *prev) { } | 19 | static inline void vtime_task_switch(struct task_struct *prev) { } |
15 | static inline void vtime_account_system(struct task_struct *tsk) { } | 20 | static inline void vtime_account_system(struct task_struct *tsk) { } |
16 | static inline void vtime_account_system_irqsafe(struct task_struct *tsk) { } | 21 | static inline void vtime_account_user(struct task_struct *tsk) { } |
17 | static inline void vtime_account(struct task_struct *tsk) { } | 22 | static inline void vtime_account_irq_enter(struct task_struct *tsk) { } |
23 | static inline bool vtime_accounting_enabled(void) { return false; } | ||
24 | #endif | ||
25 | |||
26 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN | ||
27 | extern void arch_vtime_task_switch(struct task_struct *tsk); | ||
28 | extern void vtime_account_irq_exit(struct task_struct *tsk); | ||
29 | extern bool vtime_accounting_enabled(void); | ||
30 | extern void vtime_user_enter(struct task_struct *tsk); | ||
31 | static inline void vtime_user_exit(struct task_struct *tsk) | ||
32 | { | ||
33 | vtime_account_user(tsk); | ||
34 | } | ||
35 | extern void vtime_guest_enter(struct task_struct *tsk); | ||
36 | extern void vtime_guest_exit(struct task_struct *tsk); | ||
37 | extern void vtime_init_idle(struct task_struct *tsk); | ||
38 | #else | ||
39 | static inline void vtime_account_irq_exit(struct task_struct *tsk) | ||
40 | { | ||
41 | /* On hard|softirq exit we always account to hard|softirq cputime */ | ||
42 | vtime_account_system(tsk); | ||
43 | } | ||
44 | static inline void vtime_user_enter(struct task_struct *tsk) { } | ||
45 | static inline void vtime_user_exit(struct task_struct *tsk) { } | ||
46 | static inline void vtime_guest_enter(struct task_struct *tsk) { } | ||
47 | static inline void vtime_guest_exit(struct task_struct *tsk) { } | ||
48 | static inline void vtime_init_idle(struct task_struct *tsk) { } | ||
18 | #endif | 49 | #endif |
19 | 50 | ||
20 | #ifdef CONFIG_IRQ_TIME_ACCOUNTING | 51 | #ifdef CONFIG_IRQ_TIME_ACCOUNTING |
@@ -23,25 +54,15 @@ extern void irqtime_account_irq(struct task_struct *tsk); | |||
23 | static inline void irqtime_account_irq(struct task_struct *tsk) { } | 54 | static inline void irqtime_account_irq(struct task_struct *tsk) { } |
24 | #endif | 55 | #endif |
25 | 56 | ||
26 | static inline void vtime_account_irq_enter(struct task_struct *tsk) | 57 | static inline void account_irq_enter_time(struct task_struct *tsk) |
27 | { | 58 | { |
28 | /* | 59 | vtime_account_irq_enter(tsk); |
29 | * Hardirq can interrupt idle task anytime. So we need vtime_account() | ||
30 | * that performs the idle check in CONFIG_VIRT_CPU_ACCOUNTING. | ||
31 | * Softirq can also interrupt idle task directly if it calls | ||
32 | * local_bh_enable(). Such case probably don't exist but we never know. | ||
33 | * Ksoftirqd is not concerned because idle time is flushed on context | ||
34 | * switch. Softirqs in the end of hardirqs are also not a problem because | ||
35 | * the idle time is flushed on hardirq time already. | ||
36 | */ | ||
37 | vtime_account(tsk); | ||
38 | irqtime_account_irq(tsk); | 60 | irqtime_account_irq(tsk); |
39 | } | 61 | } |
40 | 62 | ||
41 | static inline void vtime_account_irq_exit(struct task_struct *tsk) | 63 | static inline void account_irq_exit_time(struct task_struct *tsk) |
42 | { | 64 | { |
43 | /* On hard|softirq exit we always account to hard|softirq cputime */ | 65 | vtime_account_irq_exit(tsk); |
44 | vtime_account_system(tsk); | ||
45 | irqtime_account_irq(tsk); | 66 | irqtime_account_irq(tsk); |
46 | } | 67 | } |
47 | 68 | ||
diff --git a/include/trace/events/ras.h b/include/trace/events/ras.h new file mode 100644 index 000000000000..88b878383797 --- /dev/null +++ b/include/trace/events/ras.h | |||
@@ -0,0 +1,77 @@ | |||
1 | #undef TRACE_SYSTEM | ||
2 | #define TRACE_SYSTEM ras | ||
3 | |||
4 | #if !defined(_TRACE_AER_H) || defined(TRACE_HEADER_MULTI_READ) | ||
5 | #define _TRACE_AER_H | ||
6 | |||
7 | #include <linux/tracepoint.h> | ||
8 | #include <linux/edac.h> | ||
9 | |||
10 | |||
11 | /* | ||
12 | * PCIe AER Trace event | ||
13 | * | ||
14 | * These events are generated when hardware detects a corrected or | ||
15 | * uncorrected event on a PCIe device. The event report has | ||
16 | * the following structure: | ||
17 | * | ||
18 | * char * dev_name - The name of the slot where the device resides | ||
19 | * ([domain:]bus:device.function). | ||
20 | * u32 status - Either the correctable or uncorrectable register | ||
21 | * indicating what error or errors have been seen | ||
22 | * u8 severity - error severity 0:NONFATAL 1:FATAL 2:CORRECTED | ||
23 | */ | ||
24 | |||
25 | #define aer_correctable_errors \ | ||
26 | {BIT(0), "Receiver Error"}, \ | ||
27 | {BIT(6), "Bad TLP"}, \ | ||
28 | {BIT(7), "Bad DLLP"}, \ | ||
29 | {BIT(8), "RELAY_NUM Rollover"}, \ | ||
30 | {BIT(12), "Replay Timer Timeout"}, \ | ||
31 | {BIT(13), "Advisory Non-Fatal"} | ||
32 | |||
33 | #define aer_uncorrectable_errors \ | ||
34 | {BIT(4), "Data Link Protocol"}, \ | ||
35 | {BIT(12), "Poisoned TLP"}, \ | ||
36 | {BIT(13), "Flow Control Protocol"}, \ | ||
37 | {BIT(14), "Completion Timeout"}, \ | ||
38 | {BIT(15), "Completer Abort"}, \ | ||
39 | {BIT(16), "Unexpected Completion"}, \ | ||
40 | {BIT(17), "Receiver Overflow"}, \ | ||
41 | {BIT(18), "Malformed TLP"}, \ | ||
42 | {BIT(19), "ECRC"}, \ | ||
43 | {BIT(20), "Unsupported Request"} | ||
44 | |||
45 | TRACE_EVENT(aer_event, | ||
46 | TP_PROTO(const char *dev_name, | ||
47 | const u32 status, | ||
48 | const u8 severity), | ||
49 | |||
50 | TP_ARGS(dev_name, status, severity), | ||
51 | |||
52 | TP_STRUCT__entry( | ||
53 | __string( dev_name, dev_name ) | ||
54 | __field( u32, status ) | ||
55 | __field( u8, severity ) | ||
56 | ), | ||
57 | |||
58 | TP_fast_assign( | ||
59 | __assign_str(dev_name, dev_name); | ||
60 | __entry->status = status; | ||
61 | __entry->severity = severity; | ||
62 | ), | ||
63 | |||
64 | TP_printk("%s PCIe Bus Error: severity=%s, %s\n", | ||
65 | __get_str(dev_name), | ||
66 | __entry->severity == HW_EVENT_ERR_CORRECTED ? "Corrected" : | ||
67 | __entry->severity == HW_EVENT_ERR_FATAL ? | ||
68 | "Fatal" : "Uncorrected", | ||
69 | __entry->severity == HW_EVENT_ERR_CORRECTED ? | ||
70 | __print_flags(__entry->status, "|", aer_correctable_errors) : | ||
71 | __print_flags(__entry->status, "|", aer_uncorrectable_errors)) | ||
72 | ); | ||
73 | |||
74 | #endif /* _TRACE_AER_H */ | ||
75 | |||
76 | /* This part must be outside protection */ | ||
77 | #include <trace/define_trace.h> | ||
diff --git a/include/trace/events/rcu.h b/include/trace/events/rcu.h index d4f559b1ec34..1918e832da4f 100644 --- a/include/trace/events/rcu.h +++ b/include/trace/events/rcu.h | |||
@@ -44,8 +44,10 @@ TRACE_EVENT(rcu_utilization, | |||
44 | * of a new grace period or the end of an old grace period ("cpustart" | 44 | * of a new grace period or the end of an old grace period ("cpustart" |
45 | * and "cpuend", respectively), a CPU passing through a quiescent | 45 | * and "cpuend", respectively), a CPU passing through a quiescent |
46 | * state ("cpuqs"), a CPU coming online or going offline ("cpuonl" | 46 | * state ("cpuqs"), a CPU coming online or going offline ("cpuonl" |
47 | * and "cpuofl", respectively), and a CPU being kicked for being too | 47 | * and "cpuofl", respectively), a CPU being kicked for being too |
48 | * long in dyntick-idle mode ("kick"). | 48 | * long in dyntick-idle mode ("kick"), a CPU accelerating its new |
49 | * callbacks to RCU_NEXT_READY_TAIL ("AccReadyCB"), and a CPU | ||
50 | * accelerating its new callbacks to RCU_WAIT_TAIL ("AccWaitCB"). | ||
49 | */ | 51 | */ |
50 | TRACE_EVENT(rcu_grace_period, | 52 | TRACE_EVENT(rcu_grace_period, |
51 | 53 | ||
@@ -393,7 +395,7 @@ TRACE_EVENT(rcu_kfree_callback, | |||
393 | */ | 395 | */ |
394 | TRACE_EVENT(rcu_batch_start, | 396 | TRACE_EVENT(rcu_batch_start, |
395 | 397 | ||
396 | TP_PROTO(char *rcuname, long qlen_lazy, long qlen, int blimit), | 398 | TP_PROTO(char *rcuname, long qlen_lazy, long qlen, long blimit), |
397 | 399 | ||
398 | TP_ARGS(rcuname, qlen_lazy, qlen, blimit), | 400 | TP_ARGS(rcuname, qlen_lazy, qlen, blimit), |
399 | 401 | ||
@@ -401,7 +403,7 @@ TRACE_EVENT(rcu_batch_start, | |||
401 | __field(char *, rcuname) | 403 | __field(char *, rcuname) |
402 | __field(long, qlen_lazy) | 404 | __field(long, qlen_lazy) |
403 | __field(long, qlen) | 405 | __field(long, qlen) |
404 | __field(int, blimit) | 406 | __field(long, blimit) |
405 | ), | 407 | ), |
406 | 408 | ||
407 | TP_fast_assign( | 409 | TP_fast_assign( |
@@ -411,7 +413,7 @@ TRACE_EVENT(rcu_batch_start, | |||
411 | __entry->blimit = blimit; | 413 | __entry->blimit = blimit; |
412 | ), | 414 | ), |
413 | 415 | ||
414 | TP_printk("%s CBs=%ld/%ld bl=%d", | 416 | TP_printk("%s CBs=%ld/%ld bl=%ld", |
415 | __entry->rcuname, __entry->qlen_lazy, __entry->qlen, | 417 | __entry->rcuname, __entry->qlen_lazy, __entry->qlen, |
416 | __entry->blimit) | 418 | __entry->blimit) |
417 | ); | 419 | ); |
@@ -523,22 +525,30 @@ TRACE_EVENT(rcu_batch_end, | |||
523 | */ | 525 | */ |
524 | TRACE_EVENT(rcu_torture_read, | 526 | TRACE_EVENT(rcu_torture_read, |
525 | 527 | ||
526 | TP_PROTO(char *rcutorturename, struct rcu_head *rhp), | 528 | TP_PROTO(char *rcutorturename, struct rcu_head *rhp, |
529 | unsigned long secs, unsigned long c_old, unsigned long c), | ||
527 | 530 | ||
528 | TP_ARGS(rcutorturename, rhp), | 531 | TP_ARGS(rcutorturename, rhp, secs, c_old, c), |
529 | 532 | ||
530 | TP_STRUCT__entry( | 533 | TP_STRUCT__entry( |
531 | __field(char *, rcutorturename) | 534 | __field(char *, rcutorturename) |
532 | __field(struct rcu_head *, rhp) | 535 | __field(struct rcu_head *, rhp) |
536 | __field(unsigned long, secs) | ||
537 | __field(unsigned long, c_old) | ||
538 | __field(unsigned long, c) | ||
533 | ), | 539 | ), |
534 | 540 | ||
535 | TP_fast_assign( | 541 | TP_fast_assign( |
536 | __entry->rcutorturename = rcutorturename; | 542 | __entry->rcutorturename = rcutorturename; |
537 | __entry->rhp = rhp; | 543 | __entry->rhp = rhp; |
544 | __entry->secs = secs; | ||
545 | __entry->c_old = c_old; | ||
546 | __entry->c = c; | ||
538 | ), | 547 | ), |
539 | 548 | ||
540 | TP_printk("%s torture read %p", | 549 | TP_printk("%s torture read %p %luus c: %lu %lu", |
541 | __entry->rcutorturename, __entry->rhp) | 550 | __entry->rcutorturename, __entry->rhp, |
551 | __entry->secs, __entry->c_old, __entry->c) | ||
542 | ); | 552 | ); |
543 | 553 | ||
544 | /* | 554 | /* |
@@ -608,7 +618,8 @@ TRACE_EVENT(rcu_barrier, | |||
608 | #define trace_rcu_invoke_kfree_callback(rcuname, rhp, offset) do { } while (0) | 618 | #define trace_rcu_invoke_kfree_callback(rcuname, rhp, offset) do { } while (0) |
609 | #define trace_rcu_batch_end(rcuname, callbacks_invoked, cb, nr, iit, risk) \ | 619 | #define trace_rcu_batch_end(rcuname, callbacks_invoked, cb, nr, iit, risk) \ |
610 | do { } while (0) | 620 | do { } while (0) |
611 | #define trace_rcu_torture_read(rcutorturename, rhp) do { } while (0) | 621 | #define trace_rcu_torture_read(rcutorturename, rhp, secs, c_old, c) \ |
622 | do { } while (0) | ||
612 | #define trace_rcu_barrier(name, s, cpu, cnt, done) do { } while (0) | 623 | #define trace_rcu_barrier(name, s, cpu, cnt, done) do { } while (0) |
613 | 624 | ||
614 | #endif /* #else #ifdef CONFIG_RCU_TRACE */ | 625 | #endif /* #else #ifdef CONFIG_RCU_TRACE */ |
diff --git a/include/uapi/linux/auto_fs.h b/include/uapi/linux/auto_fs.h index 77cdba9df274..bb991dfe134f 100644 --- a/include/uapi/linux/auto_fs.h +++ b/include/uapi/linux/auto_fs.h | |||
@@ -28,25 +28,16 @@ | |||
28 | #define AUTOFS_MIN_PROTO_VERSION AUTOFS_PROTO_VERSION | 28 | #define AUTOFS_MIN_PROTO_VERSION AUTOFS_PROTO_VERSION |
29 | 29 | ||
30 | /* | 30 | /* |
31 | * Architectures where both 32- and 64-bit binaries can be executed | 31 | * The wait_queue_token (autofs_wqt_t) is part of a structure which is passed |
32 | * on 64-bit kernels need this. This keeps the structure format | 32 | * back to the kernel via ioctl from userspace. On architectures where 32- and |
33 | * uniform, and makes sure the wait_queue_token isn't too big to be | 33 | * 64-bit userspace binaries can be executed it's important that the size of |
34 | * passed back down to the kernel. | 34 | * autofs_wqt_t stays constant between 32- and 64-bit Linux kernels so that we |
35 | * | 35 | * do not break the binary ABI interface by changing the structure size. |
36 | * This assumes that on these architectures: | ||
37 | * mode 32 bit 64 bit | ||
38 | * ------------------------- | ||
39 | * int 32 bit 32 bit | ||
40 | * long 32 bit 64 bit | ||
41 | * | ||
42 | * If so, 32-bit user-space code should be backwards compatible. | ||
43 | */ | 36 | */ |
44 | 37 | #if defined(__ia64__) || defined(__alpha__) /* pure 64bit architectures */ | |
45 | #if defined(__sparc__) || defined(__mips__) || defined(__x86_64__) \ | ||
46 | || defined(__powerpc__) || defined(__s390__) | ||
47 | typedef unsigned int autofs_wqt_t; | ||
48 | #else | ||
49 | typedef unsigned long autofs_wqt_t; | 38 | typedef unsigned long autofs_wqt_t; |
39 | #else | ||
40 | typedef unsigned int autofs_wqt_t; | ||
50 | #endif | 41 | #endif |
51 | 42 | ||
52 | /* Packet types */ | 43 | /* Packet types */ |
diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h index 4f63c05d27c9..9fa9c622a7f4 100644 --- a/include/uapi/linux/perf_event.h +++ b/include/uapi/linux/perf_event.h | |||
@@ -579,7 +579,8 @@ enum perf_event_type { | |||
579 | * { u32 size; | 579 | * { u32 size; |
580 | * char data[size];}&& PERF_SAMPLE_RAW | 580 | * char data[size];}&& PERF_SAMPLE_RAW |
581 | * | 581 | * |
582 | * { u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK | 582 | * { u64 nr; |
583 | * { u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK | ||
583 | * | 584 | * |
584 | * { u64 abi; # enum perf_sample_regs_abi | 585 | * { u64 abi; # enum perf_sample_regs_abi |
585 | * u64 regs[weight(mask)]; } && PERF_SAMPLE_REGS_USER | 586 | * u64 regs[weight(mask)]; } && PERF_SAMPLE_REGS_USER |
diff --git a/init/Kconfig b/init/Kconfig index be8b7f55312d..7000d9657402 100644 --- a/init/Kconfig +++ b/init/Kconfig | |||
@@ -20,12 +20,8 @@ config CONSTRUCTORS | |||
20 | bool | 20 | bool |
21 | depends on !UML | 21 | depends on !UML |
22 | 22 | ||
23 | config HAVE_IRQ_WORK | ||
24 | bool | ||
25 | |||
26 | config IRQ_WORK | 23 | config IRQ_WORK |
27 | bool | 24 | bool |
28 | depends on HAVE_IRQ_WORK | ||
29 | 25 | ||
30 | config BUILDTIME_EXTABLE_SORT | 26 | config BUILDTIME_EXTABLE_SORT |
31 | bool | 27 | bool |
@@ -326,10 +322,13 @@ source "kernel/time/Kconfig" | |||
326 | 322 | ||
327 | menu "CPU/Task time and stats accounting" | 323 | menu "CPU/Task time and stats accounting" |
328 | 324 | ||
325 | config VIRT_CPU_ACCOUNTING | ||
326 | bool | ||
327 | |||
329 | choice | 328 | choice |
330 | prompt "Cputime accounting" | 329 | prompt "Cputime accounting" |
331 | default TICK_CPU_ACCOUNTING if !PPC64 | 330 | default TICK_CPU_ACCOUNTING if !PPC64 |
332 | default VIRT_CPU_ACCOUNTING if PPC64 | 331 | default VIRT_CPU_ACCOUNTING_NATIVE if PPC64 |
333 | 332 | ||
334 | # Kind of a stub config for the pure tick based cputime accounting | 333 | # Kind of a stub config for the pure tick based cputime accounting |
335 | config TICK_CPU_ACCOUNTING | 334 | config TICK_CPU_ACCOUNTING |
@@ -342,9 +341,10 @@ config TICK_CPU_ACCOUNTING | |||
342 | 341 | ||
343 | If unsure, say Y. | 342 | If unsure, say Y. |
344 | 343 | ||
345 | config VIRT_CPU_ACCOUNTING | 344 | config VIRT_CPU_ACCOUNTING_NATIVE |
346 | bool "Deterministic task and CPU time accounting" | 345 | bool "Deterministic task and CPU time accounting" |
347 | depends on HAVE_VIRT_CPU_ACCOUNTING | 346 | depends on HAVE_VIRT_CPU_ACCOUNTING |
347 | select VIRT_CPU_ACCOUNTING | ||
348 | help | 348 | help |
349 | Select this option to enable more accurate task and CPU time | 349 | Select this option to enable more accurate task and CPU time |
350 | accounting. This is done by reading a CPU counter on each | 350 | accounting. This is done by reading a CPU counter on each |
@@ -354,6 +354,23 @@ config VIRT_CPU_ACCOUNTING | |||
354 | this also enables accounting of stolen time on logically-partitioned | 354 | this also enables accounting of stolen time on logically-partitioned |
355 | systems. | 355 | systems. |
356 | 356 | ||
357 | config VIRT_CPU_ACCOUNTING_GEN | ||
358 | bool "Full dynticks CPU time accounting" | ||
359 | depends on HAVE_CONTEXT_TRACKING && 64BIT | ||
360 | select VIRT_CPU_ACCOUNTING | ||
361 | select CONTEXT_TRACKING | ||
362 | help | ||
363 | Select this option to enable task and CPU time accounting on full | ||
364 | dynticks systems. This accounting is implemented by watching every | ||
365 | kernel-user boundaries using the context tracking subsystem. | ||
366 | The accounting is thus performed at the expense of some significant | ||
367 | overhead. | ||
368 | |||
369 | For now this is only useful if you are working on the full | ||
370 | dynticks subsystem development. | ||
371 | |||
372 | If unsure, say N. | ||
373 | |||
357 | config IRQ_TIME_ACCOUNTING | 374 | config IRQ_TIME_ACCOUNTING |
358 | bool "Fine granularity task level IRQ time accounting" | 375 | bool "Fine granularity task level IRQ time accounting" |
359 | depends on HAVE_IRQ_TIME_ACCOUNTING | 376 | depends on HAVE_IRQ_TIME_ACCOUNTING |
@@ -453,7 +470,7 @@ config TREE_RCU | |||
453 | 470 | ||
454 | config TREE_PREEMPT_RCU | 471 | config TREE_PREEMPT_RCU |
455 | bool "Preemptible tree-based hierarchical RCU" | 472 | bool "Preemptible tree-based hierarchical RCU" |
456 | depends on PREEMPT && SMP | 473 | depends on PREEMPT |
457 | help | 474 | help |
458 | This option selects the RCU implementation that is | 475 | This option selects the RCU implementation that is |
459 | designed for very large SMP systems with hundreds or | 476 | designed for very large SMP systems with hundreds or |
@@ -461,6 +478,8 @@ config TREE_PREEMPT_RCU | |||
461 | is also required. It also scales down nicely to | 478 | is also required. It also scales down nicely to |
462 | smaller systems. | 479 | smaller systems. |
463 | 480 | ||
481 | Select this option if you are unsure. | ||
482 | |||
464 | config TINY_RCU | 483 | config TINY_RCU |
465 | bool "UP-only small-memory-footprint RCU" | 484 | bool "UP-only small-memory-footprint RCU" |
466 | depends on !PREEMPT && !SMP | 485 | depends on !PREEMPT && !SMP |
@@ -486,6 +505,14 @@ config PREEMPT_RCU | |||
486 | This option enables preemptible-RCU code that is common between | 505 | This option enables preemptible-RCU code that is common between |
487 | the TREE_PREEMPT_RCU and TINY_PREEMPT_RCU implementations. | 506 | the TREE_PREEMPT_RCU and TINY_PREEMPT_RCU implementations. |
488 | 507 | ||
508 | config RCU_STALL_COMMON | ||
509 | def_bool ( TREE_RCU || TREE_PREEMPT_RCU || RCU_TRACE ) | ||
510 | help | ||
511 | This option enables RCU CPU stall code that is common between | ||
512 | the TINY and TREE variants of RCU. The purpose is to allow | ||
513 | the tiny variants to disable RCU CPU stall warnings, while | ||
514 | making these warnings mandatory for the tree variants. | ||
515 | |||
489 | config CONTEXT_TRACKING | 516 | config CONTEXT_TRACKING |
490 | bool | 517 | bool |
491 | 518 | ||
@@ -1263,6 +1290,7 @@ config HOTPLUG | |||
1263 | config PRINTK | 1290 | config PRINTK |
1264 | default y | 1291 | default y |
1265 | bool "Enable support for printk" if EXPERT | 1292 | bool "Enable support for printk" if EXPERT |
1293 | select IRQ_WORK | ||
1266 | help | 1294 | help |
1267 | This option enables normal printk support. Removing it | 1295 | This option enables normal printk support. Removing it |
1268 | eliminates most of the message strings from the kernel image | 1296 | eliminates most of the message strings from the kernel image |
diff --git a/init/init_task.c b/init/init_task.c index 8b2f3996b035..ba0a7f362d9e 100644 --- a/init/init_task.c +++ b/init/init_task.c | |||
@@ -2,6 +2,8 @@ | |||
2 | #include <linux/export.h> | 2 | #include <linux/export.h> |
3 | #include <linux/mqueue.h> | 3 | #include <linux/mqueue.h> |
4 | #include <linux/sched.h> | 4 | #include <linux/sched.h> |
5 | #include <linux/sched/sysctl.h> | ||
6 | #include <linux/sched/rt.h> | ||
5 | #include <linux/init.h> | 7 | #include <linux/init.h> |
6 | #include <linux/fs.h> | 8 | #include <linux/fs.h> |
7 | #include <linux/mm.h> | 9 | #include <linux/mm.h> |
diff --git a/kernel/acct.c b/kernel/acct.c index 051e071a06e7..e8b1627ab9c7 100644 --- a/kernel/acct.c +++ b/kernel/acct.c | |||
@@ -566,6 +566,7 @@ out: | |||
566 | void acct_collect(long exitcode, int group_dead) | 566 | void acct_collect(long exitcode, int group_dead) |
567 | { | 567 | { |
568 | struct pacct_struct *pacct = ¤t->signal->pacct; | 568 | struct pacct_struct *pacct = ¤t->signal->pacct; |
569 | cputime_t utime, stime; | ||
569 | unsigned long vsize = 0; | 570 | unsigned long vsize = 0; |
570 | 571 | ||
571 | if (group_dead && current->mm) { | 572 | if (group_dead && current->mm) { |
@@ -593,8 +594,9 @@ void acct_collect(long exitcode, int group_dead) | |||
593 | pacct->ac_flag |= ACORE; | 594 | pacct->ac_flag |= ACORE; |
594 | if (current->flags & PF_SIGNALED) | 595 | if (current->flags & PF_SIGNALED) |
595 | pacct->ac_flag |= AXSIG; | 596 | pacct->ac_flag |= AXSIG; |
596 | pacct->ac_utime += current->utime; | 597 | task_cputime(current, &utime, &stime); |
597 | pacct->ac_stime += current->stime; | 598 | pacct->ac_utime += utime; |
599 | pacct->ac_stime += stime; | ||
598 | pacct->ac_minflt += current->min_flt; | 600 | pacct->ac_minflt += current->min_flt; |
599 | pacct->ac_majflt += current->maj_flt; | 601 | pacct->ac_majflt += current->maj_flt; |
600 | spin_unlock_irq(¤t->sighand->siglock); | 602 | spin_unlock_irq(¤t->sighand->siglock); |
diff --git a/kernel/context_tracking.c b/kernel/context_tracking.c index e0e07fd55508..65349f07b878 100644 --- a/kernel/context_tracking.c +++ b/kernel/context_tracking.c | |||
@@ -1,29 +1,41 @@ | |||
1 | /* | ||
2 | * Context tracking: Probe on high level context boundaries such as kernel | ||
3 | * and userspace. This includes syscalls and exceptions entry/exit. | ||
4 | * | ||
5 | * This is used by RCU to remove its dependency on the timer tick while a CPU | ||
6 | * runs in userspace. | ||
7 | * | ||
8 | * Started by Frederic Weisbecker: | ||
9 | * | ||
10 | * Copyright (C) 2012 Red Hat, Inc., Frederic Weisbecker <fweisbec@redhat.com> | ||
11 | * | ||
12 | * Many thanks to Gilad Ben-Yossef, Paul McKenney, Ingo Molnar, Andrew Morton, | ||
13 | * Steven Rostedt, Peter Zijlstra for suggestions and improvements. | ||
14 | * | ||
15 | */ | ||
16 | |||
1 | #include <linux/context_tracking.h> | 17 | #include <linux/context_tracking.h> |
18 | #include <linux/kvm_host.h> | ||
2 | #include <linux/rcupdate.h> | 19 | #include <linux/rcupdate.h> |
3 | #include <linux/sched.h> | 20 | #include <linux/sched.h> |
4 | #include <linux/percpu.h> | ||
5 | #include <linux/hardirq.h> | 21 | #include <linux/hardirq.h> |
22 | #include <linux/export.h> | ||
6 | 23 | ||
7 | struct context_tracking { | 24 | DEFINE_PER_CPU(struct context_tracking, context_tracking) = { |
8 | /* | ||
9 | * When active is false, hooks are not set to | ||
10 | * minimize overhead: TIF flags are cleared | ||
11 | * and calls to user_enter/exit are ignored. This | ||
12 | * may be further optimized using static keys. | ||
13 | */ | ||
14 | bool active; | ||
15 | enum { | ||
16 | IN_KERNEL = 0, | ||
17 | IN_USER, | ||
18 | } state; | ||
19 | }; | ||
20 | |||
21 | static DEFINE_PER_CPU(struct context_tracking, context_tracking) = { | ||
22 | #ifdef CONFIG_CONTEXT_TRACKING_FORCE | 25 | #ifdef CONFIG_CONTEXT_TRACKING_FORCE |
23 | .active = true, | 26 | .active = true, |
24 | #endif | 27 | #endif |
25 | }; | 28 | }; |
26 | 29 | ||
30 | /** | ||
31 | * user_enter - Inform the context tracking that the CPU is going to | ||
32 | * enter userspace mode. | ||
33 | * | ||
34 | * This function must be called right before we switch from the kernel | ||
35 | * to userspace, when it's guaranteed the remaining kernel instructions | ||
36 | * to execute won't use any RCU read side critical section because this | ||
37 | * function sets RCU in extended quiescent state. | ||
38 | */ | ||
27 | void user_enter(void) | 39 | void user_enter(void) |
28 | { | 40 | { |
29 | unsigned long flags; | 41 | unsigned long flags; |
@@ -39,40 +51,90 @@ void user_enter(void) | |||
39 | if (in_interrupt()) | 51 | if (in_interrupt()) |
40 | return; | 52 | return; |
41 | 53 | ||
54 | /* Kernel threads aren't supposed to go to userspace */ | ||
42 | WARN_ON_ONCE(!current->mm); | 55 | WARN_ON_ONCE(!current->mm); |
43 | 56 | ||
44 | local_irq_save(flags); | 57 | local_irq_save(flags); |
45 | if (__this_cpu_read(context_tracking.active) && | 58 | if (__this_cpu_read(context_tracking.active) && |
46 | __this_cpu_read(context_tracking.state) != IN_USER) { | 59 | __this_cpu_read(context_tracking.state) != IN_USER) { |
47 | __this_cpu_write(context_tracking.state, IN_USER); | 60 | /* |
61 | * At this stage, only low level arch entry code remains and | ||
62 | * then we'll run in userspace. We can assume there won't be | ||
63 | * any RCU read-side critical section until the next call to | ||
64 | * user_exit() or rcu_irq_enter(). Let's remove RCU's dependency | ||
65 | * on the tick. | ||
66 | */ | ||
67 | vtime_user_enter(current); | ||
48 | rcu_user_enter(); | 68 | rcu_user_enter(); |
69 | __this_cpu_write(context_tracking.state, IN_USER); | ||
49 | } | 70 | } |
50 | local_irq_restore(flags); | 71 | local_irq_restore(flags); |
51 | } | 72 | } |
52 | 73 | ||
74 | |||
75 | /** | ||
76 | * user_exit - Inform the context tracking that the CPU is | ||
77 | * exiting userspace mode and entering the kernel. | ||
78 | * | ||
79 | * This function must be called after we entered the kernel from userspace | ||
80 | * before any use of RCU read side critical section. This potentially include | ||
81 | * any high level kernel code like syscalls, exceptions, signal handling, etc... | ||
82 | * | ||
83 | * This call supports re-entrancy. This way it can be called from any exception | ||
84 | * handler without needing to know if we came from userspace or not. | ||
85 | */ | ||
53 | void user_exit(void) | 86 | void user_exit(void) |
54 | { | 87 | { |
55 | unsigned long flags; | 88 | unsigned long flags; |
56 | 89 | ||
57 | /* | ||
58 | * Some contexts may involve an exception occuring in an irq, | ||
59 | * leading to that nesting: | ||
60 | * rcu_irq_enter() rcu_user_exit() rcu_user_exit() rcu_irq_exit() | ||
61 | * This would mess up the dyntick_nesting count though. And rcu_irq_*() | ||
62 | * helpers are enough to protect RCU uses inside the exception. So | ||
63 | * just return immediately if we detect we are in an IRQ. | ||
64 | */ | ||
65 | if (in_interrupt()) | 90 | if (in_interrupt()) |
66 | return; | 91 | return; |
67 | 92 | ||
68 | local_irq_save(flags); | 93 | local_irq_save(flags); |
69 | if (__this_cpu_read(context_tracking.state) == IN_USER) { | 94 | if (__this_cpu_read(context_tracking.state) == IN_USER) { |
70 | __this_cpu_write(context_tracking.state, IN_KERNEL); | 95 | /* |
96 | * We are going to run code that may use RCU. Inform | ||
97 | * RCU core about that (ie: we may need the tick again). | ||
98 | */ | ||
71 | rcu_user_exit(); | 99 | rcu_user_exit(); |
100 | vtime_user_exit(current); | ||
101 | __this_cpu_write(context_tracking.state, IN_KERNEL); | ||
72 | } | 102 | } |
73 | local_irq_restore(flags); | 103 | local_irq_restore(flags); |
74 | } | 104 | } |
75 | 105 | ||
106 | void guest_enter(void) | ||
107 | { | ||
108 | if (vtime_accounting_enabled()) | ||
109 | vtime_guest_enter(current); | ||
110 | else | ||
111 | __guest_enter(); | ||
112 | } | ||
113 | EXPORT_SYMBOL_GPL(guest_enter); | ||
114 | |||
115 | void guest_exit(void) | ||
116 | { | ||
117 | if (vtime_accounting_enabled()) | ||
118 | vtime_guest_exit(current); | ||
119 | else | ||
120 | __guest_exit(); | ||
121 | } | ||
122 | EXPORT_SYMBOL_GPL(guest_exit); | ||
123 | |||
124 | |||
125 | /** | ||
126 | * context_tracking_task_switch - context switch the syscall callbacks | ||
127 | * @prev: the task that is being switched out | ||
128 | * @next: the task that is being switched in | ||
129 | * | ||
130 | * The context tracking uses the syscall slow path to implement its user-kernel | ||
131 | * boundaries probes on syscalls. This way it doesn't impact the syscall fast | ||
132 | * path on CPUs that don't do context tracking. | ||
133 | * | ||
134 | * But we need to clear the flag on the previous task because it may later | ||
135 | * migrate to some CPU that doesn't do the context tracking. As such the TIF | ||
136 | * flag may not be desired there. | ||
137 | */ | ||
76 | void context_tracking_task_switch(struct task_struct *prev, | 138 | void context_tracking_task_switch(struct task_struct *prev, |
77 | struct task_struct *next) | 139 | struct task_struct *next) |
78 | { | 140 | { |
diff --git a/kernel/cpu.c b/kernel/cpu.c index 3046a503242c..b5e4ab2d427e 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c | |||
@@ -224,11 +224,13 @@ void clear_tasks_mm_cpumask(int cpu) | |||
224 | static inline void check_for_tasks(int cpu) | 224 | static inline void check_for_tasks(int cpu) |
225 | { | 225 | { |
226 | struct task_struct *p; | 226 | struct task_struct *p; |
227 | cputime_t utime, stime; | ||
227 | 228 | ||
228 | write_lock_irq(&tasklist_lock); | 229 | write_lock_irq(&tasklist_lock); |
229 | for_each_process(p) { | 230 | for_each_process(p) { |
231 | task_cputime(p, &utime, &stime); | ||
230 | if (task_cpu(p) == cpu && p->state == TASK_RUNNING && | 232 | if (task_cpu(p) == cpu && p->state == TASK_RUNNING && |
231 | (p->utime || p->stime)) | 233 | (utime || stime)) |
232 | printk(KERN_WARNING "Task %s (pid = %d) is on cpu %d " | 234 | printk(KERN_WARNING "Task %s (pid = %d) is on cpu %d " |
233 | "(state = %ld, flags = %x)\n", | 235 | "(state = %ld, flags = %x)\n", |
234 | p->comm, task_pid_nr(p), cpu, | 236 | p->comm, task_pid_nr(p), cpu, |
@@ -254,6 +256,8 @@ static int __ref take_cpu_down(void *_param) | |||
254 | return err; | 256 | return err; |
255 | 257 | ||
256 | cpu_notify(CPU_DYING | param->mod, param->hcpu); | 258 | cpu_notify(CPU_DYING | param->mod, param->hcpu); |
259 | /* Park the stopper thread */ | ||
260 | kthread_park(current); | ||
257 | return 0; | 261 | return 0; |
258 | } | 262 | } |
259 | 263 | ||
diff --git a/kernel/delayacct.c b/kernel/delayacct.c index 418b3f7053aa..d473988c1d0b 100644 --- a/kernel/delayacct.c +++ b/kernel/delayacct.c | |||
@@ -106,6 +106,7 @@ int __delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk) | |||
106 | unsigned long long t2, t3; | 106 | unsigned long long t2, t3; |
107 | unsigned long flags; | 107 | unsigned long flags; |
108 | struct timespec ts; | 108 | struct timespec ts; |
109 | cputime_t utime, stime, stimescaled, utimescaled; | ||
109 | 110 | ||
110 | /* Though tsk->delays accessed later, early exit avoids | 111 | /* Though tsk->delays accessed later, early exit avoids |
111 | * unnecessary returning of other data | 112 | * unnecessary returning of other data |
@@ -114,12 +115,14 @@ int __delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk) | |||
114 | goto done; | 115 | goto done; |
115 | 116 | ||
116 | tmp = (s64)d->cpu_run_real_total; | 117 | tmp = (s64)d->cpu_run_real_total; |
117 | cputime_to_timespec(tsk->utime + tsk->stime, &ts); | 118 | task_cputime(tsk, &utime, &stime); |
119 | cputime_to_timespec(utime + stime, &ts); | ||
118 | tmp += timespec_to_ns(&ts); | 120 | tmp += timespec_to_ns(&ts); |
119 | d->cpu_run_real_total = (tmp < (s64)d->cpu_run_real_total) ? 0 : tmp; | 121 | d->cpu_run_real_total = (tmp < (s64)d->cpu_run_real_total) ? 0 : tmp; |
120 | 122 | ||
121 | tmp = (s64)d->cpu_scaled_run_real_total; | 123 | tmp = (s64)d->cpu_scaled_run_real_total; |
122 | cputime_to_timespec(tsk->utimescaled + tsk->stimescaled, &ts); | 124 | task_cputime_scaled(tsk, &utimescaled, &stimescaled); |
125 | cputime_to_timespec(utimescaled + stimescaled, &ts); | ||
123 | tmp += timespec_to_ns(&ts); | 126 | tmp += timespec_to_ns(&ts); |
124 | d->cpu_scaled_run_real_total = | 127 | d->cpu_scaled_run_real_total = |
125 | (tmp < (s64)d->cpu_scaled_run_real_total) ? 0 : tmp; | 128 | (tmp < (s64)d->cpu_scaled_run_real_total) ? 0 : tmp; |
diff --git a/kernel/events/core.c b/kernel/events/core.c index 7b6646a8c067..5c75791d7269 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c | |||
@@ -6171,11 +6171,14 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, | |||
6171 | 6171 | ||
6172 | if (task) { | 6172 | if (task) { |
6173 | event->attach_state = PERF_ATTACH_TASK; | 6173 | event->attach_state = PERF_ATTACH_TASK; |
6174 | |||
6175 | if (attr->type == PERF_TYPE_TRACEPOINT) | ||
6176 | event->hw.tp_target = task; | ||
6174 | #ifdef CONFIG_HAVE_HW_BREAKPOINT | 6177 | #ifdef CONFIG_HAVE_HW_BREAKPOINT |
6175 | /* | 6178 | /* |
6176 | * hw_breakpoint is a bit difficult here.. | 6179 | * hw_breakpoint is a bit difficult here.. |
6177 | */ | 6180 | */ |
6178 | if (attr->type == PERF_TYPE_BREAKPOINT) | 6181 | else if (attr->type == PERF_TYPE_BREAKPOINT) |
6179 | event->hw.bp_target = task; | 6182 | event->hw.bp_target = task; |
6180 | #endif | 6183 | #endif |
6181 | } | 6184 | } |
diff --git a/kernel/events/hw_breakpoint.c b/kernel/events/hw_breakpoint.c index fe8a916507ed..a64f8aeb5c1f 100644 --- a/kernel/events/hw_breakpoint.c +++ b/kernel/events/hw_breakpoint.c | |||
@@ -676,7 +676,7 @@ int __init init_hw_breakpoint(void) | |||
676 | err_alloc: | 676 | err_alloc: |
677 | for_each_possible_cpu(err_cpu) { | 677 | for_each_possible_cpu(err_cpu) { |
678 | for (i = 0; i < TYPE_MAX; i++) | 678 | for (i = 0; i < TYPE_MAX; i++) |
679 | kfree(per_cpu(nr_task_bp_pinned[i], cpu)); | 679 | kfree(per_cpu(nr_task_bp_pinned[i], err_cpu)); |
680 | if (err_cpu == cpu) | 680 | if (err_cpu == cpu) |
681 | break; | 681 | break; |
682 | } | 682 | } |
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index dea7acfbb071..a567c8c7ef31 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/pagemap.h> /* read_mapping_page */ | 27 | #include <linux/pagemap.h> /* read_mapping_page */ |
28 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
29 | #include <linux/sched.h> | 29 | #include <linux/sched.h> |
30 | #include <linux/export.h> | ||
30 | #include <linux/rmap.h> /* anon_vma_prepare */ | 31 | #include <linux/rmap.h> /* anon_vma_prepare */ |
31 | #include <linux/mmu_notifier.h> /* set_pte_at_notify */ | 32 | #include <linux/mmu_notifier.h> /* set_pte_at_notify */ |
32 | #include <linux/swap.h> /* try_to_free_swap */ | 33 | #include <linux/swap.h> /* try_to_free_swap */ |
@@ -41,58 +42,31 @@ | |||
41 | #define MAX_UPROBE_XOL_SLOTS UINSNS_PER_PAGE | 42 | #define MAX_UPROBE_XOL_SLOTS UINSNS_PER_PAGE |
42 | 43 | ||
43 | static struct rb_root uprobes_tree = RB_ROOT; | 44 | static struct rb_root uprobes_tree = RB_ROOT; |
44 | |||
45 | static DEFINE_SPINLOCK(uprobes_treelock); /* serialize rbtree access */ | ||
46 | |||
47 | #define UPROBES_HASH_SZ 13 | ||
48 | |||
49 | /* | 45 | /* |
50 | * We need separate register/unregister and mmap/munmap lock hashes because | 46 | * allows us to skip the uprobe_mmap if there are no uprobe events active |
51 | * of mmap_sem nesting. | 47 | * at this time. Probably a fine grained per inode count is better? |
52 | * | ||
53 | * uprobe_register() needs to install probes on (potentially) all processes | ||
54 | * and thus needs to acquire multiple mmap_sems (consequtively, not | ||
55 | * concurrently), whereas uprobe_mmap() is called while holding mmap_sem | ||
56 | * for the particular process doing the mmap. | ||
57 | * | ||
58 | * uprobe_register()->register_for_each_vma() needs to drop/acquire mmap_sem | ||
59 | * because of lock order against i_mmap_mutex. This means there's a hole in | ||
60 | * the register vma iteration where a mmap() can happen. | ||
61 | * | ||
62 | * Thus uprobe_register() can race with uprobe_mmap() and we can try and | ||
63 | * install a probe where one is already installed. | ||
64 | */ | 48 | */ |
49 | #define no_uprobe_events() RB_EMPTY_ROOT(&uprobes_tree) | ||
65 | 50 | ||
66 | /* serialize (un)register */ | 51 | static DEFINE_SPINLOCK(uprobes_treelock); /* serialize rbtree access */ |
67 | static struct mutex uprobes_mutex[UPROBES_HASH_SZ]; | ||
68 | |||
69 | #define uprobes_hash(v) (&uprobes_mutex[((unsigned long)(v)) % UPROBES_HASH_SZ]) | ||
70 | 52 | ||
53 | #define UPROBES_HASH_SZ 13 | ||
71 | /* serialize uprobe->pending_list */ | 54 | /* serialize uprobe->pending_list */ |
72 | static struct mutex uprobes_mmap_mutex[UPROBES_HASH_SZ]; | 55 | static struct mutex uprobes_mmap_mutex[UPROBES_HASH_SZ]; |
73 | #define uprobes_mmap_hash(v) (&uprobes_mmap_mutex[((unsigned long)(v)) % UPROBES_HASH_SZ]) | 56 | #define uprobes_mmap_hash(v) (&uprobes_mmap_mutex[((unsigned long)(v)) % UPROBES_HASH_SZ]) |
74 | 57 | ||
75 | static struct percpu_rw_semaphore dup_mmap_sem; | 58 | static struct percpu_rw_semaphore dup_mmap_sem; |
76 | 59 | ||
77 | /* | ||
78 | * uprobe_events allows us to skip the uprobe_mmap if there are no uprobe | ||
79 | * events active at this time. Probably a fine grained per inode count is | ||
80 | * better? | ||
81 | */ | ||
82 | static atomic_t uprobe_events = ATOMIC_INIT(0); | ||
83 | |||
84 | /* Have a copy of original instruction */ | 60 | /* Have a copy of original instruction */ |
85 | #define UPROBE_COPY_INSN 0 | 61 | #define UPROBE_COPY_INSN 0 |
86 | /* Dont run handlers when first register/ last unregister in progress*/ | ||
87 | #define UPROBE_RUN_HANDLER 1 | ||
88 | /* Can skip singlestep */ | 62 | /* Can skip singlestep */ |
89 | #define UPROBE_SKIP_SSTEP 2 | 63 | #define UPROBE_SKIP_SSTEP 1 |
90 | 64 | ||
91 | struct uprobe { | 65 | struct uprobe { |
92 | struct rb_node rb_node; /* node in the rb tree */ | 66 | struct rb_node rb_node; /* node in the rb tree */ |
93 | atomic_t ref; | 67 | atomic_t ref; |
68 | struct rw_semaphore register_rwsem; | ||
94 | struct rw_semaphore consumer_rwsem; | 69 | struct rw_semaphore consumer_rwsem; |
95 | struct mutex copy_mutex; /* TODO: kill me and UPROBE_COPY_INSN */ | ||
96 | struct list_head pending_list; | 70 | struct list_head pending_list; |
97 | struct uprobe_consumer *consumers; | 71 | struct uprobe_consumer *consumers; |
98 | struct inode *inode; /* Also hold a ref to inode */ | 72 | struct inode *inode; /* Also hold a ref to inode */ |
@@ -430,9 +404,6 @@ static struct uprobe *insert_uprobe(struct uprobe *uprobe) | |||
430 | u = __insert_uprobe(uprobe); | 404 | u = __insert_uprobe(uprobe); |
431 | spin_unlock(&uprobes_treelock); | 405 | spin_unlock(&uprobes_treelock); |
432 | 406 | ||
433 | /* For now assume that the instruction need not be single-stepped */ | ||
434 | __set_bit(UPROBE_SKIP_SSTEP, &uprobe->flags); | ||
435 | |||
436 | return u; | 407 | return u; |
437 | } | 408 | } |
438 | 409 | ||
@@ -452,8 +423,10 @@ static struct uprobe *alloc_uprobe(struct inode *inode, loff_t offset) | |||
452 | 423 | ||
453 | uprobe->inode = igrab(inode); | 424 | uprobe->inode = igrab(inode); |
454 | uprobe->offset = offset; | 425 | uprobe->offset = offset; |
426 | init_rwsem(&uprobe->register_rwsem); | ||
455 | init_rwsem(&uprobe->consumer_rwsem); | 427 | init_rwsem(&uprobe->consumer_rwsem); |
456 | mutex_init(&uprobe->copy_mutex); | 428 | /* For now assume that the instruction need not be single-stepped */ |
429 | __set_bit(UPROBE_SKIP_SSTEP, &uprobe->flags); | ||
457 | 430 | ||
458 | /* add to uprobes_tree, sorted on inode:offset */ | 431 | /* add to uprobes_tree, sorted on inode:offset */ |
459 | cur_uprobe = insert_uprobe(uprobe); | 432 | cur_uprobe = insert_uprobe(uprobe); |
@@ -463,38 +436,17 @@ static struct uprobe *alloc_uprobe(struct inode *inode, loff_t offset) | |||
463 | kfree(uprobe); | 436 | kfree(uprobe); |
464 | uprobe = cur_uprobe; | 437 | uprobe = cur_uprobe; |
465 | iput(inode); | 438 | iput(inode); |
466 | } else { | ||
467 | atomic_inc(&uprobe_events); | ||
468 | } | 439 | } |
469 | 440 | ||
470 | return uprobe; | 441 | return uprobe; |
471 | } | 442 | } |
472 | 443 | ||
473 | static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs) | 444 | static void consumer_add(struct uprobe *uprobe, struct uprobe_consumer *uc) |
474 | { | ||
475 | struct uprobe_consumer *uc; | ||
476 | |||
477 | if (!test_bit(UPROBE_RUN_HANDLER, &uprobe->flags)) | ||
478 | return; | ||
479 | |||
480 | down_read(&uprobe->consumer_rwsem); | ||
481 | for (uc = uprobe->consumers; uc; uc = uc->next) { | ||
482 | if (!uc->filter || uc->filter(uc, current)) | ||
483 | uc->handler(uc, regs); | ||
484 | } | ||
485 | up_read(&uprobe->consumer_rwsem); | ||
486 | } | ||
487 | |||
488 | /* Returns the previous consumer */ | ||
489 | static struct uprobe_consumer * | ||
490 | consumer_add(struct uprobe *uprobe, struct uprobe_consumer *uc) | ||
491 | { | 445 | { |
492 | down_write(&uprobe->consumer_rwsem); | 446 | down_write(&uprobe->consumer_rwsem); |
493 | uc->next = uprobe->consumers; | 447 | uc->next = uprobe->consumers; |
494 | uprobe->consumers = uc; | 448 | uprobe->consumers = uc; |
495 | up_write(&uprobe->consumer_rwsem); | 449 | up_write(&uprobe->consumer_rwsem); |
496 | |||
497 | return uc->next; | ||
498 | } | 450 | } |
499 | 451 | ||
500 | /* | 452 | /* |
@@ -588,7 +540,8 @@ static int prepare_uprobe(struct uprobe *uprobe, struct file *file, | |||
588 | if (test_bit(UPROBE_COPY_INSN, &uprobe->flags)) | 540 | if (test_bit(UPROBE_COPY_INSN, &uprobe->flags)) |
589 | return ret; | 541 | return ret; |
590 | 542 | ||
591 | mutex_lock(&uprobe->copy_mutex); | 543 | /* TODO: move this into _register, until then we abuse this sem. */ |
544 | down_write(&uprobe->consumer_rwsem); | ||
592 | if (test_bit(UPROBE_COPY_INSN, &uprobe->flags)) | 545 | if (test_bit(UPROBE_COPY_INSN, &uprobe->flags)) |
593 | goto out; | 546 | goto out; |
594 | 547 | ||
@@ -612,7 +565,30 @@ static int prepare_uprobe(struct uprobe *uprobe, struct file *file, | |||
612 | set_bit(UPROBE_COPY_INSN, &uprobe->flags); | 565 | set_bit(UPROBE_COPY_INSN, &uprobe->flags); |
613 | 566 | ||
614 | out: | 567 | out: |
615 | mutex_unlock(&uprobe->copy_mutex); | 568 | up_write(&uprobe->consumer_rwsem); |
569 | |||
570 | return ret; | ||
571 | } | ||
572 | |||
573 | static inline bool consumer_filter(struct uprobe_consumer *uc, | ||
574 | enum uprobe_filter_ctx ctx, struct mm_struct *mm) | ||
575 | { | ||
576 | return !uc->filter || uc->filter(uc, ctx, mm); | ||
577 | } | ||
578 | |||
579 | static bool filter_chain(struct uprobe *uprobe, | ||
580 | enum uprobe_filter_ctx ctx, struct mm_struct *mm) | ||
581 | { | ||
582 | struct uprobe_consumer *uc; | ||
583 | bool ret = false; | ||
584 | |||
585 | down_read(&uprobe->consumer_rwsem); | ||
586 | for (uc = uprobe->consumers; uc; uc = uc->next) { | ||
587 | ret = consumer_filter(uc, ctx, mm); | ||
588 | if (ret) | ||
589 | break; | ||
590 | } | ||
591 | up_read(&uprobe->consumer_rwsem); | ||
616 | 592 | ||
617 | return ret; | 593 | return ret; |
618 | } | 594 | } |
@@ -624,16 +600,6 @@ install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, | |||
624 | bool first_uprobe; | 600 | bool first_uprobe; |
625 | int ret; | 601 | int ret; |
626 | 602 | ||
627 | /* | ||
628 | * If probe is being deleted, unregister thread could be done with | ||
629 | * the vma-rmap-walk through. Adding a probe now can be fatal since | ||
630 | * nobody will be able to cleanup. Also we could be from fork or | ||
631 | * mremap path, where the probe might have already been inserted. | ||
632 | * Hence behave as if probe already existed. | ||
633 | */ | ||
634 | if (!uprobe->consumers) | ||
635 | return 0; | ||
636 | |||
637 | ret = prepare_uprobe(uprobe, vma->vm_file, mm, vaddr); | 603 | ret = prepare_uprobe(uprobe, vma->vm_file, mm, vaddr); |
638 | if (ret) | 604 | if (ret) |
639 | return ret; | 605 | return ret; |
@@ -658,14 +624,14 @@ install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, | |||
658 | static int | 624 | static int |
659 | remove_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, unsigned long vaddr) | 625 | remove_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, unsigned long vaddr) |
660 | { | 626 | { |
661 | /* can happen if uprobe_register() fails */ | ||
662 | if (!test_bit(MMF_HAS_UPROBES, &mm->flags)) | ||
663 | return 0; | ||
664 | |||
665 | set_bit(MMF_RECALC_UPROBES, &mm->flags); | 627 | set_bit(MMF_RECALC_UPROBES, &mm->flags); |
666 | return set_orig_insn(&uprobe->arch, mm, vaddr); | 628 | return set_orig_insn(&uprobe->arch, mm, vaddr); |
667 | } | 629 | } |
668 | 630 | ||
631 | static inline bool uprobe_is_active(struct uprobe *uprobe) | ||
632 | { | ||
633 | return !RB_EMPTY_NODE(&uprobe->rb_node); | ||
634 | } | ||
669 | /* | 635 | /* |
670 | * There could be threads that have already hit the breakpoint. They | 636 | * There could be threads that have already hit the breakpoint. They |
671 | * will recheck the current insn and restart if find_uprobe() fails. | 637 | * will recheck the current insn and restart if find_uprobe() fails. |
@@ -673,12 +639,15 @@ remove_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, unsigned long vad | |||
673 | */ | 639 | */ |
674 | static void delete_uprobe(struct uprobe *uprobe) | 640 | static void delete_uprobe(struct uprobe *uprobe) |
675 | { | 641 | { |
642 | if (WARN_ON(!uprobe_is_active(uprobe))) | ||
643 | return; | ||
644 | |||
676 | spin_lock(&uprobes_treelock); | 645 | spin_lock(&uprobes_treelock); |
677 | rb_erase(&uprobe->rb_node, &uprobes_tree); | 646 | rb_erase(&uprobe->rb_node, &uprobes_tree); |
678 | spin_unlock(&uprobes_treelock); | 647 | spin_unlock(&uprobes_treelock); |
648 | RB_CLEAR_NODE(&uprobe->rb_node); /* for uprobe_is_active() */ | ||
679 | iput(uprobe->inode); | 649 | iput(uprobe->inode); |
680 | put_uprobe(uprobe); | 650 | put_uprobe(uprobe); |
681 | atomic_dec(&uprobe_events); | ||
682 | } | 651 | } |
683 | 652 | ||
684 | struct map_info { | 653 | struct map_info { |
@@ -764,8 +733,10 @@ build_map_info(struct address_space *mapping, loff_t offset, bool is_register) | |||
764 | return curr; | 733 | return curr; |
765 | } | 734 | } |
766 | 735 | ||
767 | static int register_for_each_vma(struct uprobe *uprobe, bool is_register) | 736 | static int |
737 | register_for_each_vma(struct uprobe *uprobe, struct uprobe_consumer *new) | ||
768 | { | 738 | { |
739 | bool is_register = !!new; | ||
769 | struct map_info *info; | 740 | struct map_info *info; |
770 | int err = 0; | 741 | int err = 0; |
771 | 742 | ||
@@ -794,10 +765,16 @@ static int register_for_each_vma(struct uprobe *uprobe, bool is_register) | |||
794 | vaddr_to_offset(vma, info->vaddr) != uprobe->offset) | 765 | vaddr_to_offset(vma, info->vaddr) != uprobe->offset) |
795 | goto unlock; | 766 | goto unlock; |
796 | 767 | ||
797 | if (is_register) | 768 | if (is_register) { |
798 | err = install_breakpoint(uprobe, mm, vma, info->vaddr); | 769 | /* consult only the "caller", new consumer. */ |
799 | else | 770 | if (consumer_filter(new, |
800 | err |= remove_breakpoint(uprobe, mm, info->vaddr); | 771 | UPROBE_FILTER_REGISTER, mm)) |
772 | err = install_breakpoint(uprobe, mm, vma, info->vaddr); | ||
773 | } else if (test_bit(MMF_HAS_UPROBES, &mm->flags)) { | ||
774 | if (!filter_chain(uprobe, | ||
775 | UPROBE_FILTER_UNREGISTER, mm)) | ||
776 | err |= remove_breakpoint(uprobe, mm, info->vaddr); | ||
777 | } | ||
801 | 778 | ||
802 | unlock: | 779 | unlock: |
803 | up_write(&mm->mmap_sem); | 780 | up_write(&mm->mmap_sem); |
@@ -810,17 +787,23 @@ static int register_for_each_vma(struct uprobe *uprobe, bool is_register) | |||
810 | return err; | 787 | return err; |
811 | } | 788 | } |
812 | 789 | ||
813 | static int __uprobe_register(struct uprobe *uprobe) | 790 | static int __uprobe_register(struct uprobe *uprobe, struct uprobe_consumer *uc) |
814 | { | 791 | { |
815 | return register_for_each_vma(uprobe, true); | 792 | consumer_add(uprobe, uc); |
793 | return register_for_each_vma(uprobe, uc); | ||
816 | } | 794 | } |
817 | 795 | ||
818 | static void __uprobe_unregister(struct uprobe *uprobe) | 796 | static void __uprobe_unregister(struct uprobe *uprobe, struct uprobe_consumer *uc) |
819 | { | 797 | { |
820 | if (!register_for_each_vma(uprobe, false)) | 798 | int err; |
821 | delete_uprobe(uprobe); | 799 | |
800 | if (!consumer_del(uprobe, uc)) /* WARN? */ | ||
801 | return; | ||
822 | 802 | ||
803 | err = register_for_each_vma(uprobe, NULL); | ||
823 | /* TODO : cant unregister? schedule a worker thread */ | 804 | /* TODO : cant unregister? schedule a worker thread */ |
805 | if (!uprobe->consumers && !err) | ||
806 | delete_uprobe(uprobe); | ||
824 | } | 807 | } |
825 | 808 | ||
826 | /* | 809 | /* |
@@ -845,31 +828,59 @@ int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer * | |||
845 | struct uprobe *uprobe; | 828 | struct uprobe *uprobe; |
846 | int ret; | 829 | int ret; |
847 | 830 | ||
848 | if (!inode || !uc || uc->next) | 831 | /* Racy, just to catch the obvious mistakes */ |
849 | return -EINVAL; | ||
850 | |||
851 | if (offset > i_size_read(inode)) | 832 | if (offset > i_size_read(inode)) |
852 | return -EINVAL; | 833 | return -EINVAL; |
853 | 834 | ||
854 | ret = 0; | 835 | retry: |
855 | mutex_lock(uprobes_hash(inode)); | ||
856 | uprobe = alloc_uprobe(inode, offset); | 836 | uprobe = alloc_uprobe(inode, offset); |
857 | 837 | if (!uprobe) | |
858 | if (!uprobe) { | 838 | return -ENOMEM; |
859 | ret = -ENOMEM; | 839 | /* |
860 | } else if (!consumer_add(uprobe, uc)) { | 840 | * We can race with uprobe_unregister()->delete_uprobe(). |
861 | ret = __uprobe_register(uprobe); | 841 | * Check uprobe_is_active() and retry if it is false. |
862 | if (ret) { | 842 | */ |
863 | uprobe->consumers = NULL; | 843 | down_write(&uprobe->register_rwsem); |
864 | __uprobe_unregister(uprobe); | 844 | ret = -EAGAIN; |
865 | } else { | 845 | if (likely(uprobe_is_active(uprobe))) { |
866 | set_bit(UPROBE_RUN_HANDLER, &uprobe->flags); | 846 | ret = __uprobe_register(uprobe, uc); |
867 | } | 847 | if (ret) |
848 | __uprobe_unregister(uprobe, uc); | ||
868 | } | 849 | } |
850 | up_write(&uprobe->register_rwsem); | ||
851 | put_uprobe(uprobe); | ||
869 | 852 | ||
870 | mutex_unlock(uprobes_hash(inode)); | 853 | if (unlikely(ret == -EAGAIN)) |
871 | if (uprobe) | 854 | goto retry; |
872 | put_uprobe(uprobe); | 855 | return ret; |
856 | } | ||
857 | EXPORT_SYMBOL_GPL(uprobe_register); | ||
858 | |||
859 | /* | ||
860 | * uprobe_apply - unregister a already registered probe. | ||
861 | * @inode: the file in which the probe has to be removed. | ||
862 | * @offset: offset from the start of the file. | ||
863 | * @uc: consumer which wants to add more or remove some breakpoints | ||
864 | * @add: add or remove the breakpoints | ||
865 | */ | ||
866 | int uprobe_apply(struct inode *inode, loff_t offset, | ||
867 | struct uprobe_consumer *uc, bool add) | ||
868 | { | ||
869 | struct uprobe *uprobe; | ||
870 | struct uprobe_consumer *con; | ||
871 | int ret = -ENOENT; | ||
872 | |||
873 | uprobe = find_uprobe(inode, offset); | ||
874 | if (!uprobe) | ||
875 | return ret; | ||
876 | |||
877 | down_write(&uprobe->register_rwsem); | ||
878 | for (con = uprobe->consumers; con && con != uc ; con = con->next) | ||
879 | ; | ||
880 | if (con) | ||
881 | ret = register_for_each_vma(uprobe, add ? uc : NULL); | ||
882 | up_write(&uprobe->register_rwsem); | ||
883 | put_uprobe(uprobe); | ||
873 | 884 | ||
874 | return ret; | 885 | return ret; |
875 | } | 886 | } |
@@ -884,25 +895,42 @@ void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consume | |||
884 | { | 895 | { |
885 | struct uprobe *uprobe; | 896 | struct uprobe *uprobe; |
886 | 897 | ||
887 | if (!inode || !uc) | ||
888 | return; | ||
889 | |||
890 | uprobe = find_uprobe(inode, offset); | 898 | uprobe = find_uprobe(inode, offset); |
891 | if (!uprobe) | 899 | if (!uprobe) |
892 | return; | 900 | return; |
893 | 901 | ||
894 | mutex_lock(uprobes_hash(inode)); | 902 | down_write(&uprobe->register_rwsem); |
903 | __uprobe_unregister(uprobe, uc); | ||
904 | up_write(&uprobe->register_rwsem); | ||
905 | put_uprobe(uprobe); | ||
906 | } | ||
907 | EXPORT_SYMBOL_GPL(uprobe_unregister); | ||
895 | 908 | ||
896 | if (consumer_del(uprobe, uc)) { | 909 | static int unapply_uprobe(struct uprobe *uprobe, struct mm_struct *mm) |
897 | if (!uprobe->consumers) { | 910 | { |
898 | __uprobe_unregister(uprobe); | 911 | struct vm_area_struct *vma; |
899 | clear_bit(UPROBE_RUN_HANDLER, &uprobe->flags); | 912 | int err = 0; |
900 | } | 913 | |
914 | down_read(&mm->mmap_sem); | ||
915 | for (vma = mm->mmap; vma; vma = vma->vm_next) { | ||
916 | unsigned long vaddr; | ||
917 | loff_t offset; | ||
918 | |||
919 | if (!valid_vma(vma, false) || | ||
920 | vma->vm_file->f_mapping->host != uprobe->inode) | ||
921 | continue; | ||
922 | |||
923 | offset = (loff_t)vma->vm_pgoff << PAGE_SHIFT; | ||
924 | if (uprobe->offset < offset || | ||
925 | uprobe->offset >= offset + vma->vm_end - vma->vm_start) | ||
926 | continue; | ||
927 | |||
928 | vaddr = offset_to_vaddr(vma, uprobe->offset); | ||
929 | err |= remove_breakpoint(uprobe, mm, vaddr); | ||
901 | } | 930 | } |
931 | up_read(&mm->mmap_sem); | ||
902 | 932 | ||
903 | mutex_unlock(uprobes_hash(inode)); | 933 | return err; |
904 | if (uprobe) | ||
905 | put_uprobe(uprobe); | ||
906 | } | 934 | } |
907 | 935 | ||
908 | static struct rb_node * | 936 | static struct rb_node * |
@@ -979,7 +1007,7 @@ int uprobe_mmap(struct vm_area_struct *vma) | |||
979 | struct uprobe *uprobe, *u; | 1007 | struct uprobe *uprobe, *u; |
980 | struct inode *inode; | 1008 | struct inode *inode; |
981 | 1009 | ||
982 | if (!atomic_read(&uprobe_events) || !valid_vma(vma, true)) | 1010 | if (no_uprobe_events() || !valid_vma(vma, true)) |
983 | return 0; | 1011 | return 0; |
984 | 1012 | ||
985 | inode = vma->vm_file->f_mapping->host; | 1013 | inode = vma->vm_file->f_mapping->host; |
@@ -988,9 +1016,14 @@ int uprobe_mmap(struct vm_area_struct *vma) | |||
988 | 1016 | ||
989 | mutex_lock(uprobes_mmap_hash(inode)); | 1017 | mutex_lock(uprobes_mmap_hash(inode)); |
990 | build_probe_list(inode, vma, vma->vm_start, vma->vm_end, &tmp_list); | 1018 | build_probe_list(inode, vma, vma->vm_start, vma->vm_end, &tmp_list); |
991 | 1019 | /* | |
1020 | * We can race with uprobe_unregister(), this uprobe can be already | ||
1021 | * removed. But in this case filter_chain() must return false, all | ||
1022 | * consumers have gone away. | ||
1023 | */ | ||
992 | list_for_each_entry_safe(uprobe, u, &tmp_list, pending_list) { | 1024 | list_for_each_entry_safe(uprobe, u, &tmp_list, pending_list) { |
993 | if (!fatal_signal_pending(current)) { | 1025 | if (!fatal_signal_pending(current) && |
1026 | filter_chain(uprobe, UPROBE_FILTER_MMAP, vma->vm_mm)) { | ||
994 | unsigned long vaddr = offset_to_vaddr(vma, uprobe->offset); | 1027 | unsigned long vaddr = offset_to_vaddr(vma, uprobe->offset); |
995 | install_breakpoint(uprobe, vma->vm_mm, vma, vaddr); | 1028 | install_breakpoint(uprobe, vma->vm_mm, vma, vaddr); |
996 | } | 1029 | } |
@@ -1025,7 +1058,7 @@ vma_has_uprobes(struct vm_area_struct *vma, unsigned long start, unsigned long e | |||
1025 | */ | 1058 | */ |
1026 | void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end) | 1059 | void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end) |
1027 | { | 1060 | { |
1028 | if (!atomic_read(&uprobe_events) || !valid_vma(vma, false)) | 1061 | if (no_uprobe_events() || !valid_vma(vma, false)) |
1029 | return; | 1062 | return; |
1030 | 1063 | ||
1031 | if (!atomic_read(&vma->vm_mm->mm_users)) /* called by mmput() ? */ | 1064 | if (!atomic_read(&vma->vm_mm->mm_users)) /* called by mmput() ? */ |
@@ -1042,22 +1075,14 @@ void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned lon | |||
1042 | /* Slot allocation for XOL */ | 1075 | /* Slot allocation for XOL */ |
1043 | static int xol_add_vma(struct xol_area *area) | 1076 | static int xol_add_vma(struct xol_area *area) |
1044 | { | 1077 | { |
1045 | struct mm_struct *mm; | 1078 | struct mm_struct *mm = current->mm; |
1046 | int ret; | 1079 | int ret = -EALREADY; |
1047 | |||
1048 | area->page = alloc_page(GFP_HIGHUSER); | ||
1049 | if (!area->page) | ||
1050 | return -ENOMEM; | ||
1051 | |||
1052 | ret = -EALREADY; | ||
1053 | mm = current->mm; | ||
1054 | 1080 | ||
1055 | down_write(&mm->mmap_sem); | 1081 | down_write(&mm->mmap_sem); |
1056 | if (mm->uprobes_state.xol_area) | 1082 | if (mm->uprobes_state.xol_area) |
1057 | goto fail; | 1083 | goto fail; |
1058 | 1084 | ||
1059 | ret = -ENOMEM; | 1085 | ret = -ENOMEM; |
1060 | |||
1061 | /* Try to map as high as possible, this is only a hint. */ | 1086 | /* Try to map as high as possible, this is only a hint. */ |
1062 | area->vaddr = get_unmapped_area(NULL, TASK_SIZE - PAGE_SIZE, PAGE_SIZE, 0, 0); | 1087 | area->vaddr = get_unmapped_area(NULL, TASK_SIZE - PAGE_SIZE, PAGE_SIZE, 0, 0); |
1063 | if (area->vaddr & ~PAGE_MASK) { | 1088 | if (area->vaddr & ~PAGE_MASK) { |
@@ -1073,54 +1098,53 @@ static int xol_add_vma(struct xol_area *area) | |||
1073 | smp_wmb(); /* pairs with get_xol_area() */ | 1098 | smp_wmb(); /* pairs with get_xol_area() */ |
1074 | mm->uprobes_state.xol_area = area; | 1099 | mm->uprobes_state.xol_area = area; |
1075 | ret = 0; | 1100 | ret = 0; |
1076 | 1101 | fail: | |
1077 | fail: | ||
1078 | up_write(&mm->mmap_sem); | 1102 | up_write(&mm->mmap_sem); |
1079 | if (ret) | ||
1080 | __free_page(area->page); | ||
1081 | 1103 | ||
1082 | return ret; | 1104 | return ret; |
1083 | } | 1105 | } |
1084 | 1106 | ||
1085 | static struct xol_area *get_xol_area(struct mm_struct *mm) | ||
1086 | { | ||
1087 | struct xol_area *area; | ||
1088 | |||
1089 | area = mm->uprobes_state.xol_area; | ||
1090 | smp_read_barrier_depends(); /* pairs with wmb in xol_add_vma() */ | ||
1091 | |||
1092 | return area; | ||
1093 | } | ||
1094 | |||
1095 | /* | 1107 | /* |
1096 | * xol_alloc_area - Allocate process's xol_area. | 1108 | * get_xol_area - Allocate process's xol_area if necessary. |
1097 | * This area will be used for storing instructions for execution out of | 1109 | * This area will be used for storing instructions for execution out of line. |
1098 | * line. | ||
1099 | * | 1110 | * |
1100 | * Returns the allocated area or NULL. | 1111 | * Returns the allocated area or NULL. |
1101 | */ | 1112 | */ |
1102 | static struct xol_area *xol_alloc_area(void) | 1113 | static struct xol_area *get_xol_area(void) |
1103 | { | 1114 | { |
1115 | struct mm_struct *mm = current->mm; | ||
1104 | struct xol_area *area; | 1116 | struct xol_area *area; |
1105 | 1117 | ||
1118 | area = mm->uprobes_state.xol_area; | ||
1119 | if (area) | ||
1120 | goto ret; | ||
1121 | |||
1106 | area = kzalloc(sizeof(*area), GFP_KERNEL); | 1122 | area = kzalloc(sizeof(*area), GFP_KERNEL); |
1107 | if (unlikely(!area)) | 1123 | if (unlikely(!area)) |
1108 | return NULL; | 1124 | goto out; |
1109 | 1125 | ||
1110 | area->bitmap = kzalloc(BITS_TO_LONGS(UINSNS_PER_PAGE) * sizeof(long), GFP_KERNEL); | 1126 | area->bitmap = kzalloc(BITS_TO_LONGS(UINSNS_PER_PAGE) * sizeof(long), GFP_KERNEL); |
1111 | |||
1112 | if (!area->bitmap) | 1127 | if (!area->bitmap) |
1113 | goto fail; | 1128 | goto free_area; |
1129 | |||
1130 | area->page = alloc_page(GFP_HIGHUSER); | ||
1131 | if (!area->page) | ||
1132 | goto free_bitmap; | ||
1114 | 1133 | ||
1115 | init_waitqueue_head(&area->wq); | 1134 | init_waitqueue_head(&area->wq); |
1116 | if (!xol_add_vma(area)) | 1135 | if (!xol_add_vma(area)) |
1117 | return area; | 1136 | return area; |
1118 | 1137 | ||
1119 | fail: | 1138 | __free_page(area->page); |
1139 | free_bitmap: | ||
1120 | kfree(area->bitmap); | 1140 | kfree(area->bitmap); |
1141 | free_area: | ||
1121 | kfree(area); | 1142 | kfree(area); |
1122 | 1143 | out: | |
1123 | return get_xol_area(current->mm); | 1144 | area = mm->uprobes_state.xol_area; |
1145 | ret: | ||
1146 | smp_read_barrier_depends(); /* pairs with wmb in xol_add_vma() */ | ||
1147 | return area; | ||
1124 | } | 1148 | } |
1125 | 1149 | ||
1126 | /* | 1150 | /* |
@@ -1186,33 +1210,26 @@ static unsigned long xol_take_insn_slot(struct xol_area *area) | |||
1186 | } | 1210 | } |
1187 | 1211 | ||
1188 | /* | 1212 | /* |
1189 | * xol_get_insn_slot - If was not allocated a slot, then | 1213 | * xol_get_insn_slot - allocate a slot for xol. |
1190 | * allocate a slot. | ||
1191 | * Returns the allocated slot address or 0. | 1214 | * Returns the allocated slot address or 0. |
1192 | */ | 1215 | */ |
1193 | static unsigned long xol_get_insn_slot(struct uprobe *uprobe, unsigned long slot_addr) | 1216 | static unsigned long xol_get_insn_slot(struct uprobe *uprobe) |
1194 | { | 1217 | { |
1195 | struct xol_area *area; | 1218 | struct xol_area *area; |
1196 | unsigned long offset; | 1219 | unsigned long offset; |
1220 | unsigned long xol_vaddr; | ||
1197 | void *vaddr; | 1221 | void *vaddr; |
1198 | 1222 | ||
1199 | area = get_xol_area(current->mm); | 1223 | area = get_xol_area(); |
1200 | if (!area) { | 1224 | if (!area) |
1201 | area = xol_alloc_area(); | 1225 | return 0; |
1202 | if (!area) | ||
1203 | return 0; | ||
1204 | } | ||
1205 | current->utask->xol_vaddr = xol_take_insn_slot(area); | ||
1206 | 1226 | ||
1207 | /* | 1227 | xol_vaddr = xol_take_insn_slot(area); |
1208 | * Initialize the slot if xol_vaddr points to valid | 1228 | if (unlikely(!xol_vaddr)) |
1209 | * instruction slot. | ||
1210 | */ | ||
1211 | if (unlikely(!current->utask->xol_vaddr)) | ||
1212 | return 0; | 1229 | return 0; |
1213 | 1230 | ||
1214 | current->utask->vaddr = slot_addr; | 1231 | /* Initialize the slot */ |
1215 | offset = current->utask->xol_vaddr & ~PAGE_MASK; | 1232 | offset = xol_vaddr & ~PAGE_MASK; |
1216 | vaddr = kmap_atomic(area->page); | 1233 | vaddr = kmap_atomic(area->page); |
1217 | memcpy(vaddr + offset, uprobe->arch.insn, MAX_UINSN_BYTES); | 1234 | memcpy(vaddr + offset, uprobe->arch.insn, MAX_UINSN_BYTES); |
1218 | kunmap_atomic(vaddr); | 1235 | kunmap_atomic(vaddr); |
@@ -1222,7 +1239,7 @@ static unsigned long xol_get_insn_slot(struct uprobe *uprobe, unsigned long slot | |||
1222 | */ | 1239 | */ |
1223 | flush_dcache_page(area->page); | 1240 | flush_dcache_page(area->page); |
1224 | 1241 | ||
1225 | return current->utask->xol_vaddr; | 1242 | return xol_vaddr; |
1226 | } | 1243 | } |
1227 | 1244 | ||
1228 | /* | 1245 | /* |
@@ -1240,8 +1257,7 @@ static void xol_free_insn_slot(struct task_struct *tsk) | |||
1240 | return; | 1257 | return; |
1241 | 1258 | ||
1242 | slot_addr = tsk->utask->xol_vaddr; | 1259 | slot_addr = tsk->utask->xol_vaddr; |
1243 | 1260 | if (unlikely(!slot_addr)) | |
1244 | if (unlikely(!slot_addr || IS_ERR_VALUE(slot_addr))) | ||
1245 | return; | 1261 | return; |
1246 | 1262 | ||
1247 | area = tsk->mm->uprobes_state.xol_area; | 1263 | area = tsk->mm->uprobes_state.xol_area; |
@@ -1303,33 +1319,48 @@ void uprobe_copy_process(struct task_struct *t) | |||
1303 | } | 1319 | } |
1304 | 1320 | ||
1305 | /* | 1321 | /* |
1306 | * Allocate a uprobe_task object for the task. | 1322 | * Allocate a uprobe_task object for the task if if necessary. |
1307 | * Called when the thread hits a breakpoint for the first time. | 1323 | * Called when the thread hits a breakpoint. |
1308 | * | 1324 | * |
1309 | * Returns: | 1325 | * Returns: |
1310 | * - pointer to new uprobe_task on success | 1326 | * - pointer to new uprobe_task on success |
1311 | * - NULL otherwise | 1327 | * - NULL otherwise |
1312 | */ | 1328 | */ |
1313 | static struct uprobe_task *add_utask(void) | 1329 | static struct uprobe_task *get_utask(void) |
1314 | { | 1330 | { |
1315 | struct uprobe_task *utask; | 1331 | if (!current->utask) |
1316 | 1332 | current->utask = kzalloc(sizeof(struct uprobe_task), GFP_KERNEL); | |
1317 | utask = kzalloc(sizeof *utask, GFP_KERNEL); | 1333 | return current->utask; |
1318 | if (unlikely(!utask)) | ||
1319 | return NULL; | ||
1320 | |||
1321 | current->utask = utask; | ||
1322 | return utask; | ||
1323 | } | 1334 | } |
1324 | 1335 | ||
1325 | /* Prepare to single-step probed instruction out of line. */ | 1336 | /* Prepare to single-step probed instruction out of line. */ |
1326 | static int | 1337 | static int |
1327 | pre_ssout(struct uprobe *uprobe, struct pt_regs *regs, unsigned long vaddr) | 1338 | pre_ssout(struct uprobe *uprobe, struct pt_regs *regs, unsigned long bp_vaddr) |
1328 | { | 1339 | { |
1329 | if (xol_get_insn_slot(uprobe, vaddr) && !arch_uprobe_pre_xol(&uprobe->arch, regs)) | 1340 | struct uprobe_task *utask; |
1330 | return 0; | 1341 | unsigned long xol_vaddr; |
1342 | int err; | ||
1343 | |||
1344 | utask = get_utask(); | ||
1345 | if (!utask) | ||
1346 | return -ENOMEM; | ||
1347 | |||
1348 | xol_vaddr = xol_get_insn_slot(uprobe); | ||
1349 | if (!xol_vaddr) | ||
1350 | return -ENOMEM; | ||
1351 | |||
1352 | utask->xol_vaddr = xol_vaddr; | ||
1353 | utask->vaddr = bp_vaddr; | ||
1354 | |||
1355 | err = arch_uprobe_pre_xol(&uprobe->arch, regs); | ||
1356 | if (unlikely(err)) { | ||
1357 | xol_free_insn_slot(current); | ||
1358 | return err; | ||
1359 | } | ||
1331 | 1360 | ||
1332 | return -EFAULT; | 1361 | utask->active_uprobe = uprobe; |
1362 | utask->state = UTASK_SSTEP; | ||
1363 | return 0; | ||
1333 | } | 1364 | } |
1334 | 1365 | ||
1335 | /* | 1366 | /* |
@@ -1391,6 +1422,7 @@ static void mmf_recalc_uprobes(struct mm_struct *mm) | |||
1391 | * This is not strictly accurate, we can race with | 1422 | * This is not strictly accurate, we can race with |
1392 | * uprobe_unregister() and see the already removed | 1423 | * uprobe_unregister() and see the already removed |
1393 | * uprobe if delete_uprobe() was not yet called. | 1424 | * uprobe if delete_uprobe() was not yet called. |
1425 | * Or this uprobe can be filtered out. | ||
1394 | */ | 1426 | */ |
1395 | if (vma_has_uprobes(vma, vma->vm_start, vma->vm_end)) | 1427 | if (vma_has_uprobes(vma, vma->vm_start, vma->vm_end)) |
1396 | return; | 1428 | return; |
@@ -1452,13 +1484,33 @@ static struct uprobe *find_active_uprobe(unsigned long bp_vaddr, int *is_swbp) | |||
1452 | return uprobe; | 1484 | return uprobe; |
1453 | } | 1485 | } |
1454 | 1486 | ||
1487 | static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs) | ||
1488 | { | ||
1489 | struct uprobe_consumer *uc; | ||
1490 | int remove = UPROBE_HANDLER_REMOVE; | ||
1491 | |||
1492 | down_read(&uprobe->register_rwsem); | ||
1493 | for (uc = uprobe->consumers; uc; uc = uc->next) { | ||
1494 | int rc = uc->handler(uc, regs); | ||
1495 | |||
1496 | WARN(rc & ~UPROBE_HANDLER_MASK, | ||
1497 | "bad rc=0x%x from %pf()\n", rc, uc->handler); | ||
1498 | remove &= rc; | ||
1499 | } | ||
1500 | |||
1501 | if (remove && uprobe->consumers) { | ||
1502 | WARN_ON(!uprobe_is_active(uprobe)); | ||
1503 | unapply_uprobe(uprobe, current->mm); | ||
1504 | } | ||
1505 | up_read(&uprobe->register_rwsem); | ||
1506 | } | ||
1507 | |||
1455 | /* | 1508 | /* |
1456 | * Run handler and ask thread to singlestep. | 1509 | * Run handler and ask thread to singlestep. |
1457 | * Ensure all non-fatal signals cannot interrupt thread while it singlesteps. | 1510 | * Ensure all non-fatal signals cannot interrupt thread while it singlesteps. |
1458 | */ | 1511 | */ |
1459 | static void handle_swbp(struct pt_regs *regs) | 1512 | static void handle_swbp(struct pt_regs *regs) |
1460 | { | 1513 | { |
1461 | struct uprobe_task *utask; | ||
1462 | struct uprobe *uprobe; | 1514 | struct uprobe *uprobe; |
1463 | unsigned long bp_vaddr; | 1515 | unsigned long bp_vaddr; |
1464 | int uninitialized_var(is_swbp); | 1516 | int uninitialized_var(is_swbp); |
@@ -1483,6 +1535,10 @@ static void handle_swbp(struct pt_regs *regs) | |||
1483 | } | 1535 | } |
1484 | return; | 1536 | return; |
1485 | } | 1537 | } |
1538 | |||
1539 | /* change it in advance for ->handler() and restart */ | ||
1540 | instruction_pointer_set(regs, bp_vaddr); | ||
1541 | |||
1486 | /* | 1542 | /* |
1487 | * TODO: move copy_insn/etc into _register and remove this hack. | 1543 | * TODO: move copy_insn/etc into _register and remove this hack. |
1488 | * After we hit the bp, _unregister + _register can install the | 1544 | * After we hit the bp, _unregister + _register can install the |
@@ -1490,32 +1546,16 @@ static void handle_swbp(struct pt_regs *regs) | |||
1490 | */ | 1546 | */ |
1491 | smp_rmb(); /* pairs with wmb() in install_breakpoint() */ | 1547 | smp_rmb(); /* pairs with wmb() in install_breakpoint() */ |
1492 | if (unlikely(!test_bit(UPROBE_COPY_INSN, &uprobe->flags))) | 1548 | if (unlikely(!test_bit(UPROBE_COPY_INSN, &uprobe->flags))) |
1493 | goto restart; | 1549 | goto out; |
1494 | |||
1495 | utask = current->utask; | ||
1496 | if (!utask) { | ||
1497 | utask = add_utask(); | ||
1498 | /* Cannot allocate; re-execute the instruction. */ | ||
1499 | if (!utask) | ||
1500 | goto restart; | ||
1501 | } | ||
1502 | 1550 | ||
1503 | handler_chain(uprobe, regs); | 1551 | handler_chain(uprobe, regs); |
1504 | if (can_skip_sstep(uprobe, regs)) | 1552 | if (can_skip_sstep(uprobe, regs)) |
1505 | goto out; | 1553 | goto out; |
1506 | 1554 | ||
1507 | if (!pre_ssout(uprobe, regs, bp_vaddr)) { | 1555 | if (!pre_ssout(uprobe, regs, bp_vaddr)) |
1508 | utask->active_uprobe = uprobe; | ||
1509 | utask->state = UTASK_SSTEP; | ||
1510 | return; | 1556 | return; |
1511 | } | ||
1512 | 1557 | ||
1513 | restart: | 1558 | /* can_skip_sstep() succeeded, or restart if can't singlestep */ |
1514 | /* | ||
1515 | * cannot singlestep; cannot skip instruction; | ||
1516 | * re-execute the instruction. | ||
1517 | */ | ||
1518 | instruction_pointer_set(regs, bp_vaddr); | ||
1519 | out: | 1559 | out: |
1520 | put_uprobe(uprobe); | 1560 | put_uprobe(uprobe); |
1521 | } | 1561 | } |
@@ -1609,10 +1649,8 @@ static int __init init_uprobes(void) | |||
1609 | { | 1649 | { |
1610 | int i; | 1650 | int i; |
1611 | 1651 | ||
1612 | for (i = 0; i < UPROBES_HASH_SZ; i++) { | 1652 | for (i = 0; i < UPROBES_HASH_SZ; i++) |
1613 | mutex_init(&uprobes_mutex[i]); | ||
1614 | mutex_init(&uprobes_mmap_mutex[i]); | 1653 | mutex_init(&uprobes_mmap_mutex[i]); |
1615 | } | ||
1616 | 1654 | ||
1617 | if (percpu_init_rwsem(&dup_mmap_sem)) | 1655 | if (percpu_init_rwsem(&dup_mmap_sem)) |
1618 | return -ENOMEM; | 1656 | return -ENOMEM; |
diff --git a/kernel/exit.c b/kernel/exit.c index b4df21937216..7dd20408707c 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
@@ -85,6 +85,7 @@ static void __exit_signal(struct task_struct *tsk) | |||
85 | bool group_dead = thread_group_leader(tsk); | 85 | bool group_dead = thread_group_leader(tsk); |
86 | struct sighand_struct *sighand; | 86 | struct sighand_struct *sighand; |
87 | struct tty_struct *uninitialized_var(tty); | 87 | struct tty_struct *uninitialized_var(tty); |
88 | cputime_t utime, stime; | ||
88 | 89 | ||
89 | sighand = rcu_dereference_check(tsk->sighand, | 90 | sighand = rcu_dereference_check(tsk->sighand, |
90 | lockdep_tasklist_lock_is_held()); | 91 | lockdep_tasklist_lock_is_held()); |
@@ -123,9 +124,10 @@ static void __exit_signal(struct task_struct *tsk) | |||
123 | * We won't ever get here for the group leader, since it | 124 | * We won't ever get here for the group leader, since it |
124 | * will have been the last reference on the signal_struct. | 125 | * will have been the last reference on the signal_struct. |
125 | */ | 126 | */ |
126 | sig->utime += tsk->utime; | 127 | task_cputime(tsk, &utime, &stime); |
127 | sig->stime += tsk->stime; | 128 | sig->utime += utime; |
128 | sig->gtime += tsk->gtime; | 129 | sig->stime += stime; |
130 | sig->gtime += task_gtime(tsk); | ||
129 | sig->min_flt += tsk->min_flt; | 131 | sig->min_flt += tsk->min_flt; |
130 | sig->maj_flt += tsk->maj_flt; | 132 | sig->maj_flt += tsk->maj_flt; |
131 | sig->nvcsw += tsk->nvcsw; | 133 | sig->nvcsw += tsk->nvcsw; |
@@ -1092,7 +1094,7 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p) | |||
1092 | sig = p->signal; | 1094 | sig = p->signal; |
1093 | psig->cutime += tgutime + sig->cutime; | 1095 | psig->cutime += tgutime + sig->cutime; |
1094 | psig->cstime += tgstime + sig->cstime; | 1096 | psig->cstime += tgstime + sig->cstime; |
1095 | psig->cgtime += p->gtime + sig->gtime + sig->cgtime; | 1097 | psig->cgtime += task_gtime(p) + sig->gtime + sig->cgtime; |
1096 | psig->cmin_flt += | 1098 | psig->cmin_flt += |
1097 | p->min_flt + sig->min_flt + sig->cmin_flt; | 1099 | p->min_flt + sig->min_flt + sig->cmin_flt; |
1098 | psig->cmaj_flt += | 1100 | psig->cmaj_flt += |
diff --git a/kernel/fork.c b/kernel/fork.c index c535f33bbb9c..4133876d8cd2 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -1233,6 +1233,12 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
1233 | #ifndef CONFIG_VIRT_CPU_ACCOUNTING | 1233 | #ifndef CONFIG_VIRT_CPU_ACCOUNTING |
1234 | p->prev_cputime.utime = p->prev_cputime.stime = 0; | 1234 | p->prev_cputime.utime = p->prev_cputime.stime = 0; |
1235 | #endif | 1235 | #endif |
1236 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN | ||
1237 | seqlock_init(&p->vtime_seqlock); | ||
1238 | p->vtime_snap = 0; | ||
1239 | p->vtime_snap_whence = VTIME_SLEEPING; | ||
1240 | #endif | ||
1241 | |||
1236 | #if defined(SPLIT_RSS_COUNTING) | 1242 | #if defined(SPLIT_RSS_COUNTING) |
1237 | memset(&p->rss_stat, 0, sizeof(p->rss_stat)); | 1243 | memset(&p->rss_stat, 0, sizeof(p->rss_stat)); |
1238 | #endif | 1244 | #endif |
diff --git a/kernel/futex.c b/kernel/futex.c index 19eb089ca003..9618b6e9fb36 100644 --- a/kernel/futex.c +++ b/kernel/futex.c | |||
@@ -60,6 +60,7 @@ | |||
60 | #include <linux/pid.h> | 60 | #include <linux/pid.h> |
61 | #include <linux/nsproxy.h> | 61 | #include <linux/nsproxy.h> |
62 | #include <linux/ptrace.h> | 62 | #include <linux/ptrace.h> |
63 | #include <linux/sched/rt.h> | ||
63 | 64 | ||
64 | #include <asm/futex.h> | 65 | #include <asm/futex.h> |
65 | 66 | ||
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index 6db7a5ed52b5..cc47812d3feb 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c | |||
@@ -44,6 +44,8 @@ | |||
44 | #include <linux/err.h> | 44 | #include <linux/err.h> |
45 | #include <linux/debugobjects.h> | 45 | #include <linux/debugobjects.h> |
46 | #include <linux/sched.h> | 46 | #include <linux/sched.h> |
47 | #include <linux/sched/sysctl.h> | ||
48 | #include <linux/sched/rt.h> | ||
47 | #include <linux/timer.h> | 49 | #include <linux/timer.h> |
48 | 50 | ||
49 | #include <asm/uaccess.h> | 51 | #include <asm/uaccess.h> |
@@ -640,21 +642,9 @@ static inline void hrtimer_init_hres(struct hrtimer_cpu_base *base) | |||
640 | * and expiry check is done in the hrtimer_interrupt or in the softirq. | 642 | * and expiry check is done in the hrtimer_interrupt or in the softirq. |
641 | */ | 643 | */ |
642 | static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer, | 644 | static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer, |
643 | struct hrtimer_clock_base *base, | 645 | struct hrtimer_clock_base *base) |
644 | int wakeup) | ||
645 | { | 646 | { |
646 | if (base->cpu_base->hres_active && hrtimer_reprogram(timer, base)) { | 647 | return base->cpu_base->hres_active && hrtimer_reprogram(timer, base); |
647 | if (wakeup) { | ||
648 | raw_spin_unlock(&base->cpu_base->lock); | ||
649 | raise_softirq_irqoff(HRTIMER_SOFTIRQ); | ||
650 | raw_spin_lock(&base->cpu_base->lock); | ||
651 | } else | ||
652 | __raise_softirq_irqoff(HRTIMER_SOFTIRQ); | ||
653 | |||
654 | return 1; | ||
655 | } | ||
656 | |||
657 | return 0; | ||
658 | } | 648 | } |
659 | 649 | ||
660 | static inline ktime_t hrtimer_update_base(struct hrtimer_cpu_base *base) | 650 | static inline ktime_t hrtimer_update_base(struct hrtimer_cpu_base *base) |
@@ -735,8 +725,7 @@ static inline int hrtimer_switch_to_hres(void) { return 0; } | |||
735 | static inline void | 725 | static inline void |
736 | hrtimer_force_reprogram(struct hrtimer_cpu_base *base, int skip_equal) { } | 726 | hrtimer_force_reprogram(struct hrtimer_cpu_base *base, int skip_equal) { } |
737 | static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer, | 727 | static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer, |
738 | struct hrtimer_clock_base *base, | 728 | struct hrtimer_clock_base *base) |
739 | int wakeup) | ||
740 | { | 729 | { |
741 | return 0; | 730 | return 0; |
742 | } | 731 | } |
@@ -995,8 +984,21 @@ int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, | |||
995 | * | 984 | * |
996 | * XXX send_remote_softirq() ? | 985 | * XXX send_remote_softirq() ? |
997 | */ | 986 | */ |
998 | if (leftmost && new_base->cpu_base == &__get_cpu_var(hrtimer_bases)) | 987 | if (leftmost && new_base->cpu_base == &__get_cpu_var(hrtimer_bases) |
999 | hrtimer_enqueue_reprogram(timer, new_base, wakeup); | 988 | && hrtimer_enqueue_reprogram(timer, new_base)) { |
989 | if (wakeup) { | ||
990 | /* | ||
991 | * We need to drop cpu_base->lock to avoid a | ||
992 | * lock ordering issue vs. rq->lock. | ||
993 | */ | ||
994 | raw_spin_unlock(&new_base->cpu_base->lock); | ||
995 | raise_softirq_irqoff(HRTIMER_SOFTIRQ); | ||
996 | local_irq_restore(flags); | ||
997 | return ret; | ||
998 | } else { | ||
999 | __raise_softirq_irqoff(HRTIMER_SOFTIRQ); | ||
1000 | } | ||
1001 | } | ||
1000 | 1002 | ||
1001 | unlock_hrtimer_base(timer, &flags); | 1003 | unlock_hrtimer_base(timer, &flags); |
1002 | 1004 | ||
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 3aca9f29d30e..cbd97ce0b000 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c | |||
@@ -90,27 +90,41 @@ int irq_set_handler_data(unsigned int irq, void *data) | |||
90 | EXPORT_SYMBOL(irq_set_handler_data); | 90 | EXPORT_SYMBOL(irq_set_handler_data); |
91 | 91 | ||
92 | /** | 92 | /** |
93 | * irq_set_msi_desc - set MSI descriptor data for an irq | 93 | * irq_set_msi_desc_off - set MSI descriptor data for an irq at offset |
94 | * @irq: Interrupt number | 94 | * @irq_base: Interrupt number base |
95 | * @entry: Pointer to MSI descriptor data | 95 | * @irq_offset: Interrupt number offset |
96 | * @entry: Pointer to MSI descriptor data | ||
96 | * | 97 | * |
97 | * Set the MSI descriptor entry for an irq | 98 | * Set the MSI descriptor entry for an irq at offset |
98 | */ | 99 | */ |
99 | int irq_set_msi_desc(unsigned int irq, struct msi_desc *entry) | 100 | int irq_set_msi_desc_off(unsigned int irq_base, unsigned int irq_offset, |
101 | struct msi_desc *entry) | ||
100 | { | 102 | { |
101 | unsigned long flags; | 103 | unsigned long flags; |
102 | struct irq_desc *desc = irq_get_desc_lock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL); | 104 | struct irq_desc *desc = irq_get_desc_lock(irq_base + irq_offset, &flags, IRQ_GET_DESC_CHECK_GLOBAL); |
103 | 105 | ||
104 | if (!desc) | 106 | if (!desc) |
105 | return -EINVAL; | 107 | return -EINVAL; |
106 | desc->irq_data.msi_desc = entry; | 108 | desc->irq_data.msi_desc = entry; |
107 | if (entry) | 109 | if (entry && !irq_offset) |
108 | entry->irq = irq; | 110 | entry->irq = irq_base; |
109 | irq_put_desc_unlock(desc, flags); | 111 | irq_put_desc_unlock(desc, flags); |
110 | return 0; | 112 | return 0; |
111 | } | 113 | } |
112 | 114 | ||
113 | /** | 115 | /** |
116 | * irq_set_msi_desc - set MSI descriptor data for an irq | ||
117 | * @irq: Interrupt number | ||
118 | * @entry: Pointer to MSI descriptor data | ||
119 | * | ||
120 | * Set the MSI descriptor entry for an irq | ||
121 | */ | ||
122 | int irq_set_msi_desc(unsigned int irq, struct msi_desc *entry) | ||
123 | { | ||
124 | return irq_set_msi_desc_off(irq, 0, entry); | ||
125 | } | ||
126 | |||
127 | /** | ||
114 | * irq_set_chip_data - set irq chip data for an irq | 128 | * irq_set_chip_data - set irq chip data for an irq |
115 | * @irq: Interrupt number | 129 | * @irq: Interrupt number |
116 | * @data: Pointer to chip specific data | 130 | * @data: Pointer to chip specific data |
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index e49a288fa479..fa17855ca65a 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/interrupt.h> | 16 | #include <linux/interrupt.h> |
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | #include <linux/sched.h> | 18 | #include <linux/sched.h> |
19 | #include <linux/sched/rt.h> | ||
19 | #include <linux/task_work.h> | 20 | #include <linux/task_work.h> |
20 | 21 | ||
21 | #include "internals.h" | 22 | #include "internals.h" |
@@ -1524,6 +1525,7 @@ void enable_percpu_irq(unsigned int irq, unsigned int type) | |||
1524 | out: | 1525 | out: |
1525 | irq_put_desc_unlock(desc, flags); | 1526 | irq_put_desc_unlock(desc, flags); |
1526 | } | 1527 | } |
1528 | EXPORT_SYMBOL_GPL(enable_percpu_irq); | ||
1527 | 1529 | ||
1528 | void disable_percpu_irq(unsigned int irq) | 1530 | void disable_percpu_irq(unsigned int irq) |
1529 | { | 1531 | { |
@@ -1537,6 +1539,7 @@ void disable_percpu_irq(unsigned int irq) | |||
1537 | irq_percpu_disable(desc, cpu); | 1539 | irq_percpu_disable(desc, cpu); |
1538 | irq_put_desc_unlock(desc, flags); | 1540 | irq_put_desc_unlock(desc, flags); |
1539 | } | 1541 | } |
1542 | EXPORT_SYMBOL_GPL(disable_percpu_irq); | ||
1540 | 1543 | ||
1541 | /* | 1544 | /* |
1542 | * Internal function to unregister a percpu irqaction. | 1545 | * Internal function to unregister a percpu irqaction. |
diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c index 611cd6003c45..7b5f012bde9d 100644 --- a/kernel/irq/spurious.c +++ b/kernel/irq/spurious.c | |||
@@ -80,13 +80,11 @@ static int try_one_irq(int irq, struct irq_desc *desc, bool force) | |||
80 | 80 | ||
81 | /* | 81 | /* |
82 | * All handlers must agree on IRQF_SHARED, so we test just the | 82 | * All handlers must agree on IRQF_SHARED, so we test just the |
83 | * first. Check for action->next as well. | 83 | * first. |
84 | */ | 84 | */ |
85 | action = desc->action; | 85 | action = desc->action; |
86 | if (!action || !(action->flags & IRQF_SHARED) || | 86 | if (!action || !(action->flags & IRQF_SHARED) || |
87 | (action->flags & __IRQF_TIMER) || | 87 | (action->flags & __IRQF_TIMER)) |
88 | (action->handler(irq, action->dev_id) == IRQ_HANDLED) || | ||
89 | !action->next) | ||
90 | goto out; | 88 | goto out; |
91 | 89 | ||
92 | /* Already running on another processor */ | 90 | /* Already running on another processor */ |
@@ -104,6 +102,7 @@ static int try_one_irq(int irq, struct irq_desc *desc, bool force) | |||
104 | do { | 102 | do { |
105 | if (handle_irq_event(desc) == IRQ_HANDLED) | 103 | if (handle_irq_event(desc) == IRQ_HANDLED) |
106 | ret = IRQ_HANDLED; | 104 | ret = IRQ_HANDLED; |
105 | /* Make sure that there is still a valid action */ | ||
107 | action = desc->action; | 106 | action = desc->action; |
108 | } while ((desc->istate & IRQS_PENDING) && action); | 107 | } while ((desc->istate & IRQS_PENDING) && action); |
109 | desc->istate &= ~IRQS_POLL_INPROGRESS; | 108 | desc->istate &= ~IRQS_POLL_INPROGRESS; |
diff --git a/kernel/irq_work.c b/kernel/irq_work.c index 1588e3b2871b..55fcce6065cf 100644 --- a/kernel/irq_work.c +++ b/kernel/irq_work.c | |||
@@ -12,37 +12,36 @@ | |||
12 | #include <linux/percpu.h> | 12 | #include <linux/percpu.h> |
13 | #include <linux/hardirq.h> | 13 | #include <linux/hardirq.h> |
14 | #include <linux/irqflags.h> | 14 | #include <linux/irqflags.h> |
15 | #include <linux/sched.h> | ||
16 | #include <linux/tick.h> | ||
17 | #include <linux/cpu.h> | ||
18 | #include <linux/notifier.h> | ||
15 | #include <asm/processor.h> | 19 | #include <asm/processor.h> |
16 | 20 | ||
17 | /* | ||
18 | * An entry can be in one of four states: | ||
19 | * | ||
20 | * free NULL, 0 -> {claimed} : free to be used | ||
21 | * claimed NULL, 3 -> {pending} : claimed to be enqueued | ||
22 | * pending next, 3 -> {busy} : queued, pending callback | ||
23 | * busy NULL, 2 -> {free, claimed} : callback in progress, can be claimed | ||
24 | */ | ||
25 | |||
26 | #define IRQ_WORK_PENDING 1UL | ||
27 | #define IRQ_WORK_BUSY 2UL | ||
28 | #define IRQ_WORK_FLAGS 3UL | ||
29 | 21 | ||
30 | static DEFINE_PER_CPU(struct llist_head, irq_work_list); | 22 | static DEFINE_PER_CPU(struct llist_head, irq_work_list); |
23 | static DEFINE_PER_CPU(int, irq_work_raised); | ||
31 | 24 | ||
32 | /* | 25 | /* |
33 | * Claim the entry so that no one else will poke at it. | 26 | * Claim the entry so that no one else will poke at it. |
34 | */ | 27 | */ |
35 | static bool irq_work_claim(struct irq_work *work) | 28 | static bool irq_work_claim(struct irq_work *work) |
36 | { | 29 | { |
37 | unsigned long flags, nflags; | 30 | unsigned long flags, oflags, nflags; |
38 | 31 | ||
32 | /* | ||
33 | * Start with our best wish as a premise but only trust any | ||
34 | * flag value after cmpxchg() result. | ||
35 | */ | ||
36 | flags = work->flags & ~IRQ_WORK_PENDING; | ||
39 | for (;;) { | 37 | for (;;) { |
40 | flags = work->flags; | ||
41 | if (flags & IRQ_WORK_PENDING) | ||
42 | return false; | ||
43 | nflags = flags | IRQ_WORK_FLAGS; | 38 | nflags = flags | IRQ_WORK_FLAGS; |
44 | if (cmpxchg(&work->flags, flags, nflags) == flags) | 39 | oflags = cmpxchg(&work->flags, flags, nflags); |
40 | if (oflags == flags) | ||
45 | break; | 41 | break; |
42 | if (oflags & IRQ_WORK_PENDING) | ||
43 | return false; | ||
44 | flags = oflags; | ||
46 | cpu_relax(); | 45 | cpu_relax(); |
47 | } | 46 | } |
48 | 47 | ||
@@ -57,57 +56,69 @@ void __weak arch_irq_work_raise(void) | |||
57 | } | 56 | } |
58 | 57 | ||
59 | /* | 58 | /* |
60 | * Queue the entry and raise the IPI if needed. | 59 | * Enqueue the irq_work @entry unless it's already pending |
60 | * somewhere. | ||
61 | * | ||
62 | * Can be re-enqueued while the callback is still in progress. | ||
61 | */ | 63 | */ |
62 | static void __irq_work_queue(struct irq_work *work) | 64 | void irq_work_queue(struct irq_work *work) |
63 | { | 65 | { |
64 | bool empty; | 66 | /* Only queue if not already pending */ |
67 | if (!irq_work_claim(work)) | ||
68 | return; | ||
65 | 69 | ||
70 | /* Queue the entry and raise the IPI if needed. */ | ||
66 | preempt_disable(); | 71 | preempt_disable(); |
67 | 72 | ||
68 | empty = llist_add(&work->llnode, &__get_cpu_var(irq_work_list)); | 73 | llist_add(&work->llnode, &__get_cpu_var(irq_work_list)); |
69 | /* The list was empty, raise self-interrupt to start processing. */ | 74 | |
70 | if (empty) | 75 | /* |
71 | arch_irq_work_raise(); | 76 | * If the work is not "lazy" or the tick is stopped, raise the irq |
77 | * work interrupt (if supported by the arch), otherwise, just wait | ||
78 | * for the next tick. | ||
79 | */ | ||
80 | if (!(work->flags & IRQ_WORK_LAZY) || tick_nohz_tick_stopped()) { | ||
81 | if (!this_cpu_cmpxchg(irq_work_raised, 0, 1)) | ||
82 | arch_irq_work_raise(); | ||
83 | } | ||
72 | 84 | ||
73 | preempt_enable(); | 85 | preempt_enable(); |
74 | } | 86 | } |
87 | EXPORT_SYMBOL_GPL(irq_work_queue); | ||
75 | 88 | ||
76 | /* | 89 | bool irq_work_needs_cpu(void) |
77 | * Enqueue the irq_work @entry, returns true on success, failure when the | ||
78 | * @entry was already enqueued by someone else. | ||
79 | * | ||
80 | * Can be re-enqueued while the callback is still in progress. | ||
81 | */ | ||
82 | bool irq_work_queue(struct irq_work *work) | ||
83 | { | 90 | { |
84 | if (!irq_work_claim(work)) { | 91 | struct llist_head *this_list; |
85 | /* | 92 | |
86 | * Already enqueued, can't do! | 93 | this_list = &__get_cpu_var(irq_work_list); |
87 | */ | 94 | if (llist_empty(this_list)) |
88 | return false; | 95 | return false; |
89 | } | ||
90 | 96 | ||
91 | __irq_work_queue(work); | 97 | /* All work should have been flushed before going offline */ |
98 | WARN_ON_ONCE(cpu_is_offline(smp_processor_id())); | ||
99 | |||
92 | return true; | 100 | return true; |
93 | } | 101 | } |
94 | EXPORT_SYMBOL_GPL(irq_work_queue); | ||
95 | 102 | ||
96 | /* | 103 | static void __irq_work_run(void) |
97 | * Run the irq_work entries on this cpu. Requires to be ran from hardirq | ||
98 | * context with local IRQs disabled. | ||
99 | */ | ||
100 | void irq_work_run(void) | ||
101 | { | 104 | { |
105 | unsigned long flags; | ||
102 | struct irq_work *work; | 106 | struct irq_work *work; |
103 | struct llist_head *this_list; | 107 | struct llist_head *this_list; |
104 | struct llist_node *llnode; | 108 | struct llist_node *llnode; |
105 | 109 | ||
110 | |||
111 | /* | ||
112 | * Reset the "raised" state right before we check the list because | ||
113 | * an NMI may enqueue after we find the list empty from the runner. | ||
114 | */ | ||
115 | __this_cpu_write(irq_work_raised, 0); | ||
116 | barrier(); | ||
117 | |||
106 | this_list = &__get_cpu_var(irq_work_list); | 118 | this_list = &__get_cpu_var(irq_work_list); |
107 | if (llist_empty(this_list)) | 119 | if (llist_empty(this_list)) |
108 | return; | 120 | return; |
109 | 121 | ||
110 | BUG_ON(!in_irq()); | ||
111 | BUG_ON(!irqs_disabled()); | 122 | BUG_ON(!irqs_disabled()); |
112 | 123 | ||
113 | llnode = llist_del_all(this_list); | 124 | llnode = llist_del_all(this_list); |
@@ -119,16 +130,31 @@ void irq_work_run(void) | |||
119 | /* | 130 | /* |
120 | * Clear the PENDING bit, after this point the @work | 131 | * Clear the PENDING bit, after this point the @work |
121 | * can be re-used. | 132 | * can be re-used. |
133 | * Make it immediately visible so that other CPUs trying | ||
134 | * to claim that work don't rely on us to handle their data | ||
135 | * while we are in the middle of the func. | ||
122 | */ | 136 | */ |
123 | work->flags = IRQ_WORK_BUSY; | 137 | flags = work->flags & ~IRQ_WORK_PENDING; |
138 | xchg(&work->flags, flags); | ||
139 | |||
124 | work->func(work); | 140 | work->func(work); |
125 | /* | 141 | /* |
126 | * Clear the BUSY bit and return to the free state if | 142 | * Clear the BUSY bit and return to the free state if |
127 | * no-one else claimed it meanwhile. | 143 | * no-one else claimed it meanwhile. |
128 | */ | 144 | */ |
129 | (void)cmpxchg(&work->flags, IRQ_WORK_BUSY, 0); | 145 | (void)cmpxchg(&work->flags, flags, flags & ~IRQ_WORK_BUSY); |
130 | } | 146 | } |
131 | } | 147 | } |
148 | |||
149 | /* | ||
150 | * Run the irq_work entries on this cpu. Requires to be ran from hardirq | ||
151 | * context with local IRQs disabled. | ||
152 | */ | ||
153 | void irq_work_run(void) | ||
154 | { | ||
155 | BUG_ON(!in_irq()); | ||
156 | __irq_work_run(); | ||
157 | } | ||
132 | EXPORT_SYMBOL_GPL(irq_work_run); | 158 | EXPORT_SYMBOL_GPL(irq_work_run); |
133 | 159 | ||
134 | /* | 160 | /* |
@@ -143,3 +169,35 @@ void irq_work_sync(struct irq_work *work) | |||
143 | cpu_relax(); | 169 | cpu_relax(); |
144 | } | 170 | } |
145 | EXPORT_SYMBOL_GPL(irq_work_sync); | 171 | EXPORT_SYMBOL_GPL(irq_work_sync); |
172 | |||
173 | #ifdef CONFIG_HOTPLUG_CPU | ||
174 | static int irq_work_cpu_notify(struct notifier_block *self, | ||
175 | unsigned long action, void *hcpu) | ||
176 | { | ||
177 | long cpu = (long)hcpu; | ||
178 | |||
179 | switch (action) { | ||
180 | case CPU_DYING: | ||
181 | /* Called from stop_machine */ | ||
182 | if (WARN_ON_ONCE(cpu != smp_processor_id())) | ||
183 | break; | ||
184 | __irq_work_run(); | ||
185 | break; | ||
186 | default: | ||
187 | break; | ||
188 | } | ||
189 | return NOTIFY_OK; | ||
190 | } | ||
191 | |||
192 | static struct notifier_block cpu_notify; | ||
193 | |||
194 | static __init int irq_work_init_cpu_notifier(void) | ||
195 | { | ||
196 | cpu_notify.notifier_call = irq_work_cpu_notify; | ||
197 | cpu_notify.priority = 0; | ||
198 | register_cpu_notifier(&cpu_notify); | ||
199 | return 0; | ||
200 | } | ||
201 | device_initcall(irq_work_init_cpu_notifier); | ||
202 | |||
203 | #endif /* CONFIG_HOTPLUG_CPU */ | ||
diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 098f396aa409..f423c3ef4a82 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c | |||
@@ -919,7 +919,7 @@ static __kprobes struct kprobe *alloc_aggr_kprobe(struct kprobe *p) | |||
919 | } | 919 | } |
920 | #endif /* CONFIG_OPTPROBES */ | 920 | #endif /* CONFIG_OPTPROBES */ |
921 | 921 | ||
922 | #ifdef KPROBES_CAN_USE_FTRACE | 922 | #ifdef CONFIG_KPROBES_ON_FTRACE |
923 | static struct ftrace_ops kprobe_ftrace_ops __read_mostly = { | 923 | static struct ftrace_ops kprobe_ftrace_ops __read_mostly = { |
924 | .func = kprobe_ftrace_handler, | 924 | .func = kprobe_ftrace_handler, |
925 | .flags = FTRACE_OPS_FL_SAVE_REGS, | 925 | .flags = FTRACE_OPS_FL_SAVE_REGS, |
@@ -964,7 +964,7 @@ static void __kprobes disarm_kprobe_ftrace(struct kprobe *p) | |||
964 | (unsigned long)p->addr, 1, 0); | 964 | (unsigned long)p->addr, 1, 0); |
965 | WARN(ret < 0, "Failed to disarm kprobe-ftrace at %p (%d)\n", p->addr, ret); | 965 | WARN(ret < 0, "Failed to disarm kprobe-ftrace at %p (%d)\n", p->addr, ret); |
966 | } | 966 | } |
967 | #else /* !KPROBES_CAN_USE_FTRACE */ | 967 | #else /* !CONFIG_KPROBES_ON_FTRACE */ |
968 | #define prepare_kprobe(p) arch_prepare_kprobe(p) | 968 | #define prepare_kprobe(p) arch_prepare_kprobe(p) |
969 | #define arm_kprobe_ftrace(p) do {} while (0) | 969 | #define arm_kprobe_ftrace(p) do {} while (0) |
970 | #define disarm_kprobe_ftrace(p) do {} while (0) | 970 | #define disarm_kprobe_ftrace(p) do {} while (0) |
@@ -1414,12 +1414,12 @@ static __kprobes int check_kprobe_address_safe(struct kprobe *p, | |||
1414 | */ | 1414 | */ |
1415 | ftrace_addr = ftrace_location((unsigned long)p->addr); | 1415 | ftrace_addr = ftrace_location((unsigned long)p->addr); |
1416 | if (ftrace_addr) { | 1416 | if (ftrace_addr) { |
1417 | #ifdef KPROBES_CAN_USE_FTRACE | 1417 | #ifdef CONFIG_KPROBES_ON_FTRACE |
1418 | /* Given address is not on the instruction boundary */ | 1418 | /* Given address is not on the instruction boundary */ |
1419 | if ((unsigned long)p->addr != ftrace_addr) | 1419 | if ((unsigned long)p->addr != ftrace_addr) |
1420 | return -EILSEQ; | 1420 | return -EILSEQ; |
1421 | p->flags |= KPROBE_FLAG_FTRACE; | 1421 | p->flags |= KPROBE_FLAG_FTRACE; |
1422 | #else /* !KPROBES_CAN_USE_FTRACE */ | 1422 | #else /* !CONFIG_KPROBES_ON_FTRACE */ |
1423 | return -EINVAL; | 1423 | return -EINVAL; |
1424 | #endif | 1424 | #endif |
1425 | } | 1425 | } |
diff --git a/kernel/mutex.c b/kernel/mutex.c index a307cc9c9526..52f23011b6e0 100644 --- a/kernel/mutex.c +++ b/kernel/mutex.c | |||
@@ -19,6 +19,7 @@ | |||
19 | */ | 19 | */ |
20 | #include <linux/mutex.h> | 20 | #include <linux/mutex.h> |
21 | #include <linux/sched.h> | 21 | #include <linux/sched.h> |
22 | #include <linux/sched/rt.h> | ||
22 | #include <linux/export.h> | 23 | #include <linux/export.h> |
23 | #include <linux/spinlock.h> | 24 | #include <linux/spinlock.h> |
24 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
diff --git a/kernel/pid.c b/kernel/pid.c index de9af600006f..f2c6a6825098 100644 --- a/kernel/pid.c +++ b/kernel/pid.c | |||
@@ -331,7 +331,7 @@ out: | |||
331 | return pid; | 331 | return pid; |
332 | 332 | ||
333 | out_unlock: | 333 | out_unlock: |
334 | spin_unlock(&pidmap_lock); | 334 | spin_unlock_irq(&pidmap_lock); |
335 | out_free: | 335 | out_free: |
336 | while (++i <= ns->level) | 336 | while (++i <= ns->level) |
337 | free_pidmap(pid->numbers + i); | 337 | free_pidmap(pid->numbers + i); |
diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c index a278cad1d5d6..8fd709c9bb58 100644 --- a/kernel/posix-cpu-timers.c +++ b/kernel/posix-cpu-timers.c | |||
@@ -155,11 +155,19 @@ static void bump_cpu_timer(struct k_itimer *timer, | |||
155 | 155 | ||
156 | static inline cputime_t prof_ticks(struct task_struct *p) | 156 | static inline cputime_t prof_ticks(struct task_struct *p) |
157 | { | 157 | { |
158 | return p->utime + p->stime; | 158 | cputime_t utime, stime; |
159 | |||
160 | task_cputime(p, &utime, &stime); | ||
161 | |||
162 | return utime + stime; | ||
159 | } | 163 | } |
160 | static inline cputime_t virt_ticks(struct task_struct *p) | 164 | static inline cputime_t virt_ticks(struct task_struct *p) |
161 | { | 165 | { |
162 | return p->utime; | 166 | cputime_t utime; |
167 | |||
168 | task_cputime(p, &utime, NULL); | ||
169 | |||
170 | return utime; | ||
163 | } | 171 | } |
164 | 172 | ||
165 | static int | 173 | static int |
@@ -471,18 +479,23 @@ static void cleanup_timers(struct list_head *head, | |||
471 | */ | 479 | */ |
472 | void posix_cpu_timers_exit(struct task_struct *tsk) | 480 | void posix_cpu_timers_exit(struct task_struct *tsk) |
473 | { | 481 | { |
482 | cputime_t utime, stime; | ||
483 | |||
474 | add_device_randomness((const void*) &tsk->se.sum_exec_runtime, | 484 | add_device_randomness((const void*) &tsk->se.sum_exec_runtime, |
475 | sizeof(unsigned long long)); | 485 | sizeof(unsigned long long)); |
486 | task_cputime(tsk, &utime, &stime); | ||
476 | cleanup_timers(tsk->cpu_timers, | 487 | cleanup_timers(tsk->cpu_timers, |
477 | tsk->utime, tsk->stime, tsk->se.sum_exec_runtime); | 488 | utime, stime, tsk->se.sum_exec_runtime); |
478 | 489 | ||
479 | } | 490 | } |
480 | void posix_cpu_timers_exit_group(struct task_struct *tsk) | 491 | void posix_cpu_timers_exit_group(struct task_struct *tsk) |
481 | { | 492 | { |
482 | struct signal_struct *const sig = tsk->signal; | 493 | struct signal_struct *const sig = tsk->signal; |
494 | cputime_t utime, stime; | ||
483 | 495 | ||
496 | task_cputime(tsk, &utime, &stime); | ||
484 | cleanup_timers(tsk->signal->cpu_timers, | 497 | cleanup_timers(tsk->signal->cpu_timers, |
485 | tsk->utime + sig->utime, tsk->stime + sig->stime, | 498 | utime + sig->utime, stime + sig->stime, |
486 | tsk->se.sum_exec_runtime + sig->sum_sched_runtime); | 499 | tsk->se.sum_exec_runtime + sig->sum_sched_runtime); |
487 | } | 500 | } |
488 | 501 | ||
@@ -1226,11 +1239,14 @@ static inline int task_cputime_expired(const struct task_cputime *sample, | |||
1226 | static inline int fastpath_timer_check(struct task_struct *tsk) | 1239 | static inline int fastpath_timer_check(struct task_struct *tsk) |
1227 | { | 1240 | { |
1228 | struct signal_struct *sig; | 1241 | struct signal_struct *sig; |
1242 | cputime_t utime, stime; | ||
1243 | |||
1244 | task_cputime(tsk, &utime, &stime); | ||
1229 | 1245 | ||
1230 | if (!task_cputime_zero(&tsk->cputime_expires)) { | 1246 | if (!task_cputime_zero(&tsk->cputime_expires)) { |
1231 | struct task_cputime task_sample = { | 1247 | struct task_cputime task_sample = { |
1232 | .utime = tsk->utime, | 1248 | .utime = utime, |
1233 | .stime = tsk->stime, | 1249 | .stime = stime, |
1234 | .sum_exec_runtime = tsk->se.sum_exec_runtime | 1250 | .sum_exec_runtime = tsk->se.sum_exec_runtime |
1235 | }; | 1251 | }; |
1236 | 1252 | ||
@@ -1401,8 +1417,10 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags, | |||
1401 | while (!signal_pending(current)) { | 1417 | while (!signal_pending(current)) { |
1402 | if (timer.it.cpu.expires.sched == 0) { | 1418 | if (timer.it.cpu.expires.sched == 0) { |
1403 | /* | 1419 | /* |
1404 | * Our timer fired and was reset. | 1420 | * Our timer fired and was reset, below |
1421 | * deletion can not fail. | ||
1405 | */ | 1422 | */ |
1423 | posix_cpu_timer_del(&timer); | ||
1406 | spin_unlock_irq(&timer.it_lock); | 1424 | spin_unlock_irq(&timer.it_lock); |
1407 | return 0; | 1425 | return 0; |
1408 | } | 1426 | } |
@@ -1420,9 +1438,26 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags, | |||
1420 | * We were interrupted by a signal. | 1438 | * We were interrupted by a signal. |
1421 | */ | 1439 | */ |
1422 | sample_to_timespec(which_clock, timer.it.cpu.expires, rqtp); | 1440 | sample_to_timespec(which_clock, timer.it.cpu.expires, rqtp); |
1423 | posix_cpu_timer_set(&timer, 0, &zero_it, it); | 1441 | error = posix_cpu_timer_set(&timer, 0, &zero_it, it); |
1442 | if (!error) { | ||
1443 | /* | ||
1444 | * Timer is now unarmed, deletion can not fail. | ||
1445 | */ | ||
1446 | posix_cpu_timer_del(&timer); | ||
1447 | } | ||
1424 | spin_unlock_irq(&timer.it_lock); | 1448 | spin_unlock_irq(&timer.it_lock); |
1425 | 1449 | ||
1450 | while (error == TIMER_RETRY) { | ||
1451 | /* | ||
1452 | * We need to handle case when timer was or is in the | ||
1453 | * middle of firing. In other cases we already freed | ||
1454 | * resources. | ||
1455 | */ | ||
1456 | spin_lock_irq(&timer.it_lock); | ||
1457 | error = posix_cpu_timer_del(&timer); | ||
1458 | spin_unlock_irq(&timer.it_lock); | ||
1459 | } | ||
1460 | |||
1426 | if ((it->it_value.tv_sec | it->it_value.tv_nsec) == 0) { | 1461 | if ((it->it_value.tv_sec | it->it_value.tv_nsec) == 0) { |
1427 | /* | 1462 | /* |
1428 | * It actually did fire already. | 1463 | * It actually did fire already. |
diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c index 69185ae6b701..10349d5f2ec3 100644 --- a/kernel/posix-timers.c +++ b/kernel/posix-timers.c | |||
@@ -997,7 +997,7 @@ SYSCALL_DEFINE2(clock_adjtime, const clockid_t, which_clock, | |||
997 | 997 | ||
998 | err = kc->clock_adj(which_clock, &ktx); | 998 | err = kc->clock_adj(which_clock, &ktx); |
999 | 999 | ||
1000 | if (!err && copy_to_user(utx, &ktx, sizeof(ktx))) | 1000 | if (err >= 0 && copy_to_user(utx, &ktx, sizeof(ktx))) |
1001 | return -EFAULT; | 1001 | return -EFAULT; |
1002 | 1002 | ||
1003 | return err; | 1003 | return err; |
diff --git a/kernel/printk.c b/kernel/printk.c index 267ce780abe8..f24633afa46a 100644 --- a/kernel/printk.c +++ b/kernel/printk.c | |||
@@ -42,6 +42,7 @@ | |||
42 | #include <linux/notifier.h> | 42 | #include <linux/notifier.h> |
43 | #include <linux/rculist.h> | 43 | #include <linux/rculist.h> |
44 | #include <linux/poll.h> | 44 | #include <linux/poll.h> |
45 | #include <linux/irq_work.h> | ||
45 | 46 | ||
46 | #include <asm/uaccess.h> | 47 | #include <asm/uaccess.h> |
47 | 48 | ||
@@ -1959,30 +1960,32 @@ int is_console_locked(void) | |||
1959 | static DEFINE_PER_CPU(int, printk_pending); | 1960 | static DEFINE_PER_CPU(int, printk_pending); |
1960 | static DEFINE_PER_CPU(char [PRINTK_BUF_SIZE], printk_sched_buf); | 1961 | static DEFINE_PER_CPU(char [PRINTK_BUF_SIZE], printk_sched_buf); |
1961 | 1962 | ||
1962 | void printk_tick(void) | 1963 | static void wake_up_klogd_work_func(struct irq_work *irq_work) |
1963 | { | 1964 | { |
1964 | if (__this_cpu_read(printk_pending)) { | 1965 | int pending = __this_cpu_xchg(printk_pending, 0); |
1965 | int pending = __this_cpu_xchg(printk_pending, 0); | 1966 | |
1966 | if (pending & PRINTK_PENDING_SCHED) { | 1967 | if (pending & PRINTK_PENDING_SCHED) { |
1967 | char *buf = __get_cpu_var(printk_sched_buf); | 1968 | char *buf = __get_cpu_var(printk_sched_buf); |
1968 | printk(KERN_WARNING "[sched_delayed] %s", buf); | 1969 | printk(KERN_WARNING "[sched_delayed] %s", buf); |
1969 | } | ||
1970 | if (pending & PRINTK_PENDING_WAKEUP) | ||
1971 | wake_up_interruptible(&log_wait); | ||
1972 | } | 1970 | } |
1973 | } | ||
1974 | 1971 | ||
1975 | int printk_needs_cpu(int cpu) | 1972 | if (pending & PRINTK_PENDING_WAKEUP) |
1976 | { | 1973 | wake_up_interruptible(&log_wait); |
1977 | if (cpu_is_offline(cpu)) | ||
1978 | printk_tick(); | ||
1979 | return __this_cpu_read(printk_pending); | ||
1980 | } | 1974 | } |
1981 | 1975 | ||
1976 | static DEFINE_PER_CPU(struct irq_work, wake_up_klogd_work) = { | ||
1977 | .func = wake_up_klogd_work_func, | ||
1978 | .flags = IRQ_WORK_LAZY, | ||
1979 | }; | ||
1980 | |||
1982 | void wake_up_klogd(void) | 1981 | void wake_up_klogd(void) |
1983 | { | 1982 | { |
1984 | if (waitqueue_active(&log_wait)) | 1983 | preempt_disable(); |
1984 | if (waitqueue_active(&log_wait)) { | ||
1985 | this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP); | 1985 | this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP); |
1986 | irq_work_queue(&__get_cpu_var(wake_up_klogd_work)); | ||
1987 | } | ||
1988 | preempt_enable(); | ||
1986 | } | 1989 | } |
1987 | 1990 | ||
1988 | static void console_cont_flush(char *text, size_t size) | 1991 | static void console_cont_flush(char *text, size_t size) |
@@ -2462,6 +2465,7 @@ int printk_sched(const char *fmt, ...) | |||
2462 | va_end(args); | 2465 | va_end(args); |
2463 | 2466 | ||
2464 | __this_cpu_or(printk_pending, PRINTK_PENDING_SCHED); | 2467 | __this_cpu_or(printk_pending, PRINTK_PENDING_SCHED); |
2468 | irq_work_queue(&__get_cpu_var(wake_up_klogd_work)); | ||
2465 | local_irq_restore(flags); | 2469 | local_irq_restore(flags); |
2466 | 2470 | ||
2467 | return r; | 2471 | return r; |
diff --git a/kernel/profile.c b/kernel/profile.c index 1f391819c42f..dc3384ee874e 100644 --- a/kernel/profile.c +++ b/kernel/profile.c | |||
@@ -37,9 +37,6 @@ struct profile_hit { | |||
37 | #define NR_PROFILE_HIT (PAGE_SIZE/sizeof(struct profile_hit)) | 37 | #define NR_PROFILE_HIT (PAGE_SIZE/sizeof(struct profile_hit)) |
38 | #define NR_PROFILE_GRP (NR_PROFILE_HIT/PROFILE_GRPSZ) | 38 | #define NR_PROFILE_GRP (NR_PROFILE_HIT/PROFILE_GRPSZ) |
39 | 39 | ||
40 | /* Oprofile timer tick hook */ | ||
41 | static int (*timer_hook)(struct pt_regs *) __read_mostly; | ||
42 | |||
43 | static atomic_t *prof_buffer; | 40 | static atomic_t *prof_buffer; |
44 | static unsigned long prof_len, prof_shift; | 41 | static unsigned long prof_len, prof_shift; |
45 | 42 | ||
@@ -208,25 +205,6 @@ int profile_event_unregister(enum profile_type type, struct notifier_block *n) | |||
208 | } | 205 | } |
209 | EXPORT_SYMBOL_GPL(profile_event_unregister); | 206 | EXPORT_SYMBOL_GPL(profile_event_unregister); |
210 | 207 | ||
211 | int register_timer_hook(int (*hook)(struct pt_regs *)) | ||
212 | { | ||
213 | if (timer_hook) | ||
214 | return -EBUSY; | ||
215 | timer_hook = hook; | ||
216 | return 0; | ||
217 | } | ||
218 | EXPORT_SYMBOL_GPL(register_timer_hook); | ||
219 | |||
220 | void unregister_timer_hook(int (*hook)(struct pt_regs *)) | ||
221 | { | ||
222 | WARN_ON(hook != timer_hook); | ||
223 | timer_hook = NULL; | ||
224 | /* make sure all CPUs see the NULL hook */ | ||
225 | synchronize_sched(); /* Allow ongoing interrupts to complete. */ | ||
226 | } | ||
227 | EXPORT_SYMBOL_GPL(unregister_timer_hook); | ||
228 | |||
229 | |||
230 | #ifdef CONFIG_SMP | 208 | #ifdef CONFIG_SMP |
231 | /* | 209 | /* |
232 | * Each cpu has a pair of open-addressed hashtables for pending | 210 | * Each cpu has a pair of open-addressed hashtables for pending |
@@ -436,8 +414,6 @@ void profile_tick(int type) | |||
436 | { | 414 | { |
437 | struct pt_regs *regs = get_irq_regs(); | 415 | struct pt_regs *regs = get_irq_regs(); |
438 | 416 | ||
439 | if (type == CPU_PROFILING && timer_hook) | ||
440 | timer_hook(regs); | ||
441 | if (!user_mode(regs) && prof_cpu_mask != NULL && | 417 | if (!user_mode(regs) && prof_cpu_mask != NULL && |
442 | cpumask_test_cpu(smp_processor_id(), prof_cpu_mask)) | 418 | cpumask_test_cpu(smp_processor_id(), prof_cpu_mask)) |
443 | profile_hit(type, (void *)profile_pc(regs)); | 419 | profile_hit(type, (void *)profile_pc(regs)); |
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 6cbeaae4406d..acbd28424d81 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c | |||
@@ -712,6 +712,12 @@ static int ptrace_regset(struct task_struct *task, int req, unsigned int type, | |||
712 | kiov->iov_len, kiov->iov_base); | 712 | kiov->iov_len, kiov->iov_base); |
713 | } | 713 | } |
714 | 714 | ||
715 | /* | ||
716 | * This is declared in linux/regset.h and defined in machine-dependent | ||
717 | * code. We put the export here, near the primary machine-neutral use, | ||
718 | * to ensure no machine forgets it. | ||
719 | */ | ||
720 | EXPORT_SYMBOL_GPL(task_user_regset_view); | ||
715 | #endif | 721 | #endif |
716 | 722 | ||
717 | int ptrace_request(struct task_struct *child, long request, | 723 | int ptrace_request(struct task_struct *child, long request, |
diff --git a/kernel/rcu.h b/kernel/rcu.h index 20dfba576c2b..7f8e7590e3e5 100644 --- a/kernel/rcu.h +++ b/kernel/rcu.h | |||
@@ -111,4 +111,11 @@ static inline bool __rcu_reclaim(char *rn, struct rcu_head *head) | |||
111 | 111 | ||
112 | extern int rcu_expedited; | 112 | extern int rcu_expedited; |
113 | 113 | ||
114 | #ifdef CONFIG_RCU_STALL_COMMON | ||
115 | |||
116 | extern int rcu_cpu_stall_suppress; | ||
117 | int rcu_jiffies_till_stall_check(void); | ||
118 | |||
119 | #endif /* #ifdef CONFIG_RCU_STALL_COMMON */ | ||
120 | |||
114 | #endif /* __LINUX_RCU_H */ | 121 | #endif /* __LINUX_RCU_H */ |
diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c index a2cf76177b44..48ab70384a4c 100644 --- a/kernel/rcupdate.c +++ b/kernel/rcupdate.c | |||
@@ -404,11 +404,65 @@ EXPORT_SYMBOL_GPL(rcuhead_debug_descr); | |||
404 | #endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */ | 404 | #endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */ |
405 | 405 | ||
406 | #if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU) || defined(CONFIG_RCU_TRACE) | 406 | #if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU) || defined(CONFIG_RCU_TRACE) |
407 | void do_trace_rcu_torture_read(char *rcutorturename, struct rcu_head *rhp) | 407 | void do_trace_rcu_torture_read(char *rcutorturename, struct rcu_head *rhp, |
408 | unsigned long secs, | ||
409 | unsigned long c_old, unsigned long c) | ||
408 | { | 410 | { |
409 | trace_rcu_torture_read(rcutorturename, rhp); | 411 | trace_rcu_torture_read(rcutorturename, rhp, secs, c_old, c); |
410 | } | 412 | } |
411 | EXPORT_SYMBOL_GPL(do_trace_rcu_torture_read); | 413 | EXPORT_SYMBOL_GPL(do_trace_rcu_torture_read); |
412 | #else | 414 | #else |
413 | #define do_trace_rcu_torture_read(rcutorturename, rhp) do { } while (0) | 415 | #define do_trace_rcu_torture_read(rcutorturename, rhp, secs, c_old, c) \ |
416 | do { } while (0) | ||
414 | #endif | 417 | #endif |
418 | |||
419 | #ifdef CONFIG_RCU_STALL_COMMON | ||
420 | |||
421 | #ifdef CONFIG_PROVE_RCU | ||
422 | #define RCU_STALL_DELAY_DELTA (5 * HZ) | ||
423 | #else | ||
424 | #define RCU_STALL_DELAY_DELTA 0 | ||
425 | #endif | ||
426 | |||
427 | int rcu_cpu_stall_suppress __read_mostly; /* 1 = suppress stall warnings. */ | ||
428 | int rcu_cpu_stall_timeout __read_mostly = CONFIG_RCU_CPU_STALL_TIMEOUT; | ||
429 | |||
430 | module_param(rcu_cpu_stall_suppress, int, 0644); | ||
431 | module_param(rcu_cpu_stall_timeout, int, 0644); | ||
432 | |||
433 | int rcu_jiffies_till_stall_check(void) | ||
434 | { | ||
435 | int till_stall_check = ACCESS_ONCE(rcu_cpu_stall_timeout); | ||
436 | |||
437 | /* | ||
438 | * Limit check must be consistent with the Kconfig limits | ||
439 | * for CONFIG_RCU_CPU_STALL_TIMEOUT. | ||
440 | */ | ||
441 | if (till_stall_check < 3) { | ||
442 | ACCESS_ONCE(rcu_cpu_stall_timeout) = 3; | ||
443 | till_stall_check = 3; | ||
444 | } else if (till_stall_check > 300) { | ||
445 | ACCESS_ONCE(rcu_cpu_stall_timeout) = 300; | ||
446 | till_stall_check = 300; | ||
447 | } | ||
448 | return till_stall_check * HZ + RCU_STALL_DELAY_DELTA; | ||
449 | } | ||
450 | |||
451 | static int rcu_panic(struct notifier_block *this, unsigned long ev, void *ptr) | ||
452 | { | ||
453 | rcu_cpu_stall_suppress = 1; | ||
454 | return NOTIFY_DONE; | ||
455 | } | ||
456 | |||
457 | static struct notifier_block rcu_panic_block = { | ||
458 | .notifier_call = rcu_panic, | ||
459 | }; | ||
460 | |||
461 | static int __init check_cpu_stall_init(void) | ||
462 | { | ||
463 | atomic_notifier_chain_register(&panic_notifier_list, &rcu_panic_block); | ||
464 | return 0; | ||
465 | } | ||
466 | early_initcall(check_cpu_stall_init); | ||
467 | |||
468 | #endif /* #ifdef CONFIG_RCU_STALL_COMMON */ | ||
diff --git a/kernel/rcutiny.c b/kernel/rcutiny.c index e7dce58f9c2a..a0714a51b6d7 100644 --- a/kernel/rcutiny.c +++ b/kernel/rcutiny.c | |||
@@ -51,10 +51,10 @@ static void __call_rcu(struct rcu_head *head, | |||
51 | void (*func)(struct rcu_head *rcu), | 51 | void (*func)(struct rcu_head *rcu), |
52 | struct rcu_ctrlblk *rcp); | 52 | struct rcu_ctrlblk *rcp); |
53 | 53 | ||
54 | #include "rcutiny_plugin.h" | ||
55 | |||
56 | static long long rcu_dynticks_nesting = DYNTICK_TASK_EXIT_IDLE; | 54 | static long long rcu_dynticks_nesting = DYNTICK_TASK_EXIT_IDLE; |
57 | 55 | ||
56 | #include "rcutiny_plugin.h" | ||
57 | |||
58 | /* Common code for rcu_idle_enter() and rcu_irq_exit(), see kernel/rcutree.c. */ | 58 | /* Common code for rcu_idle_enter() and rcu_irq_exit(), see kernel/rcutree.c. */ |
59 | static void rcu_idle_enter_common(long long newval) | 59 | static void rcu_idle_enter_common(long long newval) |
60 | { | 60 | { |
@@ -193,7 +193,7 @@ EXPORT_SYMBOL(rcu_is_cpu_idle); | |||
193 | * interrupts don't count, we must be running at the first interrupt | 193 | * interrupts don't count, we must be running at the first interrupt |
194 | * level. | 194 | * level. |
195 | */ | 195 | */ |
196 | int rcu_is_cpu_rrupt_from_idle(void) | 196 | static int rcu_is_cpu_rrupt_from_idle(void) |
197 | { | 197 | { |
198 | return rcu_dynticks_nesting <= 1; | 198 | return rcu_dynticks_nesting <= 1; |
199 | } | 199 | } |
@@ -205,6 +205,7 @@ int rcu_is_cpu_rrupt_from_idle(void) | |||
205 | */ | 205 | */ |
206 | static int rcu_qsctr_help(struct rcu_ctrlblk *rcp) | 206 | static int rcu_qsctr_help(struct rcu_ctrlblk *rcp) |
207 | { | 207 | { |
208 | reset_cpu_stall_ticks(rcp); | ||
208 | if (rcp->rcucblist != NULL && | 209 | if (rcp->rcucblist != NULL && |
209 | rcp->donetail != rcp->curtail) { | 210 | rcp->donetail != rcp->curtail) { |
210 | rcp->donetail = rcp->curtail; | 211 | rcp->donetail = rcp->curtail; |
@@ -251,6 +252,7 @@ void rcu_bh_qs(int cpu) | |||
251 | */ | 252 | */ |
252 | void rcu_check_callbacks(int cpu, int user) | 253 | void rcu_check_callbacks(int cpu, int user) |
253 | { | 254 | { |
255 | check_cpu_stalls(); | ||
254 | if (user || rcu_is_cpu_rrupt_from_idle()) | 256 | if (user || rcu_is_cpu_rrupt_from_idle()) |
255 | rcu_sched_qs(cpu); | 257 | rcu_sched_qs(cpu); |
256 | else if (!in_softirq()) | 258 | else if (!in_softirq()) |
diff --git a/kernel/rcutiny_plugin.h b/kernel/rcutiny_plugin.h index f85016a2309b..8a233002faeb 100644 --- a/kernel/rcutiny_plugin.h +++ b/kernel/rcutiny_plugin.h | |||
@@ -33,6 +33,9 @@ struct rcu_ctrlblk { | |||
33 | struct rcu_head **donetail; /* ->next pointer of last "done" CB. */ | 33 | struct rcu_head **donetail; /* ->next pointer of last "done" CB. */ |
34 | struct rcu_head **curtail; /* ->next pointer of last CB. */ | 34 | struct rcu_head **curtail; /* ->next pointer of last CB. */ |
35 | RCU_TRACE(long qlen); /* Number of pending CBs. */ | 35 | RCU_TRACE(long qlen); /* Number of pending CBs. */ |
36 | RCU_TRACE(unsigned long gp_start); /* Start time for stalls. */ | ||
37 | RCU_TRACE(unsigned long ticks_this_gp); /* Statistic for stalls. */ | ||
38 | RCU_TRACE(unsigned long jiffies_stall); /* Jiffies at next stall. */ | ||
36 | RCU_TRACE(char *name); /* Name of RCU type. */ | 39 | RCU_TRACE(char *name); /* Name of RCU type. */ |
37 | }; | 40 | }; |
38 | 41 | ||
@@ -54,6 +57,51 @@ int rcu_scheduler_active __read_mostly; | |||
54 | EXPORT_SYMBOL_GPL(rcu_scheduler_active); | 57 | EXPORT_SYMBOL_GPL(rcu_scheduler_active); |
55 | #endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ | 58 | #endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ |
56 | 59 | ||
60 | #ifdef CONFIG_RCU_TRACE | ||
61 | |||
62 | static void check_cpu_stall(struct rcu_ctrlblk *rcp) | ||
63 | { | ||
64 | unsigned long j; | ||
65 | unsigned long js; | ||
66 | |||
67 | if (rcu_cpu_stall_suppress) | ||
68 | return; | ||
69 | rcp->ticks_this_gp++; | ||
70 | j = jiffies; | ||
71 | js = rcp->jiffies_stall; | ||
72 | if (*rcp->curtail && ULONG_CMP_GE(j, js)) { | ||
73 | pr_err("INFO: %s stall on CPU (%lu ticks this GP) idle=%llx (t=%lu jiffies q=%ld)\n", | ||
74 | rcp->name, rcp->ticks_this_gp, rcu_dynticks_nesting, | ||
75 | jiffies - rcp->gp_start, rcp->qlen); | ||
76 | dump_stack(); | ||
77 | } | ||
78 | if (*rcp->curtail && ULONG_CMP_GE(j, js)) | ||
79 | rcp->jiffies_stall = jiffies + | ||
80 | 3 * rcu_jiffies_till_stall_check() + 3; | ||
81 | else if (ULONG_CMP_GE(j, js)) | ||
82 | rcp->jiffies_stall = jiffies + rcu_jiffies_till_stall_check(); | ||
83 | } | ||
84 | |||
85 | static void check_cpu_stall_preempt(void); | ||
86 | |||
87 | #endif /* #ifdef CONFIG_RCU_TRACE */ | ||
88 | |||
89 | static void reset_cpu_stall_ticks(struct rcu_ctrlblk *rcp) | ||
90 | { | ||
91 | #ifdef CONFIG_RCU_TRACE | ||
92 | rcp->ticks_this_gp = 0; | ||
93 | rcp->gp_start = jiffies; | ||
94 | rcp->jiffies_stall = jiffies + rcu_jiffies_till_stall_check(); | ||
95 | #endif /* #ifdef CONFIG_RCU_TRACE */ | ||
96 | } | ||
97 | |||
98 | static void check_cpu_stalls(void) | ||
99 | { | ||
100 | RCU_TRACE(check_cpu_stall(&rcu_bh_ctrlblk)); | ||
101 | RCU_TRACE(check_cpu_stall(&rcu_sched_ctrlblk)); | ||
102 | RCU_TRACE(check_cpu_stall_preempt()); | ||
103 | } | ||
104 | |||
57 | #ifdef CONFIG_TINY_PREEMPT_RCU | 105 | #ifdef CONFIG_TINY_PREEMPT_RCU |
58 | 106 | ||
59 | #include <linux/delay.h> | 107 | #include <linux/delay.h> |
@@ -448,6 +496,7 @@ static void rcu_preempt_start_gp(void) | |||
448 | /* Official start of GP. */ | 496 | /* Official start of GP. */ |
449 | rcu_preempt_ctrlblk.gpnum++; | 497 | rcu_preempt_ctrlblk.gpnum++; |
450 | RCU_TRACE(rcu_preempt_ctrlblk.n_grace_periods++); | 498 | RCU_TRACE(rcu_preempt_ctrlblk.n_grace_periods++); |
499 | reset_cpu_stall_ticks(&rcu_preempt_ctrlblk.rcb); | ||
451 | 500 | ||
452 | /* Any blocked RCU readers block new GP. */ | 501 | /* Any blocked RCU readers block new GP. */ |
453 | if (rcu_preempt_blocked_readers_any()) | 502 | if (rcu_preempt_blocked_readers_any()) |
@@ -1054,4 +1103,11 @@ MODULE_AUTHOR("Paul E. McKenney"); | |||
1054 | MODULE_DESCRIPTION("Read-Copy Update tracing for tiny implementation"); | 1103 | MODULE_DESCRIPTION("Read-Copy Update tracing for tiny implementation"); |
1055 | MODULE_LICENSE("GPL"); | 1104 | MODULE_LICENSE("GPL"); |
1056 | 1105 | ||
1106 | static void check_cpu_stall_preempt(void) | ||
1107 | { | ||
1108 | #ifdef CONFIG_TINY_PREEMPT_RCU | ||
1109 | check_cpu_stall(&rcu_preempt_ctrlblk.rcb); | ||
1110 | #endif /* #ifdef CONFIG_TINY_PREEMPT_RCU */ | ||
1111 | } | ||
1112 | |||
1057 | #endif /* #ifdef CONFIG_RCU_TRACE */ | 1113 | #endif /* #ifdef CONFIG_RCU_TRACE */ |
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 31dea01c85fd..e1f3a8c96724 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c | |||
@@ -46,6 +46,7 @@ | |||
46 | #include <linux/stat.h> | 46 | #include <linux/stat.h> |
47 | #include <linux/srcu.h> | 47 | #include <linux/srcu.h> |
48 | #include <linux/slab.h> | 48 | #include <linux/slab.h> |
49 | #include <linux/trace_clock.h> | ||
49 | #include <asm/byteorder.h> | 50 | #include <asm/byteorder.h> |
50 | 51 | ||
51 | MODULE_LICENSE("GPL"); | 52 | MODULE_LICENSE("GPL"); |
@@ -207,6 +208,20 @@ MODULE_PARM_DESC(rcutorture_runnable, "Start rcutorture at boot"); | |||
207 | #define rcu_can_boost() 0 | 208 | #define rcu_can_boost() 0 |
208 | #endif /* #else #if defined(CONFIG_RCU_BOOST) && !defined(CONFIG_HOTPLUG_CPU) */ | 209 | #endif /* #else #if defined(CONFIG_RCU_BOOST) && !defined(CONFIG_HOTPLUG_CPU) */ |
209 | 210 | ||
211 | #ifdef CONFIG_RCU_TRACE | ||
212 | static u64 notrace rcu_trace_clock_local(void) | ||
213 | { | ||
214 | u64 ts = trace_clock_local(); | ||
215 | unsigned long __maybe_unused ts_rem = do_div(ts, NSEC_PER_USEC); | ||
216 | return ts; | ||
217 | } | ||
218 | #else /* #ifdef CONFIG_RCU_TRACE */ | ||
219 | static u64 notrace rcu_trace_clock_local(void) | ||
220 | { | ||
221 | return 0ULL; | ||
222 | } | ||
223 | #endif /* #else #ifdef CONFIG_RCU_TRACE */ | ||
224 | |||
210 | static unsigned long shutdown_time; /* jiffies to system shutdown. */ | 225 | static unsigned long shutdown_time; /* jiffies to system shutdown. */ |
211 | static unsigned long boost_starttime; /* jiffies of next boost test start. */ | 226 | static unsigned long boost_starttime; /* jiffies of next boost test start. */ |
212 | DEFINE_MUTEX(boost_mutex); /* protect setting boost_starttime */ | 227 | DEFINE_MUTEX(boost_mutex); /* protect setting boost_starttime */ |
@@ -845,7 +860,7 @@ static int rcu_torture_boost(void *arg) | |||
845 | /* Wait for the next test interval. */ | 860 | /* Wait for the next test interval. */ |
846 | oldstarttime = boost_starttime; | 861 | oldstarttime = boost_starttime; |
847 | while (ULONG_CMP_LT(jiffies, oldstarttime)) { | 862 | while (ULONG_CMP_LT(jiffies, oldstarttime)) { |
848 | schedule_timeout_uninterruptible(1); | 863 | schedule_timeout_interruptible(oldstarttime - jiffies); |
849 | rcu_stutter_wait("rcu_torture_boost"); | 864 | rcu_stutter_wait("rcu_torture_boost"); |
850 | if (kthread_should_stop() || | 865 | if (kthread_should_stop() || |
851 | fullstop != FULLSTOP_DONTSTOP) | 866 | fullstop != FULLSTOP_DONTSTOP) |
@@ -1028,7 +1043,6 @@ void rcutorture_trace_dump(void) | |||
1028 | return; | 1043 | return; |
1029 | if (atomic_xchg(&beenhere, 1) != 0) | 1044 | if (atomic_xchg(&beenhere, 1) != 0) |
1030 | return; | 1045 | return; |
1031 | do_trace_rcu_torture_read(cur_ops->name, (struct rcu_head *)~0UL); | ||
1032 | ftrace_dump(DUMP_ALL); | 1046 | ftrace_dump(DUMP_ALL); |
1033 | } | 1047 | } |
1034 | 1048 | ||
@@ -1042,13 +1056,16 @@ static void rcu_torture_timer(unsigned long unused) | |||
1042 | { | 1056 | { |
1043 | int idx; | 1057 | int idx; |
1044 | int completed; | 1058 | int completed; |
1059 | int completed_end; | ||
1045 | static DEFINE_RCU_RANDOM(rand); | 1060 | static DEFINE_RCU_RANDOM(rand); |
1046 | static DEFINE_SPINLOCK(rand_lock); | 1061 | static DEFINE_SPINLOCK(rand_lock); |
1047 | struct rcu_torture *p; | 1062 | struct rcu_torture *p; |
1048 | int pipe_count; | 1063 | int pipe_count; |
1064 | unsigned long long ts; | ||
1049 | 1065 | ||
1050 | idx = cur_ops->readlock(); | 1066 | idx = cur_ops->readlock(); |
1051 | completed = cur_ops->completed(); | 1067 | completed = cur_ops->completed(); |
1068 | ts = rcu_trace_clock_local(); | ||
1052 | p = rcu_dereference_check(rcu_torture_current, | 1069 | p = rcu_dereference_check(rcu_torture_current, |
1053 | rcu_read_lock_bh_held() || | 1070 | rcu_read_lock_bh_held() || |
1054 | rcu_read_lock_sched_held() || | 1071 | rcu_read_lock_sched_held() || |
@@ -1058,7 +1075,6 @@ static void rcu_torture_timer(unsigned long unused) | |||
1058 | cur_ops->readunlock(idx); | 1075 | cur_ops->readunlock(idx); |
1059 | return; | 1076 | return; |
1060 | } | 1077 | } |
1061 | do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu); | ||
1062 | if (p->rtort_mbtest == 0) | 1078 | if (p->rtort_mbtest == 0) |
1063 | atomic_inc(&n_rcu_torture_mberror); | 1079 | atomic_inc(&n_rcu_torture_mberror); |
1064 | spin_lock(&rand_lock); | 1080 | spin_lock(&rand_lock); |
@@ -1071,10 +1087,14 @@ static void rcu_torture_timer(unsigned long unused) | |||
1071 | /* Should not happen, but... */ | 1087 | /* Should not happen, but... */ |
1072 | pipe_count = RCU_TORTURE_PIPE_LEN; | 1088 | pipe_count = RCU_TORTURE_PIPE_LEN; |
1073 | } | 1089 | } |
1074 | if (pipe_count > 1) | 1090 | completed_end = cur_ops->completed(); |
1091 | if (pipe_count > 1) { | ||
1092 | do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu, ts, | ||
1093 | completed, completed_end); | ||
1075 | rcutorture_trace_dump(); | 1094 | rcutorture_trace_dump(); |
1095 | } | ||
1076 | __this_cpu_inc(rcu_torture_count[pipe_count]); | 1096 | __this_cpu_inc(rcu_torture_count[pipe_count]); |
1077 | completed = cur_ops->completed() - completed; | 1097 | completed = completed_end - completed; |
1078 | if (completed > RCU_TORTURE_PIPE_LEN) { | 1098 | if (completed > RCU_TORTURE_PIPE_LEN) { |
1079 | /* Should not happen, but... */ | 1099 | /* Should not happen, but... */ |
1080 | completed = RCU_TORTURE_PIPE_LEN; | 1100 | completed = RCU_TORTURE_PIPE_LEN; |
@@ -1094,11 +1114,13 @@ static int | |||
1094 | rcu_torture_reader(void *arg) | 1114 | rcu_torture_reader(void *arg) |
1095 | { | 1115 | { |
1096 | int completed; | 1116 | int completed; |
1117 | int completed_end; | ||
1097 | int idx; | 1118 | int idx; |
1098 | DEFINE_RCU_RANDOM(rand); | 1119 | DEFINE_RCU_RANDOM(rand); |
1099 | struct rcu_torture *p; | 1120 | struct rcu_torture *p; |
1100 | int pipe_count; | 1121 | int pipe_count; |
1101 | struct timer_list t; | 1122 | struct timer_list t; |
1123 | unsigned long long ts; | ||
1102 | 1124 | ||
1103 | VERBOSE_PRINTK_STRING("rcu_torture_reader task started"); | 1125 | VERBOSE_PRINTK_STRING("rcu_torture_reader task started"); |
1104 | set_user_nice(current, 19); | 1126 | set_user_nice(current, 19); |
@@ -1112,6 +1134,7 @@ rcu_torture_reader(void *arg) | |||
1112 | } | 1134 | } |
1113 | idx = cur_ops->readlock(); | 1135 | idx = cur_ops->readlock(); |
1114 | completed = cur_ops->completed(); | 1136 | completed = cur_ops->completed(); |
1137 | ts = rcu_trace_clock_local(); | ||
1115 | p = rcu_dereference_check(rcu_torture_current, | 1138 | p = rcu_dereference_check(rcu_torture_current, |
1116 | rcu_read_lock_bh_held() || | 1139 | rcu_read_lock_bh_held() || |
1117 | rcu_read_lock_sched_held() || | 1140 | rcu_read_lock_sched_held() || |
@@ -1122,7 +1145,6 @@ rcu_torture_reader(void *arg) | |||
1122 | schedule_timeout_interruptible(HZ); | 1145 | schedule_timeout_interruptible(HZ); |
1123 | continue; | 1146 | continue; |
1124 | } | 1147 | } |
1125 | do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu); | ||
1126 | if (p->rtort_mbtest == 0) | 1148 | if (p->rtort_mbtest == 0) |
1127 | atomic_inc(&n_rcu_torture_mberror); | 1149 | atomic_inc(&n_rcu_torture_mberror); |
1128 | cur_ops->read_delay(&rand); | 1150 | cur_ops->read_delay(&rand); |
@@ -1132,10 +1154,14 @@ rcu_torture_reader(void *arg) | |||
1132 | /* Should not happen, but... */ | 1154 | /* Should not happen, but... */ |
1133 | pipe_count = RCU_TORTURE_PIPE_LEN; | 1155 | pipe_count = RCU_TORTURE_PIPE_LEN; |
1134 | } | 1156 | } |
1135 | if (pipe_count > 1) | 1157 | completed_end = cur_ops->completed(); |
1158 | if (pipe_count > 1) { | ||
1159 | do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu, | ||
1160 | ts, completed, completed_end); | ||
1136 | rcutorture_trace_dump(); | 1161 | rcutorture_trace_dump(); |
1162 | } | ||
1137 | __this_cpu_inc(rcu_torture_count[pipe_count]); | 1163 | __this_cpu_inc(rcu_torture_count[pipe_count]); |
1138 | completed = cur_ops->completed() - completed; | 1164 | completed = completed_end - completed; |
1139 | if (completed > RCU_TORTURE_PIPE_LEN) { | 1165 | if (completed > RCU_TORTURE_PIPE_LEN) { |
1140 | /* Should not happen, but... */ | 1166 | /* Should not happen, but... */ |
1141 | completed = RCU_TORTURE_PIPE_LEN; | 1167 | completed = RCU_TORTURE_PIPE_LEN; |
@@ -1301,19 +1327,35 @@ static void rcu_torture_shuffle_tasks(void) | |||
1301 | set_cpus_allowed_ptr(reader_tasks[i], | 1327 | set_cpus_allowed_ptr(reader_tasks[i], |
1302 | shuffle_tmp_mask); | 1328 | shuffle_tmp_mask); |
1303 | } | 1329 | } |
1304 | |||
1305 | if (fakewriter_tasks) { | 1330 | if (fakewriter_tasks) { |
1306 | for (i = 0; i < nfakewriters; i++) | 1331 | for (i = 0; i < nfakewriters; i++) |
1307 | if (fakewriter_tasks[i]) | 1332 | if (fakewriter_tasks[i]) |
1308 | set_cpus_allowed_ptr(fakewriter_tasks[i], | 1333 | set_cpus_allowed_ptr(fakewriter_tasks[i], |
1309 | shuffle_tmp_mask); | 1334 | shuffle_tmp_mask); |
1310 | } | 1335 | } |
1311 | |||
1312 | if (writer_task) | 1336 | if (writer_task) |
1313 | set_cpus_allowed_ptr(writer_task, shuffle_tmp_mask); | 1337 | set_cpus_allowed_ptr(writer_task, shuffle_tmp_mask); |
1314 | |||
1315 | if (stats_task) | 1338 | if (stats_task) |
1316 | set_cpus_allowed_ptr(stats_task, shuffle_tmp_mask); | 1339 | set_cpus_allowed_ptr(stats_task, shuffle_tmp_mask); |
1340 | if (stutter_task) | ||
1341 | set_cpus_allowed_ptr(stutter_task, shuffle_tmp_mask); | ||
1342 | if (fqs_task) | ||
1343 | set_cpus_allowed_ptr(fqs_task, shuffle_tmp_mask); | ||
1344 | if (shutdown_task) | ||
1345 | set_cpus_allowed_ptr(shutdown_task, shuffle_tmp_mask); | ||
1346 | #ifdef CONFIG_HOTPLUG_CPU | ||
1347 | if (onoff_task) | ||
1348 | set_cpus_allowed_ptr(onoff_task, shuffle_tmp_mask); | ||
1349 | #endif /* #ifdef CONFIG_HOTPLUG_CPU */ | ||
1350 | if (stall_task) | ||
1351 | set_cpus_allowed_ptr(stall_task, shuffle_tmp_mask); | ||
1352 | if (barrier_cbs_tasks) | ||
1353 | for (i = 0; i < n_barrier_cbs; i++) | ||
1354 | if (barrier_cbs_tasks[i]) | ||
1355 | set_cpus_allowed_ptr(barrier_cbs_tasks[i], | ||
1356 | shuffle_tmp_mask); | ||
1357 | if (barrier_task) | ||
1358 | set_cpus_allowed_ptr(barrier_task, shuffle_tmp_mask); | ||
1317 | 1359 | ||
1318 | if (rcu_idle_cpu == -1) | 1360 | if (rcu_idle_cpu == -1) |
1319 | rcu_idle_cpu = num_online_cpus() - 1; | 1361 | rcu_idle_cpu = num_online_cpus() - 1; |
@@ -1749,7 +1791,7 @@ static int rcu_torture_barrier_init(void) | |||
1749 | barrier_cbs_wq = | 1791 | barrier_cbs_wq = |
1750 | kzalloc(n_barrier_cbs * sizeof(barrier_cbs_wq[0]), | 1792 | kzalloc(n_barrier_cbs * sizeof(barrier_cbs_wq[0]), |
1751 | GFP_KERNEL); | 1793 | GFP_KERNEL); |
1752 | if (barrier_cbs_tasks == NULL || barrier_cbs_wq == 0) | 1794 | if (barrier_cbs_tasks == NULL || !barrier_cbs_wq) |
1753 | return -ENOMEM; | 1795 | return -ENOMEM; |
1754 | for (i = 0; i < n_barrier_cbs; i++) { | 1796 | for (i = 0; i < n_barrier_cbs; i++) { |
1755 | init_waitqueue_head(&barrier_cbs_wq[i]); | 1797 | init_waitqueue_head(&barrier_cbs_wq[i]); |
diff --git a/kernel/rcutree.c b/kernel/rcutree.c index e441b77b614e..5b8ad827fd86 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c | |||
@@ -105,7 +105,7 @@ int rcu_num_nodes __read_mostly = NUM_RCU_NODES; /* Total # rcu_nodes in use. */ | |||
105 | * The rcu_scheduler_active variable transitions from zero to one just | 105 | * The rcu_scheduler_active variable transitions from zero to one just |
106 | * before the first task is spawned. So when this variable is zero, RCU | 106 | * before the first task is spawned. So when this variable is zero, RCU |
107 | * can assume that there is but one task, allowing RCU to (for example) | 107 | * can assume that there is but one task, allowing RCU to (for example) |
108 | * optimized synchronize_sched() to a simple barrier(). When this variable | 108 | * optimize synchronize_sched() to a simple barrier(). When this variable |
109 | * is one, RCU must actually do all the hard work required to detect real | 109 | * is one, RCU must actually do all the hard work required to detect real |
110 | * grace periods. This variable is also used to suppress boot-time false | 110 | * grace periods. This variable is also used to suppress boot-time false |
111 | * positives from lockdep-RCU error checking. | 111 | * positives from lockdep-RCU error checking. |
@@ -217,12 +217,6 @@ module_param(blimit, long, 0444); | |||
217 | module_param(qhimark, long, 0444); | 217 | module_param(qhimark, long, 0444); |
218 | module_param(qlowmark, long, 0444); | 218 | module_param(qlowmark, long, 0444); |
219 | 219 | ||
220 | int rcu_cpu_stall_suppress __read_mostly; /* 1 = suppress stall warnings. */ | ||
221 | int rcu_cpu_stall_timeout __read_mostly = CONFIG_RCU_CPU_STALL_TIMEOUT; | ||
222 | |||
223 | module_param(rcu_cpu_stall_suppress, int, 0644); | ||
224 | module_param(rcu_cpu_stall_timeout, int, 0644); | ||
225 | |||
226 | static ulong jiffies_till_first_fqs = RCU_JIFFIES_TILL_FORCE_QS; | 220 | static ulong jiffies_till_first_fqs = RCU_JIFFIES_TILL_FORCE_QS; |
227 | static ulong jiffies_till_next_fqs = RCU_JIFFIES_TILL_FORCE_QS; | 221 | static ulong jiffies_till_next_fqs = RCU_JIFFIES_TILL_FORCE_QS; |
228 | 222 | ||
@@ -305,17 +299,27 @@ cpu_has_callbacks_ready_to_invoke(struct rcu_data *rdp) | |||
305 | } | 299 | } |
306 | 300 | ||
307 | /* | 301 | /* |
308 | * Does the current CPU require a yet-as-unscheduled grace period? | 302 | * Does the current CPU require a not-yet-started grace period? |
303 | * The caller must have disabled interrupts to prevent races with | ||
304 | * normal callback registry. | ||
309 | */ | 305 | */ |
310 | static int | 306 | static int |
311 | cpu_needs_another_gp(struct rcu_state *rsp, struct rcu_data *rdp) | 307 | cpu_needs_another_gp(struct rcu_state *rsp, struct rcu_data *rdp) |
312 | { | 308 | { |
313 | struct rcu_head **ntp; | 309 | int i; |
314 | 310 | ||
315 | ntp = rdp->nxttail[RCU_DONE_TAIL + | 311 | if (rcu_gp_in_progress(rsp)) |
316 | (ACCESS_ONCE(rsp->completed) != rdp->completed)]; | 312 | return 0; /* No, a grace period is already in progress. */ |
317 | return rdp->nxttail[RCU_DONE_TAIL] && ntp && *ntp && | 313 | if (!rdp->nxttail[RCU_NEXT_TAIL]) |
318 | !rcu_gp_in_progress(rsp); | 314 | return 0; /* No, this is a no-CBs (or offline) CPU. */ |
315 | if (*rdp->nxttail[RCU_NEXT_READY_TAIL]) | ||
316 | return 1; /* Yes, this CPU has newly registered callbacks. */ | ||
317 | for (i = RCU_WAIT_TAIL; i < RCU_NEXT_TAIL; i++) | ||
318 | if (rdp->nxttail[i - 1] != rdp->nxttail[i] && | ||
319 | ULONG_CMP_LT(ACCESS_ONCE(rsp->completed), | ||
320 | rdp->nxtcompleted[i])) | ||
321 | return 1; /* Yes, CBs for future grace period. */ | ||
322 | return 0; /* No grace period needed. */ | ||
319 | } | 323 | } |
320 | 324 | ||
321 | /* | 325 | /* |
@@ -336,7 +340,7 @@ static struct rcu_node *rcu_get_root(struct rcu_state *rsp) | |||
336 | static void rcu_eqs_enter_common(struct rcu_dynticks *rdtp, long long oldval, | 340 | static void rcu_eqs_enter_common(struct rcu_dynticks *rdtp, long long oldval, |
337 | bool user) | 341 | bool user) |
338 | { | 342 | { |
339 | trace_rcu_dyntick("Start", oldval, 0); | 343 | trace_rcu_dyntick("Start", oldval, rdtp->dynticks_nesting); |
340 | if (!user && !is_idle_task(current)) { | 344 | if (!user && !is_idle_task(current)) { |
341 | struct task_struct *idle = idle_task(smp_processor_id()); | 345 | struct task_struct *idle = idle_task(smp_processor_id()); |
342 | 346 | ||
@@ -727,7 +731,7 @@ EXPORT_SYMBOL_GPL(rcu_lockdep_current_cpu_online); | |||
727 | * interrupt from idle, return true. The caller must have at least | 731 | * interrupt from idle, return true. The caller must have at least |
728 | * disabled preemption. | 732 | * disabled preemption. |
729 | */ | 733 | */ |
730 | int rcu_is_cpu_rrupt_from_idle(void) | 734 | static int rcu_is_cpu_rrupt_from_idle(void) |
731 | { | 735 | { |
732 | return __get_cpu_var(rcu_dynticks).dynticks_nesting <= 1; | 736 | return __get_cpu_var(rcu_dynticks).dynticks_nesting <= 1; |
733 | } | 737 | } |
@@ -793,28 +797,10 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp) | |||
793 | return 0; | 797 | return 0; |
794 | } | 798 | } |
795 | 799 | ||
796 | static int jiffies_till_stall_check(void) | ||
797 | { | ||
798 | int till_stall_check = ACCESS_ONCE(rcu_cpu_stall_timeout); | ||
799 | |||
800 | /* | ||
801 | * Limit check must be consistent with the Kconfig limits | ||
802 | * for CONFIG_RCU_CPU_STALL_TIMEOUT. | ||
803 | */ | ||
804 | if (till_stall_check < 3) { | ||
805 | ACCESS_ONCE(rcu_cpu_stall_timeout) = 3; | ||
806 | till_stall_check = 3; | ||
807 | } else if (till_stall_check > 300) { | ||
808 | ACCESS_ONCE(rcu_cpu_stall_timeout) = 300; | ||
809 | till_stall_check = 300; | ||
810 | } | ||
811 | return till_stall_check * HZ + RCU_STALL_DELAY_DELTA; | ||
812 | } | ||
813 | |||
814 | static void record_gp_stall_check_time(struct rcu_state *rsp) | 800 | static void record_gp_stall_check_time(struct rcu_state *rsp) |
815 | { | 801 | { |
816 | rsp->gp_start = jiffies; | 802 | rsp->gp_start = jiffies; |
817 | rsp->jiffies_stall = jiffies + jiffies_till_stall_check(); | 803 | rsp->jiffies_stall = jiffies + rcu_jiffies_till_stall_check(); |
818 | } | 804 | } |
819 | 805 | ||
820 | /* | 806 | /* |
@@ -857,7 +843,7 @@ static void print_other_cpu_stall(struct rcu_state *rsp) | |||
857 | raw_spin_unlock_irqrestore(&rnp->lock, flags); | 843 | raw_spin_unlock_irqrestore(&rnp->lock, flags); |
858 | return; | 844 | return; |
859 | } | 845 | } |
860 | rsp->jiffies_stall = jiffies + 3 * jiffies_till_stall_check() + 3; | 846 | rsp->jiffies_stall = jiffies + 3 * rcu_jiffies_till_stall_check() + 3; |
861 | raw_spin_unlock_irqrestore(&rnp->lock, flags); | 847 | raw_spin_unlock_irqrestore(&rnp->lock, flags); |
862 | 848 | ||
863 | /* | 849 | /* |
@@ -935,7 +921,7 @@ static void print_cpu_stall(struct rcu_state *rsp) | |||
935 | raw_spin_lock_irqsave(&rnp->lock, flags); | 921 | raw_spin_lock_irqsave(&rnp->lock, flags); |
936 | if (ULONG_CMP_GE(jiffies, rsp->jiffies_stall)) | 922 | if (ULONG_CMP_GE(jiffies, rsp->jiffies_stall)) |
937 | rsp->jiffies_stall = jiffies + | 923 | rsp->jiffies_stall = jiffies + |
938 | 3 * jiffies_till_stall_check() + 3; | 924 | 3 * rcu_jiffies_till_stall_check() + 3; |
939 | raw_spin_unlock_irqrestore(&rnp->lock, flags); | 925 | raw_spin_unlock_irqrestore(&rnp->lock, flags); |
940 | 926 | ||
941 | set_need_resched(); /* kick ourselves to get things going. */ | 927 | set_need_resched(); /* kick ourselves to get things going. */ |
@@ -966,12 +952,6 @@ static void check_cpu_stall(struct rcu_state *rsp, struct rcu_data *rdp) | |||
966 | } | 952 | } |
967 | } | 953 | } |
968 | 954 | ||
969 | static int rcu_panic(struct notifier_block *this, unsigned long ev, void *ptr) | ||
970 | { | ||
971 | rcu_cpu_stall_suppress = 1; | ||
972 | return NOTIFY_DONE; | ||
973 | } | ||
974 | |||
975 | /** | 955 | /** |
976 | * rcu_cpu_stall_reset - prevent further stall warnings in current grace period | 956 | * rcu_cpu_stall_reset - prevent further stall warnings in current grace period |
977 | * | 957 | * |
@@ -989,15 +969,6 @@ void rcu_cpu_stall_reset(void) | |||
989 | rsp->jiffies_stall = jiffies + ULONG_MAX / 2; | 969 | rsp->jiffies_stall = jiffies + ULONG_MAX / 2; |
990 | } | 970 | } |
991 | 971 | ||
992 | static struct notifier_block rcu_panic_block = { | ||
993 | .notifier_call = rcu_panic, | ||
994 | }; | ||
995 | |||
996 | static void __init check_cpu_stall_init(void) | ||
997 | { | ||
998 | atomic_notifier_chain_register(&panic_notifier_list, &rcu_panic_block); | ||
999 | } | ||
1000 | |||
1001 | /* | 972 | /* |
1002 | * Update CPU-local rcu_data state to record the newly noticed grace period. | 973 | * Update CPU-local rcu_data state to record the newly noticed grace period. |
1003 | * This is used both when we started the grace period and when we notice | 974 | * This is used both when we started the grace period and when we notice |
@@ -1071,6 +1042,145 @@ static void init_callback_list(struct rcu_data *rdp) | |||
1071 | } | 1042 | } |
1072 | 1043 | ||
1073 | /* | 1044 | /* |
1045 | * Determine the value that ->completed will have at the end of the | ||
1046 | * next subsequent grace period. This is used to tag callbacks so that | ||
1047 | * a CPU can invoke callbacks in a timely fashion even if that CPU has | ||
1048 | * been dyntick-idle for an extended period with callbacks under the | ||
1049 | * influence of RCU_FAST_NO_HZ. | ||
1050 | * | ||
1051 | * The caller must hold rnp->lock with interrupts disabled. | ||
1052 | */ | ||
1053 | static unsigned long rcu_cbs_completed(struct rcu_state *rsp, | ||
1054 | struct rcu_node *rnp) | ||
1055 | { | ||
1056 | /* | ||
1057 | * If RCU is idle, we just wait for the next grace period. | ||
1058 | * But we can only be sure that RCU is idle if we are looking | ||
1059 | * at the root rcu_node structure -- otherwise, a new grace | ||
1060 | * period might have started, but just not yet gotten around | ||
1061 | * to initializing the current non-root rcu_node structure. | ||
1062 | */ | ||
1063 | if (rcu_get_root(rsp) == rnp && rnp->gpnum == rnp->completed) | ||
1064 | return rnp->completed + 1; | ||
1065 | |||
1066 | /* | ||
1067 | * Otherwise, wait for a possible partial grace period and | ||
1068 | * then the subsequent full grace period. | ||
1069 | */ | ||
1070 | return rnp->completed + 2; | ||
1071 | } | ||
1072 | |||
1073 | /* | ||
1074 | * If there is room, assign a ->completed number to any callbacks on | ||
1075 | * this CPU that have not already been assigned. Also accelerate any | ||
1076 | * callbacks that were previously assigned a ->completed number that has | ||
1077 | * since proven to be too conservative, which can happen if callbacks get | ||
1078 | * assigned a ->completed number while RCU is idle, but with reference to | ||
1079 | * a non-root rcu_node structure. This function is idempotent, so it does | ||
1080 | * not hurt to call it repeatedly. | ||
1081 | * | ||
1082 | * The caller must hold rnp->lock with interrupts disabled. | ||
1083 | */ | ||
1084 | static void rcu_accelerate_cbs(struct rcu_state *rsp, struct rcu_node *rnp, | ||
1085 | struct rcu_data *rdp) | ||
1086 | { | ||
1087 | unsigned long c; | ||
1088 | int i; | ||
1089 | |||
1090 | /* If the CPU has no callbacks, nothing to do. */ | ||
1091 | if (!rdp->nxttail[RCU_NEXT_TAIL] || !*rdp->nxttail[RCU_DONE_TAIL]) | ||
1092 | return; | ||
1093 | |||
1094 | /* | ||
1095 | * Starting from the sublist containing the callbacks most | ||
1096 | * recently assigned a ->completed number and working down, find the | ||
1097 | * first sublist that is not assignable to an upcoming grace period. | ||
1098 | * Such a sublist has something in it (first two tests) and has | ||
1099 | * a ->completed number assigned that will complete sooner than | ||
1100 | * the ->completed number for newly arrived callbacks (last test). | ||
1101 | * | ||
1102 | * The key point is that any later sublist can be assigned the | ||
1103 | * same ->completed number as the newly arrived callbacks, which | ||
1104 | * means that the callbacks in any of these later sublist can be | ||
1105 | * grouped into a single sublist, whether or not they have already | ||
1106 | * been assigned a ->completed number. | ||
1107 | */ | ||
1108 | c = rcu_cbs_completed(rsp, rnp); | ||
1109 | for (i = RCU_NEXT_TAIL - 1; i > RCU_DONE_TAIL; i--) | ||
1110 | if (rdp->nxttail[i] != rdp->nxttail[i - 1] && | ||
1111 | !ULONG_CMP_GE(rdp->nxtcompleted[i], c)) | ||
1112 | break; | ||
1113 | |||
1114 | /* | ||
1115 | * If there are no sublist for unassigned callbacks, leave. | ||
1116 | * At the same time, advance "i" one sublist, so that "i" will | ||
1117 | * index into the sublist where all the remaining callbacks should | ||
1118 | * be grouped into. | ||
1119 | */ | ||
1120 | if (++i >= RCU_NEXT_TAIL) | ||
1121 | return; | ||
1122 | |||
1123 | /* | ||
1124 | * Assign all subsequent callbacks' ->completed number to the next | ||
1125 | * full grace period and group them all in the sublist initially | ||
1126 | * indexed by "i". | ||
1127 | */ | ||
1128 | for (; i <= RCU_NEXT_TAIL; i++) { | ||
1129 | rdp->nxttail[i] = rdp->nxttail[RCU_NEXT_TAIL]; | ||
1130 | rdp->nxtcompleted[i] = c; | ||
1131 | } | ||
1132 | |||
1133 | /* Trace depending on how much we were able to accelerate. */ | ||
1134 | if (!*rdp->nxttail[RCU_WAIT_TAIL]) | ||
1135 | trace_rcu_grace_period(rsp->name, rdp->gpnum, "AccWaitCB"); | ||
1136 | else | ||
1137 | trace_rcu_grace_period(rsp->name, rdp->gpnum, "AccReadyCB"); | ||
1138 | } | ||
1139 | |||
1140 | /* | ||
1141 | * Move any callbacks whose grace period has completed to the | ||
1142 | * RCU_DONE_TAIL sublist, then compact the remaining sublists and | ||
1143 | * assign ->completed numbers to any callbacks in the RCU_NEXT_TAIL | ||
1144 | * sublist. This function is idempotent, so it does not hurt to | ||
1145 | * invoke it repeatedly. As long as it is not invoked -too- often... | ||
1146 | * | ||
1147 | * The caller must hold rnp->lock with interrupts disabled. | ||
1148 | */ | ||
1149 | static void rcu_advance_cbs(struct rcu_state *rsp, struct rcu_node *rnp, | ||
1150 | struct rcu_data *rdp) | ||
1151 | { | ||
1152 | int i, j; | ||
1153 | |||
1154 | /* If the CPU has no callbacks, nothing to do. */ | ||
1155 | if (!rdp->nxttail[RCU_NEXT_TAIL] || !*rdp->nxttail[RCU_DONE_TAIL]) | ||
1156 | return; | ||
1157 | |||
1158 | /* | ||
1159 | * Find all callbacks whose ->completed numbers indicate that they | ||
1160 | * are ready to invoke, and put them into the RCU_DONE_TAIL sublist. | ||
1161 | */ | ||
1162 | for (i = RCU_WAIT_TAIL; i < RCU_NEXT_TAIL; i++) { | ||
1163 | if (ULONG_CMP_LT(rnp->completed, rdp->nxtcompleted[i])) | ||
1164 | break; | ||
1165 | rdp->nxttail[RCU_DONE_TAIL] = rdp->nxttail[i]; | ||
1166 | } | ||
1167 | /* Clean up any sublist tail pointers that were misordered above. */ | ||
1168 | for (j = RCU_WAIT_TAIL; j < i; j++) | ||
1169 | rdp->nxttail[j] = rdp->nxttail[RCU_DONE_TAIL]; | ||
1170 | |||
1171 | /* Copy down callbacks to fill in empty sublists. */ | ||
1172 | for (j = RCU_WAIT_TAIL; i < RCU_NEXT_TAIL; i++, j++) { | ||
1173 | if (rdp->nxttail[j] == rdp->nxttail[RCU_NEXT_TAIL]) | ||
1174 | break; | ||
1175 | rdp->nxttail[j] = rdp->nxttail[i]; | ||
1176 | rdp->nxtcompleted[j] = rdp->nxtcompleted[i]; | ||
1177 | } | ||
1178 | |||
1179 | /* Classify any remaining callbacks. */ | ||
1180 | rcu_accelerate_cbs(rsp, rnp, rdp); | ||
1181 | } | ||
1182 | |||
1183 | /* | ||
1074 | * Advance this CPU's callbacks, but only if the current grace period | 1184 | * Advance this CPU's callbacks, but only if the current grace period |
1075 | * has ended. This may be called only from the CPU to whom the rdp | 1185 | * has ended. This may be called only from the CPU to whom the rdp |
1076 | * belongs. In addition, the corresponding leaf rcu_node structure's | 1186 | * belongs. In addition, the corresponding leaf rcu_node structure's |
@@ -1080,12 +1190,15 @@ static void | |||
1080 | __rcu_process_gp_end(struct rcu_state *rsp, struct rcu_node *rnp, struct rcu_data *rdp) | 1190 | __rcu_process_gp_end(struct rcu_state *rsp, struct rcu_node *rnp, struct rcu_data *rdp) |
1081 | { | 1191 | { |
1082 | /* Did another grace period end? */ | 1192 | /* Did another grace period end? */ |
1083 | if (rdp->completed != rnp->completed) { | 1193 | if (rdp->completed == rnp->completed) { |
1084 | 1194 | ||
1085 | /* Advance callbacks. No harm if list empty. */ | 1195 | /* No, so just accelerate recent callbacks. */ |
1086 | rdp->nxttail[RCU_DONE_TAIL] = rdp->nxttail[RCU_WAIT_TAIL]; | 1196 | rcu_accelerate_cbs(rsp, rnp, rdp); |
1087 | rdp->nxttail[RCU_WAIT_TAIL] = rdp->nxttail[RCU_NEXT_READY_TAIL]; | 1197 | |
1088 | rdp->nxttail[RCU_NEXT_READY_TAIL] = rdp->nxttail[RCU_NEXT_TAIL]; | 1198 | } else { |
1199 | |||
1200 | /* Advance callbacks. */ | ||
1201 | rcu_advance_cbs(rsp, rnp, rdp); | ||
1089 | 1202 | ||
1090 | /* Remember that we saw this grace-period completion. */ | 1203 | /* Remember that we saw this grace-period completion. */ |
1091 | rdp->completed = rnp->completed; | 1204 | rdp->completed = rnp->completed; |
@@ -1392,17 +1505,10 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags) | |||
1392 | /* | 1505 | /* |
1393 | * Because there is no grace period in progress right now, | 1506 | * Because there is no grace period in progress right now, |
1394 | * any callbacks we have up to this point will be satisfied | 1507 | * any callbacks we have up to this point will be satisfied |
1395 | * by the next grace period. So promote all callbacks to be | 1508 | * by the next grace period. So this is a good place to |
1396 | * handled after the end of the next grace period. If the | 1509 | * assign a grace period number to recently posted callbacks. |
1397 | * CPU is not yet aware of the end of the previous grace period, | ||
1398 | * we need to allow for the callback advancement that will | ||
1399 | * occur when it does become aware. Deadlock prevents us from | ||
1400 | * making it aware at this point: We cannot acquire a leaf | ||
1401 | * rcu_node ->lock while holding the root rcu_node ->lock. | ||
1402 | */ | 1510 | */ |
1403 | rdp->nxttail[RCU_NEXT_READY_TAIL] = rdp->nxttail[RCU_NEXT_TAIL]; | 1511 | rcu_accelerate_cbs(rsp, rnp, rdp); |
1404 | if (rdp->completed == rsp->completed) | ||
1405 | rdp->nxttail[RCU_WAIT_TAIL] = rdp->nxttail[RCU_NEXT_TAIL]; | ||
1406 | 1512 | ||
1407 | rsp->gp_flags = RCU_GP_FLAG_INIT; | 1513 | rsp->gp_flags = RCU_GP_FLAG_INIT; |
1408 | raw_spin_unlock(&rnp->lock); /* Interrupts remain disabled. */ | 1514 | raw_spin_unlock(&rnp->lock); /* Interrupts remain disabled. */ |
@@ -1527,7 +1633,7 @@ rcu_report_qs_rdp(int cpu, struct rcu_state *rsp, struct rcu_data *rdp) | |||
1527 | * This GP can't end until cpu checks in, so all of our | 1633 | * This GP can't end until cpu checks in, so all of our |
1528 | * callbacks can be processed during the next GP. | 1634 | * callbacks can be processed during the next GP. |
1529 | */ | 1635 | */ |
1530 | rdp->nxttail[RCU_NEXT_READY_TAIL] = rdp->nxttail[RCU_NEXT_TAIL]; | 1636 | rcu_accelerate_cbs(rsp, rnp, rdp); |
1531 | 1637 | ||
1532 | rcu_report_qs_rnp(mask, rsp, rnp, flags); /* rlses rnp->lock */ | 1638 | rcu_report_qs_rnp(mask, rsp, rnp, flags); /* rlses rnp->lock */ |
1533 | } | 1639 | } |
@@ -1779,7 +1885,7 @@ static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp) | |||
1779 | long bl, count, count_lazy; | 1885 | long bl, count, count_lazy; |
1780 | int i; | 1886 | int i; |
1781 | 1887 | ||
1782 | /* If no callbacks are ready, just return.*/ | 1888 | /* If no callbacks are ready, just return. */ |
1783 | if (!cpu_has_callbacks_ready_to_invoke(rdp)) { | 1889 | if (!cpu_has_callbacks_ready_to_invoke(rdp)) { |
1784 | trace_rcu_batch_start(rsp->name, rdp->qlen_lazy, rdp->qlen, 0); | 1890 | trace_rcu_batch_start(rsp->name, rdp->qlen_lazy, rdp->qlen, 0); |
1785 | trace_rcu_batch_end(rsp->name, 0, !!ACCESS_ONCE(rdp->nxtlist), | 1891 | trace_rcu_batch_end(rsp->name, 0, !!ACCESS_ONCE(rdp->nxtlist), |
@@ -2008,19 +2114,19 @@ __rcu_process_callbacks(struct rcu_state *rsp) | |||
2008 | 2114 | ||
2009 | WARN_ON_ONCE(rdp->beenonline == 0); | 2115 | WARN_ON_ONCE(rdp->beenonline == 0); |
2010 | 2116 | ||
2011 | /* | 2117 | /* Handle the end of a grace period that some other CPU ended. */ |
2012 | * Advance callbacks in response to end of earlier grace | ||
2013 | * period that some other CPU ended. | ||
2014 | */ | ||
2015 | rcu_process_gp_end(rsp, rdp); | 2118 | rcu_process_gp_end(rsp, rdp); |
2016 | 2119 | ||
2017 | /* Update RCU state based on any recent quiescent states. */ | 2120 | /* Update RCU state based on any recent quiescent states. */ |
2018 | rcu_check_quiescent_state(rsp, rdp); | 2121 | rcu_check_quiescent_state(rsp, rdp); |
2019 | 2122 | ||
2020 | /* Does this CPU require a not-yet-started grace period? */ | 2123 | /* Does this CPU require a not-yet-started grace period? */ |
2124 | local_irq_save(flags); | ||
2021 | if (cpu_needs_another_gp(rsp, rdp)) { | 2125 | if (cpu_needs_another_gp(rsp, rdp)) { |
2022 | raw_spin_lock_irqsave(&rcu_get_root(rsp)->lock, flags); | 2126 | raw_spin_lock(&rcu_get_root(rsp)->lock); /* irqs disabled. */ |
2023 | rcu_start_gp(rsp, flags); /* releases above lock */ | 2127 | rcu_start_gp(rsp, flags); /* releases above lock */ |
2128 | } else { | ||
2129 | local_irq_restore(flags); | ||
2024 | } | 2130 | } |
2025 | 2131 | ||
2026 | /* If there are callbacks ready, invoke them. */ | 2132 | /* If there are callbacks ready, invoke them. */ |
@@ -2719,9 +2825,6 @@ rcu_boot_init_percpu_data(int cpu, struct rcu_state *rsp) | |||
2719 | rdp->dynticks = &per_cpu(rcu_dynticks, cpu); | 2825 | rdp->dynticks = &per_cpu(rcu_dynticks, cpu); |
2720 | WARN_ON_ONCE(rdp->dynticks->dynticks_nesting != DYNTICK_TASK_EXIT_IDLE); | 2826 | WARN_ON_ONCE(rdp->dynticks->dynticks_nesting != DYNTICK_TASK_EXIT_IDLE); |
2721 | WARN_ON_ONCE(atomic_read(&rdp->dynticks->dynticks) != 1); | 2827 | WARN_ON_ONCE(atomic_read(&rdp->dynticks->dynticks) != 1); |
2722 | #ifdef CONFIG_RCU_USER_QS | ||
2723 | WARN_ON_ONCE(rdp->dynticks->in_user); | ||
2724 | #endif | ||
2725 | rdp->cpu = cpu; | 2828 | rdp->cpu = cpu; |
2726 | rdp->rsp = rsp; | 2829 | rdp->rsp = rsp; |
2727 | rcu_boot_init_nocb_percpu_data(rdp); | 2830 | rcu_boot_init_nocb_percpu_data(rdp); |
@@ -2938,6 +3041,10 @@ static void __init rcu_init_one(struct rcu_state *rsp, | |||
2938 | 3041 | ||
2939 | BUILD_BUG_ON(MAX_RCU_LVLS > ARRAY_SIZE(buf)); /* Fix buf[] init! */ | 3042 | BUILD_BUG_ON(MAX_RCU_LVLS > ARRAY_SIZE(buf)); /* Fix buf[] init! */ |
2940 | 3043 | ||
3044 | /* Silence gcc 4.8 warning about array index out of range. */ | ||
3045 | if (rcu_num_lvls > RCU_NUM_LVLS) | ||
3046 | panic("rcu_init_one: rcu_num_lvls overflow"); | ||
3047 | |||
2941 | /* Initialize the level-tracking arrays. */ | 3048 | /* Initialize the level-tracking arrays. */ |
2942 | 3049 | ||
2943 | for (i = 0; i < rcu_num_lvls; i++) | 3050 | for (i = 0; i < rcu_num_lvls; i++) |
@@ -3074,7 +3181,6 @@ void __init rcu_init(void) | |||
3074 | cpu_notifier(rcu_cpu_notify, 0); | 3181 | cpu_notifier(rcu_cpu_notify, 0); |
3075 | for_each_online_cpu(cpu) | 3182 | for_each_online_cpu(cpu) |
3076 | rcu_cpu_notify(NULL, CPU_UP_PREPARE, (void *)(long)cpu); | 3183 | rcu_cpu_notify(NULL, CPU_UP_PREPARE, (void *)(long)cpu); |
3077 | check_cpu_stall_init(); | ||
3078 | } | 3184 | } |
3079 | 3185 | ||
3080 | #include "rcutree_plugin.h" | 3186 | #include "rcutree_plugin.h" |
diff --git a/kernel/rcutree.h b/kernel/rcutree.h index 4b69291b093d..c896b5045d9d 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h | |||
@@ -102,10 +102,6 @@ struct rcu_dynticks { | |||
102 | /* idle-period nonlazy_posted snapshot. */ | 102 | /* idle-period nonlazy_posted snapshot. */ |
103 | int tick_nohz_enabled_snap; /* Previously seen value from sysfs. */ | 103 | int tick_nohz_enabled_snap; /* Previously seen value from sysfs. */ |
104 | #endif /* #ifdef CONFIG_RCU_FAST_NO_HZ */ | 104 | #endif /* #ifdef CONFIG_RCU_FAST_NO_HZ */ |
105 | #ifdef CONFIG_RCU_USER_QS | ||
106 | bool ignore_user_qs; /* Treat userspace as extended QS or not */ | ||
107 | bool in_user; /* Is the CPU in userland from RCU POV? */ | ||
108 | #endif | ||
109 | }; | 105 | }; |
110 | 106 | ||
111 | /* RCU's kthread states for tracing. */ | 107 | /* RCU's kthread states for tracing. */ |
@@ -282,6 +278,8 @@ struct rcu_data { | |||
282 | */ | 278 | */ |
283 | struct rcu_head *nxtlist; | 279 | struct rcu_head *nxtlist; |
284 | struct rcu_head **nxttail[RCU_NEXT_SIZE]; | 280 | struct rcu_head **nxttail[RCU_NEXT_SIZE]; |
281 | unsigned long nxtcompleted[RCU_NEXT_SIZE]; | ||
282 | /* grace periods for sublists. */ | ||
285 | long qlen_lazy; /* # of lazy queued callbacks */ | 283 | long qlen_lazy; /* # of lazy queued callbacks */ |
286 | long qlen; /* # of queued callbacks, incl lazy */ | 284 | long qlen; /* # of queued callbacks, incl lazy */ |
287 | long qlen_last_fqs_check; | 285 | long qlen_last_fqs_check; |
@@ -343,11 +341,6 @@ struct rcu_data { | |||
343 | 341 | ||
344 | #define RCU_JIFFIES_TILL_FORCE_QS 3 /* for rsp->jiffies_force_qs */ | 342 | #define RCU_JIFFIES_TILL_FORCE_QS 3 /* for rsp->jiffies_force_qs */ |
345 | 343 | ||
346 | #ifdef CONFIG_PROVE_RCU | ||
347 | #define RCU_STALL_DELAY_DELTA (5 * HZ) | ||
348 | #else | ||
349 | #define RCU_STALL_DELAY_DELTA 0 | ||
350 | #endif | ||
351 | #define RCU_STALL_RAT_DELAY 2 /* Allow other CPUs time */ | 344 | #define RCU_STALL_RAT_DELAY 2 /* Allow other CPUs time */ |
352 | /* to take at least one */ | 345 | /* to take at least one */ |
353 | /* scheduling clock irq */ | 346 | /* scheduling clock irq */ |
diff --git a/kernel/rtmutex-debug.c b/kernel/rtmutex-debug.c index 16502d3a71c8..13b243a323fa 100644 --- a/kernel/rtmutex-debug.c +++ b/kernel/rtmutex-debug.c | |||
@@ -17,6 +17,7 @@ | |||
17 | * See rt.c in preempt-rt for proper credits and further information | 17 | * See rt.c in preempt-rt for proper credits and further information |
18 | */ | 18 | */ |
19 | #include <linux/sched.h> | 19 | #include <linux/sched.h> |
20 | #include <linux/sched/rt.h> | ||
20 | #include <linux/delay.h> | 21 | #include <linux/delay.h> |
21 | #include <linux/export.h> | 22 | #include <linux/export.h> |
22 | #include <linux/spinlock.h> | 23 | #include <linux/spinlock.h> |
diff --git a/kernel/rtmutex-tester.c b/kernel/rtmutex-tester.c index 98ec49475460..7890b10084a7 100644 --- a/kernel/rtmutex-tester.c +++ b/kernel/rtmutex-tester.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/kthread.h> | 10 | #include <linux/kthread.h> |
11 | #include <linux/export.h> | 11 | #include <linux/export.h> |
12 | #include <linux/sched.h> | 12 | #include <linux/sched.h> |
13 | #include <linux/sched/rt.h> | ||
13 | #include <linux/spinlock.h> | 14 | #include <linux/spinlock.h> |
14 | #include <linux/timer.h> | 15 | #include <linux/timer.h> |
15 | #include <linux/freezer.h> | 16 | #include <linux/freezer.h> |
diff --git a/kernel/rtmutex.c b/kernel/rtmutex.c index a242e691c993..1e09308bf2a1 100644 --- a/kernel/rtmutex.c +++ b/kernel/rtmutex.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/spinlock.h> | 13 | #include <linux/spinlock.h> |
14 | #include <linux/export.h> | 14 | #include <linux/export.h> |
15 | #include <linux/sched.h> | 15 | #include <linux/sched.h> |
16 | #include <linux/sched/rt.h> | ||
16 | #include <linux/timer.h> | 17 | #include <linux/timer.h> |
17 | 18 | ||
18 | #include "rtmutex_common.h" | 19 | #include "rtmutex_common.h" |
diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 26058d0bebba..4a88f1d51563 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c | |||
@@ -4371,7 +4371,7 @@ bool __sched yield_to(struct task_struct *p, bool preempt) | |||
4371 | struct task_struct *curr = current; | 4371 | struct task_struct *curr = current; |
4372 | struct rq *rq, *p_rq; | 4372 | struct rq *rq, *p_rq; |
4373 | unsigned long flags; | 4373 | unsigned long flags; |
4374 | bool yielded = 0; | 4374 | int yielded = 0; |
4375 | 4375 | ||
4376 | local_irq_save(flags); | 4376 | local_irq_save(flags); |
4377 | rq = this_rq(); | 4377 | rq = this_rq(); |
@@ -4667,6 +4667,7 @@ void __cpuinit init_idle(struct task_struct *idle, int cpu) | |||
4667 | */ | 4667 | */ |
4668 | idle->sched_class = &idle_sched_class; | 4668 | idle->sched_class = &idle_sched_class; |
4669 | ftrace_graph_init_idle_task(idle, cpu); | 4669 | ftrace_graph_init_idle_task(idle, cpu); |
4670 | vtime_init_idle(idle); | ||
4670 | #if defined(CONFIG_SMP) | 4671 | #if defined(CONFIG_SMP) |
4671 | sprintf(idle->comm, "%s/%d", INIT_TASK_COMM, cpu); | 4672 | sprintf(idle->comm, "%s/%d", INIT_TASK_COMM, cpu); |
4672 | #endif | 4673 | #endif |
@@ -7508,6 +7509,25 @@ static int sched_rt_global_constraints(void) | |||
7508 | } | 7509 | } |
7509 | #endif /* CONFIG_RT_GROUP_SCHED */ | 7510 | #endif /* CONFIG_RT_GROUP_SCHED */ |
7510 | 7511 | ||
7512 | int sched_rr_handler(struct ctl_table *table, int write, | ||
7513 | void __user *buffer, size_t *lenp, | ||
7514 | loff_t *ppos) | ||
7515 | { | ||
7516 | int ret; | ||
7517 | static DEFINE_MUTEX(mutex); | ||
7518 | |||
7519 | mutex_lock(&mutex); | ||
7520 | ret = proc_dointvec(table, write, buffer, lenp, ppos); | ||
7521 | /* make sure that internally we keep jiffies */ | ||
7522 | /* also, writing zero resets timeslice to default */ | ||
7523 | if (!ret && write) { | ||
7524 | sched_rr_timeslice = sched_rr_timeslice <= 0 ? | ||
7525 | RR_TIMESLICE : msecs_to_jiffies(sched_rr_timeslice); | ||
7526 | } | ||
7527 | mutex_unlock(&mutex); | ||
7528 | return ret; | ||
7529 | } | ||
7530 | |||
7511 | int sched_rt_handler(struct ctl_table *table, int write, | 7531 | int sched_rt_handler(struct ctl_table *table, int write, |
7512 | void __user *buffer, size_t *lenp, | 7532 | void __user *buffer, size_t *lenp, |
7513 | loff_t *ppos) | 7533 | loff_t *ppos) |
diff --git a/kernel/sched/cpupri.c b/kernel/sched/cpupri.c index 23aa789c53ee..1095e878a46f 100644 --- a/kernel/sched/cpupri.c +++ b/kernel/sched/cpupri.c | |||
@@ -28,6 +28,8 @@ | |||
28 | */ | 28 | */ |
29 | 29 | ||
30 | #include <linux/gfp.h> | 30 | #include <linux/gfp.h> |
31 | #include <linux/sched.h> | ||
32 | #include <linux/sched/rt.h> | ||
31 | #include "cpupri.h" | 33 | #include "cpupri.h" |
32 | 34 | ||
33 | /* Convert between a 140 based task->prio, and our 102 based cpupri */ | 35 | /* Convert between a 140 based task->prio, and our 102 based cpupri */ |
diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c index 293b202fcf79..9857329ed280 100644 --- a/kernel/sched/cputime.c +++ b/kernel/sched/cputime.c | |||
@@ -3,6 +3,7 @@ | |||
3 | #include <linux/tsacct_kern.h> | 3 | #include <linux/tsacct_kern.h> |
4 | #include <linux/kernel_stat.h> | 4 | #include <linux/kernel_stat.h> |
5 | #include <linux/static_key.h> | 5 | #include <linux/static_key.h> |
6 | #include <linux/context_tracking.h> | ||
6 | #include "sched.h" | 7 | #include "sched.h" |
7 | 8 | ||
8 | 9 | ||
@@ -163,7 +164,7 @@ void account_user_time(struct task_struct *p, cputime_t cputime, | |||
163 | task_group_account_field(p, index, (__force u64) cputime); | 164 | task_group_account_field(p, index, (__force u64) cputime); |
164 | 165 | ||
165 | /* Account for user time used */ | 166 | /* Account for user time used */ |
166 | acct_update_integrals(p); | 167 | acct_account_cputime(p); |
167 | } | 168 | } |
168 | 169 | ||
169 | /* | 170 | /* |
@@ -213,7 +214,7 @@ void __account_system_time(struct task_struct *p, cputime_t cputime, | |||
213 | task_group_account_field(p, index, (__force u64) cputime); | 214 | task_group_account_field(p, index, (__force u64) cputime); |
214 | 215 | ||
215 | /* Account for system time used */ | 216 | /* Account for system time used */ |
216 | acct_update_integrals(p); | 217 | acct_account_cputime(p); |
217 | } | 218 | } |
218 | 219 | ||
219 | /* | 220 | /* |
@@ -295,6 +296,7 @@ static __always_inline bool steal_account_process_tick(void) | |||
295 | void thread_group_cputime(struct task_struct *tsk, struct task_cputime *times) | 296 | void thread_group_cputime(struct task_struct *tsk, struct task_cputime *times) |
296 | { | 297 | { |
297 | struct signal_struct *sig = tsk->signal; | 298 | struct signal_struct *sig = tsk->signal; |
299 | cputime_t utime, stime; | ||
298 | struct task_struct *t; | 300 | struct task_struct *t; |
299 | 301 | ||
300 | times->utime = sig->utime; | 302 | times->utime = sig->utime; |
@@ -308,16 +310,15 @@ void thread_group_cputime(struct task_struct *tsk, struct task_cputime *times) | |||
308 | 310 | ||
309 | t = tsk; | 311 | t = tsk; |
310 | do { | 312 | do { |
311 | times->utime += t->utime; | 313 | task_cputime(tsk, &utime, &stime); |
312 | times->stime += t->stime; | 314 | times->utime += utime; |
315 | times->stime += stime; | ||
313 | times->sum_exec_runtime += task_sched_runtime(t); | 316 | times->sum_exec_runtime += task_sched_runtime(t); |
314 | } while_each_thread(tsk, t); | 317 | } while_each_thread(tsk, t); |
315 | out: | 318 | out: |
316 | rcu_read_unlock(); | 319 | rcu_read_unlock(); |
317 | } | 320 | } |
318 | 321 | ||
319 | #ifndef CONFIG_VIRT_CPU_ACCOUNTING | ||
320 | |||
321 | #ifdef CONFIG_IRQ_TIME_ACCOUNTING | 322 | #ifdef CONFIG_IRQ_TIME_ACCOUNTING |
322 | /* | 323 | /* |
323 | * Account a tick to a process and cpustat | 324 | * Account a tick to a process and cpustat |
@@ -382,11 +383,12 @@ static void irqtime_account_idle_ticks(int ticks) | |||
382 | irqtime_account_process_tick(current, 0, rq); | 383 | irqtime_account_process_tick(current, 0, rq); |
383 | } | 384 | } |
384 | #else /* CONFIG_IRQ_TIME_ACCOUNTING */ | 385 | #else /* CONFIG_IRQ_TIME_ACCOUNTING */ |
385 | static void irqtime_account_idle_ticks(int ticks) {} | 386 | static inline void irqtime_account_idle_ticks(int ticks) {} |
386 | static void irqtime_account_process_tick(struct task_struct *p, int user_tick, | 387 | static inline void irqtime_account_process_tick(struct task_struct *p, int user_tick, |
387 | struct rq *rq) {} | 388 | struct rq *rq) {} |
388 | #endif /* CONFIG_IRQ_TIME_ACCOUNTING */ | 389 | #endif /* CONFIG_IRQ_TIME_ACCOUNTING */ |
389 | 390 | ||
391 | #ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE | ||
390 | /* | 392 | /* |
391 | * Account a single tick of cpu time. | 393 | * Account a single tick of cpu time. |
392 | * @p: the process that the cpu time gets accounted to | 394 | * @p: the process that the cpu time gets accounted to |
@@ -397,6 +399,9 @@ void account_process_tick(struct task_struct *p, int user_tick) | |||
397 | cputime_t one_jiffy_scaled = cputime_to_scaled(cputime_one_jiffy); | 399 | cputime_t one_jiffy_scaled = cputime_to_scaled(cputime_one_jiffy); |
398 | struct rq *rq = this_rq(); | 400 | struct rq *rq = this_rq(); |
399 | 401 | ||
402 | if (vtime_accounting_enabled()) | ||
403 | return; | ||
404 | |||
400 | if (sched_clock_irqtime) { | 405 | if (sched_clock_irqtime) { |
401 | irqtime_account_process_tick(p, user_tick, rq); | 406 | irqtime_account_process_tick(p, user_tick, rq); |
402 | return; | 407 | return; |
@@ -438,8 +443,7 @@ void account_idle_ticks(unsigned long ticks) | |||
438 | 443 | ||
439 | account_idle_time(jiffies_to_cputime(ticks)); | 444 | account_idle_time(jiffies_to_cputime(ticks)); |
440 | } | 445 | } |
441 | 446 | #endif /* !CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */ | |
442 | #endif | ||
443 | 447 | ||
444 | /* | 448 | /* |
445 | * Use precise platform statistics if available: | 449 | * Use precise platform statistics if available: |
@@ -461,25 +465,20 @@ void thread_group_cputime_adjusted(struct task_struct *p, cputime_t *ut, cputime | |||
461 | *st = cputime.stime; | 465 | *st = cputime.stime; |
462 | } | 466 | } |
463 | 467 | ||
464 | void vtime_account_system_irqsafe(struct task_struct *tsk) | ||
465 | { | ||
466 | unsigned long flags; | ||
467 | |||
468 | local_irq_save(flags); | ||
469 | vtime_account_system(tsk); | ||
470 | local_irq_restore(flags); | ||
471 | } | ||
472 | EXPORT_SYMBOL_GPL(vtime_account_system_irqsafe); | ||
473 | |||
474 | #ifndef __ARCH_HAS_VTIME_TASK_SWITCH | 468 | #ifndef __ARCH_HAS_VTIME_TASK_SWITCH |
475 | void vtime_task_switch(struct task_struct *prev) | 469 | void vtime_task_switch(struct task_struct *prev) |
476 | { | 470 | { |
471 | if (!vtime_accounting_enabled()) | ||
472 | return; | ||
473 | |||
477 | if (is_idle_task(prev)) | 474 | if (is_idle_task(prev)) |
478 | vtime_account_idle(prev); | 475 | vtime_account_idle(prev); |
479 | else | 476 | else |
480 | vtime_account_system(prev); | 477 | vtime_account_system(prev); |
481 | 478 | ||
479 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE | ||
482 | vtime_account_user(prev); | 480 | vtime_account_user(prev); |
481 | #endif | ||
483 | arch_vtime_task_switch(prev); | 482 | arch_vtime_task_switch(prev); |
484 | } | 483 | } |
485 | #endif | 484 | #endif |
@@ -493,27 +492,40 @@ void vtime_task_switch(struct task_struct *prev) | |||
493 | * vtime_account(). | 492 | * vtime_account(). |
494 | */ | 493 | */ |
495 | #ifndef __ARCH_HAS_VTIME_ACCOUNT | 494 | #ifndef __ARCH_HAS_VTIME_ACCOUNT |
496 | void vtime_account(struct task_struct *tsk) | 495 | void vtime_account_irq_enter(struct task_struct *tsk) |
497 | { | 496 | { |
498 | if (in_interrupt() || !is_idle_task(tsk)) | 497 | if (!vtime_accounting_enabled()) |
499 | vtime_account_system(tsk); | 498 | return; |
500 | else | 499 | |
501 | vtime_account_idle(tsk); | 500 | if (!in_interrupt()) { |
501 | /* | ||
502 | * If we interrupted user, context_tracking_in_user() | ||
503 | * is 1 because the context tracking don't hook | ||
504 | * on irq entry/exit. This way we know if | ||
505 | * we need to flush user time on kernel entry. | ||
506 | */ | ||
507 | if (context_tracking_in_user()) { | ||
508 | vtime_account_user(tsk); | ||
509 | return; | ||
510 | } | ||
511 | |||
512 | if (is_idle_task(tsk)) { | ||
513 | vtime_account_idle(tsk); | ||
514 | return; | ||
515 | } | ||
516 | } | ||
517 | vtime_account_system(tsk); | ||
502 | } | 518 | } |
503 | EXPORT_SYMBOL_GPL(vtime_account); | 519 | EXPORT_SYMBOL_GPL(vtime_account_irq_enter); |
504 | #endif /* __ARCH_HAS_VTIME_ACCOUNT */ | 520 | #endif /* __ARCH_HAS_VTIME_ACCOUNT */ |
505 | 521 | ||
506 | #else | 522 | #else /* !CONFIG_VIRT_CPU_ACCOUNTING */ |
507 | |||
508 | #ifndef nsecs_to_cputime | ||
509 | # define nsecs_to_cputime(__nsecs) nsecs_to_jiffies(__nsecs) | ||
510 | #endif | ||
511 | 523 | ||
512 | static cputime_t scale_utime(cputime_t utime, cputime_t rtime, cputime_t total) | 524 | static cputime_t scale_stime(cputime_t stime, cputime_t rtime, cputime_t total) |
513 | { | 525 | { |
514 | u64 temp = (__force u64) rtime; | 526 | u64 temp = (__force u64) rtime; |
515 | 527 | ||
516 | temp *= (__force u64) utime; | 528 | temp *= (__force u64) stime; |
517 | 529 | ||
518 | if (sizeof(cputime_t) == 4) | 530 | if (sizeof(cputime_t) == 4) |
519 | temp = div_u64(temp, (__force u32) total); | 531 | temp = div_u64(temp, (__force u32) total); |
@@ -531,10 +543,10 @@ static void cputime_adjust(struct task_cputime *curr, | |||
531 | struct cputime *prev, | 543 | struct cputime *prev, |
532 | cputime_t *ut, cputime_t *st) | 544 | cputime_t *ut, cputime_t *st) |
533 | { | 545 | { |
534 | cputime_t rtime, utime, total; | 546 | cputime_t rtime, stime, total; |
535 | 547 | ||
536 | utime = curr->utime; | 548 | stime = curr->stime; |
537 | total = utime + curr->stime; | 549 | total = stime + curr->utime; |
538 | 550 | ||
539 | /* | 551 | /* |
540 | * Tick based cputime accounting depend on random scheduling | 552 | * Tick based cputime accounting depend on random scheduling |
@@ -549,17 +561,17 @@ static void cputime_adjust(struct task_cputime *curr, | |||
549 | rtime = nsecs_to_cputime(curr->sum_exec_runtime); | 561 | rtime = nsecs_to_cputime(curr->sum_exec_runtime); |
550 | 562 | ||
551 | if (total) | 563 | if (total) |
552 | utime = scale_utime(utime, rtime, total); | 564 | stime = scale_stime(stime, rtime, total); |
553 | else | 565 | else |
554 | utime = rtime; | 566 | stime = rtime; |
555 | 567 | ||
556 | /* | 568 | /* |
557 | * If the tick based count grows faster than the scheduler one, | 569 | * If the tick based count grows faster than the scheduler one, |
558 | * the result of the scaling may go backward. | 570 | * the result of the scaling may go backward. |
559 | * Let's enforce monotonicity. | 571 | * Let's enforce monotonicity. |
560 | */ | 572 | */ |
561 | prev->utime = max(prev->utime, utime); | 573 | prev->stime = max(prev->stime, stime); |
562 | prev->stime = max(prev->stime, rtime - prev->utime); | 574 | prev->utime = max(prev->utime, rtime - prev->stime); |
563 | 575 | ||
564 | *ut = prev->utime; | 576 | *ut = prev->utime; |
565 | *st = prev->stime; | 577 | *st = prev->stime; |
@@ -568,11 +580,10 @@ static void cputime_adjust(struct task_cputime *curr, | |||
568 | void task_cputime_adjusted(struct task_struct *p, cputime_t *ut, cputime_t *st) | 580 | void task_cputime_adjusted(struct task_struct *p, cputime_t *ut, cputime_t *st) |
569 | { | 581 | { |
570 | struct task_cputime cputime = { | 582 | struct task_cputime cputime = { |
571 | .utime = p->utime, | ||
572 | .stime = p->stime, | ||
573 | .sum_exec_runtime = p->se.sum_exec_runtime, | 583 | .sum_exec_runtime = p->se.sum_exec_runtime, |
574 | }; | 584 | }; |
575 | 585 | ||
586 | task_cputime(p, &cputime.utime, &cputime.stime); | ||
576 | cputime_adjust(&cputime, &p->prev_cputime, ut, st); | 587 | cputime_adjust(&cputime, &p->prev_cputime, ut, st); |
577 | } | 588 | } |
578 | 589 | ||
@@ -586,4 +597,221 @@ void thread_group_cputime_adjusted(struct task_struct *p, cputime_t *ut, cputime | |||
586 | thread_group_cputime(p, &cputime); | 597 | thread_group_cputime(p, &cputime); |
587 | cputime_adjust(&cputime, &p->signal->prev_cputime, ut, st); | 598 | cputime_adjust(&cputime, &p->signal->prev_cputime, ut, st); |
588 | } | 599 | } |
589 | #endif | 600 | #endif /* !CONFIG_VIRT_CPU_ACCOUNTING */ |
601 | |||
602 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN | ||
603 | static unsigned long long vtime_delta(struct task_struct *tsk) | ||
604 | { | ||
605 | unsigned long long clock; | ||
606 | |||
607 | clock = sched_clock(); | ||
608 | if (clock < tsk->vtime_snap) | ||
609 | return 0; | ||
610 | |||
611 | return clock - tsk->vtime_snap; | ||
612 | } | ||
613 | |||
614 | static cputime_t get_vtime_delta(struct task_struct *tsk) | ||
615 | { | ||
616 | unsigned long long delta = vtime_delta(tsk); | ||
617 | |||
618 | WARN_ON_ONCE(tsk->vtime_snap_whence == VTIME_SLEEPING); | ||
619 | tsk->vtime_snap += delta; | ||
620 | |||
621 | /* CHECKME: always safe to convert nsecs to cputime? */ | ||
622 | return nsecs_to_cputime(delta); | ||
623 | } | ||
624 | |||
625 | static void __vtime_account_system(struct task_struct *tsk) | ||
626 | { | ||
627 | cputime_t delta_cpu = get_vtime_delta(tsk); | ||
628 | |||
629 | account_system_time(tsk, irq_count(), delta_cpu, cputime_to_scaled(delta_cpu)); | ||
630 | } | ||
631 | |||
632 | void vtime_account_system(struct task_struct *tsk) | ||
633 | { | ||
634 | if (!vtime_accounting_enabled()) | ||
635 | return; | ||
636 | |||
637 | write_seqlock(&tsk->vtime_seqlock); | ||
638 | __vtime_account_system(tsk); | ||
639 | write_sequnlock(&tsk->vtime_seqlock); | ||
640 | } | ||
641 | |||
642 | void vtime_account_irq_exit(struct task_struct *tsk) | ||
643 | { | ||
644 | if (!vtime_accounting_enabled()) | ||
645 | return; | ||
646 | |||
647 | write_seqlock(&tsk->vtime_seqlock); | ||
648 | if (context_tracking_in_user()) | ||
649 | tsk->vtime_snap_whence = VTIME_USER; | ||
650 | __vtime_account_system(tsk); | ||
651 | write_sequnlock(&tsk->vtime_seqlock); | ||
652 | } | ||
653 | |||
654 | void vtime_account_user(struct task_struct *tsk) | ||
655 | { | ||
656 | cputime_t delta_cpu; | ||
657 | |||
658 | if (!vtime_accounting_enabled()) | ||
659 | return; | ||
660 | |||
661 | delta_cpu = get_vtime_delta(tsk); | ||
662 | |||
663 | write_seqlock(&tsk->vtime_seqlock); | ||
664 | tsk->vtime_snap_whence = VTIME_SYS; | ||
665 | account_user_time(tsk, delta_cpu, cputime_to_scaled(delta_cpu)); | ||
666 | write_sequnlock(&tsk->vtime_seqlock); | ||
667 | } | ||
668 | |||
669 | void vtime_user_enter(struct task_struct *tsk) | ||
670 | { | ||
671 | if (!vtime_accounting_enabled()) | ||
672 | return; | ||
673 | |||
674 | write_seqlock(&tsk->vtime_seqlock); | ||
675 | tsk->vtime_snap_whence = VTIME_USER; | ||
676 | __vtime_account_system(tsk); | ||
677 | write_sequnlock(&tsk->vtime_seqlock); | ||
678 | } | ||
679 | |||
680 | void vtime_guest_enter(struct task_struct *tsk) | ||
681 | { | ||
682 | write_seqlock(&tsk->vtime_seqlock); | ||
683 | __vtime_account_system(tsk); | ||
684 | current->flags |= PF_VCPU; | ||
685 | write_sequnlock(&tsk->vtime_seqlock); | ||
686 | } | ||
687 | |||
688 | void vtime_guest_exit(struct task_struct *tsk) | ||
689 | { | ||
690 | write_seqlock(&tsk->vtime_seqlock); | ||
691 | __vtime_account_system(tsk); | ||
692 | current->flags &= ~PF_VCPU; | ||
693 | write_sequnlock(&tsk->vtime_seqlock); | ||
694 | } | ||
695 | |||
696 | void vtime_account_idle(struct task_struct *tsk) | ||
697 | { | ||
698 | cputime_t delta_cpu = get_vtime_delta(tsk); | ||
699 | |||
700 | account_idle_time(delta_cpu); | ||
701 | } | ||
702 | |||
703 | bool vtime_accounting_enabled(void) | ||
704 | { | ||
705 | return context_tracking_active(); | ||
706 | } | ||
707 | |||
708 | void arch_vtime_task_switch(struct task_struct *prev) | ||
709 | { | ||
710 | write_seqlock(&prev->vtime_seqlock); | ||
711 | prev->vtime_snap_whence = VTIME_SLEEPING; | ||
712 | write_sequnlock(&prev->vtime_seqlock); | ||
713 | |||
714 | write_seqlock(¤t->vtime_seqlock); | ||
715 | current->vtime_snap_whence = VTIME_SYS; | ||
716 | current->vtime_snap = sched_clock(); | ||
717 | write_sequnlock(¤t->vtime_seqlock); | ||
718 | } | ||
719 | |||
720 | void vtime_init_idle(struct task_struct *t) | ||
721 | { | ||
722 | unsigned long flags; | ||
723 | |||
724 | write_seqlock_irqsave(&t->vtime_seqlock, flags); | ||
725 | t->vtime_snap_whence = VTIME_SYS; | ||
726 | t->vtime_snap = sched_clock(); | ||
727 | write_sequnlock_irqrestore(&t->vtime_seqlock, flags); | ||
728 | } | ||
729 | |||
730 | cputime_t task_gtime(struct task_struct *t) | ||
731 | { | ||
732 | unsigned int seq; | ||
733 | cputime_t gtime; | ||
734 | |||
735 | do { | ||
736 | seq = read_seqbegin(&t->vtime_seqlock); | ||
737 | |||
738 | gtime = t->gtime; | ||
739 | if (t->flags & PF_VCPU) | ||
740 | gtime += vtime_delta(t); | ||
741 | |||
742 | } while (read_seqretry(&t->vtime_seqlock, seq)); | ||
743 | |||
744 | return gtime; | ||
745 | } | ||
746 | |||
747 | /* | ||
748 | * Fetch cputime raw values from fields of task_struct and | ||
749 | * add up the pending nohz execution time since the last | ||
750 | * cputime snapshot. | ||
751 | */ | ||
752 | static void | ||
753 | fetch_task_cputime(struct task_struct *t, | ||
754 | cputime_t *u_dst, cputime_t *s_dst, | ||
755 | cputime_t *u_src, cputime_t *s_src, | ||
756 | cputime_t *udelta, cputime_t *sdelta) | ||
757 | { | ||
758 | unsigned int seq; | ||
759 | unsigned long long delta; | ||
760 | |||
761 | do { | ||
762 | *udelta = 0; | ||
763 | *sdelta = 0; | ||
764 | |||
765 | seq = read_seqbegin(&t->vtime_seqlock); | ||
766 | |||
767 | if (u_dst) | ||
768 | *u_dst = *u_src; | ||
769 | if (s_dst) | ||
770 | *s_dst = *s_src; | ||
771 | |||
772 | /* Task is sleeping, nothing to add */ | ||
773 | if (t->vtime_snap_whence == VTIME_SLEEPING || | ||
774 | is_idle_task(t)) | ||
775 | continue; | ||
776 | |||
777 | delta = vtime_delta(t); | ||
778 | |||
779 | /* | ||
780 | * Task runs either in user or kernel space, add pending nohz time to | ||
781 | * the right place. | ||
782 | */ | ||
783 | if (t->vtime_snap_whence == VTIME_USER || t->flags & PF_VCPU) { | ||
784 | *udelta = delta; | ||
785 | } else { | ||
786 | if (t->vtime_snap_whence == VTIME_SYS) | ||
787 | *sdelta = delta; | ||
788 | } | ||
789 | } while (read_seqretry(&t->vtime_seqlock, seq)); | ||
790 | } | ||
791 | |||
792 | |||
793 | void task_cputime(struct task_struct *t, cputime_t *utime, cputime_t *stime) | ||
794 | { | ||
795 | cputime_t udelta, sdelta; | ||
796 | |||
797 | fetch_task_cputime(t, utime, stime, &t->utime, | ||
798 | &t->stime, &udelta, &sdelta); | ||
799 | if (utime) | ||
800 | *utime += udelta; | ||
801 | if (stime) | ||
802 | *stime += sdelta; | ||
803 | } | ||
804 | |||
805 | void task_cputime_scaled(struct task_struct *t, | ||
806 | cputime_t *utimescaled, cputime_t *stimescaled) | ||
807 | { | ||
808 | cputime_t udelta, sdelta; | ||
809 | |||
810 | fetch_task_cputime(t, utimescaled, stimescaled, | ||
811 | &t->utimescaled, &t->stimescaled, &udelta, &sdelta); | ||
812 | if (utimescaled) | ||
813 | *utimescaled += cputime_to_scaled(udelta); | ||
814 | if (stimescaled) | ||
815 | *stimescaled += cputime_to_scaled(sdelta); | ||
816 | } | ||
817 | #endif /* CONFIG_VIRT_CPU_ACCOUNTING_GEN */ | ||
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 81fa53643409..7a33e5986fc5 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c | |||
@@ -1680,9 +1680,7 @@ place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int initial) | |||
1680 | } | 1680 | } |
1681 | 1681 | ||
1682 | /* ensure we never gain time by being placed backwards. */ | 1682 | /* ensure we never gain time by being placed backwards. */ |
1683 | vruntime = max_vruntime(se->vruntime, vruntime); | 1683 | se->vruntime = max_vruntime(se->vruntime, vruntime); |
1684 | |||
1685 | se->vruntime = vruntime; | ||
1686 | } | 1684 | } |
1687 | 1685 | ||
1688 | static void check_enqueue_throttle(struct cfs_rq *cfs_rq); | 1686 | static void check_enqueue_throttle(struct cfs_rq *cfs_rq); |
@@ -3254,25 +3252,18 @@ find_idlest_cpu(struct sched_group *group, struct task_struct *p, int this_cpu) | |||
3254 | */ | 3252 | */ |
3255 | static int select_idle_sibling(struct task_struct *p, int target) | 3253 | static int select_idle_sibling(struct task_struct *p, int target) |
3256 | { | 3254 | { |
3257 | int cpu = smp_processor_id(); | ||
3258 | int prev_cpu = task_cpu(p); | ||
3259 | struct sched_domain *sd; | 3255 | struct sched_domain *sd; |
3260 | struct sched_group *sg; | 3256 | struct sched_group *sg; |
3261 | int i; | 3257 | int i = task_cpu(p); |
3262 | 3258 | ||
3263 | /* | 3259 | if (idle_cpu(target)) |
3264 | * If the task is going to be woken-up on this cpu and if it is | 3260 | return target; |
3265 | * already idle, then it is the right target. | ||
3266 | */ | ||
3267 | if (target == cpu && idle_cpu(cpu)) | ||
3268 | return cpu; | ||
3269 | 3261 | ||
3270 | /* | 3262 | /* |
3271 | * If the task is going to be woken-up on the cpu where it previously | 3263 | * If the prevous cpu is cache affine and idle, don't be stupid. |
3272 | * ran and if it is currently idle, then it the right target. | ||
3273 | */ | 3264 | */ |
3274 | if (target == prev_cpu && idle_cpu(prev_cpu)) | 3265 | if (i != target && cpus_share_cache(i, target) && idle_cpu(i)) |
3275 | return prev_cpu; | 3266 | return i; |
3276 | 3267 | ||
3277 | /* | 3268 | /* |
3278 | * Otherwise, iterate the domains and find an elegible idle cpu. | 3269 | * Otherwise, iterate the domains and find an elegible idle cpu. |
@@ -3286,7 +3277,7 @@ static int select_idle_sibling(struct task_struct *p, int target) | |||
3286 | goto next; | 3277 | goto next; |
3287 | 3278 | ||
3288 | for_each_cpu(i, sched_group_cpus(sg)) { | 3279 | for_each_cpu(i, sched_group_cpus(sg)) { |
3289 | if (!idle_cpu(i)) | 3280 | if (i == target || !idle_cpu(i)) |
3290 | goto next; | 3281 | goto next; |
3291 | } | 3282 | } |
3292 | 3283 | ||
@@ -6101,7 +6092,7 @@ static unsigned int get_rr_interval_fair(struct rq *rq, struct task_struct *task | |||
6101 | * idle runqueue: | 6092 | * idle runqueue: |
6102 | */ | 6093 | */ |
6103 | if (rq->cfs.load.weight) | 6094 | if (rq->cfs.load.weight) |
6104 | rr_interval = NS_TO_JIFFIES(sched_slice(&rq->cfs, se)); | 6095 | rr_interval = NS_TO_JIFFIES(sched_slice(cfs_rq_of(se), se)); |
6105 | 6096 | ||
6106 | return rr_interval; | 6097 | return rr_interval; |
6107 | } | 6098 | } |
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c index 4f02b2847357..127a2c4cf4ab 100644 --- a/kernel/sched/rt.c +++ b/kernel/sched/rt.c | |||
@@ -7,6 +7,8 @@ | |||
7 | 7 | ||
8 | #include <linux/slab.h> | 8 | #include <linux/slab.h> |
9 | 9 | ||
10 | int sched_rr_timeslice = RR_TIMESLICE; | ||
11 | |||
10 | static int do_sched_rt_period_timer(struct rt_bandwidth *rt_b, int overrun); | 12 | static int do_sched_rt_period_timer(struct rt_bandwidth *rt_b, int overrun); |
11 | 13 | ||
12 | struct rt_bandwidth def_rt_bandwidth; | 14 | struct rt_bandwidth def_rt_bandwidth; |
@@ -925,8 +927,8 @@ static void update_curr_rt(struct rq *rq) | |||
925 | return; | 927 | return; |
926 | 928 | ||
927 | delta_exec = rq->clock_task - curr->se.exec_start; | 929 | delta_exec = rq->clock_task - curr->se.exec_start; |
928 | if (unlikely((s64)delta_exec < 0)) | 930 | if (unlikely((s64)delta_exec <= 0)) |
929 | delta_exec = 0; | 931 | return; |
930 | 932 | ||
931 | schedstat_set(curr->se.statistics.exec_max, | 933 | schedstat_set(curr->se.statistics.exec_max, |
932 | max(curr->se.statistics.exec_max, delta_exec)); | 934 | max(curr->se.statistics.exec_max, delta_exec)); |
@@ -1427,8 +1429,7 @@ static void put_prev_task_rt(struct rq *rq, struct task_struct *p) | |||
1427 | static int pick_rt_task(struct rq *rq, struct task_struct *p, int cpu) | 1429 | static int pick_rt_task(struct rq *rq, struct task_struct *p, int cpu) |
1428 | { | 1430 | { |
1429 | if (!task_running(rq, p) && | 1431 | if (!task_running(rq, p) && |
1430 | (cpu < 0 || cpumask_test_cpu(cpu, tsk_cpus_allowed(p))) && | 1432 | cpumask_test_cpu(cpu, tsk_cpus_allowed(p))) |
1431 | (p->nr_cpus_allowed > 1)) | ||
1432 | return 1; | 1433 | return 1; |
1433 | return 0; | 1434 | return 0; |
1434 | } | 1435 | } |
@@ -1889,8 +1890,11 @@ static void switched_from_rt(struct rq *rq, struct task_struct *p) | |||
1889 | * we may need to handle the pulling of RT tasks | 1890 | * we may need to handle the pulling of RT tasks |
1890 | * now. | 1891 | * now. |
1891 | */ | 1892 | */ |
1892 | if (p->on_rq && !rq->rt.rt_nr_running) | 1893 | if (!p->on_rq || rq->rt.rt_nr_running) |
1893 | pull_rt_task(rq); | 1894 | return; |
1895 | |||
1896 | if (pull_rt_task(rq)) | ||
1897 | resched_task(rq->curr); | ||
1894 | } | 1898 | } |
1895 | 1899 | ||
1896 | void init_sched_rt_class(void) | 1900 | void init_sched_rt_class(void) |
@@ -1985,7 +1989,11 @@ static void watchdog(struct rq *rq, struct task_struct *p) | |||
1985 | if (soft != RLIM_INFINITY) { | 1989 | if (soft != RLIM_INFINITY) { |
1986 | unsigned long next; | 1990 | unsigned long next; |
1987 | 1991 | ||
1988 | p->rt.timeout++; | 1992 | if (p->rt.watchdog_stamp != jiffies) { |
1993 | p->rt.timeout++; | ||
1994 | p->rt.watchdog_stamp = jiffies; | ||
1995 | } | ||
1996 | |||
1989 | next = DIV_ROUND_UP(min(soft, hard), USEC_PER_SEC/HZ); | 1997 | next = DIV_ROUND_UP(min(soft, hard), USEC_PER_SEC/HZ); |
1990 | if (p->rt.timeout > next) | 1998 | if (p->rt.timeout > next) |
1991 | p->cputime_expires.sched_exp = p->se.sum_exec_runtime; | 1999 | p->cputime_expires.sched_exp = p->se.sum_exec_runtime; |
@@ -2010,7 +2018,7 @@ static void task_tick_rt(struct rq *rq, struct task_struct *p, int queued) | |||
2010 | if (--p->rt.time_slice) | 2018 | if (--p->rt.time_slice) |
2011 | return; | 2019 | return; |
2012 | 2020 | ||
2013 | p->rt.time_slice = RR_TIMESLICE; | 2021 | p->rt.time_slice = sched_rr_timeslice; |
2014 | 2022 | ||
2015 | /* | 2023 | /* |
2016 | * Requeue to the end of queue if we (and all of our ancestors) are the | 2024 | * Requeue to the end of queue if we (and all of our ancestors) are the |
@@ -2041,7 +2049,7 @@ static unsigned int get_rr_interval_rt(struct rq *rq, struct task_struct *task) | |||
2041 | * Time slice is 0 for SCHED_FIFO tasks | 2049 | * Time slice is 0 for SCHED_FIFO tasks |
2042 | */ | 2050 | */ |
2043 | if (task->policy == SCHED_RR) | 2051 | if (task->policy == SCHED_RR) |
2044 | return RR_TIMESLICE; | 2052 | return sched_rr_timeslice; |
2045 | else | 2053 | else |
2046 | return 0; | 2054 | return 0; |
2047 | } | 2055 | } |
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index fc886441436a..cc03cfdf469f 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h | |||
@@ -1,5 +1,7 @@ | |||
1 | 1 | ||
2 | #include <linux/sched.h> | 2 | #include <linux/sched.h> |
3 | #include <linux/sched/sysctl.h> | ||
4 | #include <linux/sched/rt.h> | ||
3 | #include <linux/mutex.h> | 5 | #include <linux/mutex.h> |
4 | #include <linux/spinlock.h> | 6 | #include <linux/spinlock.h> |
5 | #include <linux/stop_machine.h> | 7 | #include <linux/stop_machine.h> |
diff --git a/kernel/signal.c b/kernel/signal.c index 3d09cf6cde75..7f82adbad480 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
@@ -1632,6 +1632,7 @@ bool do_notify_parent(struct task_struct *tsk, int sig) | |||
1632 | unsigned long flags; | 1632 | unsigned long flags; |
1633 | struct sighand_struct *psig; | 1633 | struct sighand_struct *psig; |
1634 | bool autoreap = false; | 1634 | bool autoreap = false; |
1635 | cputime_t utime, stime; | ||
1635 | 1636 | ||
1636 | BUG_ON(sig == -1); | 1637 | BUG_ON(sig == -1); |
1637 | 1638 | ||
@@ -1669,8 +1670,9 @@ bool do_notify_parent(struct task_struct *tsk, int sig) | |||
1669 | task_uid(tsk)); | 1670 | task_uid(tsk)); |
1670 | rcu_read_unlock(); | 1671 | rcu_read_unlock(); |
1671 | 1672 | ||
1672 | info.si_utime = cputime_to_clock_t(tsk->utime + tsk->signal->utime); | 1673 | task_cputime(tsk, &utime, &stime); |
1673 | info.si_stime = cputime_to_clock_t(tsk->stime + tsk->signal->stime); | 1674 | info.si_utime = cputime_to_clock_t(utime + tsk->signal->utime); |
1675 | info.si_stime = cputime_to_clock_t(stime + tsk->signal->stime); | ||
1674 | 1676 | ||
1675 | info.si_status = tsk->exit_code & 0x7f; | 1677 | info.si_status = tsk->exit_code & 0x7f; |
1676 | if (tsk->exit_code & 0x80) | 1678 | if (tsk->exit_code & 0x80) |
@@ -1734,6 +1736,7 @@ static void do_notify_parent_cldstop(struct task_struct *tsk, | |||
1734 | unsigned long flags; | 1736 | unsigned long flags; |
1735 | struct task_struct *parent; | 1737 | struct task_struct *parent; |
1736 | struct sighand_struct *sighand; | 1738 | struct sighand_struct *sighand; |
1739 | cputime_t utime, stime; | ||
1737 | 1740 | ||
1738 | if (for_ptracer) { | 1741 | if (for_ptracer) { |
1739 | parent = tsk->parent; | 1742 | parent = tsk->parent; |
@@ -1752,8 +1755,9 @@ static void do_notify_parent_cldstop(struct task_struct *tsk, | |||
1752 | info.si_uid = from_kuid_munged(task_cred_xxx(parent, user_ns), task_uid(tsk)); | 1755 | info.si_uid = from_kuid_munged(task_cred_xxx(parent, user_ns), task_uid(tsk)); |
1753 | rcu_read_unlock(); | 1756 | rcu_read_unlock(); |
1754 | 1757 | ||
1755 | info.si_utime = cputime_to_clock_t(tsk->utime); | 1758 | task_cputime(tsk, &utime, &stime); |
1756 | info.si_stime = cputime_to_clock_t(tsk->stime); | 1759 | info.si_utime = cputime_to_clock_t(utime); |
1760 | info.si_stime = cputime_to_clock_t(stime); | ||
1757 | 1761 | ||
1758 | info.si_code = why; | 1762 | info.si_code = why; |
1759 | switch (why) { | 1763 | switch (why) { |
diff --git a/kernel/smpboot.c b/kernel/smpboot.c index d6c5fc054242..d4abac261779 100644 --- a/kernel/smpboot.c +++ b/kernel/smpboot.c | |||
@@ -183,9 +183,10 @@ __smpboot_create_thread(struct smp_hotplug_thread *ht, unsigned int cpu) | |||
183 | kfree(td); | 183 | kfree(td); |
184 | return PTR_ERR(tsk); | 184 | return PTR_ERR(tsk); |
185 | } | 185 | } |
186 | |||
187 | get_task_struct(tsk); | 186 | get_task_struct(tsk); |
188 | *per_cpu_ptr(ht->store, cpu) = tsk; | 187 | *per_cpu_ptr(ht->store, cpu) = tsk; |
188 | if (ht->create) | ||
189 | ht->create(cpu); | ||
189 | return 0; | 190 | return 0; |
190 | } | 191 | } |
191 | 192 | ||
@@ -225,7 +226,7 @@ static void smpboot_park_thread(struct smp_hotplug_thread *ht, unsigned int cpu) | |||
225 | { | 226 | { |
226 | struct task_struct *tsk = *per_cpu_ptr(ht->store, cpu); | 227 | struct task_struct *tsk = *per_cpu_ptr(ht->store, cpu); |
227 | 228 | ||
228 | if (tsk) | 229 | if (tsk && !ht->selfparking) |
229 | kthread_park(tsk); | 230 | kthread_park(tsk); |
230 | } | 231 | } |
231 | 232 | ||
diff --git a/kernel/softirq.c b/kernel/softirq.c index ed567babe789..f5cc25f147a6 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c | |||
@@ -221,7 +221,7 @@ asmlinkage void __do_softirq(void) | |||
221 | current->flags &= ~PF_MEMALLOC; | 221 | current->flags &= ~PF_MEMALLOC; |
222 | 222 | ||
223 | pending = local_softirq_pending(); | 223 | pending = local_softirq_pending(); |
224 | vtime_account_irq_enter(current); | 224 | account_irq_enter_time(current); |
225 | 225 | ||
226 | __local_bh_disable((unsigned long)__builtin_return_address(0), | 226 | __local_bh_disable((unsigned long)__builtin_return_address(0), |
227 | SOFTIRQ_OFFSET); | 227 | SOFTIRQ_OFFSET); |
@@ -272,7 +272,7 @@ restart: | |||
272 | 272 | ||
273 | lockdep_softirq_exit(); | 273 | lockdep_softirq_exit(); |
274 | 274 | ||
275 | vtime_account_irq_exit(current); | 275 | account_irq_exit_time(current); |
276 | __local_bh_enable(SOFTIRQ_OFFSET); | 276 | __local_bh_enable(SOFTIRQ_OFFSET); |
277 | tsk_restore_flags(current, old_flags, PF_MEMALLOC); | 277 | tsk_restore_flags(current, old_flags, PF_MEMALLOC); |
278 | } | 278 | } |
@@ -341,7 +341,7 @@ static inline void invoke_softirq(void) | |||
341 | */ | 341 | */ |
342 | void irq_exit(void) | 342 | void irq_exit(void) |
343 | { | 343 | { |
344 | vtime_account_irq_exit(current); | 344 | account_irq_exit_time(current); |
345 | trace_hardirq_exit(); | 345 | trace_hardirq_exit(); |
346 | sub_preempt_count(IRQ_EXIT_OFFSET); | 346 | sub_preempt_count(IRQ_EXIT_OFFSET); |
347 | if (!in_interrupt() && local_softirq_pending()) | 347 | if (!in_interrupt() && local_softirq_pending()) |
diff --git a/kernel/srcu.c b/kernel/srcu.c index 2b859828cdc3..01d5ccb8bfe3 100644 --- a/kernel/srcu.c +++ b/kernel/srcu.c | |||
@@ -282,12 +282,8 @@ static int srcu_readers_active(struct srcu_struct *sp) | |||
282 | */ | 282 | */ |
283 | void cleanup_srcu_struct(struct srcu_struct *sp) | 283 | void cleanup_srcu_struct(struct srcu_struct *sp) |
284 | { | 284 | { |
285 | int sum; | 285 | if (WARN_ON(srcu_readers_active(sp))) |
286 | 286 | return; /* Leakage unless caller handles error. */ | |
287 | sum = srcu_readers_active(sp); | ||
288 | WARN_ON(sum); /* Leakage unless caller handles error. */ | ||
289 | if (sum != 0) | ||
290 | return; | ||
291 | free_percpu(sp->per_cpu_ref); | 287 | free_percpu(sp->per_cpu_ref); |
292 | sp->per_cpu_ref = NULL; | 288 | sp->per_cpu_ref = NULL; |
293 | } | 289 | } |
@@ -302,9 +298,8 @@ int __srcu_read_lock(struct srcu_struct *sp) | |||
302 | { | 298 | { |
303 | int idx; | 299 | int idx; |
304 | 300 | ||
301 | idx = ACCESS_ONCE(sp->completed) & 0x1; | ||
305 | preempt_disable(); | 302 | preempt_disable(); |
306 | idx = rcu_dereference_index_check(sp->completed, | ||
307 | rcu_read_lock_sched_held()) & 0x1; | ||
308 | ACCESS_ONCE(this_cpu_ptr(sp->per_cpu_ref)->c[idx]) += 1; | 303 | ACCESS_ONCE(this_cpu_ptr(sp->per_cpu_ref)->c[idx]) += 1; |
309 | smp_mb(); /* B */ /* Avoid leaking the critical section. */ | 304 | smp_mb(); /* B */ /* Avoid leaking the critical section. */ |
310 | ACCESS_ONCE(this_cpu_ptr(sp->per_cpu_ref)->seq[idx]) += 1; | 305 | ACCESS_ONCE(this_cpu_ptr(sp->per_cpu_ref)->seq[idx]) += 1; |
@@ -321,10 +316,8 @@ EXPORT_SYMBOL_GPL(__srcu_read_lock); | |||
321 | */ | 316 | */ |
322 | void __srcu_read_unlock(struct srcu_struct *sp, int idx) | 317 | void __srcu_read_unlock(struct srcu_struct *sp, int idx) |
323 | { | 318 | { |
324 | preempt_disable(); | ||
325 | smp_mb(); /* C */ /* Avoid leaking the critical section. */ | 319 | smp_mb(); /* C */ /* Avoid leaking the critical section. */ |
326 | ACCESS_ONCE(this_cpu_ptr(sp->per_cpu_ref)->c[idx]) -= 1; | 320 | this_cpu_dec(sp->per_cpu_ref->c[idx]); |
327 | preempt_enable(); | ||
328 | } | 321 | } |
329 | EXPORT_SYMBOL_GPL(__srcu_read_unlock); | 322 | EXPORT_SYMBOL_GPL(__srcu_read_unlock); |
330 | 323 | ||
@@ -423,6 +416,7 @@ static void __synchronize_srcu(struct srcu_struct *sp, int trycount) | |||
423 | !lock_is_held(&rcu_sched_lock_map), | 416 | !lock_is_held(&rcu_sched_lock_map), |
424 | "Illegal synchronize_srcu() in same-type SRCU (or RCU) read-side critical section"); | 417 | "Illegal synchronize_srcu() in same-type SRCU (or RCU) read-side critical section"); |
425 | 418 | ||
419 | might_sleep(); | ||
426 | init_completion(&rcu.completion); | 420 | init_completion(&rcu.completion); |
427 | 421 | ||
428 | head->next = NULL; | 422 | head->next = NULL; |
@@ -455,10 +449,12 @@ static void __synchronize_srcu(struct srcu_struct *sp, int trycount) | |||
455 | * synchronize_srcu - wait for prior SRCU read-side critical-section completion | 449 | * synchronize_srcu - wait for prior SRCU read-side critical-section completion |
456 | * @sp: srcu_struct with which to synchronize. | 450 | * @sp: srcu_struct with which to synchronize. |
457 | * | 451 | * |
458 | * Flip the completed counter, and wait for the old count to drain to zero. | 452 | * Wait for the count to drain to zero of both indexes. To avoid the |
459 | * As with classic RCU, the updater must use some separate means of | 453 | * possible starvation of synchronize_srcu(), it waits for the count of |
460 | * synchronizing concurrent updates. Can block; must be called from | 454 | * the index=((->completed & 1) ^ 1) to drain to zero at first, |
461 | * process context. | 455 | * and then flip the completed and wait for the count of the other index. |
456 | * | ||
457 | * Can block; must be called from process context. | ||
462 | * | 458 | * |
463 | * Note that it is illegal to call synchronize_srcu() from the corresponding | 459 | * Note that it is illegal to call synchronize_srcu() from the corresponding |
464 | * SRCU read-side critical section; doing so will result in deadlock. | 460 | * SRCU read-side critical section; doing so will result in deadlock. |
@@ -480,12 +476,11 @@ EXPORT_SYMBOL_GPL(synchronize_srcu); | |||
480 | * Wait for an SRCU grace period to elapse, but be more aggressive about | 476 | * Wait for an SRCU grace period to elapse, but be more aggressive about |
481 | * spinning rather than blocking when waiting. | 477 | * spinning rather than blocking when waiting. |
482 | * | 478 | * |
483 | * Note that it is illegal to call this function while holding any lock | 479 | * Note that it is also illegal to call synchronize_srcu_expedited() |
484 | * that is acquired by a CPU-hotplug notifier. It is also illegal to call | 480 | * from the corresponding SRCU read-side critical section; |
485 | * synchronize_srcu_expedited() from the corresponding SRCU read-side | 481 | * doing so will result in deadlock. However, it is perfectly legal |
486 | * critical section; doing so will result in deadlock. However, it is | 482 | * to call synchronize_srcu_expedited() on one srcu_struct from some |
487 | * perfectly legal to call synchronize_srcu_expedited() on one srcu_struct | 483 | * other srcu_struct's read-side critical section, as long as |
488 | * from some other srcu_struct's read-side critical section, as long as | ||
489 | * the resulting graph of srcu_structs is acyclic. | 484 | * the resulting graph of srcu_structs is acyclic. |
490 | */ | 485 | */ |
491 | void synchronize_srcu_expedited(struct srcu_struct *sp) | 486 | void synchronize_srcu_expedited(struct srcu_struct *sp) |
diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c index 2f194e965715..95d178c62d5a 100644 --- a/kernel/stop_machine.c +++ b/kernel/stop_machine.c | |||
@@ -18,7 +18,7 @@ | |||
18 | #include <linux/stop_machine.h> | 18 | #include <linux/stop_machine.h> |
19 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
20 | #include <linux/kallsyms.h> | 20 | #include <linux/kallsyms.h> |
21 | 21 | #include <linux/smpboot.h> | |
22 | #include <linux/atomic.h> | 22 | #include <linux/atomic.h> |
23 | 23 | ||
24 | /* | 24 | /* |
@@ -37,10 +37,10 @@ struct cpu_stopper { | |||
37 | spinlock_t lock; | 37 | spinlock_t lock; |
38 | bool enabled; /* is this stopper enabled? */ | 38 | bool enabled; /* is this stopper enabled? */ |
39 | struct list_head works; /* list of pending works */ | 39 | struct list_head works; /* list of pending works */ |
40 | struct task_struct *thread; /* stopper thread */ | ||
41 | }; | 40 | }; |
42 | 41 | ||
43 | static DEFINE_PER_CPU(struct cpu_stopper, cpu_stopper); | 42 | static DEFINE_PER_CPU(struct cpu_stopper, cpu_stopper); |
43 | static DEFINE_PER_CPU(struct task_struct *, cpu_stopper_task); | ||
44 | static bool stop_machine_initialized = false; | 44 | static bool stop_machine_initialized = false; |
45 | 45 | ||
46 | static void cpu_stop_init_done(struct cpu_stop_done *done, unsigned int nr_todo) | 46 | static void cpu_stop_init_done(struct cpu_stop_done *done, unsigned int nr_todo) |
@@ -62,16 +62,18 @@ static void cpu_stop_signal_done(struct cpu_stop_done *done, bool executed) | |||
62 | } | 62 | } |
63 | 63 | ||
64 | /* queue @work to @stopper. if offline, @work is completed immediately */ | 64 | /* queue @work to @stopper. if offline, @work is completed immediately */ |
65 | static void cpu_stop_queue_work(struct cpu_stopper *stopper, | 65 | static void cpu_stop_queue_work(unsigned int cpu, struct cpu_stop_work *work) |
66 | struct cpu_stop_work *work) | ||
67 | { | 66 | { |
67 | struct cpu_stopper *stopper = &per_cpu(cpu_stopper, cpu); | ||
68 | struct task_struct *p = per_cpu(cpu_stopper_task, cpu); | ||
69 | |||
68 | unsigned long flags; | 70 | unsigned long flags; |
69 | 71 | ||
70 | spin_lock_irqsave(&stopper->lock, flags); | 72 | spin_lock_irqsave(&stopper->lock, flags); |
71 | 73 | ||
72 | if (stopper->enabled) { | 74 | if (stopper->enabled) { |
73 | list_add_tail(&work->list, &stopper->works); | 75 | list_add_tail(&work->list, &stopper->works); |
74 | wake_up_process(stopper->thread); | 76 | wake_up_process(p); |
75 | } else | 77 | } else |
76 | cpu_stop_signal_done(work->done, false); | 78 | cpu_stop_signal_done(work->done, false); |
77 | 79 | ||
@@ -108,7 +110,7 @@ int stop_one_cpu(unsigned int cpu, cpu_stop_fn_t fn, void *arg) | |||
108 | struct cpu_stop_work work = { .fn = fn, .arg = arg, .done = &done }; | 110 | struct cpu_stop_work work = { .fn = fn, .arg = arg, .done = &done }; |
109 | 111 | ||
110 | cpu_stop_init_done(&done, 1); | 112 | cpu_stop_init_done(&done, 1); |
111 | cpu_stop_queue_work(&per_cpu(cpu_stopper, cpu), &work); | 113 | cpu_stop_queue_work(cpu, &work); |
112 | wait_for_completion(&done.completion); | 114 | wait_for_completion(&done.completion); |
113 | return done.executed ? done.ret : -ENOENT; | 115 | return done.executed ? done.ret : -ENOENT; |
114 | } | 116 | } |
@@ -130,7 +132,7 @@ void stop_one_cpu_nowait(unsigned int cpu, cpu_stop_fn_t fn, void *arg, | |||
130 | struct cpu_stop_work *work_buf) | 132 | struct cpu_stop_work *work_buf) |
131 | { | 133 | { |
132 | *work_buf = (struct cpu_stop_work){ .fn = fn, .arg = arg, }; | 134 | *work_buf = (struct cpu_stop_work){ .fn = fn, .arg = arg, }; |
133 | cpu_stop_queue_work(&per_cpu(cpu_stopper, cpu), work_buf); | 135 | cpu_stop_queue_work(cpu, work_buf); |
134 | } | 136 | } |
135 | 137 | ||
136 | /* static data for stop_cpus */ | 138 | /* static data for stop_cpus */ |
@@ -159,8 +161,7 @@ static void queue_stop_cpus_work(const struct cpumask *cpumask, | |||
159 | */ | 161 | */ |
160 | preempt_disable(); | 162 | preempt_disable(); |
161 | for_each_cpu(cpu, cpumask) | 163 | for_each_cpu(cpu, cpumask) |
162 | cpu_stop_queue_work(&per_cpu(cpu_stopper, cpu), | 164 | cpu_stop_queue_work(cpu, &per_cpu(stop_cpus_work, cpu)); |
163 | &per_cpu(stop_cpus_work, cpu)); | ||
164 | preempt_enable(); | 165 | preempt_enable(); |
165 | } | 166 | } |
166 | 167 | ||
@@ -244,20 +245,25 @@ int try_stop_cpus(const struct cpumask *cpumask, cpu_stop_fn_t fn, void *arg) | |||
244 | return ret; | 245 | return ret; |
245 | } | 246 | } |
246 | 247 | ||
247 | static int cpu_stopper_thread(void *data) | 248 | static int cpu_stop_should_run(unsigned int cpu) |
249 | { | ||
250 | struct cpu_stopper *stopper = &per_cpu(cpu_stopper, cpu); | ||
251 | unsigned long flags; | ||
252 | int run; | ||
253 | |||
254 | spin_lock_irqsave(&stopper->lock, flags); | ||
255 | run = !list_empty(&stopper->works); | ||
256 | spin_unlock_irqrestore(&stopper->lock, flags); | ||
257 | return run; | ||
258 | } | ||
259 | |||
260 | static void cpu_stopper_thread(unsigned int cpu) | ||
248 | { | 261 | { |
249 | struct cpu_stopper *stopper = data; | 262 | struct cpu_stopper *stopper = &per_cpu(cpu_stopper, cpu); |
250 | struct cpu_stop_work *work; | 263 | struct cpu_stop_work *work; |
251 | int ret; | 264 | int ret; |
252 | 265 | ||
253 | repeat: | 266 | repeat: |
254 | set_current_state(TASK_INTERRUPTIBLE); /* mb paired w/ kthread_stop */ | ||
255 | |||
256 | if (kthread_should_stop()) { | ||
257 | __set_current_state(TASK_RUNNING); | ||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | work = NULL; | 267 | work = NULL; |
262 | spin_lock_irq(&stopper->lock); | 268 | spin_lock_irq(&stopper->lock); |
263 | if (!list_empty(&stopper->works)) { | 269 | if (!list_empty(&stopper->works)) { |
@@ -273,8 +279,6 @@ repeat: | |||
273 | struct cpu_stop_done *done = work->done; | 279 | struct cpu_stop_done *done = work->done; |
274 | char ksym_buf[KSYM_NAME_LEN] __maybe_unused; | 280 | char ksym_buf[KSYM_NAME_LEN] __maybe_unused; |
275 | 281 | ||
276 | __set_current_state(TASK_RUNNING); | ||
277 | |||
278 | /* cpu stop callbacks are not allowed to sleep */ | 282 | /* cpu stop callbacks are not allowed to sleep */ |
279 | preempt_disable(); | 283 | preempt_disable(); |
280 | 284 | ||
@@ -290,88 +294,55 @@ repeat: | |||
290 | ksym_buf), arg); | 294 | ksym_buf), arg); |
291 | 295 | ||
292 | cpu_stop_signal_done(done, true); | 296 | cpu_stop_signal_done(done, true); |
293 | } else | 297 | goto repeat; |
294 | schedule(); | 298 | } |
295 | |||
296 | goto repeat; | ||
297 | } | 299 | } |
298 | 300 | ||
299 | extern void sched_set_stop_task(int cpu, struct task_struct *stop); | 301 | extern void sched_set_stop_task(int cpu, struct task_struct *stop); |
300 | 302 | ||
301 | /* manage stopper for a cpu, mostly lifted from sched migration thread mgmt */ | 303 | static void cpu_stop_create(unsigned int cpu) |
302 | static int __cpuinit cpu_stop_cpu_callback(struct notifier_block *nfb, | 304 | { |
303 | unsigned long action, void *hcpu) | 305 | sched_set_stop_task(cpu, per_cpu(cpu_stopper_task, cpu)); |
306 | } | ||
307 | |||
308 | static void cpu_stop_park(unsigned int cpu) | ||
304 | { | 309 | { |
305 | unsigned int cpu = (unsigned long)hcpu; | ||
306 | struct cpu_stopper *stopper = &per_cpu(cpu_stopper, cpu); | 310 | struct cpu_stopper *stopper = &per_cpu(cpu_stopper, cpu); |
307 | struct task_struct *p; | 311 | struct cpu_stop_work *work; |
308 | 312 | unsigned long flags; | |
309 | switch (action & ~CPU_TASKS_FROZEN) { | ||
310 | case CPU_UP_PREPARE: | ||
311 | BUG_ON(stopper->thread || stopper->enabled || | ||
312 | !list_empty(&stopper->works)); | ||
313 | p = kthread_create_on_node(cpu_stopper_thread, | ||
314 | stopper, | ||
315 | cpu_to_node(cpu), | ||
316 | "migration/%d", cpu); | ||
317 | if (IS_ERR(p)) | ||
318 | return notifier_from_errno(PTR_ERR(p)); | ||
319 | get_task_struct(p); | ||
320 | kthread_bind(p, cpu); | ||
321 | sched_set_stop_task(cpu, p); | ||
322 | stopper->thread = p; | ||
323 | break; | ||
324 | |||
325 | case CPU_ONLINE: | ||
326 | /* strictly unnecessary, as first user will wake it */ | ||
327 | wake_up_process(stopper->thread); | ||
328 | /* mark enabled */ | ||
329 | spin_lock_irq(&stopper->lock); | ||
330 | stopper->enabled = true; | ||
331 | spin_unlock_irq(&stopper->lock); | ||
332 | break; | ||
333 | |||
334 | #ifdef CONFIG_HOTPLUG_CPU | ||
335 | case CPU_UP_CANCELED: | ||
336 | case CPU_POST_DEAD: | ||
337 | { | ||
338 | struct cpu_stop_work *work; | ||
339 | |||
340 | sched_set_stop_task(cpu, NULL); | ||
341 | /* kill the stopper */ | ||
342 | kthread_stop(stopper->thread); | ||
343 | /* drain remaining works */ | ||
344 | spin_lock_irq(&stopper->lock); | ||
345 | list_for_each_entry(work, &stopper->works, list) | ||
346 | cpu_stop_signal_done(work->done, false); | ||
347 | stopper->enabled = false; | ||
348 | spin_unlock_irq(&stopper->lock); | ||
349 | /* release the stopper */ | ||
350 | put_task_struct(stopper->thread); | ||
351 | stopper->thread = NULL; | ||
352 | break; | ||
353 | } | ||
354 | #endif | ||
355 | } | ||
356 | 313 | ||
357 | return NOTIFY_OK; | 314 | /* drain remaining works */ |
315 | spin_lock_irqsave(&stopper->lock, flags); | ||
316 | list_for_each_entry(work, &stopper->works, list) | ||
317 | cpu_stop_signal_done(work->done, false); | ||
318 | stopper->enabled = false; | ||
319 | spin_unlock_irqrestore(&stopper->lock, flags); | ||
358 | } | 320 | } |
359 | 321 | ||
360 | /* | 322 | static void cpu_stop_unpark(unsigned int cpu) |
361 | * Give it a higher priority so that cpu stopper is available to other | 323 | { |
362 | * cpu notifiers. It currently shares the same priority as sched | 324 | struct cpu_stopper *stopper = &per_cpu(cpu_stopper, cpu); |
363 | * migration_notifier. | 325 | |
364 | */ | 326 | spin_lock_irq(&stopper->lock); |
365 | static struct notifier_block __cpuinitdata cpu_stop_cpu_notifier = { | 327 | stopper->enabled = true; |
366 | .notifier_call = cpu_stop_cpu_callback, | 328 | spin_unlock_irq(&stopper->lock); |
367 | .priority = 10, | 329 | } |
330 | |||
331 | static struct smp_hotplug_thread cpu_stop_threads = { | ||
332 | .store = &cpu_stopper_task, | ||
333 | .thread_should_run = cpu_stop_should_run, | ||
334 | .thread_fn = cpu_stopper_thread, | ||
335 | .thread_comm = "migration/%u", | ||
336 | .create = cpu_stop_create, | ||
337 | .setup = cpu_stop_unpark, | ||
338 | .park = cpu_stop_park, | ||
339 | .unpark = cpu_stop_unpark, | ||
340 | .selfparking = true, | ||
368 | }; | 341 | }; |
369 | 342 | ||
370 | static int __init cpu_stop_init(void) | 343 | static int __init cpu_stop_init(void) |
371 | { | 344 | { |
372 | void *bcpu = (void *)(long)smp_processor_id(); | ||
373 | unsigned int cpu; | 345 | unsigned int cpu; |
374 | int err; | ||
375 | 346 | ||
376 | for_each_possible_cpu(cpu) { | 347 | for_each_possible_cpu(cpu) { |
377 | struct cpu_stopper *stopper = &per_cpu(cpu_stopper, cpu); | 348 | struct cpu_stopper *stopper = &per_cpu(cpu_stopper, cpu); |
@@ -380,15 +351,8 @@ static int __init cpu_stop_init(void) | |||
380 | INIT_LIST_HEAD(&stopper->works); | 351 | INIT_LIST_HEAD(&stopper->works); |
381 | } | 352 | } |
382 | 353 | ||
383 | /* start one for the boot cpu */ | 354 | BUG_ON(smpboot_register_percpu_thread(&cpu_stop_threads)); |
384 | err = cpu_stop_cpu_callback(&cpu_stop_cpu_notifier, CPU_UP_PREPARE, | ||
385 | bcpu); | ||
386 | BUG_ON(err != NOTIFY_OK); | ||
387 | cpu_stop_cpu_callback(&cpu_stop_cpu_notifier, CPU_ONLINE, bcpu); | ||
388 | register_cpu_notifier(&cpu_stop_cpu_notifier); | ||
389 | |||
390 | stop_machine_initialized = true; | 355 | stop_machine_initialized = true; |
391 | |||
392 | return 0; | 356 | return 0; |
393 | } | 357 | } |
394 | early_initcall(cpu_stop_init); | 358 | early_initcall(cpu_stop_init); |
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index c88878db491e..4fc9be955c71 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
@@ -61,6 +61,7 @@ | |||
61 | #include <linux/kmod.h> | 61 | #include <linux/kmod.h> |
62 | #include <linux/capability.h> | 62 | #include <linux/capability.h> |
63 | #include <linux/binfmts.h> | 63 | #include <linux/binfmts.h> |
64 | #include <linux/sched/sysctl.h> | ||
64 | 65 | ||
65 | #include <asm/uaccess.h> | 66 | #include <asm/uaccess.h> |
66 | #include <asm/processor.h> | 67 | #include <asm/processor.h> |
@@ -403,6 +404,13 @@ static struct ctl_table kern_table[] = { | |||
403 | .mode = 0644, | 404 | .mode = 0644, |
404 | .proc_handler = sched_rt_handler, | 405 | .proc_handler = sched_rt_handler, |
405 | }, | 406 | }, |
407 | { | ||
408 | .procname = "sched_rr_timeslice_ms", | ||
409 | .data = &sched_rr_timeslice, | ||
410 | .maxlen = sizeof(int), | ||
411 | .mode = 0644, | ||
412 | .proc_handler = sched_rr_handler, | ||
413 | }, | ||
406 | #ifdef CONFIG_SCHED_AUTOGROUP | 414 | #ifdef CONFIG_SCHED_AUTOGROUP |
407 | { | 415 | { |
408 | .procname = "sched_autogroup_enabled", | 416 | .procname = "sched_autogroup_enabled", |
diff --git a/kernel/time.c b/kernel/time.c index d226c6a3fd28..c2a27dd93142 100644 --- a/kernel/time.c +++ b/kernel/time.c | |||
@@ -115,6 +115,12 @@ SYSCALL_DEFINE2(gettimeofday, struct timeval __user *, tv, | |||
115 | } | 115 | } |
116 | 116 | ||
117 | /* | 117 | /* |
118 | * Indicates if there is an offset between the system clock and the hardware | ||
119 | * clock/persistent clock/rtc. | ||
120 | */ | ||
121 | int persistent_clock_is_local; | ||
122 | |||
123 | /* | ||
118 | * Adjust the time obtained from the CMOS to be UTC time instead of | 124 | * Adjust the time obtained from the CMOS to be UTC time instead of |
119 | * local time. | 125 | * local time. |
120 | * | 126 | * |
@@ -135,6 +141,8 @@ static inline void warp_clock(void) | |||
135 | struct timespec adjust; | 141 | struct timespec adjust; |
136 | 142 | ||
137 | adjust = current_kernel_time(); | 143 | adjust = current_kernel_time(); |
144 | if (sys_tz.tz_minuteswest != 0) | ||
145 | persistent_clock_is_local = 1; | ||
138 | adjust.tv_sec += sys_tz.tz_minuteswest * 60; | 146 | adjust.tv_sec += sys_tz.tz_minuteswest * 60; |
139 | do_settimeofday(&adjust); | 147 | do_settimeofday(&adjust); |
140 | } | 148 | } |
diff --git a/kernel/time/Kconfig b/kernel/time/Kconfig index 8601f0db1261..24510d84efd7 100644 --- a/kernel/time/Kconfig +++ b/kernel/time/Kconfig | |||
@@ -12,6 +12,11 @@ config CLOCKSOURCE_WATCHDOG | |||
12 | config ARCH_CLOCKSOURCE_DATA | 12 | config ARCH_CLOCKSOURCE_DATA |
13 | bool | 13 | bool |
14 | 14 | ||
15 | # Platforms has a persistent clock | ||
16 | config ALWAYS_USE_PERSISTENT_CLOCK | ||
17 | bool | ||
18 | default n | ||
19 | |||
15 | # Timekeeping vsyscall support | 20 | # Timekeeping vsyscall support |
16 | config GENERIC_TIME_VSYSCALL | 21 | config GENERIC_TIME_VSYSCALL |
17 | bool | 22 | bool |
@@ -38,6 +43,10 @@ config GENERIC_CLOCKEVENTS_BUILD | |||
38 | default y | 43 | default y |
39 | depends on GENERIC_CLOCKEVENTS | 44 | depends on GENERIC_CLOCKEVENTS |
40 | 45 | ||
46 | # Architecture can handle broadcast in a driver-agnostic way | ||
47 | config ARCH_HAS_TICK_BROADCAST | ||
48 | bool | ||
49 | |||
41 | # Clockevents broadcasting infrastructure | 50 | # Clockevents broadcasting infrastructure |
42 | config GENERIC_CLOCKEVENTS_BROADCAST | 51 | config GENERIC_CLOCKEVENTS_BROADCAST |
43 | bool | 52 | bool |
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index 24174b4d669b..b10a42bb0165 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/time.h> | 15 | #include <linux/time.h> |
16 | #include <linux/mm.h> | 16 | #include <linux/mm.h> |
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include <linux/rtc.h> | ||
18 | 19 | ||
19 | #include "tick-internal.h" | 20 | #include "tick-internal.h" |
20 | 21 | ||
@@ -483,8 +484,7 @@ out: | |||
483 | return leap; | 484 | return leap; |
484 | } | 485 | } |
485 | 486 | ||
486 | #ifdef CONFIG_GENERIC_CMOS_UPDATE | 487 | #if defined(CONFIG_GENERIC_CMOS_UPDATE) || defined(CONFIG_RTC_SYSTOHC) |
487 | |||
488 | static void sync_cmos_clock(struct work_struct *work); | 488 | static void sync_cmos_clock(struct work_struct *work); |
489 | 489 | ||
490 | static DECLARE_DELAYED_WORK(sync_cmos_work, sync_cmos_clock); | 490 | static DECLARE_DELAYED_WORK(sync_cmos_work, sync_cmos_clock); |
@@ -510,14 +510,26 @@ static void sync_cmos_clock(struct work_struct *work) | |||
510 | } | 510 | } |
511 | 511 | ||
512 | getnstimeofday(&now); | 512 | getnstimeofday(&now); |
513 | if (abs(now.tv_nsec - (NSEC_PER_SEC / 2)) <= tick_nsec / 2) | 513 | if (abs(now.tv_nsec - (NSEC_PER_SEC / 2)) <= tick_nsec / 2) { |
514 | fail = update_persistent_clock(now); | 514 | struct timespec adjust = now; |
515 | |||
516 | fail = -ENODEV; | ||
517 | if (persistent_clock_is_local) | ||
518 | adjust.tv_sec -= (sys_tz.tz_minuteswest * 60); | ||
519 | #ifdef CONFIG_GENERIC_CMOS_UPDATE | ||
520 | fail = update_persistent_clock(adjust); | ||
521 | #endif | ||
522 | #ifdef CONFIG_RTC_SYSTOHC | ||
523 | if (fail == -ENODEV) | ||
524 | fail = rtc_set_ntp_time(adjust); | ||
525 | #endif | ||
526 | } | ||
515 | 527 | ||
516 | next.tv_nsec = (NSEC_PER_SEC / 2) - now.tv_nsec - (TICK_NSEC / 2); | 528 | next.tv_nsec = (NSEC_PER_SEC / 2) - now.tv_nsec - (TICK_NSEC / 2); |
517 | if (next.tv_nsec <= 0) | 529 | if (next.tv_nsec <= 0) |
518 | next.tv_nsec += NSEC_PER_SEC; | 530 | next.tv_nsec += NSEC_PER_SEC; |
519 | 531 | ||
520 | if (!fail) | 532 | if (!fail || fail == -ENODEV) |
521 | next.tv_sec = 659; | 533 | next.tv_sec = 659; |
522 | else | 534 | else |
523 | next.tv_sec = 0; | 535 | next.tv_sec = 0; |
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c index f113755695e2..2fb8cb88df8d 100644 --- a/kernel/time/tick-broadcast.c +++ b/kernel/time/tick-broadcast.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/percpu.h> | 18 | #include <linux/percpu.h> |
19 | #include <linux/profile.h> | 19 | #include <linux/profile.h> |
20 | #include <linux/sched.h> | 20 | #include <linux/sched.h> |
21 | #include <linux/smp.h> | ||
21 | 22 | ||
22 | #include "tick-internal.h" | 23 | #include "tick-internal.h" |
23 | 24 | ||
@@ -86,6 +87,22 @@ int tick_is_broadcast_device(struct clock_event_device *dev) | |||
86 | return (dev && tick_broadcast_device.evtdev == dev); | 87 | return (dev && tick_broadcast_device.evtdev == dev); |
87 | } | 88 | } |
88 | 89 | ||
90 | static void err_broadcast(const struct cpumask *mask) | ||
91 | { | ||
92 | pr_crit_once("Failed to broadcast timer tick. Some CPUs may be unresponsive.\n"); | ||
93 | } | ||
94 | |||
95 | static void tick_device_setup_broadcast_func(struct clock_event_device *dev) | ||
96 | { | ||
97 | if (!dev->broadcast) | ||
98 | dev->broadcast = tick_broadcast; | ||
99 | if (!dev->broadcast) { | ||
100 | pr_warn_once("%s depends on broadcast, but no broadcast function available\n", | ||
101 | dev->name); | ||
102 | dev->broadcast = err_broadcast; | ||
103 | } | ||
104 | } | ||
105 | |||
89 | /* | 106 | /* |
90 | * Check, if the device is disfunctional and a place holder, which | 107 | * Check, if the device is disfunctional and a place holder, which |
91 | * needs to be handled by the broadcast device. | 108 | * needs to be handled by the broadcast device. |
@@ -105,6 +122,7 @@ int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu) | |||
105 | */ | 122 | */ |
106 | if (!tick_device_is_functional(dev)) { | 123 | if (!tick_device_is_functional(dev)) { |
107 | dev->event_handler = tick_handle_periodic; | 124 | dev->event_handler = tick_handle_periodic; |
125 | tick_device_setup_broadcast_func(dev); | ||
108 | cpumask_set_cpu(cpu, tick_get_broadcast_mask()); | 126 | cpumask_set_cpu(cpu, tick_get_broadcast_mask()); |
109 | tick_broadcast_start_periodic(tick_broadcast_device.evtdev); | 127 | tick_broadcast_start_periodic(tick_broadcast_device.evtdev); |
110 | ret = 1; | 128 | ret = 1; |
@@ -116,15 +134,33 @@ int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu) | |||
116 | */ | 134 | */ |
117 | if (!(dev->features & CLOCK_EVT_FEAT_C3STOP)) { | 135 | if (!(dev->features & CLOCK_EVT_FEAT_C3STOP)) { |
118 | int cpu = smp_processor_id(); | 136 | int cpu = smp_processor_id(); |
119 | |||
120 | cpumask_clear_cpu(cpu, tick_get_broadcast_mask()); | 137 | cpumask_clear_cpu(cpu, tick_get_broadcast_mask()); |
121 | tick_broadcast_clear_oneshot(cpu); | 138 | tick_broadcast_clear_oneshot(cpu); |
139 | } else { | ||
140 | tick_device_setup_broadcast_func(dev); | ||
122 | } | 141 | } |
123 | } | 142 | } |
124 | raw_spin_unlock_irqrestore(&tick_broadcast_lock, flags); | 143 | raw_spin_unlock_irqrestore(&tick_broadcast_lock, flags); |
125 | return ret; | 144 | return ret; |
126 | } | 145 | } |
127 | 146 | ||
147 | #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST | ||
148 | int tick_receive_broadcast(void) | ||
149 | { | ||
150 | struct tick_device *td = this_cpu_ptr(&tick_cpu_device); | ||
151 | struct clock_event_device *evt = td->evtdev; | ||
152 | |||
153 | if (!evt) | ||
154 | return -ENODEV; | ||
155 | |||
156 | if (!evt->event_handler) | ||
157 | return -EINVAL; | ||
158 | |||
159 | evt->event_handler(evt); | ||
160 | return 0; | ||
161 | } | ||
162 | #endif | ||
163 | |||
128 | /* | 164 | /* |
129 | * Broadcast the event to the cpus, which are set in the mask (mangled). | 165 | * Broadcast the event to the cpus, which are set in the mask (mangled). |
130 | */ | 166 | */ |
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index d58e552d9fd1..314b9ee07edf 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/profile.h> | 20 | #include <linux/profile.h> |
21 | #include <linux/sched.h> | 21 | #include <linux/sched.h> |
22 | #include <linux/module.h> | 22 | #include <linux/module.h> |
23 | #include <linux/irq_work.h> | ||
23 | 24 | ||
24 | #include <asm/irq_regs.h> | 25 | #include <asm/irq_regs.h> |
25 | 26 | ||
@@ -28,7 +29,7 @@ | |||
28 | /* | 29 | /* |
29 | * Per cpu nohz control structure | 30 | * Per cpu nohz control structure |
30 | */ | 31 | */ |
31 | static DEFINE_PER_CPU(struct tick_sched, tick_cpu_sched); | 32 | DEFINE_PER_CPU(struct tick_sched, tick_cpu_sched); |
32 | 33 | ||
33 | /* | 34 | /* |
34 | * The time, when the last jiffy update happened. Protected by jiffies_lock. | 35 | * The time, when the last jiffy update happened. Protected by jiffies_lock. |
@@ -331,8 +332,8 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts, | |||
331 | time_delta = timekeeping_max_deferment(); | 332 | time_delta = timekeeping_max_deferment(); |
332 | } while (read_seqretry(&jiffies_lock, seq)); | 333 | } while (read_seqretry(&jiffies_lock, seq)); |
333 | 334 | ||
334 | if (rcu_needs_cpu(cpu, &rcu_delta_jiffies) || printk_needs_cpu(cpu) || | 335 | if (rcu_needs_cpu(cpu, &rcu_delta_jiffies) || |
335 | arch_needs_cpu(cpu)) { | 336 | arch_needs_cpu(cpu) || irq_work_needs_cpu()) { |
336 | next_jiffies = last_jiffies + 1; | 337 | next_jiffies = last_jiffies + 1; |
337 | delta_jiffies = 1; | 338 | delta_jiffies = 1; |
338 | } else { | 339 | } else { |
@@ -631,8 +632,11 @@ static void tick_nohz_restart_sched_tick(struct tick_sched *ts, ktime_t now) | |||
631 | 632 | ||
632 | static void tick_nohz_account_idle_ticks(struct tick_sched *ts) | 633 | static void tick_nohz_account_idle_ticks(struct tick_sched *ts) |
633 | { | 634 | { |
634 | #ifndef CONFIG_VIRT_CPU_ACCOUNTING | 635 | #ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE |
635 | unsigned long ticks; | 636 | unsigned long ticks; |
637 | |||
638 | if (vtime_accounting_enabled()) | ||
639 | return; | ||
636 | /* | 640 | /* |
637 | * We stopped the tick in idle. Update process times would miss the | 641 | * We stopped the tick in idle. Update process times would miss the |
638 | * time we slept as update_process_times does only a 1 tick | 642 | * time we slept as update_process_times does only a 1 tick |
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index cbc6acb0db3f..1e35515a875e 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c | |||
@@ -29,6 +29,9 @@ static struct timekeeper timekeeper; | |||
29 | /* flag for if timekeeping is suspended */ | 29 | /* flag for if timekeeping is suspended */ |
30 | int __read_mostly timekeeping_suspended; | 30 | int __read_mostly timekeeping_suspended; |
31 | 31 | ||
32 | /* Flag for if there is a persistent clock on this platform */ | ||
33 | bool __read_mostly persistent_clock_exist = false; | ||
34 | |||
32 | static inline void tk_normalize_xtime(struct timekeeper *tk) | 35 | static inline void tk_normalize_xtime(struct timekeeper *tk) |
33 | { | 36 | { |
34 | while (tk->xtime_nsec >= ((u64)NSEC_PER_SEC << tk->shift)) { | 37 | while (tk->xtime_nsec >= ((u64)NSEC_PER_SEC << tk->shift)) { |
@@ -264,19 +267,18 @@ static void timekeeping_forward_now(struct timekeeper *tk) | |||
264 | } | 267 | } |
265 | 268 | ||
266 | /** | 269 | /** |
267 | * getnstimeofday - Returns the time of day in a timespec | 270 | * __getnstimeofday - Returns the time of day in a timespec. |
268 | * @ts: pointer to the timespec to be set | 271 | * @ts: pointer to the timespec to be set |
269 | * | 272 | * |
270 | * Returns the time of day in a timespec. | 273 | * Updates the time of day in the timespec. |
274 | * Returns 0 on success, or -ve when suspended (timespec will be undefined). | ||
271 | */ | 275 | */ |
272 | void getnstimeofday(struct timespec *ts) | 276 | int __getnstimeofday(struct timespec *ts) |
273 | { | 277 | { |
274 | struct timekeeper *tk = &timekeeper; | 278 | struct timekeeper *tk = &timekeeper; |
275 | unsigned long seq; | 279 | unsigned long seq; |
276 | s64 nsecs = 0; | 280 | s64 nsecs = 0; |
277 | 281 | ||
278 | WARN_ON(timekeeping_suspended); | ||
279 | |||
280 | do { | 282 | do { |
281 | seq = read_seqbegin(&tk->lock); | 283 | seq = read_seqbegin(&tk->lock); |
282 | 284 | ||
@@ -287,6 +289,26 @@ void getnstimeofday(struct timespec *ts) | |||
287 | 289 | ||
288 | ts->tv_nsec = 0; | 290 | ts->tv_nsec = 0; |
289 | timespec_add_ns(ts, nsecs); | 291 | timespec_add_ns(ts, nsecs); |
292 | |||
293 | /* | ||
294 | * Do not bail out early, in case there were callers still using | ||
295 | * the value, even in the face of the WARN_ON. | ||
296 | */ | ||
297 | if (unlikely(timekeeping_suspended)) | ||
298 | return -EAGAIN; | ||
299 | return 0; | ||
300 | } | ||
301 | EXPORT_SYMBOL(__getnstimeofday); | ||
302 | |||
303 | /** | ||
304 | * getnstimeofday - Returns the time of day in a timespec. | ||
305 | * @ts: pointer to the timespec to be set | ||
306 | * | ||
307 | * Returns the time of day in a timespec (WARN if suspended). | ||
308 | */ | ||
309 | void getnstimeofday(struct timespec *ts) | ||
310 | { | ||
311 | WARN_ON(__getnstimeofday(ts)); | ||
290 | } | 312 | } |
291 | EXPORT_SYMBOL(getnstimeofday); | 313 | EXPORT_SYMBOL(getnstimeofday); |
292 | 314 | ||
@@ -640,12 +662,14 @@ void __init timekeeping_init(void) | |||
640 | struct timespec now, boot, tmp; | 662 | struct timespec now, boot, tmp; |
641 | 663 | ||
642 | read_persistent_clock(&now); | 664 | read_persistent_clock(&now); |
665 | |||
643 | if (!timespec_valid_strict(&now)) { | 666 | if (!timespec_valid_strict(&now)) { |
644 | pr_warn("WARNING: Persistent clock returned invalid value!\n" | 667 | pr_warn("WARNING: Persistent clock returned invalid value!\n" |
645 | " Check your CMOS/BIOS settings.\n"); | 668 | " Check your CMOS/BIOS settings.\n"); |
646 | now.tv_sec = 0; | 669 | now.tv_sec = 0; |
647 | now.tv_nsec = 0; | 670 | now.tv_nsec = 0; |
648 | } | 671 | } else if (now.tv_sec || now.tv_nsec) |
672 | persistent_clock_exist = true; | ||
649 | 673 | ||
650 | read_boot_clock(&boot); | 674 | read_boot_clock(&boot); |
651 | if (!timespec_valid_strict(&boot)) { | 675 | if (!timespec_valid_strict(&boot)) { |
@@ -718,11 +742,12 @@ void timekeeping_inject_sleeptime(struct timespec *delta) | |||
718 | { | 742 | { |
719 | struct timekeeper *tk = &timekeeper; | 743 | struct timekeeper *tk = &timekeeper; |
720 | unsigned long flags; | 744 | unsigned long flags; |
721 | struct timespec ts; | ||
722 | 745 | ||
723 | /* Make sure we don't set the clock twice */ | 746 | /* |
724 | read_persistent_clock(&ts); | 747 | * Make sure we don't set the clock twice, as timekeeping_resume() |
725 | if (!(ts.tv_sec == 0 && ts.tv_nsec == 0)) | 748 | * already did it |
749 | */ | ||
750 | if (has_persistent_clock()) | ||
726 | return; | 751 | return; |
727 | 752 | ||
728 | write_seqlock_irqsave(&tk->lock, flags); | 753 | write_seqlock_irqsave(&tk->lock, flags); |
diff --git a/kernel/timeconst.pl b/kernel/timeconst.pl index eb51d76e058a..3f42652a6a37 100644 --- a/kernel/timeconst.pl +++ b/kernel/timeconst.pl | |||
@@ -369,10 +369,8 @@ if ($hz eq '--can') { | |||
369 | die "Usage: $0 HZ\n"; | 369 | die "Usage: $0 HZ\n"; |
370 | } | 370 | } |
371 | 371 | ||
372 | @val = @{$canned_values{$hz}}; | 372 | $cv = $canned_values{$hz}; |
373 | if (!defined(@val)) { | 373 | @val = defined($cv) ? @$cv : compute_values($hz); |
374 | @val = compute_values($hz); | ||
375 | } | ||
376 | output($hz, @val); | 374 | output($hz, @val); |
377 | } | 375 | } |
378 | exit 0; | 376 | exit 0; |
diff --git a/kernel/timer.c b/kernel/timer.c index 367d00858482..dbf7a78a1ef1 100644 --- a/kernel/timer.c +++ b/kernel/timer.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <linux/kallsyms.h> | 39 | #include <linux/kallsyms.h> |
40 | #include <linux/irq_work.h> | 40 | #include <linux/irq_work.h> |
41 | #include <linux/sched.h> | 41 | #include <linux/sched.h> |
42 | #include <linux/sched/sysctl.h> | ||
42 | #include <linux/slab.h> | 43 | #include <linux/slab.h> |
43 | 44 | ||
44 | #include <asm/uaccess.h> | 45 | #include <asm/uaccess.h> |
@@ -1351,7 +1352,6 @@ void update_process_times(int user_tick) | |||
1351 | account_process_tick(p, user_tick); | 1352 | account_process_tick(p, user_tick); |
1352 | run_local_timers(); | 1353 | run_local_timers(); |
1353 | rcu_check_callbacks(cpu, user_tick); | 1354 | rcu_check_callbacks(cpu, user_tick); |
1354 | printk_tick(); | ||
1355 | #ifdef CONFIG_IRQ_WORK | 1355 | #ifdef CONFIG_IRQ_WORK |
1356 | if (in_irq()) | 1356 | if (in_irq()) |
1357 | irq_work_run(); | 1357 | irq_work_run(); |
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig index 5d89335a485f..36567564e221 100644 --- a/kernel/trace/Kconfig +++ b/kernel/trace/Kconfig | |||
@@ -39,6 +39,9 @@ config HAVE_DYNAMIC_FTRACE | |||
39 | help | 39 | help |
40 | See Documentation/trace/ftrace-design.txt | 40 | See Documentation/trace/ftrace-design.txt |
41 | 41 | ||
42 | config HAVE_DYNAMIC_FTRACE_WITH_REGS | ||
43 | bool | ||
44 | |||
42 | config HAVE_FTRACE_MCOUNT_RECORD | 45 | config HAVE_FTRACE_MCOUNT_RECORD |
43 | bool | 46 | bool |
44 | help | 47 | help |
@@ -250,6 +253,16 @@ config FTRACE_SYSCALLS | |||
250 | help | 253 | help |
251 | Basic tracer to catch the syscall entry and exit events. | 254 | Basic tracer to catch the syscall entry and exit events. |
252 | 255 | ||
256 | config TRACER_SNAPSHOT | ||
257 | bool "Create a snapshot trace buffer" | ||
258 | select TRACER_MAX_TRACE | ||
259 | help | ||
260 | Allow tracing users to take snapshot of the current buffer using the | ||
261 | ftrace interface, e.g.: | ||
262 | |||
263 | echo 1 > /sys/kernel/debug/tracing/snapshot | ||
264 | cat snapshot | ||
265 | |||
253 | config TRACE_BRANCH_PROFILING | 266 | config TRACE_BRANCH_PROFILING |
254 | bool | 267 | bool |
255 | select GENERIC_TRACER | 268 | select GENERIC_TRACER |
@@ -434,6 +447,11 @@ config DYNAMIC_FTRACE | |||
434 | were made. If so, it runs stop_machine (stops all CPUS) | 447 | were made. If so, it runs stop_machine (stops all CPUS) |
435 | and modifies the code to jump over the call to ftrace. | 448 | and modifies the code to jump over the call to ftrace. |
436 | 449 | ||
450 | config DYNAMIC_FTRACE_WITH_REGS | ||
451 | def_bool y | ||
452 | depends on DYNAMIC_FTRACE | ||
453 | depends on HAVE_DYNAMIC_FTRACE_WITH_REGS | ||
454 | |||
437 | config FUNCTION_PROFILER | 455 | config FUNCTION_PROFILER |
438 | bool "Kernel function profiler" | 456 | bool "Kernel function profiler" |
439 | depends on FUNCTION_TRACER | 457 | depends on FUNCTION_TRACER |
diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c index c0bd0308741c..71259e2b6b61 100644 --- a/kernel/trace/blktrace.c +++ b/kernel/trace/blktrace.c | |||
@@ -147,7 +147,7 @@ void __trace_note_message(struct blk_trace *bt, const char *fmt, ...) | |||
147 | return; | 147 | return; |
148 | 148 | ||
149 | local_irq_save(flags); | 149 | local_irq_save(flags); |
150 | buf = per_cpu_ptr(bt->msg_data, smp_processor_id()); | 150 | buf = this_cpu_ptr(bt->msg_data); |
151 | va_start(args, fmt); | 151 | va_start(args, fmt); |
152 | n = vscnprintf(buf, BLK_TN_MAX_MSG, fmt, args); | 152 | n = vscnprintf(buf, BLK_TN_MAX_MSG, fmt, args); |
153 | va_end(args); | 153 | va_end(args); |
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 41473b4ad7a4..ce8c3d68292f 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -111,6 +111,26 @@ static void ftrace_ops_no_ops(unsigned long ip, unsigned long parent_ip); | |||
111 | #define ftrace_ops_list_func ((ftrace_func_t)ftrace_ops_no_ops) | 111 | #define ftrace_ops_list_func ((ftrace_func_t)ftrace_ops_no_ops) |
112 | #endif | 112 | #endif |
113 | 113 | ||
114 | /* | ||
115 | * Traverse the ftrace_global_list, invoking all entries. The reason that we | ||
116 | * can use rcu_dereference_raw() is that elements removed from this list | ||
117 | * are simply leaked, so there is no need to interact with a grace-period | ||
118 | * mechanism. The rcu_dereference_raw() calls are needed to handle | ||
119 | * concurrent insertions into the ftrace_global_list. | ||
120 | * | ||
121 | * Silly Alpha and silly pointer-speculation compiler optimizations! | ||
122 | */ | ||
123 | #define do_for_each_ftrace_op(op, list) \ | ||
124 | op = rcu_dereference_raw(list); \ | ||
125 | do | ||
126 | |||
127 | /* | ||
128 | * Optimized for just a single item in the list (as that is the normal case). | ||
129 | */ | ||
130 | #define while_for_each_ftrace_op(op) \ | ||
131 | while (likely(op = rcu_dereference_raw((op)->next)) && \ | ||
132 | unlikely((op) != &ftrace_list_end)) | ||
133 | |||
114 | /** | 134 | /** |
115 | * ftrace_nr_registered_ops - return number of ops registered | 135 | * ftrace_nr_registered_ops - return number of ops registered |
116 | * | 136 | * |
@@ -132,29 +152,21 @@ int ftrace_nr_registered_ops(void) | |||
132 | return cnt; | 152 | return cnt; |
133 | } | 153 | } |
134 | 154 | ||
135 | /* | ||
136 | * Traverse the ftrace_global_list, invoking all entries. The reason that we | ||
137 | * can use rcu_dereference_raw() is that elements removed from this list | ||
138 | * are simply leaked, so there is no need to interact with a grace-period | ||
139 | * mechanism. The rcu_dereference_raw() calls are needed to handle | ||
140 | * concurrent insertions into the ftrace_global_list. | ||
141 | * | ||
142 | * Silly Alpha and silly pointer-speculation compiler optimizations! | ||
143 | */ | ||
144 | static void | 155 | static void |
145 | ftrace_global_list_func(unsigned long ip, unsigned long parent_ip, | 156 | ftrace_global_list_func(unsigned long ip, unsigned long parent_ip, |
146 | struct ftrace_ops *op, struct pt_regs *regs) | 157 | struct ftrace_ops *op, struct pt_regs *regs) |
147 | { | 158 | { |
148 | if (unlikely(trace_recursion_test(TRACE_GLOBAL_BIT))) | 159 | int bit; |
160 | |||
161 | bit = trace_test_and_set_recursion(TRACE_GLOBAL_START, TRACE_GLOBAL_MAX); | ||
162 | if (bit < 0) | ||
149 | return; | 163 | return; |
150 | 164 | ||
151 | trace_recursion_set(TRACE_GLOBAL_BIT); | 165 | do_for_each_ftrace_op(op, ftrace_global_list) { |
152 | op = rcu_dereference_raw(ftrace_global_list); /*see above*/ | ||
153 | while (op != &ftrace_list_end) { | ||
154 | op->func(ip, parent_ip, op, regs); | 166 | op->func(ip, parent_ip, op, regs); |
155 | op = rcu_dereference_raw(op->next); /*see above*/ | 167 | } while_for_each_ftrace_op(op); |
156 | }; | 168 | |
157 | trace_recursion_clear(TRACE_GLOBAL_BIT); | 169 | trace_clear_recursion(bit); |
158 | } | 170 | } |
159 | 171 | ||
160 | static void ftrace_pid_func(unsigned long ip, unsigned long parent_ip, | 172 | static void ftrace_pid_func(unsigned long ip, unsigned long parent_ip, |
@@ -221,10 +233,24 @@ static void update_global_ops(void) | |||
221 | * registered callers. | 233 | * registered callers. |
222 | */ | 234 | */ |
223 | if (ftrace_global_list == &ftrace_list_end || | 235 | if (ftrace_global_list == &ftrace_list_end || |
224 | ftrace_global_list->next == &ftrace_list_end) | 236 | ftrace_global_list->next == &ftrace_list_end) { |
225 | func = ftrace_global_list->func; | 237 | func = ftrace_global_list->func; |
226 | else | 238 | /* |
239 | * As we are calling the function directly. | ||
240 | * If it does not have recursion protection, | ||
241 | * the function_trace_op needs to be updated | ||
242 | * accordingly. | ||
243 | */ | ||
244 | if (ftrace_global_list->flags & FTRACE_OPS_FL_RECURSION_SAFE) | ||
245 | global_ops.flags |= FTRACE_OPS_FL_RECURSION_SAFE; | ||
246 | else | ||
247 | global_ops.flags &= ~FTRACE_OPS_FL_RECURSION_SAFE; | ||
248 | } else { | ||
227 | func = ftrace_global_list_func; | 249 | func = ftrace_global_list_func; |
250 | /* The list has its own recursion protection. */ | ||
251 | global_ops.flags |= FTRACE_OPS_FL_RECURSION_SAFE; | ||
252 | } | ||
253 | |||
228 | 254 | ||
229 | /* If we filter on pids, update to use the pid function */ | 255 | /* If we filter on pids, update to use the pid function */ |
230 | if (!list_empty(&ftrace_pids)) { | 256 | if (!list_empty(&ftrace_pids)) { |
@@ -337,7 +363,7 @@ static int __register_ftrace_function(struct ftrace_ops *ops) | |||
337 | if ((ops->flags & FL_GLOBAL_CONTROL_MASK) == FL_GLOBAL_CONTROL_MASK) | 363 | if ((ops->flags & FL_GLOBAL_CONTROL_MASK) == FL_GLOBAL_CONTROL_MASK) |
338 | return -EINVAL; | 364 | return -EINVAL; |
339 | 365 | ||
340 | #ifndef ARCH_SUPPORTS_FTRACE_SAVE_REGS | 366 | #ifndef CONFIG_DYNAMIC_FTRACE_WITH_REGS |
341 | /* | 367 | /* |
342 | * If the ftrace_ops specifies SAVE_REGS, then it only can be used | 368 | * If the ftrace_ops specifies SAVE_REGS, then it only can be used |
343 | * if the arch supports it, or SAVE_REGS_IF_SUPPORTED is also set. | 369 | * if the arch supports it, or SAVE_REGS_IF_SUPPORTED is also set. |
@@ -4090,14 +4116,11 @@ ftrace_ops_control_func(unsigned long ip, unsigned long parent_ip, | |||
4090 | */ | 4116 | */ |
4091 | preempt_disable_notrace(); | 4117 | preempt_disable_notrace(); |
4092 | trace_recursion_set(TRACE_CONTROL_BIT); | 4118 | trace_recursion_set(TRACE_CONTROL_BIT); |
4093 | op = rcu_dereference_raw(ftrace_control_list); | 4119 | do_for_each_ftrace_op(op, ftrace_control_list) { |
4094 | while (op != &ftrace_list_end) { | ||
4095 | if (!ftrace_function_local_disabled(op) && | 4120 | if (!ftrace_function_local_disabled(op) && |
4096 | ftrace_ops_test(op, ip)) | 4121 | ftrace_ops_test(op, ip)) |
4097 | op->func(ip, parent_ip, op, regs); | 4122 | op->func(ip, parent_ip, op, regs); |
4098 | 4123 | } while_for_each_ftrace_op(op); | |
4099 | op = rcu_dereference_raw(op->next); | ||
4100 | }; | ||
4101 | trace_recursion_clear(TRACE_CONTROL_BIT); | 4124 | trace_recursion_clear(TRACE_CONTROL_BIT); |
4102 | preempt_enable_notrace(); | 4125 | preempt_enable_notrace(); |
4103 | } | 4126 | } |
@@ -4112,27 +4135,26 @@ __ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip, | |||
4112 | struct ftrace_ops *ignored, struct pt_regs *regs) | 4135 | struct ftrace_ops *ignored, struct pt_regs *regs) |
4113 | { | 4136 | { |
4114 | struct ftrace_ops *op; | 4137 | struct ftrace_ops *op; |
4138 | int bit; | ||
4115 | 4139 | ||
4116 | if (function_trace_stop) | 4140 | if (function_trace_stop) |
4117 | return; | 4141 | return; |
4118 | 4142 | ||
4119 | if (unlikely(trace_recursion_test(TRACE_INTERNAL_BIT))) | 4143 | bit = trace_test_and_set_recursion(TRACE_LIST_START, TRACE_LIST_MAX); |
4144 | if (bit < 0) | ||
4120 | return; | 4145 | return; |
4121 | 4146 | ||
4122 | trace_recursion_set(TRACE_INTERNAL_BIT); | ||
4123 | /* | 4147 | /* |
4124 | * Some of the ops may be dynamically allocated, | 4148 | * Some of the ops may be dynamically allocated, |
4125 | * they must be freed after a synchronize_sched(). | 4149 | * they must be freed after a synchronize_sched(). |
4126 | */ | 4150 | */ |
4127 | preempt_disable_notrace(); | 4151 | preempt_disable_notrace(); |
4128 | op = rcu_dereference_raw(ftrace_ops_list); | 4152 | do_for_each_ftrace_op(op, ftrace_ops_list) { |
4129 | while (op != &ftrace_list_end) { | ||
4130 | if (ftrace_ops_test(op, ip)) | 4153 | if (ftrace_ops_test(op, ip)) |
4131 | op->func(ip, parent_ip, op, regs); | 4154 | op->func(ip, parent_ip, op, regs); |
4132 | op = rcu_dereference_raw(op->next); | 4155 | } while_for_each_ftrace_op(op); |
4133 | }; | ||
4134 | preempt_enable_notrace(); | 4156 | preempt_enable_notrace(); |
4135 | trace_recursion_clear(TRACE_INTERNAL_BIT); | 4157 | trace_clear_recursion(bit); |
4136 | } | 4158 | } |
4137 | 4159 | ||
4138 | /* | 4160 | /* |
@@ -4143,8 +4165,8 @@ __ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip, | |||
4143 | * Archs are to support both the regs and ftrace_ops at the same time. | 4165 | * Archs are to support both the regs and ftrace_ops at the same time. |
4144 | * If they support ftrace_ops, it is assumed they support regs. | 4166 | * If they support ftrace_ops, it is assumed they support regs. |
4145 | * If call backs want to use regs, they must either check for regs | 4167 | * If call backs want to use regs, they must either check for regs |
4146 | * being NULL, or ARCH_SUPPORTS_FTRACE_SAVE_REGS. | 4168 | * being NULL, or CONFIG_DYNAMIC_FTRACE_WITH_REGS. |
4147 | * Note, ARCH_SUPPORT_SAVE_REGS expects a full regs to be saved. | 4169 | * Note, CONFIG_DYNAMIC_FTRACE_WITH_REGS expects a full regs to be saved. |
4148 | * An architecture can pass partial regs with ftrace_ops and still | 4170 | * An architecture can pass partial regs with ftrace_ops and still |
4149 | * set the ARCH_SUPPORT_FTARCE_OPS. | 4171 | * set the ARCH_SUPPORT_FTARCE_OPS. |
4150 | */ | 4172 | */ |
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index ce8514feedcd..7244acde77b0 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c | |||
@@ -3,8 +3,10 @@ | |||
3 | * | 3 | * |
4 | * Copyright (C) 2008 Steven Rostedt <srostedt@redhat.com> | 4 | * Copyright (C) 2008 Steven Rostedt <srostedt@redhat.com> |
5 | */ | 5 | */ |
6 | #include <linux/ftrace_event.h> | ||
6 | #include <linux/ring_buffer.h> | 7 | #include <linux/ring_buffer.h> |
7 | #include <linux/trace_clock.h> | 8 | #include <linux/trace_clock.h> |
9 | #include <linux/trace_seq.h> | ||
8 | #include <linux/spinlock.h> | 10 | #include <linux/spinlock.h> |
9 | #include <linux/debugfs.h> | 11 | #include <linux/debugfs.h> |
10 | #include <linux/uaccess.h> | 12 | #include <linux/uaccess.h> |
@@ -21,7 +23,6 @@ | |||
21 | #include <linux/fs.h> | 23 | #include <linux/fs.h> |
22 | 24 | ||
23 | #include <asm/local.h> | 25 | #include <asm/local.h> |
24 | #include "trace.h" | ||
25 | 26 | ||
26 | static void update_pages_handler(struct work_struct *work); | 27 | static void update_pages_handler(struct work_struct *work); |
27 | 28 | ||
@@ -2432,41 +2433,76 @@ rb_reserve_next_event(struct ring_buffer *buffer, | |||
2432 | 2433 | ||
2433 | #ifdef CONFIG_TRACING | 2434 | #ifdef CONFIG_TRACING |
2434 | 2435 | ||
2435 | #define TRACE_RECURSIVE_DEPTH 16 | 2436 | /* |
2437 | * The lock and unlock are done within a preempt disable section. | ||
2438 | * The current_context per_cpu variable can only be modified | ||
2439 | * by the current task between lock and unlock. But it can | ||
2440 | * be modified more than once via an interrupt. To pass this | ||
2441 | * information from the lock to the unlock without having to | ||
2442 | * access the 'in_interrupt()' functions again (which do show | ||
2443 | * a bit of overhead in something as critical as function tracing, | ||
2444 | * we use a bitmask trick. | ||
2445 | * | ||
2446 | * bit 0 = NMI context | ||
2447 | * bit 1 = IRQ context | ||
2448 | * bit 2 = SoftIRQ context | ||
2449 | * bit 3 = normal context. | ||
2450 | * | ||
2451 | * This works because this is the order of contexts that can | ||
2452 | * preempt other contexts. A SoftIRQ never preempts an IRQ | ||
2453 | * context. | ||
2454 | * | ||
2455 | * When the context is determined, the corresponding bit is | ||
2456 | * checked and set (if it was set, then a recursion of that context | ||
2457 | * happened). | ||
2458 | * | ||
2459 | * On unlock, we need to clear this bit. To do so, just subtract | ||
2460 | * 1 from the current_context and AND it to itself. | ||
2461 | * | ||
2462 | * (binary) | ||
2463 | * 101 - 1 = 100 | ||
2464 | * 101 & 100 = 100 (clearing bit zero) | ||
2465 | * | ||
2466 | * 1010 - 1 = 1001 | ||
2467 | * 1010 & 1001 = 1000 (clearing bit 1) | ||
2468 | * | ||
2469 | * The least significant bit can be cleared this way, and it | ||
2470 | * just so happens that it is the same bit corresponding to | ||
2471 | * the current context. | ||
2472 | */ | ||
2473 | static DEFINE_PER_CPU(unsigned int, current_context); | ||
2436 | 2474 | ||
2437 | /* Keep this code out of the fast path cache */ | 2475 | static __always_inline int trace_recursive_lock(void) |
2438 | static noinline void trace_recursive_fail(void) | ||
2439 | { | 2476 | { |
2440 | /* Disable all tracing before we do anything else */ | 2477 | unsigned int val = this_cpu_read(current_context); |
2441 | tracing_off_permanent(); | 2478 | int bit; |
2442 | |||
2443 | printk_once(KERN_WARNING "Tracing recursion: depth[%ld]:" | ||
2444 | "HC[%lu]:SC[%lu]:NMI[%lu]\n", | ||
2445 | trace_recursion_buffer(), | ||
2446 | hardirq_count() >> HARDIRQ_SHIFT, | ||
2447 | softirq_count() >> SOFTIRQ_SHIFT, | ||
2448 | in_nmi()); | ||
2449 | |||
2450 | WARN_ON_ONCE(1); | ||
2451 | } | ||
2452 | 2479 | ||
2453 | static inline int trace_recursive_lock(void) | 2480 | if (in_interrupt()) { |
2454 | { | 2481 | if (in_nmi()) |
2455 | trace_recursion_inc(); | 2482 | bit = 0; |
2483 | else if (in_irq()) | ||
2484 | bit = 1; | ||
2485 | else | ||
2486 | bit = 2; | ||
2487 | } else | ||
2488 | bit = 3; | ||
2456 | 2489 | ||
2457 | if (likely(trace_recursion_buffer() < TRACE_RECURSIVE_DEPTH)) | 2490 | if (unlikely(val & (1 << bit))) |
2458 | return 0; | 2491 | return 1; |
2459 | 2492 | ||
2460 | trace_recursive_fail(); | 2493 | val |= (1 << bit); |
2494 | this_cpu_write(current_context, val); | ||
2461 | 2495 | ||
2462 | return -1; | 2496 | return 0; |
2463 | } | 2497 | } |
2464 | 2498 | ||
2465 | static inline void trace_recursive_unlock(void) | 2499 | static __always_inline void trace_recursive_unlock(void) |
2466 | { | 2500 | { |
2467 | WARN_ON_ONCE(!trace_recursion_buffer()); | 2501 | unsigned int val = this_cpu_read(current_context); |
2468 | 2502 | ||
2469 | trace_recursion_dec(); | 2503 | val--; |
2504 | val &= this_cpu_read(current_context); | ||
2505 | this_cpu_write(current_context, val); | ||
2470 | } | 2506 | } |
2471 | 2507 | ||
2472 | #else | 2508 | #else |
@@ -3067,6 +3103,24 @@ ring_buffer_dropped_events_cpu(struct ring_buffer *buffer, int cpu) | |||
3067 | EXPORT_SYMBOL_GPL(ring_buffer_dropped_events_cpu); | 3103 | EXPORT_SYMBOL_GPL(ring_buffer_dropped_events_cpu); |
3068 | 3104 | ||
3069 | /** | 3105 | /** |
3106 | * ring_buffer_read_events_cpu - get the number of events successfully read | ||
3107 | * @buffer: The ring buffer | ||
3108 | * @cpu: The per CPU buffer to get the number of events read | ||
3109 | */ | ||
3110 | unsigned long | ||
3111 | ring_buffer_read_events_cpu(struct ring_buffer *buffer, int cpu) | ||
3112 | { | ||
3113 | struct ring_buffer_per_cpu *cpu_buffer; | ||
3114 | |||
3115 | if (!cpumask_test_cpu(cpu, buffer->cpumask)) | ||
3116 | return 0; | ||
3117 | |||
3118 | cpu_buffer = buffer->buffers[cpu]; | ||
3119 | return cpu_buffer->read; | ||
3120 | } | ||
3121 | EXPORT_SYMBOL_GPL(ring_buffer_read_events_cpu); | ||
3122 | |||
3123 | /** | ||
3070 | * ring_buffer_entries - get the number of entries in a buffer | 3124 | * ring_buffer_entries - get the number of entries in a buffer |
3071 | * @buffer: The ring buffer | 3125 | * @buffer: The ring buffer |
3072 | * | 3126 | * |
@@ -3425,7 +3479,7 @@ static void rb_advance_iter(struct ring_buffer_iter *iter) | |||
3425 | /* check for end of page padding */ | 3479 | /* check for end of page padding */ |
3426 | if ((iter->head >= rb_page_size(iter->head_page)) && | 3480 | if ((iter->head >= rb_page_size(iter->head_page)) && |
3427 | (iter->head_page != cpu_buffer->commit_page)) | 3481 | (iter->head_page != cpu_buffer->commit_page)) |
3428 | rb_advance_iter(iter); | 3482 | rb_inc_iter(iter); |
3429 | } | 3483 | } |
3430 | 3484 | ||
3431 | static int rb_lost_events(struct ring_buffer_per_cpu *cpu_buffer) | 3485 | static int rb_lost_events(struct ring_buffer_per_cpu *cpu_buffer) |
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 3c13e46d7d24..c2e2c2310374 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <linux/poll.h> | 39 | #include <linux/poll.h> |
40 | #include <linux/nmi.h> | 40 | #include <linux/nmi.h> |
41 | #include <linux/fs.h> | 41 | #include <linux/fs.h> |
42 | #include <linux/sched/rt.h> | ||
42 | 43 | ||
43 | #include "trace.h" | 44 | #include "trace.h" |
44 | #include "trace_output.h" | 45 | #include "trace_output.h" |
@@ -249,7 +250,7 @@ static unsigned long trace_buf_size = TRACE_BUF_SIZE_DEFAULT; | |||
249 | static struct tracer *trace_types __read_mostly; | 250 | static struct tracer *trace_types __read_mostly; |
250 | 251 | ||
251 | /* current_trace points to the tracer that is currently active */ | 252 | /* current_trace points to the tracer that is currently active */ |
252 | static struct tracer *current_trace __read_mostly; | 253 | static struct tracer *current_trace __read_mostly = &nop_trace; |
253 | 254 | ||
254 | /* | 255 | /* |
255 | * trace_types_lock is used to protect the trace_types list. | 256 | * trace_types_lock is used to protect the trace_types list. |
@@ -709,10 +710,13 @@ update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu) | |||
709 | return; | 710 | return; |
710 | 711 | ||
711 | WARN_ON_ONCE(!irqs_disabled()); | 712 | WARN_ON_ONCE(!irqs_disabled()); |
712 | if (!current_trace->use_max_tr) { | 713 | |
713 | WARN_ON_ONCE(1); | 714 | if (!current_trace->allocated_snapshot) { |
715 | /* Only the nop tracer should hit this when disabling */ | ||
716 | WARN_ON_ONCE(current_trace != &nop_trace); | ||
714 | return; | 717 | return; |
715 | } | 718 | } |
719 | |||
716 | arch_spin_lock(&ftrace_max_lock); | 720 | arch_spin_lock(&ftrace_max_lock); |
717 | 721 | ||
718 | tr->buffer = max_tr.buffer; | 722 | tr->buffer = max_tr.buffer; |
@@ -739,10 +743,8 @@ update_max_tr_single(struct trace_array *tr, struct task_struct *tsk, int cpu) | |||
739 | return; | 743 | return; |
740 | 744 | ||
741 | WARN_ON_ONCE(!irqs_disabled()); | 745 | WARN_ON_ONCE(!irqs_disabled()); |
742 | if (!current_trace->use_max_tr) { | 746 | if (WARN_ON_ONCE(!current_trace->allocated_snapshot)) |
743 | WARN_ON_ONCE(1); | ||
744 | return; | 747 | return; |
745 | } | ||
746 | 748 | ||
747 | arch_spin_lock(&ftrace_max_lock); | 749 | arch_spin_lock(&ftrace_max_lock); |
748 | 750 | ||
@@ -862,10 +864,13 @@ int register_tracer(struct tracer *type) | |||
862 | 864 | ||
863 | current_trace = type; | 865 | current_trace = type; |
864 | 866 | ||
865 | /* If we expanded the buffers, make sure the max is expanded too */ | 867 | if (type->use_max_tr) { |
866 | if (ring_buffer_expanded && type->use_max_tr) | 868 | /* If we expanded the buffers, make sure the max is expanded too */ |
867 | ring_buffer_resize(max_tr.buffer, trace_buf_size, | 869 | if (ring_buffer_expanded) |
868 | RING_BUFFER_ALL_CPUS); | 870 | ring_buffer_resize(max_tr.buffer, trace_buf_size, |
871 | RING_BUFFER_ALL_CPUS); | ||
872 | type->allocated_snapshot = true; | ||
873 | } | ||
869 | 874 | ||
870 | /* the test is responsible for initializing and enabling */ | 875 | /* the test is responsible for initializing and enabling */ |
871 | pr_info("Testing tracer %s: ", type->name); | 876 | pr_info("Testing tracer %s: ", type->name); |
@@ -881,10 +886,14 @@ int register_tracer(struct tracer *type) | |||
881 | /* Only reset on passing, to avoid touching corrupted buffers */ | 886 | /* Only reset on passing, to avoid touching corrupted buffers */ |
882 | tracing_reset_online_cpus(tr); | 887 | tracing_reset_online_cpus(tr); |
883 | 888 | ||
884 | /* Shrink the max buffer again */ | 889 | if (type->use_max_tr) { |
885 | if (ring_buffer_expanded && type->use_max_tr) | 890 | type->allocated_snapshot = false; |
886 | ring_buffer_resize(max_tr.buffer, 1, | 891 | |
887 | RING_BUFFER_ALL_CPUS); | 892 | /* Shrink the max buffer again */ |
893 | if (ring_buffer_expanded) | ||
894 | ring_buffer_resize(max_tr.buffer, 1, | ||
895 | RING_BUFFER_ALL_CPUS); | ||
896 | } | ||
888 | 897 | ||
889 | printk(KERN_CONT "PASSED\n"); | 898 | printk(KERN_CONT "PASSED\n"); |
890 | } | 899 | } |
@@ -922,6 +931,9 @@ void tracing_reset(struct trace_array *tr, int cpu) | |||
922 | { | 931 | { |
923 | struct ring_buffer *buffer = tr->buffer; | 932 | struct ring_buffer *buffer = tr->buffer; |
924 | 933 | ||
934 | if (!buffer) | ||
935 | return; | ||
936 | |||
925 | ring_buffer_record_disable(buffer); | 937 | ring_buffer_record_disable(buffer); |
926 | 938 | ||
927 | /* Make sure all commits have finished */ | 939 | /* Make sure all commits have finished */ |
@@ -936,6 +948,9 @@ void tracing_reset_online_cpus(struct trace_array *tr) | |||
936 | struct ring_buffer *buffer = tr->buffer; | 948 | struct ring_buffer *buffer = tr->buffer; |
937 | int cpu; | 949 | int cpu; |
938 | 950 | ||
951 | if (!buffer) | ||
952 | return; | ||
953 | |||
939 | ring_buffer_record_disable(buffer); | 954 | ring_buffer_record_disable(buffer); |
940 | 955 | ||
941 | /* Make sure all commits have finished */ | 956 | /* Make sure all commits have finished */ |
@@ -1167,7 +1182,6 @@ tracing_generic_entry_update(struct trace_entry *entry, unsigned long flags, | |||
1167 | 1182 | ||
1168 | entry->preempt_count = pc & 0xff; | 1183 | entry->preempt_count = pc & 0xff; |
1169 | entry->pid = (tsk) ? tsk->pid : 0; | 1184 | entry->pid = (tsk) ? tsk->pid : 0; |
1170 | entry->padding = 0; | ||
1171 | entry->flags = | 1185 | entry->flags = |
1172 | #ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT | 1186 | #ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT |
1173 | (irqs_disabled_flags(flags) ? TRACE_FLAG_IRQS_OFF : 0) | | 1187 | (irqs_disabled_flags(flags) ? TRACE_FLAG_IRQS_OFF : 0) | |
@@ -1335,7 +1349,7 @@ static void __ftrace_trace_stack(struct ring_buffer *buffer, | |||
1335 | */ | 1349 | */ |
1336 | preempt_disable_notrace(); | 1350 | preempt_disable_notrace(); |
1337 | 1351 | ||
1338 | use_stack = ++__get_cpu_var(ftrace_stack_reserve); | 1352 | use_stack = __this_cpu_inc_return(ftrace_stack_reserve); |
1339 | /* | 1353 | /* |
1340 | * We don't need any atomic variables, just a barrier. | 1354 | * We don't need any atomic variables, just a barrier. |
1341 | * If an interrupt comes in, we don't care, because it would | 1355 | * If an interrupt comes in, we don't care, because it would |
@@ -1389,7 +1403,7 @@ static void __ftrace_trace_stack(struct ring_buffer *buffer, | |||
1389 | out: | 1403 | out: |
1390 | /* Again, don't let gcc optimize things here */ | 1404 | /* Again, don't let gcc optimize things here */ |
1391 | barrier(); | 1405 | barrier(); |
1392 | __get_cpu_var(ftrace_stack_reserve)--; | 1406 | __this_cpu_dec(ftrace_stack_reserve); |
1393 | preempt_enable_notrace(); | 1407 | preempt_enable_notrace(); |
1394 | 1408 | ||
1395 | } | 1409 | } |
@@ -1517,7 +1531,6 @@ static struct trace_buffer_struct *trace_percpu_nmi_buffer; | |||
1517 | static char *get_trace_buf(void) | 1531 | static char *get_trace_buf(void) |
1518 | { | 1532 | { |
1519 | struct trace_buffer_struct *percpu_buffer; | 1533 | struct trace_buffer_struct *percpu_buffer; |
1520 | struct trace_buffer_struct *buffer; | ||
1521 | 1534 | ||
1522 | /* | 1535 | /* |
1523 | * If we have allocated per cpu buffers, then we do not | 1536 | * If we have allocated per cpu buffers, then we do not |
@@ -1535,9 +1548,7 @@ static char *get_trace_buf(void) | |||
1535 | if (!percpu_buffer) | 1548 | if (!percpu_buffer) |
1536 | return NULL; | 1549 | return NULL; |
1537 | 1550 | ||
1538 | buffer = per_cpu_ptr(percpu_buffer, smp_processor_id()); | 1551 | return this_cpu_ptr(&percpu_buffer->buffer[0]); |
1539 | |||
1540 | return buffer->buffer; | ||
1541 | } | 1552 | } |
1542 | 1553 | ||
1543 | static int alloc_percpu_trace_buffer(void) | 1554 | static int alloc_percpu_trace_buffer(void) |
@@ -1942,21 +1953,27 @@ void tracing_iter_reset(struct trace_iterator *iter, int cpu) | |||
1942 | static void *s_start(struct seq_file *m, loff_t *pos) | 1953 | static void *s_start(struct seq_file *m, loff_t *pos) |
1943 | { | 1954 | { |
1944 | struct trace_iterator *iter = m->private; | 1955 | struct trace_iterator *iter = m->private; |
1945 | static struct tracer *old_tracer; | ||
1946 | int cpu_file = iter->cpu_file; | 1956 | int cpu_file = iter->cpu_file; |
1947 | void *p = NULL; | 1957 | void *p = NULL; |
1948 | loff_t l = 0; | 1958 | loff_t l = 0; |
1949 | int cpu; | 1959 | int cpu; |
1950 | 1960 | ||
1951 | /* copy the tracer to avoid using a global lock all around */ | 1961 | /* |
1962 | * copy the tracer to avoid using a global lock all around. | ||
1963 | * iter->trace is a copy of current_trace, the pointer to the | ||
1964 | * name may be used instead of a strcmp(), as iter->trace->name | ||
1965 | * will point to the same string as current_trace->name. | ||
1966 | */ | ||
1952 | mutex_lock(&trace_types_lock); | 1967 | mutex_lock(&trace_types_lock); |
1953 | if (unlikely(old_tracer != current_trace && current_trace)) { | 1968 | if (unlikely(current_trace && iter->trace->name != current_trace->name)) |
1954 | old_tracer = current_trace; | ||
1955 | *iter->trace = *current_trace; | 1969 | *iter->trace = *current_trace; |
1956 | } | ||
1957 | mutex_unlock(&trace_types_lock); | 1970 | mutex_unlock(&trace_types_lock); |
1958 | 1971 | ||
1959 | atomic_inc(&trace_record_cmdline_disabled); | 1972 | if (iter->snapshot && iter->trace->use_max_tr) |
1973 | return ERR_PTR(-EBUSY); | ||
1974 | |||
1975 | if (!iter->snapshot) | ||
1976 | atomic_inc(&trace_record_cmdline_disabled); | ||
1960 | 1977 | ||
1961 | if (*pos != iter->pos) { | 1978 | if (*pos != iter->pos) { |
1962 | iter->ent = NULL; | 1979 | iter->ent = NULL; |
@@ -1995,7 +2012,11 @@ static void s_stop(struct seq_file *m, void *p) | |||
1995 | { | 2012 | { |
1996 | struct trace_iterator *iter = m->private; | 2013 | struct trace_iterator *iter = m->private; |
1997 | 2014 | ||
1998 | atomic_dec(&trace_record_cmdline_disabled); | 2015 | if (iter->snapshot && iter->trace->use_max_tr) |
2016 | return; | ||
2017 | |||
2018 | if (!iter->snapshot) | ||
2019 | atomic_dec(&trace_record_cmdline_disabled); | ||
1999 | trace_access_unlock(iter->cpu_file); | 2020 | trace_access_unlock(iter->cpu_file); |
2000 | trace_event_read_unlock(); | 2021 | trace_event_read_unlock(); |
2001 | } | 2022 | } |
@@ -2080,8 +2101,7 @@ print_trace_header(struct seq_file *m, struct trace_iterator *iter) | |||
2080 | unsigned long total; | 2101 | unsigned long total; |
2081 | const char *name = "preemption"; | 2102 | const char *name = "preemption"; |
2082 | 2103 | ||
2083 | if (type) | 2104 | name = type->name; |
2084 | name = type->name; | ||
2085 | 2105 | ||
2086 | get_total_entries(tr, &total, &entries); | 2106 | get_total_entries(tr, &total, &entries); |
2087 | 2107 | ||
@@ -2430,7 +2450,7 @@ static const struct seq_operations tracer_seq_ops = { | |||
2430 | }; | 2450 | }; |
2431 | 2451 | ||
2432 | static struct trace_iterator * | 2452 | static struct trace_iterator * |
2433 | __tracing_open(struct inode *inode, struct file *file) | 2453 | __tracing_open(struct inode *inode, struct file *file, bool snapshot) |
2434 | { | 2454 | { |
2435 | long cpu_file = (long) inode->i_private; | 2455 | long cpu_file = (long) inode->i_private; |
2436 | struct trace_iterator *iter; | 2456 | struct trace_iterator *iter; |
@@ -2457,16 +2477,16 @@ __tracing_open(struct inode *inode, struct file *file) | |||
2457 | if (!iter->trace) | 2477 | if (!iter->trace) |
2458 | goto fail; | 2478 | goto fail; |
2459 | 2479 | ||
2460 | if (current_trace) | 2480 | *iter->trace = *current_trace; |
2461 | *iter->trace = *current_trace; | ||
2462 | 2481 | ||
2463 | if (!zalloc_cpumask_var(&iter->started, GFP_KERNEL)) | 2482 | if (!zalloc_cpumask_var(&iter->started, GFP_KERNEL)) |
2464 | goto fail; | 2483 | goto fail; |
2465 | 2484 | ||
2466 | if (current_trace && current_trace->print_max) | 2485 | if (current_trace->print_max || snapshot) |
2467 | iter->tr = &max_tr; | 2486 | iter->tr = &max_tr; |
2468 | else | 2487 | else |
2469 | iter->tr = &global_trace; | 2488 | iter->tr = &global_trace; |
2489 | iter->snapshot = snapshot; | ||
2470 | iter->pos = -1; | 2490 | iter->pos = -1; |
2471 | mutex_init(&iter->mutex); | 2491 | mutex_init(&iter->mutex); |
2472 | iter->cpu_file = cpu_file; | 2492 | iter->cpu_file = cpu_file; |
@@ -2483,8 +2503,9 @@ __tracing_open(struct inode *inode, struct file *file) | |||
2483 | if (trace_clocks[trace_clock_id].in_ns) | 2503 | if (trace_clocks[trace_clock_id].in_ns) |
2484 | iter->iter_flags |= TRACE_FILE_TIME_IN_NS; | 2504 | iter->iter_flags |= TRACE_FILE_TIME_IN_NS; |
2485 | 2505 | ||
2486 | /* stop the trace while dumping */ | 2506 | /* stop the trace while dumping if we are not opening "snapshot" */ |
2487 | tracing_stop(); | 2507 | if (!iter->snapshot) |
2508 | tracing_stop(); | ||
2488 | 2509 | ||
2489 | if (iter->cpu_file == TRACE_PIPE_ALL_CPU) { | 2510 | if (iter->cpu_file == TRACE_PIPE_ALL_CPU) { |
2490 | for_each_tracing_cpu(cpu) { | 2511 | for_each_tracing_cpu(cpu) { |
@@ -2547,8 +2568,9 @@ static int tracing_release(struct inode *inode, struct file *file) | |||
2547 | if (iter->trace && iter->trace->close) | 2568 | if (iter->trace && iter->trace->close) |
2548 | iter->trace->close(iter); | 2569 | iter->trace->close(iter); |
2549 | 2570 | ||
2550 | /* reenable tracing if it was previously enabled */ | 2571 | if (!iter->snapshot) |
2551 | tracing_start(); | 2572 | /* reenable tracing if it was previously enabled */ |
2573 | tracing_start(); | ||
2552 | mutex_unlock(&trace_types_lock); | 2574 | mutex_unlock(&trace_types_lock); |
2553 | 2575 | ||
2554 | mutex_destroy(&iter->mutex); | 2576 | mutex_destroy(&iter->mutex); |
@@ -2576,7 +2598,7 @@ static int tracing_open(struct inode *inode, struct file *file) | |||
2576 | } | 2598 | } |
2577 | 2599 | ||
2578 | if (file->f_mode & FMODE_READ) { | 2600 | if (file->f_mode & FMODE_READ) { |
2579 | iter = __tracing_open(inode, file); | 2601 | iter = __tracing_open(inode, file, false); |
2580 | if (IS_ERR(iter)) | 2602 | if (IS_ERR(iter)) |
2581 | ret = PTR_ERR(iter); | 2603 | ret = PTR_ERR(iter); |
2582 | else if (trace_flags & TRACE_ITER_LATENCY_FMT) | 2604 | else if (trace_flags & TRACE_ITER_LATENCY_FMT) |
@@ -3014,10 +3036,7 @@ tracing_set_trace_read(struct file *filp, char __user *ubuf, | |||
3014 | int r; | 3036 | int r; |
3015 | 3037 | ||
3016 | mutex_lock(&trace_types_lock); | 3038 | mutex_lock(&trace_types_lock); |
3017 | if (current_trace) | 3039 | r = sprintf(buf, "%s\n", current_trace->name); |
3018 | r = sprintf(buf, "%s\n", current_trace->name); | ||
3019 | else | ||
3020 | r = sprintf(buf, "\n"); | ||
3021 | mutex_unlock(&trace_types_lock); | 3040 | mutex_unlock(&trace_types_lock); |
3022 | 3041 | ||
3023 | return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); | 3042 | return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); |
@@ -3183,6 +3202,7 @@ static int tracing_set_tracer(const char *buf) | |||
3183 | static struct trace_option_dentry *topts; | 3202 | static struct trace_option_dentry *topts; |
3184 | struct trace_array *tr = &global_trace; | 3203 | struct trace_array *tr = &global_trace; |
3185 | struct tracer *t; | 3204 | struct tracer *t; |
3205 | bool had_max_tr; | ||
3186 | int ret = 0; | 3206 | int ret = 0; |
3187 | 3207 | ||
3188 | mutex_lock(&trace_types_lock); | 3208 | mutex_lock(&trace_types_lock); |
@@ -3207,9 +3227,21 @@ static int tracing_set_tracer(const char *buf) | |||
3207 | goto out; | 3227 | goto out; |
3208 | 3228 | ||
3209 | trace_branch_disable(); | 3229 | trace_branch_disable(); |
3210 | if (current_trace && current_trace->reset) | 3230 | if (current_trace->reset) |
3211 | current_trace->reset(tr); | 3231 | current_trace->reset(tr); |
3212 | if (current_trace && current_trace->use_max_tr) { | 3232 | |
3233 | had_max_tr = current_trace->allocated_snapshot; | ||
3234 | current_trace = &nop_trace; | ||
3235 | |||
3236 | if (had_max_tr && !t->use_max_tr) { | ||
3237 | /* | ||
3238 | * We need to make sure that the update_max_tr sees that | ||
3239 | * current_trace changed to nop_trace to keep it from | ||
3240 | * swapping the buffers after we resize it. | ||
3241 | * The update_max_tr is called from interrupts disabled | ||
3242 | * so a synchronized_sched() is sufficient. | ||
3243 | */ | ||
3244 | synchronize_sched(); | ||
3213 | /* | 3245 | /* |
3214 | * We don't free the ring buffer. instead, resize it because | 3246 | * We don't free the ring buffer. instead, resize it because |
3215 | * The max_tr ring buffer has some state (e.g. ring->clock) and | 3247 | * The max_tr ring buffer has some state (e.g. ring->clock) and |
@@ -3217,18 +3249,19 @@ static int tracing_set_tracer(const char *buf) | |||
3217 | */ | 3249 | */ |
3218 | ring_buffer_resize(max_tr.buffer, 1, RING_BUFFER_ALL_CPUS); | 3250 | ring_buffer_resize(max_tr.buffer, 1, RING_BUFFER_ALL_CPUS); |
3219 | set_buffer_entries(&max_tr, 1); | 3251 | set_buffer_entries(&max_tr, 1); |
3252 | tracing_reset_online_cpus(&max_tr); | ||
3253 | current_trace->allocated_snapshot = false; | ||
3220 | } | 3254 | } |
3221 | destroy_trace_option_files(topts); | 3255 | destroy_trace_option_files(topts); |
3222 | 3256 | ||
3223 | current_trace = &nop_trace; | ||
3224 | |||
3225 | topts = create_trace_option_files(t); | 3257 | topts = create_trace_option_files(t); |
3226 | if (t->use_max_tr) { | 3258 | if (t->use_max_tr && !had_max_tr) { |
3227 | /* we need to make per cpu buffer sizes equivalent */ | 3259 | /* we need to make per cpu buffer sizes equivalent */ |
3228 | ret = resize_buffer_duplicate_size(&max_tr, &global_trace, | 3260 | ret = resize_buffer_duplicate_size(&max_tr, &global_trace, |
3229 | RING_BUFFER_ALL_CPUS); | 3261 | RING_BUFFER_ALL_CPUS); |
3230 | if (ret < 0) | 3262 | if (ret < 0) |
3231 | goto out; | 3263 | goto out; |
3264 | t->allocated_snapshot = true; | ||
3232 | } | 3265 | } |
3233 | 3266 | ||
3234 | if (t->init) { | 3267 | if (t->init) { |
@@ -3336,8 +3369,7 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp) | |||
3336 | ret = -ENOMEM; | 3369 | ret = -ENOMEM; |
3337 | goto fail; | 3370 | goto fail; |
3338 | } | 3371 | } |
3339 | if (current_trace) | 3372 | *iter->trace = *current_trace; |
3340 | *iter->trace = *current_trace; | ||
3341 | 3373 | ||
3342 | if (!alloc_cpumask_var(&iter->started, GFP_KERNEL)) { | 3374 | if (!alloc_cpumask_var(&iter->started, GFP_KERNEL)) { |
3343 | ret = -ENOMEM; | 3375 | ret = -ENOMEM; |
@@ -3477,7 +3509,6 @@ tracing_read_pipe(struct file *filp, char __user *ubuf, | |||
3477 | size_t cnt, loff_t *ppos) | 3509 | size_t cnt, loff_t *ppos) |
3478 | { | 3510 | { |
3479 | struct trace_iterator *iter = filp->private_data; | 3511 | struct trace_iterator *iter = filp->private_data; |
3480 | static struct tracer *old_tracer; | ||
3481 | ssize_t sret; | 3512 | ssize_t sret; |
3482 | 3513 | ||
3483 | /* return any leftover data */ | 3514 | /* return any leftover data */ |
@@ -3489,10 +3520,8 @@ tracing_read_pipe(struct file *filp, char __user *ubuf, | |||
3489 | 3520 | ||
3490 | /* copy the tracer to avoid using a global lock all around */ | 3521 | /* copy the tracer to avoid using a global lock all around */ |
3491 | mutex_lock(&trace_types_lock); | 3522 | mutex_lock(&trace_types_lock); |
3492 | if (unlikely(old_tracer != current_trace && current_trace)) { | 3523 | if (unlikely(iter->trace->name != current_trace->name)) |
3493 | old_tracer = current_trace; | ||
3494 | *iter->trace = *current_trace; | 3524 | *iter->trace = *current_trace; |
3495 | } | ||
3496 | mutex_unlock(&trace_types_lock); | 3525 | mutex_unlock(&trace_types_lock); |
3497 | 3526 | ||
3498 | /* | 3527 | /* |
@@ -3648,7 +3677,6 @@ static ssize_t tracing_splice_read_pipe(struct file *filp, | |||
3648 | .ops = &tracing_pipe_buf_ops, | 3677 | .ops = &tracing_pipe_buf_ops, |
3649 | .spd_release = tracing_spd_release_pipe, | 3678 | .spd_release = tracing_spd_release_pipe, |
3650 | }; | 3679 | }; |
3651 | static struct tracer *old_tracer; | ||
3652 | ssize_t ret; | 3680 | ssize_t ret; |
3653 | size_t rem; | 3681 | size_t rem; |
3654 | unsigned int i; | 3682 | unsigned int i; |
@@ -3658,10 +3686,8 @@ static ssize_t tracing_splice_read_pipe(struct file *filp, | |||
3658 | 3686 | ||
3659 | /* copy the tracer to avoid using a global lock all around */ | 3687 | /* copy the tracer to avoid using a global lock all around */ |
3660 | mutex_lock(&trace_types_lock); | 3688 | mutex_lock(&trace_types_lock); |
3661 | if (unlikely(old_tracer != current_trace && current_trace)) { | 3689 | if (unlikely(iter->trace->name != current_trace->name)) |
3662 | old_tracer = current_trace; | ||
3663 | *iter->trace = *current_trace; | 3690 | *iter->trace = *current_trace; |
3664 | } | ||
3665 | mutex_unlock(&trace_types_lock); | 3691 | mutex_unlock(&trace_types_lock); |
3666 | 3692 | ||
3667 | mutex_lock(&iter->mutex); | 3693 | mutex_lock(&iter->mutex); |
@@ -4037,8 +4063,7 @@ static ssize_t tracing_clock_write(struct file *filp, const char __user *ubuf, | |||
4037 | * Reset the buffer so that it doesn't have incomparable timestamps. | 4063 | * Reset the buffer so that it doesn't have incomparable timestamps. |
4038 | */ | 4064 | */ |
4039 | tracing_reset_online_cpus(&global_trace); | 4065 | tracing_reset_online_cpus(&global_trace); |
4040 | if (max_tr.buffer) | 4066 | tracing_reset_online_cpus(&max_tr); |
4041 | tracing_reset_online_cpus(&max_tr); | ||
4042 | 4067 | ||
4043 | mutex_unlock(&trace_types_lock); | 4068 | mutex_unlock(&trace_types_lock); |
4044 | 4069 | ||
@@ -4054,6 +4079,87 @@ static int tracing_clock_open(struct inode *inode, struct file *file) | |||
4054 | return single_open(file, tracing_clock_show, NULL); | 4079 | return single_open(file, tracing_clock_show, NULL); |
4055 | } | 4080 | } |
4056 | 4081 | ||
4082 | #ifdef CONFIG_TRACER_SNAPSHOT | ||
4083 | static int tracing_snapshot_open(struct inode *inode, struct file *file) | ||
4084 | { | ||
4085 | struct trace_iterator *iter; | ||
4086 | int ret = 0; | ||
4087 | |||
4088 | if (file->f_mode & FMODE_READ) { | ||
4089 | iter = __tracing_open(inode, file, true); | ||
4090 | if (IS_ERR(iter)) | ||
4091 | ret = PTR_ERR(iter); | ||
4092 | } | ||
4093 | return ret; | ||
4094 | } | ||
4095 | |||
4096 | static ssize_t | ||
4097 | tracing_snapshot_write(struct file *filp, const char __user *ubuf, size_t cnt, | ||
4098 | loff_t *ppos) | ||
4099 | { | ||
4100 | unsigned long val; | ||
4101 | int ret; | ||
4102 | |||
4103 | ret = tracing_update_buffers(); | ||
4104 | if (ret < 0) | ||
4105 | return ret; | ||
4106 | |||
4107 | ret = kstrtoul_from_user(ubuf, cnt, 10, &val); | ||
4108 | if (ret) | ||
4109 | return ret; | ||
4110 | |||
4111 | mutex_lock(&trace_types_lock); | ||
4112 | |||
4113 | if (current_trace->use_max_tr) { | ||
4114 | ret = -EBUSY; | ||
4115 | goto out; | ||
4116 | } | ||
4117 | |||
4118 | switch (val) { | ||
4119 | case 0: | ||
4120 | if (current_trace->allocated_snapshot) { | ||
4121 | /* free spare buffer */ | ||
4122 | ring_buffer_resize(max_tr.buffer, 1, | ||
4123 | RING_BUFFER_ALL_CPUS); | ||
4124 | set_buffer_entries(&max_tr, 1); | ||
4125 | tracing_reset_online_cpus(&max_tr); | ||
4126 | current_trace->allocated_snapshot = false; | ||
4127 | } | ||
4128 | break; | ||
4129 | case 1: | ||
4130 | if (!current_trace->allocated_snapshot) { | ||
4131 | /* allocate spare buffer */ | ||
4132 | ret = resize_buffer_duplicate_size(&max_tr, | ||
4133 | &global_trace, RING_BUFFER_ALL_CPUS); | ||
4134 | if (ret < 0) | ||
4135 | break; | ||
4136 | current_trace->allocated_snapshot = true; | ||
4137 | } | ||
4138 | |||
4139 | local_irq_disable(); | ||
4140 | /* Now, we're going to swap */ | ||
4141 | update_max_tr(&global_trace, current, smp_processor_id()); | ||
4142 | local_irq_enable(); | ||
4143 | break; | ||
4144 | default: | ||
4145 | if (current_trace->allocated_snapshot) | ||
4146 | tracing_reset_online_cpus(&max_tr); | ||
4147 | else | ||
4148 | ret = -EINVAL; | ||
4149 | break; | ||
4150 | } | ||
4151 | |||
4152 | if (ret >= 0) { | ||
4153 | *ppos += cnt; | ||
4154 | ret = cnt; | ||
4155 | } | ||
4156 | out: | ||
4157 | mutex_unlock(&trace_types_lock); | ||
4158 | return ret; | ||
4159 | } | ||
4160 | #endif /* CONFIG_TRACER_SNAPSHOT */ | ||
4161 | |||
4162 | |||
4057 | static const struct file_operations tracing_max_lat_fops = { | 4163 | static const struct file_operations tracing_max_lat_fops = { |
4058 | .open = tracing_open_generic, | 4164 | .open = tracing_open_generic, |
4059 | .read = tracing_max_lat_read, | 4165 | .read = tracing_max_lat_read, |
@@ -4110,6 +4216,16 @@ static const struct file_operations trace_clock_fops = { | |||
4110 | .write = tracing_clock_write, | 4216 | .write = tracing_clock_write, |
4111 | }; | 4217 | }; |
4112 | 4218 | ||
4219 | #ifdef CONFIG_TRACER_SNAPSHOT | ||
4220 | static const struct file_operations snapshot_fops = { | ||
4221 | .open = tracing_snapshot_open, | ||
4222 | .read = seq_read, | ||
4223 | .write = tracing_snapshot_write, | ||
4224 | .llseek = tracing_seek, | ||
4225 | .release = tracing_release, | ||
4226 | }; | ||
4227 | #endif /* CONFIG_TRACER_SNAPSHOT */ | ||
4228 | |||
4113 | struct ftrace_buffer_info { | 4229 | struct ftrace_buffer_info { |
4114 | struct trace_array *tr; | 4230 | struct trace_array *tr; |
4115 | void *spare; | 4231 | void *spare; |
@@ -4414,6 +4530,9 @@ tracing_stats_read(struct file *filp, char __user *ubuf, | |||
4414 | cnt = ring_buffer_dropped_events_cpu(tr->buffer, cpu); | 4530 | cnt = ring_buffer_dropped_events_cpu(tr->buffer, cpu); |
4415 | trace_seq_printf(s, "dropped events: %ld\n", cnt); | 4531 | trace_seq_printf(s, "dropped events: %ld\n", cnt); |
4416 | 4532 | ||
4533 | cnt = ring_buffer_read_events_cpu(tr->buffer, cpu); | ||
4534 | trace_seq_printf(s, "read events: %ld\n", cnt); | ||
4535 | |||
4417 | count = simple_read_from_buffer(ubuf, count, ppos, s->buffer, s->len); | 4536 | count = simple_read_from_buffer(ubuf, count, ppos, s->buffer, s->len); |
4418 | 4537 | ||
4419 | kfree(s); | 4538 | kfree(s); |
@@ -4490,7 +4609,7 @@ struct dentry *tracing_init_dentry(void) | |||
4490 | 4609 | ||
4491 | static struct dentry *d_percpu; | 4610 | static struct dentry *d_percpu; |
4492 | 4611 | ||
4493 | struct dentry *tracing_dentry_percpu(void) | 4612 | static struct dentry *tracing_dentry_percpu(void) |
4494 | { | 4613 | { |
4495 | static int once; | 4614 | static int once; |
4496 | struct dentry *d_tracer; | 4615 | struct dentry *d_tracer; |
@@ -4906,6 +5025,11 @@ static __init int tracer_init_debugfs(void) | |||
4906 | &ftrace_update_tot_cnt, &tracing_dyn_info_fops); | 5025 | &ftrace_update_tot_cnt, &tracing_dyn_info_fops); |
4907 | #endif | 5026 | #endif |
4908 | 5027 | ||
5028 | #ifdef CONFIG_TRACER_SNAPSHOT | ||
5029 | trace_create_file("snapshot", 0644, d_tracer, | ||
5030 | (void *) TRACE_PIPE_ALL_CPU, &snapshot_fops); | ||
5031 | #endif | ||
5032 | |||
4909 | create_trace_options_dir(); | 5033 | create_trace_options_dir(); |
4910 | 5034 | ||
4911 | for_each_tracing_cpu(cpu) | 5035 | for_each_tracing_cpu(cpu) |
@@ -5014,6 +5138,7 @@ __ftrace_dump(bool disable_tracing, enum ftrace_dump_mode oops_dump_mode) | |||
5014 | if (disable_tracing) | 5138 | if (disable_tracing) |
5015 | ftrace_kill(); | 5139 | ftrace_kill(); |
5016 | 5140 | ||
5141 | /* Simulate the iterator */ | ||
5017 | trace_init_global_iter(&iter); | 5142 | trace_init_global_iter(&iter); |
5018 | 5143 | ||
5019 | for_each_tracing_cpu(cpu) { | 5144 | for_each_tracing_cpu(cpu) { |
@@ -5025,10 +5150,6 @@ __ftrace_dump(bool disable_tracing, enum ftrace_dump_mode oops_dump_mode) | |||
5025 | /* don't look at user memory in panic mode */ | 5150 | /* don't look at user memory in panic mode */ |
5026 | trace_flags &= ~TRACE_ITER_SYM_USEROBJ; | 5151 | trace_flags &= ~TRACE_ITER_SYM_USEROBJ; |
5027 | 5152 | ||
5028 | /* Simulate the iterator */ | ||
5029 | iter.tr = &global_trace; | ||
5030 | iter.trace = current_trace; | ||
5031 | |||
5032 | switch (oops_dump_mode) { | 5153 | switch (oops_dump_mode) { |
5033 | case DUMP_ALL: | 5154 | case DUMP_ALL: |
5034 | iter.cpu_file = TRACE_PIPE_ALL_CPU; | 5155 | iter.cpu_file = TRACE_PIPE_ALL_CPU; |
@@ -5173,7 +5294,7 @@ __init static int tracer_alloc_buffers(void) | |||
5173 | init_irq_work(&trace_work_wakeup, trace_wake_up); | 5294 | init_irq_work(&trace_work_wakeup, trace_wake_up); |
5174 | 5295 | ||
5175 | register_tracer(&nop_trace); | 5296 | register_tracer(&nop_trace); |
5176 | current_trace = &nop_trace; | 5297 | |
5177 | /* All seems OK, enable tracing */ | 5298 | /* All seems OK, enable tracing */ |
5178 | tracing_disabled = 0; | 5299 | tracing_disabled = 0; |
5179 | 5300 | ||
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index c75d7988902c..57d7e5397d56 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
@@ -287,20 +287,62 @@ struct tracer { | |||
287 | struct tracer_flags *flags; | 287 | struct tracer_flags *flags; |
288 | bool print_max; | 288 | bool print_max; |
289 | bool use_max_tr; | 289 | bool use_max_tr; |
290 | bool allocated_snapshot; | ||
290 | }; | 291 | }; |
291 | 292 | ||
292 | 293 | ||
293 | /* Only current can touch trace_recursion */ | 294 | /* Only current can touch trace_recursion */ |
294 | #define trace_recursion_inc() do { (current)->trace_recursion++; } while (0) | ||
295 | #define trace_recursion_dec() do { (current)->trace_recursion--; } while (0) | ||
296 | 295 | ||
297 | /* Ring buffer has the 10 LSB bits to count */ | 296 | /* |
298 | #define trace_recursion_buffer() ((current)->trace_recursion & 0x3ff) | 297 | * For function tracing recursion: |
299 | 298 | * The order of these bits are important. | |
300 | /* for function tracing recursion */ | 299 | * |
301 | #define TRACE_INTERNAL_BIT (1<<11) | 300 | * When function tracing occurs, the following steps are made: |
302 | #define TRACE_GLOBAL_BIT (1<<12) | 301 | * If arch does not support a ftrace feature: |
303 | #define TRACE_CONTROL_BIT (1<<13) | 302 | * call internal function (uses INTERNAL bits) which calls... |
303 | * If callback is registered to the "global" list, the list | ||
304 | * function is called and recursion checks the GLOBAL bits. | ||
305 | * then this function calls... | ||
306 | * The function callback, which can use the FTRACE bits to | ||
307 | * check for recursion. | ||
308 | * | ||
309 | * Now if the arch does not suppport a feature, and it calls | ||
310 | * the global list function which calls the ftrace callback | ||
311 | * all three of these steps will do a recursion protection. | ||
312 | * There's no reason to do one if the previous caller already | ||
313 | * did. The recursion that we are protecting against will | ||
314 | * go through the same steps again. | ||
315 | * | ||
316 | * To prevent the multiple recursion checks, if a recursion | ||
317 | * bit is set that is higher than the MAX bit of the current | ||
318 | * check, then we know that the check was made by the previous | ||
319 | * caller, and we can skip the current check. | ||
320 | */ | ||
321 | enum { | ||
322 | TRACE_BUFFER_BIT, | ||
323 | TRACE_BUFFER_NMI_BIT, | ||
324 | TRACE_BUFFER_IRQ_BIT, | ||
325 | TRACE_BUFFER_SIRQ_BIT, | ||
326 | |||
327 | /* Start of function recursion bits */ | ||
328 | TRACE_FTRACE_BIT, | ||
329 | TRACE_FTRACE_NMI_BIT, | ||
330 | TRACE_FTRACE_IRQ_BIT, | ||
331 | TRACE_FTRACE_SIRQ_BIT, | ||
332 | |||
333 | /* GLOBAL_BITs must be greater than FTRACE_BITs */ | ||
334 | TRACE_GLOBAL_BIT, | ||
335 | TRACE_GLOBAL_NMI_BIT, | ||
336 | TRACE_GLOBAL_IRQ_BIT, | ||
337 | TRACE_GLOBAL_SIRQ_BIT, | ||
338 | |||
339 | /* INTERNAL_BITs must be greater than GLOBAL_BITs */ | ||
340 | TRACE_INTERNAL_BIT, | ||
341 | TRACE_INTERNAL_NMI_BIT, | ||
342 | TRACE_INTERNAL_IRQ_BIT, | ||
343 | TRACE_INTERNAL_SIRQ_BIT, | ||
344 | |||
345 | TRACE_CONTROL_BIT, | ||
304 | 346 | ||
305 | /* | 347 | /* |
306 | * Abuse of the trace_recursion. | 348 | * Abuse of the trace_recursion. |
@@ -309,11 +351,77 @@ struct tracer { | |||
309 | * was called in irq context but we have irq tracing off. Since this | 351 | * was called in irq context but we have irq tracing off. Since this |
310 | * can only be modified by current, we can reuse trace_recursion. | 352 | * can only be modified by current, we can reuse trace_recursion. |
311 | */ | 353 | */ |
312 | #define TRACE_IRQ_BIT (1<<13) | 354 | TRACE_IRQ_BIT, |
355 | }; | ||
356 | |||
357 | #define trace_recursion_set(bit) do { (current)->trace_recursion |= (1<<(bit)); } while (0) | ||
358 | #define trace_recursion_clear(bit) do { (current)->trace_recursion &= ~(1<<(bit)); } while (0) | ||
359 | #define trace_recursion_test(bit) ((current)->trace_recursion & (1<<(bit))) | ||
360 | |||
361 | #define TRACE_CONTEXT_BITS 4 | ||
362 | |||
363 | #define TRACE_FTRACE_START TRACE_FTRACE_BIT | ||
364 | #define TRACE_FTRACE_MAX ((1 << (TRACE_FTRACE_START + TRACE_CONTEXT_BITS)) - 1) | ||
365 | |||
366 | #define TRACE_GLOBAL_START TRACE_GLOBAL_BIT | ||
367 | #define TRACE_GLOBAL_MAX ((1 << (TRACE_GLOBAL_START + TRACE_CONTEXT_BITS)) - 1) | ||
368 | |||
369 | #define TRACE_LIST_START TRACE_INTERNAL_BIT | ||
370 | #define TRACE_LIST_MAX ((1 << (TRACE_LIST_START + TRACE_CONTEXT_BITS)) - 1) | ||
371 | |||
372 | #define TRACE_CONTEXT_MASK TRACE_LIST_MAX | ||
373 | |||
374 | static __always_inline int trace_get_context_bit(void) | ||
375 | { | ||
376 | int bit; | ||
313 | 377 | ||
314 | #define trace_recursion_set(bit) do { (current)->trace_recursion |= (bit); } while (0) | 378 | if (in_interrupt()) { |
315 | #define trace_recursion_clear(bit) do { (current)->trace_recursion &= ~(bit); } while (0) | 379 | if (in_nmi()) |
316 | #define trace_recursion_test(bit) ((current)->trace_recursion & (bit)) | 380 | bit = 0; |
381 | |||
382 | else if (in_irq()) | ||
383 | bit = 1; | ||
384 | else | ||
385 | bit = 2; | ||
386 | } else | ||
387 | bit = 3; | ||
388 | |||
389 | return bit; | ||
390 | } | ||
391 | |||
392 | static __always_inline int trace_test_and_set_recursion(int start, int max) | ||
393 | { | ||
394 | unsigned int val = current->trace_recursion; | ||
395 | int bit; | ||
396 | |||
397 | /* A previous recursion check was made */ | ||
398 | if ((val & TRACE_CONTEXT_MASK) > max) | ||
399 | return 0; | ||
400 | |||
401 | bit = trace_get_context_bit() + start; | ||
402 | if (unlikely(val & (1 << bit))) | ||
403 | return -1; | ||
404 | |||
405 | val |= 1 << bit; | ||
406 | current->trace_recursion = val; | ||
407 | barrier(); | ||
408 | |||
409 | return bit; | ||
410 | } | ||
411 | |||
412 | static __always_inline void trace_clear_recursion(int bit) | ||
413 | { | ||
414 | unsigned int val = current->trace_recursion; | ||
415 | |||
416 | if (!bit) | ||
417 | return; | ||
418 | |||
419 | bit = 1 << bit; | ||
420 | val &= ~bit; | ||
421 | |||
422 | barrier(); | ||
423 | current->trace_recursion = val; | ||
424 | } | ||
317 | 425 | ||
318 | #define TRACE_PIPE_ALL_CPU -1 | 426 | #define TRACE_PIPE_ALL_CPU -1 |
319 | 427 | ||
diff --git a/kernel/trace/trace_clock.c b/kernel/trace/trace_clock.c index 394783531cbb..aa8f5f48dae6 100644 --- a/kernel/trace/trace_clock.c +++ b/kernel/trace/trace_clock.c | |||
@@ -21,8 +21,6 @@ | |||
21 | #include <linux/ktime.h> | 21 | #include <linux/ktime.h> |
22 | #include <linux/trace_clock.h> | 22 | #include <linux/trace_clock.h> |
23 | 23 | ||
24 | #include "trace.h" | ||
25 | |||
26 | /* | 24 | /* |
27 | * trace_clock_local(): the simplest and least coherent tracing clock. | 25 | * trace_clock_local(): the simplest and least coherent tracing clock. |
28 | * | 26 | * |
@@ -44,6 +42,7 @@ u64 notrace trace_clock_local(void) | |||
44 | 42 | ||
45 | return clock; | 43 | return clock; |
46 | } | 44 | } |
45 | EXPORT_SYMBOL_GPL(trace_clock_local); | ||
47 | 46 | ||
48 | /* | 47 | /* |
49 | * trace_clock(): 'between' trace clock. Not completely serialized, | 48 | * trace_clock(): 'between' trace clock. Not completely serialized, |
@@ -86,7 +85,7 @@ u64 notrace trace_clock_global(void) | |||
86 | local_irq_save(flags); | 85 | local_irq_save(flags); |
87 | 86 | ||
88 | this_cpu = raw_smp_processor_id(); | 87 | this_cpu = raw_smp_processor_id(); |
89 | now = cpu_clock(this_cpu); | 88 | now = sched_clock_cpu(this_cpu); |
90 | /* | 89 | /* |
91 | * If in an NMI context then dont risk lockups and return the | 90 | * If in an NMI context then dont risk lockups and return the |
92 | * cpu_clock() time: | 91 | * cpu_clock() time: |
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 880073d0b946..57e9b284250c 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
@@ -116,7 +116,6 @@ static int trace_define_common_fields(void) | |||
116 | __common_field(unsigned char, flags); | 116 | __common_field(unsigned char, flags); |
117 | __common_field(unsigned char, preempt_count); | 117 | __common_field(unsigned char, preempt_count); |
118 | __common_field(int, pid); | 118 | __common_field(int, pid); |
119 | __common_field(int, padding); | ||
120 | 119 | ||
121 | return ret; | 120 | return ret; |
122 | } | 121 | } |
diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c index 8e3ad8082ab7..601152523326 100644 --- a/kernel/trace/trace_functions.c +++ b/kernel/trace/trace_functions.c | |||
@@ -47,34 +47,6 @@ static void function_trace_start(struct trace_array *tr) | |||
47 | tracing_reset_online_cpus(tr); | 47 | tracing_reset_online_cpus(tr); |
48 | } | 48 | } |
49 | 49 | ||
50 | static void | ||
51 | function_trace_call_preempt_only(unsigned long ip, unsigned long parent_ip, | ||
52 | struct ftrace_ops *op, struct pt_regs *pt_regs) | ||
53 | { | ||
54 | struct trace_array *tr = func_trace; | ||
55 | struct trace_array_cpu *data; | ||
56 | unsigned long flags; | ||
57 | long disabled; | ||
58 | int cpu; | ||
59 | int pc; | ||
60 | |||
61 | if (unlikely(!ftrace_function_enabled)) | ||
62 | return; | ||
63 | |||
64 | pc = preempt_count(); | ||
65 | preempt_disable_notrace(); | ||
66 | local_save_flags(flags); | ||
67 | cpu = raw_smp_processor_id(); | ||
68 | data = tr->data[cpu]; | ||
69 | disabled = atomic_inc_return(&data->disabled); | ||
70 | |||
71 | if (likely(disabled == 1)) | ||
72 | trace_function(tr, ip, parent_ip, flags, pc); | ||
73 | |||
74 | atomic_dec(&data->disabled); | ||
75 | preempt_enable_notrace(); | ||
76 | } | ||
77 | |||
78 | /* Our option */ | 50 | /* Our option */ |
79 | enum { | 51 | enum { |
80 | TRACE_FUNC_OPT_STACK = 0x1, | 52 | TRACE_FUNC_OPT_STACK = 0x1, |
@@ -85,34 +57,34 @@ static struct tracer_flags func_flags; | |||
85 | static void | 57 | static void |
86 | function_trace_call(unsigned long ip, unsigned long parent_ip, | 58 | function_trace_call(unsigned long ip, unsigned long parent_ip, |
87 | struct ftrace_ops *op, struct pt_regs *pt_regs) | 59 | struct ftrace_ops *op, struct pt_regs *pt_regs) |
88 | |||
89 | { | 60 | { |
90 | struct trace_array *tr = func_trace; | 61 | struct trace_array *tr = func_trace; |
91 | struct trace_array_cpu *data; | 62 | struct trace_array_cpu *data; |
92 | unsigned long flags; | 63 | unsigned long flags; |
93 | long disabled; | 64 | int bit; |
94 | int cpu; | 65 | int cpu; |
95 | int pc; | 66 | int pc; |
96 | 67 | ||
97 | if (unlikely(!ftrace_function_enabled)) | 68 | if (unlikely(!ftrace_function_enabled)) |
98 | return; | 69 | return; |
99 | 70 | ||
100 | /* | 71 | pc = preempt_count(); |
101 | * Need to use raw, since this must be called before the | 72 | preempt_disable_notrace(); |
102 | * recursive protection is performed. | ||
103 | */ | ||
104 | local_irq_save(flags); | ||
105 | cpu = raw_smp_processor_id(); | ||
106 | data = tr->data[cpu]; | ||
107 | disabled = atomic_inc_return(&data->disabled); | ||
108 | 73 | ||
109 | if (likely(disabled == 1)) { | 74 | bit = trace_test_and_set_recursion(TRACE_FTRACE_START, TRACE_FTRACE_MAX); |
110 | pc = preempt_count(); | 75 | if (bit < 0) |
76 | goto out; | ||
77 | |||
78 | cpu = smp_processor_id(); | ||
79 | data = tr->data[cpu]; | ||
80 | if (!atomic_read(&data->disabled)) { | ||
81 | local_save_flags(flags); | ||
111 | trace_function(tr, ip, parent_ip, flags, pc); | 82 | trace_function(tr, ip, parent_ip, flags, pc); |
112 | } | 83 | } |
84 | trace_clear_recursion(bit); | ||
113 | 85 | ||
114 | atomic_dec(&data->disabled); | 86 | out: |
115 | local_irq_restore(flags); | 87 | preempt_enable_notrace(); |
116 | } | 88 | } |
117 | 89 | ||
118 | static void | 90 | static void |
@@ -185,11 +157,6 @@ static void tracing_start_function_trace(void) | |||
185 | { | 157 | { |
186 | ftrace_function_enabled = 0; | 158 | ftrace_function_enabled = 0; |
187 | 159 | ||
188 | if (trace_flags & TRACE_ITER_PREEMPTONLY) | ||
189 | trace_ops.func = function_trace_call_preempt_only; | ||
190 | else | ||
191 | trace_ops.func = function_trace_call; | ||
192 | |||
193 | if (func_flags.val & TRACE_FUNC_OPT_STACK) | 160 | if (func_flags.val & TRACE_FUNC_OPT_STACK) |
194 | register_ftrace_function(&trace_stack_ops); | 161 | register_ftrace_function(&trace_stack_ops); |
195 | else | 162 | else |
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index 4edb4b74eb7e..39ada66389cc 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c | |||
@@ -47,6 +47,8 @@ struct fgraph_data { | |||
47 | #define TRACE_GRAPH_PRINT_ABS_TIME 0x20 | 47 | #define TRACE_GRAPH_PRINT_ABS_TIME 0x20 |
48 | #define TRACE_GRAPH_PRINT_IRQS 0x40 | 48 | #define TRACE_GRAPH_PRINT_IRQS 0x40 |
49 | 49 | ||
50 | static unsigned int max_depth; | ||
51 | |||
50 | static struct tracer_opt trace_opts[] = { | 52 | static struct tracer_opt trace_opts[] = { |
51 | /* Display overruns? (for self-debug purpose) */ | 53 | /* Display overruns? (for self-debug purpose) */ |
52 | { TRACER_OPT(funcgraph-overrun, TRACE_GRAPH_PRINT_OVERRUN) }, | 54 | { TRACER_OPT(funcgraph-overrun, TRACE_GRAPH_PRINT_OVERRUN) }, |
@@ -189,10 +191,16 @@ unsigned long ftrace_return_to_handler(unsigned long frame_pointer) | |||
189 | 191 | ||
190 | ftrace_pop_return_trace(&trace, &ret, frame_pointer); | 192 | ftrace_pop_return_trace(&trace, &ret, frame_pointer); |
191 | trace.rettime = trace_clock_local(); | 193 | trace.rettime = trace_clock_local(); |
192 | ftrace_graph_return(&trace); | ||
193 | barrier(); | 194 | barrier(); |
194 | current->curr_ret_stack--; | 195 | current->curr_ret_stack--; |
195 | 196 | ||
197 | /* | ||
198 | * The trace should run after decrementing the ret counter | ||
199 | * in case an interrupt were to come in. We don't want to | ||
200 | * lose the interrupt if max_depth is set. | ||
201 | */ | ||
202 | ftrace_graph_return(&trace); | ||
203 | |||
196 | if (unlikely(!ret)) { | 204 | if (unlikely(!ret)) { |
197 | ftrace_graph_stop(); | 205 | ftrace_graph_stop(); |
198 | WARN_ON(1); | 206 | WARN_ON(1); |
@@ -250,8 +258,9 @@ int trace_graph_entry(struct ftrace_graph_ent *trace) | |||
250 | return 0; | 258 | return 0; |
251 | 259 | ||
252 | /* trace it when it is-nested-in or is a function enabled. */ | 260 | /* trace it when it is-nested-in or is a function enabled. */ |
253 | if (!(trace->depth || ftrace_graph_addr(trace->func)) || | 261 | if ((!(trace->depth || ftrace_graph_addr(trace->func)) || |
254 | ftrace_graph_ignore_irqs()) | 262 | ftrace_graph_ignore_irqs()) || |
263 | (max_depth && trace->depth >= max_depth)) | ||
255 | return 0; | 264 | return 0; |
256 | 265 | ||
257 | local_irq_save(flags); | 266 | local_irq_save(flags); |
@@ -1457,6 +1466,59 @@ static struct tracer graph_trace __read_mostly = { | |||
1457 | #endif | 1466 | #endif |
1458 | }; | 1467 | }; |
1459 | 1468 | ||
1469 | |||
1470 | static ssize_t | ||
1471 | graph_depth_write(struct file *filp, const char __user *ubuf, size_t cnt, | ||
1472 | loff_t *ppos) | ||
1473 | { | ||
1474 | unsigned long val; | ||
1475 | int ret; | ||
1476 | |||
1477 | ret = kstrtoul_from_user(ubuf, cnt, 10, &val); | ||
1478 | if (ret) | ||
1479 | return ret; | ||
1480 | |||
1481 | max_depth = val; | ||
1482 | |||
1483 | *ppos += cnt; | ||
1484 | |||
1485 | return cnt; | ||
1486 | } | ||
1487 | |||
1488 | static ssize_t | ||
1489 | graph_depth_read(struct file *filp, char __user *ubuf, size_t cnt, | ||
1490 | loff_t *ppos) | ||
1491 | { | ||
1492 | char buf[15]; /* More than enough to hold UINT_MAX + "\n"*/ | ||
1493 | int n; | ||
1494 | |||
1495 | n = sprintf(buf, "%d\n", max_depth); | ||
1496 | |||
1497 | return simple_read_from_buffer(ubuf, cnt, ppos, buf, n); | ||
1498 | } | ||
1499 | |||
1500 | static const struct file_operations graph_depth_fops = { | ||
1501 | .open = tracing_open_generic, | ||
1502 | .write = graph_depth_write, | ||
1503 | .read = graph_depth_read, | ||
1504 | .llseek = generic_file_llseek, | ||
1505 | }; | ||
1506 | |||
1507 | static __init int init_graph_debugfs(void) | ||
1508 | { | ||
1509 | struct dentry *d_tracer; | ||
1510 | |||
1511 | d_tracer = tracing_init_dentry(); | ||
1512 | if (!d_tracer) | ||
1513 | return 0; | ||
1514 | |||
1515 | trace_create_file("max_graph_depth", 0644, d_tracer, | ||
1516 | NULL, &graph_depth_fops); | ||
1517 | |||
1518 | return 0; | ||
1519 | } | ||
1520 | fs_initcall(init_graph_debugfs); | ||
1521 | |||
1460 | static __init int init_graph_trace(void) | 1522 | static __init int init_graph_trace(void) |
1461 | { | 1523 | { |
1462 | max_bytes_for_cpu = snprintf(NULL, 0, "%d", nr_cpu_ids - 1); | 1524 | max_bytes_for_cpu = snprintf(NULL, 0, "%d", nr_cpu_ids - 1); |
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h index 933708677814..5c7e09d10d74 100644 --- a/kernel/trace/trace_probe.h +++ b/kernel/trace/trace_probe.h | |||
@@ -66,7 +66,6 @@ | |||
66 | #define TP_FLAG_TRACE 1 | 66 | #define TP_FLAG_TRACE 1 |
67 | #define TP_FLAG_PROFILE 2 | 67 | #define TP_FLAG_PROFILE 2 |
68 | #define TP_FLAG_REGISTERED 4 | 68 | #define TP_FLAG_REGISTERED 4 |
69 | #define TP_FLAG_UPROBE 8 | ||
70 | 69 | ||
71 | 70 | ||
72 | /* data_rloc: data relative location, compatible with u32 */ | 71 | /* data_rloc: data relative location, compatible with u32 */ |
diff --git a/kernel/trace/trace_sched_wakeup.c b/kernel/trace/trace_sched_wakeup.c index 9fe45fcefca0..75aa97fbe1a1 100644 --- a/kernel/trace/trace_sched_wakeup.c +++ b/kernel/trace/trace_sched_wakeup.c | |||
@@ -15,8 +15,8 @@ | |||
15 | #include <linux/kallsyms.h> | 15 | #include <linux/kallsyms.h> |
16 | #include <linux/uaccess.h> | 16 | #include <linux/uaccess.h> |
17 | #include <linux/ftrace.h> | 17 | #include <linux/ftrace.h> |
18 | #include <linux/sched/rt.h> | ||
18 | #include <trace/events/sched.h> | 19 | #include <trace/events/sched.h> |
19 | |||
20 | #include "trace.h" | 20 | #include "trace.h" |
21 | 21 | ||
22 | static struct trace_array *wakeup_trace; | 22 | static struct trace_array *wakeup_trace; |
diff --git a/kernel/trace/trace_selftest.c b/kernel/trace/trace_selftest.c index 47623169a815..51c819c12c29 100644 --- a/kernel/trace/trace_selftest.c +++ b/kernel/trace/trace_selftest.c | |||
@@ -415,7 +415,8 @@ static void trace_selftest_test_recursion_func(unsigned long ip, | |||
415 | * The ftrace infrastructure should provide the recursion | 415 | * The ftrace infrastructure should provide the recursion |
416 | * protection. If not, this will crash the kernel! | 416 | * protection. If not, this will crash the kernel! |
417 | */ | 417 | */ |
418 | trace_selftest_recursion_cnt++; | 418 | if (trace_selftest_recursion_cnt++ > 10) |
419 | return; | ||
419 | DYN_FTRACE_TEST_NAME(); | 420 | DYN_FTRACE_TEST_NAME(); |
420 | } | 421 | } |
421 | 422 | ||
@@ -452,7 +453,6 @@ trace_selftest_function_recursion(void) | |||
452 | char *func_name; | 453 | char *func_name; |
453 | int len; | 454 | int len; |
454 | int ret; | 455 | int ret; |
455 | int cnt; | ||
456 | 456 | ||
457 | /* The previous test PASSED */ | 457 | /* The previous test PASSED */ |
458 | pr_cont("PASSED\n"); | 458 | pr_cont("PASSED\n"); |
@@ -510,19 +510,10 @@ trace_selftest_function_recursion(void) | |||
510 | 510 | ||
511 | unregister_ftrace_function(&test_recsafe_probe); | 511 | unregister_ftrace_function(&test_recsafe_probe); |
512 | 512 | ||
513 | /* | ||
514 | * If arch supports all ftrace features, and no other task | ||
515 | * was on the list, we should be fine. | ||
516 | */ | ||
517 | if (!ftrace_nr_registered_ops() && !FTRACE_FORCE_LIST_FUNC) | ||
518 | cnt = 2; /* Should have recursed */ | ||
519 | else | ||
520 | cnt = 1; | ||
521 | |||
522 | ret = -1; | 513 | ret = -1; |
523 | if (trace_selftest_recursion_cnt != cnt) { | 514 | if (trace_selftest_recursion_cnt != 2) { |
524 | pr_cont("*callback not called expected %d times (%d)* ", | 515 | pr_cont("*callback not called expected 2 times (%d)* ", |
525 | cnt, trace_selftest_recursion_cnt); | 516 | trace_selftest_recursion_cnt); |
526 | goto out; | 517 | goto out; |
527 | } | 518 | } |
528 | 519 | ||
@@ -568,7 +559,7 @@ trace_selftest_function_regs(void) | |||
568 | int ret; | 559 | int ret; |
569 | int supported = 0; | 560 | int supported = 0; |
570 | 561 | ||
571 | #ifdef ARCH_SUPPORTS_FTRACE_SAVE_REGS | 562 | #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS |
572 | supported = 1; | 563 | supported = 1; |
573 | #endif | 564 | #endif |
574 | 565 | ||
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index 7609dd6714c2..5329e13e74a1 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c | |||
@@ -77,7 +77,7 @@ static struct syscall_metadata *syscall_nr_to_meta(int nr) | |||
77 | return syscalls_metadata[nr]; | 77 | return syscalls_metadata[nr]; |
78 | } | 78 | } |
79 | 79 | ||
80 | enum print_line_t | 80 | static enum print_line_t |
81 | print_syscall_enter(struct trace_iterator *iter, int flags, | 81 | print_syscall_enter(struct trace_iterator *iter, int flags, |
82 | struct trace_event *event) | 82 | struct trace_event *event) |
83 | { | 83 | { |
@@ -130,7 +130,7 @@ end: | |||
130 | return TRACE_TYPE_HANDLED; | 130 | return TRACE_TYPE_HANDLED; |
131 | } | 131 | } |
132 | 132 | ||
133 | enum print_line_t | 133 | static enum print_line_t |
134 | print_syscall_exit(struct trace_iterator *iter, int flags, | 134 | print_syscall_exit(struct trace_iterator *iter, int flags, |
135 | struct trace_event *event) | 135 | struct trace_event *event) |
136 | { | 136 | { |
@@ -270,7 +270,7 @@ static int syscall_exit_define_fields(struct ftrace_event_call *call) | |||
270 | return ret; | 270 | return ret; |
271 | } | 271 | } |
272 | 272 | ||
273 | void ftrace_syscall_enter(void *ignore, struct pt_regs *regs, long id) | 273 | static void ftrace_syscall_enter(void *ignore, struct pt_regs *regs, long id) |
274 | { | 274 | { |
275 | struct syscall_trace_enter *entry; | 275 | struct syscall_trace_enter *entry; |
276 | struct syscall_metadata *sys_data; | 276 | struct syscall_metadata *sys_data; |
@@ -305,7 +305,7 @@ void ftrace_syscall_enter(void *ignore, struct pt_regs *regs, long id) | |||
305 | trace_current_buffer_unlock_commit(buffer, event, 0, 0); | 305 | trace_current_buffer_unlock_commit(buffer, event, 0, 0); |
306 | } | 306 | } |
307 | 307 | ||
308 | void ftrace_syscall_exit(void *ignore, struct pt_regs *regs, long ret) | 308 | static void ftrace_syscall_exit(void *ignore, struct pt_regs *regs, long ret) |
309 | { | 309 | { |
310 | struct syscall_trace_exit *entry; | 310 | struct syscall_trace_exit *entry; |
311 | struct syscall_metadata *sys_data; | 311 | struct syscall_metadata *sys_data; |
@@ -337,7 +337,7 @@ void ftrace_syscall_exit(void *ignore, struct pt_regs *regs, long ret) | |||
337 | trace_current_buffer_unlock_commit(buffer, event, 0, 0); | 337 | trace_current_buffer_unlock_commit(buffer, event, 0, 0); |
338 | } | 338 | } |
339 | 339 | ||
340 | int reg_event_syscall_enter(struct ftrace_event_call *call) | 340 | static int reg_event_syscall_enter(struct ftrace_event_call *call) |
341 | { | 341 | { |
342 | int ret = 0; | 342 | int ret = 0; |
343 | int num; | 343 | int num; |
@@ -356,7 +356,7 @@ int reg_event_syscall_enter(struct ftrace_event_call *call) | |||
356 | return ret; | 356 | return ret; |
357 | } | 357 | } |
358 | 358 | ||
359 | void unreg_event_syscall_enter(struct ftrace_event_call *call) | 359 | static void unreg_event_syscall_enter(struct ftrace_event_call *call) |
360 | { | 360 | { |
361 | int num; | 361 | int num; |
362 | 362 | ||
@@ -371,7 +371,7 @@ void unreg_event_syscall_enter(struct ftrace_event_call *call) | |||
371 | mutex_unlock(&syscall_trace_lock); | 371 | mutex_unlock(&syscall_trace_lock); |
372 | } | 372 | } |
373 | 373 | ||
374 | int reg_event_syscall_exit(struct ftrace_event_call *call) | 374 | static int reg_event_syscall_exit(struct ftrace_event_call *call) |
375 | { | 375 | { |
376 | int ret = 0; | 376 | int ret = 0; |
377 | int num; | 377 | int num; |
@@ -390,7 +390,7 @@ int reg_event_syscall_exit(struct ftrace_event_call *call) | |||
390 | return ret; | 390 | return ret; |
391 | } | 391 | } |
392 | 392 | ||
393 | void unreg_event_syscall_exit(struct ftrace_event_call *call) | 393 | static void unreg_event_syscall_exit(struct ftrace_event_call *call) |
394 | { | 394 | { |
395 | int num; | 395 | int num; |
396 | 396 | ||
@@ -459,7 +459,7 @@ unsigned long __init __weak arch_syscall_addr(int nr) | |||
459 | return (unsigned long)sys_call_table[nr]; | 459 | return (unsigned long)sys_call_table[nr]; |
460 | } | 460 | } |
461 | 461 | ||
462 | int __init init_ftrace_syscalls(void) | 462 | static int __init init_ftrace_syscalls(void) |
463 | { | 463 | { |
464 | struct syscall_metadata *meta; | 464 | struct syscall_metadata *meta; |
465 | unsigned long addr; | 465 | unsigned long addr; |
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c index c86e6d4f67fb..8dad2a92dee9 100644 --- a/kernel/trace/trace_uprobe.c +++ b/kernel/trace/trace_uprobe.c | |||
@@ -28,20 +28,21 @@ | |||
28 | 28 | ||
29 | #define UPROBE_EVENT_SYSTEM "uprobes" | 29 | #define UPROBE_EVENT_SYSTEM "uprobes" |
30 | 30 | ||
31 | struct trace_uprobe_filter { | ||
32 | rwlock_t rwlock; | ||
33 | int nr_systemwide; | ||
34 | struct list_head perf_events; | ||
35 | }; | ||
36 | |||
31 | /* | 37 | /* |
32 | * uprobe event core functions | 38 | * uprobe event core functions |
33 | */ | 39 | */ |
34 | struct trace_uprobe; | ||
35 | struct uprobe_trace_consumer { | ||
36 | struct uprobe_consumer cons; | ||
37 | struct trace_uprobe *tu; | ||
38 | }; | ||
39 | |||
40 | struct trace_uprobe { | 40 | struct trace_uprobe { |
41 | struct list_head list; | 41 | struct list_head list; |
42 | struct ftrace_event_class class; | 42 | struct ftrace_event_class class; |
43 | struct ftrace_event_call call; | 43 | struct ftrace_event_call call; |
44 | struct uprobe_trace_consumer *consumer; | 44 | struct trace_uprobe_filter filter; |
45 | struct uprobe_consumer consumer; | ||
45 | struct inode *inode; | 46 | struct inode *inode; |
46 | char *filename; | 47 | char *filename; |
47 | unsigned long offset; | 48 | unsigned long offset; |
@@ -64,6 +65,18 @@ static LIST_HEAD(uprobe_list); | |||
64 | 65 | ||
65 | static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs); | 66 | static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs); |
66 | 67 | ||
68 | static inline void init_trace_uprobe_filter(struct trace_uprobe_filter *filter) | ||
69 | { | ||
70 | rwlock_init(&filter->rwlock); | ||
71 | filter->nr_systemwide = 0; | ||
72 | INIT_LIST_HEAD(&filter->perf_events); | ||
73 | } | ||
74 | |||
75 | static inline bool uprobe_filter_is_empty(struct trace_uprobe_filter *filter) | ||
76 | { | ||
77 | return !filter->nr_systemwide && list_empty(&filter->perf_events); | ||
78 | } | ||
79 | |||
67 | /* | 80 | /* |
68 | * Allocate new trace_uprobe and initialize it (including uprobes). | 81 | * Allocate new trace_uprobe and initialize it (including uprobes). |
69 | */ | 82 | */ |
@@ -92,6 +105,8 @@ alloc_trace_uprobe(const char *group, const char *event, int nargs) | |||
92 | goto error; | 105 | goto error; |
93 | 106 | ||
94 | INIT_LIST_HEAD(&tu->list); | 107 | INIT_LIST_HEAD(&tu->list); |
108 | tu->consumer.handler = uprobe_dispatcher; | ||
109 | init_trace_uprobe_filter(&tu->filter); | ||
95 | return tu; | 110 | return tu; |
96 | 111 | ||
97 | error: | 112 | error: |
@@ -253,12 +268,18 @@ static int create_trace_uprobe(int argc, char **argv) | |||
253 | if (ret) | 268 | if (ret) |
254 | goto fail_address_parse; | 269 | goto fail_address_parse; |
255 | 270 | ||
271 | inode = igrab(path.dentry->d_inode); | ||
272 | path_put(&path); | ||
273 | |||
274 | if (!inode || !S_ISREG(inode->i_mode)) { | ||
275 | ret = -EINVAL; | ||
276 | goto fail_address_parse; | ||
277 | } | ||
278 | |||
256 | ret = kstrtoul(arg, 0, &offset); | 279 | ret = kstrtoul(arg, 0, &offset); |
257 | if (ret) | 280 | if (ret) |
258 | goto fail_address_parse; | 281 | goto fail_address_parse; |
259 | 282 | ||
260 | inode = igrab(path.dentry->d_inode); | ||
261 | |||
262 | argc -= 2; | 283 | argc -= 2; |
263 | argv += 2; | 284 | argv += 2; |
264 | 285 | ||
@@ -356,7 +377,7 @@ fail_address_parse: | |||
356 | if (inode) | 377 | if (inode) |
357 | iput(inode); | 378 | iput(inode); |
358 | 379 | ||
359 | pr_info("Failed to parse address.\n"); | 380 | pr_info("Failed to parse address or file.\n"); |
360 | 381 | ||
361 | return ret; | 382 | return ret; |
362 | } | 383 | } |
@@ -465,7 +486,7 @@ static const struct file_operations uprobe_profile_ops = { | |||
465 | }; | 486 | }; |
466 | 487 | ||
467 | /* uprobe handler */ | 488 | /* uprobe handler */ |
468 | static void uprobe_trace_func(struct trace_uprobe *tu, struct pt_regs *regs) | 489 | static int uprobe_trace_func(struct trace_uprobe *tu, struct pt_regs *regs) |
469 | { | 490 | { |
470 | struct uprobe_trace_entry_head *entry; | 491 | struct uprobe_trace_entry_head *entry; |
471 | struct ring_buffer_event *event; | 492 | struct ring_buffer_event *event; |
@@ -475,8 +496,6 @@ static void uprobe_trace_func(struct trace_uprobe *tu, struct pt_regs *regs) | |||
475 | unsigned long irq_flags; | 496 | unsigned long irq_flags; |
476 | struct ftrace_event_call *call = &tu->call; | 497 | struct ftrace_event_call *call = &tu->call; |
477 | 498 | ||
478 | tu->nhit++; | ||
479 | |||
480 | local_save_flags(irq_flags); | 499 | local_save_flags(irq_flags); |
481 | pc = preempt_count(); | 500 | pc = preempt_count(); |
482 | 501 | ||
@@ -485,16 +504,18 @@ static void uprobe_trace_func(struct trace_uprobe *tu, struct pt_regs *regs) | |||
485 | event = trace_current_buffer_lock_reserve(&buffer, call->event.type, | 504 | event = trace_current_buffer_lock_reserve(&buffer, call->event.type, |
486 | size, irq_flags, pc); | 505 | size, irq_flags, pc); |
487 | if (!event) | 506 | if (!event) |
488 | return; | 507 | return 0; |
489 | 508 | ||
490 | entry = ring_buffer_event_data(event); | 509 | entry = ring_buffer_event_data(event); |
491 | entry->ip = uprobe_get_swbp_addr(task_pt_regs(current)); | 510 | entry->ip = instruction_pointer(task_pt_regs(current)); |
492 | data = (u8 *)&entry[1]; | 511 | data = (u8 *)&entry[1]; |
493 | for (i = 0; i < tu->nr_args; i++) | 512 | for (i = 0; i < tu->nr_args; i++) |
494 | call_fetch(&tu->args[i].fetch, regs, data + tu->args[i].offset); | 513 | call_fetch(&tu->args[i].fetch, regs, data + tu->args[i].offset); |
495 | 514 | ||
496 | if (!filter_current_check_discard(buffer, call, entry, event)) | 515 | if (!filter_current_check_discard(buffer, call, entry, event)) |
497 | trace_buffer_unlock_commit(buffer, event, irq_flags, pc); | 516 | trace_buffer_unlock_commit(buffer, event, irq_flags, pc); |
517 | |||
518 | return 0; | ||
498 | } | 519 | } |
499 | 520 | ||
500 | /* Event entry printers */ | 521 | /* Event entry printers */ |
@@ -533,42 +554,43 @@ partial: | |||
533 | return TRACE_TYPE_PARTIAL_LINE; | 554 | return TRACE_TYPE_PARTIAL_LINE; |
534 | } | 555 | } |
535 | 556 | ||
536 | static int probe_event_enable(struct trace_uprobe *tu, int flag) | 557 | static inline bool is_trace_uprobe_enabled(struct trace_uprobe *tu) |
537 | { | 558 | { |
538 | struct uprobe_trace_consumer *utc; | 559 | return tu->flags & (TP_FLAG_TRACE | TP_FLAG_PROFILE); |
539 | int ret = 0; | 560 | } |
540 | 561 | ||
541 | if (!tu->inode || tu->consumer) | 562 | typedef bool (*filter_func_t)(struct uprobe_consumer *self, |
542 | return -EINTR; | 563 | enum uprobe_filter_ctx ctx, |
564 | struct mm_struct *mm); | ||
543 | 565 | ||
544 | utc = kzalloc(sizeof(struct uprobe_trace_consumer), GFP_KERNEL); | 566 | static int |
545 | if (!utc) | 567 | probe_event_enable(struct trace_uprobe *tu, int flag, filter_func_t filter) |
568 | { | ||
569 | int ret = 0; | ||
570 | |||
571 | if (is_trace_uprobe_enabled(tu)) | ||
546 | return -EINTR; | 572 | return -EINTR; |
547 | 573 | ||
548 | utc->cons.handler = uprobe_dispatcher; | 574 | WARN_ON(!uprobe_filter_is_empty(&tu->filter)); |
549 | utc->cons.filter = NULL; | ||
550 | ret = uprobe_register(tu->inode, tu->offset, &utc->cons); | ||
551 | if (ret) { | ||
552 | kfree(utc); | ||
553 | return ret; | ||
554 | } | ||
555 | 575 | ||
556 | tu->flags |= flag; | 576 | tu->flags |= flag; |
557 | utc->tu = tu; | 577 | tu->consumer.filter = filter; |
558 | tu->consumer = utc; | 578 | ret = uprobe_register(tu->inode, tu->offset, &tu->consumer); |
579 | if (ret) | ||
580 | tu->flags &= ~flag; | ||
559 | 581 | ||
560 | return 0; | 582 | return ret; |
561 | } | 583 | } |
562 | 584 | ||
563 | static void probe_event_disable(struct trace_uprobe *tu, int flag) | 585 | static void probe_event_disable(struct trace_uprobe *tu, int flag) |
564 | { | 586 | { |
565 | if (!tu->inode || !tu->consumer) | 587 | if (!is_trace_uprobe_enabled(tu)) |
566 | return; | 588 | return; |
567 | 589 | ||
568 | uprobe_unregister(tu->inode, tu->offset, &tu->consumer->cons); | 590 | WARN_ON(!uprobe_filter_is_empty(&tu->filter)); |
591 | |||
592 | uprobe_unregister(tu->inode, tu->offset, &tu->consumer); | ||
569 | tu->flags &= ~flag; | 593 | tu->flags &= ~flag; |
570 | kfree(tu->consumer); | ||
571 | tu->consumer = NULL; | ||
572 | } | 594 | } |
573 | 595 | ||
574 | static int uprobe_event_define_fields(struct ftrace_event_call *event_call) | 596 | static int uprobe_event_define_fields(struct ftrace_event_call *event_call) |
@@ -642,8 +664,96 @@ static int set_print_fmt(struct trace_uprobe *tu) | |||
642 | } | 664 | } |
643 | 665 | ||
644 | #ifdef CONFIG_PERF_EVENTS | 666 | #ifdef CONFIG_PERF_EVENTS |
667 | static bool | ||
668 | __uprobe_perf_filter(struct trace_uprobe_filter *filter, struct mm_struct *mm) | ||
669 | { | ||
670 | struct perf_event *event; | ||
671 | |||
672 | if (filter->nr_systemwide) | ||
673 | return true; | ||
674 | |||
675 | list_for_each_entry(event, &filter->perf_events, hw.tp_list) { | ||
676 | if (event->hw.tp_target->mm == mm) | ||
677 | return true; | ||
678 | } | ||
679 | |||
680 | return false; | ||
681 | } | ||
682 | |||
683 | static inline bool | ||
684 | uprobe_filter_event(struct trace_uprobe *tu, struct perf_event *event) | ||
685 | { | ||
686 | return __uprobe_perf_filter(&tu->filter, event->hw.tp_target->mm); | ||
687 | } | ||
688 | |||
689 | static int uprobe_perf_open(struct trace_uprobe *tu, struct perf_event *event) | ||
690 | { | ||
691 | bool done; | ||
692 | |||
693 | write_lock(&tu->filter.rwlock); | ||
694 | if (event->hw.tp_target) { | ||
695 | /* | ||
696 | * event->parent != NULL means copy_process(), we can avoid | ||
697 | * uprobe_apply(). current->mm must be probed and we can rely | ||
698 | * on dup_mmap() which preserves the already installed bp's. | ||
699 | * | ||
700 | * attr.enable_on_exec means that exec/mmap will install the | ||
701 | * breakpoints we need. | ||
702 | */ | ||
703 | done = tu->filter.nr_systemwide || | ||
704 | event->parent || event->attr.enable_on_exec || | ||
705 | uprobe_filter_event(tu, event); | ||
706 | list_add(&event->hw.tp_list, &tu->filter.perf_events); | ||
707 | } else { | ||
708 | done = tu->filter.nr_systemwide; | ||
709 | tu->filter.nr_systemwide++; | ||
710 | } | ||
711 | write_unlock(&tu->filter.rwlock); | ||
712 | |||
713 | if (!done) | ||
714 | uprobe_apply(tu->inode, tu->offset, &tu->consumer, true); | ||
715 | |||
716 | return 0; | ||
717 | } | ||
718 | |||
719 | static int uprobe_perf_close(struct trace_uprobe *tu, struct perf_event *event) | ||
720 | { | ||
721 | bool done; | ||
722 | |||
723 | write_lock(&tu->filter.rwlock); | ||
724 | if (event->hw.tp_target) { | ||
725 | list_del(&event->hw.tp_list); | ||
726 | done = tu->filter.nr_systemwide || | ||
727 | (event->hw.tp_target->flags & PF_EXITING) || | ||
728 | uprobe_filter_event(tu, event); | ||
729 | } else { | ||
730 | tu->filter.nr_systemwide--; | ||
731 | done = tu->filter.nr_systemwide; | ||
732 | } | ||
733 | write_unlock(&tu->filter.rwlock); | ||
734 | |||
735 | if (!done) | ||
736 | uprobe_apply(tu->inode, tu->offset, &tu->consumer, false); | ||
737 | |||
738 | return 0; | ||
739 | } | ||
740 | |||
741 | static bool uprobe_perf_filter(struct uprobe_consumer *uc, | ||
742 | enum uprobe_filter_ctx ctx, struct mm_struct *mm) | ||
743 | { | ||
744 | struct trace_uprobe *tu; | ||
745 | int ret; | ||
746 | |||
747 | tu = container_of(uc, struct trace_uprobe, consumer); | ||
748 | read_lock(&tu->filter.rwlock); | ||
749 | ret = __uprobe_perf_filter(&tu->filter, mm); | ||
750 | read_unlock(&tu->filter.rwlock); | ||
751 | |||
752 | return ret; | ||
753 | } | ||
754 | |||
645 | /* uprobe profile handler */ | 755 | /* uprobe profile handler */ |
646 | static void uprobe_perf_func(struct trace_uprobe *tu, struct pt_regs *regs) | 756 | static int uprobe_perf_func(struct trace_uprobe *tu, struct pt_regs *regs) |
647 | { | 757 | { |
648 | struct ftrace_event_call *call = &tu->call; | 758 | struct ftrace_event_call *call = &tu->call; |
649 | struct uprobe_trace_entry_head *entry; | 759 | struct uprobe_trace_entry_head *entry; |
@@ -652,11 +762,14 @@ static void uprobe_perf_func(struct trace_uprobe *tu, struct pt_regs *regs) | |||
652 | int size, __size, i; | 762 | int size, __size, i; |
653 | int rctx; | 763 | int rctx; |
654 | 764 | ||
765 | if (!uprobe_perf_filter(&tu->consumer, 0, current->mm)) | ||
766 | return UPROBE_HANDLER_REMOVE; | ||
767 | |||
655 | __size = sizeof(*entry) + tu->size; | 768 | __size = sizeof(*entry) + tu->size; |
656 | size = ALIGN(__size + sizeof(u32), sizeof(u64)); | 769 | size = ALIGN(__size + sizeof(u32), sizeof(u64)); |
657 | size -= sizeof(u32); | 770 | size -= sizeof(u32); |
658 | if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE, "profile buffer not large enough")) | 771 | if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE, "profile buffer not large enough")) |
659 | return; | 772 | return 0; |
660 | 773 | ||
661 | preempt_disable(); | 774 | preempt_disable(); |
662 | 775 | ||
@@ -664,7 +777,7 @@ static void uprobe_perf_func(struct trace_uprobe *tu, struct pt_regs *regs) | |||
664 | if (!entry) | 777 | if (!entry) |
665 | goto out; | 778 | goto out; |
666 | 779 | ||
667 | entry->ip = uprobe_get_swbp_addr(task_pt_regs(current)); | 780 | entry->ip = instruction_pointer(task_pt_regs(current)); |
668 | data = (u8 *)&entry[1]; | 781 | data = (u8 *)&entry[1]; |
669 | for (i = 0; i < tu->nr_args; i++) | 782 | for (i = 0; i < tu->nr_args; i++) |
670 | call_fetch(&tu->args[i].fetch, regs, data + tu->args[i].offset); | 783 | call_fetch(&tu->args[i].fetch, regs, data + tu->args[i].offset); |
@@ -674,6 +787,7 @@ static void uprobe_perf_func(struct trace_uprobe *tu, struct pt_regs *regs) | |||
674 | 787 | ||
675 | out: | 788 | out: |
676 | preempt_enable(); | 789 | preempt_enable(); |
790 | return 0; | ||
677 | } | 791 | } |
678 | #endif /* CONFIG_PERF_EVENTS */ | 792 | #endif /* CONFIG_PERF_EVENTS */ |
679 | 793 | ||
@@ -684,7 +798,7 @@ int trace_uprobe_register(struct ftrace_event_call *event, enum trace_reg type, | |||
684 | 798 | ||
685 | switch (type) { | 799 | switch (type) { |
686 | case TRACE_REG_REGISTER: | 800 | case TRACE_REG_REGISTER: |
687 | return probe_event_enable(tu, TP_FLAG_TRACE); | 801 | return probe_event_enable(tu, TP_FLAG_TRACE, NULL); |
688 | 802 | ||
689 | case TRACE_REG_UNREGISTER: | 803 | case TRACE_REG_UNREGISTER: |
690 | probe_event_disable(tu, TP_FLAG_TRACE); | 804 | probe_event_disable(tu, TP_FLAG_TRACE); |
@@ -692,11 +806,18 @@ int trace_uprobe_register(struct ftrace_event_call *event, enum trace_reg type, | |||
692 | 806 | ||
693 | #ifdef CONFIG_PERF_EVENTS | 807 | #ifdef CONFIG_PERF_EVENTS |
694 | case TRACE_REG_PERF_REGISTER: | 808 | case TRACE_REG_PERF_REGISTER: |
695 | return probe_event_enable(tu, TP_FLAG_PROFILE); | 809 | return probe_event_enable(tu, TP_FLAG_PROFILE, uprobe_perf_filter); |
696 | 810 | ||
697 | case TRACE_REG_PERF_UNREGISTER: | 811 | case TRACE_REG_PERF_UNREGISTER: |
698 | probe_event_disable(tu, TP_FLAG_PROFILE); | 812 | probe_event_disable(tu, TP_FLAG_PROFILE); |
699 | return 0; | 813 | return 0; |
814 | |||
815 | case TRACE_REG_PERF_OPEN: | ||
816 | return uprobe_perf_open(tu, data); | ||
817 | |||
818 | case TRACE_REG_PERF_CLOSE: | ||
819 | return uprobe_perf_close(tu, data); | ||
820 | |||
700 | #endif | 821 | #endif |
701 | default: | 822 | default: |
702 | return 0; | 823 | return 0; |
@@ -706,22 +827,20 @@ int trace_uprobe_register(struct ftrace_event_call *event, enum trace_reg type, | |||
706 | 827 | ||
707 | static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs) | 828 | static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs) |
708 | { | 829 | { |
709 | struct uprobe_trace_consumer *utc; | ||
710 | struct trace_uprobe *tu; | 830 | struct trace_uprobe *tu; |
831 | int ret = 0; | ||
711 | 832 | ||
712 | utc = container_of(con, struct uprobe_trace_consumer, cons); | 833 | tu = container_of(con, struct trace_uprobe, consumer); |
713 | tu = utc->tu; | 834 | tu->nhit++; |
714 | if (!tu || tu->consumer != utc) | ||
715 | return 0; | ||
716 | 835 | ||
717 | if (tu->flags & TP_FLAG_TRACE) | 836 | if (tu->flags & TP_FLAG_TRACE) |
718 | uprobe_trace_func(tu, regs); | 837 | ret |= uprobe_trace_func(tu, regs); |
719 | 838 | ||
720 | #ifdef CONFIG_PERF_EVENTS | 839 | #ifdef CONFIG_PERF_EVENTS |
721 | if (tu->flags & TP_FLAG_PROFILE) | 840 | if (tu->flags & TP_FLAG_PROFILE) |
722 | uprobe_perf_func(tu, regs); | 841 | ret |= uprobe_perf_func(tu, regs); |
723 | #endif | 842 | #endif |
724 | return 0; | 843 | return ret; |
725 | } | 844 | } |
726 | 845 | ||
727 | static struct trace_event_functions uprobe_funcs = { | 846 | static struct trace_event_functions uprobe_funcs = { |
diff --git a/kernel/tsacct.c b/kernel/tsacct.c index 625df0b44690..a1dd9a1b1327 100644 --- a/kernel/tsacct.c +++ b/kernel/tsacct.c | |||
@@ -32,6 +32,7 @@ void bacct_add_tsk(struct user_namespace *user_ns, | |||
32 | { | 32 | { |
33 | const struct cred *tcred; | 33 | const struct cred *tcred; |
34 | struct timespec uptime, ts; | 34 | struct timespec uptime, ts; |
35 | cputime_t utime, stime, utimescaled, stimescaled; | ||
35 | u64 ac_etime; | 36 | u64 ac_etime; |
36 | 37 | ||
37 | BUILD_BUG_ON(TS_COMM_LEN < TASK_COMM_LEN); | 38 | BUILD_BUG_ON(TS_COMM_LEN < TASK_COMM_LEN); |
@@ -65,10 +66,15 @@ void bacct_add_tsk(struct user_namespace *user_ns, | |||
65 | stats->ac_ppid = pid_alive(tsk) ? | 66 | stats->ac_ppid = pid_alive(tsk) ? |
66 | task_tgid_nr_ns(rcu_dereference(tsk->real_parent), pid_ns) : 0; | 67 | task_tgid_nr_ns(rcu_dereference(tsk->real_parent), pid_ns) : 0; |
67 | rcu_read_unlock(); | 68 | rcu_read_unlock(); |
68 | stats->ac_utime = cputime_to_usecs(tsk->utime); | 69 | |
69 | stats->ac_stime = cputime_to_usecs(tsk->stime); | 70 | task_cputime(tsk, &utime, &stime); |
70 | stats->ac_utimescaled = cputime_to_usecs(tsk->utimescaled); | 71 | stats->ac_utime = cputime_to_usecs(utime); |
71 | stats->ac_stimescaled = cputime_to_usecs(tsk->stimescaled); | 72 | stats->ac_stime = cputime_to_usecs(stime); |
73 | |||
74 | task_cputime_scaled(tsk, &utimescaled, &stimescaled); | ||
75 | stats->ac_utimescaled = cputime_to_usecs(utimescaled); | ||
76 | stats->ac_stimescaled = cputime_to_usecs(stimescaled); | ||
77 | |||
72 | stats->ac_minflt = tsk->min_flt; | 78 | stats->ac_minflt = tsk->min_flt; |
73 | stats->ac_majflt = tsk->maj_flt; | 79 | stats->ac_majflt = tsk->maj_flt; |
74 | 80 | ||
@@ -115,11 +121,8 @@ void xacct_add_tsk(struct taskstats *stats, struct task_struct *p) | |||
115 | #undef KB | 121 | #undef KB |
116 | #undef MB | 122 | #undef MB |
117 | 123 | ||
118 | /** | 124 | static void __acct_update_integrals(struct task_struct *tsk, |
119 | * acct_update_integrals - update mm integral fields in task_struct | 125 | cputime_t utime, cputime_t stime) |
120 | * @tsk: task_struct for accounting | ||
121 | */ | ||
122 | void acct_update_integrals(struct task_struct *tsk) | ||
123 | { | 126 | { |
124 | if (likely(tsk->mm)) { | 127 | if (likely(tsk->mm)) { |
125 | cputime_t time, dtime; | 128 | cputime_t time, dtime; |
@@ -128,7 +131,7 @@ void acct_update_integrals(struct task_struct *tsk) | |||
128 | u64 delta; | 131 | u64 delta; |
129 | 132 | ||
130 | local_irq_save(flags); | 133 | local_irq_save(flags); |
131 | time = tsk->stime + tsk->utime; | 134 | time = stime + utime; |
132 | dtime = time - tsk->acct_timexpd; | 135 | dtime = time - tsk->acct_timexpd; |
133 | jiffies_to_timeval(cputime_to_jiffies(dtime), &value); | 136 | jiffies_to_timeval(cputime_to_jiffies(dtime), &value); |
134 | delta = value.tv_sec; | 137 | delta = value.tv_sec; |
@@ -145,6 +148,27 @@ void acct_update_integrals(struct task_struct *tsk) | |||
145 | } | 148 | } |
146 | 149 | ||
147 | /** | 150 | /** |
151 | * acct_update_integrals - update mm integral fields in task_struct | ||
152 | * @tsk: task_struct for accounting | ||
153 | */ | ||
154 | void acct_update_integrals(struct task_struct *tsk) | ||
155 | { | ||
156 | cputime_t utime, stime; | ||
157 | |||
158 | task_cputime(tsk, &utime, &stime); | ||
159 | __acct_update_integrals(tsk, utime, stime); | ||
160 | } | ||
161 | |||
162 | /** | ||
163 | * acct_account_cputime - update mm integral after cputime update | ||
164 | * @tsk: task_struct for accounting | ||
165 | */ | ||
166 | void acct_account_cputime(struct task_struct *tsk) | ||
167 | { | ||
168 | __acct_update_integrals(tsk, tsk->utime, tsk->stime); | ||
169 | } | ||
170 | |||
171 | /** | ||
148 | * acct_clear_integrals - clear the mm integral fields in task_struct | 172 | * acct_clear_integrals - clear the mm integral fields in task_struct |
149 | * @tsk: task_struct whose accounting fields are cleared | 173 | * @tsk: task_struct whose accounting fields are cleared |
150 | */ | 174 | */ |
diff --git a/kernel/watchdog.c b/kernel/watchdog.c index 75a2ab3d0b02..27689422aa92 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/module.h> | 23 | #include <linux/module.h> |
24 | #include <linux/sysctl.h> | 24 | #include <linux/sysctl.h> |
25 | #include <linux/smpboot.h> | 25 | #include <linux/smpboot.h> |
26 | #include <linux/sched/rt.h> | ||
26 | 27 | ||
27 | #include <asm/irq_regs.h> | 28 | #include <asm/irq_regs.h> |
28 | #include <linux/kvm_para.h> | 29 | #include <linux/kvm_para.h> |
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 67604e599384..a1714c897e3f 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug | |||
@@ -605,61 +605,6 @@ config PROVE_LOCKING | |||
605 | 605 | ||
606 | For more details, see Documentation/lockdep-design.txt. | 606 | For more details, see Documentation/lockdep-design.txt. |
607 | 607 | ||
608 | config PROVE_RCU | ||
609 | bool "RCU debugging: prove RCU correctness" | ||
610 | depends on PROVE_LOCKING | ||
611 | default n | ||
612 | help | ||
613 | This feature enables lockdep extensions that check for correct | ||
614 | use of RCU APIs. This is currently under development. Say Y | ||
615 | if you want to debug RCU usage or help work on the PROVE_RCU | ||
616 | feature. | ||
617 | |||
618 | Say N if you are unsure. | ||
619 | |||
620 | config PROVE_RCU_REPEATEDLY | ||
621 | bool "RCU debugging: don't disable PROVE_RCU on first splat" | ||
622 | depends on PROVE_RCU | ||
623 | default n | ||
624 | help | ||
625 | By itself, PROVE_RCU will disable checking upon issuing the | ||
626 | first warning (or "splat"). This feature prevents such | ||
627 | disabling, allowing multiple RCU-lockdep warnings to be printed | ||
628 | on a single reboot. | ||
629 | |||
630 | Say Y to allow multiple RCU-lockdep warnings per boot. | ||
631 | |||
632 | Say N if you are unsure. | ||
633 | |||
634 | config PROVE_RCU_DELAY | ||
635 | bool "RCU debugging: preemptible RCU race provocation" | ||
636 | depends on DEBUG_KERNEL && PREEMPT_RCU | ||
637 | default n | ||
638 | help | ||
639 | There is a class of races that involve an unlikely preemption | ||
640 | of __rcu_read_unlock() just after ->rcu_read_lock_nesting has | ||
641 | been set to INT_MIN. This feature inserts a delay at that | ||
642 | point to increase the probability of these races. | ||
643 | |||
644 | Say Y to increase probability of preemption of __rcu_read_unlock(). | ||
645 | |||
646 | Say N if you are unsure. | ||
647 | |||
648 | config SPARSE_RCU_POINTER | ||
649 | bool "RCU debugging: sparse-based checks for pointer usage" | ||
650 | default n | ||
651 | help | ||
652 | This feature enables the __rcu sparse annotation for | ||
653 | RCU-protected pointers. This annotation will cause sparse | ||
654 | to flag any non-RCU used of annotated pointers. This can be | ||
655 | helpful when debugging RCU usage. Please note that this feature | ||
656 | is not intended to enforce code cleanliness; it is instead merely | ||
657 | a debugging aid. | ||
658 | |||
659 | Say Y to make sparse flag questionable use of RCU-protected pointers | ||
660 | |||
661 | Say N if you are unsure. | ||
662 | |||
663 | config LOCKDEP | 608 | config LOCKDEP |
664 | bool | 609 | bool |
665 | depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT | 610 | depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT |
@@ -937,6 +882,63 @@ config BOOT_PRINTK_DELAY | |||
937 | BOOT_PRINTK_DELAY also may cause LOCKUP_DETECTOR to detect | 882 | BOOT_PRINTK_DELAY also may cause LOCKUP_DETECTOR to detect |
938 | what it believes to be lockup conditions. | 883 | what it believes to be lockup conditions. |
939 | 884 | ||
885 | menu "RCU Debugging" | ||
886 | |||
887 | config PROVE_RCU | ||
888 | bool "RCU debugging: prove RCU correctness" | ||
889 | depends on PROVE_LOCKING | ||
890 | default n | ||
891 | help | ||
892 | This feature enables lockdep extensions that check for correct | ||
893 | use of RCU APIs. This is currently under development. Say Y | ||
894 | if you want to debug RCU usage or help work on the PROVE_RCU | ||
895 | feature. | ||
896 | |||
897 | Say N if you are unsure. | ||
898 | |||
899 | config PROVE_RCU_REPEATEDLY | ||
900 | bool "RCU debugging: don't disable PROVE_RCU on first splat" | ||
901 | depends on PROVE_RCU | ||
902 | default n | ||
903 | help | ||
904 | By itself, PROVE_RCU will disable checking upon issuing the | ||
905 | first warning (or "splat"). This feature prevents such | ||
906 | disabling, allowing multiple RCU-lockdep warnings to be printed | ||
907 | on a single reboot. | ||
908 | |||
909 | Say Y to allow multiple RCU-lockdep warnings per boot. | ||
910 | |||
911 | Say N if you are unsure. | ||
912 | |||
913 | config PROVE_RCU_DELAY | ||
914 | bool "RCU debugging: preemptible RCU race provocation" | ||
915 | depends on DEBUG_KERNEL && PREEMPT_RCU | ||
916 | default n | ||
917 | help | ||
918 | There is a class of races that involve an unlikely preemption | ||
919 | of __rcu_read_unlock() just after ->rcu_read_lock_nesting has | ||
920 | been set to INT_MIN. This feature inserts a delay at that | ||
921 | point to increase the probability of these races. | ||
922 | |||
923 | Say Y to increase probability of preemption of __rcu_read_unlock(). | ||
924 | |||
925 | Say N if you are unsure. | ||
926 | |||
927 | config SPARSE_RCU_POINTER | ||
928 | bool "RCU debugging: sparse-based checks for pointer usage" | ||
929 | default n | ||
930 | help | ||
931 | This feature enables the __rcu sparse annotation for | ||
932 | RCU-protected pointers. This annotation will cause sparse | ||
933 | to flag any non-RCU used of annotated pointers. This can be | ||
934 | helpful when debugging RCU usage. Please note that this feature | ||
935 | is not intended to enforce code cleanliness; it is instead merely | ||
936 | a debugging aid. | ||
937 | |||
938 | Say Y to make sparse flag questionable use of RCU-protected pointers | ||
939 | |||
940 | Say N if you are unsure. | ||
941 | |||
940 | config RCU_TORTURE_TEST | 942 | config RCU_TORTURE_TEST |
941 | tristate "torture tests for RCU" | 943 | tristate "torture tests for RCU" |
942 | depends on DEBUG_KERNEL | 944 | depends on DEBUG_KERNEL |
@@ -970,7 +972,7 @@ config RCU_TORTURE_TEST_RUNNABLE | |||
970 | 972 | ||
971 | config RCU_CPU_STALL_TIMEOUT | 973 | config RCU_CPU_STALL_TIMEOUT |
972 | int "RCU CPU stall timeout in seconds" | 974 | int "RCU CPU stall timeout in seconds" |
973 | depends on TREE_RCU || TREE_PREEMPT_RCU | 975 | depends on RCU_STALL_COMMON |
974 | range 3 300 | 976 | range 3 300 |
975 | default 21 | 977 | default 21 |
976 | help | 978 | help |
@@ -1008,6 +1010,7 @@ config RCU_CPU_STALL_INFO | |||
1008 | config RCU_TRACE | 1010 | config RCU_TRACE |
1009 | bool "Enable tracing for RCU" | 1011 | bool "Enable tracing for RCU" |
1010 | depends on DEBUG_KERNEL | 1012 | depends on DEBUG_KERNEL |
1013 | select TRACE_CLOCK | ||
1011 | help | 1014 | help |
1012 | This option provides tracing in RCU which presents stats | 1015 | This option provides tracing in RCU which presents stats |
1013 | in debugfs for debugging RCU implementation. | 1016 | in debugfs for debugging RCU implementation. |
@@ -1015,6 +1018,8 @@ config RCU_TRACE | |||
1015 | Say Y here if you want to enable RCU tracing | 1018 | Say Y here if you want to enable RCU tracing |
1016 | Say N if you are unsure. | 1019 | Say N if you are unsure. |
1017 | 1020 | ||
1021 | endmenu # "RCU Debugging" | ||
1022 | |||
1018 | config KPROBES_SANITY_TEST | 1023 | config KPROBES_SANITY_TEST |
1019 | bool "Kprobes sanity tests" | 1024 | bool "Kprobes sanity tests" |
1020 | depends on DEBUG_KERNEL | 1025 | depends on DEBUG_KERNEL |
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 09255ec8159c..fbb60b103e64 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -3030,7 +3030,9 @@ int memcg_register_cache(struct mem_cgroup *memcg, struct kmem_cache *s, | |||
3030 | if (memcg) { | 3030 | if (memcg) { |
3031 | s->memcg_params->memcg = memcg; | 3031 | s->memcg_params->memcg = memcg; |
3032 | s->memcg_params->root_cache = root_cache; | 3032 | s->memcg_params->root_cache = root_cache; |
3033 | } | 3033 | } else |
3034 | s->memcg_params->is_root_cache = true; | ||
3035 | |||
3034 | return 0; | 3036 | return 0; |
3035 | } | 3037 | } |
3036 | 3038 | ||
diff --git a/mm/mlock.c b/mm/mlock.c index f0b9ce572fc7..c9bd528b01d2 100644 --- a/mm/mlock.c +++ b/mm/mlock.c | |||
@@ -517,11 +517,11 @@ SYSCALL_DEFINE2(munlock, unsigned long, start, size_t, len) | |||
517 | static int do_mlockall(int flags) | 517 | static int do_mlockall(int flags) |
518 | { | 518 | { |
519 | struct vm_area_struct * vma, * prev = NULL; | 519 | struct vm_area_struct * vma, * prev = NULL; |
520 | unsigned int def_flags = 0; | ||
521 | 520 | ||
522 | if (flags & MCL_FUTURE) | 521 | if (flags & MCL_FUTURE) |
523 | def_flags = VM_LOCKED; | 522 | current->mm->def_flags |= VM_LOCKED; |
524 | current->mm->def_flags = def_flags; | 523 | else |
524 | current->mm->def_flags &= ~VM_LOCKED; | ||
525 | if (flags == MCL_FUTURE) | 525 | if (flags == MCL_FUTURE) |
526 | goto out; | 526 | goto out; |
527 | 527 | ||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/khugepaged.h> | 32 | #include <linux/khugepaged.h> |
33 | #include <linux/uprobes.h> | 33 | #include <linux/uprobes.h> |
34 | #include <linux/rbtree_augmented.h> | 34 | #include <linux/rbtree_augmented.h> |
35 | #include <linux/sched/sysctl.h> | ||
35 | 36 | ||
36 | #include <asm/uaccess.h> | 37 | #include <asm/uaccess.h> |
37 | #include <asm/cacheflush.h> | 38 | #include <asm/cacheflush.h> |
diff --git a/mm/mremap.c b/mm/mremap.c index e1031e1f6a61..f9766f460299 100644 --- a/mm/mremap.c +++ b/mm/mremap.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/security.h> | 19 | #include <linux/security.h> |
20 | #include <linux/syscalls.h> | 20 | #include <linux/syscalls.h> |
21 | #include <linux/mmu_notifier.h> | 21 | #include <linux/mmu_notifier.h> |
22 | #include <linux/sched/sysctl.h> | ||
22 | 23 | ||
23 | #include <asm/uaccess.h> | 24 | #include <asm/uaccess.h> |
24 | #include <asm/cacheflush.h> | 25 | #include <asm/cacheflush.h> |
diff --git a/mm/nommu.c b/mm/nommu.c index 79c3cac87afa..b20db4e22263 100644 --- a/mm/nommu.c +++ b/mm/nommu.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/security.h> | 29 | #include <linux/security.h> |
30 | #include <linux/syscalls.h> | 30 | #include <linux/syscalls.h> |
31 | #include <linux/audit.h> | 31 | #include <linux/audit.h> |
32 | #include <linux/sched/sysctl.h> | ||
32 | 33 | ||
33 | #include <asm/uaccess.h> | 34 | #include <asm/uaccess.h> |
34 | #include <asm/tlb.h> | 35 | #include <asm/tlb.h> |
diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 0713bfbf0954..66a0024becd9 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/buffer_head.h> /* __set_page_dirty_buffers */ | 35 | #include <linux/buffer_head.h> /* __set_page_dirty_buffers */ |
36 | #include <linux/pagevec.h> | 36 | #include <linux/pagevec.h> |
37 | #include <linux/timer.h> | 37 | #include <linux/timer.h> |
38 | #include <linux/sched/rt.h> | ||
38 | #include <trace/events/writeback.h> | 39 | #include <trace/events/writeback.h> |
39 | 40 | ||
40 | /* | 41 | /* |
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index df2022ff0c8a..d1107adf174a 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -58,6 +58,7 @@ | |||
58 | #include <linux/prefetch.h> | 58 | #include <linux/prefetch.h> |
59 | #include <linux/migrate.h> | 59 | #include <linux/migrate.h> |
60 | #include <linux/page-debug-flags.h> | 60 | #include <linux/page-debug-flags.h> |
61 | #include <linux/sched/rt.h> | ||
61 | 62 | ||
62 | #include <asm/tlbflush.h> | 63 | #include <asm/tlbflush.h> |
63 | #include <asm/div64.h> | 64 | #include <asm/div64.h> |
@@ -773,6 +774,10 @@ void __init init_cma_reserved_pageblock(struct page *page) | |||
773 | set_pageblock_migratetype(page, MIGRATE_CMA); | 774 | set_pageblock_migratetype(page, MIGRATE_CMA); |
774 | __free_pages(page, pageblock_order); | 775 | __free_pages(page, pageblock_order); |
775 | totalram_pages += pageblock_nr_pages; | 776 | totalram_pages += pageblock_nr_pages; |
777 | #ifdef CONFIG_HIGHMEM | ||
778 | if (PageHighMem(page)) | ||
779 | totalhigh_pages += pageblock_nr_pages; | ||
780 | #endif | ||
776 | } | 781 | } |
777 | #endif | 782 | #endif |
778 | 783 | ||
@@ -4416,10 +4421,11 @@ static void __meminit calculate_node_totalpages(struct pglist_data *pgdat, | |||
4416 | * round what is now in bits to nearest long in bits, then return it in | 4421 | * round what is now in bits to nearest long in bits, then return it in |
4417 | * bytes. | 4422 | * bytes. |
4418 | */ | 4423 | */ |
4419 | static unsigned long __init usemap_size(unsigned long zonesize) | 4424 | static unsigned long __init usemap_size(unsigned long zone_start_pfn, unsigned long zonesize) |
4420 | { | 4425 | { |
4421 | unsigned long usemapsize; | 4426 | unsigned long usemapsize; |
4422 | 4427 | ||
4428 | zonesize += zone_start_pfn & (pageblock_nr_pages-1); | ||
4423 | usemapsize = roundup(zonesize, pageblock_nr_pages); | 4429 | usemapsize = roundup(zonesize, pageblock_nr_pages); |
4424 | usemapsize = usemapsize >> pageblock_order; | 4430 | usemapsize = usemapsize >> pageblock_order; |
4425 | usemapsize *= NR_PAGEBLOCK_BITS; | 4431 | usemapsize *= NR_PAGEBLOCK_BITS; |
@@ -4429,17 +4435,19 @@ static unsigned long __init usemap_size(unsigned long zonesize) | |||
4429 | } | 4435 | } |
4430 | 4436 | ||
4431 | static void __init setup_usemap(struct pglist_data *pgdat, | 4437 | static void __init setup_usemap(struct pglist_data *pgdat, |
4432 | struct zone *zone, unsigned long zonesize) | 4438 | struct zone *zone, |
4439 | unsigned long zone_start_pfn, | ||
4440 | unsigned long zonesize) | ||
4433 | { | 4441 | { |
4434 | unsigned long usemapsize = usemap_size(zonesize); | 4442 | unsigned long usemapsize = usemap_size(zone_start_pfn, zonesize); |
4435 | zone->pageblock_flags = NULL; | 4443 | zone->pageblock_flags = NULL; |
4436 | if (usemapsize) | 4444 | if (usemapsize) |
4437 | zone->pageblock_flags = alloc_bootmem_node_nopanic(pgdat, | 4445 | zone->pageblock_flags = alloc_bootmem_node_nopanic(pgdat, |
4438 | usemapsize); | 4446 | usemapsize); |
4439 | } | 4447 | } |
4440 | #else | 4448 | #else |
4441 | static inline void setup_usemap(struct pglist_data *pgdat, | 4449 | static inline void setup_usemap(struct pglist_data *pgdat, struct zone *zone, |
4442 | struct zone *zone, unsigned long zonesize) {} | 4450 | unsigned long zone_start_pfn, unsigned long zonesize) {} |
4443 | #endif /* CONFIG_SPARSEMEM */ | 4451 | #endif /* CONFIG_SPARSEMEM */ |
4444 | 4452 | ||
4445 | #ifdef CONFIG_HUGETLB_PAGE_SIZE_VARIABLE | 4453 | #ifdef CONFIG_HUGETLB_PAGE_SIZE_VARIABLE |
@@ -4590,7 +4598,7 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat, | |||
4590 | continue; | 4598 | continue; |
4591 | 4599 | ||
4592 | set_pageblock_order(); | 4600 | set_pageblock_order(); |
4593 | setup_usemap(pgdat, zone, size); | 4601 | setup_usemap(pgdat, zone, zone_start_pfn, size); |
4594 | ret = init_currently_empty_zone(zone, zone_start_pfn, | 4602 | ret = init_currently_empty_zone(zone, zone_start_pfn, |
4595 | size, MEMMAP_EARLY); | 4603 | size, MEMMAP_EARLY); |
4596 | BUG_ON(ret); | 4604 | BUG_ON(ret); |
diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c index 183f97a86bb2..553921511e4e 100644 --- a/net/batman-adv/distributed-arp-table.c +++ b/net/batman-adv/distributed-arp-table.c | |||
@@ -440,7 +440,7 @@ static bool batadv_is_orig_node_eligible(struct batadv_dat_candidate *res, | |||
440 | /* this is an hash collision with the temporary selected node. Choose | 440 | /* this is an hash collision with the temporary selected node. Choose |
441 | * the one with the lowest address | 441 | * the one with the lowest address |
442 | */ | 442 | */ |
443 | if ((tmp_max == max) && | 443 | if ((tmp_max == max) && max_orig_node && |
444 | (batadv_compare_eth(candidate->orig, max_orig_node->orig) > 0)) | 444 | (batadv_compare_eth(candidate->orig, max_orig_node->orig) > 0)) |
445 | goto out; | 445 | goto out; |
446 | 446 | ||
diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c index 7f884e3fb955..8660ea3be705 100644 --- a/net/bridge/br_stp_bpdu.c +++ b/net/bridge/br_stp_bpdu.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/etherdevice.h> | 16 | #include <linux/etherdevice.h> |
17 | #include <linux/llc.h> | 17 | #include <linux/llc.h> |
18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
19 | #include <linux/pkt_sched.h> | ||
19 | #include <net/net_namespace.h> | 20 | #include <net/net_namespace.h> |
20 | #include <net/llc.h> | 21 | #include <net/llc.h> |
21 | #include <net/llc_pdu.h> | 22 | #include <net/llc_pdu.h> |
@@ -40,6 +41,7 @@ static void br_send_bpdu(struct net_bridge_port *p, | |||
40 | 41 | ||
41 | skb->dev = p->dev; | 42 | skb->dev = p->dev; |
42 | skb->protocol = htons(ETH_P_802_2); | 43 | skb->protocol = htons(ETH_P_802_2); |
44 | skb->priority = TC_PRIO_CONTROL; | ||
43 | 45 | ||
44 | skb_reserve(skb, LLC_RESERVE); | 46 | skb_reserve(skb, LLC_RESERVE); |
45 | memcpy(__skb_put(skb, length), data, length); | 47 | memcpy(__skb_put(skb, length), data, length); |
diff --git a/net/core/datagram.c b/net/core/datagram.c index 0337e2b76862..368f9c3f9dc6 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c | |||
@@ -187,7 +187,7 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags, | |||
187 | skb_queue_walk(queue, skb) { | 187 | skb_queue_walk(queue, skb) { |
188 | *peeked = skb->peeked; | 188 | *peeked = skb->peeked; |
189 | if (flags & MSG_PEEK) { | 189 | if (flags & MSG_PEEK) { |
190 | if (*off >= skb->len) { | 190 | if (*off >= skb->len && skb->len) { |
191 | *off -= skb->len; | 191 | *off -= skb->len; |
192 | continue; | 192 | continue; |
193 | } | 193 | } |
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 9547a273b9e9..ded146b217f1 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c | |||
@@ -928,24 +928,25 @@ static void parp_redo(struct sk_buff *skb) | |||
928 | static int arp_rcv(struct sk_buff *skb, struct net_device *dev, | 928 | static int arp_rcv(struct sk_buff *skb, struct net_device *dev, |
929 | struct packet_type *pt, struct net_device *orig_dev) | 929 | struct packet_type *pt, struct net_device *orig_dev) |
930 | { | 930 | { |
931 | struct arphdr *arp; | 931 | const struct arphdr *arp; |
932 | |||
933 | if (dev->flags & IFF_NOARP || | ||
934 | skb->pkt_type == PACKET_OTHERHOST || | ||
935 | skb->pkt_type == PACKET_LOOPBACK) | ||
936 | goto freeskb; | ||
937 | |||
938 | skb = skb_share_check(skb, GFP_ATOMIC); | ||
939 | if (!skb) | ||
940 | goto out_of_mem; | ||
932 | 941 | ||
933 | /* ARP header, plus 2 device addresses, plus 2 IP addresses. */ | 942 | /* ARP header, plus 2 device addresses, plus 2 IP addresses. */ |
934 | if (!pskb_may_pull(skb, arp_hdr_len(dev))) | 943 | if (!pskb_may_pull(skb, arp_hdr_len(dev))) |
935 | goto freeskb; | 944 | goto freeskb; |
936 | 945 | ||
937 | arp = arp_hdr(skb); | 946 | arp = arp_hdr(skb); |
938 | if (arp->ar_hln != dev->addr_len || | 947 | if (arp->ar_hln != dev->addr_len || arp->ar_pln != 4) |
939 | dev->flags & IFF_NOARP || | ||
940 | skb->pkt_type == PACKET_OTHERHOST || | ||
941 | skb->pkt_type == PACKET_LOOPBACK || | ||
942 | arp->ar_pln != 4) | ||
943 | goto freeskb; | 948 | goto freeskb; |
944 | 949 | ||
945 | skb = skb_share_check(skb, GFP_ATOMIC); | ||
946 | if (skb == NULL) | ||
947 | goto out_of_mem; | ||
948 | |||
949 | memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb)); | 950 | memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb)); |
950 | 951 | ||
951 | return NF_HOOK(NFPROTO_ARP, NF_ARP_IN, skb, dev, NULL, arp_process); | 952 | return NF_HOOK(NFPROTO_ARP, NF_ARP_IN, skb, dev, NULL, arp_process); |
diff --git a/net/ipv6/netfilter/ip6t_NPT.c b/net/ipv6/netfilter/ip6t_NPT.c index 7302b0b7b642..83acc1405a18 100644 --- a/net/ipv6/netfilter/ip6t_NPT.c +++ b/net/ipv6/netfilter/ip6t_NPT.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <linux/module.h> | 9 | #include <linux/module.h> |
10 | #include <linux/skbuff.h> | 10 | #include <linux/skbuff.h> |
11 | #include <linux/ipv6.h> | 11 | #include <linux/ipv6.h> |
12 | #include <net/ipv6.h> | ||
12 | #include <linux/netfilter.h> | 13 | #include <linux/netfilter.h> |
13 | #include <linux/netfilter_ipv6.h> | 14 | #include <linux/netfilter_ipv6.h> |
14 | #include <linux/netfilter_ipv6/ip6t_NPT.h> | 15 | #include <linux/netfilter_ipv6/ip6t_NPT.h> |
@@ -18,11 +19,20 @@ static int ip6t_npt_checkentry(const struct xt_tgchk_param *par) | |||
18 | { | 19 | { |
19 | struct ip6t_npt_tginfo *npt = par->targinfo; | 20 | struct ip6t_npt_tginfo *npt = par->targinfo; |
20 | __wsum src_sum = 0, dst_sum = 0; | 21 | __wsum src_sum = 0, dst_sum = 0; |
22 | struct in6_addr pfx; | ||
21 | unsigned int i; | 23 | unsigned int i; |
22 | 24 | ||
23 | if (npt->src_pfx_len > 64 || npt->dst_pfx_len > 64) | 25 | if (npt->src_pfx_len > 64 || npt->dst_pfx_len > 64) |
24 | return -EINVAL; | 26 | return -EINVAL; |
25 | 27 | ||
28 | /* Ensure that LSB of prefix is zero */ | ||
29 | ipv6_addr_prefix(&pfx, &npt->src_pfx.in6, npt->src_pfx_len); | ||
30 | if (!ipv6_addr_equal(&pfx, &npt->src_pfx.in6)) | ||
31 | return -EINVAL; | ||
32 | ipv6_addr_prefix(&pfx, &npt->dst_pfx.in6, npt->dst_pfx_len); | ||
33 | if (!ipv6_addr_equal(&pfx, &npt->dst_pfx.in6)) | ||
34 | return -EINVAL; | ||
35 | |||
26 | for (i = 0; i < ARRAY_SIZE(npt->src_pfx.in6.s6_addr16); i++) { | 36 | for (i = 0; i < ARRAY_SIZE(npt->src_pfx.in6.s6_addr16); i++) { |
27 | src_sum = csum_add(src_sum, | 37 | src_sum = csum_add(src_sum, |
28 | (__force __wsum)npt->src_pfx.in6.s6_addr16[i]); | 38 | (__force __wsum)npt->src_pfx.in6.s6_addr16[i]); |
@@ -30,7 +40,7 @@ static int ip6t_npt_checkentry(const struct xt_tgchk_param *par) | |||
30 | (__force __wsum)npt->dst_pfx.in6.s6_addr16[i]); | 40 | (__force __wsum)npt->dst_pfx.in6.s6_addr16[i]); |
31 | } | 41 | } |
32 | 42 | ||
33 | npt->adjustment = (__force __sum16) csum_sub(src_sum, dst_sum); | 43 | npt->adjustment = ~csum_fold(csum_sub(src_sum, dst_sum)); |
34 | return 0; | 44 | return 0; |
35 | } | 45 | } |
36 | 46 | ||
@@ -51,7 +61,7 @@ static bool ip6t_npt_map_pfx(const struct ip6t_npt_tginfo *npt, | |||
51 | 61 | ||
52 | idx = i / 32; | 62 | idx = i / 32; |
53 | addr->s6_addr32[idx] &= mask; | 63 | addr->s6_addr32[idx] &= mask; |
54 | addr->s6_addr32[idx] |= npt->dst_pfx.in6.s6_addr32[idx]; | 64 | addr->s6_addr32[idx] |= ~mask & npt->dst_pfx.in6.s6_addr32[idx]; |
55 | } | 65 | } |
56 | 66 | ||
57 | if (pfx_len <= 48) | 67 | if (pfx_len <= 48) |
@@ -66,8 +76,8 @@ static bool ip6t_npt_map_pfx(const struct ip6t_npt_tginfo *npt, | |||
66 | return false; | 76 | return false; |
67 | } | 77 | } |
68 | 78 | ||
69 | sum = (__force __sum16) csum_add((__force __wsum)addr->s6_addr16[idx], | 79 | sum = ~csum_fold(csum_add(csum_unfold((__force __sum16)addr->s6_addr16[idx]), |
70 | npt->adjustment); | 80 | csum_unfold(npt->adjustment))); |
71 | if (sum == CSUM_MANGLED_0) | 81 | if (sum == CSUM_MANGLED_0) |
72 | sum = 0; | 82 | sum = 0; |
73 | *(__force __sum16 *)&addr->s6_addr16[idx] = sum; | 83 | *(__force __sum16 *)&addr->s6_addr16[idx] = sum; |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 516fbc96feff..0479c64aa83c 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -2004,7 +2004,8 @@ static int ieee80211_set_mcast_rate(struct wiphy *wiphy, struct net_device *dev, | |||
2004 | { | 2004 | { |
2005 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 2005 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
2006 | 2006 | ||
2007 | memcpy(sdata->vif.bss_conf.mcast_rate, rate, sizeof(rate)); | 2007 | memcpy(sdata->vif.bss_conf.mcast_rate, rate, |
2008 | sizeof(int) * IEEE80211_NUM_BANDS); | ||
2008 | 2009 | ||
2009 | return 0; | 2010 | return 0; |
2010 | } | 2011 | } |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index a3552929a21d..5107248af7fb 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -3400,6 +3400,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, | |||
3400 | 3400 | ||
3401 | ret = 0; | 3401 | ret = 0; |
3402 | 3402 | ||
3403 | out: | ||
3403 | while (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, | 3404 | while (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, |
3404 | IEEE80211_CHAN_DISABLED)) { | 3405 | IEEE80211_CHAN_DISABLED)) { |
3405 | if (WARN_ON(chandef->width == NL80211_CHAN_WIDTH_20_NOHT)) { | 3406 | if (WARN_ON(chandef->width == NL80211_CHAN_WIDTH_20_NOHT)) { |
@@ -3408,14 +3409,13 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, | |||
3408 | goto out; | 3409 | goto out; |
3409 | } | 3410 | } |
3410 | 3411 | ||
3411 | ret = chandef_downgrade(chandef); | 3412 | ret |= chandef_downgrade(chandef); |
3412 | } | 3413 | } |
3413 | 3414 | ||
3414 | if (chandef->width != vht_chandef.width) | 3415 | if (chandef->width != vht_chandef.width) |
3415 | sdata_info(sdata, | 3416 | sdata_info(sdata, |
3416 | "local regulatory prevented using AP HT/VHT configuration, downgraded\n"); | 3417 | "capabilities/regulatory prevented using AP HT/VHT configuration, downgraded\n"); |
3417 | 3418 | ||
3418 | out: | ||
3419 | WARN_ON_ONCE(!cfg80211_chandef_valid(chandef)); | 3419 | WARN_ON_ONCE(!cfg80211_chandef_valid(chandef)); |
3420 | return ret; | 3420 | return ret; |
3421 | } | 3421 | } |
@@ -3529,8 +3529,11 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, | |||
3529 | */ | 3529 | */ |
3530 | ret = ieee80211_vif_use_channel(sdata, &chandef, | 3530 | ret = ieee80211_vif_use_channel(sdata, &chandef, |
3531 | IEEE80211_CHANCTX_SHARED); | 3531 | IEEE80211_CHANCTX_SHARED); |
3532 | while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) | 3532 | while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) { |
3533 | ifmgd->flags |= chandef_downgrade(&chandef); | 3533 | ifmgd->flags |= chandef_downgrade(&chandef); |
3534 | ret = ieee80211_vif_use_channel(sdata, &chandef, | ||
3535 | IEEE80211_CHANCTX_SHARED); | ||
3536 | } | ||
3534 | return ret; | 3537 | return ret; |
3535 | } | 3538 | } |
3536 | 3539 | ||
diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c b/net/netfilter/ipvs/ip_vs_proto_sctp.c index 746048b13ef3..ae8ec6f27688 100644 --- a/net/netfilter/ipvs/ip_vs_proto_sctp.c +++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c | |||
@@ -61,14 +61,27 @@ sctp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, | |||
61 | return 1; | 61 | return 1; |
62 | } | 62 | } |
63 | 63 | ||
64 | static void sctp_nat_csum(struct sk_buff *skb, sctp_sctphdr_t *sctph, | ||
65 | unsigned int sctphoff) | ||
66 | { | ||
67 | __u32 crc32; | ||
68 | struct sk_buff *iter; | ||
69 | |||
70 | crc32 = sctp_start_cksum((__u8 *)sctph, skb_headlen(skb) - sctphoff); | ||
71 | skb_walk_frags(skb, iter) | ||
72 | crc32 = sctp_update_cksum((u8 *) iter->data, | ||
73 | skb_headlen(iter), crc32); | ||
74 | sctph->checksum = sctp_end_cksum(crc32); | ||
75 | |||
76 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
77 | } | ||
78 | |||
64 | static int | 79 | static int |
65 | sctp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp, | 80 | sctp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp, |
66 | struct ip_vs_conn *cp, struct ip_vs_iphdr *iph) | 81 | struct ip_vs_conn *cp, struct ip_vs_iphdr *iph) |
67 | { | 82 | { |
68 | sctp_sctphdr_t *sctph; | 83 | sctp_sctphdr_t *sctph; |
69 | unsigned int sctphoff = iph->len; | 84 | unsigned int sctphoff = iph->len; |
70 | struct sk_buff *iter; | ||
71 | __be32 crc32; | ||
72 | 85 | ||
73 | #ifdef CONFIG_IP_VS_IPV6 | 86 | #ifdef CONFIG_IP_VS_IPV6 |
74 | if (cp->af == AF_INET6 && iph->fragoffs) | 87 | if (cp->af == AF_INET6 && iph->fragoffs) |
@@ -92,13 +105,7 @@ sctp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp, | |||
92 | sctph = (void *) skb_network_header(skb) + sctphoff; | 105 | sctph = (void *) skb_network_header(skb) + sctphoff; |
93 | sctph->source = cp->vport; | 106 | sctph->source = cp->vport; |
94 | 107 | ||
95 | /* Calculate the checksum */ | 108 | sctp_nat_csum(skb, sctph, sctphoff); |
96 | crc32 = sctp_start_cksum((u8 *) sctph, skb_headlen(skb) - sctphoff); | ||
97 | skb_walk_frags(skb, iter) | ||
98 | crc32 = sctp_update_cksum((u8 *) iter->data, skb_headlen(iter), | ||
99 | crc32); | ||
100 | crc32 = sctp_end_cksum(crc32); | ||
101 | sctph->checksum = crc32; | ||
102 | 109 | ||
103 | return 1; | 110 | return 1; |
104 | } | 111 | } |
@@ -109,8 +116,6 @@ sctp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp, | |||
109 | { | 116 | { |
110 | sctp_sctphdr_t *sctph; | 117 | sctp_sctphdr_t *sctph; |
111 | unsigned int sctphoff = iph->len; | 118 | unsigned int sctphoff = iph->len; |
112 | struct sk_buff *iter; | ||
113 | __be32 crc32; | ||
114 | 119 | ||
115 | #ifdef CONFIG_IP_VS_IPV6 | 120 | #ifdef CONFIG_IP_VS_IPV6 |
116 | if (cp->af == AF_INET6 && iph->fragoffs) | 121 | if (cp->af == AF_INET6 && iph->fragoffs) |
@@ -134,13 +139,7 @@ sctp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp, | |||
134 | sctph = (void *) skb_network_header(skb) + sctphoff; | 139 | sctph = (void *) skb_network_header(skb) + sctphoff; |
135 | sctph->dest = cp->dport; | 140 | sctph->dest = cp->dport; |
136 | 141 | ||
137 | /* Calculate the checksum */ | 142 | sctp_nat_csum(skb, sctph, sctphoff); |
138 | crc32 = sctp_start_cksum((u8 *) sctph, skb_headlen(skb) - sctphoff); | ||
139 | skb_walk_frags(skb, iter) | ||
140 | crc32 = sctp_update_cksum((u8 *) iter->data, skb_headlen(iter), | ||
141 | crc32); | ||
142 | crc32 = sctp_end_cksum(crc32); | ||
143 | sctph->checksum = crc32; | ||
144 | 143 | ||
145 | return 1; | 144 | return 1; |
146 | } | 145 | } |
diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c index effa10c9e4e3..44fd10c539ac 100644 --- a/net/netfilter/ipvs/ip_vs_sync.c +++ b/net/netfilter/ipvs/ip_vs_sync.c | |||
@@ -1795,6 +1795,8 @@ int start_sync_thread(struct net *net, int state, char *mcast_ifn, __u8 syncid) | |||
1795 | GFP_KERNEL); | 1795 | GFP_KERNEL); |
1796 | if (!tinfo->buf) | 1796 | if (!tinfo->buf) |
1797 | goto outtinfo; | 1797 | goto outtinfo; |
1798 | } else { | ||
1799 | tinfo->buf = NULL; | ||
1798 | } | 1800 | } |
1799 | tinfo->id = id; | 1801 | tinfo->id = id; |
1800 | 1802 | ||
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 51561eafcb72..79e8ed4ac7ce 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c | |||
@@ -1135,9 +1135,9 @@ static int htb_dump_class(struct Qdisc *sch, unsigned long arg, | |||
1135 | memset(&opt, 0, sizeof(opt)); | 1135 | memset(&opt, 0, sizeof(opt)); |
1136 | 1136 | ||
1137 | opt.rate.rate = cl->rate.rate_bps >> 3; | 1137 | opt.rate.rate = cl->rate.rate_bps >> 3; |
1138 | opt.buffer = cl->buffer; | 1138 | opt.buffer = PSCHED_NS2TICKS(cl->buffer); |
1139 | opt.ceil.rate = cl->ceil.rate_bps >> 3; | 1139 | opt.ceil.rate = cl->ceil.rate_bps >> 3; |
1140 | opt.cbuffer = cl->cbuffer; | 1140 | opt.cbuffer = PSCHED_NS2TICKS(cl->cbuffer); |
1141 | opt.quantum = cl->quantum; | 1141 | opt.quantum = cl->quantum; |
1142 | opt.prio = cl->prio; | 1142 | opt.prio = cl->prio; |
1143 | opt.level = cl->level; | 1143 | opt.level = cl->level; |
diff --git a/net/sctp/Kconfig b/net/sctp/Kconfig index 7521d944c0fb..cf4852814e0c 100644 --- a/net/sctp/Kconfig +++ b/net/sctp/Kconfig | |||
@@ -3,8 +3,8 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | menuconfig IP_SCTP | 5 | menuconfig IP_SCTP |
6 | tristate "The SCTP Protocol (EXPERIMENTAL)" | 6 | tristate "The SCTP Protocol" |
7 | depends on INET && EXPERIMENTAL | 7 | depends on INET |
8 | depends on IPV6 || IPV6=n | 8 | depends on IPV6 || IPV6=n |
9 | select CRYPTO | 9 | select CRYPTO |
10 | select CRYPTO_HMAC | 10 | select CRYPTO_HMAC |
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index f3f0f4dc31dd..391a245d5203 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c | |||
@@ -326,9 +326,10 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr, | |||
326 | */ | 326 | */ |
327 | rcu_read_lock(); | 327 | rcu_read_lock(); |
328 | list_for_each_entry_rcu(laddr, &bp->address_list, list) { | 328 | list_for_each_entry_rcu(laddr, &bp->address_list, list) { |
329 | if (!laddr->valid && laddr->state != SCTP_ADDR_SRC) | 329 | if (!laddr->valid) |
330 | continue; | 330 | continue; |
331 | if ((laddr->a.sa.sa_family == AF_INET6) && | 331 | if ((laddr->state == SCTP_ADDR_SRC) && |
332 | (laddr->a.sa.sa_family == AF_INET6) && | ||
332 | (scope <= sctp_scope(&laddr->a))) { | 333 | (scope <= sctp_scope(&laddr->a))) { |
333 | bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a); | 334 | bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a); |
334 | if (!baddr || (matchlen < bmatchlen)) { | 335 | if (!baddr || (matchlen < bmatchlen)) { |
diff --git a/samples/Kconfig b/samples/Kconfig index 7b6792a18c05..6181c2cc9ca0 100644 --- a/samples/Kconfig +++ b/samples/Kconfig | |||
@@ -5,12 +5,6 @@ menuconfig SAMPLES | |||
5 | 5 | ||
6 | if SAMPLES | 6 | if SAMPLES |
7 | 7 | ||
8 | config SAMPLE_TRACEPOINTS | ||
9 | tristate "Build tracepoints examples -- loadable modules only" | ||
10 | depends on TRACEPOINTS && m | ||
11 | help | ||
12 | This build tracepoints example modules. | ||
13 | |||
14 | config SAMPLE_TRACE_EVENTS | 8 | config SAMPLE_TRACE_EVENTS |
15 | tristate "Build trace_events examples -- loadable modules only" | 9 | tristate "Build trace_events examples -- loadable modules only" |
16 | depends on EVENT_TRACING && m | 10 | depends on EVENT_TRACING && m |
diff --git a/samples/Makefile b/samples/Makefile index 5ef08bba96ce..1a60c62e2045 100644 --- a/samples/Makefile +++ b/samples/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | # Makefile for Linux samples code | 1 | # Makefile for Linux samples code |
2 | 2 | ||
3 | obj-$(CONFIG_SAMPLES) += kobject/ kprobes/ tracepoints/ trace_events/ \ | 3 | obj-$(CONFIG_SAMPLES) += kobject/ kprobes/ trace_events/ \ |
4 | hw_breakpoint/ kfifo/ kdb/ hidraw/ rpmsg/ seccomp/ | 4 | hw_breakpoint/ kfifo/ kdb/ hidraw/ rpmsg/ seccomp/ |
diff --git a/samples/tracepoints/Makefile b/samples/tracepoints/Makefile deleted file mode 100644 index 36479ad9ae14..000000000000 --- a/samples/tracepoints/Makefile +++ /dev/null | |||
@@ -1,6 +0,0 @@ | |||
1 | # builds the tracepoint example kernel modules; | ||
2 | # then to use one (as root): insmod <module_name.ko> | ||
3 | |||
4 | obj-$(CONFIG_SAMPLE_TRACEPOINTS) += tracepoint-sample.o | ||
5 | obj-$(CONFIG_SAMPLE_TRACEPOINTS) += tracepoint-probe-sample.o | ||
6 | obj-$(CONFIG_SAMPLE_TRACEPOINTS) += tracepoint-probe-sample2.o | ||
diff --git a/samples/tracepoints/tp-samples-trace.h b/samples/tracepoints/tp-samples-trace.h deleted file mode 100644 index 4d46be965961..000000000000 --- a/samples/tracepoints/tp-samples-trace.h +++ /dev/null | |||
@@ -1,11 +0,0 @@ | |||
1 | #ifndef _TP_SAMPLES_TRACE_H | ||
2 | #define _TP_SAMPLES_TRACE_H | ||
3 | |||
4 | #include <linux/proc_fs.h> /* for struct inode and struct file */ | ||
5 | #include <linux/tracepoint.h> | ||
6 | |||
7 | DECLARE_TRACE(subsys_event, | ||
8 | TP_PROTO(struct inode *inode, struct file *file), | ||
9 | TP_ARGS(inode, file)); | ||
10 | DECLARE_TRACE_NOARGS(subsys_eventb); | ||
11 | #endif | ||
diff --git a/samples/tracepoints/tracepoint-probe-sample.c b/samples/tracepoints/tracepoint-probe-sample.c deleted file mode 100644 index 744c0b9652a7..000000000000 --- a/samples/tracepoints/tracepoint-probe-sample.c +++ /dev/null | |||
@@ -1,57 +0,0 @@ | |||
1 | /* | ||
2 | * tracepoint-probe-sample.c | ||
3 | * | ||
4 | * sample tracepoint probes. | ||
5 | */ | ||
6 | |||
7 | #include <linux/module.h> | ||
8 | #include <linux/file.h> | ||
9 | #include <linux/dcache.h> | ||
10 | #include "tp-samples-trace.h" | ||
11 | |||
12 | /* | ||
13 | * Here the caller only guarantees locking for struct file and struct inode. | ||
14 | * Locking must therefore be done in the probe to use the dentry. | ||
15 | */ | ||
16 | static void probe_subsys_event(void *ignore, | ||
17 | struct inode *inode, struct file *file) | ||
18 | { | ||
19 | path_get(&file->f_path); | ||
20 | dget(file->f_path.dentry); | ||
21 | printk(KERN_INFO "Event is encountered with filename %s\n", | ||
22 | file->f_path.dentry->d_name.name); | ||
23 | dput(file->f_path.dentry); | ||
24 | path_put(&file->f_path); | ||
25 | } | ||
26 | |||
27 | static void probe_subsys_eventb(void *ignore) | ||
28 | { | ||
29 | printk(KERN_INFO "Event B is encountered\n"); | ||
30 | } | ||
31 | |||
32 | static int __init tp_sample_trace_init(void) | ||
33 | { | ||
34 | int ret; | ||
35 | |||
36 | ret = register_trace_subsys_event(probe_subsys_event, NULL); | ||
37 | WARN_ON(ret); | ||
38 | ret = register_trace_subsys_eventb(probe_subsys_eventb, NULL); | ||
39 | WARN_ON(ret); | ||
40 | |||
41 | return 0; | ||
42 | } | ||
43 | |||
44 | module_init(tp_sample_trace_init); | ||
45 | |||
46 | static void __exit tp_sample_trace_exit(void) | ||
47 | { | ||
48 | unregister_trace_subsys_eventb(probe_subsys_eventb, NULL); | ||
49 | unregister_trace_subsys_event(probe_subsys_event, NULL); | ||
50 | tracepoint_synchronize_unregister(); | ||
51 | } | ||
52 | |||
53 | module_exit(tp_sample_trace_exit); | ||
54 | |||
55 | MODULE_LICENSE("GPL"); | ||
56 | MODULE_AUTHOR("Mathieu Desnoyers"); | ||
57 | MODULE_DESCRIPTION("Tracepoint Probes Samples"); | ||
diff --git a/samples/tracepoints/tracepoint-probe-sample2.c b/samples/tracepoints/tracepoint-probe-sample2.c deleted file mode 100644 index 9fcf990e5d4b..000000000000 --- a/samples/tracepoints/tracepoint-probe-sample2.c +++ /dev/null | |||
@@ -1,44 +0,0 @@ | |||
1 | /* | ||
2 | * tracepoint-probe-sample2.c | ||
3 | * | ||
4 | * 2nd sample tracepoint probes. | ||
5 | */ | ||
6 | |||
7 | #include <linux/module.h> | ||
8 | #include <linux/fs.h> | ||
9 | #include "tp-samples-trace.h" | ||
10 | |||
11 | /* | ||
12 | * Here the caller only guarantees locking for struct file and struct inode. | ||
13 | * Locking must therefore be done in the probe to use the dentry. | ||
14 | */ | ||
15 | static void probe_subsys_event(void *ignore, | ||
16 | struct inode *inode, struct file *file) | ||
17 | { | ||
18 | printk(KERN_INFO "Event is encountered with inode number %lu\n", | ||
19 | inode->i_ino); | ||
20 | } | ||
21 | |||
22 | static int __init tp_sample_trace_init(void) | ||
23 | { | ||
24 | int ret; | ||
25 | |||
26 | ret = register_trace_subsys_event(probe_subsys_event, NULL); | ||
27 | WARN_ON(ret); | ||
28 | |||
29 | return 0; | ||
30 | } | ||
31 | |||
32 | module_init(tp_sample_trace_init); | ||
33 | |||
34 | static void __exit tp_sample_trace_exit(void) | ||
35 | { | ||
36 | unregister_trace_subsys_event(probe_subsys_event, NULL); | ||
37 | tracepoint_synchronize_unregister(); | ||
38 | } | ||
39 | |||
40 | module_exit(tp_sample_trace_exit); | ||
41 | |||
42 | MODULE_LICENSE("GPL"); | ||
43 | MODULE_AUTHOR("Mathieu Desnoyers"); | ||
44 | MODULE_DESCRIPTION("Tracepoint Probes Samples"); | ||
diff --git a/samples/tracepoints/tracepoint-sample.c b/samples/tracepoints/tracepoint-sample.c deleted file mode 100644 index f4d89e008c32..000000000000 --- a/samples/tracepoints/tracepoint-sample.c +++ /dev/null | |||
@@ -1,57 +0,0 @@ | |||
1 | /* tracepoint-sample.c | ||
2 | * | ||
3 | * Executes a tracepoint when /proc/tracepoint-sample is opened. | ||
4 | * | ||
5 | * (C) Copyright 2007 Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca> | ||
6 | * | ||
7 | * This file is released under the GPLv2. | ||
8 | * See the file COPYING for more details. | ||
9 | */ | ||
10 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/sched.h> | ||
13 | #include <linux/proc_fs.h> | ||
14 | #include "tp-samples-trace.h" | ||
15 | |||
16 | DEFINE_TRACE(subsys_event); | ||
17 | DEFINE_TRACE(subsys_eventb); | ||
18 | |||
19 | struct proc_dir_entry *pentry_sample; | ||
20 | |||
21 | static int my_open(struct inode *inode, struct file *file) | ||
22 | { | ||
23 | int i; | ||
24 | |||
25 | trace_subsys_event(inode, file); | ||
26 | for (i = 0; i < 10; i++) | ||
27 | trace_subsys_eventb(); | ||
28 | return -EPERM; | ||
29 | } | ||
30 | |||
31 | static const struct file_operations mark_ops = { | ||
32 | .open = my_open, | ||
33 | .llseek = noop_llseek, | ||
34 | }; | ||
35 | |||
36 | static int __init sample_init(void) | ||
37 | { | ||
38 | printk(KERN_ALERT "sample init\n"); | ||
39 | pentry_sample = proc_create("tracepoint-sample", 0444, NULL, | ||
40 | &mark_ops); | ||
41 | if (!pentry_sample) | ||
42 | return -EPERM; | ||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | static void __exit sample_exit(void) | ||
47 | { | ||
48 | printk(KERN_ALERT "sample exit\n"); | ||
49 | remove_proc_entry("tracepoint-sample", NULL); | ||
50 | } | ||
51 | |||
52 | module_init(sample_init) | ||
53 | module_exit(sample_exit) | ||
54 | |||
55 | MODULE_LICENSE("GPL"); | ||
56 | MODULE_AUTHOR("Mathieu Desnoyers"); | ||
57 | MODULE_DESCRIPTION("Tracepoint sample"); | ||
diff --git a/tools/Makefile b/tools/Makefile index 1f9a529fe544..798fa0ef048e 100644 --- a/tools/Makefile +++ b/tools/Makefile | |||
@@ -15,7 +15,7 @@ help: | |||
15 | @echo ' x86_energy_perf_policy - Intel energy policy tool' | 15 | @echo ' x86_energy_perf_policy - Intel energy policy tool' |
16 | @echo '' | 16 | @echo '' |
17 | @echo 'You can do:' | 17 | @echo 'You can do:' |
18 | @echo ' $$ make -C tools/<tool>_install' | 18 | @echo ' $$ make -C tools/ <tool>_install' |
19 | @echo '' | 19 | @echo '' |
20 | @echo ' from the kernel command line to build and install one of' | 20 | @echo ' from the kernel command line to build and install one of' |
21 | @echo ' the tools above' | 21 | @echo ' the tools above' |
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index 5a824e355d04..82b0606dcb8a 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c | |||
@@ -13,8 +13,7 @@ | |||
13 | * GNU Lesser General Public License for more details. | 13 | * GNU Lesser General Public License for more details. |
14 | * | 14 | * |
15 | * You should have received a copy of the GNU Lesser General Public | 15 | * You should have received a copy of the GNU Lesser General Public |
16 | * License along with this program; if not, write to the Free Software | 16 | * License along with this program; if not, see <http://www.gnu.org/licenses> |
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | * | 17 | * |
19 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
20 | * | 19 | * |
@@ -1224,6 +1223,34 @@ static int field_is_long(struct format_field *field) | |||
1224 | return 0; | 1223 | return 0; |
1225 | } | 1224 | } |
1226 | 1225 | ||
1226 | static unsigned int type_size(const char *name) | ||
1227 | { | ||
1228 | /* This covers all FIELD_IS_STRING types. */ | ||
1229 | static struct { | ||
1230 | const char *type; | ||
1231 | unsigned int size; | ||
1232 | } table[] = { | ||
1233 | { "u8", 1 }, | ||
1234 | { "u16", 2 }, | ||
1235 | { "u32", 4 }, | ||
1236 | { "u64", 8 }, | ||
1237 | { "s8", 1 }, | ||
1238 | { "s16", 2 }, | ||
1239 | { "s32", 4 }, | ||
1240 | { "s64", 8 }, | ||
1241 | { "char", 1 }, | ||
1242 | { }, | ||
1243 | }; | ||
1244 | int i; | ||
1245 | |||
1246 | for (i = 0; table[i].type; i++) { | ||
1247 | if (!strcmp(table[i].type, name)) | ||
1248 | return table[i].size; | ||
1249 | } | ||
1250 | |||
1251 | return 0; | ||
1252 | } | ||
1253 | |||
1227 | static int event_read_fields(struct event_format *event, struct format_field **fields) | 1254 | static int event_read_fields(struct event_format *event, struct format_field **fields) |
1228 | { | 1255 | { |
1229 | struct format_field *field = NULL; | 1256 | struct format_field *field = NULL; |
@@ -1233,6 +1260,8 @@ static int event_read_fields(struct event_format *event, struct format_field **f | |||
1233 | int count = 0; | 1260 | int count = 0; |
1234 | 1261 | ||
1235 | do { | 1262 | do { |
1263 | unsigned int size_dynamic = 0; | ||
1264 | |||
1236 | type = read_token(&token); | 1265 | type = read_token(&token); |
1237 | if (type == EVENT_NEWLINE) { | 1266 | if (type == EVENT_NEWLINE) { |
1238 | free_token(token); | 1267 | free_token(token); |
@@ -1391,6 +1420,7 @@ static int event_read_fields(struct event_format *event, struct format_field **f | |||
1391 | field->type = new_type; | 1420 | field->type = new_type; |
1392 | strcat(field->type, " "); | 1421 | strcat(field->type, " "); |
1393 | strcat(field->type, field->name); | 1422 | strcat(field->type, field->name); |
1423 | size_dynamic = type_size(field->name); | ||
1394 | free_token(field->name); | 1424 | free_token(field->name); |
1395 | strcat(field->type, brackets); | 1425 | strcat(field->type, brackets); |
1396 | field->name = token; | 1426 | field->name = token; |
@@ -1463,7 +1493,8 @@ static int event_read_fields(struct event_format *event, struct format_field **f | |||
1463 | if (read_expect_type(EVENT_ITEM, &token)) | 1493 | if (read_expect_type(EVENT_ITEM, &token)) |
1464 | goto fail; | 1494 | goto fail; |
1465 | 1495 | ||
1466 | /* add signed type */ | 1496 | if (strtoul(token, NULL, 0)) |
1497 | field->flags |= FIELD_IS_SIGNED; | ||
1467 | 1498 | ||
1468 | free_token(token); | 1499 | free_token(token); |
1469 | if (read_expected(EVENT_OP, ";") < 0) | 1500 | if (read_expected(EVENT_OP, ";") < 0) |
@@ -1478,10 +1509,14 @@ static int event_read_fields(struct event_format *event, struct format_field **f | |||
1478 | if (field->flags & FIELD_IS_ARRAY) { | 1509 | if (field->flags & FIELD_IS_ARRAY) { |
1479 | if (field->arraylen) | 1510 | if (field->arraylen) |
1480 | field->elementsize = field->size / field->arraylen; | 1511 | field->elementsize = field->size / field->arraylen; |
1512 | else if (field->flags & FIELD_IS_DYNAMIC) | ||
1513 | field->elementsize = size_dynamic; | ||
1481 | else if (field->flags & FIELD_IS_STRING) | 1514 | else if (field->flags & FIELD_IS_STRING) |
1482 | field->elementsize = 1; | 1515 | field->elementsize = 1; |
1483 | else | 1516 | else if (field->flags & FIELD_IS_LONG) |
1484 | field->elementsize = event->pevent->long_size; | 1517 | field->elementsize = event->pevent ? |
1518 | event->pevent->long_size : | ||
1519 | sizeof(long); | ||
1485 | } else | 1520 | } else |
1486 | field->elementsize = field->size; | 1521 | field->elementsize = field->size; |
1487 | 1522 | ||
@@ -1785,6 +1820,8 @@ process_op(struct event_format *event, struct print_arg *arg, char **tok) | |||
1785 | strcmp(token, "/") == 0 || | 1820 | strcmp(token, "/") == 0 || |
1786 | strcmp(token, "<") == 0 || | 1821 | strcmp(token, "<") == 0 || |
1787 | strcmp(token, ">") == 0 || | 1822 | strcmp(token, ">") == 0 || |
1823 | strcmp(token, "<=") == 0 || | ||
1824 | strcmp(token, ">=") == 0 || | ||
1788 | strcmp(token, "==") == 0 || | 1825 | strcmp(token, "==") == 0 || |
1789 | strcmp(token, "!=") == 0) { | 1826 | strcmp(token, "!=") == 0) { |
1790 | 1827 | ||
@@ -2481,7 +2518,7 @@ process_dynamic_array(struct event_format *event, struct print_arg *arg, char ** | |||
2481 | 2518 | ||
2482 | free_token(token); | 2519 | free_token(token); |
2483 | arg = alloc_arg(); | 2520 | arg = alloc_arg(); |
2484 | if (!field) { | 2521 | if (!arg) { |
2485 | do_warning("%s: not enough memory!", __func__); | 2522 | do_warning("%s: not enough memory!", __func__); |
2486 | *tok = NULL; | 2523 | *tok = NULL; |
2487 | return EVENT_ERROR; | 2524 | return EVENT_ERROR; |
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index 24a4bbabc5d5..7be7e89533e4 100644 --- a/tools/lib/traceevent/event-parse.h +++ b/tools/lib/traceevent/event-parse.h | |||
@@ -13,8 +13,7 @@ | |||
13 | * GNU Lesser General Public License for more details. | 13 | * GNU Lesser General Public License for more details. |
14 | * | 14 | * |
15 | * You should have received a copy of the GNU Lesser General Public | 15 | * You should have received a copy of the GNU Lesser General Public |
16 | * License along with this program; if not, write to the Free Software | 16 | * License along with this program; if not, see <http://www.gnu.org/licenses> |
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | * | 17 | * |
19 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
20 | */ | 19 | */ |
diff --git a/tools/lib/traceevent/event-utils.h b/tools/lib/traceevent/event-utils.h index bc075006966e..e76c9acb92cd 100644 --- a/tools/lib/traceevent/event-utils.h +++ b/tools/lib/traceevent/event-utils.h | |||
@@ -13,8 +13,7 @@ | |||
13 | * GNU Lesser General Public License for more details. | 13 | * GNU Lesser General Public License for more details. |
14 | * | 14 | * |
15 | * You should have received a copy of the GNU Lesser General Public | 15 | * You should have received a copy of the GNU Lesser General Public |
16 | * License along with this program; if not, write to the Free Software | 16 | * License along with this program; if not, see <http://www.gnu.org/licenses> |
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | * | 17 | * |
19 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
20 | */ | 19 | */ |
diff --git a/tools/lib/traceevent/parse-filter.c b/tools/lib/traceevent/parse-filter.c index 5ea4326ad11f..2500e75583fc 100644 --- a/tools/lib/traceevent/parse-filter.c +++ b/tools/lib/traceevent/parse-filter.c | |||
@@ -13,8 +13,7 @@ | |||
13 | * GNU Lesser General Public License for more details. | 13 | * GNU Lesser General Public License for more details. |
14 | * | 14 | * |
15 | * You should have received a copy of the GNU Lesser General Public | 15 | * You should have received a copy of the GNU Lesser General Public |
16 | * License along with this program; if not, write to the Free Software | 16 | * License along with this program; if not, see <http://www.gnu.org/licenses> |
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | * | 17 | * |
19 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
20 | */ | 19 | */ |
diff --git a/tools/lib/traceevent/parse-utils.c b/tools/lib/traceevent/parse-utils.c index f023a133abb6..bba701cf10e6 100644 --- a/tools/lib/traceevent/parse-utils.c +++ b/tools/lib/traceevent/parse-utils.c | |||
@@ -1,3 +1,22 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
3 | * | ||
4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU Lesser General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * version 2.1 of the License (not later!) | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this program; if not, see <http://www.gnu.org/licenses> | ||
17 | * | ||
18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
19 | */ | ||
1 | #include <stdio.h> | 20 | #include <stdio.h> |
2 | #include <stdlib.h> | 21 | #include <stdlib.h> |
3 | #include <string.h> | 22 | #include <string.h> |
diff --git a/tools/lib/traceevent/trace-seq.c b/tools/lib/traceevent/trace-seq.c index b1ccc923e8a5..a57db805136a 100644 --- a/tools/lib/traceevent/trace-seq.c +++ b/tools/lib/traceevent/trace-seq.c | |||
@@ -13,8 +13,7 @@ | |||
13 | * GNU Lesser General Public License for more details. | 13 | * GNU Lesser General Public License for more details. |
14 | * | 14 | * |
15 | * You should have received a copy of the GNU Lesser General Public | 15 | * You should have received a copy of the GNU Lesser General Public |
16 | * License along with this program; if not, write to the Free Software | 16 | * License along with this program; if not, see <http://www.gnu.org/licenses> |
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | * | 17 | * |
19 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
20 | */ | 19 | */ |
diff --git a/tools/perf/Documentation/Makefile b/tools/perf/Documentation/Makefile index ef6d22e879eb..eb30044a922a 100644 --- a/tools/perf/Documentation/Makefile +++ b/tools/perf/Documentation/Makefile | |||
@@ -222,10 +222,14 @@ install-pdf: pdf | |||
222 | #install-html: html | 222 | #install-html: html |
223 | # '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir) | 223 | # '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir) |
224 | 224 | ||
225 | ifneq ($(MAKECMDGOALS),clean) | ||
226 | ifneq ($(MAKECMDGOALS),tags) | ||
225 | $(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE | 227 | $(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE |
226 | $(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) $(OUTPUT)PERF-VERSION-FILE | 228 | $(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) $(OUTPUT)PERF-VERSION-FILE |
227 | 229 | ||
228 | -include $(OUTPUT)PERF-VERSION-FILE | 230 | -include $(OUTPUT)PERF-VERSION-FILE |
231 | endif | ||
232 | endif | ||
229 | 233 | ||
230 | # | 234 | # |
231 | # Determine "include::" file references in asciidoc files. | 235 | # Determine "include::" file references in asciidoc files. |
diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt index c8ffd9fd5c6a..5ad07ef417f0 100644 --- a/tools/perf/Documentation/perf-annotate.txt +++ b/tools/perf/Documentation/perf-annotate.txt | |||
@@ -61,11 +61,13 @@ OPTIONS | |||
61 | 61 | ||
62 | --stdio:: Use the stdio interface. | 62 | --stdio:: Use the stdio interface. |
63 | 63 | ||
64 | --tui:: Use the TUI interface Use of --tui requires a tty, if one is not | 64 | --tui:: Use the TUI interface. Use of --tui requires a tty, if one is not |
65 | present, as when piping to other commands, the stdio interface is | 65 | present, as when piping to other commands, the stdio interface is |
66 | used. This interfaces starts by centering on the line with more | 66 | used. This interfaces starts by centering on the line with more |
67 | samples, TAB/UNTAB cycles through the lines with more samples. | 67 | samples, TAB/UNTAB cycles through the lines with more samples. |
68 | 68 | ||
69 | --gtk:: Use the GTK interface. | ||
70 | |||
69 | -C:: | 71 | -C:: |
70 | --cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can | 72 | --cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can |
71 | be provided as a comma-separated list with no space: 0,1. Ranges of | 73 | be provided as a comma-separated list with no space: 0,1. Ranges of |
@@ -88,6 +90,9 @@ OPTIONS | |||
88 | --objdump=<path>:: | 90 | --objdump=<path>:: |
89 | Path to objdump binary. | 91 | Path to objdump binary. |
90 | 92 | ||
93 | --skip-missing:: | ||
94 | Skip symbols that cannot be annotated. | ||
95 | |||
91 | SEE ALSO | 96 | SEE ALSO |
92 | -------- | 97 | -------- |
93 | linkperf:perf-record[1], linkperf:perf-report[1] | 98 | linkperf:perf-record[1], linkperf:perf-report[1] |
diff --git a/tools/perf/Documentation/perf-buildid-cache.txt b/tools/perf/Documentation/perf-buildid-cache.txt index c1057701a7dc..e9a8349a7172 100644 --- a/tools/perf/Documentation/perf-buildid-cache.txt +++ b/tools/perf/Documentation/perf-buildid-cache.txt | |||
@@ -24,6 +24,13 @@ OPTIONS | |||
24 | -r:: | 24 | -r:: |
25 | --remove=:: | 25 | --remove=:: |
26 | Remove specified file from the cache. | 26 | Remove specified file from the cache. |
27 | -M:: | ||
28 | --missing=:: | ||
29 | List missing build ids in the cache for the specified file. | ||
30 | -u:: | ||
31 | --update:: | ||
32 | Update specified file of the cache. It can be used to update kallsyms | ||
33 | kernel dso to vmlinux in order to support annotation. | ||
27 | -v:: | 34 | -v:: |
28 | --verbose:: | 35 | --verbose:: |
29 | Be more verbose. | 36 | Be more verbose. |
diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt index 194f37d635df..5b3123d5721f 100644 --- a/tools/perf/Documentation/perf-diff.txt +++ b/tools/perf/Documentation/perf-diff.txt | |||
@@ -22,10 +22,6 @@ specified perf.data files. | |||
22 | 22 | ||
23 | OPTIONS | 23 | OPTIONS |
24 | ------- | 24 | ------- |
25 | -M:: | ||
26 | --displacement:: | ||
27 | Show position displacement relative to baseline. | ||
28 | |||
29 | -D:: | 25 | -D:: |
30 | --dump-raw-trace:: | 26 | --dump-raw-trace:: |
31 | Dump raw trace in ASCII. | 27 | Dump raw trace in ASCII. |
diff --git a/tools/perf/Documentation/perf-evlist.txt b/tools/perf/Documentation/perf-evlist.txt index 15217345c2fa..1ceb3700ffbb 100644 --- a/tools/perf/Documentation/perf-evlist.txt +++ b/tools/perf/Documentation/perf-evlist.txt | |||
@@ -28,6 +28,10 @@ OPTIONS | |||
28 | --verbose=:: | 28 | --verbose=:: |
29 | Show all fields. | 29 | Show all fields. |
30 | 30 | ||
31 | -g:: | ||
32 | --group:: | ||
33 | Show event group information. | ||
34 | |||
31 | SEE ALSO | 35 | SEE ALSO |
32 | -------- | 36 | -------- |
33 | linkperf:perf-record[1], linkperf:perf-list[1], | 37 | linkperf:perf-record[1], linkperf:perf-list[1], |
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index f4d91bebd59d..02284a0067f0 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt | |||
@@ -57,11 +57,44 @@ OPTIONS | |||
57 | 57 | ||
58 | -s:: | 58 | -s:: |
59 | --sort=:: | 59 | --sort=:: |
60 | Sort by key(s): pid, comm, dso, symbol, parent, srcline. | 60 | Sort histogram entries by given key(s) - multiple keys can be specified |
61 | in CSV format. Following sort keys are available: | ||
62 | pid, comm, dso, symbol, parent, cpu, srcline. | ||
63 | |||
64 | Each key has following meaning: | ||
65 | |||
66 | - comm: command (name) of the task which can be read via /proc/<pid>/comm | ||
67 | - pid: command and tid of the task | ||
68 | - dso: name of library or module executed at the time of sample | ||
69 | - symbol: name of function executed at the time of sample | ||
70 | - parent: name of function matched to the parent regex filter. Unmatched | ||
71 | entries are displayed as "[other]". | ||
72 | - cpu: cpu number the task ran at the time of sample | ||
73 | - srcline: filename and line number executed at the time of sample. The | ||
74 | DWARF debuggin info must be provided. | ||
75 | |||
76 | By default, comm, dso and symbol keys are used. | ||
77 | (i.e. --sort comm,dso,symbol) | ||
78 | |||
79 | If --branch-stack option is used, following sort keys are also | ||
80 | available: | ||
81 | dso_from, dso_to, symbol_from, symbol_to, mispredict. | ||
82 | |||
83 | - dso_from: name of library or module branched from | ||
84 | - dso_to: name of library or module branched to | ||
85 | - symbol_from: name of function branched from | ||
86 | - symbol_to: name of function branched to | ||
87 | - mispredict: "N" for predicted branch, "Y" for mispredicted branch | ||
88 | |||
89 | And default sort keys are changed to comm, dso_from, symbol_from, dso_to | ||
90 | and symbol_to, see '--branch-stack'. | ||
61 | 91 | ||
62 | -p:: | 92 | -p:: |
63 | --parent=<regex>:: | 93 | --parent=<regex>:: |
64 | regex filter to identify parent, see: '--sort parent' | 94 | A regex filter to identify parent. The parent is a caller of this |
95 | function and searched through the callchain, thus it requires callchain | ||
96 | information recorded. The pattern is in the exteneded regex format and | ||
97 | defaults to "\^sys_|^do_page_fault", see '--sort parent'. | ||
65 | 98 | ||
66 | -x:: | 99 | -x:: |
67 | --exclude-other:: | 100 | --exclude-other:: |
@@ -74,7 +107,6 @@ OPTIONS | |||
74 | 107 | ||
75 | -t:: | 108 | -t:: |
76 | --field-separator=:: | 109 | --field-separator=:: |
77 | |||
78 | Use a special separator character and don't pad with spaces, replacing | 110 | Use a special separator character and don't pad with spaces, replacing |
79 | all occurrences of this separator in symbol names (and other output) | 111 | all occurrences of this separator in symbol names (and other output) |
80 | with a '.' character, that thus it's the only non valid separator. | 112 | with a '.' character, that thus it's the only non valid separator. |
@@ -171,6 +203,9 @@ OPTIONS | |||
171 | --objdump=<path>:: | 203 | --objdump=<path>:: |
172 | Path to objdump binary. | 204 | Path to objdump binary. |
173 | 205 | ||
206 | --group:: | ||
207 | Show event group information together. | ||
208 | |||
174 | SEE ALSO | 209 | SEE ALSO |
175 | -------- | 210 | -------- |
176 | linkperf:perf-stat[1], linkperf:perf-annotate[1] | 211 | linkperf:perf-stat[1], linkperf:perf-annotate[1] |
diff --git a/tools/perf/Documentation/perf-script-python.txt b/tools/perf/Documentation/perf-script-python.txt index a4027f221a53..9f1f054b8432 100644 --- a/tools/perf/Documentation/perf-script-python.txt +++ b/tools/perf/Documentation/perf-script-python.txt | |||
@@ -336,7 +336,6 @@ scripts listed by the 'perf script -l' command e.g.: | |||
336 | ---- | 336 | ---- |
337 | root@tropicana:~# perf script -l | 337 | root@tropicana:~# perf script -l |
338 | List of available trace scripts: | 338 | List of available trace scripts: |
339 | workqueue-stats workqueue stats (ins/exe/create/destroy) | ||
340 | wakeup-latency system-wide min/max/avg wakeup latency | 339 | wakeup-latency system-wide min/max/avg wakeup latency |
341 | rw-by-file <comm> r/w activity for a program, by file | 340 | rw-by-file <comm> r/w activity for a program, by file |
342 | rw-by-pid system-wide r/w activity | 341 | rw-by-pid system-wide r/w activity |
@@ -402,7 +401,6 @@ should show a new entry for your script: | |||
402 | ---- | 401 | ---- |
403 | root@tropicana:~# perf script -l | 402 | root@tropicana:~# perf script -l |
404 | List of available trace scripts: | 403 | List of available trace scripts: |
405 | workqueue-stats workqueue stats (ins/exe/create/destroy) | ||
406 | wakeup-latency system-wide min/max/avg wakeup latency | 404 | wakeup-latency system-wide min/max/avg wakeup latency |
407 | rw-by-file <comm> r/w activity for a program, by file | 405 | rw-by-file <comm> r/w activity for a program, by file |
408 | rw-by-pid system-wide r/w activity | 406 | rw-by-pid system-wide r/w activity |
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt index cf0c3107e06e..faf4f4feebcc 100644 --- a/tools/perf/Documentation/perf-stat.txt +++ b/tools/perf/Documentation/perf-stat.txt | |||
@@ -114,6 +114,17 @@ with it. --append may be used here. Examples: | |||
114 | 114 | ||
115 | perf stat --repeat 10 --null --sync --pre 'make -s O=defconfig-build/clean' -- make -s -j64 O=defconfig-build/ bzImage | 115 | perf stat --repeat 10 --null --sync --pre 'make -s O=defconfig-build/clean' -- make -s -j64 O=defconfig-build/ bzImage |
116 | 116 | ||
117 | -I msecs:: | ||
118 | --interval-print msecs:: | ||
119 | Print count deltas every N milliseconds (minimum: 100ms) | ||
120 | example: perf stat -I 1000 -e cycles -a sleep 5 | ||
121 | |||
122 | --aggr-socket:: | ||
123 | Aggregate counts per processor socket for system-wide mode measurements. This | ||
124 | is a useful mode to detect imbalance between sockets. To enable this mode, | ||
125 | use --aggr-socket in addition to -a. (system-wide). The output includes the | ||
126 | socket number and the number of online processors on that socket. This is | ||
127 | useful to gauge the amount of aggregation. | ||
117 | 128 | ||
118 | EXAMPLES | 129 | EXAMPLES |
119 | -------- | 130 | -------- |
diff --git a/tools/perf/Documentation/perf-test.txt b/tools/perf/Documentation/perf-test.txt index b24ac40fcd58..d1d3e5121f89 100644 --- a/tools/perf/Documentation/perf-test.txt +++ b/tools/perf/Documentation/perf-test.txt | |||
@@ -23,6 +23,10 @@ from 'perf test list'. | |||
23 | 23 | ||
24 | OPTIONS | 24 | OPTIONS |
25 | ------- | 25 | ------- |
26 | -s:: | ||
27 | --skip:: | ||
28 | Tests to skip (comma separater numeric list). | ||
29 | |||
26 | -v:: | 30 | -v:: |
27 | --verbose:: | 31 | --verbose:: |
28 | Be more verbose. | 32 | Be more verbose. |
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt index 5b80d84d6b4a..a414bc95fd52 100644 --- a/tools/perf/Documentation/perf-top.txt +++ b/tools/perf/Documentation/perf-top.txt | |||
@@ -60,7 +60,7 @@ Default is to monitor all CPUS. | |||
60 | 60 | ||
61 | -i:: | 61 | -i:: |
62 | --inherit:: | 62 | --inherit:: |
63 | Child tasks inherit counters, only makes sens with -p option. | 63 | Child tasks do not inherit counters. |
64 | 64 | ||
65 | -k <path>:: | 65 | -k <path>:: |
66 | --vmlinux=<path>:: | 66 | --vmlinux=<path>:: |
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 8ab05e543ef4..a2108ca1cc17 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
@@ -47,10 +47,11 @@ include config/utilities.mak | |||
47 | # backtrace post unwind. | 47 | # backtrace post unwind. |
48 | # | 48 | # |
49 | # Define NO_BACKTRACE if you do not want stack backtrace debug feature | 49 | # Define NO_BACKTRACE if you do not want stack backtrace debug feature |
50 | # | ||
51 | # Define NO_LIBNUMA if you do not want numa perf benchmark | ||
50 | 52 | ||
51 | $(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE | 53 | $(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE |
52 | @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT) | 54 | @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT) |
53 | -include $(OUTPUT)PERF-VERSION-FILE | ||
54 | 55 | ||
55 | uname_M := $(shell uname -m 2>/dev/null || echo not) | 56 | uname_M := $(shell uname -m 2>/dev/null || echo not) |
56 | 57 | ||
@@ -148,13 +149,25 @@ RM = rm -f | |||
148 | MKDIR = mkdir | 149 | MKDIR = mkdir |
149 | FIND = find | 150 | FIND = find |
150 | INSTALL = install | 151 | INSTALL = install |
152 | FLEX = flex | ||
153 | BISON= bison | ||
151 | 154 | ||
152 | # sparse is architecture-neutral, which means that we need to tell it | 155 | # sparse is architecture-neutral, which means that we need to tell it |
153 | # explicitly what architecture to check for. Fix this up for yours.. | 156 | # explicitly what architecture to check for. Fix this up for yours.. |
154 | SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__ | 157 | SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__ |
155 | 158 | ||
159 | ifneq ($(MAKECMDGOALS),clean) | ||
160 | ifneq ($(MAKECMDGOALS),tags) | ||
156 | -include config/feature-tests.mak | 161 | -include config/feature-tests.mak |
157 | 162 | ||
163 | ifeq ($(call get-executable,$(FLEX)),) | ||
164 | dummy := $(error Error: $(FLEX) is missing on this system, please install it) | ||
165 | endif | ||
166 | |||
167 | ifeq ($(call get-executable,$(BISON)),) | ||
168 | dummy := $(error Error: $(BISON) is missing on this system, please install it) | ||
169 | endif | ||
170 | |||
158 | ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -fstack-protector-all,-fstack-protector-all),y) | 171 | ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -fstack-protector-all,-fstack-protector-all),y) |
159 | CFLAGS := $(CFLAGS) -fstack-protector-all | 172 | CFLAGS := $(CFLAGS) -fstack-protector-all |
160 | endif | 173 | endif |
@@ -206,6 +219,8 @@ ifeq ($(call try-cc,$(SOURCE_BIONIC),$(CFLAGS),bionic),y) | |||
206 | EXTLIBS := $(filter-out -lpthread,$(EXTLIBS)) | 219 | EXTLIBS := $(filter-out -lpthread,$(EXTLIBS)) |
207 | BASIC_CFLAGS += -I. | 220 | BASIC_CFLAGS += -I. |
208 | endif | 221 | endif |
222 | endif # MAKECMDGOALS != tags | ||
223 | endif # MAKECMDGOALS != clean | ||
209 | 224 | ||
210 | # Guard against environment variables | 225 | # Guard against environment variables |
211 | BUILTIN_OBJS = | 226 | BUILTIN_OBJS = |
@@ -230,11 +245,19 @@ endif | |||
230 | LIBTRACEEVENT = $(TE_PATH)libtraceevent.a | 245 | LIBTRACEEVENT = $(TE_PATH)libtraceevent.a |
231 | TE_LIB := -L$(TE_PATH) -ltraceevent | 246 | TE_LIB := -L$(TE_PATH) -ltraceevent |
232 | 247 | ||
248 | export LIBTRACEEVENT | ||
249 | |||
250 | # python extension build directories | ||
251 | PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/ | ||
252 | PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/ | ||
253 | PYTHON_EXTBUILD_TMP := $(PYTHON_EXTBUILD)tmp/ | ||
254 | export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP | ||
255 | |||
256 | python-clean := rm -rf $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so | ||
257 | |||
233 | PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources) | 258 | PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources) |
234 | PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py | 259 | PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py |
235 | 260 | ||
236 | export LIBTRACEEVENT | ||
237 | |||
238 | $(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) | 261 | $(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) |
239 | $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \ | 262 | $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \ |
240 | --quiet build_ext; \ | 263 | --quiet build_ext; \ |
@@ -269,20 +292,17 @@ endif | |||
269 | 292 | ||
270 | export PERL_PATH | 293 | export PERL_PATH |
271 | 294 | ||
272 | FLEX = flex | ||
273 | BISON= bison | ||
274 | |||
275 | $(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c | 295 | $(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c |
276 | $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h $(PARSER_DEBUG_FLEX) -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c | 296 | $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h $(PARSER_DEBUG_FLEX) -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c |
277 | 297 | ||
278 | $(OUTPUT)util/parse-events-bison.c: util/parse-events.y | 298 | $(OUTPUT)util/parse-events-bison.c: util/parse-events.y |
279 | $(QUIET_BISON)$(BISON) -v util/parse-events.y -d $(PARSER_DEBUG_BISON) -o $(OUTPUT)util/parse-events-bison.c | 299 | $(QUIET_BISON)$(BISON) -v util/parse-events.y -d $(PARSER_DEBUG_BISON) -o $(OUTPUT)util/parse-events-bison.c -p parse_events_ |
280 | 300 | ||
281 | $(OUTPUT)util/pmu-flex.c: util/pmu.l $(OUTPUT)util/pmu-bison.c | 301 | $(OUTPUT)util/pmu-flex.c: util/pmu.l $(OUTPUT)util/pmu-bison.c |
282 | $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/pmu-flex.h -t util/pmu.l > $(OUTPUT)util/pmu-flex.c | 302 | $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/pmu-flex.h -t util/pmu.l > $(OUTPUT)util/pmu-flex.c |
283 | 303 | ||
284 | $(OUTPUT)util/pmu-bison.c: util/pmu.y | 304 | $(OUTPUT)util/pmu-bison.c: util/pmu.y |
285 | $(QUIET_BISON)$(BISON) -v util/pmu.y -d -o $(OUTPUT)util/pmu-bison.c | 305 | $(QUIET_BISON)$(BISON) -v util/pmu.y -d -o $(OUTPUT)util/pmu-bison.c -p perf_pmu_ |
286 | 306 | ||
287 | $(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c | 307 | $(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c |
288 | $(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c | 308 | $(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c |
@@ -378,8 +398,11 @@ LIB_H += util/rblist.h | |||
378 | LIB_H += util/intlist.h | 398 | LIB_H += util/intlist.h |
379 | LIB_H += util/perf_regs.h | 399 | LIB_H += util/perf_regs.h |
380 | LIB_H += util/unwind.h | 400 | LIB_H += util/unwind.h |
381 | LIB_H += ui/helpline.h | ||
382 | LIB_H += util/vdso.h | 401 | LIB_H += util/vdso.h |
402 | LIB_H += ui/helpline.h | ||
403 | LIB_H += ui/progress.h | ||
404 | LIB_H += ui/util.h | ||
405 | LIB_H += ui/ui.h | ||
383 | 406 | ||
384 | LIB_OBJS += $(OUTPUT)util/abspath.o | 407 | LIB_OBJS += $(OUTPUT)util/abspath.o |
385 | LIB_OBJS += $(OUTPUT)util/alias.o | 408 | LIB_OBJS += $(OUTPUT)util/alias.o |
@@ -453,6 +476,7 @@ LIB_OBJS += $(OUTPUT)util/stat.o | |||
453 | LIB_OBJS += $(OUTPUT)ui/setup.o | 476 | LIB_OBJS += $(OUTPUT)ui/setup.o |
454 | LIB_OBJS += $(OUTPUT)ui/helpline.o | 477 | LIB_OBJS += $(OUTPUT)ui/helpline.o |
455 | LIB_OBJS += $(OUTPUT)ui/progress.o | 478 | LIB_OBJS += $(OUTPUT)ui/progress.o |
479 | LIB_OBJS += $(OUTPUT)ui/util.o | ||
456 | LIB_OBJS += $(OUTPUT)ui/hist.o | 480 | LIB_OBJS += $(OUTPUT)ui/hist.o |
457 | LIB_OBJS += $(OUTPUT)ui/stdio/hist.o | 481 | LIB_OBJS += $(OUTPUT)ui/stdio/hist.o |
458 | 482 | ||
@@ -471,7 +495,8 @@ LIB_OBJS += $(OUTPUT)tests/rdpmc.o | |||
471 | LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o | 495 | LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o |
472 | LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o | 496 | LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o |
473 | LIB_OBJS += $(OUTPUT)tests/pmu.o | 497 | LIB_OBJS += $(OUTPUT)tests/pmu.o |
474 | LIB_OBJS += $(OUTPUT)tests/util.o | 498 | LIB_OBJS += $(OUTPUT)tests/hists_link.o |
499 | LIB_OBJS += $(OUTPUT)tests/python-use.o | ||
475 | 500 | ||
476 | BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o | 501 | BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o |
477 | BUILTIN_OBJS += $(OUTPUT)builtin-bench.o | 502 | BUILTIN_OBJS += $(OUTPUT)builtin-bench.o |
@@ -510,14 +535,13 @@ PERFLIBS = $(LIB_FILE) $(LIBTRACEEVENT) | |||
510 | # | 535 | # |
511 | # Platform specific tweaks | 536 | # Platform specific tweaks |
512 | # | 537 | # |
538 | ifneq ($(MAKECMDGOALS),clean) | ||
539 | ifneq ($(MAKECMDGOALS),tags) | ||
513 | 540 | ||
514 | # We choose to avoid "if .. else if .. else .. endif endif" | 541 | # We choose to avoid "if .. else if .. else .. endif endif" |
515 | # because maintaining the nesting to match is a pain. If | 542 | # because maintaining the nesting to match is a pain. If |
516 | # we had "elif" things would have been much nicer... | 543 | # we had "elif" things would have been much nicer... |
517 | 544 | ||
518 | -include config.mak.autogen | ||
519 | -include config.mak | ||
520 | |||
521 | ifdef NO_LIBELF | 545 | ifdef NO_LIBELF |
522 | NO_DWARF := 1 | 546 | NO_DWARF := 1 |
523 | NO_DEMANGLE := 1 | 547 | NO_DEMANGLE := 1 |
@@ -557,6 +581,11 @@ else | |||
557 | endif # SOURCE_LIBELF | 581 | endif # SOURCE_LIBELF |
558 | endif # NO_LIBELF | 582 | endif # NO_LIBELF |
559 | 583 | ||
584 | # There's only x86 (both 32 and 64) support for CFI unwind so far | ||
585 | ifneq ($(ARCH),x86) | ||
586 | NO_LIBUNWIND := 1 | ||
587 | endif | ||
588 | |||
560 | ifndef NO_LIBUNWIND | 589 | ifndef NO_LIBUNWIND |
561 | # for linking with debug library, run like: | 590 | # for linking with debug library, run like: |
562 | # make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/ | 591 | # make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/ |
@@ -646,7 +675,6 @@ ifndef NO_NEWT | |||
646 | LIB_OBJS += $(OUTPUT)ui/browsers/hists.o | 675 | LIB_OBJS += $(OUTPUT)ui/browsers/hists.o |
647 | LIB_OBJS += $(OUTPUT)ui/browsers/map.o | 676 | LIB_OBJS += $(OUTPUT)ui/browsers/map.o |
648 | LIB_OBJS += $(OUTPUT)ui/browsers/scripts.o | 677 | LIB_OBJS += $(OUTPUT)ui/browsers/scripts.o |
649 | LIB_OBJS += $(OUTPUT)ui/util.o | ||
650 | LIB_OBJS += $(OUTPUT)ui/tui/setup.o | 678 | LIB_OBJS += $(OUTPUT)ui/tui/setup.o |
651 | LIB_OBJS += $(OUTPUT)ui/tui/util.o | 679 | LIB_OBJS += $(OUTPUT)ui/tui/util.o |
652 | LIB_OBJS += $(OUTPUT)ui/tui/helpline.o | 680 | LIB_OBJS += $(OUTPUT)ui/tui/helpline.o |
@@ -655,9 +683,6 @@ ifndef NO_NEWT | |||
655 | LIB_H += ui/browsers/map.h | 683 | LIB_H += ui/browsers/map.h |
656 | LIB_H += ui/keysyms.h | 684 | LIB_H += ui/keysyms.h |
657 | LIB_H += ui/libslang.h | 685 | LIB_H += ui/libslang.h |
658 | LIB_H += ui/progress.h | ||
659 | LIB_H += ui/util.h | ||
660 | LIB_H += ui/ui.h | ||
661 | endif | 686 | endif |
662 | endif | 687 | endif |
663 | 688 | ||
@@ -673,14 +698,12 @@ ifndef NO_GTK2 | |||
673 | BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null) | 698 | BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null) |
674 | EXTLIBS += $(shell pkg-config --libs gtk+-2.0 2>/dev/null) | 699 | EXTLIBS += $(shell pkg-config --libs gtk+-2.0 2>/dev/null) |
675 | LIB_OBJS += $(OUTPUT)ui/gtk/browser.o | 700 | LIB_OBJS += $(OUTPUT)ui/gtk/browser.o |
701 | LIB_OBJS += $(OUTPUT)ui/gtk/hists.o | ||
676 | LIB_OBJS += $(OUTPUT)ui/gtk/setup.o | 702 | LIB_OBJS += $(OUTPUT)ui/gtk/setup.o |
677 | LIB_OBJS += $(OUTPUT)ui/gtk/util.o | 703 | LIB_OBJS += $(OUTPUT)ui/gtk/util.o |
678 | LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o | 704 | LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o |
679 | LIB_OBJS += $(OUTPUT)ui/gtk/progress.o | 705 | LIB_OBJS += $(OUTPUT)ui/gtk/progress.o |
680 | # Make sure that it'd be included only once. | 706 | LIB_OBJS += $(OUTPUT)ui/gtk/annotate.o |
681 | ifeq ($(findstring -DNEWT_SUPPORT,$(BASIC_CFLAGS)),) | ||
682 | LIB_OBJS += $(OUTPUT)ui/util.o | ||
683 | endif | ||
684 | endif | 707 | endif |
685 | endif | 708 | endif |
686 | 709 | ||
@@ -707,7 +730,7 @@ disable-python = $(eval $(disable-python_code)) | |||
707 | define disable-python_code | 730 | define disable-python_code |
708 | BASIC_CFLAGS += -DNO_LIBPYTHON | 731 | BASIC_CFLAGS += -DNO_LIBPYTHON |
709 | $(if $(1),$(warning No $(1) was found)) | 732 | $(if $(1),$(warning No $(1) was found)) |
710 | $(warning Python support won't be built) | 733 | $(warning Python support will not be built) |
711 | endef | 734 | endef |
712 | 735 | ||
713 | override PYTHON := \ | 736 | override PYTHON := \ |
@@ -715,19 +738,10 @@ override PYTHON := \ | |||
715 | 738 | ||
716 | ifndef PYTHON | 739 | ifndef PYTHON |
717 | $(call disable-python,python interpreter) | 740 | $(call disable-python,python interpreter) |
718 | python-clean := | ||
719 | else | 741 | else |
720 | 742 | ||
721 | PYTHON_WORD := $(call shell-wordify,$(PYTHON)) | 743 | PYTHON_WORD := $(call shell-wordify,$(PYTHON)) |
722 | 744 | ||
723 | # python extension build directories | ||
724 | PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/ | ||
725 | PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/ | ||
726 | PYTHON_EXTBUILD_TMP := $(PYTHON_EXTBUILD)tmp/ | ||
727 | export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP | ||
728 | |||
729 | python-clean := rm -rf $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so | ||
730 | |||
731 | ifdef NO_LIBPYTHON | 745 | ifdef NO_LIBPYTHON |
732 | $(call disable-python) | 746 | $(call disable-python) |
733 | else | 747 | else |
@@ -839,10 +853,24 @@ ifndef NO_BACKTRACE | |||
839 | endif | 853 | endif |
840 | endif | 854 | endif |
841 | 855 | ||
856 | ifndef NO_LIBNUMA | ||
857 | FLAGS_LIBNUMA = $(ALL_CFLAGS) $(ALL_LDFLAGS) -lnuma | ||
858 | ifneq ($(call try-cc,$(SOURCE_LIBNUMA),$(FLAGS_LIBNUMA),libnuma),y) | ||
859 | msg := $(warning No numa.h found, disables 'perf bench numa mem' benchmark, please install numa-libs-devel or libnuma-dev); | ||
860 | else | ||
861 | BASIC_CFLAGS += -DLIBNUMA_SUPPORT | ||
862 | BUILTIN_OBJS += $(OUTPUT)bench/numa.o | ||
863 | EXTLIBS += -lnuma | ||
864 | endif | ||
865 | endif | ||
866 | |||
842 | ifdef ASCIIDOC8 | 867 | ifdef ASCIIDOC8 |
843 | export ASCIIDOC8 | 868 | export ASCIIDOC8 |
844 | endif | 869 | endif |
845 | 870 | ||
871 | endif # MAKECMDGOALS != tags | ||
872 | endif # MAKECMDGOALS != clean | ||
873 | |||
846 | # Shell quote (do not use $(call) to accommodate ancient setups); | 874 | # Shell quote (do not use $(call) to accommodate ancient setups); |
847 | 875 | ||
848 | ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG)) | 876 | ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG)) |
@@ -884,7 +912,7 @@ strip: $(PROGRAMS) $(OUTPUT)perf | |||
884 | $(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf | 912 | $(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf |
885 | 913 | ||
886 | $(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS | 914 | $(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS |
887 | $(QUIET_CC)$(CC) -DPERF_VERSION='"$(PERF_VERSION)"' \ | 915 | $(QUIET_CC)$(CC) -include $(OUTPUT)PERF-VERSION-FILE \ |
888 | '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ | 916 | '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ |
889 | $(ALL_CFLAGS) -c $(filter %.c,$^) -o $@ | 917 | $(ALL_CFLAGS) -c $(filter %.c,$^) -o $@ |
890 | 918 | ||
@@ -948,7 +976,13 @@ $(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS | |||
948 | 976 | ||
949 | $(OUTPUT)tests/attr.o: tests/attr.c $(OUTPUT)PERF-CFLAGS | 977 | $(OUTPUT)tests/attr.o: tests/attr.c $(OUTPUT)PERF-CFLAGS |
950 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \ | 978 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \ |
951 | '-DBINDIR="$(bindir_SQ)"' \ | 979 | '-DBINDIR="$(bindir_SQ)"' -DPYTHON='"$(PYTHON_WORD)"' \ |
980 | $< | ||
981 | |||
982 | $(OUTPUT)tests/python-use.o: tests/python-use.c $(OUTPUT)PERF-CFLAGS | ||
983 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \ | ||
984 | -DPYTHONPATH='"$(OUTPUT)python"' \ | ||
985 | -DPYTHON='"$(PYTHON_WORD)"' \ | ||
952 | $< | 986 | $< |
953 | 987 | ||
954 | $(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS | 988 | $(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS |
@@ -1099,7 +1133,7 @@ perfexec_instdir = $(prefix)/$(perfexecdir) | |||
1099 | endif | 1133 | endif |
1100 | perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir)) | 1134 | perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir)) |
1101 | 1135 | ||
1102 | install: all try-install-man | 1136 | install-bin: all |
1103 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' | 1137 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' |
1104 | $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)' | 1138 | $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)' |
1105 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' | 1139 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' |
@@ -1120,6 +1154,8 @@ install: all try-install-man | |||
1120 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr' | 1154 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr' |
1121 | $(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr' | 1155 | $(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr' |
1122 | 1156 | ||
1157 | install: install-bin try-install-man | ||
1158 | |||
1123 | install-python_ext: | 1159 | install-python_ext: |
1124 | $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)' | 1160 | $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)' |
1125 | 1161 | ||
diff --git a/tools/perf/arch/common.c b/tools/perf/arch/common.c index 3e975cb6232e..aacef07ebf31 100644 --- a/tools/perf/arch/common.c +++ b/tools/perf/arch/common.c | |||
@@ -155,6 +155,7 @@ static int perf_session_env__lookup_binutils_path(struct perf_session_env *env, | |||
155 | if (lookup_path(buf)) | 155 | if (lookup_path(buf)) |
156 | goto out; | 156 | goto out; |
157 | free(buf); | 157 | free(buf); |
158 | buf = NULL; | ||
158 | } | 159 | } |
159 | 160 | ||
160 | if (!strcmp(arch, "arm")) | 161 | if (!strcmp(arch, "arm")) |
diff --git a/tools/perf/bench/bench.h b/tools/perf/bench/bench.h index 8f89998eeaf4..a5223e6a7b43 100644 --- a/tools/perf/bench/bench.h +++ b/tools/perf/bench/bench.h | |||
@@ -1,6 +1,7 @@ | |||
1 | #ifndef BENCH_H | 1 | #ifndef BENCH_H |
2 | #define BENCH_H | 2 | #define BENCH_H |
3 | 3 | ||
4 | extern int bench_numa(int argc, const char **argv, const char *prefix); | ||
4 | extern int bench_sched_messaging(int argc, const char **argv, const char *prefix); | 5 | extern int bench_sched_messaging(int argc, const char **argv, const char *prefix); |
5 | extern int bench_sched_pipe(int argc, const char **argv, const char *prefix); | 6 | extern int bench_sched_pipe(int argc, const char **argv, const char *prefix); |
6 | extern int bench_mem_memcpy(int argc, const char **argv, | 7 | extern int bench_mem_memcpy(int argc, const char **argv, |
diff --git a/tools/perf/bench/numa.c b/tools/perf/bench/numa.c new file mode 100644 index 000000000000..30d1c3225b46 --- /dev/null +++ b/tools/perf/bench/numa.c | |||
@@ -0,0 +1,1731 @@ | |||
1 | /* | ||
2 | * numa.c | ||
3 | * | ||
4 | * numa: Simulate NUMA-sensitive workload and measure their NUMA performance | ||
5 | */ | ||
6 | |||
7 | #include "../perf.h" | ||
8 | #include "../builtin.h" | ||
9 | #include "../util/util.h" | ||
10 | #include "../util/parse-options.h" | ||
11 | |||
12 | #include "bench.h" | ||
13 | |||
14 | #include <errno.h> | ||
15 | #include <sched.h> | ||
16 | #include <stdio.h> | ||
17 | #include <assert.h> | ||
18 | #include <malloc.h> | ||
19 | #include <signal.h> | ||
20 | #include <stdlib.h> | ||
21 | #include <string.h> | ||
22 | #include <unistd.h> | ||
23 | #include <pthread.h> | ||
24 | #include <sys/mman.h> | ||
25 | #include <sys/time.h> | ||
26 | #include <sys/wait.h> | ||
27 | #include <sys/prctl.h> | ||
28 | #include <sys/types.h> | ||
29 | |||
30 | #include <numa.h> | ||
31 | #include <numaif.h> | ||
32 | |||
33 | /* | ||
34 | * Regular printout to the terminal, supressed if -q is specified: | ||
35 | */ | ||
36 | #define tprintf(x...) do { if (g && g->p.show_details >= 0) printf(x); } while (0) | ||
37 | |||
38 | /* | ||
39 | * Debug printf: | ||
40 | */ | ||
41 | #define dprintf(x...) do { if (g && g->p.show_details >= 1) printf(x); } while (0) | ||
42 | |||
43 | struct thread_data { | ||
44 | int curr_cpu; | ||
45 | cpu_set_t bind_cpumask; | ||
46 | int bind_node; | ||
47 | u8 *process_data; | ||
48 | int process_nr; | ||
49 | int thread_nr; | ||
50 | int task_nr; | ||
51 | unsigned int loops_done; | ||
52 | u64 val; | ||
53 | u64 runtime_ns; | ||
54 | pthread_mutex_t *process_lock; | ||
55 | }; | ||
56 | |||
57 | /* Parameters set by options: */ | ||
58 | |||
59 | struct params { | ||
60 | /* Startup synchronization: */ | ||
61 | bool serialize_startup; | ||
62 | |||
63 | /* Task hierarchy: */ | ||
64 | int nr_proc; | ||
65 | int nr_threads; | ||
66 | |||
67 | /* Working set sizes: */ | ||
68 | const char *mb_global_str; | ||
69 | const char *mb_proc_str; | ||
70 | const char *mb_proc_locked_str; | ||
71 | const char *mb_thread_str; | ||
72 | |||
73 | double mb_global; | ||
74 | double mb_proc; | ||
75 | double mb_proc_locked; | ||
76 | double mb_thread; | ||
77 | |||
78 | /* Access patterns to the working set: */ | ||
79 | bool data_reads; | ||
80 | bool data_writes; | ||
81 | bool data_backwards; | ||
82 | bool data_zero_memset; | ||
83 | bool data_rand_walk; | ||
84 | u32 nr_loops; | ||
85 | u32 nr_secs; | ||
86 | u32 sleep_usecs; | ||
87 | |||
88 | /* Working set initialization: */ | ||
89 | bool init_zero; | ||
90 | bool init_random; | ||
91 | bool init_cpu0; | ||
92 | |||
93 | /* Misc options: */ | ||
94 | int show_details; | ||
95 | int run_all; | ||
96 | int thp; | ||
97 | |||
98 | long bytes_global; | ||
99 | long bytes_process; | ||
100 | long bytes_process_locked; | ||
101 | long bytes_thread; | ||
102 | |||
103 | int nr_tasks; | ||
104 | bool show_quiet; | ||
105 | |||
106 | bool show_convergence; | ||
107 | bool measure_convergence; | ||
108 | |||
109 | int perturb_secs; | ||
110 | int nr_cpus; | ||
111 | int nr_nodes; | ||
112 | |||
113 | /* Affinity options -C and -N: */ | ||
114 | char *cpu_list_str; | ||
115 | char *node_list_str; | ||
116 | }; | ||
117 | |||
118 | |||
119 | /* Global, read-writable area, accessible to all processes and threads: */ | ||
120 | |||
121 | struct global_info { | ||
122 | u8 *data; | ||
123 | |||
124 | pthread_mutex_t startup_mutex; | ||
125 | int nr_tasks_started; | ||
126 | |||
127 | pthread_mutex_t startup_done_mutex; | ||
128 | |||
129 | pthread_mutex_t start_work_mutex; | ||
130 | int nr_tasks_working; | ||
131 | |||
132 | pthread_mutex_t stop_work_mutex; | ||
133 | u64 bytes_done; | ||
134 | |||
135 | struct thread_data *threads; | ||
136 | |||
137 | /* Convergence latency measurement: */ | ||
138 | bool all_converged; | ||
139 | bool stop_work; | ||
140 | |||
141 | int print_once; | ||
142 | |||
143 | struct params p; | ||
144 | }; | ||
145 | |||
146 | static struct global_info *g = NULL; | ||
147 | |||
148 | static int parse_cpus_opt(const struct option *opt, const char *arg, int unset); | ||
149 | static int parse_nodes_opt(const struct option *opt, const char *arg, int unset); | ||
150 | |||
151 | struct params p0; | ||
152 | |||
153 | static const struct option options[] = { | ||
154 | OPT_INTEGER('p', "nr_proc" , &p0.nr_proc, "number of processes"), | ||
155 | OPT_INTEGER('t', "nr_threads" , &p0.nr_threads, "number of threads per process"), | ||
156 | |||
157 | OPT_STRING('G', "mb_global" , &p0.mb_global_str, "MB", "global memory (MBs)"), | ||
158 | OPT_STRING('P', "mb_proc" , &p0.mb_proc_str, "MB", "process memory (MBs)"), | ||
159 | OPT_STRING('L', "mb_proc_locked", &p0.mb_proc_locked_str,"MB", "process serialized/locked memory access (MBs), <= process_memory"), | ||
160 | OPT_STRING('T', "mb_thread" , &p0.mb_thread_str, "MB", "thread memory (MBs)"), | ||
161 | |||
162 | OPT_UINTEGER('l', "nr_loops" , &p0.nr_loops, "max number of loops to run"), | ||
163 | OPT_UINTEGER('s', "nr_secs" , &p0.nr_secs, "max number of seconds to run"), | ||
164 | OPT_UINTEGER('u', "usleep" , &p0.sleep_usecs, "usecs to sleep per loop iteration"), | ||
165 | |||
166 | OPT_BOOLEAN('R', "data_reads" , &p0.data_reads, "access the data via writes (can be mixed with -W)"), | ||
167 | OPT_BOOLEAN('W', "data_writes" , &p0.data_writes, "access the data via writes (can be mixed with -R)"), | ||
168 | OPT_BOOLEAN('B', "data_backwards", &p0.data_backwards, "access the data backwards as well"), | ||
169 | OPT_BOOLEAN('Z', "data_zero_memset", &p0.data_zero_memset,"access the data via glibc bzero only"), | ||
170 | OPT_BOOLEAN('r', "data_rand_walk", &p0.data_rand_walk, "access the data with random (32bit LFSR) walk"), | ||
171 | |||
172 | |||
173 | OPT_BOOLEAN('z', "init_zero" , &p0.init_zero, "bzero the initial allocations"), | ||
174 | OPT_BOOLEAN('I', "init_random" , &p0.init_random, "randomize the contents of the initial allocations"), | ||
175 | OPT_BOOLEAN('0', "init_cpu0" , &p0.init_cpu0, "do the initial allocations on CPU#0"), | ||
176 | OPT_INTEGER('x', "perturb_secs", &p0.perturb_secs, "perturb thread 0/0 every X secs, to test convergence stability"), | ||
177 | |||
178 | OPT_INCR ('d', "show_details" , &p0.show_details, "Show details"), | ||
179 | OPT_INCR ('a', "all" , &p0.run_all, "Run all tests in the suite"), | ||
180 | OPT_INTEGER('H', "thp" , &p0.thp, "MADV_NOHUGEPAGE < 0 < MADV_HUGEPAGE"), | ||
181 | OPT_BOOLEAN('c', "show_convergence", &p0.show_convergence, "show convergence details"), | ||
182 | OPT_BOOLEAN('m', "measure_convergence", &p0.measure_convergence, "measure convergence latency"), | ||
183 | OPT_BOOLEAN('q', "quiet" , &p0.show_quiet, "bzero the initial allocations"), | ||
184 | OPT_BOOLEAN('S', "serialize-startup", &p0.serialize_startup,"serialize thread startup"), | ||
185 | |||
186 | /* Special option string parsing callbacks: */ | ||
187 | OPT_CALLBACK('C', "cpus", NULL, "cpu[,cpu2,...cpuN]", | ||
188 | "bind the first N tasks to these specific cpus (the rest is unbound)", | ||
189 | parse_cpus_opt), | ||
190 | OPT_CALLBACK('M', "memnodes", NULL, "node[,node2,...nodeN]", | ||
191 | "bind the first N tasks to these specific memory nodes (the rest is unbound)", | ||
192 | parse_nodes_opt), | ||
193 | OPT_END() | ||
194 | }; | ||
195 | |||
196 | static const char * const bench_numa_usage[] = { | ||
197 | "perf bench numa <options>", | ||
198 | NULL | ||
199 | }; | ||
200 | |||
201 | static const char * const numa_usage[] = { | ||
202 | "perf bench numa mem [<options>]", | ||
203 | NULL | ||
204 | }; | ||
205 | |||
206 | static cpu_set_t bind_to_cpu(int target_cpu) | ||
207 | { | ||
208 | cpu_set_t orig_mask, mask; | ||
209 | int ret; | ||
210 | |||
211 | ret = sched_getaffinity(0, sizeof(orig_mask), &orig_mask); | ||
212 | BUG_ON(ret); | ||
213 | |||
214 | CPU_ZERO(&mask); | ||
215 | |||
216 | if (target_cpu == -1) { | ||
217 | int cpu; | ||
218 | |||
219 | for (cpu = 0; cpu < g->p.nr_cpus; cpu++) | ||
220 | CPU_SET(cpu, &mask); | ||
221 | } else { | ||
222 | BUG_ON(target_cpu < 0 || target_cpu >= g->p.nr_cpus); | ||
223 | CPU_SET(target_cpu, &mask); | ||
224 | } | ||
225 | |||
226 | ret = sched_setaffinity(0, sizeof(mask), &mask); | ||
227 | BUG_ON(ret); | ||
228 | |||
229 | return orig_mask; | ||
230 | } | ||
231 | |||
232 | static cpu_set_t bind_to_node(int target_node) | ||
233 | { | ||
234 | int cpus_per_node = g->p.nr_cpus/g->p.nr_nodes; | ||
235 | cpu_set_t orig_mask, mask; | ||
236 | int cpu; | ||
237 | int ret; | ||
238 | |||
239 | BUG_ON(cpus_per_node*g->p.nr_nodes != g->p.nr_cpus); | ||
240 | BUG_ON(!cpus_per_node); | ||
241 | |||
242 | ret = sched_getaffinity(0, sizeof(orig_mask), &orig_mask); | ||
243 | BUG_ON(ret); | ||
244 | |||
245 | CPU_ZERO(&mask); | ||
246 | |||
247 | if (target_node == -1) { | ||
248 | for (cpu = 0; cpu < g->p.nr_cpus; cpu++) | ||
249 | CPU_SET(cpu, &mask); | ||
250 | } else { | ||
251 | int cpu_start = (target_node + 0) * cpus_per_node; | ||
252 | int cpu_stop = (target_node + 1) * cpus_per_node; | ||
253 | |||
254 | BUG_ON(cpu_stop > g->p.nr_cpus); | ||
255 | |||
256 | for (cpu = cpu_start; cpu < cpu_stop; cpu++) | ||
257 | CPU_SET(cpu, &mask); | ||
258 | } | ||
259 | |||
260 | ret = sched_setaffinity(0, sizeof(mask), &mask); | ||
261 | BUG_ON(ret); | ||
262 | |||
263 | return orig_mask; | ||
264 | } | ||
265 | |||
266 | static void bind_to_cpumask(cpu_set_t mask) | ||
267 | { | ||
268 | int ret; | ||
269 | |||
270 | ret = sched_setaffinity(0, sizeof(mask), &mask); | ||
271 | BUG_ON(ret); | ||
272 | } | ||
273 | |||
274 | static void mempol_restore(void) | ||
275 | { | ||
276 | int ret; | ||
277 | |||
278 | ret = set_mempolicy(MPOL_DEFAULT, NULL, g->p.nr_nodes-1); | ||
279 | |||
280 | BUG_ON(ret); | ||
281 | } | ||
282 | |||
283 | static void bind_to_memnode(int node) | ||
284 | { | ||
285 | unsigned long nodemask; | ||
286 | int ret; | ||
287 | |||
288 | if (node == -1) | ||
289 | return; | ||
290 | |||
291 | BUG_ON(g->p.nr_nodes > (int)sizeof(nodemask)); | ||
292 | nodemask = 1L << node; | ||
293 | |||
294 | ret = set_mempolicy(MPOL_BIND, &nodemask, sizeof(nodemask)*8); | ||
295 | dprintf("binding to node %d, mask: %016lx => %d\n", node, nodemask, ret); | ||
296 | |||
297 | BUG_ON(ret); | ||
298 | } | ||
299 | |||
300 | #define HPSIZE (2*1024*1024) | ||
301 | |||
302 | #define set_taskname(fmt...) \ | ||
303 | do { \ | ||
304 | char name[20]; \ | ||
305 | \ | ||
306 | snprintf(name, 20, fmt); \ | ||
307 | prctl(PR_SET_NAME, name); \ | ||
308 | } while (0) | ||
309 | |||
310 | static u8 *alloc_data(ssize_t bytes0, int map_flags, | ||
311 | int init_zero, int init_cpu0, int thp, int init_random) | ||
312 | { | ||
313 | cpu_set_t orig_mask; | ||
314 | ssize_t bytes; | ||
315 | u8 *buf; | ||
316 | int ret; | ||
317 | |||
318 | if (!bytes0) | ||
319 | return NULL; | ||
320 | |||
321 | /* Allocate and initialize all memory on CPU#0: */ | ||
322 | if (init_cpu0) { | ||
323 | orig_mask = bind_to_node(0); | ||
324 | bind_to_memnode(0); | ||
325 | } | ||
326 | |||
327 | bytes = bytes0 + HPSIZE; | ||
328 | |||
329 | buf = (void *)mmap(0, bytes, PROT_READ|PROT_WRITE, MAP_ANON|map_flags, -1, 0); | ||
330 | BUG_ON(buf == (void *)-1); | ||
331 | |||
332 | if (map_flags == MAP_PRIVATE) { | ||
333 | if (thp > 0) { | ||
334 | ret = madvise(buf, bytes, MADV_HUGEPAGE); | ||
335 | if (ret && !g->print_once) { | ||
336 | g->print_once = 1; | ||
337 | printf("WARNING: Could not enable THP - do: 'echo madvise > /sys/kernel/mm/transparent_hugepage/enabled'\n"); | ||
338 | } | ||
339 | } | ||
340 | if (thp < 0) { | ||
341 | ret = madvise(buf, bytes, MADV_NOHUGEPAGE); | ||
342 | if (ret && !g->print_once) { | ||
343 | g->print_once = 1; | ||
344 | printf("WARNING: Could not disable THP: run a CONFIG_TRANSPARENT_HUGEPAGE kernel?\n"); | ||
345 | } | ||
346 | } | ||
347 | } | ||
348 | |||
349 | if (init_zero) { | ||
350 | bzero(buf, bytes); | ||
351 | } else { | ||
352 | /* Initialize random contents, different in each word: */ | ||
353 | if (init_random) { | ||
354 | u64 *wbuf = (void *)buf; | ||
355 | long off = rand(); | ||
356 | long i; | ||
357 | |||
358 | for (i = 0; i < bytes/8; i++) | ||
359 | wbuf[i] = i + off; | ||
360 | } | ||
361 | } | ||
362 | |||
363 | /* Align to 2MB boundary: */ | ||
364 | buf = (void *)(((unsigned long)buf + HPSIZE-1) & ~(HPSIZE-1)); | ||
365 | |||
366 | /* Restore affinity: */ | ||
367 | if (init_cpu0) { | ||
368 | bind_to_cpumask(orig_mask); | ||
369 | mempol_restore(); | ||
370 | } | ||
371 | |||
372 | return buf; | ||
373 | } | ||
374 | |||
375 | static void free_data(void *data, ssize_t bytes) | ||
376 | { | ||
377 | int ret; | ||
378 | |||
379 | if (!data) | ||
380 | return; | ||
381 | |||
382 | ret = munmap(data, bytes); | ||
383 | BUG_ON(ret); | ||
384 | } | ||
385 | |||
386 | /* | ||
387 | * Create a shared memory buffer that can be shared between processes, zeroed: | ||
388 | */ | ||
389 | static void * zalloc_shared_data(ssize_t bytes) | ||
390 | { | ||
391 | return alloc_data(bytes, MAP_SHARED, 1, g->p.init_cpu0, g->p.thp, g->p.init_random); | ||
392 | } | ||
393 | |||
394 | /* | ||
395 | * Create a shared memory buffer that can be shared between processes: | ||
396 | */ | ||
397 | static void * setup_shared_data(ssize_t bytes) | ||
398 | { | ||
399 | return alloc_data(bytes, MAP_SHARED, 0, g->p.init_cpu0, g->p.thp, g->p.init_random); | ||
400 | } | ||
401 | |||
402 | /* | ||
403 | * Allocate process-local memory - this will either be shared between | ||
404 | * threads of this process, or only be accessed by this thread: | ||
405 | */ | ||
406 | static void * setup_private_data(ssize_t bytes) | ||
407 | { | ||
408 | return alloc_data(bytes, MAP_PRIVATE, 0, g->p.init_cpu0, g->p.thp, g->p.init_random); | ||
409 | } | ||
410 | |||
411 | /* | ||
412 | * Return a process-shared (global) mutex: | ||
413 | */ | ||
414 | static void init_global_mutex(pthread_mutex_t *mutex) | ||
415 | { | ||
416 | pthread_mutexattr_t attr; | ||
417 | |||
418 | pthread_mutexattr_init(&attr); | ||
419 | pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED); | ||
420 | pthread_mutex_init(mutex, &attr); | ||
421 | } | ||
422 | |||
423 | static int parse_cpu_list(const char *arg) | ||
424 | { | ||
425 | p0.cpu_list_str = strdup(arg); | ||
426 | |||
427 | dprintf("got CPU list: {%s}\n", p0.cpu_list_str); | ||
428 | |||
429 | return 0; | ||
430 | } | ||
431 | |||
432 | static void parse_setup_cpu_list(void) | ||
433 | { | ||
434 | struct thread_data *td; | ||
435 | char *str0, *str; | ||
436 | int t; | ||
437 | |||
438 | if (!g->p.cpu_list_str) | ||
439 | return; | ||
440 | |||
441 | dprintf("g->p.nr_tasks: %d\n", g->p.nr_tasks); | ||
442 | |||
443 | str0 = str = strdup(g->p.cpu_list_str); | ||
444 | t = 0; | ||
445 | |||
446 | BUG_ON(!str); | ||
447 | |||
448 | tprintf("# binding tasks to CPUs:\n"); | ||
449 | tprintf("# "); | ||
450 | |||
451 | while (true) { | ||
452 | int bind_cpu, bind_cpu_0, bind_cpu_1; | ||
453 | char *tok, *tok_end, *tok_step, *tok_len, *tok_mul; | ||
454 | int bind_len; | ||
455 | int step; | ||
456 | int mul; | ||
457 | |||
458 | tok = strsep(&str, ","); | ||
459 | if (!tok) | ||
460 | break; | ||
461 | |||
462 | tok_end = strstr(tok, "-"); | ||
463 | |||
464 | dprintf("\ntoken: {%s}, end: {%s}\n", tok, tok_end); | ||
465 | if (!tok_end) { | ||
466 | /* Single CPU specified: */ | ||
467 | bind_cpu_0 = bind_cpu_1 = atol(tok); | ||
468 | } else { | ||
469 | /* CPU range specified (for example: "5-11"): */ | ||
470 | bind_cpu_0 = atol(tok); | ||
471 | bind_cpu_1 = atol(tok_end + 1); | ||
472 | } | ||
473 | |||
474 | step = 1; | ||
475 | tok_step = strstr(tok, "#"); | ||
476 | if (tok_step) { | ||
477 | step = atol(tok_step + 1); | ||
478 | BUG_ON(step <= 0 || step >= g->p.nr_cpus); | ||
479 | } | ||
480 | |||
481 | /* | ||
482 | * Mask length. | ||
483 | * Eg: "--cpus 8_4-16#4" means: '--cpus 8_4,12_4,16_4', | ||
484 | * where the _4 means the next 4 CPUs are allowed. | ||
485 | */ | ||
486 | bind_len = 1; | ||
487 | tok_len = strstr(tok, "_"); | ||
488 | if (tok_len) { | ||
489 | bind_len = atol(tok_len + 1); | ||
490 | BUG_ON(bind_len <= 0 || bind_len > g->p.nr_cpus); | ||
491 | } | ||
492 | |||
493 | /* Multiplicator shortcut, "0x8" is a shortcut for: "0,0,0,0,0,0,0,0" */ | ||
494 | mul = 1; | ||
495 | tok_mul = strstr(tok, "x"); | ||
496 | if (tok_mul) { | ||
497 | mul = atol(tok_mul + 1); | ||
498 | BUG_ON(mul <= 0); | ||
499 | } | ||
500 | |||
501 | dprintf("CPUs: %d_%d-%d#%dx%d\n", bind_cpu_0, bind_len, bind_cpu_1, step, mul); | ||
502 | |||
503 | BUG_ON(bind_cpu_0 < 0 || bind_cpu_0 >= g->p.nr_cpus); | ||
504 | BUG_ON(bind_cpu_1 < 0 || bind_cpu_1 >= g->p.nr_cpus); | ||
505 | BUG_ON(bind_cpu_0 > bind_cpu_1); | ||
506 | |||
507 | for (bind_cpu = bind_cpu_0; bind_cpu <= bind_cpu_1; bind_cpu += step) { | ||
508 | int i; | ||
509 | |||
510 | for (i = 0; i < mul; i++) { | ||
511 | int cpu; | ||
512 | |||
513 | if (t >= g->p.nr_tasks) { | ||
514 | printf("\n# NOTE: ignoring bind CPUs starting at CPU#%d\n #", bind_cpu); | ||
515 | goto out; | ||
516 | } | ||
517 | td = g->threads + t; | ||
518 | |||
519 | if (t) | ||
520 | tprintf(","); | ||
521 | if (bind_len > 1) { | ||
522 | tprintf("%2d/%d", bind_cpu, bind_len); | ||
523 | } else { | ||
524 | tprintf("%2d", bind_cpu); | ||
525 | } | ||
526 | |||
527 | CPU_ZERO(&td->bind_cpumask); | ||
528 | for (cpu = bind_cpu; cpu < bind_cpu+bind_len; cpu++) { | ||
529 | BUG_ON(cpu < 0 || cpu >= g->p.nr_cpus); | ||
530 | CPU_SET(cpu, &td->bind_cpumask); | ||
531 | } | ||
532 | t++; | ||
533 | } | ||
534 | } | ||
535 | } | ||
536 | out: | ||
537 | |||
538 | tprintf("\n"); | ||
539 | |||
540 | if (t < g->p.nr_tasks) | ||
541 | printf("# NOTE: %d tasks bound, %d tasks unbound\n", t, g->p.nr_tasks - t); | ||
542 | |||
543 | free(str0); | ||
544 | } | ||
545 | |||
546 | static int parse_cpus_opt(const struct option *opt __maybe_unused, | ||
547 | const char *arg, int unset __maybe_unused) | ||
548 | { | ||
549 | if (!arg) | ||
550 | return -1; | ||
551 | |||
552 | return parse_cpu_list(arg); | ||
553 | } | ||
554 | |||
555 | static int parse_node_list(const char *arg) | ||
556 | { | ||
557 | p0.node_list_str = strdup(arg); | ||
558 | |||
559 | dprintf("got NODE list: {%s}\n", p0.node_list_str); | ||
560 | |||
561 | return 0; | ||
562 | } | ||
563 | |||
564 | static void parse_setup_node_list(void) | ||
565 | { | ||
566 | struct thread_data *td; | ||
567 | char *str0, *str; | ||
568 | int t; | ||
569 | |||
570 | if (!g->p.node_list_str) | ||
571 | return; | ||
572 | |||
573 | dprintf("g->p.nr_tasks: %d\n", g->p.nr_tasks); | ||
574 | |||
575 | str0 = str = strdup(g->p.node_list_str); | ||
576 | t = 0; | ||
577 | |||
578 | BUG_ON(!str); | ||
579 | |||
580 | tprintf("# binding tasks to NODEs:\n"); | ||
581 | tprintf("# "); | ||
582 | |||
583 | while (true) { | ||
584 | int bind_node, bind_node_0, bind_node_1; | ||
585 | char *tok, *tok_end, *tok_step, *tok_mul; | ||
586 | int step; | ||
587 | int mul; | ||
588 | |||
589 | tok = strsep(&str, ","); | ||
590 | if (!tok) | ||
591 | break; | ||
592 | |||
593 | tok_end = strstr(tok, "-"); | ||
594 | |||
595 | dprintf("\ntoken: {%s}, end: {%s}\n", tok, tok_end); | ||
596 | if (!tok_end) { | ||
597 | /* Single NODE specified: */ | ||
598 | bind_node_0 = bind_node_1 = atol(tok); | ||
599 | } else { | ||
600 | /* NODE range specified (for example: "5-11"): */ | ||
601 | bind_node_0 = atol(tok); | ||
602 | bind_node_1 = atol(tok_end + 1); | ||
603 | } | ||
604 | |||
605 | step = 1; | ||
606 | tok_step = strstr(tok, "#"); | ||
607 | if (tok_step) { | ||
608 | step = atol(tok_step + 1); | ||
609 | BUG_ON(step <= 0 || step >= g->p.nr_nodes); | ||
610 | } | ||
611 | |||
612 | /* Multiplicator shortcut, "0x8" is a shortcut for: "0,0,0,0,0,0,0,0" */ | ||
613 | mul = 1; | ||
614 | tok_mul = strstr(tok, "x"); | ||
615 | if (tok_mul) { | ||
616 | mul = atol(tok_mul + 1); | ||
617 | BUG_ON(mul <= 0); | ||
618 | } | ||
619 | |||
620 | dprintf("NODEs: %d-%d #%d\n", bind_node_0, bind_node_1, step); | ||
621 | |||
622 | BUG_ON(bind_node_0 < 0 || bind_node_0 >= g->p.nr_nodes); | ||
623 | BUG_ON(bind_node_1 < 0 || bind_node_1 >= g->p.nr_nodes); | ||
624 | BUG_ON(bind_node_0 > bind_node_1); | ||
625 | |||
626 | for (bind_node = bind_node_0; bind_node <= bind_node_1; bind_node += step) { | ||
627 | int i; | ||
628 | |||
629 | for (i = 0; i < mul; i++) { | ||
630 | if (t >= g->p.nr_tasks) { | ||
631 | printf("\n# NOTE: ignoring bind NODEs starting at NODE#%d\n", bind_node); | ||
632 | goto out; | ||
633 | } | ||
634 | td = g->threads + t; | ||
635 | |||
636 | if (!t) | ||
637 | tprintf(" %2d", bind_node); | ||
638 | else | ||
639 | tprintf(",%2d", bind_node); | ||
640 | |||
641 | td->bind_node = bind_node; | ||
642 | t++; | ||
643 | } | ||
644 | } | ||
645 | } | ||
646 | out: | ||
647 | |||
648 | tprintf("\n"); | ||
649 | |||
650 | if (t < g->p.nr_tasks) | ||
651 | printf("# NOTE: %d tasks mem-bound, %d tasks unbound\n", t, g->p.nr_tasks - t); | ||
652 | |||
653 | free(str0); | ||
654 | } | ||
655 | |||
656 | static int parse_nodes_opt(const struct option *opt __maybe_unused, | ||
657 | const char *arg, int unset __maybe_unused) | ||
658 | { | ||
659 | if (!arg) | ||
660 | return -1; | ||
661 | |||
662 | return parse_node_list(arg); | ||
663 | |||
664 | return 0; | ||
665 | } | ||
666 | |||
667 | #define BIT(x) (1ul << x) | ||
668 | |||
669 | static inline uint32_t lfsr_32(uint32_t lfsr) | ||
670 | { | ||
671 | const uint32_t taps = BIT(1) | BIT(5) | BIT(6) | BIT(31); | ||
672 | return (lfsr>>1) ^ ((0x0u - (lfsr & 0x1u)) & taps); | ||
673 | } | ||
674 | |||
675 | /* | ||
676 | * Make sure there's real data dependency to RAM (when read | ||
677 | * accesses are enabled), so the compiler, the CPU and the | ||
678 | * kernel (KSM, zero page, etc.) cannot optimize away RAM | ||
679 | * accesses: | ||
680 | */ | ||
681 | static inline u64 access_data(u64 *data __attribute__((unused)), u64 val) | ||
682 | { | ||
683 | if (g->p.data_reads) | ||
684 | val += *data; | ||
685 | if (g->p.data_writes) | ||
686 | *data = val + 1; | ||
687 | return val; | ||
688 | } | ||
689 | |||
690 | /* | ||
691 | * The worker process does two types of work, a forwards going | ||
692 | * loop and a backwards going loop. | ||
693 | * | ||
694 | * We do this so that on multiprocessor systems we do not create | ||
695 | * a 'train' of processing, with highly synchronized processes, | ||
696 | * skewing the whole benchmark. | ||
697 | */ | ||
698 | static u64 do_work(u8 *__data, long bytes, int nr, int nr_max, int loop, u64 val) | ||
699 | { | ||
700 | long words = bytes/sizeof(u64); | ||
701 | u64 *data = (void *)__data; | ||
702 | long chunk_0, chunk_1; | ||
703 | u64 *d0, *d, *d1; | ||
704 | long off; | ||
705 | long i; | ||
706 | |||
707 | BUG_ON(!data && words); | ||
708 | BUG_ON(data && !words); | ||
709 | |||
710 | if (!data) | ||
711 | return val; | ||
712 | |||
713 | /* Very simple memset() work variant: */ | ||
714 | if (g->p.data_zero_memset && !g->p.data_rand_walk) { | ||
715 | bzero(data, bytes); | ||
716 | return val; | ||
717 | } | ||
718 | |||
719 | /* Spread out by PID/TID nr and by loop nr: */ | ||
720 | chunk_0 = words/nr_max; | ||
721 | chunk_1 = words/g->p.nr_loops; | ||
722 | off = nr*chunk_0 + loop*chunk_1; | ||
723 | |||
724 | while (off >= words) | ||
725 | off -= words; | ||
726 | |||
727 | if (g->p.data_rand_walk) { | ||
728 | u32 lfsr = nr + loop + val; | ||
729 | int j; | ||
730 | |||
731 | for (i = 0; i < words/1024; i++) { | ||
732 | long start, end; | ||
733 | |||
734 | lfsr = lfsr_32(lfsr); | ||
735 | |||
736 | start = lfsr % words; | ||
737 | end = min(start + 1024, words-1); | ||
738 | |||
739 | if (g->p.data_zero_memset) { | ||
740 | bzero(data + start, (end-start) * sizeof(u64)); | ||
741 | } else { | ||
742 | for (j = start; j < end; j++) | ||
743 | val = access_data(data + j, val); | ||
744 | } | ||
745 | } | ||
746 | } else if (!g->p.data_backwards || (nr + loop) & 1) { | ||
747 | |||
748 | d0 = data + off; | ||
749 | d = data + off + 1; | ||
750 | d1 = data + words; | ||
751 | |||
752 | /* Process data forwards: */ | ||
753 | for (;;) { | ||
754 | if (unlikely(d >= d1)) | ||
755 | d = data; | ||
756 | if (unlikely(d == d0)) | ||
757 | break; | ||
758 | |||
759 | val = access_data(d, val); | ||
760 | |||
761 | d++; | ||
762 | } | ||
763 | } else { | ||
764 | /* Process data backwards: */ | ||
765 | |||
766 | d0 = data + off; | ||
767 | d = data + off - 1; | ||
768 | d1 = data + words; | ||
769 | |||
770 | /* Process data forwards: */ | ||
771 | for (;;) { | ||
772 | if (unlikely(d < data)) | ||
773 | d = data + words-1; | ||
774 | if (unlikely(d == d0)) | ||
775 | break; | ||
776 | |||
777 | val = access_data(d, val); | ||
778 | |||
779 | d--; | ||
780 | } | ||
781 | } | ||
782 | |||
783 | return val; | ||
784 | } | ||
785 | |||
786 | static void update_curr_cpu(int task_nr, unsigned long bytes_worked) | ||
787 | { | ||
788 | unsigned int cpu; | ||
789 | |||
790 | cpu = sched_getcpu(); | ||
791 | |||
792 | g->threads[task_nr].curr_cpu = cpu; | ||
793 | prctl(0, bytes_worked); | ||
794 | } | ||
795 | |||
796 | #define MAX_NR_NODES 64 | ||
797 | |||
798 | /* | ||
799 | * Count the number of nodes a process's threads | ||
800 | * are spread out on. | ||
801 | * | ||
802 | * A count of 1 means that the process is compressed | ||
803 | * to a single node. A count of g->p.nr_nodes means it's | ||
804 | * spread out on the whole system. | ||
805 | */ | ||
806 | static int count_process_nodes(int process_nr) | ||
807 | { | ||
808 | char node_present[MAX_NR_NODES] = { 0, }; | ||
809 | int nodes; | ||
810 | int n, t; | ||
811 | |||
812 | for (t = 0; t < g->p.nr_threads; t++) { | ||
813 | struct thread_data *td; | ||
814 | int task_nr; | ||
815 | int node; | ||
816 | |||
817 | task_nr = process_nr*g->p.nr_threads + t; | ||
818 | td = g->threads + task_nr; | ||
819 | |||
820 | node = numa_node_of_cpu(td->curr_cpu); | ||
821 | node_present[node] = 1; | ||
822 | } | ||
823 | |||
824 | nodes = 0; | ||
825 | |||
826 | for (n = 0; n < MAX_NR_NODES; n++) | ||
827 | nodes += node_present[n]; | ||
828 | |||
829 | return nodes; | ||
830 | } | ||
831 | |||
832 | /* | ||
833 | * Count the number of distinct process-threads a node contains. | ||
834 | * | ||
835 | * A count of 1 means that the node contains only a single | ||
836 | * process. If all nodes on the system contain at most one | ||
837 | * process then we are well-converged. | ||
838 | */ | ||
839 | static int count_node_processes(int node) | ||
840 | { | ||
841 | int processes = 0; | ||
842 | int t, p; | ||
843 | |||
844 | for (p = 0; p < g->p.nr_proc; p++) { | ||
845 | for (t = 0; t < g->p.nr_threads; t++) { | ||
846 | struct thread_data *td; | ||
847 | int task_nr; | ||
848 | int n; | ||
849 | |||
850 | task_nr = p*g->p.nr_threads + t; | ||
851 | td = g->threads + task_nr; | ||
852 | |||
853 | n = numa_node_of_cpu(td->curr_cpu); | ||
854 | if (n == node) { | ||
855 | processes++; | ||
856 | break; | ||
857 | } | ||
858 | } | ||
859 | } | ||
860 | |||
861 | return processes; | ||
862 | } | ||
863 | |||
864 | static void calc_convergence_compression(int *strong) | ||
865 | { | ||
866 | unsigned int nodes_min, nodes_max; | ||
867 | int p; | ||
868 | |||
869 | nodes_min = -1; | ||
870 | nodes_max = 0; | ||
871 | |||
872 | for (p = 0; p < g->p.nr_proc; p++) { | ||
873 | unsigned int nodes = count_process_nodes(p); | ||
874 | |||
875 | nodes_min = min(nodes, nodes_min); | ||
876 | nodes_max = max(nodes, nodes_max); | ||
877 | } | ||
878 | |||
879 | /* Strong convergence: all threads compress on a single node: */ | ||
880 | if (nodes_min == 1 && nodes_max == 1) { | ||
881 | *strong = 1; | ||
882 | } else { | ||
883 | *strong = 0; | ||
884 | tprintf(" {%d-%d}", nodes_min, nodes_max); | ||
885 | } | ||
886 | } | ||
887 | |||
888 | static void calc_convergence(double runtime_ns_max, double *convergence) | ||
889 | { | ||
890 | unsigned int loops_done_min, loops_done_max; | ||
891 | int process_groups; | ||
892 | int nodes[MAX_NR_NODES]; | ||
893 | int distance; | ||
894 | int nr_min; | ||
895 | int nr_max; | ||
896 | int strong; | ||
897 | int sum; | ||
898 | int nr; | ||
899 | int node; | ||
900 | int cpu; | ||
901 | int t; | ||
902 | |||
903 | if (!g->p.show_convergence && !g->p.measure_convergence) | ||
904 | return; | ||
905 | |||
906 | for (node = 0; node < g->p.nr_nodes; node++) | ||
907 | nodes[node] = 0; | ||
908 | |||
909 | loops_done_min = -1; | ||
910 | loops_done_max = 0; | ||
911 | |||
912 | for (t = 0; t < g->p.nr_tasks; t++) { | ||
913 | struct thread_data *td = g->threads + t; | ||
914 | unsigned int loops_done; | ||
915 | |||
916 | cpu = td->curr_cpu; | ||
917 | |||
918 | /* Not all threads have written it yet: */ | ||
919 | if (cpu < 0) | ||
920 | continue; | ||
921 | |||
922 | node = numa_node_of_cpu(cpu); | ||
923 | |||
924 | nodes[node]++; | ||
925 | |||
926 | loops_done = td->loops_done; | ||
927 | loops_done_min = min(loops_done, loops_done_min); | ||
928 | loops_done_max = max(loops_done, loops_done_max); | ||
929 | } | ||
930 | |||
931 | nr_max = 0; | ||
932 | nr_min = g->p.nr_tasks; | ||
933 | sum = 0; | ||
934 | |||
935 | for (node = 0; node < g->p.nr_nodes; node++) { | ||
936 | nr = nodes[node]; | ||
937 | nr_min = min(nr, nr_min); | ||
938 | nr_max = max(nr, nr_max); | ||
939 | sum += nr; | ||
940 | } | ||
941 | BUG_ON(nr_min > nr_max); | ||
942 | |||
943 | BUG_ON(sum > g->p.nr_tasks); | ||
944 | |||
945 | if (0 && (sum < g->p.nr_tasks)) | ||
946 | return; | ||
947 | |||
948 | /* | ||
949 | * Count the number of distinct process groups present | ||
950 | * on nodes - when we are converged this will decrease | ||
951 | * to g->p.nr_proc: | ||
952 | */ | ||
953 | process_groups = 0; | ||
954 | |||
955 | for (node = 0; node < g->p.nr_nodes; node++) { | ||
956 | int processes = count_node_processes(node); | ||
957 | |||
958 | nr = nodes[node]; | ||
959 | tprintf(" %2d/%-2d", nr, processes); | ||
960 | |||
961 | process_groups += processes; | ||
962 | } | ||
963 | |||
964 | distance = nr_max - nr_min; | ||
965 | |||
966 | tprintf(" [%2d/%-2d]", distance, process_groups); | ||
967 | |||
968 | tprintf(" l:%3d-%-3d (%3d)", | ||
969 | loops_done_min, loops_done_max, loops_done_max-loops_done_min); | ||
970 | |||
971 | if (loops_done_min && loops_done_max) { | ||
972 | double skew = 1.0 - (double)loops_done_min/loops_done_max; | ||
973 | |||
974 | tprintf(" [%4.1f%%]", skew * 100.0); | ||
975 | } | ||
976 | |||
977 | calc_convergence_compression(&strong); | ||
978 | |||
979 | if (strong && process_groups == g->p.nr_proc) { | ||
980 | if (!*convergence) { | ||
981 | *convergence = runtime_ns_max; | ||
982 | tprintf(" (%6.1fs converged)\n", *convergence/1e9); | ||
983 | if (g->p.measure_convergence) { | ||
984 | g->all_converged = true; | ||
985 | g->stop_work = true; | ||
986 | } | ||
987 | } | ||
988 | } else { | ||
989 | if (*convergence) { | ||
990 | tprintf(" (%6.1fs de-converged)", runtime_ns_max/1e9); | ||
991 | *convergence = 0; | ||
992 | } | ||
993 | tprintf("\n"); | ||
994 | } | ||
995 | } | ||
996 | |||
997 | static void show_summary(double runtime_ns_max, int l, double *convergence) | ||
998 | { | ||
999 | tprintf("\r # %5.1f%% [%.1f mins]", | ||
1000 | (double)(l+1)/g->p.nr_loops*100.0, runtime_ns_max/1e9 / 60.0); | ||
1001 | |||
1002 | calc_convergence(runtime_ns_max, convergence); | ||
1003 | |||
1004 | if (g->p.show_details >= 0) | ||
1005 | fflush(stdout); | ||
1006 | } | ||
1007 | |||
1008 | static void *worker_thread(void *__tdata) | ||
1009 | { | ||
1010 | struct thread_data *td = __tdata; | ||
1011 | struct timeval start0, start, stop, diff; | ||
1012 | int process_nr = td->process_nr; | ||
1013 | int thread_nr = td->thread_nr; | ||
1014 | unsigned long last_perturbance; | ||
1015 | int task_nr = td->task_nr; | ||
1016 | int details = g->p.show_details; | ||
1017 | int first_task, last_task; | ||
1018 | double convergence = 0; | ||
1019 | u64 val = td->val; | ||
1020 | double runtime_ns_max; | ||
1021 | u8 *global_data; | ||
1022 | u8 *process_data; | ||
1023 | u8 *thread_data; | ||
1024 | u64 bytes_done; | ||
1025 | long work_done; | ||
1026 | u32 l; | ||
1027 | |||
1028 | bind_to_cpumask(td->bind_cpumask); | ||
1029 | bind_to_memnode(td->bind_node); | ||
1030 | |||
1031 | set_taskname("thread %d/%d", process_nr, thread_nr); | ||
1032 | |||
1033 | global_data = g->data; | ||
1034 | process_data = td->process_data; | ||
1035 | thread_data = setup_private_data(g->p.bytes_thread); | ||
1036 | |||
1037 | bytes_done = 0; | ||
1038 | |||
1039 | last_task = 0; | ||
1040 | if (process_nr == g->p.nr_proc-1 && thread_nr == g->p.nr_threads-1) | ||
1041 | last_task = 1; | ||
1042 | |||
1043 | first_task = 0; | ||
1044 | if (process_nr == 0 && thread_nr == 0) | ||
1045 | first_task = 1; | ||
1046 | |||
1047 | if (details >= 2) { | ||
1048 | printf("# thread %2d / %2d global mem: %p, process mem: %p, thread mem: %p\n", | ||
1049 | process_nr, thread_nr, global_data, process_data, thread_data); | ||
1050 | } | ||
1051 | |||
1052 | if (g->p.serialize_startup) { | ||
1053 | pthread_mutex_lock(&g->startup_mutex); | ||
1054 | g->nr_tasks_started++; | ||
1055 | pthread_mutex_unlock(&g->startup_mutex); | ||
1056 | |||
1057 | /* Here we will wait for the main process to start us all at once: */ | ||
1058 | pthread_mutex_lock(&g->start_work_mutex); | ||
1059 | g->nr_tasks_working++; | ||
1060 | |||
1061 | /* Last one wake the main process: */ | ||
1062 | if (g->nr_tasks_working == g->p.nr_tasks) | ||
1063 | pthread_mutex_unlock(&g->startup_done_mutex); | ||
1064 | |||
1065 | pthread_mutex_unlock(&g->start_work_mutex); | ||
1066 | } | ||
1067 | |||
1068 | gettimeofday(&start0, NULL); | ||
1069 | |||
1070 | start = stop = start0; | ||
1071 | last_perturbance = start.tv_sec; | ||
1072 | |||
1073 | for (l = 0; l < g->p.nr_loops; l++) { | ||
1074 | start = stop; | ||
1075 | |||
1076 | if (g->stop_work) | ||
1077 | break; | ||
1078 | |||
1079 | val += do_work(global_data, g->p.bytes_global, process_nr, g->p.nr_proc, l, val); | ||
1080 | val += do_work(process_data, g->p.bytes_process, thread_nr, g->p.nr_threads, l, val); | ||
1081 | val += do_work(thread_data, g->p.bytes_thread, 0, 1, l, val); | ||
1082 | |||
1083 | if (g->p.sleep_usecs) { | ||
1084 | pthread_mutex_lock(td->process_lock); | ||
1085 | usleep(g->p.sleep_usecs); | ||
1086 | pthread_mutex_unlock(td->process_lock); | ||
1087 | } | ||
1088 | /* | ||
1089 | * Amount of work to be done under a process-global lock: | ||
1090 | */ | ||
1091 | if (g->p.bytes_process_locked) { | ||
1092 | pthread_mutex_lock(td->process_lock); | ||
1093 | val += do_work(process_data, g->p.bytes_process_locked, thread_nr, g->p.nr_threads, l, val); | ||
1094 | pthread_mutex_unlock(td->process_lock); | ||
1095 | } | ||
1096 | |||
1097 | work_done = g->p.bytes_global + g->p.bytes_process + | ||
1098 | g->p.bytes_process_locked + g->p.bytes_thread; | ||
1099 | |||
1100 | update_curr_cpu(task_nr, work_done); | ||
1101 | bytes_done += work_done; | ||
1102 | |||
1103 | if (details < 0 && !g->p.perturb_secs && !g->p.measure_convergence && !g->p.nr_secs) | ||
1104 | continue; | ||
1105 | |||
1106 | td->loops_done = l; | ||
1107 | |||
1108 | gettimeofday(&stop, NULL); | ||
1109 | |||
1110 | /* Check whether our max runtime timed out: */ | ||
1111 | if (g->p.nr_secs) { | ||
1112 | timersub(&stop, &start0, &diff); | ||
1113 | if (diff.tv_sec >= g->p.nr_secs) { | ||
1114 | g->stop_work = true; | ||
1115 | break; | ||
1116 | } | ||
1117 | } | ||
1118 | |||
1119 | /* Update the summary at most once per second: */ | ||
1120 | if (start.tv_sec == stop.tv_sec) | ||
1121 | continue; | ||
1122 | |||
1123 | /* | ||
1124 | * Perturb the first task's equilibrium every g->p.perturb_secs seconds, | ||
1125 | * by migrating to CPU#0: | ||
1126 | */ | ||
1127 | if (first_task && g->p.perturb_secs && (int)(stop.tv_sec - last_perturbance) >= g->p.perturb_secs) { | ||
1128 | cpu_set_t orig_mask; | ||
1129 | int target_cpu; | ||
1130 | int this_cpu; | ||
1131 | |||
1132 | last_perturbance = stop.tv_sec; | ||
1133 | |||
1134 | /* | ||
1135 | * Depending on where we are running, move into | ||
1136 | * the other half of the system, to create some | ||
1137 | * real disturbance: | ||
1138 | */ | ||
1139 | this_cpu = g->threads[task_nr].curr_cpu; | ||
1140 | if (this_cpu < g->p.nr_cpus/2) | ||
1141 | target_cpu = g->p.nr_cpus-1; | ||
1142 | else | ||
1143 | target_cpu = 0; | ||
1144 | |||
1145 | orig_mask = bind_to_cpu(target_cpu); | ||
1146 | |||
1147 | /* Here we are running on the target CPU already */ | ||
1148 | if (details >= 1) | ||
1149 | printf(" (injecting perturbalance, moved to CPU#%d)\n", target_cpu); | ||
1150 | |||
1151 | bind_to_cpumask(orig_mask); | ||
1152 | } | ||
1153 | |||
1154 | if (details >= 3) { | ||
1155 | timersub(&stop, &start, &diff); | ||
1156 | runtime_ns_max = diff.tv_sec * 1000000000; | ||
1157 | runtime_ns_max += diff.tv_usec * 1000; | ||
1158 | |||
1159 | if (details >= 0) { | ||
1160 | printf(" #%2d / %2d: %14.2lf nsecs/op [val: %016lx]\n", | ||
1161 | process_nr, thread_nr, runtime_ns_max / bytes_done, val); | ||
1162 | } | ||
1163 | fflush(stdout); | ||
1164 | } | ||
1165 | if (!last_task) | ||
1166 | continue; | ||
1167 | |||
1168 | timersub(&stop, &start0, &diff); | ||
1169 | runtime_ns_max = diff.tv_sec * 1000000000ULL; | ||
1170 | runtime_ns_max += diff.tv_usec * 1000ULL; | ||
1171 | |||
1172 | show_summary(runtime_ns_max, l, &convergence); | ||
1173 | } | ||
1174 | |||
1175 | gettimeofday(&stop, NULL); | ||
1176 | timersub(&stop, &start0, &diff); | ||
1177 | td->runtime_ns = diff.tv_sec * 1000000000ULL; | ||
1178 | td->runtime_ns += diff.tv_usec * 1000ULL; | ||
1179 | |||
1180 | free_data(thread_data, g->p.bytes_thread); | ||
1181 | |||
1182 | pthread_mutex_lock(&g->stop_work_mutex); | ||
1183 | g->bytes_done += bytes_done; | ||
1184 | pthread_mutex_unlock(&g->stop_work_mutex); | ||
1185 | |||
1186 | return NULL; | ||
1187 | } | ||
1188 | |||
1189 | /* | ||
1190 | * A worker process starts a couple of threads: | ||
1191 | */ | ||
1192 | static void worker_process(int process_nr) | ||
1193 | { | ||
1194 | pthread_mutex_t process_lock; | ||
1195 | struct thread_data *td; | ||
1196 | pthread_t *pthreads; | ||
1197 | u8 *process_data; | ||
1198 | int task_nr; | ||
1199 | int ret; | ||
1200 | int t; | ||
1201 | |||
1202 | pthread_mutex_init(&process_lock, NULL); | ||
1203 | set_taskname("process %d", process_nr); | ||
1204 | |||
1205 | /* | ||
1206 | * Pick up the memory policy and the CPU binding of our first thread, | ||
1207 | * so that we initialize memory accordingly: | ||
1208 | */ | ||
1209 | task_nr = process_nr*g->p.nr_threads; | ||
1210 | td = g->threads + task_nr; | ||
1211 | |||
1212 | bind_to_memnode(td->bind_node); | ||
1213 | bind_to_cpumask(td->bind_cpumask); | ||
1214 | |||
1215 | pthreads = zalloc(g->p.nr_threads * sizeof(pthread_t)); | ||
1216 | process_data = setup_private_data(g->p.bytes_process); | ||
1217 | |||
1218 | if (g->p.show_details >= 3) { | ||
1219 | printf(" # process %2d global mem: %p, process mem: %p\n", | ||
1220 | process_nr, g->data, process_data); | ||
1221 | } | ||
1222 | |||
1223 | for (t = 0; t < g->p.nr_threads; t++) { | ||
1224 | task_nr = process_nr*g->p.nr_threads + t; | ||
1225 | td = g->threads + task_nr; | ||
1226 | |||
1227 | td->process_data = process_data; | ||
1228 | td->process_nr = process_nr; | ||
1229 | td->thread_nr = t; | ||
1230 | td->task_nr = task_nr; | ||
1231 | td->val = rand(); | ||
1232 | td->curr_cpu = -1; | ||
1233 | td->process_lock = &process_lock; | ||
1234 | |||
1235 | ret = pthread_create(pthreads + t, NULL, worker_thread, td); | ||
1236 | BUG_ON(ret); | ||
1237 | } | ||
1238 | |||
1239 | for (t = 0; t < g->p.nr_threads; t++) { | ||
1240 | ret = pthread_join(pthreads[t], NULL); | ||
1241 | BUG_ON(ret); | ||
1242 | } | ||
1243 | |||
1244 | free_data(process_data, g->p.bytes_process); | ||
1245 | free(pthreads); | ||
1246 | } | ||
1247 | |||
1248 | static void print_summary(void) | ||
1249 | { | ||
1250 | if (g->p.show_details < 0) | ||
1251 | return; | ||
1252 | |||
1253 | printf("\n ###\n"); | ||
1254 | printf(" # %d %s will execute (on %d nodes, %d CPUs):\n", | ||
1255 | g->p.nr_tasks, g->p.nr_tasks == 1 ? "task" : "tasks", g->p.nr_nodes, g->p.nr_cpus); | ||
1256 | printf(" # %5dx %5ldMB global shared mem operations\n", | ||
1257 | g->p.nr_loops, g->p.bytes_global/1024/1024); | ||
1258 | printf(" # %5dx %5ldMB process shared mem operations\n", | ||
1259 | g->p.nr_loops, g->p.bytes_process/1024/1024); | ||
1260 | printf(" # %5dx %5ldMB thread local mem operations\n", | ||
1261 | g->p.nr_loops, g->p.bytes_thread/1024/1024); | ||
1262 | |||
1263 | printf(" ###\n"); | ||
1264 | |||
1265 | printf("\n ###\n"); fflush(stdout); | ||
1266 | } | ||
1267 | |||
1268 | static void init_thread_data(void) | ||
1269 | { | ||
1270 | ssize_t size = sizeof(*g->threads)*g->p.nr_tasks; | ||
1271 | int t; | ||
1272 | |||
1273 | g->threads = zalloc_shared_data(size); | ||
1274 | |||
1275 | for (t = 0; t < g->p.nr_tasks; t++) { | ||
1276 | struct thread_data *td = g->threads + t; | ||
1277 | int cpu; | ||
1278 | |||
1279 | /* Allow all nodes by default: */ | ||
1280 | td->bind_node = -1; | ||
1281 | |||
1282 | /* Allow all CPUs by default: */ | ||
1283 | CPU_ZERO(&td->bind_cpumask); | ||
1284 | for (cpu = 0; cpu < g->p.nr_cpus; cpu++) | ||
1285 | CPU_SET(cpu, &td->bind_cpumask); | ||
1286 | } | ||
1287 | } | ||
1288 | |||
1289 | static void deinit_thread_data(void) | ||
1290 | { | ||
1291 | ssize_t size = sizeof(*g->threads)*g->p.nr_tasks; | ||
1292 | |||
1293 | free_data(g->threads, size); | ||
1294 | } | ||
1295 | |||
1296 | static int init(void) | ||
1297 | { | ||
1298 | g = (void *)alloc_data(sizeof(*g), MAP_SHARED, 1, 0, 0 /* THP */, 0); | ||
1299 | |||
1300 | /* Copy over options: */ | ||
1301 | g->p = p0; | ||
1302 | |||
1303 | g->p.nr_cpus = numa_num_configured_cpus(); | ||
1304 | |||
1305 | g->p.nr_nodes = numa_max_node() + 1; | ||
1306 | |||
1307 | /* char array in count_process_nodes(): */ | ||
1308 | BUG_ON(g->p.nr_nodes > MAX_NR_NODES || g->p.nr_nodes < 0); | ||
1309 | |||
1310 | if (g->p.show_quiet && !g->p.show_details) | ||
1311 | g->p.show_details = -1; | ||
1312 | |||
1313 | /* Some memory should be specified: */ | ||
1314 | if (!g->p.mb_global_str && !g->p.mb_proc_str && !g->p.mb_thread_str) | ||
1315 | return -1; | ||
1316 | |||
1317 | if (g->p.mb_global_str) { | ||
1318 | g->p.mb_global = atof(g->p.mb_global_str); | ||
1319 | BUG_ON(g->p.mb_global < 0); | ||
1320 | } | ||
1321 | |||
1322 | if (g->p.mb_proc_str) { | ||
1323 | g->p.mb_proc = atof(g->p.mb_proc_str); | ||
1324 | BUG_ON(g->p.mb_proc < 0); | ||
1325 | } | ||
1326 | |||
1327 | if (g->p.mb_proc_locked_str) { | ||
1328 | g->p.mb_proc_locked = atof(g->p.mb_proc_locked_str); | ||
1329 | BUG_ON(g->p.mb_proc_locked < 0); | ||
1330 | BUG_ON(g->p.mb_proc_locked > g->p.mb_proc); | ||
1331 | } | ||
1332 | |||
1333 | if (g->p.mb_thread_str) { | ||
1334 | g->p.mb_thread = atof(g->p.mb_thread_str); | ||
1335 | BUG_ON(g->p.mb_thread < 0); | ||
1336 | } | ||
1337 | |||
1338 | BUG_ON(g->p.nr_threads <= 0); | ||
1339 | BUG_ON(g->p.nr_proc <= 0); | ||
1340 | |||
1341 | g->p.nr_tasks = g->p.nr_proc*g->p.nr_threads; | ||
1342 | |||
1343 | g->p.bytes_global = g->p.mb_global *1024L*1024L; | ||
1344 | g->p.bytes_process = g->p.mb_proc *1024L*1024L; | ||
1345 | g->p.bytes_process_locked = g->p.mb_proc_locked *1024L*1024L; | ||
1346 | g->p.bytes_thread = g->p.mb_thread *1024L*1024L; | ||
1347 | |||
1348 | g->data = setup_shared_data(g->p.bytes_global); | ||
1349 | |||
1350 | /* Startup serialization: */ | ||
1351 | init_global_mutex(&g->start_work_mutex); | ||
1352 | init_global_mutex(&g->startup_mutex); | ||
1353 | init_global_mutex(&g->startup_done_mutex); | ||
1354 | init_global_mutex(&g->stop_work_mutex); | ||
1355 | |||
1356 | init_thread_data(); | ||
1357 | |||
1358 | tprintf("#\n"); | ||
1359 | parse_setup_cpu_list(); | ||
1360 | parse_setup_node_list(); | ||
1361 | tprintf("#\n"); | ||
1362 | |||
1363 | print_summary(); | ||
1364 | |||
1365 | return 0; | ||
1366 | } | ||
1367 | |||
1368 | static void deinit(void) | ||
1369 | { | ||
1370 | free_data(g->data, g->p.bytes_global); | ||
1371 | g->data = NULL; | ||
1372 | |||
1373 | deinit_thread_data(); | ||
1374 | |||
1375 | free_data(g, sizeof(*g)); | ||
1376 | g = NULL; | ||
1377 | } | ||
1378 | |||
1379 | /* | ||
1380 | * Print a short or long result, depending on the verbosity setting: | ||
1381 | */ | ||
1382 | static void print_res(const char *name, double val, | ||
1383 | const char *txt_unit, const char *txt_short, const char *txt_long) | ||
1384 | { | ||
1385 | if (!name) | ||
1386 | name = "main,"; | ||
1387 | |||
1388 | if (g->p.show_quiet) | ||
1389 | printf(" %-30s %15.3f, %-15s %s\n", name, val, txt_unit, txt_short); | ||
1390 | else | ||
1391 | printf(" %14.3f %s\n", val, txt_long); | ||
1392 | } | ||
1393 | |||
1394 | static int __bench_numa(const char *name) | ||
1395 | { | ||
1396 | struct timeval start, stop, diff; | ||
1397 | u64 runtime_ns_min, runtime_ns_sum; | ||
1398 | pid_t *pids, pid, wpid; | ||
1399 | double delta_runtime; | ||
1400 | double runtime_avg; | ||
1401 | double runtime_sec_max; | ||
1402 | double runtime_sec_min; | ||
1403 | int wait_stat; | ||
1404 | double bytes; | ||
1405 | int i, t; | ||
1406 | |||
1407 | if (init()) | ||
1408 | return -1; | ||
1409 | |||
1410 | pids = zalloc(g->p.nr_proc * sizeof(*pids)); | ||
1411 | pid = -1; | ||
1412 | |||
1413 | /* All threads try to acquire it, this way we can wait for them to start up: */ | ||
1414 | pthread_mutex_lock(&g->start_work_mutex); | ||
1415 | |||
1416 | if (g->p.serialize_startup) { | ||
1417 | tprintf(" #\n"); | ||
1418 | tprintf(" # Startup synchronization: ..."); fflush(stdout); | ||
1419 | } | ||
1420 | |||
1421 | gettimeofday(&start, NULL); | ||
1422 | |||
1423 | for (i = 0; i < g->p.nr_proc; i++) { | ||
1424 | pid = fork(); | ||
1425 | dprintf(" # process %2d: PID %d\n", i, pid); | ||
1426 | |||
1427 | BUG_ON(pid < 0); | ||
1428 | if (!pid) { | ||
1429 | /* Child process: */ | ||
1430 | worker_process(i); | ||
1431 | |||
1432 | exit(0); | ||
1433 | } | ||
1434 | pids[i] = pid; | ||
1435 | |||
1436 | } | ||
1437 | /* Wait for all the threads to start up: */ | ||
1438 | while (g->nr_tasks_started != g->p.nr_tasks) | ||
1439 | usleep(1000); | ||
1440 | |||
1441 | BUG_ON(g->nr_tasks_started != g->p.nr_tasks); | ||
1442 | |||
1443 | if (g->p.serialize_startup) { | ||
1444 | double startup_sec; | ||
1445 | |||
1446 | pthread_mutex_lock(&g->startup_done_mutex); | ||
1447 | |||
1448 | /* This will start all threads: */ | ||
1449 | pthread_mutex_unlock(&g->start_work_mutex); | ||
1450 | |||
1451 | /* This mutex is locked - the last started thread will wake us: */ | ||
1452 | pthread_mutex_lock(&g->startup_done_mutex); | ||
1453 | |||
1454 | gettimeofday(&stop, NULL); | ||
1455 | |||
1456 | timersub(&stop, &start, &diff); | ||
1457 | |||
1458 | startup_sec = diff.tv_sec * 1000000000.0; | ||
1459 | startup_sec += diff.tv_usec * 1000.0; | ||
1460 | startup_sec /= 1e9; | ||
1461 | |||
1462 | tprintf(" threads initialized in %.6f seconds.\n", startup_sec); | ||
1463 | tprintf(" #\n"); | ||
1464 | |||
1465 | start = stop; | ||
1466 | pthread_mutex_unlock(&g->startup_done_mutex); | ||
1467 | } else { | ||
1468 | gettimeofday(&start, NULL); | ||
1469 | } | ||
1470 | |||
1471 | /* Parent process: */ | ||
1472 | |||
1473 | |||
1474 | for (i = 0; i < g->p.nr_proc; i++) { | ||
1475 | wpid = waitpid(pids[i], &wait_stat, 0); | ||
1476 | BUG_ON(wpid < 0); | ||
1477 | BUG_ON(!WIFEXITED(wait_stat)); | ||
1478 | |||
1479 | } | ||
1480 | |||
1481 | runtime_ns_sum = 0; | ||
1482 | runtime_ns_min = -1LL; | ||
1483 | |||
1484 | for (t = 0; t < g->p.nr_tasks; t++) { | ||
1485 | u64 thread_runtime_ns = g->threads[t].runtime_ns; | ||
1486 | |||
1487 | runtime_ns_sum += thread_runtime_ns; | ||
1488 | runtime_ns_min = min(thread_runtime_ns, runtime_ns_min); | ||
1489 | } | ||
1490 | |||
1491 | gettimeofday(&stop, NULL); | ||
1492 | timersub(&stop, &start, &diff); | ||
1493 | |||
1494 | BUG_ON(bench_format != BENCH_FORMAT_DEFAULT); | ||
1495 | |||
1496 | tprintf("\n ###\n"); | ||
1497 | tprintf("\n"); | ||
1498 | |||
1499 | runtime_sec_max = diff.tv_sec * 1000000000.0; | ||
1500 | runtime_sec_max += diff.tv_usec * 1000.0; | ||
1501 | runtime_sec_max /= 1e9; | ||
1502 | |||
1503 | runtime_sec_min = runtime_ns_min/1e9; | ||
1504 | |||
1505 | bytes = g->bytes_done; | ||
1506 | runtime_avg = (double)runtime_ns_sum / g->p.nr_tasks / 1e9; | ||
1507 | |||
1508 | if (g->p.measure_convergence) { | ||
1509 | print_res(name, runtime_sec_max, | ||
1510 | "secs,", "NUMA-convergence-latency", "secs latency to NUMA-converge"); | ||
1511 | } | ||
1512 | |||
1513 | print_res(name, runtime_sec_max, | ||
1514 | "secs,", "runtime-max/thread", "secs slowest (max) thread-runtime"); | ||
1515 | |||
1516 | print_res(name, runtime_sec_min, | ||
1517 | "secs,", "runtime-min/thread", "secs fastest (min) thread-runtime"); | ||
1518 | |||
1519 | print_res(name, runtime_avg, | ||
1520 | "secs,", "runtime-avg/thread", "secs average thread-runtime"); | ||
1521 | |||
1522 | delta_runtime = (runtime_sec_max - runtime_sec_min)/2.0; | ||
1523 | print_res(name, delta_runtime / runtime_sec_max * 100.0, | ||
1524 | "%,", "spread-runtime/thread", "% difference between max/avg runtime"); | ||
1525 | |||
1526 | print_res(name, bytes / g->p.nr_tasks / 1e9, | ||
1527 | "GB,", "data/thread", "GB data processed, per thread"); | ||
1528 | |||
1529 | print_res(name, bytes / 1e9, | ||
1530 | "GB,", "data-total", "GB data processed, total"); | ||
1531 | |||
1532 | print_res(name, runtime_sec_max * 1e9 / (bytes / g->p.nr_tasks), | ||
1533 | "nsecs,", "runtime/byte/thread","nsecs/byte/thread runtime"); | ||
1534 | |||
1535 | print_res(name, bytes / g->p.nr_tasks / 1e9 / runtime_sec_max, | ||
1536 | "GB/sec,", "thread-speed", "GB/sec/thread speed"); | ||
1537 | |||
1538 | print_res(name, bytes / runtime_sec_max / 1e9, | ||
1539 | "GB/sec,", "total-speed", "GB/sec total speed"); | ||
1540 | |||
1541 | free(pids); | ||
1542 | |||
1543 | deinit(); | ||
1544 | |||
1545 | return 0; | ||
1546 | } | ||
1547 | |||
1548 | #define MAX_ARGS 50 | ||
1549 | |||
1550 | static int command_size(const char **argv) | ||
1551 | { | ||
1552 | int size = 0; | ||
1553 | |||
1554 | while (*argv) { | ||
1555 | size++; | ||
1556 | argv++; | ||
1557 | } | ||
1558 | |||
1559 | BUG_ON(size >= MAX_ARGS); | ||
1560 | |||
1561 | return size; | ||
1562 | } | ||
1563 | |||
1564 | static void init_params(struct params *p, const char *name, int argc, const char **argv) | ||
1565 | { | ||
1566 | int i; | ||
1567 | |||
1568 | printf("\n # Running %s \"perf bench numa", name); | ||
1569 | |||
1570 | for (i = 0; i < argc; i++) | ||
1571 | printf(" %s", argv[i]); | ||
1572 | |||
1573 | printf("\"\n"); | ||
1574 | |||
1575 | memset(p, 0, sizeof(*p)); | ||
1576 | |||
1577 | /* Initialize nonzero defaults: */ | ||
1578 | |||
1579 | p->serialize_startup = 1; | ||
1580 | p->data_reads = true; | ||
1581 | p->data_writes = true; | ||
1582 | p->data_backwards = true; | ||
1583 | p->data_rand_walk = true; | ||
1584 | p->nr_loops = -1; | ||
1585 | p->init_random = true; | ||
1586 | } | ||
1587 | |||
1588 | static int run_bench_numa(const char *name, const char **argv) | ||
1589 | { | ||
1590 | int argc = command_size(argv); | ||
1591 | |||
1592 | init_params(&p0, name, argc, argv); | ||
1593 | argc = parse_options(argc, argv, options, bench_numa_usage, 0); | ||
1594 | if (argc) | ||
1595 | goto err; | ||
1596 | |||
1597 | if (__bench_numa(name)) | ||
1598 | goto err; | ||
1599 | |||
1600 | return 0; | ||
1601 | |||
1602 | err: | ||
1603 | usage_with_options(numa_usage, options); | ||
1604 | return -1; | ||
1605 | } | ||
1606 | |||
1607 | #define OPT_BW_RAM "-s", "20", "-zZq", "--thp", " 1", "--no-data_rand_walk" | ||
1608 | #define OPT_BW_RAM_NOTHP OPT_BW_RAM, "--thp", "-1" | ||
1609 | |||
1610 | #define OPT_CONV "-s", "100", "-zZ0qcm", "--thp", " 1" | ||
1611 | #define OPT_CONV_NOTHP OPT_CONV, "--thp", "-1" | ||
1612 | |||
1613 | #define OPT_BW "-s", "20", "-zZ0q", "--thp", " 1" | ||
1614 | #define OPT_BW_NOTHP OPT_BW, "--thp", "-1" | ||
1615 | |||
1616 | /* | ||
1617 | * The built-in test-suite executed by "perf bench numa -a". | ||
1618 | * | ||
1619 | * (A minimum of 4 nodes and 16 GB of RAM is recommended.) | ||
1620 | */ | ||
1621 | static const char *tests[][MAX_ARGS] = { | ||
1622 | /* Basic single-stream NUMA bandwidth measurements: */ | ||
1623 | { "RAM-bw-local,", "mem", "-p", "1", "-t", "1", "-P", "1024", | ||
1624 | "-C" , "0", "-M", "0", OPT_BW_RAM }, | ||
1625 | { "RAM-bw-local-NOTHP,", | ||
1626 | "mem", "-p", "1", "-t", "1", "-P", "1024", | ||
1627 | "-C" , "0", "-M", "0", OPT_BW_RAM_NOTHP }, | ||
1628 | { "RAM-bw-remote,", "mem", "-p", "1", "-t", "1", "-P", "1024", | ||
1629 | "-C" , "0", "-M", "1", OPT_BW_RAM }, | ||
1630 | |||
1631 | /* 2-stream NUMA bandwidth measurements: */ | ||
1632 | { "RAM-bw-local-2x,", "mem", "-p", "2", "-t", "1", "-P", "1024", | ||
1633 | "-C", "0,2", "-M", "0x2", OPT_BW_RAM }, | ||
1634 | { "RAM-bw-remote-2x,", "mem", "-p", "2", "-t", "1", "-P", "1024", | ||
1635 | "-C", "0,2", "-M", "1x2", OPT_BW_RAM }, | ||
1636 | |||
1637 | /* Cross-stream NUMA bandwidth measurement: */ | ||
1638 | { "RAM-bw-cross,", "mem", "-p", "2", "-t", "1", "-P", "1024", | ||
1639 | "-C", "0,8", "-M", "1,0", OPT_BW_RAM }, | ||
1640 | |||
1641 | /* Convergence latency measurements: */ | ||
1642 | { " 1x3-convergence,", "mem", "-p", "1", "-t", "3", "-P", "512", OPT_CONV }, | ||
1643 | { " 1x4-convergence,", "mem", "-p", "1", "-t", "4", "-P", "512", OPT_CONV }, | ||
1644 | { " 1x6-convergence,", "mem", "-p", "1", "-t", "6", "-P", "1020", OPT_CONV }, | ||
1645 | { " 2x3-convergence,", "mem", "-p", "3", "-t", "3", "-P", "1020", OPT_CONV }, | ||
1646 | { " 3x3-convergence,", "mem", "-p", "3", "-t", "3", "-P", "1020", OPT_CONV }, | ||
1647 | { " 4x4-convergence,", "mem", "-p", "4", "-t", "4", "-P", "512", OPT_CONV }, | ||
1648 | { " 4x4-convergence-NOTHP,", | ||
1649 | "mem", "-p", "4", "-t", "4", "-P", "512", OPT_CONV_NOTHP }, | ||
1650 | { " 4x6-convergence,", "mem", "-p", "4", "-t", "6", "-P", "1020", OPT_CONV }, | ||
1651 | { " 4x8-convergence,", "mem", "-p", "4", "-t", "8", "-P", "512", OPT_CONV }, | ||
1652 | { " 8x4-convergence,", "mem", "-p", "8", "-t", "4", "-P", "512", OPT_CONV }, | ||
1653 | { " 8x4-convergence-NOTHP,", | ||
1654 | "mem", "-p", "8", "-t", "4", "-P", "512", OPT_CONV_NOTHP }, | ||
1655 | { " 3x1-convergence,", "mem", "-p", "3", "-t", "1", "-P", "512", OPT_CONV }, | ||
1656 | { " 4x1-convergence,", "mem", "-p", "4", "-t", "1", "-P", "512", OPT_CONV }, | ||
1657 | { " 8x1-convergence,", "mem", "-p", "8", "-t", "1", "-P", "512", OPT_CONV }, | ||
1658 | { "16x1-convergence,", "mem", "-p", "16", "-t", "1", "-P", "256", OPT_CONV }, | ||
1659 | { "32x1-convergence,", "mem", "-p", "32", "-t", "1", "-P", "128", OPT_CONV }, | ||
1660 | |||
1661 | /* Various NUMA process/thread layout bandwidth measurements: */ | ||
1662 | { " 2x1-bw-process,", "mem", "-p", "2", "-t", "1", "-P", "1024", OPT_BW }, | ||
1663 | { " 3x1-bw-process,", "mem", "-p", "3", "-t", "1", "-P", "1024", OPT_BW }, | ||
1664 | { " 4x1-bw-process,", "mem", "-p", "4", "-t", "1", "-P", "1024", OPT_BW }, | ||
1665 | { " 8x1-bw-process,", "mem", "-p", "8", "-t", "1", "-P", " 512", OPT_BW }, | ||
1666 | { " 8x1-bw-process-NOTHP,", | ||
1667 | "mem", "-p", "8", "-t", "1", "-P", " 512", OPT_BW_NOTHP }, | ||
1668 | { "16x1-bw-process,", "mem", "-p", "16", "-t", "1", "-P", "256", OPT_BW }, | ||
1669 | |||
1670 | { " 4x1-bw-thread,", "mem", "-p", "1", "-t", "4", "-T", "256", OPT_BW }, | ||
1671 | { " 8x1-bw-thread,", "mem", "-p", "1", "-t", "8", "-T", "256", OPT_BW }, | ||
1672 | { "16x1-bw-thread,", "mem", "-p", "1", "-t", "16", "-T", "128", OPT_BW }, | ||
1673 | { "32x1-bw-thread,", "mem", "-p", "1", "-t", "32", "-T", "64", OPT_BW }, | ||
1674 | |||
1675 | { " 2x3-bw-thread,", "mem", "-p", "2", "-t", "3", "-P", "512", OPT_BW }, | ||
1676 | { " 4x4-bw-thread,", "mem", "-p", "4", "-t", "4", "-P", "512", OPT_BW }, | ||
1677 | { " 4x6-bw-thread,", "mem", "-p", "4", "-t", "6", "-P", "512", OPT_BW }, | ||
1678 | { " 4x8-bw-thread,", "mem", "-p", "4", "-t", "8", "-P", "512", OPT_BW }, | ||
1679 | { " 4x8-bw-thread-NOTHP,", | ||
1680 | "mem", "-p", "4", "-t", "8", "-P", "512", OPT_BW_NOTHP }, | ||
1681 | { " 3x3-bw-thread,", "mem", "-p", "3", "-t", "3", "-P", "512", OPT_BW }, | ||
1682 | { " 5x5-bw-thread,", "mem", "-p", "5", "-t", "5", "-P", "512", OPT_BW }, | ||
1683 | |||
1684 | { "2x16-bw-thread,", "mem", "-p", "2", "-t", "16", "-P", "512", OPT_BW }, | ||
1685 | { "1x32-bw-thread,", "mem", "-p", "1", "-t", "32", "-P", "2048", OPT_BW }, | ||
1686 | |||
1687 | { "numa02-bw,", "mem", "-p", "1", "-t", "32", "-T", "32", OPT_BW }, | ||
1688 | { "numa02-bw-NOTHP,", "mem", "-p", "1", "-t", "32", "-T", "32", OPT_BW_NOTHP }, | ||
1689 | { "numa01-bw-thread,", "mem", "-p", "2", "-t", "16", "-T", "192", OPT_BW }, | ||
1690 | { "numa01-bw-thread-NOTHP,", | ||
1691 | "mem", "-p", "2", "-t", "16", "-T", "192", OPT_BW_NOTHP }, | ||
1692 | }; | ||
1693 | |||
1694 | static int bench_all(void) | ||
1695 | { | ||
1696 | int nr = ARRAY_SIZE(tests); | ||
1697 | int ret; | ||
1698 | int i; | ||
1699 | |||
1700 | ret = system("echo ' #'; echo ' # Running test on: '$(uname -a); echo ' #'"); | ||
1701 | BUG_ON(ret < 0); | ||
1702 | |||
1703 | for (i = 0; i < nr; i++) { | ||
1704 | if (run_bench_numa(tests[i][0], tests[i] + 1)) | ||
1705 | return -1; | ||
1706 | } | ||
1707 | |||
1708 | printf("\n"); | ||
1709 | |||
1710 | return 0; | ||
1711 | } | ||
1712 | |||
1713 | int bench_numa(int argc, const char **argv, const char *prefix __maybe_unused) | ||
1714 | { | ||
1715 | init_params(&p0, "main,", argc, argv); | ||
1716 | argc = parse_options(argc, argv, options, bench_numa_usage, 0); | ||
1717 | if (argc) | ||
1718 | goto err; | ||
1719 | |||
1720 | if (p0.run_all) | ||
1721 | return bench_all(); | ||
1722 | |||
1723 | if (__bench_numa(NULL)) | ||
1724 | goto err; | ||
1725 | |||
1726 | return 0; | ||
1727 | |||
1728 | err: | ||
1729 | usage_with_options(numa_usage, options); | ||
1730 | return -1; | ||
1731 | } | ||
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index dc870cf31b79..2e6961ea3184 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
@@ -34,9 +34,10 @@ | |||
34 | 34 | ||
35 | struct perf_annotate { | 35 | struct perf_annotate { |
36 | struct perf_tool tool; | 36 | struct perf_tool tool; |
37 | bool force, use_tui, use_stdio; | 37 | bool force, use_tui, use_stdio, use_gtk; |
38 | bool full_paths; | 38 | bool full_paths; |
39 | bool print_line; | 39 | bool print_line; |
40 | bool skip_missing; | ||
40 | const char *sym_hist_filter; | 41 | const char *sym_hist_filter; |
41 | const char *cpu_list; | 42 | const char *cpu_list; |
42 | DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); | 43 | DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); |
@@ -138,9 +139,22 @@ find_next: | |||
138 | continue; | 139 | continue; |
139 | } | 140 | } |
140 | 141 | ||
141 | if (use_browser > 0) { | 142 | if (use_browser == 2) { |
143 | int ret; | ||
144 | |||
145 | ret = hist_entry__gtk_annotate(he, evidx, NULL); | ||
146 | if (!ret || !ann->skip_missing) | ||
147 | return; | ||
148 | |||
149 | /* skip missing symbols */ | ||
150 | nd = rb_next(nd); | ||
151 | } else if (use_browser == 1) { | ||
142 | key = hist_entry__tui_annotate(he, evidx, NULL); | 152 | key = hist_entry__tui_annotate(he, evidx, NULL); |
143 | switch (key) { | 153 | switch (key) { |
154 | case -1: | ||
155 | if (!ann->skip_missing) | ||
156 | return; | ||
157 | /* fall through */ | ||
144 | case K_RIGHT: | 158 | case K_RIGHT: |
145 | next = rb_next(nd); | 159 | next = rb_next(nd); |
146 | break; | 160 | break; |
@@ -224,6 +238,10 @@ static int __cmd_annotate(struct perf_annotate *ann) | |||
224 | ui__error("The %s file has no samples!\n", session->filename); | 238 | ui__error("The %s file has no samples!\n", session->filename); |
225 | goto out_delete; | 239 | goto out_delete; |
226 | } | 240 | } |
241 | |||
242 | if (use_browser == 2) | ||
243 | perf_gtk__show_annotations(); | ||
244 | |||
227 | out_delete: | 245 | out_delete: |
228 | /* | 246 | /* |
229 | * Speed up the exit process, for large files this can | 247 | * Speed up the exit process, for large files this can |
@@ -270,6 +288,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) | |||
270 | "be more verbose (show symbol address, etc)"), | 288 | "be more verbose (show symbol address, etc)"), |
271 | OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, | 289 | OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, |
272 | "dump raw trace in ASCII"), | 290 | "dump raw trace in ASCII"), |
291 | OPT_BOOLEAN(0, "gtk", &annotate.use_gtk, "Use the GTK interface"), | ||
273 | OPT_BOOLEAN(0, "tui", &annotate.use_tui, "Use the TUI interface"), | 292 | OPT_BOOLEAN(0, "tui", &annotate.use_tui, "Use the TUI interface"), |
274 | OPT_BOOLEAN(0, "stdio", &annotate.use_stdio, "Use the stdio interface"), | 293 | OPT_BOOLEAN(0, "stdio", &annotate.use_stdio, "Use the stdio interface"), |
275 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, | 294 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, |
@@ -280,6 +299,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) | |||
280 | "print matching source lines (may be slow)"), | 299 | "print matching source lines (may be slow)"), |
281 | OPT_BOOLEAN('P', "full-paths", &annotate.full_paths, | 300 | OPT_BOOLEAN('P', "full-paths", &annotate.full_paths, |
282 | "Don't shorten the displayed pathnames"), | 301 | "Don't shorten the displayed pathnames"), |
302 | OPT_BOOLEAN(0, "skip-missing", &annotate.skip_missing, | ||
303 | "Skip symbols that cannot be annotated"), | ||
283 | OPT_STRING('C', "cpu", &annotate.cpu_list, "cpu", "list of cpus to profile"), | 304 | OPT_STRING('C', "cpu", &annotate.cpu_list, "cpu", "list of cpus to profile"), |
284 | OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", | 305 | OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", |
285 | "Look for files with symbols relative to this directory"), | 306 | "Look for files with symbols relative to this directory"), |
@@ -300,6 +321,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) | |||
300 | use_browser = 0; | 321 | use_browser = 0; |
301 | else if (annotate.use_tui) | 322 | else if (annotate.use_tui) |
302 | use_browser = 1; | 323 | use_browser = 1; |
324 | else if (annotate.use_gtk) | ||
325 | use_browser = 2; | ||
303 | 326 | ||
304 | setup_browser(true); | 327 | setup_browser(true); |
305 | 328 | ||
@@ -309,7 +332,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) | |||
309 | if (symbol__init() < 0) | 332 | if (symbol__init() < 0) |
310 | return -1; | 333 | return -1; |
311 | 334 | ||
312 | setup_sorting(annotate_usage, options); | 335 | if (setup_sorting() < 0) |
336 | usage_with_options(annotate_usage, options); | ||
313 | 337 | ||
314 | if (argc) { | 338 | if (argc) { |
315 | /* | 339 | /* |
diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c index cae9a5fd2ecf..77298bf892b8 100644 --- a/tools/perf/builtin-bench.c +++ b/tools/perf/builtin-bench.c | |||
@@ -35,6 +35,18 @@ struct bench_suite { | |||
35 | /* sentinel: easy for help */ | 35 | /* sentinel: easy for help */ |
36 | #define suite_all { "all", "Test all benchmark suites", NULL } | 36 | #define suite_all { "all", "Test all benchmark suites", NULL } |
37 | 37 | ||
38 | #ifdef LIBNUMA_SUPPORT | ||
39 | static struct bench_suite numa_suites[] = { | ||
40 | { "mem", | ||
41 | "Benchmark for NUMA workloads", | ||
42 | bench_numa }, | ||
43 | suite_all, | ||
44 | { NULL, | ||
45 | NULL, | ||
46 | NULL } | ||
47 | }; | ||
48 | #endif | ||
49 | |||
38 | static struct bench_suite sched_suites[] = { | 50 | static struct bench_suite sched_suites[] = { |
39 | { "messaging", | 51 | { "messaging", |
40 | "Benchmark for scheduler and IPC mechanisms", | 52 | "Benchmark for scheduler and IPC mechanisms", |
@@ -68,6 +80,11 @@ struct bench_subsys { | |||
68 | }; | 80 | }; |
69 | 81 | ||
70 | static struct bench_subsys subsystems[] = { | 82 | static struct bench_subsys subsystems[] = { |
83 | #ifdef LIBNUMA_SUPPORT | ||
84 | { "numa", | ||
85 | "NUMA scheduling and MM behavior", | ||
86 | numa_suites }, | ||
87 | #endif | ||
71 | { "sched", | 88 | { "sched", |
72 | "scheduler and IPC mechanism", | 89 | "scheduler and IPC mechanism", |
73 | sched_suites }, | 90 | sched_suites }, |
@@ -159,6 +176,7 @@ static void all_suite(struct bench_subsys *subsys) /* FROM HERE */ | |||
159 | printf("# Running %s/%s benchmark...\n", | 176 | printf("# Running %s/%s benchmark...\n", |
160 | subsys->name, | 177 | subsys->name, |
161 | suites[i].name); | 178 | suites[i].name); |
179 | fflush(stdout); | ||
162 | 180 | ||
163 | argv[1] = suites[i].name; | 181 | argv[1] = suites[i].name; |
164 | suites[i].fn(1, argv, NULL); | 182 | suites[i].fn(1, argv, NULL); |
@@ -225,6 +243,7 @@ int cmd_bench(int argc, const char **argv, const char *prefix __maybe_unused) | |||
225 | printf("# Running %s/%s benchmark...\n", | 243 | printf("# Running %s/%s benchmark...\n", |
226 | subsystems[i].name, | 244 | subsystems[i].name, |
227 | subsystems[i].suites[j].name); | 245 | subsystems[i].suites[j].name); |
246 | fflush(stdout); | ||
228 | status = subsystems[i].suites[j].fn(argc - 1, | 247 | status = subsystems[i].suites[j].fn(argc - 1, |
229 | argv + 1, prefix); | 248 | argv + 1, prefix); |
230 | goto end; | 249 | goto end; |
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c index fae8b250b2ca..c96c8fa38243 100644 --- a/tools/perf/builtin-buildid-cache.c +++ b/tools/perf/builtin-buildid-cache.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include "util/parse-options.h" | 14 | #include "util/parse-options.h" |
15 | #include "util/strlist.h" | 15 | #include "util/strlist.h" |
16 | #include "util/build-id.h" | 16 | #include "util/build-id.h" |
17 | #include "util/session.h" | ||
17 | #include "util/symbol.h" | 18 | #include "util/symbol.h" |
18 | 19 | ||
19 | static int build_id_cache__add_file(const char *filename, const char *debugdir) | 20 | static int build_id_cache__add_file(const char *filename, const char *debugdir) |
@@ -58,19 +59,89 @@ static int build_id_cache__remove_file(const char *filename, | |||
58 | return err; | 59 | return err; |
59 | } | 60 | } |
60 | 61 | ||
62 | static bool dso__missing_buildid_cache(struct dso *dso, int parm __maybe_unused) | ||
63 | { | ||
64 | char filename[PATH_MAX]; | ||
65 | u8 build_id[BUILD_ID_SIZE]; | ||
66 | |||
67 | if (dso__build_id_filename(dso, filename, sizeof(filename)) && | ||
68 | filename__read_build_id(filename, build_id, | ||
69 | sizeof(build_id)) != sizeof(build_id)) { | ||
70 | if (errno == ENOENT) | ||
71 | return false; | ||
72 | |||
73 | pr_warning("Problems with %s file, consider removing it from the cache\n", | ||
74 | filename); | ||
75 | } else if (memcmp(dso->build_id, build_id, sizeof(dso->build_id))) { | ||
76 | pr_warning("Problems with %s file, consider removing it from the cache\n", | ||
77 | filename); | ||
78 | } | ||
79 | |||
80 | return true; | ||
81 | } | ||
82 | |||
83 | static int build_id_cache__fprintf_missing(const char *filename, bool force, FILE *fp) | ||
84 | { | ||
85 | struct perf_session *session = perf_session__new(filename, O_RDONLY, | ||
86 | force, false, NULL); | ||
87 | if (session == NULL) | ||
88 | return -1; | ||
89 | |||
90 | perf_session__fprintf_dsos_buildid(session, fp, dso__missing_buildid_cache, 0); | ||
91 | perf_session__delete(session); | ||
92 | |||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | static int build_id_cache__update_file(const char *filename, | ||
97 | const char *debugdir) | ||
98 | { | ||
99 | u8 build_id[BUILD_ID_SIZE]; | ||
100 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; | ||
101 | |||
102 | int err; | ||
103 | |||
104 | if (filename__read_build_id(filename, &build_id, sizeof(build_id)) < 0) { | ||
105 | pr_debug("Couldn't read a build-id in %s\n", filename); | ||
106 | return -1; | ||
107 | } | ||
108 | |||
109 | build_id__sprintf(build_id, sizeof(build_id), sbuild_id); | ||
110 | err = build_id_cache__remove_s(sbuild_id, debugdir); | ||
111 | if (!err) { | ||
112 | err = build_id_cache__add_s(sbuild_id, debugdir, filename, | ||
113 | false, false); | ||
114 | } | ||
115 | if (verbose) | ||
116 | pr_info("Updating %s %s: %s\n", sbuild_id, filename, | ||
117 | err ? "FAIL" : "Ok"); | ||
118 | |||
119 | return err; | ||
120 | } | ||
121 | |||
61 | int cmd_buildid_cache(int argc, const char **argv, | 122 | int cmd_buildid_cache(int argc, const char **argv, |
62 | const char *prefix __maybe_unused) | 123 | const char *prefix __maybe_unused) |
63 | { | 124 | { |
64 | struct strlist *list; | 125 | struct strlist *list; |
65 | struct str_node *pos; | 126 | struct str_node *pos; |
127 | int ret = 0; | ||
128 | bool force = false; | ||
66 | char debugdir[PATH_MAX]; | 129 | char debugdir[PATH_MAX]; |
67 | char const *add_name_list_str = NULL, | 130 | char const *add_name_list_str = NULL, |
68 | *remove_name_list_str = NULL; | 131 | *remove_name_list_str = NULL, |
132 | *missing_filename = NULL, | ||
133 | *update_name_list_str = NULL; | ||
134 | |||
69 | const struct option buildid_cache_options[] = { | 135 | const struct option buildid_cache_options[] = { |
70 | OPT_STRING('a', "add", &add_name_list_str, | 136 | OPT_STRING('a', "add", &add_name_list_str, |
71 | "file list", "file(s) to add"), | 137 | "file list", "file(s) to add"), |
72 | OPT_STRING('r', "remove", &remove_name_list_str, "file list", | 138 | OPT_STRING('r', "remove", &remove_name_list_str, "file list", |
73 | "file(s) to remove"), | 139 | "file(s) to remove"), |
140 | OPT_STRING('M', "missing", &missing_filename, "file", | ||
141 | "to find missing build ids in the cache"), | ||
142 | OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), | ||
143 | OPT_STRING('u', "update", &update_name_list_str, "file list", | ||
144 | "file(s) to update"), | ||
74 | OPT_INCR('v', "verbose", &verbose, "be more verbose"), | 145 | OPT_INCR('v', "verbose", &verbose, "be more verbose"), |
75 | OPT_END() | 146 | OPT_END() |
76 | }; | 147 | }; |
@@ -125,5 +196,26 @@ int cmd_buildid_cache(int argc, const char **argv, | |||
125 | } | 196 | } |
126 | } | 197 | } |
127 | 198 | ||
128 | return 0; | 199 | if (missing_filename) |
200 | ret = build_id_cache__fprintf_missing(missing_filename, force, stdout); | ||
201 | |||
202 | if (update_name_list_str) { | ||
203 | list = strlist__new(true, update_name_list_str); | ||
204 | if (list) { | ||
205 | strlist__for_each(pos, list) | ||
206 | if (build_id_cache__update_file(pos->s, debugdir)) { | ||
207 | if (errno == ENOENT) { | ||
208 | pr_debug("%s wasn't in the cache\n", | ||
209 | pos->s); | ||
210 | continue; | ||
211 | } | ||
212 | pr_warning("Couldn't update %s: %s\n", | ||
213 | pos->s, strerror(errno)); | ||
214 | } | ||
215 | |||
216 | strlist__delete(list); | ||
217 | } | ||
218 | } | ||
219 | |||
220 | return ret; | ||
129 | } | 221 | } |
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c index a82d99fec83e..e74366a13218 100644 --- a/tools/perf/builtin-buildid-list.c +++ b/tools/perf/builtin-buildid-list.c | |||
@@ -44,23 +44,26 @@ static int filename__fprintf_build_id(const char *name, FILE *fp) | |||
44 | return fprintf(fp, "%s\n", sbuild_id); | 44 | return fprintf(fp, "%s\n", sbuild_id); |
45 | } | 45 | } |
46 | 46 | ||
47 | static bool dso__skip_buildid(struct dso *dso, int with_hits) | ||
48 | { | ||
49 | return with_hits && !dso->hit; | ||
50 | } | ||
51 | |||
47 | static int perf_session__list_build_ids(bool force, bool with_hits) | 52 | static int perf_session__list_build_ids(bool force, bool with_hits) |
48 | { | 53 | { |
49 | struct perf_session *session; | 54 | struct perf_session *session; |
50 | 55 | ||
51 | symbol__elf_init(); | 56 | symbol__elf_init(); |
52 | |||
53 | session = perf_session__new(input_name, O_RDONLY, force, false, | ||
54 | &build_id__mark_dso_hit_ops); | ||
55 | if (session == NULL) | ||
56 | return -1; | ||
57 | |||
58 | /* | 57 | /* |
59 | * See if this is an ELF file first: | 58 | * See if this is an ELF file first: |
60 | */ | 59 | */ |
61 | if (filename__fprintf_build_id(session->filename, stdout)) | 60 | if (filename__fprintf_build_id(input_name, stdout)) |
62 | goto out; | 61 | goto out; |
63 | 62 | ||
63 | session = perf_session__new(input_name, O_RDONLY, force, false, | ||
64 | &build_id__mark_dso_hit_ops); | ||
65 | if (session == NULL) | ||
66 | return -1; | ||
64 | /* | 67 | /* |
65 | * in pipe-mode, the only way to get the buildids is to parse | 68 | * in pipe-mode, the only way to get the buildids is to parse |
66 | * the record stream. Buildids are stored as RECORD_HEADER_BUILD_ID | 69 | * the record stream. Buildids are stored as RECORD_HEADER_BUILD_ID |
@@ -68,9 +71,9 @@ static int perf_session__list_build_ids(bool force, bool with_hits) | |||
68 | if (with_hits || session->fd_pipe) | 71 | if (with_hits || session->fd_pipe) |
69 | perf_session__process_events(session, &build_id__mark_dso_hit_ops); | 72 | perf_session__process_events(session, &build_id__mark_dso_hit_ops); |
70 | 73 | ||
71 | perf_session__fprintf_dsos_buildid(session, stdout, with_hits); | 74 | perf_session__fprintf_dsos_buildid(session, stdout, dso__skip_buildid, with_hits); |
72 | out: | ||
73 | perf_session__delete(session); | 75 | perf_session__delete(session); |
76 | out: | ||
74 | return 0; | 77 | return 0; |
75 | } | 78 | } |
76 | 79 | ||
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 93b852f8a5d5..d207a97a2db1 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c | |||
@@ -23,7 +23,6 @@ static char const *input_old = "perf.data.old", | |||
23 | *input_new = "perf.data"; | 23 | *input_new = "perf.data"; |
24 | static char diff__default_sort_order[] = "dso,symbol"; | 24 | static char diff__default_sort_order[] = "dso,symbol"; |
25 | static bool force; | 25 | static bool force; |
26 | static bool show_displacement; | ||
27 | static bool show_period; | 26 | static bool show_period; |
28 | static bool show_formula; | 27 | static bool show_formula; |
29 | static bool show_baseline_only; | 28 | static bool show_baseline_only; |
@@ -146,58 +145,47 @@ static int setup_compute(const struct option *opt, const char *str, | |||
146 | return -EINVAL; | 145 | return -EINVAL; |
147 | } | 146 | } |
148 | 147 | ||
149 | static double get_period_percent(struct hist_entry *he, u64 period) | 148 | double perf_diff__period_percent(struct hist_entry *he, u64 period) |
150 | { | 149 | { |
151 | u64 total = he->hists->stats.total_period; | 150 | u64 total = he->hists->stats.total_period; |
152 | return (period * 100.0) / total; | 151 | return (period * 100.0) / total; |
153 | } | 152 | } |
154 | 153 | ||
155 | double perf_diff__compute_delta(struct hist_entry *he) | 154 | double perf_diff__compute_delta(struct hist_entry *he, struct hist_entry *pair) |
156 | { | 155 | { |
157 | struct hist_entry *pair = hist_entry__next_pair(he); | 156 | double new_percent = perf_diff__period_percent(he, he->stat.period); |
158 | double new_percent = get_period_percent(he, he->stat.period); | 157 | double old_percent = perf_diff__period_percent(pair, pair->stat.period); |
159 | double old_percent = pair ? get_period_percent(pair, pair->stat.period) : 0.0; | ||
160 | 158 | ||
161 | he->diff.period_ratio_delta = new_percent - old_percent; | 159 | he->diff.period_ratio_delta = new_percent - old_percent; |
162 | he->diff.computed = true; | 160 | he->diff.computed = true; |
163 | return he->diff.period_ratio_delta; | 161 | return he->diff.period_ratio_delta; |
164 | } | 162 | } |
165 | 163 | ||
166 | double perf_diff__compute_ratio(struct hist_entry *he) | 164 | double perf_diff__compute_ratio(struct hist_entry *he, struct hist_entry *pair) |
167 | { | 165 | { |
168 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
169 | double new_period = he->stat.period; | 166 | double new_period = he->stat.period; |
170 | double old_period = pair ? pair->stat.period : 0; | 167 | double old_period = pair->stat.period; |
171 | 168 | ||
172 | he->diff.computed = true; | 169 | he->diff.computed = true; |
173 | he->diff.period_ratio = pair ? (new_period / old_period) : 0; | 170 | he->diff.period_ratio = new_period / old_period; |
174 | return he->diff.period_ratio; | 171 | return he->diff.period_ratio; |
175 | } | 172 | } |
176 | 173 | ||
177 | s64 perf_diff__compute_wdiff(struct hist_entry *he) | 174 | s64 perf_diff__compute_wdiff(struct hist_entry *he, struct hist_entry *pair) |
178 | { | 175 | { |
179 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
180 | u64 new_period = he->stat.period; | 176 | u64 new_period = he->stat.period; |
181 | u64 old_period = pair ? pair->stat.period : 0; | 177 | u64 old_period = pair->stat.period; |
182 | 178 | ||
183 | he->diff.computed = true; | 179 | he->diff.computed = true; |
184 | 180 | he->diff.wdiff = new_period * compute_wdiff_w2 - | |
185 | if (!pair) | 181 | old_period * compute_wdiff_w1; |
186 | he->diff.wdiff = 0; | ||
187 | else | ||
188 | he->diff.wdiff = new_period * compute_wdiff_w2 - | ||
189 | old_period * compute_wdiff_w1; | ||
190 | 182 | ||
191 | return he->diff.wdiff; | 183 | return he->diff.wdiff; |
192 | } | 184 | } |
193 | 185 | ||
194 | static int formula_delta(struct hist_entry *he, char *buf, size_t size) | 186 | static int formula_delta(struct hist_entry *he, struct hist_entry *pair, |
187 | char *buf, size_t size) | ||
195 | { | 188 | { |
196 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
197 | |||
198 | if (!pair) | ||
199 | return -1; | ||
200 | |||
201 | return scnprintf(buf, size, | 189 | return scnprintf(buf, size, |
202 | "(%" PRIu64 " * 100 / %" PRIu64 ") - " | 190 | "(%" PRIu64 " * 100 / %" PRIu64 ") - " |
203 | "(%" PRIu64 " * 100 / %" PRIu64 ")", | 191 | "(%" PRIu64 " * 100 / %" PRIu64 ")", |
@@ -205,41 +193,36 @@ static int formula_delta(struct hist_entry *he, char *buf, size_t size) | |||
205 | pair->stat.period, pair->hists->stats.total_period); | 193 | pair->stat.period, pair->hists->stats.total_period); |
206 | } | 194 | } |
207 | 195 | ||
208 | static int formula_ratio(struct hist_entry *he, char *buf, size_t size) | 196 | static int formula_ratio(struct hist_entry *he, struct hist_entry *pair, |
197 | char *buf, size_t size) | ||
209 | { | 198 | { |
210 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
211 | double new_period = he->stat.period; | 199 | double new_period = he->stat.period; |
212 | double old_period = pair ? pair->stat.period : 0; | 200 | double old_period = pair->stat.period; |
213 | |||
214 | if (!pair) | ||
215 | return -1; | ||
216 | 201 | ||
217 | return scnprintf(buf, size, "%.0F / %.0F", new_period, old_period); | 202 | return scnprintf(buf, size, "%.0F / %.0F", new_period, old_period); |
218 | } | 203 | } |
219 | 204 | ||
220 | static int formula_wdiff(struct hist_entry *he, char *buf, size_t size) | 205 | static int formula_wdiff(struct hist_entry *he, struct hist_entry *pair, |
206 | char *buf, size_t size) | ||
221 | { | 207 | { |
222 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
223 | u64 new_period = he->stat.period; | 208 | u64 new_period = he->stat.period; |
224 | u64 old_period = pair ? pair->stat.period : 0; | 209 | u64 old_period = pair->stat.period; |
225 | |||
226 | if (!pair) | ||
227 | return -1; | ||
228 | 210 | ||
229 | return scnprintf(buf, size, | 211 | return scnprintf(buf, size, |
230 | "(%" PRIu64 " * " "%" PRId64 ") - (%" PRIu64 " * " "%" PRId64 ")", | 212 | "(%" PRIu64 " * " "%" PRId64 ") - (%" PRIu64 " * " "%" PRId64 ")", |
231 | new_period, compute_wdiff_w2, old_period, compute_wdiff_w1); | 213 | new_period, compute_wdiff_w2, old_period, compute_wdiff_w1); |
232 | } | 214 | } |
233 | 215 | ||
234 | int perf_diff__formula(char *buf, size_t size, struct hist_entry *he) | 216 | int perf_diff__formula(struct hist_entry *he, struct hist_entry *pair, |
217 | char *buf, size_t size) | ||
235 | { | 218 | { |
236 | switch (compute) { | 219 | switch (compute) { |
237 | case COMPUTE_DELTA: | 220 | case COMPUTE_DELTA: |
238 | return formula_delta(he, buf, size); | 221 | return formula_delta(he, pair, buf, size); |
239 | case COMPUTE_RATIO: | 222 | case COMPUTE_RATIO: |
240 | return formula_ratio(he, buf, size); | 223 | return formula_ratio(he, pair, buf, size); |
241 | case COMPUTE_WEIGHTED_DIFF: | 224 | case COMPUTE_WEIGHTED_DIFF: |
242 | return formula_wdiff(he, buf, size); | 225 | return formula_wdiff(he, pair, buf, size); |
243 | default: | 226 | default: |
244 | BUG_ON(1); | 227 | BUG_ON(1); |
245 | } | 228 | } |
@@ -292,48 +275,6 @@ static struct perf_tool tool = { | |||
292 | .ordering_requires_timestamps = true, | 275 | .ordering_requires_timestamps = true, |
293 | }; | 276 | }; |
294 | 277 | ||
295 | static void insert_hist_entry_by_name(struct rb_root *root, | ||
296 | struct hist_entry *he) | ||
297 | { | ||
298 | struct rb_node **p = &root->rb_node; | ||
299 | struct rb_node *parent = NULL; | ||
300 | struct hist_entry *iter; | ||
301 | |||
302 | while (*p != NULL) { | ||
303 | parent = *p; | ||
304 | iter = rb_entry(parent, struct hist_entry, rb_node); | ||
305 | if (hist_entry__cmp(he, iter) < 0) | ||
306 | p = &(*p)->rb_left; | ||
307 | else | ||
308 | p = &(*p)->rb_right; | ||
309 | } | ||
310 | |||
311 | rb_link_node(&he->rb_node, parent, p); | ||
312 | rb_insert_color(&he->rb_node, root); | ||
313 | } | ||
314 | |||
315 | static void hists__name_resort(struct hists *self, bool sort) | ||
316 | { | ||
317 | unsigned long position = 1; | ||
318 | struct rb_root tmp = RB_ROOT; | ||
319 | struct rb_node *next = rb_first(&self->entries); | ||
320 | |||
321 | while (next != NULL) { | ||
322 | struct hist_entry *n = rb_entry(next, struct hist_entry, rb_node); | ||
323 | |||
324 | next = rb_next(&n->rb_node); | ||
325 | n->position = position++; | ||
326 | |||
327 | if (sort) { | ||
328 | rb_erase(&n->rb_node, &self->entries); | ||
329 | insert_hist_entry_by_name(&tmp, n); | ||
330 | } | ||
331 | } | ||
332 | |||
333 | if (sort) | ||
334 | self->entries = tmp; | ||
335 | } | ||
336 | |||
337 | static struct perf_evsel *evsel_match(struct perf_evsel *evsel, | 278 | static struct perf_evsel *evsel_match(struct perf_evsel *evsel, |
338 | struct perf_evlist *evlist) | 279 | struct perf_evlist *evlist) |
339 | { | 280 | { |
@@ -346,34 +287,34 @@ static struct perf_evsel *evsel_match(struct perf_evsel *evsel, | |||
346 | return NULL; | 287 | return NULL; |
347 | } | 288 | } |
348 | 289 | ||
349 | static void perf_evlist__resort_hists(struct perf_evlist *evlist, bool name) | 290 | static void perf_evlist__collapse_resort(struct perf_evlist *evlist) |
350 | { | 291 | { |
351 | struct perf_evsel *evsel; | 292 | struct perf_evsel *evsel; |
352 | 293 | ||
353 | list_for_each_entry(evsel, &evlist->entries, node) { | 294 | list_for_each_entry(evsel, &evlist->entries, node) { |
354 | struct hists *hists = &evsel->hists; | 295 | struct hists *hists = &evsel->hists; |
355 | 296 | ||
356 | hists__output_resort(hists); | 297 | hists__collapse_resort(hists); |
357 | |||
358 | /* | ||
359 | * The hists__name_resort only sets possition | ||
360 | * if name is false. | ||
361 | */ | ||
362 | if (name || ((!name) && show_displacement)) | ||
363 | hists__name_resort(hists, name); | ||
364 | } | 298 | } |
365 | } | 299 | } |
366 | 300 | ||
367 | static void hists__baseline_only(struct hists *hists) | 301 | static void hists__baseline_only(struct hists *hists) |
368 | { | 302 | { |
369 | struct rb_node *next = rb_first(&hists->entries); | 303 | struct rb_root *root; |
304 | struct rb_node *next; | ||
370 | 305 | ||
306 | if (sort__need_collapse) | ||
307 | root = &hists->entries_collapsed; | ||
308 | else | ||
309 | root = hists->entries_in; | ||
310 | |||
311 | next = rb_first(root); | ||
371 | while (next != NULL) { | 312 | while (next != NULL) { |
372 | struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node); | 313 | struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node_in); |
373 | 314 | ||
374 | next = rb_next(&he->rb_node); | 315 | next = rb_next(&he->rb_node_in); |
375 | if (!hist_entry__next_pair(he)) { | 316 | if (!hist_entry__next_pair(he)) { |
376 | rb_erase(&he->rb_node, &hists->entries); | 317 | rb_erase(&he->rb_node_in, root); |
377 | hist_entry__free(he); | 318 | hist_entry__free(he); |
378 | } | 319 | } |
379 | } | 320 | } |
@@ -385,18 +326,21 @@ static void hists__precompute(struct hists *hists) | |||
385 | 326 | ||
386 | while (next != NULL) { | 327 | while (next != NULL) { |
387 | struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node); | 328 | struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node); |
329 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
388 | 330 | ||
389 | next = rb_next(&he->rb_node); | 331 | next = rb_next(&he->rb_node); |
332 | if (!pair) | ||
333 | continue; | ||
390 | 334 | ||
391 | switch (compute) { | 335 | switch (compute) { |
392 | case COMPUTE_DELTA: | 336 | case COMPUTE_DELTA: |
393 | perf_diff__compute_delta(he); | 337 | perf_diff__compute_delta(he, pair); |
394 | break; | 338 | break; |
395 | case COMPUTE_RATIO: | 339 | case COMPUTE_RATIO: |
396 | perf_diff__compute_ratio(he); | 340 | perf_diff__compute_ratio(he, pair); |
397 | break; | 341 | break; |
398 | case COMPUTE_WEIGHTED_DIFF: | 342 | case COMPUTE_WEIGHTED_DIFF: |
399 | perf_diff__compute_wdiff(he); | 343 | perf_diff__compute_wdiff(he, pair); |
400 | break; | 344 | break; |
401 | default: | 345 | default: |
402 | BUG_ON(1); | 346 | BUG_ON(1); |
@@ -470,19 +414,30 @@ static void insert_hist_entry_by_compute(struct rb_root *root, | |||
470 | 414 | ||
471 | static void hists__compute_resort(struct hists *hists) | 415 | static void hists__compute_resort(struct hists *hists) |
472 | { | 416 | { |
473 | struct rb_root tmp = RB_ROOT; | 417 | struct rb_root *root; |
474 | struct rb_node *next = rb_first(&hists->entries); | 418 | struct rb_node *next; |
419 | |||
420 | if (sort__need_collapse) | ||
421 | root = &hists->entries_collapsed; | ||
422 | else | ||
423 | root = hists->entries_in; | ||
424 | |||
425 | hists->entries = RB_ROOT; | ||
426 | next = rb_first(root); | ||
427 | |||
428 | hists->nr_entries = 0; | ||
429 | hists->stats.total_period = 0; | ||
430 | hists__reset_col_len(hists); | ||
475 | 431 | ||
476 | while (next != NULL) { | 432 | while (next != NULL) { |
477 | struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node); | 433 | struct hist_entry *he; |
478 | 434 | ||
479 | next = rb_next(&he->rb_node); | 435 | he = rb_entry(next, struct hist_entry, rb_node_in); |
436 | next = rb_next(&he->rb_node_in); | ||
480 | 437 | ||
481 | rb_erase(&he->rb_node, &hists->entries); | 438 | insert_hist_entry_by_compute(&hists->entries, he, compute); |
482 | insert_hist_entry_by_compute(&tmp, he, compute); | 439 | hists__inc_nr_entries(hists, he); |
483 | } | 440 | } |
484 | |||
485 | hists->entries = tmp; | ||
486 | } | 441 | } |
487 | 442 | ||
488 | static void hists__process(struct hists *old, struct hists *new) | 443 | static void hists__process(struct hists *old, struct hists *new) |
@@ -497,6 +452,8 @@ static void hists__process(struct hists *old, struct hists *new) | |||
497 | if (sort_compute) { | 452 | if (sort_compute) { |
498 | hists__precompute(new); | 453 | hists__precompute(new); |
499 | hists__compute_resort(new); | 454 | hists__compute_resort(new); |
455 | } else { | ||
456 | hists__output_resort(new); | ||
500 | } | 457 | } |
501 | 458 | ||
502 | hists__fprintf(new, true, 0, 0, stdout); | 459 | hists__fprintf(new, true, 0, 0, stdout); |
@@ -528,8 +485,8 @@ static int __cmd_diff(void) | |||
528 | evlist_old = older->evlist; | 485 | evlist_old = older->evlist; |
529 | evlist_new = newer->evlist; | 486 | evlist_new = newer->evlist; |
530 | 487 | ||
531 | perf_evlist__resort_hists(evlist_old, true); | 488 | perf_evlist__collapse_resort(evlist_old); |
532 | perf_evlist__resort_hists(evlist_new, false); | 489 | perf_evlist__collapse_resort(evlist_new); |
533 | 490 | ||
534 | list_for_each_entry(evsel, &evlist_new->entries, node) { | 491 | list_for_each_entry(evsel, &evlist_new->entries, node) { |
535 | struct perf_evsel *evsel_old; | 492 | struct perf_evsel *evsel_old; |
@@ -562,8 +519,6 @@ static const char * const diff_usage[] = { | |||
562 | static const struct option options[] = { | 519 | static const struct option options[] = { |
563 | OPT_INCR('v', "verbose", &verbose, | 520 | OPT_INCR('v', "verbose", &verbose, |
564 | "be more verbose (show symbol address, etc)"), | 521 | "be more verbose (show symbol address, etc)"), |
565 | OPT_BOOLEAN('M', "displacement", &show_displacement, | ||
566 | "Show position displacement relative to baseline"), | ||
567 | OPT_BOOLEAN('b', "baseline-only", &show_baseline_only, | 522 | OPT_BOOLEAN('b', "baseline-only", &show_baseline_only, |
568 | "Show only items with match in baseline"), | 523 | "Show only items with match in baseline"), |
569 | OPT_CALLBACK('c', "compute", &compute, | 524 | OPT_CALLBACK('c', "compute", &compute, |
@@ -597,40 +552,32 @@ static const struct option options[] = { | |||
597 | 552 | ||
598 | static void ui_init(void) | 553 | static void ui_init(void) |
599 | { | 554 | { |
600 | perf_hpp__init(); | ||
601 | |||
602 | /* No overhead column. */ | ||
603 | perf_hpp__column_enable(PERF_HPP__OVERHEAD, false); | ||
604 | |||
605 | /* | 555 | /* |
606 | * Display baseline/delta/ratio/displacement/ | 556 | * Display baseline/delta/ratio |
607 | * formula/periods columns. | 557 | * formula/periods columns. |
608 | */ | 558 | */ |
609 | perf_hpp__column_enable(PERF_HPP__BASELINE, true); | 559 | perf_hpp__column_enable(PERF_HPP__BASELINE); |
610 | 560 | ||
611 | switch (compute) { | 561 | switch (compute) { |
612 | case COMPUTE_DELTA: | 562 | case COMPUTE_DELTA: |
613 | perf_hpp__column_enable(PERF_HPP__DELTA, true); | 563 | perf_hpp__column_enable(PERF_HPP__DELTA); |
614 | break; | 564 | break; |
615 | case COMPUTE_RATIO: | 565 | case COMPUTE_RATIO: |
616 | perf_hpp__column_enable(PERF_HPP__RATIO, true); | 566 | perf_hpp__column_enable(PERF_HPP__RATIO); |
617 | break; | 567 | break; |
618 | case COMPUTE_WEIGHTED_DIFF: | 568 | case COMPUTE_WEIGHTED_DIFF: |
619 | perf_hpp__column_enable(PERF_HPP__WEIGHTED_DIFF, true); | 569 | perf_hpp__column_enable(PERF_HPP__WEIGHTED_DIFF); |
620 | break; | 570 | break; |
621 | default: | 571 | default: |
622 | BUG_ON(1); | 572 | BUG_ON(1); |
623 | }; | 573 | }; |
624 | 574 | ||
625 | if (show_displacement) | ||
626 | perf_hpp__column_enable(PERF_HPP__DISPL, true); | ||
627 | |||
628 | if (show_formula) | 575 | if (show_formula) |
629 | perf_hpp__column_enable(PERF_HPP__FORMULA, true); | 576 | perf_hpp__column_enable(PERF_HPP__FORMULA); |
630 | 577 | ||
631 | if (show_period) { | 578 | if (show_period) { |
632 | perf_hpp__column_enable(PERF_HPP__PERIOD, true); | 579 | perf_hpp__column_enable(PERF_HPP__PERIOD); |
633 | perf_hpp__column_enable(PERF_HPP__PERIOD_BASELINE, true); | 580 | perf_hpp__column_enable(PERF_HPP__PERIOD_BASELINE); |
634 | } | 581 | } |
635 | } | 582 | } |
636 | 583 | ||
@@ -658,7 +605,9 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused) | |||
658 | 605 | ||
659 | ui_init(); | 606 | ui_init(); |
660 | 607 | ||
661 | setup_sorting(diff_usage, options); | 608 | if (setup_sorting() < 0) |
609 | usage_with_options(diff_usage, options); | ||
610 | |||
662 | setup_pager(); | 611 | setup_pager(); |
663 | 612 | ||
664 | sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", NULL); | 613 | sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", NULL); |
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c index c20f1dcfb7e2..05bd9dfe875c 100644 --- a/tools/perf/builtin-evlist.c +++ b/tools/perf/builtin-evlist.c | |||
@@ -15,39 +15,6 @@ | |||
15 | #include "util/parse-options.h" | 15 | #include "util/parse-options.h" |
16 | #include "util/session.h" | 16 | #include "util/session.h" |
17 | 17 | ||
18 | struct perf_attr_details { | ||
19 | bool freq; | ||
20 | bool verbose; | ||
21 | }; | ||
22 | |||
23 | static int comma_printf(bool *first, const char *fmt, ...) | ||
24 | { | ||
25 | va_list args; | ||
26 | int ret = 0; | ||
27 | |||
28 | if (!*first) { | ||
29 | ret += printf(","); | ||
30 | } else { | ||
31 | ret += printf(":"); | ||
32 | *first = false; | ||
33 | } | ||
34 | |||
35 | va_start(args, fmt); | ||
36 | ret += vprintf(fmt, args); | ||
37 | va_end(args); | ||
38 | return ret; | ||
39 | } | ||
40 | |||
41 | static int __if_print(bool *first, const char *field, u64 value) | ||
42 | { | ||
43 | if (value == 0) | ||
44 | return 0; | ||
45 | |||
46 | return comma_printf(first, " %s: %" PRIu64, field, value); | ||
47 | } | ||
48 | |||
49 | #define if_print(field) __if_print(&first, #field, pos->attr.field) | ||
50 | |||
51 | static int __cmd_evlist(const char *file_name, struct perf_attr_details *details) | 18 | static int __cmd_evlist(const char *file_name, struct perf_attr_details *details) |
52 | { | 19 | { |
53 | struct perf_session *session; | 20 | struct perf_session *session; |
@@ -57,52 +24,8 @@ static int __cmd_evlist(const char *file_name, struct perf_attr_details *details | |||
57 | if (session == NULL) | 24 | if (session == NULL) |
58 | return -ENOMEM; | 25 | return -ENOMEM; |
59 | 26 | ||
60 | list_for_each_entry(pos, &session->evlist->entries, node) { | 27 | list_for_each_entry(pos, &session->evlist->entries, node) |
61 | bool first = true; | 28 | perf_evsel__fprintf(pos, details, stdout); |
62 | |||
63 | printf("%s", perf_evsel__name(pos)); | ||
64 | |||
65 | if (details->verbose || details->freq) { | ||
66 | comma_printf(&first, " sample_freq=%" PRIu64, | ||
67 | (u64)pos->attr.sample_freq); | ||
68 | } | ||
69 | |||
70 | if (details->verbose) { | ||
71 | if_print(type); | ||
72 | if_print(config); | ||
73 | if_print(config1); | ||
74 | if_print(config2); | ||
75 | if_print(size); | ||
76 | if_print(sample_type); | ||
77 | if_print(read_format); | ||
78 | if_print(disabled); | ||
79 | if_print(inherit); | ||
80 | if_print(pinned); | ||
81 | if_print(exclusive); | ||
82 | if_print(exclude_user); | ||
83 | if_print(exclude_kernel); | ||
84 | if_print(exclude_hv); | ||
85 | if_print(exclude_idle); | ||
86 | if_print(mmap); | ||
87 | if_print(comm); | ||
88 | if_print(freq); | ||
89 | if_print(inherit_stat); | ||
90 | if_print(enable_on_exec); | ||
91 | if_print(task); | ||
92 | if_print(watermark); | ||
93 | if_print(precise_ip); | ||
94 | if_print(mmap_data); | ||
95 | if_print(sample_id_all); | ||
96 | if_print(exclude_host); | ||
97 | if_print(exclude_guest); | ||
98 | if_print(__reserved_1); | ||
99 | if_print(wakeup_events); | ||
100 | if_print(bp_type); | ||
101 | if_print(branch_sample_type); | ||
102 | } | ||
103 | |||
104 | putchar('\n'); | ||
105 | } | ||
106 | 29 | ||
107 | perf_session__delete(session); | 30 | perf_session__delete(session); |
108 | return 0; | 31 | return 0; |
@@ -116,6 +39,8 @@ int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused) | |||
116 | OPT_BOOLEAN('F', "freq", &details.freq, "Show the sample frequency"), | 39 | OPT_BOOLEAN('F', "freq", &details.freq, "Show the sample frequency"), |
117 | OPT_BOOLEAN('v', "verbose", &details.verbose, | 40 | OPT_BOOLEAN('v', "verbose", &details.verbose, |
118 | "Show all event attr details"), | 41 | "Show all event attr details"), |
42 | OPT_BOOLEAN('g', "group", &details.event_group, | ||
43 | "Show event group information"), | ||
119 | OPT_END() | 44 | OPT_END() |
120 | }; | 45 | }; |
121 | const char * const evlist_usage[] = { | 46 | const char * const evlist_usage[] = { |
@@ -127,5 +52,10 @@ int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused) | |||
127 | if (argc) | 52 | if (argc) |
128 | usage_with_options(evlist_usage, options); | 53 | usage_with_options(evlist_usage, options); |
129 | 54 | ||
55 | if (details.event_group && (details.verbose || details.freq)) { | ||
56 | pr_err("--group option is not compatible with other options\n"); | ||
57 | usage_with_options(evlist_usage, options); | ||
58 | } | ||
59 | |||
130 | return __cmd_evlist(input_name, &details); | 60 | return __cmd_evlist(input_name, &details); |
131 | } | 61 | } |
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 0b4b796167be..46878daca5cc 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include "util/debug.h" | 17 | #include "util/debug.h" |
18 | 18 | ||
19 | #include <linux/rbtree.h> | 19 | #include <linux/rbtree.h> |
20 | #include <linux/string.h> | ||
20 | 21 | ||
21 | struct alloc_stat; | 22 | struct alloc_stat; |
22 | typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *); | 23 | typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *); |
@@ -340,7 +341,7 @@ static void __print_result(struct rb_root *root, struct perf_session *session, | |||
340 | int n_lines, int is_caller) | 341 | int n_lines, int is_caller) |
341 | { | 342 | { |
342 | struct rb_node *next; | 343 | struct rb_node *next; |
343 | struct machine *machine; | 344 | struct machine *machine = &session->machines.host; |
344 | 345 | ||
345 | printf("%.102s\n", graph_dotted_line); | 346 | printf("%.102s\n", graph_dotted_line); |
346 | printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr"); | 347 | printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr"); |
@@ -349,11 +350,6 @@ static void __print_result(struct rb_root *root, struct perf_session *session, | |||
349 | 350 | ||
350 | next = rb_first(root); | 351 | next = rb_first(root); |
351 | 352 | ||
352 | machine = perf_session__find_host_machine(session); | ||
353 | if (!machine) { | ||
354 | pr_err("__print_result: couldn't find kernel information\n"); | ||
355 | return; | ||
356 | } | ||
357 | while (next && n_lines--) { | 353 | while (next && n_lines--) { |
358 | struct alloc_stat *data = rb_entry(next, struct alloc_stat, | 354 | struct alloc_stat *data = rb_entry(next, struct alloc_stat, |
359 | node); | 355 | node); |
@@ -614,8 +610,7 @@ static struct sort_dimension *avail_sorts[] = { | |||
614 | &pingpong_sort_dimension, | 610 | &pingpong_sort_dimension, |
615 | }; | 611 | }; |
616 | 612 | ||
617 | #define NUM_AVAIL_SORTS \ | 613 | #define NUM_AVAIL_SORTS ((int)ARRAY_SIZE(avail_sorts)) |
618 | (int)(sizeof(avail_sorts) / sizeof(struct sort_dimension *)) | ||
619 | 614 | ||
620 | static int sort_dimension__add(const char *tok, struct list_head *list) | 615 | static int sort_dimension__add(const char *tok, struct list_head *list) |
621 | { | 616 | { |
@@ -624,12 +619,11 @@ static int sort_dimension__add(const char *tok, struct list_head *list) | |||
624 | 619 | ||
625 | for (i = 0; i < NUM_AVAIL_SORTS; i++) { | 620 | for (i = 0; i < NUM_AVAIL_SORTS; i++) { |
626 | if (!strcmp(avail_sorts[i]->name, tok)) { | 621 | if (!strcmp(avail_sorts[i]->name, tok)) { |
627 | sort = malloc(sizeof(*sort)); | 622 | sort = memdup(avail_sorts[i], sizeof(*avail_sorts[i])); |
628 | if (!sort) { | 623 | if (!sort) { |
629 | pr_err("%s: malloc failed\n", __func__); | 624 | pr_err("%s: memdup failed\n", __func__); |
630 | return -1; | 625 | return -1; |
631 | } | 626 | } |
632 | memcpy(sort, avail_sorts[i], sizeof(*sort)); | ||
633 | list_add_tail(&sort->list, list); | 627 | list_add_tail(&sort->list, list); |
634 | return 0; | 628 | return 0; |
635 | } | 629 | } |
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index ca3f80ebc100..37a769d7f9fe 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c | |||
@@ -973,8 +973,7 @@ __cmd_buildid_list(const char *file_name, int argc, const char **argv) | |||
973 | 973 | ||
974 | int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused) | 974 | int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused) |
975 | { | 975 | { |
976 | const char *file_name; | 976 | const char *file_name = NULL; |
977 | |||
978 | const struct option kvm_options[] = { | 977 | const struct option kvm_options[] = { |
979 | OPT_STRING('i', "input", &file_name, "file", | 978 | OPT_STRING('i', "input", &file_name, "file", |
980 | "Input file name"), | 979 | "Input file name"), |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index f3151d3c70ce..774c90713a53 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -224,130 +224,28 @@ static bool perf_evlist__equal(struct perf_evlist *evlist, | |||
224 | 224 | ||
225 | static int perf_record__open(struct perf_record *rec) | 225 | static int perf_record__open(struct perf_record *rec) |
226 | { | 226 | { |
227 | char msg[512]; | ||
227 | struct perf_evsel *pos; | 228 | struct perf_evsel *pos; |
228 | struct perf_evlist *evlist = rec->evlist; | 229 | struct perf_evlist *evlist = rec->evlist; |
229 | struct perf_session *session = rec->session; | 230 | struct perf_session *session = rec->session; |
230 | struct perf_record_opts *opts = &rec->opts; | 231 | struct perf_record_opts *opts = &rec->opts; |
231 | int rc = 0; | 232 | int rc = 0; |
232 | 233 | ||
233 | /* | 234 | perf_evlist__config(evlist, opts); |
234 | * Set the evsel leader links before we configure attributes, | ||
235 | * since some might depend on this info. | ||
236 | */ | ||
237 | if (opts->group) | ||
238 | perf_evlist__set_leader(evlist); | ||
239 | |||
240 | perf_evlist__config_attrs(evlist, opts); | ||
241 | 235 | ||
242 | list_for_each_entry(pos, &evlist->entries, node) { | 236 | list_for_each_entry(pos, &evlist->entries, node) { |
243 | struct perf_event_attr *attr = &pos->attr; | ||
244 | /* | ||
245 | * Check if parse_single_tracepoint_event has already asked for | ||
246 | * PERF_SAMPLE_TIME. | ||
247 | * | ||
248 | * XXX this is kludgy but short term fix for problems introduced by | ||
249 | * eac23d1c that broke 'perf script' by having different sample_types | ||
250 | * when using multiple tracepoint events when we use a perf binary | ||
251 | * that tries to use sample_id_all on an older kernel. | ||
252 | * | ||
253 | * We need to move counter creation to perf_session, support | ||
254 | * different sample_types, etc. | ||
255 | */ | ||
256 | bool time_needed = attr->sample_type & PERF_SAMPLE_TIME; | ||
257 | |||
258 | fallback_missing_features: | ||
259 | if (opts->exclude_guest_missing) | ||
260 | attr->exclude_guest = attr->exclude_host = 0; | ||
261 | retry_sample_id: | ||
262 | attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1; | ||
263 | try_again: | 237 | try_again: |
264 | if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) { | 238 | if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) { |
265 | int err = errno; | 239 | if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) { |
266 | |||
267 | if (err == EPERM || err == EACCES) { | ||
268 | ui__error_paranoid(); | ||
269 | rc = -err; | ||
270 | goto out; | ||
271 | } else if (err == ENODEV && opts->target.cpu_list) { | ||
272 | pr_err("No such device - did you specify" | ||
273 | " an out-of-range profile CPU?\n"); | ||
274 | rc = -err; | ||
275 | goto out; | ||
276 | } else if (err == EINVAL) { | ||
277 | if (!opts->exclude_guest_missing && | ||
278 | (attr->exclude_guest || attr->exclude_host)) { | ||
279 | pr_debug("Old kernel, cannot exclude " | ||
280 | "guest or host samples.\n"); | ||
281 | opts->exclude_guest_missing = true; | ||
282 | goto fallback_missing_features; | ||
283 | } else if (!opts->sample_id_all_missing) { | ||
284 | /* | ||
285 | * Old kernel, no attr->sample_id_type_all field | ||
286 | */ | ||
287 | opts->sample_id_all_missing = true; | ||
288 | if (!opts->sample_time && !opts->raw_samples && !time_needed) | ||
289 | attr->sample_type &= ~PERF_SAMPLE_TIME; | ||
290 | |||
291 | goto retry_sample_id; | ||
292 | } | ||
293 | } | ||
294 | |||
295 | /* | ||
296 | * If it's cycles then fall back to hrtimer | ||
297 | * based cpu-clock-tick sw counter, which | ||
298 | * is always available even if no PMU support. | ||
299 | * | ||
300 | * PPC returns ENXIO until 2.6.37 (behavior changed | ||
301 | * with commit b0a873e). | ||
302 | */ | ||
303 | if ((err == ENOENT || err == ENXIO) | ||
304 | && attr->type == PERF_TYPE_HARDWARE | ||
305 | && attr->config == PERF_COUNT_HW_CPU_CYCLES) { | ||
306 | |||
307 | if (verbose) | 240 | if (verbose) |
308 | ui__warning("The cycles event is not supported, " | 241 | ui__warning("%s\n", msg); |
309 | "trying to fall back to cpu-clock-ticks\n"); | ||
310 | attr->type = PERF_TYPE_SOFTWARE; | ||
311 | attr->config = PERF_COUNT_SW_CPU_CLOCK; | ||
312 | if (pos->name) { | ||
313 | free(pos->name); | ||
314 | pos->name = NULL; | ||
315 | } | ||
316 | goto try_again; | 242 | goto try_again; |
317 | } | 243 | } |
318 | 244 | ||
319 | if (err == ENOENT) { | 245 | rc = -errno; |
320 | ui__error("The %s event is not supported.\n", | 246 | perf_evsel__open_strerror(pos, &opts->target, |
321 | perf_evsel__name(pos)); | 247 | errno, msg, sizeof(msg)); |
322 | rc = -err; | 248 | ui__error("%s\n", msg); |
323 | goto out; | ||
324 | } else if ((err == EOPNOTSUPP) && (attr->precise_ip)) { | ||
325 | ui__error("\'precise\' request may not be supported. " | ||
326 | "Try removing 'p' modifier\n"); | ||
327 | rc = -err; | ||
328 | goto out; | ||
329 | } | ||
330 | |||
331 | printf("\n"); | ||
332 | error("sys_perf_event_open() syscall returned with %d " | ||
333 | "(%s) for event %s. /bin/dmesg may provide " | ||
334 | "additional information.\n", | ||
335 | err, strerror(err), perf_evsel__name(pos)); | ||
336 | |||
337 | #if defined(__i386__) || defined(__x86_64__) | ||
338 | if (attr->type == PERF_TYPE_HARDWARE && | ||
339 | err == EOPNOTSUPP) { | ||
340 | pr_err("No hardware sampling interrupt available." | ||
341 | " No APIC? If so then you can boot the kernel" | ||
342 | " with the \"lapic\" boot parameter to" | ||
343 | " force-enable it.\n"); | ||
344 | rc = -err; | ||
345 | goto out; | ||
346 | } | ||
347 | #endif | ||
348 | |||
349 | pr_err("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); | ||
350 | rc = -err; | ||
351 | goto out; | 249 | goto out; |
352 | } | 250 | } |
353 | } | 251 | } |
@@ -430,10 +328,6 @@ static void perf_event__synthesize_guest_os(struct machine *machine, void *data) | |||
430 | { | 328 | { |
431 | int err; | 329 | int err; |
432 | struct perf_tool *tool = data; | 330 | struct perf_tool *tool = data; |
433 | |||
434 | if (machine__is_host(machine)) | ||
435 | return; | ||
436 | |||
437 | /* | 331 | /* |
438 | *As for guest kernel when processing subcommand record&report, | 332 | *As for guest kernel when processing subcommand record&report, |
439 | *we arrange module mmap prior to guest kernel mmap and trigger | 333 | *we arrange module mmap prior to guest kernel mmap and trigger |
@@ -592,6 +486,9 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | |||
592 | goto out_delete_session; | 486 | goto out_delete_session; |
593 | } | 487 | } |
594 | 488 | ||
489 | if (!evsel_list->nr_groups) | ||
490 | perf_header__clear_feat(&session->header, HEADER_GROUP_DESC); | ||
491 | |||
595 | /* | 492 | /* |
596 | * perf_session__delete(session) will be called at perf_record__exit() | 493 | * perf_session__delete(session) will be called at perf_record__exit() |
597 | */ | 494 | */ |
@@ -618,12 +515,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | |||
618 | 515 | ||
619 | rec->post_processing_offset = lseek(output, 0, SEEK_CUR); | 516 | rec->post_processing_offset = lseek(output, 0, SEEK_CUR); |
620 | 517 | ||
621 | machine = perf_session__find_host_machine(session); | 518 | machine = &session->machines.host; |
622 | if (!machine) { | ||
623 | pr_err("Couldn't find native kernel information.\n"); | ||
624 | err = -1; | ||
625 | goto out_delete_session; | ||
626 | } | ||
627 | 519 | ||
628 | if (opts->pipe_output) { | 520 | if (opts->pipe_output) { |
629 | err = perf_event__synthesize_attrs(tool, session, | 521 | err = perf_event__synthesize_attrs(tool, session, |
@@ -676,9 +568,10 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | |||
676 | "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" | 568 | "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" |
677 | "Check /proc/modules permission or run as root.\n"); | 569 | "Check /proc/modules permission or run as root.\n"); |
678 | 570 | ||
679 | if (perf_guest) | 571 | if (perf_guest) { |
680 | perf_session__process_machines(session, tool, | 572 | machines__process_guests(&session->machines, |
681 | perf_event__synthesize_guest_os); | 573 | perf_event__synthesize_guest_os, tool); |
574 | } | ||
682 | 575 | ||
683 | if (!opts->target.system_wide) | 576 | if (!opts->target.system_wide) |
684 | err = perf_event__synthesize_thread_map(tool, evsel_list->threads, | 577 | err = perf_event__synthesize_thread_map(tool, evsel_list->threads, |
@@ -875,11 +768,10 @@ static int get_stack_size(char *str, unsigned long *_size) | |||
875 | } | 768 | } |
876 | #endif /* LIBUNWIND_SUPPORT */ | 769 | #endif /* LIBUNWIND_SUPPORT */ |
877 | 770 | ||
878 | static int | 771 | int record_parse_callchain_opt(const struct option *opt, |
879 | parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg, | 772 | const char *arg, int unset) |
880 | int unset) | ||
881 | { | 773 | { |
882 | struct perf_record *rec = (struct perf_record *)opt->value; | 774 | struct perf_record_opts *opts = opt->value; |
883 | char *tok, *name, *saveptr = NULL; | 775 | char *tok, *name, *saveptr = NULL; |
884 | char *buf; | 776 | char *buf; |
885 | int ret = -1; | 777 | int ret = -1; |
@@ -905,7 +797,7 @@ parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg, | |||
905 | /* Framepointer style */ | 797 | /* Framepointer style */ |
906 | if (!strncmp(name, "fp", sizeof("fp"))) { | 798 | if (!strncmp(name, "fp", sizeof("fp"))) { |
907 | if (!strtok_r(NULL, ",", &saveptr)) { | 799 | if (!strtok_r(NULL, ",", &saveptr)) { |
908 | rec->opts.call_graph = CALLCHAIN_FP; | 800 | opts->call_graph = CALLCHAIN_FP; |
909 | ret = 0; | 801 | ret = 0; |
910 | } else | 802 | } else |
911 | pr_err("callchain: No more arguments " | 803 | pr_err("callchain: No more arguments " |
@@ -918,20 +810,20 @@ parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg, | |||
918 | const unsigned long default_stack_dump_size = 8192; | 810 | const unsigned long default_stack_dump_size = 8192; |
919 | 811 | ||
920 | ret = 0; | 812 | ret = 0; |
921 | rec->opts.call_graph = CALLCHAIN_DWARF; | 813 | opts->call_graph = CALLCHAIN_DWARF; |
922 | rec->opts.stack_dump_size = default_stack_dump_size; | 814 | opts->stack_dump_size = default_stack_dump_size; |
923 | 815 | ||
924 | tok = strtok_r(NULL, ",", &saveptr); | 816 | tok = strtok_r(NULL, ",", &saveptr); |
925 | if (tok) { | 817 | if (tok) { |
926 | unsigned long size = 0; | 818 | unsigned long size = 0; |
927 | 819 | ||
928 | ret = get_stack_size(tok, &size); | 820 | ret = get_stack_size(tok, &size); |
929 | rec->opts.stack_dump_size = size; | 821 | opts->stack_dump_size = size; |
930 | } | 822 | } |
931 | 823 | ||
932 | if (!ret) | 824 | if (!ret) |
933 | pr_debug("callchain: stack dump size %d\n", | 825 | pr_debug("callchain: stack dump size %d\n", |
934 | rec->opts.stack_dump_size); | 826 | opts->stack_dump_size); |
935 | #endif /* LIBUNWIND_SUPPORT */ | 827 | #endif /* LIBUNWIND_SUPPORT */ |
936 | } else { | 828 | } else { |
937 | pr_err("callchain: Unknown -g option " | 829 | pr_err("callchain: Unknown -g option " |
@@ -944,7 +836,7 @@ parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg, | |||
944 | free(buf); | 836 | free(buf); |
945 | 837 | ||
946 | if (!ret) | 838 | if (!ret) |
947 | pr_debug("callchain: type %d\n", rec->opts.call_graph); | 839 | pr_debug("callchain: type %d\n", opts->call_graph); |
948 | 840 | ||
949 | return ret; | 841 | return ret; |
950 | } | 842 | } |
@@ -982,9 +874,9 @@ static struct perf_record record = { | |||
982 | #define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: " | 874 | #define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: " |
983 | 875 | ||
984 | #ifdef LIBUNWIND_SUPPORT | 876 | #ifdef LIBUNWIND_SUPPORT |
985 | static const char callchain_help[] = CALLCHAIN_HELP "[fp] dwarf"; | 877 | const char record_callchain_help[] = CALLCHAIN_HELP "[fp] dwarf"; |
986 | #else | 878 | #else |
987 | static const char callchain_help[] = CALLCHAIN_HELP "[fp]"; | 879 | const char record_callchain_help[] = CALLCHAIN_HELP "[fp]"; |
988 | #endif | 880 | #endif |
989 | 881 | ||
990 | /* | 882 | /* |
@@ -1028,9 +920,9 @@ const struct option record_options[] = { | |||
1028 | "number of mmap data pages"), | 920 | "number of mmap data pages"), |
1029 | OPT_BOOLEAN(0, "group", &record.opts.group, | 921 | OPT_BOOLEAN(0, "group", &record.opts.group, |
1030 | "put the counters into a counter group"), | 922 | "put the counters into a counter group"), |
1031 | OPT_CALLBACK_DEFAULT('g', "call-graph", &record, "mode[,dump_size]", | 923 | OPT_CALLBACK_DEFAULT('g', "call-graph", &record.opts, |
1032 | callchain_help, &parse_callchain_opt, | 924 | "mode[,dump_size]", record_callchain_help, |
1033 | "fp"), | 925 | &record_parse_callchain_opt, "fp"), |
1034 | OPT_INCR('v', "verbose", &verbose, | 926 | OPT_INCR('v', "verbose", &verbose, |
1035 | "be more verbose (show counter open errors, etc)"), | 927 | "be more verbose (show counter open errors, etc)"), |
1036 | OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"), | 928 | OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"), |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index fc251005dd3d..96b5a7fee4bb 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include "builtin.h" | 8 | #include "builtin.h" |
9 | 9 | ||
10 | #include "util/util.h" | 10 | #include "util/util.h" |
11 | #include "util/cache.h" | ||
11 | 12 | ||
12 | #include "util/annotate.h" | 13 | #include "util/annotate.h" |
13 | #include "util/color.h" | 14 | #include "util/color.h" |
@@ -54,6 +55,16 @@ struct perf_report { | |||
54 | DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); | 55 | DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); |
55 | }; | 56 | }; |
56 | 57 | ||
58 | static int perf_report_config(const char *var, const char *value, void *cb) | ||
59 | { | ||
60 | if (!strcmp(var, "report.group")) { | ||
61 | symbol_conf.event_group = perf_config_bool(var, value); | ||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | return perf_default_config(var, value, cb); | ||
66 | } | ||
67 | |||
57 | static int perf_report__add_branch_hist_entry(struct perf_tool *tool, | 68 | static int perf_report__add_branch_hist_entry(struct perf_tool *tool, |
58 | struct addr_location *al, | 69 | struct addr_location *al, |
59 | struct perf_sample *sample, | 70 | struct perf_sample *sample, |
@@ -299,6 +310,21 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self, | |||
299 | char unit; | 310 | char unit; |
300 | unsigned long nr_samples = self->stats.nr_events[PERF_RECORD_SAMPLE]; | 311 | unsigned long nr_samples = self->stats.nr_events[PERF_RECORD_SAMPLE]; |
301 | u64 nr_events = self->stats.total_period; | 312 | u64 nr_events = self->stats.total_period; |
313 | struct perf_evsel *evsel = hists_to_evsel(self); | ||
314 | char buf[512]; | ||
315 | size_t size = sizeof(buf); | ||
316 | |||
317 | if (symbol_conf.event_group && evsel->nr_members > 1) { | ||
318 | struct perf_evsel *pos; | ||
319 | |||
320 | perf_evsel__group_desc(evsel, buf, size); | ||
321 | evname = buf; | ||
322 | |||
323 | for_each_group_member(pos, evsel) { | ||
324 | nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE]; | ||
325 | nr_events += pos->hists.stats.total_period; | ||
326 | } | ||
327 | } | ||
302 | 328 | ||
303 | nr_samples = convert_unit(nr_samples, &unit); | 329 | nr_samples = convert_unit(nr_samples, &unit); |
304 | ret = fprintf(fp, "# Samples: %lu%c", nr_samples, unit); | 330 | ret = fprintf(fp, "# Samples: %lu%c", nr_samples, unit); |
@@ -319,6 +345,10 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, | |||
319 | struct hists *hists = &pos->hists; | 345 | struct hists *hists = &pos->hists; |
320 | const char *evname = perf_evsel__name(pos); | 346 | const char *evname = perf_evsel__name(pos); |
321 | 347 | ||
348 | if (symbol_conf.event_group && | ||
349 | !perf_evsel__is_group_leader(pos)) | ||
350 | continue; | ||
351 | |||
322 | hists__fprintf_nr_sample_events(hists, evname, stdout); | 352 | hists__fprintf_nr_sample_events(hists, evname, stdout); |
323 | hists__fprintf(hists, true, 0, 0, stdout); | 353 | hists__fprintf(hists, true, 0, 0, stdout); |
324 | fprintf(stdout, "\n\n"); | 354 | fprintf(stdout, "\n\n"); |
@@ -372,7 +402,7 @@ static int __cmd_report(struct perf_report *rep) | |||
372 | if (ret) | 402 | if (ret) |
373 | goto out_delete; | 403 | goto out_delete; |
374 | 404 | ||
375 | kernel_map = session->host_machine.vmlinux_maps[MAP__FUNCTION]; | 405 | kernel_map = session->machines.host.vmlinux_maps[MAP__FUNCTION]; |
376 | kernel_kmap = map__kmap(kernel_map); | 406 | kernel_kmap = map__kmap(kernel_map); |
377 | if (kernel_map == NULL || | 407 | if (kernel_map == NULL || |
378 | (kernel_map->dso->hit && | 408 | (kernel_map->dso->hit && |
@@ -416,8 +446,16 @@ static int __cmd_report(struct perf_report *rep) | |||
416 | hists->symbol_filter_str = rep->symbol_filter_str; | 446 | hists->symbol_filter_str = rep->symbol_filter_str; |
417 | 447 | ||
418 | hists__collapse_resort(hists); | 448 | hists__collapse_resort(hists); |
419 | hists__output_resort(hists); | ||
420 | nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE]; | 449 | nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE]; |
450 | |||
451 | /* Non-group events are considered as leader */ | ||
452 | if (symbol_conf.event_group && | ||
453 | !perf_evsel__is_group_leader(pos)) { | ||
454 | struct hists *leader_hists = &pos->leader->hists; | ||
455 | |||
456 | hists__match(leader_hists, hists); | ||
457 | hists__link(leader_hists, hists); | ||
458 | } | ||
421 | } | 459 | } |
422 | 460 | ||
423 | if (nr_samples == 0) { | 461 | if (nr_samples == 0) { |
@@ -425,11 +463,22 @@ static int __cmd_report(struct perf_report *rep) | |||
425 | goto out_delete; | 463 | goto out_delete; |
426 | } | 464 | } |
427 | 465 | ||
466 | list_for_each_entry(pos, &session->evlist->entries, node) | ||
467 | hists__output_resort(&pos->hists); | ||
468 | |||
428 | if (use_browser > 0) { | 469 | if (use_browser > 0) { |
429 | if (use_browser == 1) { | 470 | if (use_browser == 1) { |
430 | perf_evlist__tui_browse_hists(session->evlist, help, | 471 | ret = perf_evlist__tui_browse_hists(session->evlist, |
431 | NULL, | 472 | help, |
432 | &session->header.env); | 473 | NULL, |
474 | &session->header.env); | ||
475 | /* | ||
476 | * Usually "ret" is the last pressed key, and we only | ||
477 | * care if the key notifies us to switch data file. | ||
478 | */ | ||
479 | if (ret != K_SWITCH_INPUT_DATA) | ||
480 | ret = 0; | ||
481 | |||
433 | } else if (use_browser == 2) { | 482 | } else if (use_browser == 2) { |
434 | perf_evlist__gtk_browse_hists(session->evlist, help, | 483 | perf_evlist__gtk_browse_hists(session->evlist, help, |
435 | NULL); | 484 | NULL); |
@@ -595,8 +644,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
595 | OPT_BOOLEAN(0, "stdio", &report.use_stdio, | 644 | OPT_BOOLEAN(0, "stdio", &report.use_stdio, |
596 | "Use the stdio interface"), | 645 | "Use the stdio interface"), |
597 | OPT_STRING('s', "sort", &sort_order, "key[,key2...]", | 646 | OPT_STRING('s', "sort", &sort_order, "key[,key2...]", |
598 | "sort by key(s): pid, comm, dso, symbol, parent, dso_to," | 647 | "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline," |
599 | " dso_from, symbol_to, symbol_from, mispredict"), | 648 | " dso_to, dso_from, symbol_to, symbol_from, mispredict"), |
600 | OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization, | 649 | OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization, |
601 | "Show sample percentage for different cpu modes"), | 650 | "Show sample percentage for different cpu modes"), |
602 | OPT_STRING('p', "parent", &parent_pattern, "regex", | 651 | OPT_STRING('p', "parent", &parent_pattern, "regex", |
@@ -638,6 +687,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
638 | "Specify disassembler style (e.g. -M intel for intel syntax)"), | 687 | "Specify disassembler style (e.g. -M intel for intel syntax)"), |
639 | OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, | 688 | OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, |
640 | "Show a column with the sum of periods"), | 689 | "Show a column with the sum of periods"), |
690 | OPT_BOOLEAN(0, "group", &symbol_conf.event_group, | ||
691 | "Show event group information together"), | ||
641 | OPT_CALLBACK_NOOPT('b', "branch-stack", &sort__branch_mode, "", | 692 | OPT_CALLBACK_NOOPT('b', "branch-stack", &sort__branch_mode, "", |
642 | "use branch records for histogram filling", parse_branch_mode), | 693 | "use branch records for histogram filling", parse_branch_mode), |
643 | OPT_STRING(0, "objdump", &objdump_path, "path", | 694 | OPT_STRING(0, "objdump", &objdump_path, "path", |
@@ -645,6 +696,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
645 | OPT_END() | 696 | OPT_END() |
646 | }; | 697 | }; |
647 | 698 | ||
699 | perf_config(perf_report_config, NULL); | ||
700 | |||
648 | argc = parse_options(argc, argv, options, report_usage, 0); | 701 | argc = parse_options(argc, argv, options, report_usage, 0); |
649 | 702 | ||
650 | if (report.use_stdio) | 703 | if (report.use_stdio) |
@@ -663,6 +716,16 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
663 | else | 716 | else |
664 | input_name = "perf.data"; | 717 | input_name = "perf.data"; |
665 | } | 718 | } |
719 | |||
720 | if (strcmp(input_name, "-") != 0) | ||
721 | setup_browser(true); | ||
722 | else { | ||
723 | use_browser = 0; | ||
724 | perf_hpp__column_enable(PERF_HPP__OVERHEAD); | ||
725 | perf_hpp__init(); | ||
726 | } | ||
727 | |||
728 | repeat: | ||
666 | session = perf_session__new(input_name, O_RDONLY, | 729 | session = perf_session__new(input_name, O_RDONLY, |
667 | report.force, false, &report.tool); | 730 | report.force, false, &report.tool); |
668 | if (session == NULL) | 731 | if (session == NULL) |
@@ -688,14 +751,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
688 | 751 | ||
689 | } | 752 | } |
690 | 753 | ||
691 | if (strcmp(input_name, "-") != 0) | 754 | if (setup_sorting() < 0) |
692 | setup_browser(true); | 755 | usage_with_options(report_usage, options); |
693 | else { | ||
694 | use_browser = 0; | ||
695 | perf_hpp__init(); | ||
696 | } | ||
697 | |||
698 | setup_sorting(report_usage, options); | ||
699 | 756 | ||
700 | /* | 757 | /* |
701 | * Only in the newt browser we are doing integrated annotation, | 758 | * Only in the newt browser we are doing integrated annotation, |
@@ -763,6 +820,12 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
763 | } | 820 | } |
764 | 821 | ||
765 | ret = __cmd_report(&report); | 822 | ret = __cmd_report(&report); |
823 | if (ret == K_SWITCH_INPUT_DATA) { | ||
824 | perf_session__delete(session); | ||
825 | goto repeat; | ||
826 | } else | ||
827 | ret = 0; | ||
828 | |||
766 | error: | 829 | error: |
767 | perf_session__delete(session); | 830 | perf_session__delete(session); |
768 | return ret; | 831 | return ret; |
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index cc28b85dabd5..138229439a93 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c | |||
@@ -1475,9 +1475,9 @@ static int perf_sched__read_events(struct perf_sched *sched, bool destroy, | |||
1475 | goto out_delete; | 1475 | goto out_delete; |
1476 | } | 1476 | } |
1477 | 1477 | ||
1478 | sched->nr_events = session->hists.stats.nr_events[0]; | 1478 | sched->nr_events = session->stats.nr_events[0]; |
1479 | sched->nr_lost_events = session->hists.stats.total_lost; | 1479 | sched->nr_lost_events = session->stats.total_lost; |
1480 | sched->nr_lost_chunks = session->hists.stats.nr_events[PERF_RECORD_LOST]; | 1480 | sched->nr_lost_chunks = session->stats.nr_events[PERF_RECORD_LOST]; |
1481 | } | 1481 | } |
1482 | 1482 | ||
1483 | if (destroy) | 1483 | if (destroy) |
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index b363e7b292b2..92d4658f56fb 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -692,7 +692,7 @@ static int parse_output_fields(const struct option *opt __maybe_unused, | |||
692 | const char *arg, int unset __maybe_unused) | 692 | const char *arg, int unset __maybe_unused) |
693 | { | 693 | { |
694 | char *tok; | 694 | char *tok; |
695 | int i, imax = sizeof(all_output_options) / sizeof(struct output_option); | 695 | int i, imax = ARRAY_SIZE(all_output_options); |
696 | int j; | 696 | int j; |
697 | int rc = 0; | 697 | int rc = 0; |
698 | char *str = strdup(arg); | 698 | char *str = strdup(arg); |
@@ -909,18 +909,6 @@ static const char *ends_with(const char *str, const char *suffix) | |||
909 | return NULL; | 909 | return NULL; |
910 | } | 910 | } |
911 | 911 | ||
912 | static char *ltrim(char *str) | ||
913 | { | ||
914 | int len = strlen(str); | ||
915 | |||
916 | while (len && isspace(*str)) { | ||
917 | len--; | ||
918 | str++; | ||
919 | } | ||
920 | |||
921 | return str; | ||
922 | } | ||
923 | |||
924 | static int read_script_info(struct script_desc *desc, const char *filename) | 912 | static int read_script_info(struct script_desc *desc, const char *filename) |
925 | { | 913 | { |
926 | char line[BUFSIZ], *p; | 914 | char line[BUFSIZ], *p; |
@@ -1487,7 +1475,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1487 | return -1; | 1475 | return -1; |
1488 | } | 1476 | } |
1489 | 1477 | ||
1490 | perf_session__fprintf_info(session, stdout, show_full_info); | 1478 | if (!script_name && !generate_script_lang) |
1479 | perf_session__fprintf_info(session, stdout, show_full_info); | ||
1491 | 1480 | ||
1492 | if (!no_callchain) | 1481 | if (!no_callchain) |
1493 | symbol_conf.use_callchain = true; | 1482 | symbol_conf.use_callchain = true; |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index c247faca7127..99848761f573 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -65,6 +65,11 @@ | |||
65 | #define CNTR_NOT_SUPPORTED "<not supported>" | 65 | #define CNTR_NOT_SUPPORTED "<not supported>" |
66 | #define CNTR_NOT_COUNTED "<not counted>" | 66 | #define CNTR_NOT_COUNTED "<not counted>" |
67 | 67 | ||
68 | static void print_stat(int argc, const char **argv); | ||
69 | static void print_counter_aggr(struct perf_evsel *counter, char *prefix); | ||
70 | static void print_counter(struct perf_evsel *counter, char *prefix); | ||
71 | static void print_aggr_socket(char *prefix); | ||
72 | |||
68 | static struct perf_evlist *evsel_list; | 73 | static struct perf_evlist *evsel_list; |
69 | 74 | ||
70 | static struct perf_target target = { | 75 | static struct perf_target target = { |
@@ -75,6 +80,7 @@ static int run_count = 1; | |||
75 | static bool no_inherit = false; | 80 | static bool no_inherit = false; |
76 | static bool scale = true; | 81 | static bool scale = true; |
77 | static bool no_aggr = false; | 82 | static bool no_aggr = false; |
83 | static bool aggr_socket = false; | ||
78 | static pid_t child_pid = -1; | 84 | static pid_t child_pid = -1; |
79 | static bool null_run = false; | 85 | static bool null_run = false; |
80 | static int detailed_run = 0; | 86 | static int detailed_run = 0; |
@@ -87,6 +93,9 @@ static FILE *output = NULL; | |||
87 | static const char *pre_cmd = NULL; | 93 | static const char *pre_cmd = NULL; |
88 | static const char *post_cmd = NULL; | 94 | static const char *post_cmd = NULL; |
89 | static bool sync_run = false; | 95 | static bool sync_run = false; |
96 | static unsigned int interval = 0; | ||
97 | static struct timespec ref_time; | ||
98 | static struct cpu_map *sock_map; | ||
90 | 99 | ||
91 | static volatile int done = 0; | 100 | static volatile int done = 0; |
92 | 101 | ||
@@ -94,6 +103,28 @@ struct perf_stat { | |||
94 | struct stats res_stats[3]; | 103 | struct stats res_stats[3]; |
95 | }; | 104 | }; |
96 | 105 | ||
106 | static inline void diff_timespec(struct timespec *r, struct timespec *a, | ||
107 | struct timespec *b) | ||
108 | { | ||
109 | r->tv_sec = a->tv_sec - b->tv_sec; | ||
110 | if (a->tv_nsec < b->tv_nsec) { | ||
111 | r->tv_nsec = a->tv_nsec + 1000000000L - b->tv_nsec; | ||
112 | r->tv_sec--; | ||
113 | } else { | ||
114 | r->tv_nsec = a->tv_nsec - b->tv_nsec ; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | static inline struct cpu_map *perf_evsel__cpus(struct perf_evsel *evsel) | ||
119 | { | ||
120 | return (evsel->cpus && !target.cpu_list) ? evsel->cpus : evsel_list->cpus; | ||
121 | } | ||
122 | |||
123 | static inline int perf_evsel__nr_cpus(struct perf_evsel *evsel) | ||
124 | { | ||
125 | return perf_evsel__cpus(evsel)->nr; | ||
126 | } | ||
127 | |||
97 | static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel) | 128 | static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel) |
98 | { | 129 | { |
99 | evsel->priv = zalloc(sizeof(struct perf_stat)); | 130 | evsel->priv = zalloc(sizeof(struct perf_stat)); |
@@ -106,14 +137,27 @@ static void perf_evsel__free_stat_priv(struct perf_evsel *evsel) | |||
106 | evsel->priv = NULL; | 137 | evsel->priv = NULL; |
107 | } | 138 | } |
108 | 139 | ||
109 | static inline struct cpu_map *perf_evsel__cpus(struct perf_evsel *evsel) | 140 | static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel) |
110 | { | 141 | { |
111 | return (evsel->cpus && !target.cpu_list) ? evsel->cpus : evsel_list->cpus; | 142 | void *addr; |
143 | size_t sz; | ||
144 | |||
145 | sz = sizeof(*evsel->counts) + | ||
146 | (perf_evsel__nr_cpus(evsel) * sizeof(struct perf_counts_values)); | ||
147 | |||
148 | addr = zalloc(sz); | ||
149 | if (!addr) | ||
150 | return -ENOMEM; | ||
151 | |||
152 | evsel->prev_raw_counts = addr; | ||
153 | |||
154 | return 0; | ||
112 | } | 155 | } |
113 | 156 | ||
114 | static inline int perf_evsel__nr_cpus(struct perf_evsel *evsel) | 157 | static void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel) |
115 | { | 158 | { |
116 | return perf_evsel__cpus(evsel)->nr; | 159 | free(evsel->prev_raw_counts); |
160 | evsel->prev_raw_counts = NULL; | ||
117 | } | 161 | } |
118 | 162 | ||
119 | static struct stats runtime_nsecs_stats[MAX_NR_CPUS]; | 163 | static struct stats runtime_nsecs_stats[MAX_NR_CPUS]; |
@@ -132,8 +176,6 @@ static struct stats walltime_nsecs_stats; | |||
132 | static int create_perf_stat_counter(struct perf_evsel *evsel) | 176 | static int create_perf_stat_counter(struct perf_evsel *evsel) |
133 | { | 177 | { |
134 | struct perf_event_attr *attr = &evsel->attr; | 178 | struct perf_event_attr *attr = &evsel->attr; |
135 | bool exclude_guest_missing = false; | ||
136 | int ret; | ||
137 | 179 | ||
138 | if (scale) | 180 | if (scale) |
139 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | | 181 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | |
@@ -141,38 +183,16 @@ static int create_perf_stat_counter(struct perf_evsel *evsel) | |||
141 | 183 | ||
142 | attr->inherit = !no_inherit; | 184 | attr->inherit = !no_inherit; |
143 | 185 | ||
144 | retry: | 186 | if (perf_target__has_cpu(&target)) |
145 | if (exclude_guest_missing) | 187 | return perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel)); |
146 | evsel->attr.exclude_guest = evsel->attr.exclude_host = 0; | ||
147 | |||
148 | if (perf_target__has_cpu(&target)) { | ||
149 | ret = perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel)); | ||
150 | if (ret) | ||
151 | goto check_ret; | ||
152 | return 0; | ||
153 | } | ||
154 | 188 | ||
155 | if (!perf_target__has_task(&target) && | 189 | if (!perf_target__has_task(&target) && |
156 | !perf_evsel__is_group_member(evsel)) { | 190 | perf_evsel__is_group_leader(evsel)) { |
157 | attr->disabled = 1; | 191 | attr->disabled = 1; |
158 | attr->enable_on_exec = 1; | 192 | attr->enable_on_exec = 1; |
159 | } | 193 | } |
160 | 194 | ||
161 | ret = perf_evsel__open_per_thread(evsel, evsel_list->threads); | 195 | return perf_evsel__open_per_thread(evsel, evsel_list->threads); |
162 | if (!ret) | ||
163 | return 0; | ||
164 | /* fall through */ | ||
165 | check_ret: | ||
166 | if (ret && errno == EINVAL) { | ||
167 | if (!exclude_guest_missing && | ||
168 | (evsel->attr.exclude_guest || evsel->attr.exclude_host)) { | ||
169 | pr_debug("Old kernel, cannot exclude " | ||
170 | "guest or host samples.\n"); | ||
171 | exclude_guest_missing = true; | ||
172 | goto retry; | ||
173 | } | ||
174 | } | ||
175 | return ret; | ||
176 | } | 196 | } |
177 | 197 | ||
178 | /* | 198 | /* |
@@ -269,15 +289,79 @@ static int read_counter(struct perf_evsel *counter) | |||
269 | return 0; | 289 | return 0; |
270 | } | 290 | } |
271 | 291 | ||
292 | static void print_interval(void) | ||
293 | { | ||
294 | static int num_print_interval; | ||
295 | struct perf_evsel *counter; | ||
296 | struct perf_stat *ps; | ||
297 | struct timespec ts, rs; | ||
298 | char prefix[64]; | ||
299 | |||
300 | if (no_aggr) { | ||
301 | list_for_each_entry(counter, &evsel_list->entries, node) { | ||
302 | ps = counter->priv; | ||
303 | memset(ps->res_stats, 0, sizeof(ps->res_stats)); | ||
304 | read_counter(counter); | ||
305 | } | ||
306 | } else { | ||
307 | list_for_each_entry(counter, &evsel_list->entries, node) { | ||
308 | ps = counter->priv; | ||
309 | memset(ps->res_stats, 0, sizeof(ps->res_stats)); | ||
310 | read_counter_aggr(counter); | ||
311 | } | ||
312 | } | ||
313 | clock_gettime(CLOCK_MONOTONIC, &ts); | ||
314 | diff_timespec(&rs, &ts, &ref_time); | ||
315 | sprintf(prefix, "%6lu.%09lu%s", rs.tv_sec, rs.tv_nsec, csv_sep); | ||
316 | |||
317 | if (num_print_interval == 0 && !csv_output) { | ||
318 | if (aggr_socket) | ||
319 | fprintf(output, "# time socket cpus counts events\n"); | ||
320 | else if (no_aggr) | ||
321 | fprintf(output, "# time CPU counts events\n"); | ||
322 | else | ||
323 | fprintf(output, "# time counts events\n"); | ||
324 | } | ||
325 | |||
326 | if (++num_print_interval == 25) | ||
327 | num_print_interval = 0; | ||
328 | |||
329 | if (aggr_socket) | ||
330 | print_aggr_socket(prefix); | ||
331 | else if (no_aggr) { | ||
332 | list_for_each_entry(counter, &evsel_list->entries, node) | ||
333 | print_counter(counter, prefix); | ||
334 | } else { | ||
335 | list_for_each_entry(counter, &evsel_list->entries, node) | ||
336 | print_counter_aggr(counter, prefix); | ||
337 | } | ||
338 | } | ||
339 | |||
272 | static int __run_perf_stat(int argc __maybe_unused, const char **argv) | 340 | static int __run_perf_stat(int argc __maybe_unused, const char **argv) |
273 | { | 341 | { |
342 | char msg[512]; | ||
274 | unsigned long long t0, t1; | 343 | unsigned long long t0, t1; |
275 | struct perf_evsel *counter; | 344 | struct perf_evsel *counter; |
345 | struct timespec ts; | ||
276 | int status = 0; | 346 | int status = 0; |
277 | int child_ready_pipe[2], go_pipe[2]; | 347 | int child_ready_pipe[2], go_pipe[2]; |
278 | const bool forks = (argc > 0); | 348 | const bool forks = (argc > 0); |
279 | char buf; | 349 | char buf; |
280 | 350 | ||
351 | if (interval) { | ||
352 | ts.tv_sec = interval / 1000; | ||
353 | ts.tv_nsec = (interval % 1000) * 1000000; | ||
354 | } else { | ||
355 | ts.tv_sec = 1; | ||
356 | ts.tv_nsec = 0; | ||
357 | } | ||
358 | |||
359 | if (aggr_socket | ||
360 | && cpu_map__build_socket_map(evsel_list->cpus, &sock_map)) { | ||
361 | perror("cannot build socket map"); | ||
362 | return -1; | ||
363 | } | ||
364 | |||
281 | if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) { | 365 | if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) { |
282 | perror("failed to create pipes"); | 366 | perror("failed to create pipes"); |
283 | return -1; | 367 | return -1; |
@@ -348,20 +432,13 @@ static int __run_perf_stat(int argc __maybe_unused, const char **argv) | |||
348 | continue; | 432 | continue; |
349 | } | 433 | } |
350 | 434 | ||
351 | if (errno == EPERM || errno == EACCES) { | 435 | perf_evsel__open_strerror(counter, &target, |
352 | error("You may not have permission to collect %sstats.\n" | 436 | errno, msg, sizeof(msg)); |
353 | "\t Consider tweaking" | 437 | ui__error("%s\n", msg); |
354 | " /proc/sys/kernel/perf_event_paranoid or running as root.", | 438 | |
355 | target.system_wide ? "system-wide " : ""); | ||
356 | } else { | ||
357 | error("open_counter returned with %d (%s). " | ||
358 | "/bin/dmesg may provide additional information.\n", | ||
359 | errno, strerror(errno)); | ||
360 | } | ||
361 | if (child_pid != -1) | 439 | if (child_pid != -1) |
362 | kill(child_pid, SIGTERM); | 440 | kill(child_pid, SIGTERM); |
363 | 441 | ||
364 | pr_err("Not all events could be opened.\n"); | ||
365 | return -1; | 442 | return -1; |
366 | } | 443 | } |
367 | counter->supported = true; | 444 | counter->supported = true; |
@@ -377,14 +454,25 @@ static int __run_perf_stat(int argc __maybe_unused, const char **argv) | |||
377 | * Enable counters and exec the command: | 454 | * Enable counters and exec the command: |
378 | */ | 455 | */ |
379 | t0 = rdclock(); | 456 | t0 = rdclock(); |
457 | clock_gettime(CLOCK_MONOTONIC, &ref_time); | ||
380 | 458 | ||
381 | if (forks) { | 459 | if (forks) { |
382 | close(go_pipe[1]); | 460 | close(go_pipe[1]); |
461 | if (interval) { | ||
462 | while (!waitpid(child_pid, &status, WNOHANG)) { | ||
463 | nanosleep(&ts, NULL); | ||
464 | print_interval(); | ||
465 | } | ||
466 | } | ||
383 | wait(&status); | 467 | wait(&status); |
384 | if (WIFSIGNALED(status)) | 468 | if (WIFSIGNALED(status)) |
385 | psignal(WTERMSIG(status), argv[0]); | 469 | psignal(WTERMSIG(status), argv[0]); |
386 | } else { | 470 | } else { |
387 | while(!done) sleep(1); | 471 | while (!done) { |
472 | nanosleep(&ts, NULL); | ||
473 | if (interval) | ||
474 | print_interval(); | ||
475 | } | ||
388 | } | 476 | } |
389 | 477 | ||
390 | t1 = rdclock(); | 478 | t1 = rdclock(); |
@@ -454,13 +542,21 @@ static void print_noise(struct perf_evsel *evsel, double avg) | |||
454 | print_noise_pct(stddev_stats(&ps->res_stats[0]), avg); | 542 | print_noise_pct(stddev_stats(&ps->res_stats[0]), avg); |
455 | } | 543 | } |
456 | 544 | ||
457 | static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg) | 545 | static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) |
458 | { | 546 | { |
459 | double msecs = avg / 1e6; | 547 | double msecs = avg / 1e6; |
460 | char cpustr[16] = { '\0', }; | 548 | char cpustr[16] = { '\0', }; |
461 | const char *fmt = csv_output ? "%s%.6f%s%s" : "%s%18.6f%s%-25s"; | 549 | const char *fmt = csv_output ? "%s%.6f%s%s" : "%s%18.6f%s%-25s"; |
462 | 550 | ||
463 | if (no_aggr) | 551 | if (aggr_socket) |
552 | sprintf(cpustr, "S%*d%s%*d%s", | ||
553 | csv_output ? 0 : -5, | ||
554 | cpu, | ||
555 | csv_sep, | ||
556 | csv_output ? 0 : 4, | ||
557 | nr, | ||
558 | csv_sep); | ||
559 | else if (no_aggr) | ||
464 | sprintf(cpustr, "CPU%*d%s", | 560 | sprintf(cpustr, "CPU%*d%s", |
465 | csv_output ? 0 : -4, | 561 | csv_output ? 0 : -4, |
466 | perf_evsel__cpus(evsel)->map[cpu], csv_sep); | 562 | perf_evsel__cpus(evsel)->map[cpu], csv_sep); |
@@ -470,7 +566,7 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg) | |||
470 | if (evsel->cgrp) | 566 | if (evsel->cgrp) |
471 | fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); | 567 | fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); |
472 | 568 | ||
473 | if (csv_output) | 569 | if (csv_output || interval) |
474 | return; | 570 | return; |
475 | 571 | ||
476 | if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK)) | 572 | if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK)) |
@@ -659,7 +755,7 @@ static void print_ll_cache_misses(int cpu, | |||
659 | fprintf(output, " of all LL-cache hits "); | 755 | fprintf(output, " of all LL-cache hits "); |
660 | } | 756 | } |
661 | 757 | ||
662 | static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) | 758 | static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) |
663 | { | 759 | { |
664 | double total, ratio = 0.0; | 760 | double total, ratio = 0.0; |
665 | char cpustr[16] = { '\0', }; | 761 | char cpustr[16] = { '\0', }; |
@@ -672,7 +768,15 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) | |||
672 | else | 768 | else |
673 | fmt = "%s%18.0f%s%-25s"; | 769 | fmt = "%s%18.0f%s%-25s"; |
674 | 770 | ||
675 | if (no_aggr) | 771 | if (aggr_socket) |
772 | sprintf(cpustr, "S%*d%s%*d%s", | ||
773 | csv_output ? 0 : -5, | ||
774 | cpu, | ||
775 | csv_sep, | ||
776 | csv_output ? 0 : 4, | ||
777 | nr, | ||
778 | csv_sep); | ||
779 | else if (no_aggr) | ||
676 | sprintf(cpustr, "CPU%*d%s", | 780 | sprintf(cpustr, "CPU%*d%s", |
677 | csv_output ? 0 : -4, | 781 | csv_output ? 0 : -4, |
678 | perf_evsel__cpus(evsel)->map[cpu], csv_sep); | 782 | perf_evsel__cpus(evsel)->map[cpu], csv_sep); |
@@ -684,12 +788,11 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) | |||
684 | if (evsel->cgrp) | 788 | if (evsel->cgrp) |
685 | fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); | 789 | fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); |
686 | 790 | ||
687 | if (csv_output) | 791 | if (csv_output || interval) |
688 | return; | 792 | return; |
689 | 793 | ||
690 | if (perf_evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS)) { | 794 | if (perf_evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS)) { |
691 | total = avg_stats(&runtime_cycles_stats[cpu]); | 795 | total = avg_stats(&runtime_cycles_stats[cpu]); |
692 | |||
693 | if (total) | 796 | if (total) |
694 | ratio = avg / total; | 797 | ratio = avg / total; |
695 | 798 | ||
@@ -779,16 +882,83 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) | |||
779 | } | 882 | } |
780 | } | 883 | } |
781 | 884 | ||
885 | static void print_aggr_socket(char *prefix) | ||
886 | { | ||
887 | struct perf_evsel *counter; | ||
888 | u64 ena, run, val; | ||
889 | int cpu, s, s2, sock, nr; | ||
890 | |||
891 | if (!sock_map) | ||
892 | return; | ||
893 | |||
894 | for (s = 0; s < sock_map->nr; s++) { | ||
895 | sock = cpu_map__socket(sock_map, s); | ||
896 | list_for_each_entry(counter, &evsel_list->entries, node) { | ||
897 | val = ena = run = 0; | ||
898 | nr = 0; | ||
899 | for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { | ||
900 | s2 = cpu_map__get_socket(evsel_list->cpus, cpu); | ||
901 | if (s2 != sock) | ||
902 | continue; | ||
903 | val += counter->counts->cpu[cpu].val; | ||
904 | ena += counter->counts->cpu[cpu].ena; | ||
905 | run += counter->counts->cpu[cpu].run; | ||
906 | nr++; | ||
907 | } | ||
908 | if (prefix) | ||
909 | fprintf(output, "%s", prefix); | ||
910 | |||
911 | if (run == 0 || ena == 0) { | ||
912 | fprintf(output, "S%*d%s%*d%s%*s%s%*s", | ||
913 | csv_output ? 0 : -5, | ||
914 | s, | ||
915 | csv_sep, | ||
916 | csv_output ? 0 : 4, | ||
917 | nr, | ||
918 | csv_sep, | ||
919 | csv_output ? 0 : 18, | ||
920 | counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, | ||
921 | csv_sep, | ||
922 | csv_output ? 0 : -24, | ||
923 | perf_evsel__name(counter)); | ||
924 | if (counter->cgrp) | ||
925 | fprintf(output, "%s%s", | ||
926 | csv_sep, counter->cgrp->name); | ||
927 | |||
928 | fputc('\n', output); | ||
929 | continue; | ||
930 | } | ||
931 | |||
932 | if (nsec_counter(counter)) | ||
933 | nsec_printout(sock, nr, counter, val); | ||
934 | else | ||
935 | abs_printout(sock, nr, counter, val); | ||
936 | |||
937 | if (!csv_output) { | ||
938 | print_noise(counter, 1.0); | ||
939 | |||
940 | if (run != ena) | ||
941 | fprintf(output, " (%.2f%%)", | ||
942 | 100.0 * run / ena); | ||
943 | } | ||
944 | fputc('\n', output); | ||
945 | } | ||
946 | } | ||
947 | } | ||
948 | |||
782 | /* | 949 | /* |
783 | * Print out the results of a single counter: | 950 | * Print out the results of a single counter: |
784 | * aggregated counts in system-wide mode | 951 | * aggregated counts in system-wide mode |
785 | */ | 952 | */ |
786 | static void print_counter_aggr(struct perf_evsel *counter) | 953 | static void print_counter_aggr(struct perf_evsel *counter, char *prefix) |
787 | { | 954 | { |
788 | struct perf_stat *ps = counter->priv; | 955 | struct perf_stat *ps = counter->priv; |
789 | double avg = avg_stats(&ps->res_stats[0]); | 956 | double avg = avg_stats(&ps->res_stats[0]); |
790 | int scaled = counter->counts->scaled; | 957 | int scaled = counter->counts->scaled; |
791 | 958 | ||
959 | if (prefix) | ||
960 | fprintf(output, "%s", prefix); | ||
961 | |||
792 | if (scaled == -1) { | 962 | if (scaled == -1) { |
793 | fprintf(output, "%*s%s%*s", | 963 | fprintf(output, "%*s%s%*s", |
794 | csv_output ? 0 : 18, | 964 | csv_output ? 0 : 18, |
@@ -805,9 +975,9 @@ static void print_counter_aggr(struct perf_evsel *counter) | |||
805 | } | 975 | } |
806 | 976 | ||
807 | if (nsec_counter(counter)) | 977 | if (nsec_counter(counter)) |
808 | nsec_printout(-1, counter, avg); | 978 | nsec_printout(-1, 0, counter, avg); |
809 | else | 979 | else |
810 | abs_printout(-1, counter, avg); | 980 | abs_printout(-1, 0, counter, avg); |
811 | 981 | ||
812 | print_noise(counter, avg); | 982 | print_noise(counter, avg); |
813 | 983 | ||
@@ -831,7 +1001,7 @@ static void print_counter_aggr(struct perf_evsel *counter) | |||
831 | * Print out the results of a single counter: | 1001 | * Print out the results of a single counter: |
832 | * does not use aggregated count in system-wide | 1002 | * does not use aggregated count in system-wide |
833 | */ | 1003 | */ |
834 | static void print_counter(struct perf_evsel *counter) | 1004 | static void print_counter(struct perf_evsel *counter, char *prefix) |
835 | { | 1005 | { |
836 | u64 ena, run, val; | 1006 | u64 ena, run, val; |
837 | int cpu; | 1007 | int cpu; |
@@ -840,6 +1010,10 @@ static void print_counter(struct perf_evsel *counter) | |||
840 | val = counter->counts->cpu[cpu].val; | 1010 | val = counter->counts->cpu[cpu].val; |
841 | ena = counter->counts->cpu[cpu].ena; | 1011 | ena = counter->counts->cpu[cpu].ena; |
842 | run = counter->counts->cpu[cpu].run; | 1012 | run = counter->counts->cpu[cpu].run; |
1013 | |||
1014 | if (prefix) | ||
1015 | fprintf(output, "%s", prefix); | ||
1016 | |||
843 | if (run == 0 || ena == 0) { | 1017 | if (run == 0 || ena == 0) { |
844 | fprintf(output, "CPU%*d%s%*s%s%*s", | 1018 | fprintf(output, "CPU%*d%s%*s%s%*s", |
845 | csv_output ? 0 : -4, | 1019 | csv_output ? 0 : -4, |
@@ -859,9 +1033,9 @@ static void print_counter(struct perf_evsel *counter) | |||
859 | } | 1033 | } |
860 | 1034 | ||
861 | if (nsec_counter(counter)) | 1035 | if (nsec_counter(counter)) |
862 | nsec_printout(cpu, counter, val); | 1036 | nsec_printout(cpu, 0, counter, val); |
863 | else | 1037 | else |
864 | abs_printout(cpu, counter, val); | 1038 | abs_printout(cpu, 0, counter, val); |
865 | 1039 | ||
866 | if (!csv_output) { | 1040 | if (!csv_output) { |
867 | print_noise(counter, 1.0); | 1041 | print_noise(counter, 1.0); |
@@ -899,12 +1073,14 @@ static void print_stat(int argc, const char **argv) | |||
899 | fprintf(output, ":\n\n"); | 1073 | fprintf(output, ":\n\n"); |
900 | } | 1074 | } |
901 | 1075 | ||
902 | if (no_aggr) { | 1076 | if (aggr_socket) |
1077 | print_aggr_socket(NULL); | ||
1078 | else if (no_aggr) { | ||
903 | list_for_each_entry(counter, &evsel_list->entries, node) | 1079 | list_for_each_entry(counter, &evsel_list->entries, node) |
904 | print_counter(counter); | 1080 | print_counter(counter, NULL); |
905 | } else { | 1081 | } else { |
906 | list_for_each_entry(counter, &evsel_list->entries, node) | 1082 | list_for_each_entry(counter, &evsel_list->entries, node) |
907 | print_counter_aggr(counter); | 1083 | print_counter_aggr(counter, NULL); |
908 | } | 1084 | } |
909 | 1085 | ||
910 | if (!csv_output) { | 1086 | if (!csv_output) { |
@@ -925,7 +1101,7 @@ static volatile int signr = -1; | |||
925 | 1101 | ||
926 | static void skip_signal(int signo) | 1102 | static void skip_signal(int signo) |
927 | { | 1103 | { |
928 | if(child_pid == -1) | 1104 | if ((child_pid == -1) || interval) |
929 | done = 1; | 1105 | done = 1; |
930 | 1106 | ||
931 | signr = signo; | 1107 | signr = signo; |
@@ -1145,6 +1321,9 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1145 | "command to run prior to the measured command"), | 1321 | "command to run prior to the measured command"), |
1146 | OPT_STRING(0, "post", &post_cmd, "command", | 1322 | OPT_STRING(0, "post", &post_cmd, "command", |
1147 | "command to run after to the measured command"), | 1323 | "command to run after to the measured command"), |
1324 | OPT_UINTEGER('I', "interval-print", &interval, | ||
1325 | "print counts at regular interval in ms (>= 100)"), | ||
1326 | OPT_BOOLEAN(0, "aggr-socket", &aggr_socket, "aggregate counts per processor socket"), | ||
1148 | OPT_END() | 1327 | OPT_END() |
1149 | }; | 1328 | }; |
1150 | const char * const stat_usage[] = { | 1329 | const char * const stat_usage[] = { |
@@ -1231,6 +1410,14 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1231 | usage_with_options(stat_usage, options); | 1410 | usage_with_options(stat_usage, options); |
1232 | } | 1411 | } |
1233 | 1412 | ||
1413 | if (aggr_socket) { | ||
1414 | if (!perf_target__has_cpu(&target)) { | ||
1415 | fprintf(stderr, "--aggr-socket only available in system-wide mode (-a)\n"); | ||
1416 | usage_with_options(stat_usage, options); | ||
1417 | } | ||
1418 | no_aggr = true; | ||
1419 | } | ||
1420 | |||
1234 | if (add_default_attributes()) | 1421 | if (add_default_attributes()) |
1235 | goto out; | 1422 | goto out; |
1236 | 1423 | ||
@@ -1245,12 +1432,23 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1245 | usage_with_options(stat_usage, options); | 1432 | usage_with_options(stat_usage, options); |
1246 | return -1; | 1433 | return -1; |
1247 | } | 1434 | } |
1435 | if (interval && interval < 100) { | ||
1436 | pr_err("print interval must be >= 100ms\n"); | ||
1437 | usage_with_options(stat_usage, options); | ||
1438 | return -1; | ||
1439 | } | ||
1248 | 1440 | ||
1249 | list_for_each_entry(pos, &evsel_list->entries, node) { | 1441 | list_for_each_entry(pos, &evsel_list->entries, node) { |
1250 | if (perf_evsel__alloc_stat_priv(pos) < 0 || | 1442 | if (perf_evsel__alloc_stat_priv(pos) < 0 || |
1251 | perf_evsel__alloc_counts(pos, perf_evsel__nr_cpus(pos)) < 0) | 1443 | perf_evsel__alloc_counts(pos, perf_evsel__nr_cpus(pos)) < 0) |
1252 | goto out_free_fd; | 1444 | goto out_free_fd; |
1253 | } | 1445 | } |
1446 | if (interval) { | ||
1447 | list_for_each_entry(pos, &evsel_list->entries, node) { | ||
1448 | if (perf_evsel__alloc_prev_raw_counts(pos) < 0) | ||
1449 | goto out_free_fd; | ||
1450 | } | ||
1451 | } | ||
1254 | 1452 | ||
1255 | /* | 1453 | /* |
1256 | * We dont want to block the signals - that would cause | 1454 | * We dont want to block the signals - that would cause |
@@ -1260,6 +1458,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1260 | */ | 1458 | */ |
1261 | atexit(sig_atexit); | 1459 | atexit(sig_atexit); |
1262 | signal(SIGINT, skip_signal); | 1460 | signal(SIGINT, skip_signal); |
1461 | signal(SIGCHLD, skip_signal); | ||
1263 | signal(SIGALRM, skip_signal); | 1462 | signal(SIGALRM, skip_signal); |
1264 | signal(SIGABRT, skip_signal); | 1463 | signal(SIGABRT, skip_signal); |
1265 | 1464 | ||
@@ -1272,11 +1471,14 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1272 | status = run_perf_stat(argc, argv); | 1471 | status = run_perf_stat(argc, argv); |
1273 | } | 1472 | } |
1274 | 1473 | ||
1275 | if (status != -1) | 1474 | if (status != -1 && !interval) |
1276 | print_stat(argc, argv); | 1475 | print_stat(argc, argv); |
1277 | out_free_fd: | 1476 | out_free_fd: |
1278 | list_for_each_entry(pos, &evsel_list->entries, node) | 1477 | list_for_each_entry(pos, &evsel_list->entries, node) { |
1279 | perf_evsel__free_stat_priv(pos); | 1478 | perf_evsel__free_stat_priv(pos); |
1479 | perf_evsel__free_counts(pos); | ||
1480 | perf_evsel__free_prev_raw_counts(pos); | ||
1481 | } | ||
1280 | perf_evlist__delete_maps(evsel_list); | 1482 | perf_evlist__delete_maps(evsel_list); |
1281 | out: | 1483 | out: |
1282 | perf_evlist__delete(evsel_list); | 1484 | perf_evlist__delete(evsel_list); |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index c9ff3950cd4b..72f6eb7b4173 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -68,27 +68,7 @@ | |||
68 | #include <linux/unistd.h> | 68 | #include <linux/unistd.h> |
69 | #include <linux/types.h> | 69 | #include <linux/types.h> |
70 | 70 | ||
71 | void get_term_dimensions(struct winsize *ws) | 71 | static volatile int done; |
72 | { | ||
73 | char *s = getenv("LINES"); | ||
74 | |||
75 | if (s != NULL) { | ||
76 | ws->ws_row = atoi(s); | ||
77 | s = getenv("COLUMNS"); | ||
78 | if (s != NULL) { | ||
79 | ws->ws_col = atoi(s); | ||
80 | if (ws->ws_row && ws->ws_col) | ||
81 | return; | ||
82 | } | ||
83 | } | ||
84 | #ifdef TIOCGWINSZ | ||
85 | if (ioctl(1, TIOCGWINSZ, ws) == 0 && | ||
86 | ws->ws_row && ws->ws_col) | ||
87 | return; | ||
88 | #endif | ||
89 | ws->ws_row = 25; | ||
90 | ws->ws_col = 80; | ||
91 | } | ||
92 | 72 | ||
93 | static void perf_top__update_print_entries(struct perf_top *top) | 73 | static void perf_top__update_print_entries(struct perf_top *top) |
94 | { | 74 | { |
@@ -453,8 +433,10 @@ static int perf_top__key_mapped(struct perf_top *top, int c) | |||
453 | return 0; | 433 | return 0; |
454 | } | 434 | } |
455 | 435 | ||
456 | static void perf_top__handle_keypress(struct perf_top *top, int c) | 436 | static bool perf_top__handle_keypress(struct perf_top *top, int c) |
457 | { | 437 | { |
438 | bool ret = true; | ||
439 | |||
458 | if (!perf_top__key_mapped(top, c)) { | 440 | if (!perf_top__key_mapped(top, c)) { |
459 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; | 441 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; |
460 | struct termios tc, save; | 442 | struct termios tc, save; |
@@ -475,7 +457,7 @@ static void perf_top__handle_keypress(struct perf_top *top, int c) | |||
475 | 457 | ||
476 | tcsetattr(0, TCSAFLUSH, &save); | 458 | tcsetattr(0, TCSAFLUSH, &save); |
477 | if (!perf_top__key_mapped(top, c)) | 459 | if (!perf_top__key_mapped(top, c)) |
478 | return; | 460 | return ret; |
479 | } | 461 | } |
480 | 462 | ||
481 | switch (c) { | 463 | switch (c) { |
@@ -537,7 +519,8 @@ static void perf_top__handle_keypress(struct perf_top *top, int c) | |||
537 | printf("exiting.\n"); | 519 | printf("exiting.\n"); |
538 | if (top->dump_symtab) | 520 | if (top->dump_symtab) |
539 | perf_session__fprintf_dsos(top->session, stderr); | 521 | perf_session__fprintf_dsos(top->session, stderr); |
540 | exit(0); | 522 | ret = false; |
523 | break; | ||
541 | case 's': | 524 | case 's': |
542 | perf_top__prompt_symbol(top, "Enter details symbol"); | 525 | perf_top__prompt_symbol(top, "Enter details symbol"); |
543 | break; | 526 | break; |
@@ -560,6 +543,8 @@ static void perf_top__handle_keypress(struct perf_top *top, int c) | |||
560 | default: | 543 | default: |
561 | break; | 544 | break; |
562 | } | 545 | } |
546 | |||
547 | return ret; | ||
563 | } | 548 | } |
564 | 549 | ||
565 | static void perf_top__sort_new_samples(void *arg) | 550 | static void perf_top__sort_new_samples(void *arg) |
@@ -596,13 +581,12 @@ static void *display_thread_tui(void *arg) | |||
596 | * via --uid. | 581 | * via --uid. |
597 | */ | 582 | */ |
598 | list_for_each_entry(pos, &top->evlist->entries, node) | 583 | list_for_each_entry(pos, &top->evlist->entries, node) |
599 | pos->hists.uid_filter_str = top->target.uid_str; | 584 | pos->hists.uid_filter_str = top->record_opts.target.uid_str; |
600 | 585 | ||
601 | perf_evlist__tui_browse_hists(top->evlist, help, &hbt, | 586 | perf_evlist__tui_browse_hists(top->evlist, help, &hbt, |
602 | &top->session->header.env); | 587 | &top->session->header.env); |
603 | 588 | ||
604 | exit_browser(0); | 589 | done = 1; |
605 | exit(0); | ||
606 | return NULL; | 590 | return NULL; |
607 | } | 591 | } |
608 | 592 | ||
@@ -626,7 +610,7 @@ repeat: | |||
626 | /* trash return*/ | 610 | /* trash return*/ |
627 | getc(stdin); | 611 | getc(stdin); |
628 | 612 | ||
629 | while (1) { | 613 | while (!done) { |
630 | perf_top__print_sym_table(top); | 614 | perf_top__print_sym_table(top); |
631 | /* | 615 | /* |
632 | * Either timeout expired or we got an EINTR due to SIGWINCH, | 616 | * Either timeout expired or we got an EINTR due to SIGWINCH, |
@@ -640,15 +624,14 @@ repeat: | |||
640 | continue; | 624 | continue; |
641 | /* Fall trhu */ | 625 | /* Fall trhu */ |
642 | default: | 626 | default: |
643 | goto process_hotkey; | 627 | c = getc(stdin); |
628 | tcsetattr(0, TCSAFLUSH, &save); | ||
629 | |||
630 | if (perf_top__handle_keypress(top, c)) | ||
631 | goto repeat; | ||
632 | done = 1; | ||
644 | } | 633 | } |
645 | } | 634 | } |
646 | process_hotkey: | ||
647 | c = getc(stdin); | ||
648 | tcsetattr(0, TCSAFLUSH, &save); | ||
649 | |||
650 | perf_top__handle_keypress(top, c); | ||
651 | goto repeat; | ||
652 | 635 | ||
653 | return NULL; | 636 | return NULL; |
654 | } | 637 | } |
@@ -716,7 +699,7 @@ static void perf_event__process_sample(struct perf_tool *tool, | |||
716 | static struct intlist *seen; | 699 | static struct intlist *seen; |
717 | 700 | ||
718 | if (!seen) | 701 | if (!seen) |
719 | seen = intlist__new(); | 702 | seen = intlist__new(NULL); |
720 | 703 | ||
721 | if (!intlist__has_entry(seen, event->ip.pid)) { | 704 | if (!intlist__has_entry(seen, event->ip.pid)) { |
722 | pr_err("Can't find guest [%d]'s kernel information\n", | 705 | pr_err("Can't find guest [%d]'s kernel information\n", |
@@ -727,8 +710,8 @@ static void perf_event__process_sample(struct perf_tool *tool, | |||
727 | } | 710 | } |
728 | 711 | ||
729 | if (!machine) { | 712 | if (!machine) { |
730 | pr_err("%u unprocessable samples recorded.", | 713 | pr_err("%u unprocessable samples recorded.\r", |
731 | top->session->hists.stats.nr_unprocessable_samples++); | 714 | top->session->stats.nr_unprocessable_samples++); |
732 | return; | 715 | return; |
733 | } | 716 | } |
734 | 717 | ||
@@ -847,13 +830,13 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx) | |||
847 | ++top->us_samples; | 830 | ++top->us_samples; |
848 | if (top->hide_user_symbols) | 831 | if (top->hide_user_symbols) |
849 | continue; | 832 | continue; |
850 | machine = perf_session__find_host_machine(session); | 833 | machine = &session->machines.host; |
851 | break; | 834 | break; |
852 | case PERF_RECORD_MISC_KERNEL: | 835 | case PERF_RECORD_MISC_KERNEL: |
853 | ++top->kernel_samples; | 836 | ++top->kernel_samples; |
854 | if (top->hide_kernel_symbols) | 837 | if (top->hide_kernel_symbols) |
855 | continue; | 838 | continue; |
856 | machine = perf_session__find_host_machine(session); | 839 | machine = &session->machines.host; |
857 | break; | 840 | break; |
858 | case PERF_RECORD_MISC_GUEST_KERNEL: | 841 | case PERF_RECORD_MISC_GUEST_KERNEL: |
859 | ++top->guest_kernel_samples; | 842 | ++top->guest_kernel_samples; |
@@ -878,7 +861,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx) | |||
878 | hists__inc_nr_events(&evsel->hists, event->header.type); | 861 | hists__inc_nr_events(&evsel->hists, event->header.type); |
879 | machine__process_event(machine, event); | 862 | machine__process_event(machine, event); |
880 | } else | 863 | } else |
881 | ++session->hists.stats.nr_unknown_events; | 864 | ++session->stats.nr_unknown_events; |
882 | } | 865 | } |
883 | } | 866 | } |
884 | 867 | ||
@@ -890,123 +873,42 @@ static void perf_top__mmap_read(struct perf_top *top) | |||
890 | perf_top__mmap_read_idx(top, i); | 873 | perf_top__mmap_read_idx(top, i); |
891 | } | 874 | } |
892 | 875 | ||
893 | static void perf_top__start_counters(struct perf_top *top) | 876 | static int perf_top__start_counters(struct perf_top *top) |
894 | { | 877 | { |
878 | char msg[512]; | ||
895 | struct perf_evsel *counter; | 879 | struct perf_evsel *counter; |
896 | struct perf_evlist *evlist = top->evlist; | 880 | struct perf_evlist *evlist = top->evlist; |
881 | struct perf_record_opts *opts = &top->record_opts; | ||
897 | 882 | ||
898 | if (top->group) | 883 | perf_evlist__config(evlist, opts); |
899 | perf_evlist__set_leader(evlist); | ||
900 | 884 | ||
901 | list_for_each_entry(counter, &evlist->entries, node) { | 885 | list_for_each_entry(counter, &evlist->entries, node) { |
902 | struct perf_event_attr *attr = &counter->attr; | ||
903 | |||
904 | attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; | ||
905 | |||
906 | if (top->freq) { | ||
907 | attr->sample_type |= PERF_SAMPLE_PERIOD; | ||
908 | attr->freq = 1; | ||
909 | attr->sample_freq = top->freq; | ||
910 | } | ||
911 | |||
912 | if (evlist->nr_entries > 1) { | ||
913 | attr->sample_type |= PERF_SAMPLE_ID; | ||
914 | attr->read_format |= PERF_FORMAT_ID; | ||
915 | } | ||
916 | |||
917 | if (perf_target__has_cpu(&top->target)) | ||
918 | attr->sample_type |= PERF_SAMPLE_CPU; | ||
919 | |||
920 | if (symbol_conf.use_callchain) | ||
921 | attr->sample_type |= PERF_SAMPLE_CALLCHAIN; | ||
922 | |||
923 | attr->mmap = 1; | ||
924 | attr->comm = 1; | ||
925 | attr->inherit = top->inherit; | ||
926 | fallback_missing_features: | ||
927 | if (top->exclude_guest_missing) | ||
928 | attr->exclude_guest = attr->exclude_host = 0; | ||
929 | retry_sample_id: | ||
930 | attr->sample_id_all = top->sample_id_all_missing ? 0 : 1; | ||
931 | try_again: | 886 | try_again: |
932 | if (perf_evsel__open(counter, top->evlist->cpus, | 887 | if (perf_evsel__open(counter, top->evlist->cpus, |
933 | top->evlist->threads) < 0) { | 888 | top->evlist->threads) < 0) { |
934 | int err = errno; | 889 | if (perf_evsel__fallback(counter, errno, msg, sizeof(msg))) { |
935 | |||
936 | if (err == EPERM || err == EACCES) { | ||
937 | ui__error_paranoid(); | ||
938 | goto out_err; | ||
939 | } else if (err == EINVAL) { | ||
940 | if (!top->exclude_guest_missing && | ||
941 | (attr->exclude_guest || attr->exclude_host)) { | ||
942 | pr_debug("Old kernel, cannot exclude " | ||
943 | "guest or host samples.\n"); | ||
944 | top->exclude_guest_missing = true; | ||
945 | goto fallback_missing_features; | ||
946 | } else if (!top->sample_id_all_missing) { | ||
947 | /* | ||
948 | * Old kernel, no attr->sample_id_type_all field | ||
949 | */ | ||
950 | top->sample_id_all_missing = true; | ||
951 | goto retry_sample_id; | ||
952 | } | ||
953 | } | ||
954 | /* | ||
955 | * If it's cycles then fall back to hrtimer | ||
956 | * based cpu-clock-tick sw counter, which | ||
957 | * is always available even if no PMU support: | ||
958 | */ | ||
959 | if ((err == ENOENT || err == ENXIO) && | ||
960 | (attr->type == PERF_TYPE_HARDWARE) && | ||
961 | (attr->config == PERF_COUNT_HW_CPU_CYCLES)) { | ||
962 | |||
963 | if (verbose) | 890 | if (verbose) |
964 | ui__warning("Cycles event not supported,\n" | 891 | ui__warning("%s\n", msg); |
965 | "trying to fall back to cpu-clock-ticks\n"); | ||
966 | |||
967 | attr->type = PERF_TYPE_SOFTWARE; | ||
968 | attr->config = PERF_COUNT_SW_CPU_CLOCK; | ||
969 | if (counter->name) { | ||
970 | free(counter->name); | ||
971 | counter->name = NULL; | ||
972 | } | ||
973 | goto try_again; | 892 | goto try_again; |
974 | } | 893 | } |
975 | 894 | ||
976 | if (err == ENOENT) { | 895 | perf_evsel__open_strerror(counter, &opts->target, |
977 | ui__error("The %s event is not supported.\n", | 896 | errno, msg, sizeof(msg)); |
978 | perf_evsel__name(counter)); | 897 | ui__error("%s\n", msg); |
979 | goto out_err; | ||
980 | } else if (err == EMFILE) { | ||
981 | ui__error("Too many events are opened.\n" | ||
982 | "Try again after reducing the number of events\n"); | ||
983 | goto out_err; | ||
984 | } else if ((err == EOPNOTSUPP) && (attr->precise_ip)) { | ||
985 | ui__error("\'precise\' request may not be supported. " | ||
986 | "Try removing 'p' modifier\n"); | ||
987 | goto out_err; | ||
988 | } | ||
989 | |||
990 | ui__error("The sys_perf_event_open() syscall " | ||
991 | "returned with %d (%s). /bin/dmesg " | ||
992 | "may provide additional information.\n" | ||
993 | "No CONFIG_PERF_EVENTS=y kernel support " | ||
994 | "configured?\n", err, strerror(err)); | ||
995 | goto out_err; | 898 | goto out_err; |
996 | } | 899 | } |
997 | } | 900 | } |
998 | 901 | ||
999 | if (perf_evlist__mmap(evlist, top->mmap_pages, false) < 0) { | 902 | if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) { |
1000 | ui__error("Failed to mmap with %d (%s)\n", | 903 | ui__error("Failed to mmap with %d (%s)\n", |
1001 | errno, strerror(errno)); | 904 | errno, strerror(errno)); |
1002 | goto out_err; | 905 | goto out_err; |
1003 | } | 906 | } |
1004 | 907 | ||
1005 | return; | 908 | return 0; |
1006 | 909 | ||
1007 | out_err: | 910 | out_err: |
1008 | exit_browser(0); | 911 | return -1; |
1009 | exit(0); | ||
1010 | } | 912 | } |
1011 | 913 | ||
1012 | static int perf_top__setup_sample_type(struct perf_top *top) | 914 | static int perf_top__setup_sample_type(struct perf_top *top) |
@@ -1016,7 +918,7 @@ static int perf_top__setup_sample_type(struct perf_top *top) | |||
1016 | ui__error("Selected -g but \"sym\" not present in --sort/-s."); | 918 | ui__error("Selected -g but \"sym\" not present in --sort/-s."); |
1017 | return -EINVAL; | 919 | return -EINVAL; |
1018 | } | 920 | } |
1019 | } else if (!top->dont_use_callchains && callchain_param.mode != CHAIN_NONE) { | 921 | } else if (callchain_param.mode != CHAIN_NONE) { |
1020 | if (callchain_register_param(&callchain_param) < 0) { | 922 | if (callchain_register_param(&callchain_param) < 0) { |
1021 | ui__error("Can't register callchain params.\n"); | 923 | ui__error("Can't register callchain params.\n"); |
1022 | return -EINVAL; | 924 | return -EINVAL; |
@@ -1028,6 +930,7 @@ static int perf_top__setup_sample_type(struct perf_top *top) | |||
1028 | 930 | ||
1029 | static int __cmd_top(struct perf_top *top) | 931 | static int __cmd_top(struct perf_top *top) |
1030 | { | 932 | { |
933 | struct perf_record_opts *opts = &top->record_opts; | ||
1031 | pthread_t thread; | 934 | pthread_t thread; |
1032 | int ret; | 935 | int ret; |
1033 | /* | 936 | /* |
@@ -1042,26 +945,42 @@ static int __cmd_top(struct perf_top *top) | |||
1042 | if (ret) | 945 | if (ret) |
1043 | goto out_delete; | 946 | goto out_delete; |
1044 | 947 | ||
1045 | if (perf_target__has_task(&top->target)) | 948 | if (perf_target__has_task(&opts->target)) |
1046 | perf_event__synthesize_thread_map(&top->tool, top->evlist->threads, | 949 | perf_event__synthesize_thread_map(&top->tool, top->evlist->threads, |
1047 | perf_event__process, | 950 | perf_event__process, |
1048 | &top->session->host_machine); | 951 | &top->session->machines.host); |
1049 | else | 952 | else |
1050 | perf_event__synthesize_threads(&top->tool, perf_event__process, | 953 | perf_event__synthesize_threads(&top->tool, perf_event__process, |
1051 | &top->session->host_machine); | 954 | &top->session->machines.host); |
1052 | perf_top__start_counters(top); | 955 | |
956 | ret = perf_top__start_counters(top); | ||
957 | if (ret) | ||
958 | goto out_delete; | ||
959 | |||
1053 | top->session->evlist = top->evlist; | 960 | top->session->evlist = top->evlist; |
1054 | perf_session__set_id_hdr_size(top->session); | 961 | perf_session__set_id_hdr_size(top->session); |
1055 | 962 | ||
963 | /* | ||
964 | * When perf is starting the traced process, all the events (apart from | ||
965 | * group members) have enable_on_exec=1 set, so don't spoil it by | ||
966 | * prematurely enabling them. | ||
967 | * | ||
968 | * XXX 'top' still doesn't start workloads like record, trace, but should, | ||
969 | * so leave the check here. | ||
970 | */ | ||
971 | if (!perf_target__none(&opts->target)) | ||
972 | perf_evlist__enable(top->evlist); | ||
973 | |||
1056 | /* Wait for a minimal set of events before starting the snapshot */ | 974 | /* Wait for a minimal set of events before starting the snapshot */ |
1057 | poll(top->evlist->pollfd, top->evlist->nr_fds, 100); | 975 | poll(top->evlist->pollfd, top->evlist->nr_fds, 100); |
1058 | 976 | ||
1059 | perf_top__mmap_read(top); | 977 | perf_top__mmap_read(top); |
1060 | 978 | ||
979 | ret = -1; | ||
1061 | if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui : | 980 | if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui : |
1062 | display_thread), top)) { | 981 | display_thread), top)) { |
1063 | ui__error("Could not create display thread.\n"); | 982 | ui__error("Could not create display thread.\n"); |
1064 | exit(-1); | 983 | goto out_delete; |
1065 | } | 984 | } |
1066 | 985 | ||
1067 | if (top->realtime_prio) { | 986 | if (top->realtime_prio) { |
@@ -1070,11 +989,11 @@ static int __cmd_top(struct perf_top *top) | |||
1070 | param.sched_priority = top->realtime_prio; | 989 | param.sched_priority = top->realtime_prio; |
1071 | if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { | 990 | if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { |
1072 | ui__error("Could not set realtime priority.\n"); | 991 | ui__error("Could not set realtime priority.\n"); |
1073 | exit(-1); | 992 | goto out_delete; |
1074 | } | 993 | } |
1075 | } | 994 | } |
1076 | 995 | ||
1077 | while (1) { | 996 | while (!done) { |
1078 | u64 hits = top->samples; | 997 | u64 hits = top->samples; |
1079 | 998 | ||
1080 | perf_top__mmap_read(top); | 999 | perf_top__mmap_read(top); |
@@ -1083,126 +1002,67 @@ static int __cmd_top(struct perf_top *top) | |||
1083 | ret = poll(top->evlist->pollfd, top->evlist->nr_fds, 100); | 1002 | ret = poll(top->evlist->pollfd, top->evlist->nr_fds, 100); |
1084 | } | 1003 | } |
1085 | 1004 | ||
1005 | ret = 0; | ||
1086 | out_delete: | 1006 | out_delete: |
1087 | perf_session__delete(top->session); | 1007 | perf_session__delete(top->session); |
1088 | top->session = NULL; | 1008 | top->session = NULL; |
1089 | 1009 | ||
1090 | return 0; | 1010 | return ret; |
1091 | } | 1011 | } |
1092 | 1012 | ||
1093 | static int | 1013 | static int |
1094 | parse_callchain_opt(const struct option *opt, const char *arg, int unset) | 1014 | parse_callchain_opt(const struct option *opt, const char *arg, int unset) |
1095 | { | 1015 | { |
1096 | struct perf_top *top = (struct perf_top *)opt->value; | ||
1097 | char *tok, *tok2; | ||
1098 | char *endptr; | ||
1099 | |||
1100 | /* | 1016 | /* |
1101 | * --no-call-graph | 1017 | * --no-call-graph |
1102 | */ | 1018 | */ |
1103 | if (unset) { | 1019 | if (unset) |
1104 | top->dont_use_callchains = true; | ||
1105 | return 0; | 1020 | return 0; |
1106 | } | ||
1107 | 1021 | ||
1108 | symbol_conf.use_callchain = true; | 1022 | symbol_conf.use_callchain = true; |
1109 | 1023 | ||
1110 | if (!arg) | 1024 | return record_parse_callchain_opt(opt, arg, unset); |
1111 | return 0; | ||
1112 | |||
1113 | tok = strtok((char *)arg, ","); | ||
1114 | if (!tok) | ||
1115 | return -1; | ||
1116 | |||
1117 | /* get the output mode */ | ||
1118 | if (!strncmp(tok, "graph", strlen(arg))) | ||
1119 | callchain_param.mode = CHAIN_GRAPH_ABS; | ||
1120 | |||
1121 | else if (!strncmp(tok, "flat", strlen(arg))) | ||
1122 | callchain_param.mode = CHAIN_FLAT; | ||
1123 | |||
1124 | else if (!strncmp(tok, "fractal", strlen(arg))) | ||
1125 | callchain_param.mode = CHAIN_GRAPH_REL; | ||
1126 | |||
1127 | else if (!strncmp(tok, "none", strlen(arg))) { | ||
1128 | callchain_param.mode = CHAIN_NONE; | ||
1129 | symbol_conf.use_callchain = false; | ||
1130 | |||
1131 | return 0; | ||
1132 | } else | ||
1133 | return -1; | ||
1134 | |||
1135 | /* get the min percentage */ | ||
1136 | tok = strtok(NULL, ","); | ||
1137 | if (!tok) | ||
1138 | goto setup; | ||
1139 | |||
1140 | callchain_param.min_percent = strtod(tok, &endptr); | ||
1141 | if (tok == endptr) | ||
1142 | return -1; | ||
1143 | |||
1144 | /* get the print limit */ | ||
1145 | tok2 = strtok(NULL, ","); | ||
1146 | if (!tok2) | ||
1147 | goto setup; | ||
1148 | |||
1149 | if (tok2[0] != 'c') { | ||
1150 | callchain_param.print_limit = strtod(tok2, &endptr); | ||
1151 | tok2 = strtok(NULL, ","); | ||
1152 | if (!tok2) | ||
1153 | goto setup; | ||
1154 | } | ||
1155 | |||
1156 | /* get the call chain order */ | ||
1157 | if (!strcmp(tok2, "caller")) | ||
1158 | callchain_param.order = ORDER_CALLER; | ||
1159 | else if (!strcmp(tok2, "callee")) | ||
1160 | callchain_param.order = ORDER_CALLEE; | ||
1161 | else | ||
1162 | return -1; | ||
1163 | setup: | ||
1164 | if (callchain_register_param(&callchain_param) < 0) { | ||
1165 | fprintf(stderr, "Can't register callchain params\n"); | ||
1166 | return -1; | ||
1167 | } | ||
1168 | return 0; | ||
1169 | } | 1025 | } |
1170 | 1026 | ||
1171 | int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | 1027 | int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) |
1172 | { | 1028 | { |
1173 | struct perf_evsel *pos; | ||
1174 | int status; | 1029 | int status; |
1175 | char errbuf[BUFSIZ]; | 1030 | char errbuf[BUFSIZ]; |
1176 | struct perf_top top = { | 1031 | struct perf_top top = { |
1177 | .count_filter = 5, | 1032 | .count_filter = 5, |
1178 | .delay_secs = 2, | 1033 | .delay_secs = 2, |
1179 | .freq = 4000, /* 4 KHz */ | 1034 | .record_opts = { |
1180 | .mmap_pages = 128, | 1035 | .mmap_pages = UINT_MAX, |
1181 | .sym_pcnt_filter = 5, | 1036 | .user_freq = UINT_MAX, |
1182 | .target = { | 1037 | .user_interval = ULLONG_MAX, |
1183 | .uses_mmap = true, | 1038 | .freq = 4000, /* 4 KHz */ |
1039 | .target = { | ||
1040 | .uses_mmap = true, | ||
1041 | }, | ||
1184 | }, | 1042 | }, |
1043 | .sym_pcnt_filter = 5, | ||
1185 | }; | 1044 | }; |
1186 | char callchain_default_opt[] = "fractal,0.5,callee"; | 1045 | struct perf_record_opts *opts = &top.record_opts; |
1046 | struct perf_target *target = &opts->target; | ||
1187 | const struct option options[] = { | 1047 | const struct option options[] = { |
1188 | OPT_CALLBACK('e', "event", &top.evlist, "event", | 1048 | OPT_CALLBACK('e', "event", &top.evlist, "event", |
1189 | "event selector. use 'perf list' to list available events", | 1049 | "event selector. use 'perf list' to list available events", |
1190 | parse_events_option), | 1050 | parse_events_option), |
1191 | OPT_INTEGER('c', "count", &top.default_interval, | 1051 | OPT_U64('c', "count", &opts->user_interval, "event period to sample"), |
1192 | "event period to sample"), | 1052 | OPT_STRING('p', "pid", &target->pid, "pid", |
1193 | OPT_STRING('p', "pid", &top.target.pid, "pid", | ||
1194 | "profile events on existing process id"), | 1053 | "profile events on existing process id"), |
1195 | OPT_STRING('t', "tid", &top.target.tid, "tid", | 1054 | OPT_STRING('t', "tid", &target->tid, "tid", |
1196 | "profile events on existing thread id"), | 1055 | "profile events on existing thread id"), |
1197 | OPT_BOOLEAN('a', "all-cpus", &top.target.system_wide, | 1056 | OPT_BOOLEAN('a', "all-cpus", &target->system_wide, |
1198 | "system-wide collection from all CPUs"), | 1057 | "system-wide collection from all CPUs"), |
1199 | OPT_STRING('C', "cpu", &top.target.cpu_list, "cpu", | 1058 | OPT_STRING('C', "cpu", &target->cpu_list, "cpu", |
1200 | "list of cpus to monitor"), | 1059 | "list of cpus to monitor"), |
1201 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, | 1060 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, |
1202 | "file", "vmlinux pathname"), | 1061 | "file", "vmlinux pathname"), |
1203 | OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols, | 1062 | OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols, |
1204 | "hide kernel symbols"), | 1063 | "hide kernel symbols"), |
1205 | OPT_UINTEGER('m', "mmap-pages", &top.mmap_pages, "number of mmap data pages"), | 1064 | OPT_UINTEGER('m', "mmap-pages", &opts->mmap_pages, |
1065 | "number of mmap data pages"), | ||
1206 | OPT_INTEGER('r', "realtime", &top.realtime_prio, | 1066 | OPT_INTEGER('r', "realtime", &top.realtime_prio, |
1207 | "collect data with this RT SCHED_FIFO priority"), | 1067 | "collect data with this RT SCHED_FIFO priority"), |
1208 | OPT_INTEGER('d', "delay", &top.delay_secs, | 1068 | OPT_INTEGER('d', "delay", &top.delay_secs, |
@@ -1211,16 +1071,14 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1211 | "dump the symbol table used for profiling"), | 1071 | "dump the symbol table used for profiling"), |
1212 | OPT_INTEGER('f', "count-filter", &top.count_filter, | 1072 | OPT_INTEGER('f', "count-filter", &top.count_filter, |
1213 | "only display functions with more events than this"), | 1073 | "only display functions with more events than this"), |
1214 | OPT_BOOLEAN('g', "group", &top.group, | 1074 | OPT_BOOLEAN('g', "group", &opts->group, |
1215 | "put the counters into a counter group"), | 1075 | "put the counters into a counter group"), |
1216 | OPT_BOOLEAN('i', "inherit", &top.inherit, | 1076 | OPT_BOOLEAN('i', "no-inherit", &opts->no_inherit, |
1217 | "child tasks inherit counters"), | 1077 | "child tasks do not inherit counters"), |
1218 | OPT_STRING(0, "sym-annotate", &top.sym_filter, "symbol name", | 1078 | OPT_STRING(0, "sym-annotate", &top.sym_filter, "symbol name", |
1219 | "symbol to annotate"), | 1079 | "symbol to annotate"), |
1220 | OPT_BOOLEAN('z', "zero", &top.zero, | 1080 | OPT_BOOLEAN('z', "zero", &top.zero, "zero history across updates"), |
1221 | "zero history across updates"), | 1081 | OPT_UINTEGER('F', "freq", &opts->user_freq, "profile at this frequency"), |
1222 | OPT_INTEGER('F', "freq", &top.freq, | ||
1223 | "profile at this frequency"), | ||
1224 | OPT_INTEGER('E', "entries", &top.print_entries, | 1082 | OPT_INTEGER('E', "entries", &top.print_entries, |
1225 | "display this many functions"), | 1083 | "display this many functions"), |
1226 | OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols, | 1084 | OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols, |
@@ -1233,10 +1091,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1233 | "sort by key(s): pid, comm, dso, symbol, parent"), | 1091 | "sort by key(s): pid, comm, dso, symbol, parent"), |
1234 | OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, | 1092 | OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, |
1235 | "Show a column with the number of samples"), | 1093 | "Show a column with the number of samples"), |
1236 | OPT_CALLBACK_DEFAULT('G', "call-graph", &top, "output_type,min_percent, call_order", | 1094 | OPT_CALLBACK_DEFAULT('G', "call-graph", &top.record_opts, |
1237 | "Display callchains using output_type (graph, flat, fractal, or none), min percent threshold and callchain order. " | 1095 | "mode[,dump_size]", record_callchain_help, |
1238 | "Default: fractal,0.5,callee", &parse_callchain_opt, | 1096 | &parse_callchain_opt, "fp"), |
1239 | callchain_default_opt), | ||
1240 | OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, | 1097 | OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, |
1241 | "Show a column with the sum of periods"), | 1098 | "Show a column with the sum of periods"), |
1242 | OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", | 1099 | OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", |
@@ -1251,7 +1108,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1251 | "Display raw encoding of assembly instructions (default)"), | 1108 | "Display raw encoding of assembly instructions (default)"), |
1252 | OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", | 1109 | OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", |
1253 | "Specify disassembler style (e.g. -M intel for intel syntax)"), | 1110 | "Specify disassembler style (e.g. -M intel for intel syntax)"), |
1254 | OPT_STRING('u', "uid", &top.target.uid_str, "user", "user to profile"), | 1111 | OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"), |
1255 | OPT_END() | 1112 | OPT_END() |
1256 | }; | 1113 | }; |
1257 | const char * const top_usage[] = { | 1114 | const char * const top_usage[] = { |
@@ -1272,7 +1129,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1272 | if (sort_order == default_sort_order) | 1129 | if (sort_order == default_sort_order) |
1273 | sort_order = "dso,symbol"; | 1130 | sort_order = "dso,symbol"; |
1274 | 1131 | ||
1275 | setup_sorting(top_usage, options); | 1132 | if (setup_sorting() < 0) |
1133 | usage_with_options(top_usage, options); | ||
1276 | 1134 | ||
1277 | if (top.use_stdio) | 1135 | if (top.use_stdio) |
1278 | use_browser = 0; | 1136 | use_browser = 0; |
@@ -1281,33 +1139,33 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1281 | 1139 | ||
1282 | setup_browser(false); | 1140 | setup_browser(false); |
1283 | 1141 | ||
1284 | status = perf_target__validate(&top.target); | 1142 | status = perf_target__validate(target); |
1285 | if (status) { | 1143 | if (status) { |
1286 | perf_target__strerror(&top.target, status, errbuf, BUFSIZ); | 1144 | perf_target__strerror(target, status, errbuf, BUFSIZ); |
1287 | ui__warning("%s", errbuf); | 1145 | ui__warning("%s", errbuf); |
1288 | } | 1146 | } |
1289 | 1147 | ||
1290 | status = perf_target__parse_uid(&top.target); | 1148 | status = perf_target__parse_uid(target); |
1291 | if (status) { | 1149 | if (status) { |
1292 | int saved_errno = errno; | 1150 | int saved_errno = errno; |
1293 | 1151 | ||
1294 | perf_target__strerror(&top.target, status, errbuf, BUFSIZ); | 1152 | perf_target__strerror(target, status, errbuf, BUFSIZ); |
1295 | ui__error("%s", errbuf); | 1153 | ui__error("%s", errbuf); |
1296 | 1154 | ||
1297 | status = -saved_errno; | 1155 | status = -saved_errno; |
1298 | goto out_delete_evlist; | 1156 | goto out_delete_evlist; |
1299 | } | 1157 | } |
1300 | 1158 | ||
1301 | if (perf_target__none(&top.target)) | 1159 | if (perf_target__none(target)) |
1302 | top.target.system_wide = true; | 1160 | target->system_wide = true; |
1303 | 1161 | ||
1304 | if (perf_evlist__create_maps(top.evlist, &top.target) < 0) | 1162 | if (perf_evlist__create_maps(top.evlist, target) < 0) |
1305 | usage_with_options(top_usage, options); | 1163 | usage_with_options(top_usage, options); |
1306 | 1164 | ||
1307 | if (!top.evlist->nr_entries && | 1165 | if (!top.evlist->nr_entries && |
1308 | perf_evlist__add_default(top.evlist) < 0) { | 1166 | perf_evlist__add_default(top.evlist) < 0) { |
1309 | ui__error("Not enough memory for event selector list\n"); | 1167 | ui__error("Not enough memory for event selector list\n"); |
1310 | return -ENOMEM; | 1168 | goto out_delete_maps; |
1311 | } | 1169 | } |
1312 | 1170 | ||
1313 | symbol_conf.nr_events = top.evlist->nr_entries; | 1171 | symbol_conf.nr_events = top.evlist->nr_entries; |
@@ -1315,24 +1173,22 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1315 | if (top.delay_secs < 1) | 1173 | if (top.delay_secs < 1) |
1316 | top.delay_secs = 1; | 1174 | top.delay_secs = 1; |
1317 | 1175 | ||
1176 | if (opts->user_interval != ULLONG_MAX) | ||
1177 | opts->default_interval = opts->user_interval; | ||
1178 | if (opts->user_freq != UINT_MAX) | ||
1179 | opts->freq = opts->user_freq; | ||
1180 | |||
1318 | /* | 1181 | /* |
1319 | * User specified count overrides default frequency. | 1182 | * User specified count overrides default frequency. |
1320 | */ | 1183 | */ |
1321 | if (top.default_interval) | 1184 | if (opts->default_interval) |
1322 | top.freq = 0; | 1185 | opts->freq = 0; |
1323 | else if (top.freq) { | 1186 | else if (opts->freq) { |
1324 | top.default_interval = top.freq; | 1187 | opts->default_interval = opts->freq; |
1325 | } else { | 1188 | } else { |
1326 | ui__error("frequency and count are zero, aborting\n"); | 1189 | ui__error("frequency and count are zero, aborting\n"); |
1327 | exit(EXIT_FAILURE); | 1190 | status = -EINVAL; |
1328 | } | 1191 | goto out_delete_maps; |
1329 | |||
1330 | list_for_each_entry(pos, &top.evlist->entries, node) { | ||
1331 | /* | ||
1332 | * Fill in the ones not specifically initialized via -c: | ||
1333 | */ | ||
1334 | if (!pos->attr.sample_period) | ||
1335 | pos->attr.sample_period = top.default_interval; | ||
1336 | } | 1192 | } |
1337 | 1193 | ||
1338 | top.sym_evsel = perf_evlist__first(top.evlist); | 1194 | top.sym_evsel = perf_evlist__first(top.evlist); |
@@ -1365,6 +1221,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1365 | 1221 | ||
1366 | status = __cmd_top(&top); | 1222 | status = __cmd_top(&top); |
1367 | 1223 | ||
1224 | out_delete_maps: | ||
1225 | perf_evlist__delete_maps(top.evlist); | ||
1368 | out_delete_evlist: | 1226 | out_delete_evlist: |
1369 | perf_evlist__delete(top.evlist); | 1227 | perf_evlist__delete(top.evlist); |
1370 | 1228 | ||
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 7932ffa29889..d222d7fc7e96 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -455,7 +455,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv) | |||
455 | goto out_delete_evlist; | 455 | goto out_delete_evlist; |
456 | } | 456 | } |
457 | 457 | ||
458 | perf_evlist__config_attrs(evlist, &trace->opts); | 458 | perf_evlist__config(evlist, &trace->opts); |
459 | 459 | ||
460 | signal(SIGCHLD, sig_handler); | 460 | signal(SIGCHLD, sig_handler); |
461 | signal(SIGINT, sig_handler); | 461 | signal(SIGINT, sig_handler); |
diff --git a/tools/perf/config/feature-tests.mak b/tools/perf/config/feature-tests.mak index f5ac77485a4f..b4eabb44e381 100644 --- a/tools/perf/config/feature-tests.mak +++ b/tools/perf/config/feature-tests.mak | |||
@@ -225,3 +225,14 @@ int main(void) | |||
225 | return on_exit(NULL, NULL); | 225 | return on_exit(NULL, NULL); |
226 | } | 226 | } |
227 | endef | 227 | endef |
228 | |||
229 | define SOURCE_LIBNUMA | ||
230 | #include <numa.h> | ||
231 | #include <numaif.h> | ||
232 | |||
233 | int main(void) | ||
234 | { | ||
235 | numa_available(); | ||
236 | return 0; | ||
237 | } | ||
238 | endef \ No newline at end of file | ||
diff --git a/tools/perf/config/utilities.mak b/tools/perf/config/utilities.mak index e5413125e6bb..8ef3bd30a549 100644 --- a/tools/perf/config/utilities.mak +++ b/tools/perf/config/utilities.mak | |||
@@ -13,7 +13,7 @@ newline := $(newline) | |||
13 | # what should replace a newline when escaping | 13 | # what should replace a newline when escaping |
14 | # newlines; the default is a bizarre string. | 14 | # newlines; the default is a bizarre string. |
15 | # | 15 | # |
16 | nl-escape = $(or $(1),m822df3020w6a44id34bt574ctac44eb9f4n) | 16 | nl-escape = $(if $(1),$(1),m822df3020w6a44id34bt574ctac44eb9f4n) |
17 | 17 | ||
18 | # escape-nl | 18 | # escape-nl |
19 | # | 19 | # |
@@ -173,9 +173,9 @@ _ge-abspath = $(if $(is-executable),$(1)) | |||
173 | # Usage: absolute-executable-path-or-empty = $(call get-executable-or-default,variable,default) | 173 | # Usage: absolute-executable-path-or-empty = $(call get-executable-or-default,variable,default) |
174 | # | 174 | # |
175 | define get-executable-or-default | 175 | define get-executable-or-default |
176 | $(if $($(1)),$(call _ge_attempt,$($(1)),$(1)),$(call _ge_attempt,$(2))) | 176 | $(if $($(1)),$(call _ge_attempt,$($(1)),$(1)),$(call _ge_attempt,$(2),$(1))) |
177 | endef | 177 | endef |
178 | _ge_attempt = $(or $(get-executable),$(_gea_warn),$(call _gea_err,$(2))) | 178 | _ge_attempt = $(if $(get-executable),$(get-executable),$(_gea_warn)$(call _gea_err,$(2))) |
179 | _gea_warn = $(warning The path '$(1)' is not executable.) | 179 | _gea_warn = $(warning The path '$(1)' is not executable.) |
180 | _gea_err = $(if $(1),$(error Please set '$(1)' appropriately)) | 180 | _gea_err = $(if $(1),$(error Please set '$(1)' appropriately)) |
181 | 181 | ||
diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 0f661fbce6a8..095b88207cd3 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c | |||
@@ -328,14 +328,23 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv) | |||
328 | if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) | 328 | if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) |
329 | return 0; | 329 | return 0; |
330 | 330 | ||
331 | status = 1; | ||
331 | /* Check for ENOSPC and EIO errors.. */ | 332 | /* Check for ENOSPC and EIO errors.. */ |
332 | if (fflush(stdout)) | 333 | if (fflush(stdout)) { |
333 | die("write failure on standard output: %s", strerror(errno)); | 334 | fprintf(stderr, "write failure on standard output: %s", strerror(errno)); |
334 | if (ferror(stdout)) | 335 | goto out; |
335 | die("unknown write failure on standard output"); | 336 | } |
336 | if (fclose(stdout)) | 337 | if (ferror(stdout)) { |
337 | die("close failed on standard output: %s", strerror(errno)); | 338 | fprintf(stderr, "unknown write failure on standard output"); |
338 | return 0; | 339 | goto out; |
340 | } | ||
341 | if (fclose(stdout)) { | ||
342 | fprintf(stderr, "close failed on standard output: %s", strerror(errno)); | ||
343 | goto out; | ||
344 | } | ||
345 | status = 0; | ||
346 | out: | ||
347 | return status; | ||
339 | } | 348 | } |
340 | 349 | ||
341 | static void handle_internal_command(int argc, const char **argv) | 350 | static void handle_internal_command(int argc, const char **argv) |
@@ -467,7 +476,8 @@ int main(int argc, const char **argv) | |||
467 | cmd += 5; | 476 | cmd += 5; |
468 | argv[0] = cmd; | 477 | argv[0] = cmd; |
469 | handle_internal_command(argc, argv); | 478 | handle_internal_command(argc, argv); |
470 | die("cannot handle %s internally", cmd); | 479 | fprintf(stderr, "cannot handle %s internally", cmd); |
480 | goto out; | ||
471 | } | 481 | } |
472 | 482 | ||
473 | /* Look for flags.. */ | 483 | /* Look for flags.. */ |
@@ -485,7 +495,7 @@ int main(int argc, const char **argv) | |||
485 | printf("\n usage: %s\n\n", perf_usage_string); | 495 | printf("\n usage: %s\n\n", perf_usage_string); |
486 | list_common_cmds_help(); | 496 | list_common_cmds_help(); |
487 | printf("\n %s\n\n", perf_more_info_string); | 497 | printf("\n %s\n\n", perf_more_info_string); |
488 | exit(1); | 498 | goto out; |
489 | } | 499 | } |
490 | cmd = argv[0]; | 500 | cmd = argv[0]; |
491 | 501 | ||
@@ -517,7 +527,7 @@ int main(int argc, const char **argv) | |||
517 | fprintf(stderr, "Expansion of alias '%s' failed; " | 527 | fprintf(stderr, "Expansion of alias '%s' failed; " |
518 | "'%s' is not a perf-command\n", | 528 | "'%s' is not a perf-command\n", |
519 | cmd, argv[0]); | 529 | cmd, argv[0]); |
520 | exit(1); | 530 | goto out; |
521 | } | 531 | } |
522 | if (!done_help) { | 532 | if (!done_help) { |
523 | cmd = argv[0] = help_unknown_cmd(cmd); | 533 | cmd = argv[0] = help_unknown_cmd(cmd); |
@@ -528,6 +538,6 @@ int main(int argc, const char **argv) | |||
528 | 538 | ||
529 | fprintf(stderr, "Failed to run command '%s': %s\n", | 539 | fprintf(stderr, "Failed to run command '%s': %s\n", |
530 | cmd, strerror(errno)); | 540 | cmd, strerror(errno)); |
531 | 541 | out: | |
532 | return 1; | 542 | return 1; |
533 | } | 543 | } |
diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 2c340e7da458..c2206c87fc9f 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h | |||
@@ -1,10 +1,6 @@ | |||
1 | #ifndef _PERF_PERF_H | 1 | #ifndef _PERF_PERF_H |
2 | #define _PERF_PERF_H | 2 | #define _PERF_PERF_H |
3 | 3 | ||
4 | struct winsize; | ||
5 | |||
6 | void get_term_dimensions(struct winsize *ws); | ||
7 | |||
8 | #include <asm/unistd.h> | 4 | #include <asm/unistd.h> |
9 | 5 | ||
10 | #if defined(__i386__) | 6 | #if defined(__i386__) |
@@ -107,32 +103,6 @@ void get_term_dimensions(struct winsize *ws); | |||
107 | #include "util/types.h" | 103 | #include "util/types.h" |
108 | #include <stdbool.h> | 104 | #include <stdbool.h> |
109 | 105 | ||
110 | struct perf_mmap { | ||
111 | void *base; | ||
112 | int mask; | ||
113 | unsigned int prev; | ||
114 | }; | ||
115 | |||
116 | static inline unsigned int perf_mmap__read_head(struct perf_mmap *mm) | ||
117 | { | ||
118 | struct perf_event_mmap_page *pc = mm->base; | ||
119 | int head = pc->data_head; | ||
120 | rmb(); | ||
121 | return head; | ||
122 | } | ||
123 | |||
124 | static inline void perf_mmap__write_tail(struct perf_mmap *md, | ||
125 | unsigned long tail) | ||
126 | { | ||
127 | struct perf_event_mmap_page *pc = md->base; | ||
128 | |||
129 | /* | ||
130 | * ensure all reads are done before we write the tail out. | ||
131 | */ | ||
132 | /* mb(); */ | ||
133 | pc->data_tail = tail; | ||
134 | } | ||
135 | |||
136 | /* | 106 | /* |
137 | * prctl(PR_TASK_PERF_EVENTS_DISABLE) will (cheaply) disable all | 107 | * prctl(PR_TASK_PERF_EVENTS_DISABLE) will (cheaply) disable all |
138 | * counters in the current task. | 108 | * counters in the current task. |
@@ -237,8 +207,6 @@ struct perf_record_opts { | |||
237 | bool raw_samples; | 207 | bool raw_samples; |
238 | bool sample_address; | 208 | bool sample_address; |
239 | bool sample_time; | 209 | bool sample_time; |
240 | bool sample_id_all_missing; | ||
241 | bool exclude_guest_missing; | ||
242 | bool period; | 210 | bool period; |
243 | unsigned int freq; | 211 | unsigned int freq; |
244 | unsigned int mmap_pages; | 212 | unsigned int mmap_pages; |
diff --git a/tools/perf/scripts/perl/bin/workqueue-stats-record b/tools/perf/scripts/perl/bin/workqueue-stats-record deleted file mode 100644 index 8edda9078d5d..000000000000 --- a/tools/perf/scripts/perl/bin/workqueue-stats-record +++ /dev/null | |||
@@ -1,2 +0,0 @@ | |||
1 | #!/bin/bash | ||
2 | perf record -e workqueue:workqueue_creation -e workqueue:workqueue_destruction -e workqueue:workqueue_execution -e workqueue:workqueue_insertion $@ | ||
diff --git a/tools/perf/scripts/perl/bin/workqueue-stats-report b/tools/perf/scripts/perl/bin/workqueue-stats-report deleted file mode 100644 index 6d91411d248c..000000000000 --- a/tools/perf/scripts/perl/bin/workqueue-stats-report +++ /dev/null | |||
@@ -1,3 +0,0 @@ | |||
1 | #!/bin/bash | ||
2 | # description: workqueue stats (ins/exe/create/destroy) | ||
3 | perf script $@ -s "$PERF_EXEC_PATH"/scripts/perl/workqueue-stats.pl | ||
diff --git a/tools/perf/scripts/perl/rwtop.pl b/tools/perf/scripts/perl/rwtop.pl index 4bb3ecd33472..8b20787021c1 100644 --- a/tools/perf/scripts/perl/rwtop.pl +++ b/tools/perf/scripts/perl/rwtop.pl | |||
@@ -17,6 +17,7 @@ use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib"; | |||
17 | use lib "./Perf-Trace-Util/lib"; | 17 | use lib "./Perf-Trace-Util/lib"; |
18 | use Perf::Trace::Core; | 18 | use Perf::Trace::Core; |
19 | use Perf::Trace::Util; | 19 | use Perf::Trace::Util; |
20 | use POSIX qw/SIGALRM SA_RESTART/; | ||
20 | 21 | ||
21 | my $default_interval = 3; | 22 | my $default_interval = 3; |
22 | my $nlines = 20; | 23 | my $nlines = 20; |
@@ -90,7 +91,10 @@ sub syscalls::sys_enter_write | |||
90 | 91 | ||
91 | sub trace_begin | 92 | sub trace_begin |
92 | { | 93 | { |
93 | $SIG{ALRM} = \&set_print_pending; | 94 | my $sa = POSIX::SigAction->new(\&set_print_pending); |
95 | $sa->flags(SA_RESTART); | ||
96 | $sa->safe(1); | ||
97 | POSIX::sigaction(SIGALRM, $sa) or die "Can't set SIGALRM handler: $!\n"; | ||
94 | alarm 1; | 98 | alarm 1; |
95 | } | 99 | } |
96 | 100 | ||
diff --git a/tools/perf/scripts/perl/workqueue-stats.pl b/tools/perf/scripts/perl/workqueue-stats.pl deleted file mode 100644 index a8eaff5119e0..000000000000 --- a/tools/perf/scripts/perl/workqueue-stats.pl +++ /dev/null | |||
@@ -1,129 +0,0 @@ | |||
1 | #!/usr/bin/perl -w | ||
2 | # (c) 2009, Tom Zanussi <tzanussi@gmail.com> | ||
3 | # Licensed under the terms of the GNU GPL License version 2 | ||
4 | |||
5 | # Displays workqueue stats | ||
6 | # | ||
7 | # Usage: | ||
8 | # | ||
9 | # perf record -c 1 -f -a -R -e workqueue:workqueue_creation -e | ||
10 | # workqueue:workqueue_destruction -e workqueue:workqueue_execution | ||
11 | # -e workqueue:workqueue_insertion | ||
12 | # | ||
13 | # perf script -p -s tools/perf/scripts/perl/workqueue-stats.pl | ||
14 | |||
15 | use 5.010000; | ||
16 | use strict; | ||
17 | use warnings; | ||
18 | |||
19 | use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib"; | ||
20 | use lib "./Perf-Trace-Util/lib"; | ||
21 | use Perf::Trace::Core; | ||
22 | use Perf::Trace::Util; | ||
23 | |||
24 | my @cpus; | ||
25 | |||
26 | sub workqueue::workqueue_destruction | ||
27 | { | ||
28 | my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs, | ||
29 | $common_pid, $common_comm, | ||
30 | $thread_comm, $thread_pid) = @_; | ||
31 | |||
32 | $cpus[$common_cpu]{$thread_pid}{destroyed}++; | ||
33 | $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm; | ||
34 | } | ||
35 | |||
36 | sub workqueue::workqueue_creation | ||
37 | { | ||
38 | my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs, | ||
39 | $common_pid, $common_comm, | ||
40 | $thread_comm, $thread_pid, $cpu) = @_; | ||
41 | |||
42 | $cpus[$common_cpu]{$thread_pid}{created}++; | ||
43 | $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm; | ||
44 | } | ||
45 | |||
46 | sub workqueue::workqueue_execution | ||
47 | { | ||
48 | my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs, | ||
49 | $common_pid, $common_comm, | ||
50 | $thread_comm, $thread_pid, $func) = @_; | ||
51 | |||
52 | $cpus[$common_cpu]{$thread_pid}{executed}++; | ||
53 | $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm; | ||
54 | } | ||
55 | |||
56 | sub workqueue::workqueue_insertion | ||
57 | { | ||
58 | my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs, | ||
59 | $common_pid, $common_comm, | ||
60 | $thread_comm, $thread_pid, $func) = @_; | ||
61 | |||
62 | $cpus[$common_cpu]{$thread_pid}{inserted}++; | ||
63 | $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm; | ||
64 | } | ||
65 | |||
66 | sub trace_end | ||
67 | { | ||
68 | print "workqueue work stats:\n\n"; | ||
69 | my $cpu = 0; | ||
70 | printf("%3s %6s %6s\t%-20s\n", "cpu", "ins", "exec", "name"); | ||
71 | printf("%3s %6s %6s\t%-20s\n", "---", "---", "----", "----"); | ||
72 | foreach my $pidhash (@cpus) { | ||
73 | while ((my $pid, my $wqhash) = each %$pidhash) { | ||
74 | my $ins = $$wqhash{'inserted'} || 0; | ||
75 | my $exe = $$wqhash{'executed'} || 0; | ||
76 | my $comm = $$wqhash{'comm'} || ""; | ||
77 | if ($ins || $exe) { | ||
78 | printf("%3u %6u %6u\t%-20s\n", $cpu, $ins, $exe, $comm); | ||
79 | } | ||
80 | } | ||
81 | $cpu++; | ||
82 | } | ||
83 | |||
84 | $cpu = 0; | ||
85 | print "\nworkqueue lifecycle stats:\n\n"; | ||
86 | printf("%3s %6s %6s\t%-20s\n", "cpu", "created", "destroyed", "name"); | ||
87 | printf("%3s %6s %6s\t%-20s\n", "---", "-------", "---------", "----"); | ||
88 | foreach my $pidhash (@cpus) { | ||
89 | while ((my $pid, my $wqhash) = each %$pidhash) { | ||
90 | my $created = $$wqhash{'created'} || 0; | ||
91 | my $destroyed = $$wqhash{'destroyed'} || 0; | ||
92 | my $comm = $$wqhash{'comm'} || ""; | ||
93 | if ($created || $destroyed) { | ||
94 | printf("%3u %6u %6u\t%-20s\n", $cpu, $created, $destroyed, | ||
95 | $comm); | ||
96 | } | ||
97 | } | ||
98 | $cpu++; | ||
99 | } | ||
100 | |||
101 | print_unhandled(); | ||
102 | } | ||
103 | |||
104 | my %unhandled; | ||
105 | |||
106 | sub print_unhandled | ||
107 | { | ||
108 | if ((scalar keys %unhandled) == 0) { | ||
109 | return; | ||
110 | } | ||
111 | |||
112 | print "\nunhandled events:\n\n"; | ||
113 | |||
114 | printf("%-40s %10s\n", "event", "count"); | ||
115 | printf("%-40s %10s\n", "----------------------------------------", | ||
116 | "-----------"); | ||
117 | |||
118 | foreach my $event_name (keys %unhandled) { | ||
119 | printf("%-40s %10d\n", $event_name, $unhandled{$event_name}); | ||
120 | } | ||
121 | } | ||
122 | |||
123 | sub trace_unhandled | ||
124 | { | ||
125 | my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs, | ||
126 | $common_pid, $common_comm) = @_; | ||
127 | |||
128 | $unhandled{$event_name}++; | ||
129 | } | ||
diff --git a/tools/perf/tests/attr.c b/tools/perf/tests/attr.c index 25638a986257..bdcceb886f77 100644 --- a/tools/perf/tests/attr.c +++ b/tools/perf/tests/attr.c | |||
@@ -19,6 +19,11 @@ | |||
19 | * permissions. All the event text files are stored there. | 19 | * permissions. All the event text files are stored there. |
20 | */ | 20 | */ |
21 | 21 | ||
22 | /* | ||
23 | * Powerpc needs __SANE_USERSPACE_TYPES__ before <linux/types.h> to select | ||
24 | * 'int-ll64.h' and avoid compile warnings when printing __u64 with %llu. | ||
25 | */ | ||
26 | #define __SANE_USERSPACE_TYPES__ | ||
22 | #include <stdlib.h> | 27 | #include <stdlib.h> |
23 | #include <stdio.h> | 28 | #include <stdio.h> |
24 | #include <inttypes.h> | 29 | #include <inttypes.h> |
@@ -33,8 +38,6 @@ | |||
33 | 38 | ||
34 | extern int verbose; | 39 | extern int verbose; |
35 | 40 | ||
36 | bool test_attr__enabled; | ||
37 | |||
38 | static char *dir; | 41 | static char *dir; |
39 | 42 | ||
40 | void test_attr__init(void) | 43 | void test_attr__init(void) |
@@ -146,7 +149,7 @@ static int run_dir(const char *d, const char *perf) | |||
146 | { | 149 | { |
147 | char cmd[3*PATH_MAX]; | 150 | char cmd[3*PATH_MAX]; |
148 | 151 | ||
149 | snprintf(cmd, 3*PATH_MAX, "python %s/attr.py -d %s/attr/ -p %s %s", | 152 | snprintf(cmd, 3*PATH_MAX, PYTHON " %s/attr.py -d %s/attr/ -p %s %s", |
150 | d, d, perf, verbose ? "-v" : ""); | 153 | d, d, perf, verbose ? "-v" : ""); |
151 | 154 | ||
152 | return system(cmd); | 155 | return system(cmd); |
diff --git a/tools/perf/tests/attr.py b/tools/perf/tests/attr.py index e702b82dcb86..2f629ca485bc 100644 --- a/tools/perf/tests/attr.py +++ b/tools/perf/tests/attr.py | |||
@@ -68,7 +68,7 @@ class Event(dict): | |||
68 | self[key] = val | 68 | self[key] = val |
69 | 69 | ||
70 | def __init__(self, name, data, base): | 70 | def __init__(self, name, data, base): |
71 | log.info(" Event %s" % name); | 71 | log.debug(" Event %s" % name); |
72 | self.name = name; | 72 | self.name = name; |
73 | self.group = '' | 73 | self.group = '' |
74 | self.add(base) | 74 | self.add(base) |
@@ -97,6 +97,14 @@ class Event(dict): | |||
97 | return False | 97 | return False |
98 | return True | 98 | return True |
99 | 99 | ||
100 | def diff(self, other): | ||
101 | for t in Event.terms: | ||
102 | if not self.has_key(t) or not other.has_key(t): | ||
103 | continue | ||
104 | if not self.compare_data(self[t], other[t]): | ||
105 | log.warning("expected %s=%s, got %s" % (t, self[t], other[t])) | ||
106 | |||
107 | |||
100 | # Test file description needs to have following sections: | 108 | # Test file description needs to have following sections: |
101 | # [config] | 109 | # [config] |
102 | # - just single instance in file | 110 | # - just single instance in file |
@@ -113,7 +121,7 @@ class Test(object): | |||
113 | parser = ConfigParser.SafeConfigParser() | 121 | parser = ConfigParser.SafeConfigParser() |
114 | parser.read(path) | 122 | parser.read(path) |
115 | 123 | ||
116 | log.warning("running '%s'" % path) | 124 | log.debug("running '%s'" % path) |
117 | 125 | ||
118 | self.path = path | 126 | self.path = path |
119 | self.test_dir = options.test_dir | 127 | self.test_dir = options.test_dir |
@@ -128,7 +136,7 @@ class Test(object): | |||
128 | 136 | ||
129 | self.expect = {} | 137 | self.expect = {} |
130 | self.result = {} | 138 | self.result = {} |
131 | log.info(" loading expected events"); | 139 | log.debug(" loading expected events"); |
132 | self.load_events(path, self.expect) | 140 | self.load_events(path, self.expect) |
133 | 141 | ||
134 | def is_event(self, name): | 142 | def is_event(self, name): |
@@ -164,7 +172,7 @@ class Test(object): | |||
164 | self.perf, self.command, tempdir, self.args) | 172 | self.perf, self.command, tempdir, self.args) |
165 | ret = os.WEXITSTATUS(os.system(cmd)) | 173 | ret = os.WEXITSTATUS(os.system(cmd)) |
166 | 174 | ||
167 | log.info(" running '%s' ret %d " % (cmd, ret)) | 175 | log.warning(" running '%s' ret %d " % (cmd, ret)) |
168 | 176 | ||
169 | if ret != int(self.ret): | 177 | if ret != int(self.ret): |
170 | raise Unsup(self) | 178 | raise Unsup(self) |
@@ -172,7 +180,7 @@ class Test(object): | |||
172 | def compare(self, expect, result): | 180 | def compare(self, expect, result): |
173 | match = {} | 181 | match = {} |
174 | 182 | ||
175 | log.info(" compare"); | 183 | log.debug(" compare"); |
176 | 184 | ||
177 | # For each expected event find all matching | 185 | # For each expected event find all matching |
178 | # events in result. Fail if there's not any. | 186 | # events in result. Fail if there's not any. |
@@ -187,10 +195,11 @@ class Test(object): | |||
187 | else: | 195 | else: |
188 | log.debug(" ->FAIL"); | 196 | log.debug(" ->FAIL"); |
189 | 197 | ||
190 | log.info(" match: [%s] matches %s" % (exp_name, str(exp_list))) | 198 | log.debug(" match: [%s] matches %s" % (exp_name, str(exp_list))) |
191 | 199 | ||
192 | # we did not any matching event - fail | 200 | # we did not any matching event - fail |
193 | if (not exp_list): | 201 | if (not exp_list): |
202 | exp_event.diff(res_event) | ||
194 | raise Fail(self, 'match failure'); | 203 | raise Fail(self, 'match failure'); |
195 | 204 | ||
196 | match[exp_name] = exp_list | 205 | match[exp_name] = exp_list |
@@ -208,10 +217,10 @@ class Test(object): | |||
208 | if res_group not in match[group]: | 217 | if res_group not in match[group]: |
209 | raise Fail(self, 'group failure') | 218 | raise Fail(self, 'group failure') |
210 | 219 | ||
211 | log.info(" group: [%s] matches group leader %s" % | 220 | log.debug(" group: [%s] matches group leader %s" % |
212 | (exp_name, str(match[group]))) | 221 | (exp_name, str(match[group]))) |
213 | 222 | ||
214 | log.info(" matched") | 223 | log.debug(" matched") |
215 | 224 | ||
216 | def resolve_groups(self, events): | 225 | def resolve_groups(self, events): |
217 | for name, event in events.items(): | 226 | for name, event in events.items(): |
@@ -233,7 +242,7 @@ class Test(object): | |||
233 | self.run_cmd(tempdir); | 242 | self.run_cmd(tempdir); |
234 | 243 | ||
235 | # load events expectation for the test | 244 | # load events expectation for the test |
236 | log.info(" loading result events"); | 245 | log.debug(" loading result events"); |
237 | for f in glob.glob(tempdir + '/event*'): | 246 | for f in glob.glob(tempdir + '/event*'): |
238 | self.load_events(f, self.result); | 247 | self.load_events(f, self.result); |
239 | 248 | ||
diff --git a/tools/perf/tests/attr/base-record b/tools/perf/tests/attr/base-record index f1485d8e6a0b..5bc3880f7be5 100644 --- a/tools/perf/tests/attr/base-record +++ b/tools/perf/tests/attr/base-record | |||
@@ -7,7 +7,7 @@ size=96 | |||
7 | config=0 | 7 | config=0 |
8 | sample_period=4000 | 8 | sample_period=4000 |
9 | sample_type=263 | 9 | sample_type=263 |
10 | read_format=7 | 10 | read_format=0 |
11 | disabled=1 | 11 | disabled=1 |
12 | inherit=1 | 12 | inherit=1 |
13 | pinned=0 | 13 | pinned=0 |
diff --git a/tools/perf/tests/attr/test-record-group b/tools/perf/tests/attr/test-record-group index a6599e9a19d3..57739cacdb2a 100644 --- a/tools/perf/tests/attr/test-record-group +++ b/tools/perf/tests/attr/test-record-group | |||
@@ -6,12 +6,14 @@ args = --group -e cycles,instructions kill >/dev/null 2>&1 | |||
6 | fd=1 | 6 | fd=1 |
7 | group_fd=-1 | 7 | group_fd=-1 |
8 | sample_type=327 | 8 | sample_type=327 |
9 | read_format=4 | ||
9 | 10 | ||
10 | [event-2:base-record] | 11 | [event-2:base-record] |
11 | fd=2 | 12 | fd=2 |
12 | group_fd=1 | 13 | group_fd=1 |
13 | config=1 | 14 | config=1 |
14 | sample_type=327 | 15 | sample_type=327 |
16 | read_format=4 | ||
15 | mmap=0 | 17 | mmap=0 |
16 | comm=0 | 18 | comm=0 |
17 | enable_on_exec=0 | 19 | enable_on_exec=0 |
diff --git a/tools/perf/tests/attr/test-record-group1 b/tools/perf/tests/attr/test-record-group1 index 5a8359da38af..c5548d054aff 100644 --- a/tools/perf/tests/attr/test-record-group1 +++ b/tools/perf/tests/attr/test-record-group1 | |||
@@ -1,11 +1,12 @@ | |||
1 | [config] | 1 | [config] |
2 | command = record | 2 | command = record |
3 | args = -e '{cycles,instructions}' kill >/tmp/krava 2>&1 | 3 | args = -e '{cycles,instructions}' kill >/dev/null 2>&1 |
4 | 4 | ||
5 | [event-1:base-record] | 5 | [event-1:base-record] |
6 | fd=1 | 6 | fd=1 |
7 | group_fd=-1 | 7 | group_fd=-1 |
8 | sample_type=327 | 8 | sample_type=327 |
9 | read_format=4 | ||
9 | 10 | ||
10 | [event-2:base-record] | 11 | [event-2:base-record] |
11 | fd=2 | 12 | fd=2 |
@@ -13,6 +14,7 @@ group_fd=1 | |||
13 | type=0 | 14 | type=0 |
14 | config=1 | 15 | config=1 |
15 | sample_type=327 | 16 | sample_type=327 |
17 | read_format=4 | ||
16 | mmap=0 | 18 | mmap=0 |
17 | comm=0 | 19 | comm=0 |
18 | enable_on_exec=0 | 20 | enable_on_exec=0 |
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 186f67535494..acb98e0e39f2 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c | |||
@@ -4,6 +4,7 @@ | |||
4 | * Builtin regression testing command: ever growing number of sanity tests | 4 | * Builtin regression testing command: ever growing number of sanity tests |
5 | */ | 5 | */ |
6 | #include "builtin.h" | 6 | #include "builtin.h" |
7 | #include "intlist.h" | ||
7 | #include "tests.h" | 8 | #include "tests.h" |
8 | #include "debug.h" | 9 | #include "debug.h" |
9 | #include "color.h" | 10 | #include "color.h" |
@@ -69,6 +70,14 @@ static struct test { | |||
69 | .func = test__attr, | 70 | .func = test__attr, |
70 | }, | 71 | }, |
71 | { | 72 | { |
73 | .desc = "Test matching and linking mutliple hists", | ||
74 | .func = test__hists_link, | ||
75 | }, | ||
76 | { | ||
77 | .desc = "Try 'use perf' in python, checking link problems", | ||
78 | .func = test__python_use, | ||
79 | }, | ||
80 | { | ||
72 | .func = NULL, | 81 | .func = NULL, |
73 | }, | 82 | }, |
74 | }; | 83 | }; |
@@ -97,7 +106,7 @@ static bool perf_test__matches(int curr, int argc, const char *argv[]) | |||
97 | return false; | 106 | return false; |
98 | } | 107 | } |
99 | 108 | ||
100 | static int __cmd_test(int argc, const char *argv[]) | 109 | static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist) |
101 | { | 110 | { |
102 | int i = 0; | 111 | int i = 0; |
103 | int width = 0; | 112 | int width = 0; |
@@ -118,13 +127,28 @@ static int __cmd_test(int argc, const char *argv[]) | |||
118 | continue; | 127 | continue; |
119 | 128 | ||
120 | pr_info("%2d: %-*s:", i, width, tests[curr].desc); | 129 | pr_info("%2d: %-*s:", i, width, tests[curr].desc); |
130 | |||
131 | if (intlist__find(skiplist, i)) { | ||
132 | color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip (user override)\n"); | ||
133 | continue; | ||
134 | } | ||
135 | |||
121 | pr_debug("\n--- start ---\n"); | 136 | pr_debug("\n--- start ---\n"); |
122 | err = tests[curr].func(); | 137 | err = tests[curr].func(); |
123 | pr_debug("---- end ----\n%s:", tests[curr].desc); | 138 | pr_debug("---- end ----\n%s:", tests[curr].desc); |
124 | if (err) | 139 | |
125 | color_fprintf(stderr, PERF_COLOR_RED, " FAILED!\n"); | 140 | switch (err) { |
126 | else | 141 | case TEST_OK: |
127 | pr_info(" Ok\n"); | 142 | pr_info(" Ok\n"); |
143 | break; | ||
144 | case TEST_SKIP: | ||
145 | color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip\n"); | ||
146 | break; | ||
147 | case TEST_FAIL: | ||
148 | default: | ||
149 | color_fprintf(stderr, PERF_COLOR_RED, " FAILED!\n"); | ||
150 | break; | ||
151 | } | ||
128 | } | 152 | } |
129 | 153 | ||
130 | return 0; | 154 | return 0; |
@@ -152,11 +176,14 @@ int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused) | |||
152 | "perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]", | 176 | "perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]", |
153 | NULL, | 177 | NULL, |
154 | }; | 178 | }; |
179 | const char *skip = NULL; | ||
155 | const struct option test_options[] = { | 180 | const struct option test_options[] = { |
181 | OPT_STRING('s', "skip", &skip, "tests", "tests to skip"), | ||
156 | OPT_INCR('v', "verbose", &verbose, | 182 | OPT_INCR('v', "verbose", &verbose, |
157 | "be more verbose (show symbol address, etc)"), | 183 | "be more verbose (show symbol address, etc)"), |
158 | OPT_END() | 184 | OPT_END() |
159 | }; | 185 | }; |
186 | struct intlist *skiplist = NULL; | ||
160 | 187 | ||
161 | argc = parse_options(argc, argv, test_options, test_usage, 0); | 188 | argc = parse_options(argc, argv, test_options, test_usage, 0); |
162 | if (argc >= 1 && !strcmp(argv[0], "list")) | 189 | if (argc >= 1 && !strcmp(argv[0], "list")) |
@@ -169,5 +196,8 @@ int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused) | |||
169 | if (symbol__init() < 0) | 196 | if (symbol__init() < 0) |
170 | return -1; | 197 | return -1; |
171 | 198 | ||
172 | return __cmd_test(argc, argv); | 199 | if (skip != NULL) |
200 | skiplist = intlist__new(skip); | ||
201 | |||
202 | return __cmd_test(argc, argv, skiplist); | ||
173 | } | 203 | } |
diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c index e61fc828a158..0fd99a9adb91 100644 --- a/tools/perf/tests/evsel-roundtrip-name.c +++ b/tools/perf/tests/evsel-roundtrip-name.c | |||
@@ -22,7 +22,7 @@ static int perf_evsel__roundtrip_cache_name_test(void) | |||
22 | for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { | 22 | for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { |
23 | __perf_evsel__hw_cache_type_op_res_name(type, op, i, | 23 | __perf_evsel__hw_cache_type_op_res_name(type, op, i, |
24 | name, sizeof(name)); | 24 | name, sizeof(name)); |
25 | err = parse_events(evlist, name, 0); | 25 | err = parse_events(evlist, name); |
26 | if (err) | 26 | if (err) |
27 | ret = err; | 27 | ret = err; |
28 | } | 28 | } |
@@ -70,7 +70,7 @@ static int __perf_evsel__name_array_test(const char *names[], int nr_names) | |||
70 | return -ENOMEM; | 70 | return -ENOMEM; |
71 | 71 | ||
72 | for (i = 0; i < nr_names; ++i) { | 72 | for (i = 0; i < nr_names; ++i) { |
73 | err = parse_events(evlist, names[i], 0); | 73 | err = parse_events(evlist, names[i]); |
74 | if (err) { | 74 | if (err) { |
75 | pr_debug("failed to parse event '%s', err %d\n", | 75 | pr_debug("failed to parse event '%s', err %d\n", |
76 | names[i], err); | 76 | names[i], err); |
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c new file mode 100644 index 000000000000..1be64a6c5daf --- /dev/null +++ b/tools/perf/tests/hists_link.c | |||
@@ -0,0 +1,500 @@ | |||
1 | #include "perf.h" | ||
2 | #include "tests.h" | ||
3 | #include "debug.h" | ||
4 | #include "symbol.h" | ||
5 | #include "sort.h" | ||
6 | #include "evsel.h" | ||
7 | #include "evlist.h" | ||
8 | #include "machine.h" | ||
9 | #include "thread.h" | ||
10 | #include "parse-events.h" | ||
11 | |||
12 | static struct { | ||
13 | u32 pid; | ||
14 | const char *comm; | ||
15 | } fake_threads[] = { | ||
16 | { 100, "perf" }, | ||
17 | { 200, "perf" }, | ||
18 | { 300, "bash" }, | ||
19 | }; | ||
20 | |||
21 | static struct { | ||
22 | u32 pid; | ||
23 | u64 start; | ||
24 | const char *filename; | ||
25 | } fake_mmap_info[] = { | ||
26 | { 100, 0x40000, "perf" }, | ||
27 | { 100, 0x50000, "libc" }, | ||
28 | { 100, 0xf0000, "[kernel]" }, | ||
29 | { 200, 0x40000, "perf" }, | ||
30 | { 200, 0x50000, "libc" }, | ||
31 | { 200, 0xf0000, "[kernel]" }, | ||
32 | { 300, 0x40000, "bash" }, | ||
33 | { 300, 0x50000, "libc" }, | ||
34 | { 300, 0xf0000, "[kernel]" }, | ||
35 | }; | ||
36 | |||
37 | struct fake_sym { | ||
38 | u64 start; | ||
39 | u64 length; | ||
40 | const char *name; | ||
41 | }; | ||
42 | |||
43 | static struct fake_sym perf_syms[] = { | ||
44 | { 700, 100, "main" }, | ||
45 | { 800, 100, "run_command" }, | ||
46 | { 900, 100, "cmd_record" }, | ||
47 | }; | ||
48 | |||
49 | static struct fake_sym bash_syms[] = { | ||
50 | { 700, 100, "main" }, | ||
51 | { 800, 100, "xmalloc" }, | ||
52 | { 900, 100, "xfree" }, | ||
53 | }; | ||
54 | |||
55 | static struct fake_sym libc_syms[] = { | ||
56 | { 700, 100, "malloc" }, | ||
57 | { 800, 100, "free" }, | ||
58 | { 900, 100, "realloc" }, | ||
59 | }; | ||
60 | |||
61 | static struct fake_sym kernel_syms[] = { | ||
62 | { 700, 100, "schedule" }, | ||
63 | { 800, 100, "page_fault" }, | ||
64 | { 900, 100, "sys_perf_event_open" }, | ||
65 | }; | ||
66 | |||
67 | static struct { | ||
68 | const char *dso_name; | ||
69 | struct fake_sym *syms; | ||
70 | size_t nr_syms; | ||
71 | } fake_symbols[] = { | ||
72 | { "perf", perf_syms, ARRAY_SIZE(perf_syms) }, | ||
73 | { "bash", bash_syms, ARRAY_SIZE(bash_syms) }, | ||
74 | { "libc", libc_syms, ARRAY_SIZE(libc_syms) }, | ||
75 | { "[kernel]", kernel_syms, ARRAY_SIZE(kernel_syms) }, | ||
76 | }; | ||
77 | |||
78 | static struct machine *setup_fake_machine(struct machines *machines) | ||
79 | { | ||
80 | struct machine *machine = machines__find(machines, HOST_KERNEL_ID); | ||
81 | size_t i; | ||
82 | |||
83 | if (machine == NULL) { | ||
84 | pr_debug("Not enough memory for machine setup\n"); | ||
85 | return NULL; | ||
86 | } | ||
87 | |||
88 | for (i = 0; i < ARRAY_SIZE(fake_threads); i++) { | ||
89 | struct thread *thread; | ||
90 | |||
91 | thread = machine__findnew_thread(machine, fake_threads[i].pid); | ||
92 | if (thread == NULL) | ||
93 | goto out; | ||
94 | |||
95 | thread__set_comm(thread, fake_threads[i].comm); | ||
96 | } | ||
97 | |||
98 | for (i = 0; i < ARRAY_SIZE(fake_mmap_info); i++) { | ||
99 | union perf_event fake_mmap_event = { | ||
100 | .mmap = { | ||
101 | .header = { .misc = PERF_RECORD_MISC_USER, }, | ||
102 | .pid = fake_mmap_info[i].pid, | ||
103 | .start = fake_mmap_info[i].start, | ||
104 | .len = 0x1000ULL, | ||
105 | .pgoff = 0ULL, | ||
106 | }, | ||
107 | }; | ||
108 | |||
109 | strcpy(fake_mmap_event.mmap.filename, | ||
110 | fake_mmap_info[i].filename); | ||
111 | |||
112 | machine__process_mmap_event(machine, &fake_mmap_event); | ||
113 | } | ||
114 | |||
115 | for (i = 0; i < ARRAY_SIZE(fake_symbols); i++) { | ||
116 | size_t k; | ||
117 | struct dso *dso; | ||
118 | |||
119 | dso = __dsos__findnew(&machine->user_dsos, | ||
120 | fake_symbols[i].dso_name); | ||
121 | if (dso == NULL) | ||
122 | goto out; | ||
123 | |||
124 | /* emulate dso__load() */ | ||
125 | dso__set_loaded(dso, MAP__FUNCTION); | ||
126 | |||
127 | for (k = 0; k < fake_symbols[i].nr_syms; k++) { | ||
128 | struct symbol *sym; | ||
129 | struct fake_sym *fsym = &fake_symbols[i].syms[k]; | ||
130 | |||
131 | sym = symbol__new(fsym->start, fsym->length, | ||
132 | STB_GLOBAL, fsym->name); | ||
133 | if (sym == NULL) | ||
134 | goto out; | ||
135 | |||
136 | symbols__insert(&dso->symbols[MAP__FUNCTION], sym); | ||
137 | } | ||
138 | } | ||
139 | |||
140 | return machine; | ||
141 | |||
142 | out: | ||
143 | pr_debug("Not enough memory for machine setup\n"); | ||
144 | machine__delete_threads(machine); | ||
145 | machine__delete(machine); | ||
146 | return NULL; | ||
147 | } | ||
148 | |||
149 | struct sample { | ||
150 | u32 pid; | ||
151 | u64 ip; | ||
152 | struct thread *thread; | ||
153 | struct map *map; | ||
154 | struct symbol *sym; | ||
155 | }; | ||
156 | |||
157 | static struct sample fake_common_samples[] = { | ||
158 | /* perf [kernel] schedule() */ | ||
159 | { .pid = 100, .ip = 0xf0000 + 700, }, | ||
160 | /* perf [perf] main() */ | ||
161 | { .pid = 200, .ip = 0x40000 + 700, }, | ||
162 | /* perf [perf] cmd_record() */ | ||
163 | { .pid = 200, .ip = 0x40000 + 900, }, | ||
164 | /* bash [bash] xmalloc() */ | ||
165 | { .pid = 300, .ip = 0x40000 + 800, }, | ||
166 | /* bash [libc] malloc() */ | ||
167 | { .pid = 300, .ip = 0x50000 + 700, }, | ||
168 | }; | ||
169 | |||
170 | static struct sample fake_samples[][5] = { | ||
171 | { | ||
172 | /* perf [perf] run_command() */ | ||
173 | { .pid = 100, .ip = 0x40000 + 800, }, | ||
174 | /* perf [libc] malloc() */ | ||
175 | { .pid = 100, .ip = 0x50000 + 700, }, | ||
176 | /* perf [kernel] page_fault() */ | ||
177 | { .pid = 100, .ip = 0xf0000 + 800, }, | ||
178 | /* perf [kernel] sys_perf_event_open() */ | ||
179 | { .pid = 200, .ip = 0xf0000 + 900, }, | ||
180 | /* bash [libc] free() */ | ||
181 | { .pid = 300, .ip = 0x50000 + 800, }, | ||
182 | }, | ||
183 | { | ||
184 | /* perf [libc] free() */ | ||
185 | { .pid = 200, .ip = 0x50000 + 800, }, | ||
186 | /* bash [libc] malloc() */ | ||
187 | { .pid = 300, .ip = 0x50000 + 700, }, /* will be merged */ | ||
188 | /* bash [bash] xfee() */ | ||
189 | { .pid = 300, .ip = 0x40000 + 900, }, | ||
190 | /* bash [libc] realloc() */ | ||
191 | { .pid = 300, .ip = 0x50000 + 900, }, | ||
192 | /* bash [kernel] page_fault() */ | ||
193 | { .pid = 300, .ip = 0xf0000 + 800, }, | ||
194 | }, | ||
195 | }; | ||
196 | |||
197 | static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine) | ||
198 | { | ||
199 | struct perf_evsel *evsel; | ||
200 | struct addr_location al; | ||
201 | struct hist_entry *he; | ||
202 | struct perf_sample sample = { .cpu = 0, }; | ||
203 | size_t i = 0, k; | ||
204 | |||
205 | /* | ||
206 | * each evsel will have 10 samples - 5 common and 5 distinct. | ||
207 | * However the second evsel also has a collapsed entry for | ||
208 | * "bash [libc] malloc" so total 9 entries will be in the tree. | ||
209 | */ | ||
210 | list_for_each_entry(evsel, &evlist->entries, node) { | ||
211 | for (k = 0; k < ARRAY_SIZE(fake_common_samples); k++) { | ||
212 | const union perf_event event = { | ||
213 | .ip = { | ||
214 | .header = { | ||
215 | .misc = PERF_RECORD_MISC_USER, | ||
216 | }, | ||
217 | .pid = fake_common_samples[k].pid, | ||
218 | .ip = fake_common_samples[k].ip, | ||
219 | }, | ||
220 | }; | ||
221 | |||
222 | if (perf_event__preprocess_sample(&event, machine, &al, | ||
223 | &sample, 0) < 0) | ||
224 | goto out; | ||
225 | |||
226 | he = __hists__add_entry(&evsel->hists, &al, NULL, 1); | ||
227 | if (he == NULL) | ||
228 | goto out; | ||
229 | |||
230 | fake_common_samples[k].thread = al.thread; | ||
231 | fake_common_samples[k].map = al.map; | ||
232 | fake_common_samples[k].sym = al.sym; | ||
233 | } | ||
234 | |||
235 | for (k = 0; k < ARRAY_SIZE(fake_samples[i]); k++) { | ||
236 | const union perf_event event = { | ||
237 | .ip = { | ||
238 | .header = { | ||
239 | .misc = PERF_RECORD_MISC_USER, | ||
240 | }, | ||
241 | .pid = fake_samples[i][k].pid, | ||
242 | .ip = fake_samples[i][k].ip, | ||
243 | }, | ||
244 | }; | ||
245 | |||
246 | if (perf_event__preprocess_sample(&event, machine, &al, | ||
247 | &sample, 0) < 0) | ||
248 | goto out; | ||
249 | |||
250 | he = __hists__add_entry(&evsel->hists, &al, NULL, 1); | ||
251 | if (he == NULL) | ||
252 | goto out; | ||
253 | |||
254 | fake_samples[i][k].thread = al.thread; | ||
255 | fake_samples[i][k].map = al.map; | ||
256 | fake_samples[i][k].sym = al.sym; | ||
257 | } | ||
258 | i++; | ||
259 | } | ||
260 | |||
261 | return 0; | ||
262 | |||
263 | out: | ||
264 | pr_debug("Not enough memory for adding a hist entry\n"); | ||
265 | return -1; | ||
266 | } | ||
267 | |||
268 | static int find_sample(struct sample *samples, size_t nr_samples, | ||
269 | struct thread *t, struct map *m, struct symbol *s) | ||
270 | { | ||
271 | while (nr_samples--) { | ||
272 | if (samples->thread == t && samples->map == m && | ||
273 | samples->sym == s) | ||
274 | return 1; | ||
275 | samples++; | ||
276 | } | ||
277 | return 0; | ||
278 | } | ||
279 | |||
280 | static int __validate_match(struct hists *hists) | ||
281 | { | ||
282 | size_t count = 0; | ||
283 | struct rb_root *root; | ||
284 | struct rb_node *node; | ||
285 | |||
286 | /* | ||
287 | * Only entries from fake_common_samples should have a pair. | ||
288 | */ | ||
289 | if (sort__need_collapse) | ||
290 | root = &hists->entries_collapsed; | ||
291 | else | ||
292 | root = hists->entries_in; | ||
293 | |||
294 | node = rb_first(root); | ||
295 | while (node) { | ||
296 | struct hist_entry *he; | ||
297 | |||
298 | he = rb_entry(node, struct hist_entry, rb_node_in); | ||
299 | |||
300 | if (hist_entry__has_pairs(he)) { | ||
301 | if (find_sample(fake_common_samples, | ||
302 | ARRAY_SIZE(fake_common_samples), | ||
303 | he->thread, he->ms.map, he->ms.sym)) { | ||
304 | count++; | ||
305 | } else { | ||
306 | pr_debug("Can't find the matched entry\n"); | ||
307 | return -1; | ||
308 | } | ||
309 | } | ||
310 | |||
311 | node = rb_next(node); | ||
312 | } | ||
313 | |||
314 | if (count != ARRAY_SIZE(fake_common_samples)) { | ||
315 | pr_debug("Invalid count for matched entries: %zd of %zd\n", | ||
316 | count, ARRAY_SIZE(fake_common_samples)); | ||
317 | return -1; | ||
318 | } | ||
319 | |||
320 | return 0; | ||
321 | } | ||
322 | |||
323 | static int validate_match(struct hists *leader, struct hists *other) | ||
324 | { | ||
325 | return __validate_match(leader) || __validate_match(other); | ||
326 | } | ||
327 | |||
328 | static int __validate_link(struct hists *hists, int idx) | ||
329 | { | ||
330 | size_t count = 0; | ||
331 | size_t count_pair = 0; | ||
332 | size_t count_dummy = 0; | ||
333 | struct rb_root *root; | ||
334 | struct rb_node *node; | ||
335 | |||
336 | /* | ||
337 | * Leader hists (idx = 0) will have dummy entries from other, | ||
338 | * and some entries will have no pair. However every entry | ||
339 | * in other hists should have (dummy) pair. | ||
340 | */ | ||
341 | if (sort__need_collapse) | ||
342 | root = &hists->entries_collapsed; | ||
343 | else | ||
344 | root = hists->entries_in; | ||
345 | |||
346 | node = rb_first(root); | ||
347 | while (node) { | ||
348 | struct hist_entry *he; | ||
349 | |||
350 | he = rb_entry(node, struct hist_entry, rb_node_in); | ||
351 | |||
352 | if (hist_entry__has_pairs(he)) { | ||
353 | if (!find_sample(fake_common_samples, | ||
354 | ARRAY_SIZE(fake_common_samples), | ||
355 | he->thread, he->ms.map, he->ms.sym) && | ||
356 | !find_sample(fake_samples[idx], | ||
357 | ARRAY_SIZE(fake_samples[idx]), | ||
358 | he->thread, he->ms.map, he->ms.sym)) { | ||
359 | count_dummy++; | ||
360 | } | ||
361 | count_pair++; | ||
362 | } else if (idx) { | ||
363 | pr_debug("A entry from the other hists should have pair\n"); | ||
364 | return -1; | ||
365 | } | ||
366 | |||
367 | count++; | ||
368 | node = rb_next(node); | ||
369 | } | ||
370 | |||
371 | /* | ||
372 | * Note that we have a entry collapsed in the other (idx = 1) hists. | ||
373 | */ | ||
374 | if (idx == 0) { | ||
375 | if (count_dummy != ARRAY_SIZE(fake_samples[1]) - 1) { | ||
376 | pr_debug("Invalid count of dummy entries: %zd of %zd\n", | ||
377 | count_dummy, ARRAY_SIZE(fake_samples[1]) - 1); | ||
378 | return -1; | ||
379 | } | ||
380 | if (count != count_pair + ARRAY_SIZE(fake_samples[0])) { | ||
381 | pr_debug("Invalid count of total leader entries: %zd of %zd\n", | ||
382 | count, count_pair + ARRAY_SIZE(fake_samples[0])); | ||
383 | return -1; | ||
384 | } | ||
385 | } else { | ||
386 | if (count != count_pair) { | ||
387 | pr_debug("Invalid count of total other entries: %zd of %zd\n", | ||
388 | count, count_pair); | ||
389 | return -1; | ||
390 | } | ||
391 | if (count_dummy > 0) { | ||
392 | pr_debug("Other hists should not have dummy entries: %zd\n", | ||
393 | count_dummy); | ||
394 | return -1; | ||
395 | } | ||
396 | } | ||
397 | |||
398 | return 0; | ||
399 | } | ||
400 | |||
401 | static int validate_link(struct hists *leader, struct hists *other) | ||
402 | { | ||
403 | return __validate_link(leader, 0) || __validate_link(other, 1); | ||
404 | } | ||
405 | |||
406 | static void print_hists(struct hists *hists) | ||
407 | { | ||
408 | int i = 0; | ||
409 | struct rb_root *root; | ||
410 | struct rb_node *node; | ||
411 | |||
412 | if (sort__need_collapse) | ||
413 | root = &hists->entries_collapsed; | ||
414 | else | ||
415 | root = hists->entries_in; | ||
416 | |||
417 | pr_info("----- %s --------\n", __func__); | ||
418 | node = rb_first(root); | ||
419 | while (node) { | ||
420 | struct hist_entry *he; | ||
421 | |||
422 | he = rb_entry(node, struct hist_entry, rb_node_in); | ||
423 | |||
424 | pr_info("%2d: entry: %-8s [%-8s] %20s: period = %"PRIu64"\n", | ||
425 | i, he->thread->comm, he->ms.map->dso->short_name, | ||
426 | he->ms.sym->name, he->stat.period); | ||
427 | |||
428 | i++; | ||
429 | node = rb_next(node); | ||
430 | } | ||
431 | } | ||
432 | |||
433 | int test__hists_link(void) | ||
434 | { | ||
435 | int err = -1; | ||
436 | struct machines machines; | ||
437 | struct machine *machine = NULL; | ||
438 | struct perf_evsel *evsel, *first; | ||
439 | struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); | ||
440 | |||
441 | if (evlist == NULL) | ||
442 | return -ENOMEM; | ||
443 | |||
444 | err = parse_events(evlist, "cpu-clock"); | ||
445 | if (err) | ||
446 | goto out; | ||
447 | err = parse_events(evlist, "task-clock"); | ||
448 | if (err) | ||
449 | goto out; | ||
450 | |||
451 | /* default sort order (comm,dso,sym) will be used */ | ||
452 | if (setup_sorting() < 0) | ||
453 | goto out; | ||
454 | |||
455 | machines__init(&machines); | ||
456 | |||
457 | /* setup threads/dso/map/symbols also */ | ||
458 | machine = setup_fake_machine(&machines); | ||
459 | if (!machine) | ||
460 | goto out; | ||
461 | |||
462 | if (verbose > 1) | ||
463 | machine__fprintf(machine, stderr); | ||
464 | |||
465 | /* process sample events */ | ||
466 | err = add_hist_entries(evlist, machine); | ||
467 | if (err < 0) | ||
468 | goto out; | ||
469 | |||
470 | list_for_each_entry(evsel, &evlist->entries, node) { | ||
471 | hists__collapse_resort(&evsel->hists); | ||
472 | |||
473 | if (verbose > 2) | ||
474 | print_hists(&evsel->hists); | ||
475 | } | ||
476 | |||
477 | first = perf_evlist__first(evlist); | ||
478 | evsel = perf_evlist__last(evlist); | ||
479 | |||
480 | /* match common entries */ | ||
481 | hists__match(&first->hists, &evsel->hists); | ||
482 | err = validate_match(&first->hists, &evsel->hists); | ||
483 | if (err) | ||
484 | goto out; | ||
485 | |||
486 | /* link common and/or dummy entries */ | ||
487 | hists__link(&first->hists, &evsel->hists); | ||
488 | err = validate_link(&first->hists, &evsel->hists); | ||
489 | if (err) | ||
490 | goto out; | ||
491 | |||
492 | err = 0; | ||
493 | |||
494 | out: | ||
495 | /* tear down everything */ | ||
496 | perf_evlist__delete(evlist); | ||
497 | machines__exit(&machines); | ||
498 | |||
499 | return err; | ||
500 | } | ||
diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c index e1746811e14b..cdd50755af51 100644 --- a/tools/perf/tests/mmap-basic.c +++ b/tools/perf/tests/mmap-basic.c | |||
@@ -22,36 +22,16 @@ int test__basic_mmap(void) | |||
22 | struct thread_map *threads; | 22 | struct thread_map *threads; |
23 | struct cpu_map *cpus; | 23 | struct cpu_map *cpus; |
24 | struct perf_evlist *evlist; | 24 | struct perf_evlist *evlist; |
25 | struct perf_event_attr attr = { | ||
26 | .type = PERF_TYPE_TRACEPOINT, | ||
27 | .read_format = PERF_FORMAT_ID, | ||
28 | .sample_type = PERF_SAMPLE_ID, | ||
29 | .watermark = 0, | ||
30 | }; | ||
31 | cpu_set_t cpu_set; | 25 | cpu_set_t cpu_set; |
32 | const char *syscall_names[] = { "getsid", "getppid", "getpgrp", | 26 | const char *syscall_names[] = { "getsid", "getppid", "getpgrp", |
33 | "getpgid", }; | 27 | "getpgid", }; |
34 | pid_t (*syscalls[])(void) = { (void *)getsid, getppid, getpgrp, | 28 | pid_t (*syscalls[])(void) = { (void *)getsid, getppid, getpgrp, |
35 | (void*)getpgid }; | 29 | (void*)getpgid }; |
36 | #define nsyscalls ARRAY_SIZE(syscall_names) | 30 | #define nsyscalls ARRAY_SIZE(syscall_names) |
37 | int ids[nsyscalls]; | ||
38 | unsigned int nr_events[nsyscalls], | 31 | unsigned int nr_events[nsyscalls], |
39 | expected_nr_events[nsyscalls], i, j; | 32 | expected_nr_events[nsyscalls], i, j; |
40 | struct perf_evsel *evsels[nsyscalls], *evsel; | 33 | struct perf_evsel *evsels[nsyscalls], *evsel; |
41 | 34 | ||
42 | for (i = 0; i < nsyscalls; ++i) { | ||
43 | char name[64]; | ||
44 | |||
45 | snprintf(name, sizeof(name), "sys_enter_%s", syscall_names[i]); | ||
46 | ids[i] = trace_event__id(name); | ||
47 | if (ids[i] < 0) { | ||
48 | pr_debug("Is debugfs mounted on /sys/kernel/debug?\n"); | ||
49 | return -1; | ||
50 | } | ||
51 | nr_events[i] = 0; | ||
52 | expected_nr_events[i] = random() % 257; | ||
53 | } | ||
54 | |||
55 | threads = thread_map__new(-1, getpid(), UINT_MAX); | 35 | threads = thread_map__new(-1, getpid(), UINT_MAX); |
56 | if (threads == NULL) { | 36 | if (threads == NULL) { |
57 | pr_debug("thread_map__new\n"); | 37 | pr_debug("thread_map__new\n"); |
@@ -79,18 +59,19 @@ int test__basic_mmap(void) | |||
79 | goto out_free_cpus; | 59 | goto out_free_cpus; |
80 | } | 60 | } |
81 | 61 | ||
82 | /* anonymous union fields, can't be initialized above */ | ||
83 | attr.wakeup_events = 1; | ||
84 | attr.sample_period = 1; | ||
85 | |||
86 | for (i = 0; i < nsyscalls; ++i) { | 62 | for (i = 0; i < nsyscalls; ++i) { |
87 | attr.config = ids[i]; | 63 | char name[64]; |
88 | evsels[i] = perf_evsel__new(&attr, i); | 64 | |
65 | snprintf(name, sizeof(name), "sys_enter_%s", syscall_names[i]); | ||
66 | evsels[i] = perf_evsel__newtp("syscalls", name, i); | ||
89 | if (evsels[i] == NULL) { | 67 | if (evsels[i] == NULL) { |
90 | pr_debug("perf_evsel__new\n"); | 68 | pr_debug("perf_evsel__new\n"); |
91 | goto out_free_evlist; | 69 | goto out_free_evlist; |
92 | } | 70 | } |
93 | 71 | ||
72 | evsels[i]->attr.wakeup_events = 1; | ||
73 | perf_evsel__set_sample_id(evsels[i]); | ||
74 | |||
94 | perf_evlist__add(evlist, evsels[i]); | 75 | perf_evlist__add(evlist, evsels[i]); |
95 | 76 | ||
96 | if (perf_evsel__open(evsels[i], cpus, threads) < 0) { | 77 | if (perf_evsel__open(evsels[i], cpus, threads) < 0) { |
@@ -99,6 +80,9 @@ int test__basic_mmap(void) | |||
99 | strerror(errno)); | 80 | strerror(errno)); |
100 | goto out_close_fd; | 81 | goto out_close_fd; |
101 | } | 82 | } |
83 | |||
84 | nr_events[i] = 0; | ||
85 | expected_nr_events[i] = 1 + rand() % 127; | ||
102 | } | 86 | } |
103 | 87 | ||
104 | if (perf_evlist__mmap(evlist, 128, true) < 0) { | 88 | if (perf_evlist__mmap(evlist, 128, true) < 0) { |
@@ -128,6 +112,7 @@ int test__basic_mmap(void) | |||
128 | goto out_munmap; | 112 | goto out_munmap; |
129 | } | 113 | } |
130 | 114 | ||
115 | err = -1; | ||
131 | evsel = perf_evlist__id2evsel(evlist, sample.id); | 116 | evsel = perf_evlist__id2evsel(evlist, sample.id); |
132 | if (evsel == NULL) { | 117 | if (evsel == NULL) { |
133 | pr_debug("event with id %" PRIu64 | 118 | pr_debug("event with id %" PRIu64 |
@@ -137,16 +122,17 @@ int test__basic_mmap(void) | |||
137 | nr_events[evsel->idx]++; | 122 | nr_events[evsel->idx]++; |
138 | } | 123 | } |
139 | 124 | ||
125 | err = 0; | ||
140 | list_for_each_entry(evsel, &evlist->entries, node) { | 126 | list_for_each_entry(evsel, &evlist->entries, node) { |
141 | if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) { | 127 | if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) { |
142 | pr_debug("expected %d %s events, got %d\n", | 128 | pr_debug("expected %d %s events, got %d\n", |
143 | expected_nr_events[evsel->idx], | 129 | expected_nr_events[evsel->idx], |
144 | perf_evsel__name(evsel), nr_events[evsel->idx]); | 130 | perf_evsel__name(evsel), nr_events[evsel->idx]); |
131 | err = -1; | ||
145 | goto out_munmap; | 132 | goto out_munmap; |
146 | } | 133 | } |
147 | } | 134 | } |
148 | 135 | ||
149 | err = 0; | ||
150 | out_munmap: | 136 | out_munmap: |
151 | perf_evlist__munmap(evlist); | 137 | perf_evlist__munmap(evlist); |
152 | out_close_fd: | 138 | out_close_fd: |
diff --git a/tools/perf/tests/open-syscall-all-cpus.c b/tools/perf/tests/open-syscall-all-cpus.c index 31072aba0d54..b0657a9ccda6 100644 --- a/tools/perf/tests/open-syscall-all-cpus.c +++ b/tools/perf/tests/open-syscall-all-cpus.c | |||
@@ -7,20 +7,12 @@ | |||
7 | int test__open_syscall_event_on_all_cpus(void) | 7 | int test__open_syscall_event_on_all_cpus(void) |
8 | { | 8 | { |
9 | int err = -1, fd, cpu; | 9 | int err = -1, fd, cpu; |
10 | struct thread_map *threads; | ||
11 | struct cpu_map *cpus; | 10 | struct cpu_map *cpus; |
12 | struct perf_evsel *evsel; | 11 | struct perf_evsel *evsel; |
13 | struct perf_event_attr attr; | ||
14 | unsigned int nr_open_calls = 111, i; | 12 | unsigned int nr_open_calls = 111, i; |
15 | cpu_set_t cpu_set; | 13 | cpu_set_t cpu_set; |
16 | int id = trace_event__id("sys_enter_open"); | 14 | struct thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX); |
17 | 15 | ||
18 | if (id < 0) { | ||
19 | pr_debug("is debugfs mounted on /sys/kernel/debug?\n"); | ||
20 | return -1; | ||
21 | } | ||
22 | |||
23 | threads = thread_map__new(-1, getpid(), UINT_MAX); | ||
24 | if (threads == NULL) { | 16 | if (threads == NULL) { |
25 | pr_debug("thread_map__new\n"); | 17 | pr_debug("thread_map__new\n"); |
26 | return -1; | 18 | return -1; |
@@ -32,15 +24,11 @@ int test__open_syscall_event_on_all_cpus(void) | |||
32 | goto out_thread_map_delete; | 24 | goto out_thread_map_delete; |
33 | } | 25 | } |
34 | 26 | ||
35 | |||
36 | CPU_ZERO(&cpu_set); | 27 | CPU_ZERO(&cpu_set); |
37 | 28 | ||
38 | memset(&attr, 0, sizeof(attr)); | 29 | evsel = perf_evsel__newtp("syscalls", "sys_enter_open", 0); |
39 | attr.type = PERF_TYPE_TRACEPOINT; | ||
40 | attr.config = id; | ||
41 | evsel = perf_evsel__new(&attr, 0); | ||
42 | if (evsel == NULL) { | 30 | if (evsel == NULL) { |
43 | pr_debug("perf_evsel__new\n"); | 31 | pr_debug("is debugfs mounted on /sys/kernel/debug?\n"); |
44 | goto out_thread_map_delete; | 32 | goto out_thread_map_delete; |
45 | } | 33 | } |
46 | 34 | ||
@@ -110,6 +98,7 @@ int test__open_syscall_event_on_all_cpus(void) | |||
110 | } | 98 | } |
111 | } | 99 | } |
112 | 100 | ||
101 | perf_evsel__free_counts(evsel); | ||
113 | out_close_fd: | 102 | out_close_fd: |
114 | perf_evsel__close_fd(evsel, 1, threads->nr); | 103 | perf_evsel__close_fd(evsel, 1, threads->nr); |
115 | out_evsel_delete: | 104 | out_evsel_delete: |
diff --git a/tools/perf/tests/open-syscall.c b/tools/perf/tests/open-syscall.c index 98be8b518b4f..befc0671f95d 100644 --- a/tools/perf/tests/open-syscall.c +++ b/tools/perf/tests/open-syscall.c | |||
@@ -6,29 +6,18 @@ | |||
6 | int test__open_syscall_event(void) | 6 | int test__open_syscall_event(void) |
7 | { | 7 | { |
8 | int err = -1, fd; | 8 | int err = -1, fd; |
9 | struct thread_map *threads; | ||
10 | struct perf_evsel *evsel; | 9 | struct perf_evsel *evsel; |
11 | struct perf_event_attr attr; | ||
12 | unsigned int nr_open_calls = 111, i; | 10 | unsigned int nr_open_calls = 111, i; |
13 | int id = trace_event__id("sys_enter_open"); | 11 | struct thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX); |
14 | 12 | ||
15 | if (id < 0) { | ||
16 | pr_debug("is debugfs mounted on /sys/kernel/debug?\n"); | ||
17 | return -1; | ||
18 | } | ||
19 | |||
20 | threads = thread_map__new(-1, getpid(), UINT_MAX); | ||
21 | if (threads == NULL) { | 13 | if (threads == NULL) { |
22 | pr_debug("thread_map__new\n"); | 14 | pr_debug("thread_map__new\n"); |
23 | return -1; | 15 | return -1; |
24 | } | 16 | } |
25 | 17 | ||
26 | memset(&attr, 0, sizeof(attr)); | 18 | evsel = perf_evsel__newtp("syscalls", "sys_enter_open", 0); |
27 | attr.type = PERF_TYPE_TRACEPOINT; | ||
28 | attr.config = id; | ||
29 | evsel = perf_evsel__new(&attr, 0); | ||
30 | if (evsel == NULL) { | 19 | if (evsel == NULL) { |
31 | pr_debug("perf_evsel__new\n"); | 20 | pr_debug("is debugfs mounted on /sys/kernel/debug?\n"); |
32 | goto out_thread_map_delete; | 21 | goto out_thread_map_delete; |
33 | } | 22 | } |
34 | 23 | ||
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 32ee478905eb..c5636f36fe31 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c | |||
@@ -3,6 +3,7 @@ | |||
3 | #include "evsel.h" | 3 | #include "evsel.h" |
4 | #include "evlist.h" | 4 | #include "evlist.h" |
5 | #include "sysfs.h" | 5 | #include "sysfs.h" |
6 | #include "debugfs.h" | ||
6 | #include "tests.h" | 7 | #include "tests.h" |
7 | #include <linux/hw_breakpoint.h> | 8 | #include <linux/hw_breakpoint.h> |
8 | 9 | ||
@@ -22,6 +23,7 @@ static int test__checkevent_tracepoint(struct perf_evlist *evlist) | |||
22 | struct perf_evsel *evsel = perf_evlist__first(evlist); | 23 | struct perf_evsel *evsel = perf_evlist__first(evlist); |
23 | 24 | ||
24 | TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); | 25 | TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); |
26 | TEST_ASSERT_VAL("wrong number of groups", 0 == evlist->nr_groups); | ||
25 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type); | 27 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type); |
26 | TEST_ASSERT_VAL("wrong sample_type", | 28 | TEST_ASSERT_VAL("wrong sample_type", |
27 | PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type); | 29 | PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type); |
@@ -34,6 +36,7 @@ static int test__checkevent_tracepoint_multi(struct perf_evlist *evlist) | |||
34 | struct perf_evsel *evsel; | 36 | struct perf_evsel *evsel; |
35 | 37 | ||
36 | TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1); | 38 | TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1); |
39 | TEST_ASSERT_VAL("wrong number of groups", 0 == evlist->nr_groups); | ||
37 | 40 | ||
38 | list_for_each_entry(evsel, &evlist->entries, node) { | 41 | list_for_each_entry(evsel, &evlist->entries, node) { |
39 | TEST_ASSERT_VAL("wrong type", | 42 | TEST_ASSERT_VAL("wrong type", |
@@ -463,10 +466,10 @@ static int test__checkevent_pmu_events(struct perf_evlist *evlist) | |||
463 | 466 | ||
464 | static int test__checkterms_simple(struct list_head *terms) | 467 | static int test__checkterms_simple(struct list_head *terms) |
465 | { | 468 | { |
466 | struct parse_events__term *term; | 469 | struct parse_events_term *term; |
467 | 470 | ||
468 | /* config=10 */ | 471 | /* config=10 */ |
469 | term = list_entry(terms->next, struct parse_events__term, list); | 472 | term = list_entry(terms->next, struct parse_events_term, list); |
470 | TEST_ASSERT_VAL("wrong type term", | 473 | TEST_ASSERT_VAL("wrong type term", |
471 | term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG); | 474 | term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG); |
472 | TEST_ASSERT_VAL("wrong type val", | 475 | TEST_ASSERT_VAL("wrong type val", |
@@ -475,7 +478,7 @@ static int test__checkterms_simple(struct list_head *terms) | |||
475 | TEST_ASSERT_VAL("wrong config", !term->config); | 478 | TEST_ASSERT_VAL("wrong config", !term->config); |
476 | 479 | ||
477 | /* config1 */ | 480 | /* config1 */ |
478 | term = list_entry(term->list.next, struct parse_events__term, list); | 481 | term = list_entry(term->list.next, struct parse_events_term, list); |
479 | TEST_ASSERT_VAL("wrong type term", | 482 | TEST_ASSERT_VAL("wrong type term", |
480 | term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG1); | 483 | term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG1); |
481 | TEST_ASSERT_VAL("wrong type val", | 484 | TEST_ASSERT_VAL("wrong type val", |
@@ -484,7 +487,7 @@ static int test__checkterms_simple(struct list_head *terms) | |||
484 | TEST_ASSERT_VAL("wrong config", !term->config); | 487 | TEST_ASSERT_VAL("wrong config", !term->config); |
485 | 488 | ||
486 | /* config2=3 */ | 489 | /* config2=3 */ |
487 | term = list_entry(term->list.next, struct parse_events__term, list); | 490 | term = list_entry(term->list.next, struct parse_events_term, list); |
488 | TEST_ASSERT_VAL("wrong type term", | 491 | TEST_ASSERT_VAL("wrong type term", |
489 | term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG2); | 492 | term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG2); |
490 | TEST_ASSERT_VAL("wrong type val", | 493 | TEST_ASSERT_VAL("wrong type val", |
@@ -493,7 +496,7 @@ static int test__checkterms_simple(struct list_head *terms) | |||
493 | TEST_ASSERT_VAL("wrong config", !term->config); | 496 | TEST_ASSERT_VAL("wrong config", !term->config); |
494 | 497 | ||
495 | /* umask=1*/ | 498 | /* umask=1*/ |
496 | term = list_entry(term->list.next, struct parse_events__term, list); | 499 | term = list_entry(term->list.next, struct parse_events_term, list); |
497 | TEST_ASSERT_VAL("wrong type term", | 500 | TEST_ASSERT_VAL("wrong type term", |
498 | term->type_term == PARSE_EVENTS__TERM_TYPE_USER); | 501 | term->type_term == PARSE_EVENTS__TERM_TYPE_USER); |
499 | TEST_ASSERT_VAL("wrong type val", | 502 | TEST_ASSERT_VAL("wrong type val", |
@@ -509,6 +512,7 @@ static int test__group1(struct perf_evlist *evlist) | |||
509 | struct perf_evsel *evsel, *leader; | 512 | struct perf_evsel *evsel, *leader; |
510 | 513 | ||
511 | TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); | 514 | TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); |
515 | TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); | ||
512 | 516 | ||
513 | /* instructions:k */ | 517 | /* instructions:k */ |
514 | evsel = leader = perf_evlist__first(evlist); | 518 | evsel = leader = perf_evlist__first(evlist); |
@@ -521,7 +525,9 @@ static int test__group1(struct perf_evlist *evlist) | |||
521 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | 525 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); |
522 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | 526 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); |
523 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | 527 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); |
524 | TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); | 528 | TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); |
529 | TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); | ||
530 | TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); | ||
525 | 531 | ||
526 | /* cycles:upp */ | 532 | /* cycles:upp */ |
527 | evsel = perf_evsel__next(evsel); | 533 | evsel = perf_evsel__next(evsel); |
@@ -536,6 +542,7 @@ static int test__group1(struct perf_evlist *evlist) | |||
536 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | 542 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); |
537 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2); | 543 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2); |
538 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); | 544 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); |
545 | TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); | ||
539 | 546 | ||
540 | return 0; | 547 | return 0; |
541 | } | 548 | } |
@@ -545,6 +552,7 @@ static int test__group2(struct perf_evlist *evlist) | |||
545 | struct perf_evsel *evsel, *leader; | 552 | struct perf_evsel *evsel, *leader; |
546 | 553 | ||
547 | TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries); | 554 | TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries); |
555 | TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); | ||
548 | 556 | ||
549 | /* faults + :ku modifier */ | 557 | /* faults + :ku modifier */ |
550 | evsel = leader = perf_evlist__first(evlist); | 558 | evsel = leader = perf_evlist__first(evlist); |
@@ -557,7 +565,9 @@ static int test__group2(struct perf_evlist *evlist) | |||
557 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | 565 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); |
558 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | 566 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); |
559 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | 567 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); |
560 | TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); | 568 | TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); |
569 | TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); | ||
570 | TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); | ||
561 | 571 | ||
562 | /* cache-references + :u modifier */ | 572 | /* cache-references + :u modifier */ |
563 | evsel = perf_evsel__next(evsel); | 573 | evsel = perf_evsel__next(evsel); |
@@ -567,10 +577,11 @@ static int test__group2(struct perf_evlist *evlist) | |||
567 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | 577 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); |
568 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); | 578 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); |
569 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | 579 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); |
570 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | 580 | TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); |
571 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | 581 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); |
572 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | 582 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); |
573 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); | 583 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); |
584 | TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); | ||
574 | 585 | ||
575 | /* cycles:k */ | 586 | /* cycles:k */ |
576 | evsel = perf_evsel__next(evsel); | 587 | evsel = perf_evsel__next(evsel); |
@@ -583,7 +594,7 @@ static int test__group2(struct perf_evlist *evlist) | |||
583 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | 594 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); |
584 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | 595 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); |
585 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | 596 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); |
586 | TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); | 597 | TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); |
587 | 598 | ||
588 | return 0; | 599 | return 0; |
589 | } | 600 | } |
@@ -593,6 +604,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused) | |||
593 | struct perf_evsel *evsel, *leader; | 604 | struct perf_evsel *evsel, *leader; |
594 | 605 | ||
595 | TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->nr_entries); | 606 | TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->nr_entries); |
607 | TEST_ASSERT_VAL("wrong number of groups", 2 == evlist->nr_groups); | ||
596 | 608 | ||
597 | /* group1 syscalls:sys_enter_open:H */ | 609 | /* group1 syscalls:sys_enter_open:H */ |
598 | evsel = leader = perf_evlist__first(evlist); | 610 | evsel = leader = perf_evlist__first(evlist); |
@@ -606,9 +618,11 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused) | |||
606 | TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); | 618 | TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); |
607 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | 619 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); |
608 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | 620 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); |
609 | TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); | 621 | TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); |
610 | TEST_ASSERT_VAL("wrong group name", | 622 | TEST_ASSERT_VAL("wrong group name", |
611 | !strcmp(leader->group_name, "group1")); | 623 | !strcmp(leader->group_name, "group1")); |
624 | TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); | ||
625 | TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); | ||
612 | 626 | ||
613 | /* group1 cycles:kppp */ | 627 | /* group1 cycles:kppp */ |
614 | evsel = perf_evsel__next(evsel); | 628 | evsel = perf_evsel__next(evsel); |
@@ -624,6 +638,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused) | |||
624 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 3); | 638 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 3); |
625 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); | 639 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); |
626 | TEST_ASSERT_VAL("wrong group name", !evsel->group_name); | 640 | TEST_ASSERT_VAL("wrong group name", !evsel->group_name); |
641 | TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); | ||
627 | 642 | ||
628 | /* group2 cycles + G modifier */ | 643 | /* group2 cycles + G modifier */ |
629 | evsel = leader = perf_evsel__next(evsel); | 644 | evsel = leader = perf_evsel__next(evsel); |
@@ -636,9 +651,11 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused) | |||
636 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | 651 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); |
637 | TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); | 652 | TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); |
638 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | 653 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); |
639 | TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); | 654 | TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); |
640 | TEST_ASSERT_VAL("wrong group name", | 655 | TEST_ASSERT_VAL("wrong group name", |
641 | !strcmp(leader->group_name, "group2")); | 656 | !strcmp(leader->group_name, "group2")); |
657 | TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); | ||
658 | TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); | ||
642 | 659 | ||
643 | /* group2 1:3 + G modifier */ | 660 | /* group2 1:3 + G modifier */ |
644 | evsel = perf_evsel__next(evsel); | 661 | evsel = perf_evsel__next(evsel); |
@@ -651,6 +668,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused) | |||
651 | TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); | 668 | TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); |
652 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | 669 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); |
653 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); | 670 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); |
671 | TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); | ||
654 | 672 | ||
655 | /* instructions:u */ | 673 | /* instructions:u */ |
656 | evsel = perf_evsel__next(evsel); | 674 | evsel = perf_evsel__next(evsel); |
@@ -663,7 +681,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused) | |||
663 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | 681 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); |
664 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | 682 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); |
665 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | 683 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); |
666 | TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); | 684 | TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); |
667 | 685 | ||
668 | return 0; | 686 | return 0; |
669 | } | 687 | } |
@@ -673,6 +691,7 @@ static int test__group4(struct perf_evlist *evlist __maybe_unused) | |||
673 | struct perf_evsel *evsel, *leader; | 691 | struct perf_evsel *evsel, *leader; |
674 | 692 | ||
675 | TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); | 693 | TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); |
694 | TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); | ||
676 | 695 | ||
677 | /* cycles:u + p */ | 696 | /* cycles:u + p */ |
678 | evsel = leader = perf_evlist__first(evlist); | 697 | evsel = leader = perf_evlist__first(evlist); |
@@ -687,7 +706,9 @@ static int test__group4(struct perf_evlist *evlist __maybe_unused) | |||
687 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | 706 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); |
688 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 1); | 707 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 1); |
689 | TEST_ASSERT_VAL("wrong group name", !evsel->group_name); | 708 | TEST_ASSERT_VAL("wrong group name", !evsel->group_name); |
690 | TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); | 709 | TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); |
710 | TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); | ||
711 | TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); | ||
691 | 712 | ||
692 | /* instructions:kp + p */ | 713 | /* instructions:kp + p */ |
693 | evsel = perf_evsel__next(evsel); | 714 | evsel = perf_evsel__next(evsel); |
@@ -702,6 +723,7 @@ static int test__group4(struct perf_evlist *evlist __maybe_unused) | |||
702 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | 723 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); |
703 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2); | 724 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2); |
704 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); | 725 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); |
726 | TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); | ||
705 | 727 | ||
706 | return 0; | 728 | return 0; |
707 | } | 729 | } |
@@ -711,6 +733,7 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused) | |||
711 | struct perf_evsel *evsel, *leader; | 733 | struct perf_evsel *evsel, *leader; |
712 | 734 | ||
713 | TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->nr_entries); | 735 | TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->nr_entries); |
736 | TEST_ASSERT_VAL("wrong number of groups", 2 == evlist->nr_groups); | ||
714 | 737 | ||
715 | /* cycles + G */ | 738 | /* cycles + G */ |
716 | evsel = leader = perf_evlist__first(evlist); | 739 | evsel = leader = perf_evlist__first(evlist); |
@@ -724,7 +747,9 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused) | |||
724 | TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); | 747 | TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); |
725 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | 748 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); |
726 | TEST_ASSERT_VAL("wrong group name", !evsel->group_name); | 749 | TEST_ASSERT_VAL("wrong group name", !evsel->group_name); |
727 | TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); | 750 | TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); |
751 | TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); | ||
752 | TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); | ||
728 | 753 | ||
729 | /* instructions + G */ | 754 | /* instructions + G */ |
730 | evsel = perf_evsel__next(evsel); | 755 | evsel = perf_evsel__next(evsel); |
@@ -738,6 +763,7 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused) | |||
738 | TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); | 763 | TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); |
739 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | 764 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); |
740 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); | 765 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); |
766 | TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); | ||
741 | 767 | ||
742 | /* cycles:G */ | 768 | /* cycles:G */ |
743 | evsel = leader = perf_evsel__next(evsel); | 769 | evsel = leader = perf_evsel__next(evsel); |
@@ -751,7 +777,9 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused) | |||
751 | TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); | 777 | TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); |
752 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | 778 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); |
753 | TEST_ASSERT_VAL("wrong group name", !evsel->group_name); | 779 | TEST_ASSERT_VAL("wrong group name", !evsel->group_name); |
754 | TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); | 780 | TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); |
781 | TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); | ||
782 | TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); | ||
755 | 783 | ||
756 | /* instructions:G */ | 784 | /* instructions:G */ |
757 | evsel = perf_evsel__next(evsel); | 785 | evsel = perf_evsel__next(evsel); |
@@ -765,6 +793,7 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused) | |||
765 | TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); | 793 | TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); |
766 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | 794 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); |
767 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); | 795 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); |
796 | TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); | ||
768 | 797 | ||
769 | /* cycles */ | 798 | /* cycles */ |
770 | evsel = perf_evsel__next(evsel); | 799 | evsel = perf_evsel__next(evsel); |
@@ -777,18 +806,235 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused) | |||
777 | TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); | 806 | TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); |
778 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | 807 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); |
779 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | 808 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); |
780 | TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); | 809 | TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); |
810 | |||
811 | return 0; | ||
812 | } | ||
813 | |||
814 | static int test__group_gh1(struct perf_evlist *evlist) | ||
815 | { | ||
816 | struct perf_evsel *evsel, *leader; | ||
817 | |||
818 | TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); | ||
819 | TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); | ||
820 | |||
821 | /* cycles + :H group modifier */ | ||
822 | evsel = leader = perf_evlist__first(evlist); | ||
823 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); | ||
824 | TEST_ASSERT_VAL("wrong config", | ||
825 | PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config); | ||
826 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | ||
827 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); | ||
828 | TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); | ||
829 | TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); | ||
830 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | ||
831 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
832 | TEST_ASSERT_VAL("wrong group name", !evsel->group_name); | ||
833 | TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); | ||
834 | TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); | ||
835 | TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); | ||
836 | |||
837 | /* cache-misses:G + :H group modifier */ | ||
838 | evsel = perf_evsel__next(evsel); | ||
839 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); | ||
840 | TEST_ASSERT_VAL("wrong config", | ||
841 | PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config); | ||
842 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | ||
843 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); | ||
844 | TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); | ||
845 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | ||
846 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | ||
847 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
848 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); | ||
849 | TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); | ||
850 | |||
851 | return 0; | ||
852 | } | ||
853 | |||
854 | static int test__group_gh2(struct perf_evlist *evlist) | ||
855 | { | ||
856 | struct perf_evsel *evsel, *leader; | ||
857 | |||
858 | TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); | ||
859 | TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); | ||
860 | |||
861 | /* cycles + :G group modifier */ | ||
862 | evsel = leader = perf_evlist__first(evlist); | ||
863 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); | ||
864 | TEST_ASSERT_VAL("wrong config", | ||
865 | PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config); | ||
866 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | ||
867 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); | ||
868 | TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); | ||
869 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | ||
870 | TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); | ||
871 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
872 | TEST_ASSERT_VAL("wrong group name", !evsel->group_name); | ||
873 | TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); | ||
874 | TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); | ||
875 | TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); | ||
876 | |||
877 | /* cache-misses:H + :G group modifier */ | ||
878 | evsel = perf_evsel__next(evsel); | ||
879 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); | ||
880 | TEST_ASSERT_VAL("wrong config", | ||
881 | PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config); | ||
882 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | ||
883 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); | ||
884 | TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); | ||
885 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | ||
886 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | ||
887 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
888 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); | ||
889 | TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); | ||
890 | |||
891 | return 0; | ||
892 | } | ||
893 | |||
894 | static int test__group_gh3(struct perf_evlist *evlist) | ||
895 | { | ||
896 | struct perf_evsel *evsel, *leader; | ||
897 | |||
898 | TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); | ||
899 | TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); | ||
900 | |||
901 | /* cycles:G + :u group modifier */ | ||
902 | evsel = leader = perf_evlist__first(evlist); | ||
903 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); | ||
904 | TEST_ASSERT_VAL("wrong config", | ||
905 | PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config); | ||
906 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | ||
907 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); | ||
908 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | ||
909 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | ||
910 | TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); | ||
911 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
912 | TEST_ASSERT_VAL("wrong group name", !evsel->group_name); | ||
913 | TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); | ||
914 | TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); | ||
915 | TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); | ||
916 | |||
917 | /* cache-misses:H + :u group modifier */ | ||
918 | evsel = perf_evsel__next(evsel); | ||
919 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); | ||
920 | TEST_ASSERT_VAL("wrong config", | ||
921 | PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config); | ||
922 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | ||
923 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); | ||
924 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | ||
925 | TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); | ||
926 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | ||
927 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
928 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); | ||
929 | TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); | ||
930 | |||
931 | return 0; | ||
932 | } | ||
933 | |||
934 | static int test__group_gh4(struct perf_evlist *evlist) | ||
935 | { | ||
936 | struct perf_evsel *evsel, *leader; | ||
937 | |||
938 | TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); | ||
939 | TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); | ||
940 | |||
941 | /* cycles:G + :uG group modifier */ | ||
942 | evsel = leader = perf_evlist__first(evlist); | ||
943 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); | ||
944 | TEST_ASSERT_VAL("wrong config", | ||
945 | PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config); | ||
946 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | ||
947 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); | ||
948 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | ||
949 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | ||
950 | TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); | ||
951 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
952 | TEST_ASSERT_VAL("wrong group name", !evsel->group_name); | ||
953 | TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); | ||
954 | TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); | ||
955 | TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); | ||
956 | |||
957 | /* cache-misses:H + :uG group modifier */ | ||
958 | evsel = perf_evsel__next(evsel); | ||
959 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); | ||
960 | TEST_ASSERT_VAL("wrong config", | ||
961 | PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config); | ||
962 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | ||
963 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); | ||
964 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | ||
965 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | ||
966 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | ||
967 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
968 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); | ||
969 | TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); | ||
781 | 970 | ||
782 | return 0; | 971 | return 0; |
783 | } | 972 | } |
784 | 973 | ||
785 | struct test__event_st { | 974 | static int count_tracepoints(void) |
975 | { | ||
976 | char events_path[PATH_MAX]; | ||
977 | struct dirent *events_ent; | ||
978 | DIR *events_dir; | ||
979 | int cnt = 0; | ||
980 | |||
981 | scnprintf(events_path, PATH_MAX, "%s/tracing/events", | ||
982 | debugfs_find_mountpoint()); | ||
983 | |||
984 | events_dir = opendir(events_path); | ||
985 | |||
986 | TEST_ASSERT_VAL("Can't open events dir", events_dir); | ||
987 | |||
988 | while ((events_ent = readdir(events_dir))) { | ||
989 | char sys_path[PATH_MAX]; | ||
990 | struct dirent *sys_ent; | ||
991 | DIR *sys_dir; | ||
992 | |||
993 | if (!strcmp(events_ent->d_name, ".") | ||
994 | || !strcmp(events_ent->d_name, "..") | ||
995 | || !strcmp(events_ent->d_name, "enable") | ||
996 | || !strcmp(events_ent->d_name, "header_event") | ||
997 | || !strcmp(events_ent->d_name, "header_page")) | ||
998 | continue; | ||
999 | |||
1000 | scnprintf(sys_path, PATH_MAX, "%s/%s", | ||
1001 | events_path, events_ent->d_name); | ||
1002 | |||
1003 | sys_dir = opendir(sys_path); | ||
1004 | TEST_ASSERT_VAL("Can't open sys dir", sys_dir); | ||
1005 | |||
1006 | while ((sys_ent = readdir(sys_dir))) { | ||
1007 | if (!strcmp(sys_ent->d_name, ".") | ||
1008 | || !strcmp(sys_ent->d_name, "..") | ||
1009 | || !strcmp(sys_ent->d_name, "enable") | ||
1010 | || !strcmp(sys_ent->d_name, "filter")) | ||
1011 | continue; | ||
1012 | |||
1013 | cnt++; | ||
1014 | } | ||
1015 | |||
1016 | closedir(sys_dir); | ||
1017 | } | ||
1018 | |||
1019 | closedir(events_dir); | ||
1020 | return cnt; | ||
1021 | } | ||
1022 | |||
1023 | static int test__all_tracepoints(struct perf_evlist *evlist) | ||
1024 | { | ||
1025 | TEST_ASSERT_VAL("wrong events count", | ||
1026 | count_tracepoints() == evlist->nr_entries); | ||
1027 | |||
1028 | return test__checkevent_tracepoint_multi(evlist); | ||
1029 | } | ||
1030 | |||
1031 | struct evlist_test { | ||
786 | const char *name; | 1032 | const char *name; |
787 | __u32 type; | 1033 | __u32 type; |
788 | int (*check)(struct perf_evlist *evlist); | 1034 | int (*check)(struct perf_evlist *evlist); |
789 | }; | 1035 | }; |
790 | 1036 | ||
791 | static struct test__event_st test__events[] = { | 1037 | static struct evlist_test test__events[] = { |
792 | [0] = { | 1038 | [0] = { |
793 | .name = "syscalls:sys_enter_open", | 1039 | .name = "syscalls:sys_enter_open", |
794 | .check = test__checkevent_tracepoint, | 1040 | .check = test__checkevent_tracepoint, |
@@ -921,9 +1167,29 @@ static struct test__event_st test__events[] = { | |||
921 | .name = "{cycles,instructions}:G,{cycles:G,instructions:G},cycles", | 1167 | .name = "{cycles,instructions}:G,{cycles:G,instructions:G},cycles", |
922 | .check = test__group5, | 1168 | .check = test__group5, |
923 | }, | 1169 | }, |
1170 | [33] = { | ||
1171 | .name = "*:*", | ||
1172 | .check = test__all_tracepoints, | ||
1173 | }, | ||
1174 | [34] = { | ||
1175 | .name = "{cycles,cache-misses:G}:H", | ||
1176 | .check = test__group_gh1, | ||
1177 | }, | ||
1178 | [35] = { | ||
1179 | .name = "{cycles,cache-misses:H}:G", | ||
1180 | .check = test__group_gh2, | ||
1181 | }, | ||
1182 | [36] = { | ||
1183 | .name = "{cycles:G,cache-misses:H}:u", | ||
1184 | .check = test__group_gh3, | ||
1185 | }, | ||
1186 | [37] = { | ||
1187 | .name = "{cycles:G,cache-misses:H}:uG", | ||
1188 | .check = test__group_gh4, | ||
1189 | }, | ||
924 | }; | 1190 | }; |
925 | 1191 | ||
926 | static struct test__event_st test__events_pmu[] = { | 1192 | static struct evlist_test test__events_pmu[] = { |
927 | [0] = { | 1193 | [0] = { |
928 | .name = "cpu/config=10,config1,config2=3,period=1000/u", | 1194 | .name = "cpu/config=10,config1,config2=3,period=1000/u", |
929 | .check = test__checkevent_pmu, | 1195 | .check = test__checkevent_pmu, |
@@ -934,20 +1200,20 @@ static struct test__event_st test__events_pmu[] = { | |||
934 | }, | 1200 | }, |
935 | }; | 1201 | }; |
936 | 1202 | ||
937 | struct test__term { | 1203 | struct terms_test { |
938 | const char *str; | 1204 | const char *str; |
939 | __u32 type; | 1205 | __u32 type; |
940 | int (*check)(struct list_head *terms); | 1206 | int (*check)(struct list_head *terms); |
941 | }; | 1207 | }; |
942 | 1208 | ||
943 | static struct test__term test__terms[] = { | 1209 | static struct terms_test test__terms[] = { |
944 | [0] = { | 1210 | [0] = { |
945 | .str = "config=10,config1,config2=3,umask=1", | 1211 | .str = "config=10,config1,config2=3,umask=1", |
946 | .check = test__checkterms_simple, | 1212 | .check = test__checkterms_simple, |
947 | }, | 1213 | }, |
948 | }; | 1214 | }; |
949 | 1215 | ||
950 | static int test_event(struct test__event_st *e) | 1216 | static int test_event(struct evlist_test *e) |
951 | { | 1217 | { |
952 | struct perf_evlist *evlist; | 1218 | struct perf_evlist *evlist; |
953 | int ret; | 1219 | int ret; |
@@ -956,7 +1222,7 @@ static int test_event(struct test__event_st *e) | |||
956 | if (evlist == NULL) | 1222 | if (evlist == NULL) |
957 | return -ENOMEM; | 1223 | return -ENOMEM; |
958 | 1224 | ||
959 | ret = parse_events(evlist, e->name, 0); | 1225 | ret = parse_events(evlist, e->name); |
960 | if (ret) { | 1226 | if (ret) { |
961 | pr_debug("failed to parse event '%s', err %d\n", | 1227 | pr_debug("failed to parse event '%s', err %d\n", |
962 | e->name, ret); | 1228 | e->name, ret); |
@@ -969,13 +1235,13 @@ static int test_event(struct test__event_st *e) | |||
969 | return ret; | 1235 | return ret; |
970 | } | 1236 | } |
971 | 1237 | ||
972 | static int test_events(struct test__event_st *events, unsigned cnt) | 1238 | static int test_events(struct evlist_test *events, unsigned cnt) |
973 | { | 1239 | { |
974 | int ret1, ret2 = 0; | 1240 | int ret1, ret2 = 0; |
975 | unsigned i; | 1241 | unsigned i; |
976 | 1242 | ||
977 | for (i = 0; i < cnt; i++) { | 1243 | for (i = 0; i < cnt; i++) { |
978 | struct test__event_st *e = &events[i]; | 1244 | struct evlist_test *e = &events[i]; |
979 | 1245 | ||
980 | pr_debug("running test %d '%s'\n", i, e->name); | 1246 | pr_debug("running test %d '%s'\n", i, e->name); |
981 | ret1 = test_event(e); | 1247 | ret1 = test_event(e); |
@@ -986,7 +1252,7 @@ static int test_events(struct test__event_st *events, unsigned cnt) | |||
986 | return ret2; | 1252 | return ret2; |
987 | } | 1253 | } |
988 | 1254 | ||
989 | static int test_term(struct test__term *t) | 1255 | static int test_term(struct terms_test *t) |
990 | { | 1256 | { |
991 | struct list_head *terms; | 1257 | struct list_head *terms; |
992 | int ret; | 1258 | int ret; |
@@ -1010,13 +1276,13 @@ static int test_term(struct test__term *t) | |||
1010 | return ret; | 1276 | return ret; |
1011 | } | 1277 | } |
1012 | 1278 | ||
1013 | static int test_terms(struct test__term *terms, unsigned cnt) | 1279 | static int test_terms(struct terms_test *terms, unsigned cnt) |
1014 | { | 1280 | { |
1015 | int ret = 0; | 1281 | int ret = 0; |
1016 | unsigned i; | 1282 | unsigned i; |
1017 | 1283 | ||
1018 | for (i = 0; i < cnt; i++) { | 1284 | for (i = 0; i < cnt; i++) { |
1019 | struct test__term *t = &terms[i]; | 1285 | struct terms_test *t = &terms[i]; |
1020 | 1286 | ||
1021 | pr_debug("running test %d '%s'\n", i, t->str); | 1287 | pr_debug("running test %d '%s'\n", i, t->str); |
1022 | ret = test_term(t); | 1288 | ret = test_term(t); |
@@ -1067,7 +1333,7 @@ static int test_pmu_events(void) | |||
1067 | 1333 | ||
1068 | while (!ret && (ent = readdir(dir))) { | 1334 | while (!ret && (ent = readdir(dir))) { |
1069 | #define MAX_NAME 100 | 1335 | #define MAX_NAME 100 |
1070 | struct test__event_st e; | 1336 | struct evlist_test e; |
1071 | char name[MAX_NAME]; | 1337 | char name[MAX_NAME]; |
1072 | 1338 | ||
1073 | if (!strcmp(ent->d_name, ".") || | 1339 | if (!strcmp(ent->d_name, ".") || |
diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c index 70e0d4421df8..1e8e5128d0da 100644 --- a/tools/perf/tests/perf-record.c +++ b/tools/perf/tests/perf-record.c | |||
@@ -96,22 +96,22 @@ int test__PERF_RECORD(void) | |||
96 | err = perf_evlist__prepare_workload(evlist, &opts, argv); | 96 | err = perf_evlist__prepare_workload(evlist, &opts, argv); |
97 | if (err < 0) { | 97 | if (err < 0) { |
98 | pr_debug("Couldn't run the workload!\n"); | 98 | pr_debug("Couldn't run the workload!\n"); |
99 | goto out_delete_evlist; | 99 | goto out_delete_maps; |
100 | } | 100 | } |
101 | 101 | ||
102 | /* | 102 | /* |
103 | * Config the evsels, setting attr->comm on the first one, etc. | 103 | * Config the evsels, setting attr->comm on the first one, etc. |
104 | */ | 104 | */ |
105 | evsel = perf_evlist__first(evlist); | 105 | evsel = perf_evlist__first(evlist); |
106 | evsel->attr.sample_type |= PERF_SAMPLE_CPU; | 106 | perf_evsel__set_sample_bit(evsel, CPU); |
107 | evsel->attr.sample_type |= PERF_SAMPLE_TID; | 107 | perf_evsel__set_sample_bit(evsel, TID); |
108 | evsel->attr.sample_type |= PERF_SAMPLE_TIME; | 108 | perf_evsel__set_sample_bit(evsel, TIME); |
109 | perf_evlist__config_attrs(evlist, &opts); | 109 | perf_evlist__config(evlist, &opts); |
110 | 110 | ||
111 | err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask); | 111 | err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask); |
112 | if (err < 0) { | 112 | if (err < 0) { |
113 | pr_debug("sched__get_first_possible_cpu: %s\n", strerror(errno)); | 113 | pr_debug("sched__get_first_possible_cpu: %s\n", strerror(errno)); |
114 | goto out_delete_evlist; | 114 | goto out_delete_maps; |
115 | } | 115 | } |
116 | 116 | ||
117 | cpu = err; | 117 | cpu = err; |
@@ -121,7 +121,7 @@ int test__PERF_RECORD(void) | |||
121 | */ | 121 | */ |
122 | if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, &cpu_mask) < 0) { | 122 | if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, &cpu_mask) < 0) { |
123 | pr_debug("sched_setaffinity: %s\n", strerror(errno)); | 123 | pr_debug("sched_setaffinity: %s\n", strerror(errno)); |
124 | goto out_delete_evlist; | 124 | goto out_delete_maps; |
125 | } | 125 | } |
126 | 126 | ||
127 | /* | 127 | /* |
@@ -131,7 +131,7 @@ int test__PERF_RECORD(void) | |||
131 | err = perf_evlist__open(evlist); | 131 | err = perf_evlist__open(evlist); |
132 | if (err < 0) { | 132 | if (err < 0) { |
133 | pr_debug("perf_evlist__open: %s\n", strerror(errno)); | 133 | pr_debug("perf_evlist__open: %s\n", strerror(errno)); |
134 | goto out_delete_evlist; | 134 | goto out_delete_maps; |
135 | } | 135 | } |
136 | 136 | ||
137 | /* | 137 | /* |
@@ -142,7 +142,7 @@ int test__PERF_RECORD(void) | |||
142 | err = perf_evlist__mmap(evlist, opts.mmap_pages, false); | 142 | err = perf_evlist__mmap(evlist, opts.mmap_pages, false); |
143 | if (err < 0) { | 143 | if (err < 0) { |
144 | pr_debug("perf_evlist__mmap: %s\n", strerror(errno)); | 144 | pr_debug("perf_evlist__mmap: %s\n", strerror(errno)); |
145 | goto out_delete_evlist; | 145 | goto out_delete_maps; |
146 | } | 146 | } |
147 | 147 | ||
148 | /* | 148 | /* |
@@ -305,6 +305,8 @@ found_exit: | |||
305 | } | 305 | } |
306 | out_err: | 306 | out_err: |
307 | perf_evlist__munmap(evlist); | 307 | perf_evlist__munmap(evlist); |
308 | out_delete_maps: | ||
309 | perf_evlist__delete_maps(evlist); | ||
308 | out_delete_evlist: | 310 | out_delete_evlist: |
309 | perf_evlist__delete(evlist); | 311 | perf_evlist__delete(evlist); |
310 | out: | 312 | out: |
diff --git a/tools/perf/tests/pmu.c b/tools/perf/tests/pmu.c index a5f379863b8f..12b322fa3475 100644 --- a/tools/perf/tests/pmu.c +++ b/tools/perf/tests/pmu.c | |||
@@ -19,10 +19,8 @@ static struct test_format { | |||
19 | { "krava23", "config2:28-29,38\n", }, | 19 | { "krava23", "config2:28-29,38\n", }, |
20 | }; | 20 | }; |
21 | 21 | ||
22 | #define TEST_FORMATS_CNT (sizeof(test_formats) / sizeof(struct test_format)) | ||
23 | |||
24 | /* Simulated users input. */ | 22 | /* Simulated users input. */ |
25 | static struct parse_events__term test_terms[] = { | 23 | static struct parse_events_term test_terms[] = { |
26 | { | 24 | { |
27 | .config = (char *) "krava01", | 25 | .config = (char *) "krava01", |
28 | .val.num = 15, | 26 | .val.num = 15, |
@@ -78,7 +76,6 @@ static struct parse_events__term test_terms[] = { | |||
78 | .type_term = PARSE_EVENTS__TERM_TYPE_USER, | 76 | .type_term = PARSE_EVENTS__TERM_TYPE_USER, |
79 | }, | 77 | }, |
80 | }; | 78 | }; |
81 | #define TERMS_CNT (sizeof(test_terms) / sizeof(struct parse_events__term)) | ||
82 | 79 | ||
83 | /* | 80 | /* |
84 | * Prepare format directory data, exported by kernel | 81 | * Prepare format directory data, exported by kernel |
@@ -93,7 +90,7 @@ static char *test_format_dir_get(void) | |||
93 | if (!mkdtemp(dir)) | 90 | if (!mkdtemp(dir)) |
94 | return NULL; | 91 | return NULL; |
95 | 92 | ||
96 | for (i = 0; i < TEST_FORMATS_CNT; i++) { | 93 | for (i = 0; i < ARRAY_SIZE(test_formats); i++) { |
97 | static char name[PATH_MAX]; | 94 | static char name[PATH_MAX]; |
98 | struct test_format *format = &test_formats[i]; | 95 | struct test_format *format = &test_formats[i]; |
99 | FILE *file; | 96 | FILE *file; |
@@ -130,14 +127,12 @@ static struct list_head *test_terms_list(void) | |||
130 | static LIST_HEAD(terms); | 127 | static LIST_HEAD(terms); |
131 | unsigned int i; | 128 | unsigned int i; |
132 | 129 | ||
133 | for (i = 0; i < TERMS_CNT; i++) | 130 | for (i = 0; i < ARRAY_SIZE(test_terms); i++) |
134 | list_add_tail(&test_terms[i].list, &terms); | 131 | list_add_tail(&test_terms[i].list, &terms); |
135 | 132 | ||
136 | return &terms; | 133 | return &terms; |
137 | } | 134 | } |
138 | 135 | ||
139 | #undef TERMS_CNT | ||
140 | |||
141 | int test__pmu(void) | 136 | int test__pmu(void) |
142 | { | 137 | { |
143 | char *format = test_format_dir_get(); | 138 | char *format = test_format_dir_get(); |
diff --git a/tools/perf/tests/python-use.c b/tools/perf/tests/python-use.c new file mode 100644 index 000000000000..7760277c6def --- /dev/null +++ b/tools/perf/tests/python-use.c | |||
@@ -0,0 +1,23 @@ | |||
1 | /* | ||
2 | * Just test if we can load the python binding. | ||
3 | */ | ||
4 | |||
5 | #include <stdio.h> | ||
6 | #include <stdlib.h> | ||
7 | #include "tests.h" | ||
8 | |||
9 | extern int verbose; | ||
10 | |||
11 | int test__python_use(void) | ||
12 | { | ||
13 | char *cmd; | ||
14 | int ret; | ||
15 | |||
16 | if (asprintf(&cmd, "echo \"import sys ; sys.path.append('%s'); import perf\" | %s %s", | ||
17 | PYTHONPATH, PYTHON, verbose ? "" : "2> /dev/null") < 0) | ||
18 | return -1; | ||
19 | |||
20 | ret = system(cmd) ? -1 : 0; | ||
21 | free(cmd); | ||
22 | return ret; | ||
23 | } | ||
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index fc121edab016..5de0be1ff4b6 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h | |||
@@ -1,6 +1,12 @@ | |||
1 | #ifndef TESTS_H | 1 | #ifndef TESTS_H |
2 | #define TESTS_H | 2 | #define TESTS_H |
3 | 3 | ||
4 | enum { | ||
5 | TEST_OK = 0, | ||
6 | TEST_FAIL = -1, | ||
7 | TEST_SKIP = -2, | ||
8 | }; | ||
9 | |||
4 | /* Tests */ | 10 | /* Tests */ |
5 | int test__vmlinux_matches_kallsyms(void); | 11 | int test__vmlinux_matches_kallsyms(void); |
6 | int test__open_syscall_event(void); | 12 | int test__open_syscall_event(void); |
@@ -15,8 +21,7 @@ int test__pmu(void); | |||
15 | int test__attr(void); | 21 | int test__attr(void); |
16 | int test__dso_data(void); | 22 | int test__dso_data(void); |
17 | int test__parse_events(void); | 23 | int test__parse_events(void); |
18 | 24 | int test__hists_link(void); | |
19 | /* Util */ | 25 | int test__python_use(void); |
20 | int trace_event__id(const char *evname); | ||
21 | 26 | ||
22 | #endif /* TESTS_H */ | 27 | #endif /* TESTS_H */ |
diff --git a/tools/perf/tests/util.c b/tools/perf/tests/util.c deleted file mode 100644 index 748f2e8f6961..000000000000 --- a/tools/perf/tests/util.c +++ /dev/null | |||
@@ -1,30 +0,0 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <unistd.h> | ||
3 | #include <stdlib.h> | ||
4 | #include <sys/types.h> | ||
5 | #include <sys/stat.h> | ||
6 | #include <fcntl.h> | ||
7 | #include "tests.h" | ||
8 | #include "debugfs.h" | ||
9 | |||
10 | int trace_event__id(const char *evname) | ||
11 | { | ||
12 | char *filename; | ||
13 | int err = -1, fd; | ||
14 | |||
15 | if (asprintf(&filename, | ||
16 | "%s/syscalls/%s/id", | ||
17 | tracing_events_path, evname) < 0) | ||
18 | return -1; | ||
19 | |||
20 | fd = open(filename, O_RDONLY); | ||
21 | if (fd >= 0) { | ||
22 | char id[16]; | ||
23 | if (read(fd, id, sizeof(id)) > 0) | ||
24 | err = atoi(id); | ||
25 | close(fd); | ||
26 | } | ||
27 | |||
28 | free(filename); | ||
29 | return err; | ||
30 | } | ||
diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c index 0d1cdbee2f59..7b4c4d26d1ba 100644 --- a/tools/perf/tests/vmlinux-kallsyms.c +++ b/tools/perf/tests/vmlinux-kallsyms.c | |||
@@ -44,7 +44,7 @@ int test__vmlinux_matches_kallsyms(void) | |||
44 | */ | 44 | */ |
45 | if (machine__create_kernel_maps(&kallsyms) < 0) { | 45 | if (machine__create_kernel_maps(&kallsyms) < 0) { |
46 | pr_debug("machine__create_kernel_maps "); | 46 | pr_debug("machine__create_kernel_maps "); |
47 | return -1; | 47 | goto out; |
48 | } | 48 | } |
49 | 49 | ||
50 | /* | 50 | /* |
@@ -101,7 +101,8 @@ int test__vmlinux_matches_kallsyms(void) | |||
101 | */ | 101 | */ |
102 | if (machine__load_vmlinux_path(&vmlinux, type, | 102 | if (machine__load_vmlinux_path(&vmlinux, type, |
103 | vmlinux_matches_kallsyms_filter) <= 0) { | 103 | vmlinux_matches_kallsyms_filter) <= 0) { |
104 | pr_debug("machine__load_vmlinux_path "); | 104 | pr_debug("Couldn't find a vmlinux that matches the kernel running on this machine, skipping test\n"); |
105 | err = TEST_SKIP; | ||
105 | goto out; | 106 | goto out; |
106 | } | 107 | } |
107 | 108 | ||
@@ -226,5 +227,7 @@ detour: | |||
226 | map__fprintf(pos, stderr); | 227 | map__fprintf(pos, stderr); |
227 | } | 228 | } |
228 | out: | 229 | out: |
230 | machine__exit(&kallsyms); | ||
231 | machine__exit(&vmlinux); | ||
229 | return err; | 232 | return err; |
230 | } | 233 | } |
diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c index 4aeb7d5df939..809ea4632a34 100644 --- a/tools/perf/ui/browser.c +++ b/tools/perf/ui/browser.c | |||
@@ -273,6 +273,8 @@ void ui_browser__hide(struct ui_browser *browser __maybe_unused) | |||
273 | { | 273 | { |
274 | pthread_mutex_lock(&ui__lock); | 274 | pthread_mutex_lock(&ui__lock); |
275 | ui_helpline__pop(); | 275 | ui_helpline__pop(); |
276 | free(browser->helpline); | ||
277 | browser->helpline = NULL; | ||
276 | pthread_mutex_unlock(&ui__lock); | 278 | pthread_mutex_unlock(&ui__lock); |
277 | } | 279 | } |
278 | 280 | ||
@@ -471,7 +473,7 @@ unsigned int ui_browser__list_head_refresh(struct ui_browser *browser) | |||
471 | return row; | 473 | return row; |
472 | } | 474 | } |
473 | 475 | ||
474 | static struct ui_browser__colorset { | 476 | static struct ui_browser_colorset { |
475 | const char *name, *fg, *bg; | 477 | const char *name, *fg, *bg; |
476 | int colorset; | 478 | int colorset; |
477 | } ui_browser__colorsets[] = { | 479 | } ui_browser__colorsets[] = { |
@@ -706,7 +708,7 @@ void ui_browser__init(void) | |||
706 | perf_config(ui_browser__color_config, NULL); | 708 | perf_config(ui_browser__color_config, NULL); |
707 | 709 | ||
708 | while (ui_browser__colorsets[i].name) { | 710 | while (ui_browser__colorsets[i].name) { |
709 | struct ui_browser__colorset *c = &ui_browser__colorsets[i++]; | 711 | struct ui_browser_colorset *c = &ui_browser__colorsets[i++]; |
710 | sltt_set_color(c->colorset, c->name, c->fg, c->bg); | 712 | sltt_set_color(c->colorset, c->name, c->fg, c->bg); |
711 | } | 713 | } |
712 | 714 | ||
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 5dab3ca96980..7dca1555c610 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c | |||
@@ -182,6 +182,16 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int | |||
182 | ab->selection = dl; | 182 | ab->selection = dl; |
183 | } | 183 | } |
184 | 184 | ||
185 | static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym) | ||
186 | { | ||
187 | if (!dl || !dl->ins || !ins__is_jump(dl->ins) | ||
188 | || !disasm_line__has_offset(dl) | ||
189 | || dl->ops.target.offset >= symbol__size(sym)) | ||
190 | return false; | ||
191 | |||
192 | return true; | ||
193 | } | ||
194 | |||
185 | static void annotate_browser__draw_current_jump(struct ui_browser *browser) | 195 | static void annotate_browser__draw_current_jump(struct ui_browser *browser) |
186 | { | 196 | { |
187 | struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); | 197 | struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); |
@@ -195,8 +205,7 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser) | |||
195 | if (strstr(sym->name, "@plt")) | 205 | if (strstr(sym->name, "@plt")) |
196 | return; | 206 | return; |
197 | 207 | ||
198 | if (!cursor || !cursor->ins || !ins__is_jump(cursor->ins) || | 208 | if (!disasm_line__is_valid_jump(cursor, sym)) |
199 | !disasm_line__has_offset(cursor)) | ||
200 | return; | 209 | return; |
201 | 210 | ||
202 | target = ab->offsets[cursor->ops.target.offset]; | 211 | target = ab->offsets[cursor->ops.target.offset]; |
@@ -788,17 +797,9 @@ static void annotate_browser__mark_jump_targets(struct annotate_browser *browser | |||
788 | struct disasm_line *dl = browser->offsets[offset], *dlt; | 797 | struct disasm_line *dl = browser->offsets[offset], *dlt; |
789 | struct browser_disasm_line *bdlt; | 798 | struct browser_disasm_line *bdlt; |
790 | 799 | ||
791 | if (!dl || !dl->ins || !ins__is_jump(dl->ins) || | 800 | if (!disasm_line__is_valid_jump(dl, sym)) |
792 | !disasm_line__has_offset(dl)) | ||
793 | continue; | 801 | continue; |
794 | 802 | ||
795 | if (dl->ops.target.offset >= size) { | ||
796 | ui__error("jump to after symbol!\n" | ||
797 | "size: %zx, jump target: %" PRIx64, | ||
798 | size, dl->ops.target.offset); | ||
799 | continue; | ||
800 | } | ||
801 | |||
802 | dlt = browser->offsets[dl->ops.target.offset]; | 803 | dlt = browser->offsets[dl->ops.target.offset]; |
803 | /* | 804 | /* |
804 | * FIXME: Oops, no jump target? Buggy disassembler? Or do we | 805 | * FIXME: Oops, no jump target? Buggy disassembler? Or do we |
@@ -921,11 +922,11 @@ out_free_offsets: | |||
921 | 922 | ||
922 | #define ANNOTATE_CFG(n) \ | 923 | #define ANNOTATE_CFG(n) \ |
923 | { .name = #n, .value = &annotate_browser__opts.n, } | 924 | { .name = #n, .value = &annotate_browser__opts.n, } |
924 | 925 | ||
925 | /* | 926 | /* |
926 | * Keep the entries sorted, they are bsearch'ed | 927 | * Keep the entries sorted, they are bsearch'ed |
927 | */ | 928 | */ |
928 | static struct annotate__config { | 929 | static struct annotate_config { |
929 | const char *name; | 930 | const char *name; |
930 | bool *value; | 931 | bool *value; |
931 | } annotate__configs[] = { | 932 | } annotate__configs[] = { |
@@ -939,7 +940,7 @@ static struct annotate__config { | |||
939 | 940 | ||
940 | static int annotate_config__cmp(const void *name, const void *cfgp) | 941 | static int annotate_config__cmp(const void *name, const void *cfgp) |
941 | { | 942 | { |
942 | const struct annotate__config *cfg = cfgp; | 943 | const struct annotate_config *cfg = cfgp; |
943 | 944 | ||
944 | return strcmp(name, cfg->name); | 945 | return strcmp(name, cfg->name); |
945 | } | 946 | } |
@@ -947,7 +948,7 @@ static int annotate_config__cmp(const void *name, const void *cfgp) | |||
947 | static int annotate__config(const char *var, const char *value, | 948 | static int annotate__config(const char *var, const char *value, |
948 | void *data __maybe_unused) | 949 | void *data __maybe_unused) |
949 | { | 950 | { |
950 | struct annotate__config *cfg; | 951 | struct annotate_config *cfg; |
951 | const char *name; | 952 | const char *name; |
952 | 953 | ||
953 | if (prefixcmp(var, "annotate.") != 0) | 954 | if (prefixcmp(var, "annotate.") != 0) |
@@ -955,7 +956,7 @@ static int annotate__config(const char *var, const char *value, | |||
955 | 956 | ||
956 | name = var + 9; | 957 | name = var + 9; |
957 | cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs), | 958 | cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs), |
958 | sizeof(struct annotate__config), annotate_config__cmp); | 959 | sizeof(struct annotate_config), annotate_config__cmp); |
959 | 960 | ||
960 | if (cfg == NULL) | 961 | if (cfg == NULL) |
961 | return -1; | 962 | return -1; |
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index ccc4bd161420..aa22704047d6 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c | |||
@@ -567,26 +567,128 @@ static int hist_browser__show_callchain(struct hist_browser *browser, | |||
567 | return row - first_row; | 567 | return row - first_row; |
568 | } | 568 | } |
569 | 569 | ||
570 | #define HPP__COLOR_FN(_name, _field) \ | 570 | struct hpp_arg { |
571 | static int hist_browser__hpp_color_ ## _name(struct perf_hpp *hpp, \ | 571 | struct ui_browser *b; |
572 | struct hist_entry *he) \ | 572 | char folded_sign; |
573 | bool current_entry; | ||
574 | }; | ||
575 | |||
576 | static int __hpp__color_callchain(struct hpp_arg *arg) | ||
577 | { | ||
578 | if (!symbol_conf.use_callchain) | ||
579 | return 0; | ||
580 | |||
581 | slsmg_printf("%c ", arg->folded_sign); | ||
582 | return 2; | ||
583 | } | ||
584 | |||
585 | static int __hpp__color_fmt(struct perf_hpp *hpp, struct hist_entry *he, | ||
586 | u64 (*get_field)(struct hist_entry *), | ||
587 | int (*callchain_cb)(struct hpp_arg *)) | ||
588 | { | ||
589 | int ret = 0; | ||
590 | double percent = 0.0; | ||
591 | struct hists *hists = he->hists; | ||
592 | struct hpp_arg *arg = hpp->ptr; | ||
593 | |||
594 | if (hists->stats.total_period) | ||
595 | percent = 100.0 * get_field(he) / hists->stats.total_period; | ||
596 | |||
597 | ui_browser__set_percent_color(arg->b, percent, arg->current_entry); | ||
598 | |||
599 | if (callchain_cb) | ||
600 | ret += callchain_cb(arg); | ||
601 | |||
602 | ret += scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent); | ||
603 | slsmg_printf("%s", hpp->buf); | ||
604 | |||
605 | if (symbol_conf.event_group) { | ||
606 | int prev_idx, idx_delta; | ||
607 | struct perf_evsel *evsel = hists_to_evsel(hists); | ||
608 | struct hist_entry *pair; | ||
609 | int nr_members = evsel->nr_members; | ||
610 | |||
611 | if (nr_members <= 1) | ||
612 | goto out; | ||
613 | |||
614 | prev_idx = perf_evsel__group_idx(evsel); | ||
615 | |||
616 | list_for_each_entry(pair, &he->pairs.head, pairs.node) { | ||
617 | u64 period = get_field(pair); | ||
618 | u64 total = pair->hists->stats.total_period; | ||
619 | |||
620 | if (!total) | ||
621 | continue; | ||
622 | |||
623 | evsel = hists_to_evsel(pair->hists); | ||
624 | idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1; | ||
625 | |||
626 | while (idx_delta--) { | ||
627 | /* | ||
628 | * zero-fill group members in the middle which | ||
629 | * have no sample | ||
630 | */ | ||
631 | ui_browser__set_percent_color(arg->b, 0.0, | ||
632 | arg->current_entry); | ||
633 | ret += scnprintf(hpp->buf, hpp->size, | ||
634 | " %6.2f%%", 0.0); | ||
635 | slsmg_printf("%s", hpp->buf); | ||
636 | } | ||
637 | |||
638 | percent = 100.0 * period / total; | ||
639 | ui_browser__set_percent_color(arg->b, percent, | ||
640 | arg->current_entry); | ||
641 | ret += scnprintf(hpp->buf, hpp->size, | ||
642 | " %6.2f%%", percent); | ||
643 | slsmg_printf("%s", hpp->buf); | ||
644 | |||
645 | prev_idx = perf_evsel__group_idx(evsel); | ||
646 | } | ||
647 | |||
648 | idx_delta = nr_members - prev_idx - 1; | ||
649 | |||
650 | while (idx_delta--) { | ||
651 | /* | ||
652 | * zero-fill group members at last which have no sample | ||
653 | */ | ||
654 | ui_browser__set_percent_color(arg->b, 0.0, | ||
655 | arg->current_entry); | ||
656 | ret += scnprintf(hpp->buf, hpp->size, | ||
657 | " %6.2f%%", 0.0); | ||
658 | slsmg_printf("%s", hpp->buf); | ||
659 | } | ||
660 | } | ||
661 | out: | ||
662 | if (!arg->current_entry || !arg->b->navkeypressed) | ||
663 | ui_browser__set_color(arg->b, HE_COLORSET_NORMAL); | ||
664 | |||
665 | return ret; | ||
666 | } | ||
667 | |||
668 | #define __HPP_COLOR_PERCENT_FN(_type, _field, _cb) \ | ||
669 | static u64 __hpp_get_##_field(struct hist_entry *he) \ | ||
670 | { \ | ||
671 | return he->stat._field; \ | ||
672 | } \ | ||
673 | \ | ||
674 | static int hist_browser__hpp_color_##_type(struct perf_hpp *hpp, \ | ||
675 | struct hist_entry *he) \ | ||
573 | { \ | 676 | { \ |
574 | struct hists *hists = he->hists; \ | 677 | return __hpp__color_fmt(hpp, he, __hpp_get_##_field, _cb); \ |
575 | double percent = 100.0 * he->stat._field / hists->stats.total_period; \ | ||
576 | *(double *)hpp->ptr = percent; \ | ||
577 | return scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent); \ | ||
578 | } | 678 | } |
579 | 679 | ||
580 | HPP__COLOR_FN(overhead, period) | 680 | __HPP_COLOR_PERCENT_FN(overhead, period, __hpp__color_callchain) |
581 | HPP__COLOR_FN(overhead_sys, period_sys) | 681 | __HPP_COLOR_PERCENT_FN(overhead_sys, period_sys, NULL) |
582 | HPP__COLOR_FN(overhead_us, period_us) | 682 | __HPP_COLOR_PERCENT_FN(overhead_us, period_us, NULL) |
583 | HPP__COLOR_FN(overhead_guest_sys, period_guest_sys) | 683 | __HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys, NULL) |
584 | HPP__COLOR_FN(overhead_guest_us, period_guest_us) | 684 | __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us, NULL) |
585 | 685 | ||
586 | #undef HPP__COLOR_FN | 686 | #undef __HPP_COLOR_PERCENT_FN |
587 | 687 | ||
588 | void hist_browser__init_hpp(void) | 688 | void hist_browser__init_hpp(void) |
589 | { | 689 | { |
690 | perf_hpp__column_enable(PERF_HPP__OVERHEAD); | ||
691 | |||
590 | perf_hpp__init(); | 692 | perf_hpp__init(); |
591 | 693 | ||
592 | perf_hpp__format[PERF_HPP__OVERHEAD].color = | 694 | perf_hpp__format[PERF_HPP__OVERHEAD].color = |
@@ -606,13 +708,13 @@ static int hist_browser__show_entry(struct hist_browser *browser, | |||
606 | unsigned short row) | 708 | unsigned short row) |
607 | { | 709 | { |
608 | char s[256]; | 710 | char s[256]; |
609 | double percent; | 711 | int printed = 0; |
610 | int i, printed = 0; | ||
611 | int width = browser->b.width; | 712 | int width = browser->b.width; |
612 | char folded_sign = ' '; | 713 | char folded_sign = ' '; |
613 | bool current_entry = ui_browser__is_current_entry(&browser->b, row); | 714 | bool current_entry = ui_browser__is_current_entry(&browser->b, row); |
614 | off_t row_offset = entry->row_offset; | 715 | off_t row_offset = entry->row_offset; |
615 | bool first = true; | 716 | bool first = true; |
717 | struct perf_hpp_fmt *fmt; | ||
616 | 718 | ||
617 | if (current_entry) { | 719 | if (current_entry) { |
618 | browser->he_selection = entry; | 720 | browser->he_selection = entry; |
@@ -625,41 +727,30 @@ static int hist_browser__show_entry(struct hist_browser *browser, | |||
625 | } | 727 | } |
626 | 728 | ||
627 | if (row_offset == 0) { | 729 | if (row_offset == 0) { |
730 | struct hpp_arg arg = { | ||
731 | .b = &browser->b, | ||
732 | .folded_sign = folded_sign, | ||
733 | .current_entry = current_entry, | ||
734 | }; | ||
628 | struct perf_hpp hpp = { | 735 | struct perf_hpp hpp = { |
629 | .buf = s, | 736 | .buf = s, |
630 | .size = sizeof(s), | 737 | .size = sizeof(s), |
738 | .ptr = &arg, | ||
631 | }; | 739 | }; |
632 | 740 | ||
633 | ui_browser__gotorc(&browser->b, row, 0); | 741 | ui_browser__gotorc(&browser->b, row, 0); |
634 | 742 | ||
635 | for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { | 743 | perf_hpp__for_each_format(fmt) { |
636 | if (!perf_hpp__format[i].cond) | ||
637 | continue; | ||
638 | |||
639 | if (!first) { | 744 | if (!first) { |
640 | slsmg_printf(" "); | 745 | slsmg_printf(" "); |
641 | width -= 2; | 746 | width -= 2; |
642 | } | 747 | } |
643 | first = false; | 748 | first = false; |
644 | 749 | ||
645 | if (perf_hpp__format[i].color) { | 750 | if (fmt->color) { |
646 | hpp.ptr = &percent; | 751 | width -= fmt->color(&hpp, entry); |
647 | /* It will set percent for us. See HPP__COLOR_FN above. */ | ||
648 | width -= perf_hpp__format[i].color(&hpp, entry); | ||
649 | |||
650 | ui_browser__set_percent_color(&browser->b, percent, current_entry); | ||
651 | |||
652 | if (i == PERF_HPP__OVERHEAD && symbol_conf.use_callchain) { | ||
653 | slsmg_printf("%c ", folded_sign); | ||
654 | width -= 2; | ||
655 | } | ||
656 | |||
657 | slsmg_printf("%s", s); | ||
658 | |||
659 | if (!current_entry || !browser->b.navkeypressed) | ||
660 | ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL); | ||
661 | } else { | 752 | } else { |
662 | width -= perf_hpp__format[i].entry(&hpp, entry); | 753 | width -= fmt->entry(&hpp, entry); |
663 | slsmg_printf("%s", s); | 754 | slsmg_printf("%s", s); |
664 | } | 755 | } |
665 | } | 756 | } |
@@ -1098,6 +1189,21 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size, | |||
1098 | const struct thread *thread = hists->thread_filter; | 1189 | const struct thread *thread = hists->thread_filter; |
1099 | unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; | 1190 | unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; |
1100 | u64 nr_events = hists->stats.total_period; | 1191 | u64 nr_events = hists->stats.total_period; |
1192 | struct perf_evsel *evsel = hists_to_evsel(hists); | ||
1193 | char buf[512]; | ||
1194 | size_t buflen = sizeof(buf); | ||
1195 | |||
1196 | if (symbol_conf.event_group && evsel->nr_members > 1) { | ||
1197 | struct perf_evsel *pos; | ||
1198 | |||
1199 | perf_evsel__group_desc(evsel, buf, buflen); | ||
1200 | ev_name = buf; | ||
1201 | |||
1202 | for_each_group_member(pos, evsel) { | ||
1203 | nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE]; | ||
1204 | nr_events += pos->hists.stats.total_period; | ||
1205 | } | ||
1206 | } | ||
1101 | 1207 | ||
1102 | nr_samples = convert_unit(nr_samples, &unit); | 1208 | nr_samples = convert_unit(nr_samples, &unit); |
1103 | printed = scnprintf(bf, size, | 1209 | printed = scnprintf(bf, size, |
@@ -1135,6 +1241,96 @@ static inline bool is_report_browser(void *timer) | |||
1135 | return timer == NULL; | 1241 | return timer == NULL; |
1136 | } | 1242 | } |
1137 | 1243 | ||
1244 | /* | ||
1245 | * Only runtime switching of perf data file will make "input_name" point | ||
1246 | * to a malloced buffer. So add "is_input_name_malloced" flag to decide | ||
1247 | * whether we need to call free() for current "input_name" during the switch. | ||
1248 | */ | ||
1249 | static bool is_input_name_malloced = false; | ||
1250 | |||
1251 | static int switch_data_file(void) | ||
1252 | { | ||
1253 | char *pwd, *options[32], *abs_path[32], *tmp; | ||
1254 | DIR *pwd_dir; | ||
1255 | int nr_options = 0, choice = -1, ret = -1; | ||
1256 | struct dirent *dent; | ||
1257 | |||
1258 | pwd = getenv("PWD"); | ||
1259 | if (!pwd) | ||
1260 | return ret; | ||
1261 | |||
1262 | pwd_dir = opendir(pwd); | ||
1263 | if (!pwd_dir) | ||
1264 | return ret; | ||
1265 | |||
1266 | memset(options, 0, sizeof(options)); | ||
1267 | memset(options, 0, sizeof(abs_path)); | ||
1268 | |||
1269 | while ((dent = readdir(pwd_dir))) { | ||
1270 | char path[PATH_MAX]; | ||
1271 | u64 magic; | ||
1272 | char *name = dent->d_name; | ||
1273 | FILE *file; | ||
1274 | |||
1275 | if (!(dent->d_type == DT_REG)) | ||
1276 | continue; | ||
1277 | |||
1278 | snprintf(path, sizeof(path), "%s/%s", pwd, name); | ||
1279 | |||
1280 | file = fopen(path, "r"); | ||
1281 | if (!file) | ||
1282 | continue; | ||
1283 | |||
1284 | if (fread(&magic, 1, 8, file) < 8) | ||
1285 | goto close_file_and_continue; | ||
1286 | |||
1287 | if (is_perf_magic(magic)) { | ||
1288 | options[nr_options] = strdup(name); | ||
1289 | if (!options[nr_options]) | ||
1290 | goto close_file_and_continue; | ||
1291 | |||
1292 | abs_path[nr_options] = strdup(path); | ||
1293 | if (!abs_path[nr_options]) { | ||
1294 | free(options[nr_options]); | ||
1295 | ui__warning("Can't search all data files due to memory shortage.\n"); | ||
1296 | fclose(file); | ||
1297 | break; | ||
1298 | } | ||
1299 | |||
1300 | nr_options++; | ||
1301 | } | ||
1302 | |||
1303 | close_file_and_continue: | ||
1304 | fclose(file); | ||
1305 | if (nr_options >= 32) { | ||
1306 | ui__warning("Too many perf data files in PWD!\n" | ||
1307 | "Only the first 32 files will be listed.\n"); | ||
1308 | break; | ||
1309 | } | ||
1310 | } | ||
1311 | closedir(pwd_dir); | ||
1312 | |||
1313 | if (nr_options) { | ||
1314 | choice = ui__popup_menu(nr_options, options); | ||
1315 | if (choice < nr_options && choice >= 0) { | ||
1316 | tmp = strdup(abs_path[choice]); | ||
1317 | if (tmp) { | ||
1318 | if (is_input_name_malloced) | ||
1319 | free((void *)input_name); | ||
1320 | input_name = tmp; | ||
1321 | is_input_name_malloced = true; | ||
1322 | ret = 0; | ||
1323 | } else | ||
1324 | ui__warning("Data switch failed due to memory shortage!\n"); | ||
1325 | } | ||
1326 | } | ||
1327 | |||
1328 | free_popup_options(options, nr_options); | ||
1329 | free_popup_options(abs_path, nr_options); | ||
1330 | return ret; | ||
1331 | } | ||
1332 | |||
1333 | |||
1138 | static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | 1334 | static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, |
1139 | const char *helpline, const char *ev_name, | 1335 | const char *helpline, const char *ev_name, |
1140 | bool left_exits, | 1336 | bool left_exits, |
@@ -1169,7 +1365,8 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
1169 | int choice = 0, | 1365 | int choice = 0, |
1170 | annotate = -2, zoom_dso = -2, zoom_thread = -2, | 1366 | annotate = -2, zoom_dso = -2, zoom_thread = -2, |
1171 | annotate_f = -2, annotate_t = -2, browse_map = -2; | 1367 | annotate_f = -2, annotate_t = -2, browse_map = -2; |
1172 | int scripts_comm = -2, scripts_symbol = -2, scripts_all = -2; | 1368 | int scripts_comm = -2, scripts_symbol = -2, |
1369 | scripts_all = -2, switch_data = -2; | ||
1173 | 1370 | ||
1174 | nr_options = 0; | 1371 | nr_options = 0; |
1175 | 1372 | ||
@@ -1226,6 +1423,10 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
1226 | if (is_report_browser(hbt)) | 1423 | if (is_report_browser(hbt)) |
1227 | goto do_scripts; | 1424 | goto do_scripts; |
1228 | continue; | 1425 | continue; |
1426 | case 's': | ||
1427 | if (is_report_browser(hbt)) | ||
1428 | goto do_data_switch; | ||
1429 | continue; | ||
1229 | case K_F1: | 1430 | case K_F1: |
1230 | case 'h': | 1431 | case 'h': |
1231 | case '?': | 1432 | case '?': |
@@ -1245,6 +1446,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
1245 | "d Zoom into current DSO\n" | 1446 | "d Zoom into current DSO\n" |
1246 | "t Zoom into current Thread\n" | 1447 | "t Zoom into current Thread\n" |
1247 | "r Run available scripts('perf report' only)\n" | 1448 | "r Run available scripts('perf report' only)\n" |
1449 | "s Switch to another data file in PWD ('perf report' only)\n" | ||
1248 | "P Print histograms to perf.hist.N\n" | 1450 | "P Print histograms to perf.hist.N\n" |
1249 | "V Verbose (DSO names in callchains, etc)\n" | 1451 | "V Verbose (DSO names in callchains, etc)\n" |
1250 | "/ Filter symbol by name"); | 1452 | "/ Filter symbol by name"); |
@@ -1352,6 +1554,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
1352 | if (asprintf(&options[nr_options], "Run scripts for all samples") > 0) | 1554 | if (asprintf(&options[nr_options], "Run scripts for all samples") > 0) |
1353 | scripts_all = nr_options++; | 1555 | scripts_all = nr_options++; |
1354 | 1556 | ||
1557 | if (is_report_browser(hbt) && asprintf(&options[nr_options], | ||
1558 | "Switch to another data file in PWD") > 0) | ||
1559 | switch_data = nr_options++; | ||
1355 | add_exit_option: | 1560 | add_exit_option: |
1356 | options[nr_options++] = (char *)"Exit"; | 1561 | options[nr_options++] = (char *)"Exit"; |
1357 | retry_popup_menu: | 1562 | retry_popup_menu: |
@@ -1462,6 +1667,16 @@ do_scripts: | |||
1462 | 1667 | ||
1463 | script_browse(script_opt); | 1668 | script_browse(script_opt); |
1464 | } | 1669 | } |
1670 | /* Switch to another data file */ | ||
1671 | else if (choice == switch_data) { | ||
1672 | do_data_switch: | ||
1673 | if (!switch_data_file()) { | ||
1674 | key = K_SWITCH_INPUT_DATA; | ||
1675 | break; | ||
1676 | } else | ||
1677 | ui__warning("Won't switch the data files due to\n" | ||
1678 | "no valid data file get selected!\n"); | ||
1679 | } | ||
1465 | } | 1680 | } |
1466 | out_free_stack: | 1681 | out_free_stack: |
1467 | pstack__delete(fstack); | 1682 | pstack__delete(fstack); |
@@ -1494,6 +1709,16 @@ static void perf_evsel_menu__write(struct ui_browser *browser, | |||
1494 | ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : | 1709 | ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : |
1495 | HE_COLORSET_NORMAL); | 1710 | HE_COLORSET_NORMAL); |
1496 | 1711 | ||
1712 | if (symbol_conf.event_group && evsel->nr_members > 1) { | ||
1713 | struct perf_evsel *pos; | ||
1714 | |||
1715 | ev_name = perf_evsel__group_name(evsel); | ||
1716 | |||
1717 | for_each_group_member(pos, evsel) { | ||
1718 | nr_events += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE]; | ||
1719 | } | ||
1720 | } | ||
1721 | |||
1497 | nr_events = convert_unit(nr_events, &unit); | 1722 | nr_events = convert_unit(nr_events, &unit); |
1498 | printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events, | 1723 | printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events, |
1499 | unit, unit == ' ' ? "" : " ", ev_name); | 1724 | unit, unit == ' ' ? "" : " ", ev_name); |
@@ -1578,6 +1803,7 @@ browse_hists: | |||
1578 | "Do you really want to exit?")) | 1803 | "Do you really want to exit?")) |
1579 | continue; | 1804 | continue; |
1580 | /* Fall thru */ | 1805 | /* Fall thru */ |
1806 | case K_SWITCH_INPUT_DATA: | ||
1581 | case 'q': | 1807 | case 'q': |
1582 | case CTRL('c'): | 1808 | case CTRL('c'): |
1583 | goto out; | 1809 | goto out; |
@@ -1604,8 +1830,19 @@ out: | |||
1604 | return key; | 1830 | return key; |
1605 | } | 1831 | } |
1606 | 1832 | ||
1833 | static bool filter_group_entries(struct ui_browser *self __maybe_unused, | ||
1834 | void *entry) | ||
1835 | { | ||
1836 | struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node); | ||
1837 | |||
1838 | if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel)) | ||
1839 | return true; | ||
1840 | |||
1841 | return false; | ||
1842 | } | ||
1843 | |||
1607 | static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, | 1844 | static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, |
1608 | const char *help, | 1845 | int nr_entries, const char *help, |
1609 | struct hist_browser_timer *hbt, | 1846 | struct hist_browser_timer *hbt, |
1610 | struct perf_session_env *env) | 1847 | struct perf_session_env *env) |
1611 | { | 1848 | { |
@@ -1616,7 +1853,8 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, | |||
1616 | .refresh = ui_browser__list_head_refresh, | 1853 | .refresh = ui_browser__list_head_refresh, |
1617 | .seek = ui_browser__list_head_seek, | 1854 | .seek = ui_browser__list_head_seek, |
1618 | .write = perf_evsel_menu__write, | 1855 | .write = perf_evsel_menu__write, |
1619 | .nr_entries = evlist->nr_entries, | 1856 | .filter = filter_group_entries, |
1857 | .nr_entries = nr_entries, | ||
1620 | .priv = evlist, | 1858 | .priv = evlist, |
1621 | }, | 1859 | }, |
1622 | .env = env, | 1860 | .env = env, |
@@ -1632,20 +1870,37 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, | |||
1632 | menu.b.width = line_len; | 1870 | menu.b.width = line_len; |
1633 | } | 1871 | } |
1634 | 1872 | ||
1635 | return perf_evsel_menu__run(&menu, evlist->nr_entries, help, hbt); | 1873 | return perf_evsel_menu__run(&menu, nr_entries, help, hbt); |
1636 | } | 1874 | } |
1637 | 1875 | ||
1638 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, | 1876 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, |
1639 | struct hist_browser_timer *hbt, | 1877 | struct hist_browser_timer *hbt, |
1640 | struct perf_session_env *env) | 1878 | struct perf_session_env *env) |
1641 | { | 1879 | { |
1642 | if (evlist->nr_entries == 1) { | 1880 | int nr_entries = evlist->nr_entries; |
1881 | |||
1882 | single_entry: | ||
1883 | if (nr_entries == 1) { | ||
1643 | struct perf_evsel *first = list_entry(evlist->entries.next, | 1884 | struct perf_evsel *first = list_entry(evlist->entries.next, |
1644 | struct perf_evsel, node); | 1885 | struct perf_evsel, node); |
1645 | const char *ev_name = perf_evsel__name(first); | 1886 | const char *ev_name = perf_evsel__name(first); |
1646 | return perf_evsel__hists_browse(first, evlist->nr_entries, help, | 1887 | |
1888 | return perf_evsel__hists_browse(first, nr_entries, help, | ||
1647 | ev_name, false, hbt, env); | 1889 | ev_name, false, hbt, env); |
1648 | } | 1890 | } |
1649 | 1891 | ||
1650 | return __perf_evlist__tui_browse_hists(evlist, help, hbt, env); | 1892 | if (symbol_conf.event_group) { |
1893 | struct perf_evsel *pos; | ||
1894 | |||
1895 | nr_entries = 0; | ||
1896 | list_for_each_entry(pos, &evlist->entries, node) | ||
1897 | if (perf_evsel__is_group_leader(pos)) | ||
1898 | nr_entries++; | ||
1899 | |||
1900 | if (nr_entries == 1) | ||
1901 | goto single_entry; | ||
1902 | } | ||
1903 | |||
1904 | return __perf_evlist__tui_browse_hists(evlist, nr_entries, help, | ||
1905 | hbt, env); | ||
1651 | } | 1906 | } |
diff --git a/tools/perf/ui/gtk/annotate.c b/tools/perf/ui/gtk/annotate.c new file mode 100644 index 000000000000..7d8dc581a545 --- /dev/null +++ b/tools/perf/ui/gtk/annotate.c | |||
@@ -0,0 +1,229 @@ | |||
1 | #include "gtk.h" | ||
2 | #include "util/debug.h" | ||
3 | #include "util/annotate.h" | ||
4 | #include "ui/helpline.h" | ||
5 | |||
6 | |||
7 | enum { | ||
8 | ANN_COL__PERCENT, | ||
9 | ANN_COL__OFFSET, | ||
10 | ANN_COL__LINE, | ||
11 | |||
12 | MAX_ANN_COLS | ||
13 | }; | ||
14 | |||
15 | static const char *const col_names[] = { | ||
16 | "Overhead", | ||
17 | "Offset", | ||
18 | "Line" | ||
19 | }; | ||
20 | |||
21 | static int perf_gtk__get_percent(char *buf, size_t size, struct symbol *sym, | ||
22 | struct disasm_line *dl, int evidx) | ||
23 | { | ||
24 | struct sym_hist *symhist; | ||
25 | double percent = 0.0; | ||
26 | const char *markup; | ||
27 | int ret = 0; | ||
28 | |||
29 | strcpy(buf, ""); | ||
30 | |||
31 | if (dl->offset == (s64) -1) | ||
32 | return 0; | ||
33 | |||
34 | symhist = annotation__histogram(symbol__annotation(sym), evidx); | ||
35 | if (!symhist->addr[dl->offset]) | ||
36 | return 0; | ||
37 | |||
38 | percent = 100.0 * symhist->addr[dl->offset] / symhist->sum; | ||
39 | |||
40 | markup = perf_gtk__get_percent_color(percent); | ||
41 | if (markup) | ||
42 | ret += scnprintf(buf, size, "%s", markup); | ||
43 | ret += scnprintf(buf + ret, size - ret, "%6.2f%%", percent); | ||
44 | if (markup) | ||
45 | ret += scnprintf(buf + ret, size - ret, "</span>"); | ||
46 | |||
47 | return ret; | ||
48 | } | ||
49 | |||
50 | static int perf_gtk__get_offset(char *buf, size_t size, struct symbol *sym, | ||
51 | struct map *map, struct disasm_line *dl) | ||
52 | { | ||
53 | u64 start = map__rip_2objdump(map, sym->start); | ||
54 | |||
55 | strcpy(buf, ""); | ||
56 | |||
57 | if (dl->offset == (s64) -1) | ||
58 | return 0; | ||
59 | |||
60 | return scnprintf(buf, size, "%"PRIx64, start + dl->offset); | ||
61 | } | ||
62 | |||
63 | static int perf_gtk__get_line(char *buf, size_t size, struct disasm_line *dl) | ||
64 | { | ||
65 | int ret = 0; | ||
66 | char *line = g_markup_escape_text(dl->line, -1); | ||
67 | const char *markup = "<span fgcolor='gray'>"; | ||
68 | |||
69 | strcpy(buf, ""); | ||
70 | |||
71 | if (!line) | ||
72 | return 0; | ||
73 | |||
74 | if (dl->offset != (s64) -1) | ||
75 | markup = NULL; | ||
76 | |||
77 | if (markup) | ||
78 | ret += scnprintf(buf, size, "%s", markup); | ||
79 | ret += scnprintf(buf + ret, size - ret, "%s", line); | ||
80 | if (markup) | ||
81 | ret += scnprintf(buf + ret, size - ret, "</span>"); | ||
82 | |||
83 | g_free(line); | ||
84 | return ret; | ||
85 | } | ||
86 | |||
87 | static int perf_gtk__annotate_symbol(GtkWidget *window, struct symbol *sym, | ||
88 | struct map *map, int evidx, | ||
89 | struct hist_browser_timer *hbt __maybe_unused) | ||
90 | { | ||
91 | struct disasm_line *pos, *n; | ||
92 | struct annotation *notes; | ||
93 | GType col_types[MAX_ANN_COLS]; | ||
94 | GtkCellRenderer *renderer; | ||
95 | GtkListStore *store; | ||
96 | GtkWidget *view; | ||
97 | int i; | ||
98 | char s[512]; | ||
99 | |||
100 | notes = symbol__annotation(sym); | ||
101 | |||
102 | for (i = 0; i < MAX_ANN_COLS; i++) { | ||
103 | col_types[i] = G_TYPE_STRING; | ||
104 | } | ||
105 | store = gtk_list_store_newv(MAX_ANN_COLS, col_types); | ||
106 | |||
107 | view = gtk_tree_view_new(); | ||
108 | renderer = gtk_cell_renderer_text_new(); | ||
109 | |||
110 | for (i = 0; i < MAX_ANN_COLS; i++) { | ||
111 | gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), | ||
112 | -1, col_names[i], renderer, "markup", | ||
113 | i, NULL); | ||
114 | } | ||
115 | |||
116 | gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store)); | ||
117 | g_object_unref(GTK_TREE_MODEL(store)); | ||
118 | |||
119 | list_for_each_entry(pos, ¬es->src->source, node) { | ||
120 | GtkTreeIter iter; | ||
121 | |||
122 | gtk_list_store_append(store, &iter); | ||
123 | |||
124 | if (perf_gtk__get_percent(s, sizeof(s), sym, pos, evidx)) | ||
125 | gtk_list_store_set(store, &iter, ANN_COL__PERCENT, s, -1); | ||
126 | if (perf_gtk__get_offset(s, sizeof(s), sym, map, pos)) | ||
127 | gtk_list_store_set(store, &iter, ANN_COL__OFFSET, s, -1); | ||
128 | if (perf_gtk__get_line(s, sizeof(s), pos)) | ||
129 | gtk_list_store_set(store, &iter, ANN_COL__LINE, s, -1); | ||
130 | } | ||
131 | |||
132 | gtk_container_add(GTK_CONTAINER(window), view); | ||
133 | |||
134 | list_for_each_entry_safe(pos, n, ¬es->src->source, node) { | ||
135 | list_del(&pos->node); | ||
136 | disasm_line__free(pos); | ||
137 | } | ||
138 | |||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | int symbol__gtk_annotate(struct symbol *sym, struct map *map, int evidx, | ||
143 | struct hist_browser_timer *hbt) | ||
144 | { | ||
145 | GtkWidget *window; | ||
146 | GtkWidget *notebook; | ||
147 | GtkWidget *scrolled_window; | ||
148 | GtkWidget *tab_label; | ||
149 | |||
150 | if (map->dso->annotate_warned) | ||
151 | return -1; | ||
152 | |||
153 | if (symbol__annotate(sym, map, 0) < 0) { | ||
154 | ui__error("%s", ui_helpline__current); | ||
155 | return -1; | ||
156 | } | ||
157 | |||
158 | if (perf_gtk__is_active_context(pgctx)) { | ||
159 | window = pgctx->main_window; | ||
160 | notebook = pgctx->notebook; | ||
161 | } else { | ||
162 | GtkWidget *vbox; | ||
163 | GtkWidget *infobar; | ||
164 | GtkWidget *statbar; | ||
165 | |||
166 | signal(SIGSEGV, perf_gtk__signal); | ||
167 | signal(SIGFPE, perf_gtk__signal); | ||
168 | signal(SIGINT, perf_gtk__signal); | ||
169 | signal(SIGQUIT, perf_gtk__signal); | ||
170 | signal(SIGTERM, perf_gtk__signal); | ||
171 | |||
172 | window = gtk_window_new(GTK_WINDOW_TOPLEVEL); | ||
173 | gtk_window_set_title(GTK_WINDOW(window), "perf annotate"); | ||
174 | |||
175 | g_signal_connect(window, "delete_event", gtk_main_quit, NULL); | ||
176 | |||
177 | pgctx = perf_gtk__activate_context(window); | ||
178 | if (!pgctx) | ||
179 | return -1; | ||
180 | |||
181 | vbox = gtk_vbox_new(FALSE, 0); | ||
182 | notebook = gtk_notebook_new(); | ||
183 | pgctx->notebook = notebook; | ||
184 | |||
185 | gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0); | ||
186 | |||
187 | infobar = perf_gtk__setup_info_bar(); | ||
188 | if (infobar) { | ||
189 | gtk_box_pack_start(GTK_BOX(vbox), infobar, | ||
190 | FALSE, FALSE, 0); | ||
191 | } | ||
192 | |||
193 | statbar = perf_gtk__setup_statusbar(); | ||
194 | gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0); | ||
195 | |||
196 | gtk_container_add(GTK_CONTAINER(window), vbox); | ||
197 | } | ||
198 | |||
199 | scrolled_window = gtk_scrolled_window_new(NULL, NULL); | ||
200 | tab_label = gtk_label_new(sym->name); | ||
201 | |||
202 | gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), | ||
203 | GTK_POLICY_AUTOMATIC, | ||
204 | GTK_POLICY_AUTOMATIC); | ||
205 | |||
206 | gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, | ||
207 | tab_label); | ||
208 | |||
209 | perf_gtk__annotate_symbol(scrolled_window, sym, map, evidx, hbt); | ||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | void perf_gtk__show_annotations(void) | ||
214 | { | ||
215 | GtkWidget *window; | ||
216 | |||
217 | if (!perf_gtk__is_active_context(pgctx)) | ||
218 | return; | ||
219 | |||
220 | window = pgctx->main_window; | ||
221 | gtk_widget_show_all(window); | ||
222 | |||
223 | perf_gtk__resize_window(window); | ||
224 | gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); | ||
225 | |||
226 | gtk_main(); | ||
227 | |||
228 | perf_gtk__deactivate_context(&pgctx); | ||
229 | } | ||
diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c index 253b6219a39e..c95012cdb438 100644 --- a/tools/perf/ui/gtk/browser.c +++ b/tools/perf/ui/gtk/browser.c | |||
@@ -8,15 +8,13 @@ | |||
8 | 8 | ||
9 | #include <signal.h> | 9 | #include <signal.h> |
10 | 10 | ||
11 | #define MAX_COLUMNS 32 | 11 | void perf_gtk__signal(int sig) |
12 | |||
13 | static void perf_gtk__signal(int sig) | ||
14 | { | 12 | { |
15 | perf_gtk__exit(false); | 13 | perf_gtk__exit(false); |
16 | psignal(sig, "perf"); | 14 | psignal(sig, "perf"); |
17 | } | 15 | } |
18 | 16 | ||
19 | static void perf_gtk__resize_window(GtkWidget *window) | 17 | void perf_gtk__resize_window(GtkWidget *window) |
20 | { | 18 | { |
21 | GdkRectangle rect; | 19 | GdkRectangle rect; |
22 | GdkScreen *screen; | 20 | GdkScreen *screen; |
@@ -36,7 +34,7 @@ static void perf_gtk__resize_window(GtkWidget *window) | |||
36 | gtk_window_resize(GTK_WINDOW(window), width, height); | 34 | gtk_window_resize(GTK_WINDOW(window), width, height); |
37 | } | 35 | } |
38 | 36 | ||
39 | static const char *perf_gtk__get_percent_color(double percent) | 37 | const char *perf_gtk__get_percent_color(double percent) |
40 | { | 38 | { |
41 | if (percent >= MIN_RED) | 39 | if (percent >= MIN_RED) |
42 | return "<span fgcolor='red'>"; | 40 | return "<span fgcolor='red'>"; |
@@ -45,155 +43,8 @@ static const char *perf_gtk__get_percent_color(double percent) | |||
45 | return NULL; | 43 | return NULL; |
46 | } | 44 | } |
47 | 45 | ||
48 | #define HPP__COLOR_FN(_name, _field) \ | ||
49 | static int perf_gtk__hpp_color_ ## _name(struct perf_hpp *hpp, \ | ||
50 | struct hist_entry *he) \ | ||
51 | { \ | ||
52 | struct hists *hists = he->hists; \ | ||
53 | double percent = 100.0 * he->stat._field / hists->stats.total_period; \ | ||
54 | const char *markup; \ | ||
55 | int ret = 0; \ | ||
56 | \ | ||
57 | markup = perf_gtk__get_percent_color(percent); \ | ||
58 | if (markup) \ | ||
59 | ret += scnprintf(hpp->buf, hpp->size, "%s", markup); \ | ||
60 | ret += scnprintf(hpp->buf + ret, hpp->size - ret, "%6.2f%%", percent); \ | ||
61 | if (markup) \ | ||
62 | ret += scnprintf(hpp->buf + ret, hpp->size - ret, "</span>"); \ | ||
63 | \ | ||
64 | return ret; \ | ||
65 | } | ||
66 | |||
67 | HPP__COLOR_FN(overhead, period) | ||
68 | HPP__COLOR_FN(overhead_sys, period_sys) | ||
69 | HPP__COLOR_FN(overhead_us, period_us) | ||
70 | HPP__COLOR_FN(overhead_guest_sys, period_guest_sys) | ||
71 | HPP__COLOR_FN(overhead_guest_us, period_guest_us) | ||
72 | |||
73 | #undef HPP__COLOR_FN | ||
74 | |||
75 | void perf_gtk__init_hpp(void) | ||
76 | { | ||
77 | perf_hpp__init(); | ||
78 | |||
79 | perf_hpp__format[PERF_HPP__OVERHEAD].color = | ||
80 | perf_gtk__hpp_color_overhead; | ||
81 | perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color = | ||
82 | perf_gtk__hpp_color_overhead_sys; | ||
83 | perf_hpp__format[PERF_HPP__OVERHEAD_US].color = | ||
84 | perf_gtk__hpp_color_overhead_us; | ||
85 | perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color = | ||
86 | perf_gtk__hpp_color_overhead_guest_sys; | ||
87 | perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color = | ||
88 | perf_gtk__hpp_color_overhead_guest_us; | ||
89 | } | ||
90 | |||
91 | static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists) | ||
92 | { | ||
93 | GType col_types[MAX_COLUMNS]; | ||
94 | GtkCellRenderer *renderer; | ||
95 | struct sort_entry *se; | ||
96 | GtkListStore *store; | ||
97 | struct rb_node *nd; | ||
98 | GtkWidget *view; | ||
99 | int i, col_idx; | ||
100 | int nr_cols; | ||
101 | char s[512]; | ||
102 | |||
103 | struct perf_hpp hpp = { | ||
104 | .buf = s, | ||
105 | .size = sizeof(s), | ||
106 | }; | ||
107 | |||
108 | nr_cols = 0; | ||
109 | |||
110 | for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { | ||
111 | if (!perf_hpp__format[i].cond) | ||
112 | continue; | ||
113 | |||
114 | col_types[nr_cols++] = G_TYPE_STRING; | ||
115 | } | ||
116 | |||
117 | list_for_each_entry(se, &hist_entry__sort_list, list) { | ||
118 | if (se->elide) | ||
119 | continue; | ||
120 | |||
121 | col_types[nr_cols++] = G_TYPE_STRING; | ||
122 | } | ||
123 | |||
124 | store = gtk_list_store_newv(nr_cols, col_types); | ||
125 | |||
126 | view = gtk_tree_view_new(); | ||
127 | |||
128 | renderer = gtk_cell_renderer_text_new(); | ||
129 | |||
130 | col_idx = 0; | ||
131 | |||
132 | for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { | ||
133 | if (!perf_hpp__format[i].cond) | ||
134 | continue; | ||
135 | |||
136 | perf_hpp__format[i].header(&hpp); | ||
137 | |||
138 | gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), | ||
139 | -1, s, | ||
140 | renderer, "markup", | ||
141 | col_idx++, NULL); | ||
142 | } | ||
143 | |||
144 | list_for_each_entry(se, &hist_entry__sort_list, list) { | ||
145 | if (se->elide) | ||
146 | continue; | ||
147 | |||
148 | gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), | ||
149 | -1, se->se_header, | ||
150 | renderer, "text", | ||
151 | col_idx++, NULL); | ||
152 | } | ||
153 | |||
154 | gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store)); | ||
155 | |||
156 | g_object_unref(GTK_TREE_MODEL(store)); | ||
157 | |||
158 | for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { | ||
159 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); | ||
160 | GtkTreeIter iter; | ||
161 | |||
162 | if (h->filtered) | ||
163 | continue; | ||
164 | |||
165 | gtk_list_store_append(store, &iter); | ||
166 | |||
167 | col_idx = 0; | ||
168 | |||
169 | for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { | ||
170 | if (!perf_hpp__format[i].cond) | ||
171 | continue; | ||
172 | |||
173 | if (perf_hpp__format[i].color) | ||
174 | perf_hpp__format[i].color(&hpp, h); | ||
175 | else | ||
176 | perf_hpp__format[i].entry(&hpp, h); | ||
177 | |||
178 | gtk_list_store_set(store, &iter, col_idx++, s, -1); | ||
179 | } | ||
180 | |||
181 | list_for_each_entry(se, &hist_entry__sort_list, list) { | ||
182 | if (se->elide) | ||
183 | continue; | ||
184 | |||
185 | se->se_snprintf(h, s, ARRAY_SIZE(s), | ||
186 | hists__col_len(hists, se->se_width_idx)); | ||
187 | |||
188 | gtk_list_store_set(store, &iter, col_idx++, s, -1); | ||
189 | } | ||
190 | } | ||
191 | |||
192 | gtk_container_add(GTK_CONTAINER(window), view); | ||
193 | } | ||
194 | |||
195 | #ifdef HAVE_GTK_INFO_BAR | 46 | #ifdef HAVE_GTK_INFO_BAR |
196 | static GtkWidget *perf_gtk__setup_info_bar(void) | 47 | GtkWidget *perf_gtk__setup_info_bar(void) |
197 | { | 48 | { |
198 | GtkWidget *info_bar; | 49 | GtkWidget *info_bar; |
199 | GtkWidget *label; | 50 | GtkWidget *label; |
@@ -220,7 +71,7 @@ static GtkWidget *perf_gtk__setup_info_bar(void) | |||
220 | } | 71 | } |
221 | #endif | 72 | #endif |
222 | 73 | ||
223 | static GtkWidget *perf_gtk__setup_statusbar(void) | 74 | GtkWidget *perf_gtk__setup_statusbar(void) |
224 | { | 75 | { |
225 | GtkWidget *stbar; | 76 | GtkWidget *stbar; |
226 | unsigned ctxid; | 77 | unsigned ctxid; |
@@ -234,79 +85,3 @@ static GtkWidget *perf_gtk__setup_statusbar(void) | |||
234 | 85 | ||
235 | return stbar; | 86 | return stbar; |
236 | } | 87 | } |
237 | |||
238 | int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, | ||
239 | const char *help, | ||
240 | struct hist_browser_timer *hbt __maybe_unused) | ||
241 | { | ||
242 | struct perf_evsel *pos; | ||
243 | GtkWidget *vbox; | ||
244 | GtkWidget *notebook; | ||
245 | GtkWidget *info_bar; | ||
246 | GtkWidget *statbar; | ||
247 | GtkWidget *window; | ||
248 | |||
249 | signal(SIGSEGV, perf_gtk__signal); | ||
250 | signal(SIGFPE, perf_gtk__signal); | ||
251 | signal(SIGINT, perf_gtk__signal); | ||
252 | signal(SIGQUIT, perf_gtk__signal); | ||
253 | signal(SIGTERM, perf_gtk__signal); | ||
254 | |||
255 | window = gtk_window_new(GTK_WINDOW_TOPLEVEL); | ||
256 | |||
257 | gtk_window_set_title(GTK_WINDOW(window), "perf report"); | ||
258 | |||
259 | g_signal_connect(window, "delete_event", gtk_main_quit, NULL); | ||
260 | |||
261 | pgctx = perf_gtk__activate_context(window); | ||
262 | if (!pgctx) | ||
263 | return -1; | ||
264 | |||
265 | vbox = gtk_vbox_new(FALSE, 0); | ||
266 | |||
267 | notebook = gtk_notebook_new(); | ||
268 | |||
269 | list_for_each_entry(pos, &evlist->entries, node) { | ||
270 | struct hists *hists = &pos->hists; | ||
271 | const char *evname = perf_evsel__name(pos); | ||
272 | GtkWidget *scrolled_window; | ||
273 | GtkWidget *tab_label; | ||
274 | |||
275 | scrolled_window = gtk_scrolled_window_new(NULL, NULL); | ||
276 | |||
277 | gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), | ||
278 | GTK_POLICY_AUTOMATIC, | ||
279 | GTK_POLICY_AUTOMATIC); | ||
280 | |||
281 | perf_gtk__show_hists(scrolled_window, hists); | ||
282 | |||
283 | tab_label = gtk_label_new(evname); | ||
284 | |||
285 | gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label); | ||
286 | } | ||
287 | |||
288 | gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0); | ||
289 | |||
290 | info_bar = perf_gtk__setup_info_bar(); | ||
291 | if (info_bar) | ||
292 | gtk_box_pack_start(GTK_BOX(vbox), info_bar, FALSE, FALSE, 0); | ||
293 | |||
294 | statbar = perf_gtk__setup_statusbar(); | ||
295 | gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0); | ||
296 | |||
297 | gtk_container_add(GTK_CONTAINER(window), vbox); | ||
298 | |||
299 | gtk_widget_show_all(window); | ||
300 | |||
301 | perf_gtk__resize_window(window); | ||
302 | |||
303 | gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); | ||
304 | |||
305 | ui_helpline__push(help); | ||
306 | |||
307 | gtk_main(); | ||
308 | |||
309 | perf_gtk__deactivate_context(&pgctx); | ||
310 | |||
311 | return 0; | ||
312 | } | ||
diff --git a/tools/perf/ui/gtk/gtk.h b/tools/perf/ui/gtk/gtk.h index 856320e2cc05..3d96785ef155 100644 --- a/tools/perf/ui/gtk/gtk.h +++ b/tools/perf/ui/gtk/gtk.h | |||
@@ -10,6 +10,7 @@ | |||
10 | 10 | ||
11 | struct perf_gtk_context { | 11 | struct perf_gtk_context { |
12 | GtkWidget *main_window; | 12 | GtkWidget *main_window; |
13 | GtkWidget *notebook; | ||
13 | 14 | ||
14 | #ifdef HAVE_GTK_INFO_BAR | 15 | #ifdef HAVE_GTK_INFO_BAR |
15 | GtkWidget *info_bar; | 16 | GtkWidget *info_bar; |
@@ -33,7 +34,14 @@ void perf_gtk__init_helpline(void); | |||
33 | void perf_gtk__init_progress(void); | 34 | void perf_gtk__init_progress(void); |
34 | void perf_gtk__init_hpp(void); | 35 | void perf_gtk__init_hpp(void); |
35 | 36 | ||
36 | #ifndef HAVE_GTK_INFO_BAR | 37 | void perf_gtk__signal(int sig); |
38 | void perf_gtk__resize_window(GtkWidget *window); | ||
39 | const char *perf_gtk__get_percent_color(double percent); | ||
40 | GtkWidget *perf_gtk__setup_statusbar(void); | ||
41 | |||
42 | #ifdef HAVE_GTK_INFO_BAR | ||
43 | GtkWidget *perf_gtk__setup_info_bar(void); | ||
44 | #else | ||
37 | static inline GtkWidget *perf_gtk__setup_info_bar(void) | 45 | static inline GtkWidget *perf_gtk__setup_info_bar(void) |
38 | { | 46 | { |
39 | return NULL; | 47 | return NULL; |
diff --git a/tools/perf/ui/gtk/helpline.c b/tools/perf/ui/gtk/helpline.c index 5db4432ff12a..3388cbd12186 100644 --- a/tools/perf/ui/gtk/helpline.c +++ b/tools/perf/ui/gtk/helpline.c | |||
@@ -24,17 +24,7 @@ static void gtk_helpline_push(const char *msg) | |||
24 | pgctx->statbar_ctx_id, msg); | 24 | pgctx->statbar_ctx_id, msg); |
25 | } | 25 | } |
26 | 26 | ||
27 | static struct ui_helpline gtk_helpline_fns = { | 27 | static int gtk_helpline_show(const char *fmt, va_list ap) |
28 | .pop = gtk_helpline_pop, | ||
29 | .push = gtk_helpline_push, | ||
30 | }; | ||
31 | |||
32 | void perf_gtk__init_helpline(void) | ||
33 | { | ||
34 | helpline_fns = >k_helpline_fns; | ||
35 | } | ||
36 | |||
37 | int perf_gtk__show_helpline(const char *fmt, va_list ap) | ||
38 | { | 28 | { |
39 | int ret; | 29 | int ret; |
40 | char *ptr; | 30 | char *ptr; |
@@ -54,3 +44,14 @@ int perf_gtk__show_helpline(const char *fmt, va_list ap) | |||
54 | 44 | ||
55 | return ret; | 45 | return ret; |
56 | } | 46 | } |
47 | |||
48 | static struct ui_helpline gtk_helpline_fns = { | ||
49 | .pop = gtk_helpline_pop, | ||
50 | .push = gtk_helpline_push, | ||
51 | .show = gtk_helpline_show, | ||
52 | }; | ||
53 | |||
54 | void perf_gtk__init_helpline(void) | ||
55 | { | ||
56 | helpline_fns = >k_helpline_fns; | ||
57 | } | ||
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c new file mode 100644 index 000000000000..1e764a8ad259 --- /dev/null +++ b/tools/perf/ui/gtk/hists.c | |||
@@ -0,0 +1,312 @@ | |||
1 | #include "../evlist.h" | ||
2 | #include "../cache.h" | ||
3 | #include "../evsel.h" | ||
4 | #include "../sort.h" | ||
5 | #include "../hist.h" | ||
6 | #include "../helpline.h" | ||
7 | #include "gtk.h" | ||
8 | |||
9 | #define MAX_COLUMNS 32 | ||
10 | |||
11 | static int __percent_color_snprintf(char *buf, size_t size, double percent) | ||
12 | { | ||
13 | int ret = 0; | ||
14 | const char *markup; | ||
15 | |||
16 | markup = perf_gtk__get_percent_color(percent); | ||
17 | if (markup) | ||
18 | ret += scnprintf(buf, size, markup); | ||
19 | |||
20 | ret += scnprintf(buf + ret, size - ret, " %6.2f%%", percent); | ||
21 | |||
22 | if (markup) | ||
23 | ret += scnprintf(buf + ret, size - ret, "</span>"); | ||
24 | |||
25 | return ret; | ||
26 | } | ||
27 | |||
28 | |||
29 | static int __hpp__color_fmt(struct perf_hpp *hpp, struct hist_entry *he, | ||
30 | u64 (*get_field)(struct hist_entry *)) | ||
31 | { | ||
32 | int ret; | ||
33 | double percent = 0.0; | ||
34 | struct hists *hists = he->hists; | ||
35 | |||
36 | if (hists->stats.total_period) | ||
37 | percent = 100.0 * get_field(he) / hists->stats.total_period; | ||
38 | |||
39 | ret = __percent_color_snprintf(hpp->buf, hpp->size, percent); | ||
40 | |||
41 | if (symbol_conf.event_group) { | ||
42 | int prev_idx, idx_delta; | ||
43 | struct perf_evsel *evsel = hists_to_evsel(hists); | ||
44 | struct hist_entry *pair; | ||
45 | int nr_members = evsel->nr_members; | ||
46 | |||
47 | if (nr_members <= 1) | ||
48 | return ret; | ||
49 | |||
50 | prev_idx = perf_evsel__group_idx(evsel); | ||
51 | |||
52 | list_for_each_entry(pair, &he->pairs.head, pairs.node) { | ||
53 | u64 period = get_field(pair); | ||
54 | u64 total = pair->hists->stats.total_period; | ||
55 | |||
56 | evsel = hists_to_evsel(pair->hists); | ||
57 | idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1; | ||
58 | |||
59 | while (idx_delta--) { | ||
60 | /* | ||
61 | * zero-fill group members in the middle which | ||
62 | * have no sample | ||
63 | */ | ||
64 | ret += __percent_color_snprintf(hpp->buf + ret, | ||
65 | hpp->size - ret, | ||
66 | 0.0); | ||
67 | } | ||
68 | |||
69 | percent = 100.0 * period / total; | ||
70 | ret += __percent_color_snprintf(hpp->buf + ret, | ||
71 | hpp->size - ret, | ||
72 | percent); | ||
73 | |||
74 | prev_idx = perf_evsel__group_idx(evsel); | ||
75 | } | ||
76 | |||
77 | idx_delta = nr_members - prev_idx - 1; | ||
78 | |||
79 | while (idx_delta--) { | ||
80 | /* | ||
81 | * zero-fill group members at last which have no sample | ||
82 | */ | ||
83 | ret += __percent_color_snprintf(hpp->buf + ret, | ||
84 | hpp->size - ret, | ||
85 | 0.0); | ||
86 | } | ||
87 | } | ||
88 | return ret; | ||
89 | } | ||
90 | |||
91 | #define __HPP_COLOR_PERCENT_FN(_type, _field) \ | ||
92 | static u64 he_get_##_field(struct hist_entry *he) \ | ||
93 | { \ | ||
94 | return he->stat._field; \ | ||
95 | } \ | ||
96 | \ | ||
97 | static int perf_gtk__hpp_color_##_type(struct perf_hpp *hpp, \ | ||
98 | struct hist_entry *he) \ | ||
99 | { \ | ||
100 | return __hpp__color_fmt(hpp, he, he_get_##_field); \ | ||
101 | } | ||
102 | |||
103 | __HPP_COLOR_PERCENT_FN(overhead, period) | ||
104 | __HPP_COLOR_PERCENT_FN(overhead_sys, period_sys) | ||
105 | __HPP_COLOR_PERCENT_FN(overhead_us, period_us) | ||
106 | __HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys) | ||
107 | __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us) | ||
108 | |||
109 | #undef __HPP_COLOR_PERCENT_FN | ||
110 | |||
111 | |||
112 | void perf_gtk__init_hpp(void) | ||
113 | { | ||
114 | perf_hpp__column_enable(PERF_HPP__OVERHEAD); | ||
115 | |||
116 | perf_hpp__init(); | ||
117 | |||
118 | perf_hpp__format[PERF_HPP__OVERHEAD].color = | ||
119 | perf_gtk__hpp_color_overhead; | ||
120 | perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color = | ||
121 | perf_gtk__hpp_color_overhead_sys; | ||
122 | perf_hpp__format[PERF_HPP__OVERHEAD_US].color = | ||
123 | perf_gtk__hpp_color_overhead_us; | ||
124 | perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color = | ||
125 | perf_gtk__hpp_color_overhead_guest_sys; | ||
126 | perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color = | ||
127 | perf_gtk__hpp_color_overhead_guest_us; | ||
128 | } | ||
129 | |||
130 | static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists) | ||
131 | { | ||
132 | struct perf_hpp_fmt *fmt; | ||
133 | GType col_types[MAX_COLUMNS]; | ||
134 | GtkCellRenderer *renderer; | ||
135 | struct sort_entry *se; | ||
136 | GtkListStore *store; | ||
137 | struct rb_node *nd; | ||
138 | GtkWidget *view; | ||
139 | int col_idx; | ||
140 | int nr_cols; | ||
141 | char s[512]; | ||
142 | |||
143 | struct perf_hpp hpp = { | ||
144 | .buf = s, | ||
145 | .size = sizeof(s), | ||
146 | .ptr = hists_to_evsel(hists), | ||
147 | }; | ||
148 | |||
149 | nr_cols = 0; | ||
150 | |||
151 | perf_hpp__for_each_format(fmt) | ||
152 | col_types[nr_cols++] = G_TYPE_STRING; | ||
153 | |||
154 | list_for_each_entry(se, &hist_entry__sort_list, list) { | ||
155 | if (se->elide) | ||
156 | continue; | ||
157 | |||
158 | col_types[nr_cols++] = G_TYPE_STRING; | ||
159 | } | ||
160 | |||
161 | store = gtk_list_store_newv(nr_cols, col_types); | ||
162 | |||
163 | view = gtk_tree_view_new(); | ||
164 | |||
165 | renderer = gtk_cell_renderer_text_new(); | ||
166 | |||
167 | col_idx = 0; | ||
168 | |||
169 | perf_hpp__for_each_format(fmt) { | ||
170 | fmt->header(&hpp); | ||
171 | |||
172 | gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), | ||
173 | -1, ltrim(s), | ||
174 | renderer, "markup", | ||
175 | col_idx++, NULL); | ||
176 | } | ||
177 | |||
178 | list_for_each_entry(se, &hist_entry__sort_list, list) { | ||
179 | if (se->elide) | ||
180 | continue; | ||
181 | |||
182 | gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), | ||
183 | -1, se->se_header, | ||
184 | renderer, "text", | ||
185 | col_idx++, NULL); | ||
186 | } | ||
187 | |||
188 | gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store)); | ||
189 | |||
190 | g_object_unref(GTK_TREE_MODEL(store)); | ||
191 | |||
192 | for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { | ||
193 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); | ||
194 | GtkTreeIter iter; | ||
195 | |||
196 | if (h->filtered) | ||
197 | continue; | ||
198 | |||
199 | gtk_list_store_append(store, &iter); | ||
200 | |||
201 | col_idx = 0; | ||
202 | |||
203 | perf_hpp__for_each_format(fmt) { | ||
204 | if (fmt->color) | ||
205 | fmt->color(&hpp, h); | ||
206 | else | ||
207 | fmt->entry(&hpp, h); | ||
208 | |||
209 | gtk_list_store_set(store, &iter, col_idx++, s, -1); | ||
210 | } | ||
211 | |||
212 | list_for_each_entry(se, &hist_entry__sort_list, list) { | ||
213 | if (se->elide) | ||
214 | continue; | ||
215 | |||
216 | se->se_snprintf(h, s, ARRAY_SIZE(s), | ||
217 | hists__col_len(hists, se->se_width_idx)); | ||
218 | |||
219 | gtk_list_store_set(store, &iter, col_idx++, s, -1); | ||
220 | } | ||
221 | } | ||
222 | |||
223 | gtk_container_add(GTK_CONTAINER(window), view); | ||
224 | } | ||
225 | |||
226 | int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, | ||
227 | const char *help, | ||
228 | struct hist_browser_timer *hbt __maybe_unused) | ||
229 | { | ||
230 | struct perf_evsel *pos; | ||
231 | GtkWidget *vbox; | ||
232 | GtkWidget *notebook; | ||
233 | GtkWidget *info_bar; | ||
234 | GtkWidget *statbar; | ||
235 | GtkWidget *window; | ||
236 | |||
237 | signal(SIGSEGV, perf_gtk__signal); | ||
238 | signal(SIGFPE, perf_gtk__signal); | ||
239 | signal(SIGINT, perf_gtk__signal); | ||
240 | signal(SIGQUIT, perf_gtk__signal); | ||
241 | signal(SIGTERM, perf_gtk__signal); | ||
242 | |||
243 | window = gtk_window_new(GTK_WINDOW_TOPLEVEL); | ||
244 | |||
245 | gtk_window_set_title(GTK_WINDOW(window), "perf report"); | ||
246 | |||
247 | g_signal_connect(window, "delete_event", gtk_main_quit, NULL); | ||
248 | |||
249 | pgctx = perf_gtk__activate_context(window); | ||
250 | if (!pgctx) | ||
251 | return -1; | ||
252 | |||
253 | vbox = gtk_vbox_new(FALSE, 0); | ||
254 | |||
255 | notebook = gtk_notebook_new(); | ||
256 | |||
257 | gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0); | ||
258 | |||
259 | info_bar = perf_gtk__setup_info_bar(); | ||
260 | if (info_bar) | ||
261 | gtk_box_pack_start(GTK_BOX(vbox), info_bar, FALSE, FALSE, 0); | ||
262 | |||
263 | statbar = perf_gtk__setup_statusbar(); | ||
264 | gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0); | ||
265 | |||
266 | gtk_container_add(GTK_CONTAINER(window), vbox); | ||
267 | |||
268 | list_for_each_entry(pos, &evlist->entries, node) { | ||
269 | struct hists *hists = &pos->hists; | ||
270 | const char *evname = perf_evsel__name(pos); | ||
271 | GtkWidget *scrolled_window; | ||
272 | GtkWidget *tab_label; | ||
273 | char buf[512]; | ||
274 | size_t size = sizeof(buf); | ||
275 | |||
276 | if (symbol_conf.event_group) { | ||
277 | if (!perf_evsel__is_group_leader(pos)) | ||
278 | continue; | ||
279 | |||
280 | if (pos->nr_members > 1) { | ||
281 | perf_evsel__group_desc(pos, buf, size); | ||
282 | evname = buf; | ||
283 | } | ||
284 | } | ||
285 | |||
286 | scrolled_window = gtk_scrolled_window_new(NULL, NULL); | ||
287 | |||
288 | gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), | ||
289 | GTK_POLICY_AUTOMATIC, | ||
290 | GTK_POLICY_AUTOMATIC); | ||
291 | |||
292 | perf_gtk__show_hists(scrolled_window, hists); | ||
293 | |||
294 | tab_label = gtk_label_new(evname); | ||
295 | |||
296 | gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label); | ||
297 | } | ||
298 | |||
299 | gtk_widget_show_all(window); | ||
300 | |||
301 | perf_gtk__resize_window(window); | ||
302 | |||
303 | gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); | ||
304 | |||
305 | ui_helpline__push(help); | ||
306 | |||
307 | gtk_main(); | ||
308 | |||
309 | perf_gtk__deactivate_context(&pgctx); | ||
310 | |||
311 | return 0; | ||
312 | } | ||
diff --git a/tools/perf/ui/helpline.c b/tools/perf/ui/helpline.c index a49bcf3c190b..700fb3cfa1c7 100644 --- a/tools/perf/ui/helpline.c +++ b/tools/perf/ui/helpline.c | |||
@@ -16,9 +16,16 @@ static void nop_helpline__push(const char *msg __maybe_unused) | |||
16 | { | 16 | { |
17 | } | 17 | } |
18 | 18 | ||
19 | static int nop_helpline__show(const char *fmt __maybe_unused, | ||
20 | va_list ap __maybe_unused) | ||
21 | { | ||
22 | return 0; | ||
23 | } | ||
24 | |||
19 | static struct ui_helpline default_helpline_fns = { | 25 | static struct ui_helpline default_helpline_fns = { |
20 | .pop = nop_helpline__pop, | 26 | .pop = nop_helpline__pop, |
21 | .push = nop_helpline__push, | 27 | .push = nop_helpline__push, |
28 | .show = nop_helpline__show, | ||
22 | }; | 29 | }; |
23 | 30 | ||
24 | struct ui_helpline *helpline_fns = &default_helpline_fns; | 31 | struct ui_helpline *helpline_fns = &default_helpline_fns; |
@@ -59,3 +66,8 @@ void ui_helpline__puts(const char *msg) | |||
59 | ui_helpline__pop(); | 66 | ui_helpline__pop(); |
60 | ui_helpline__push(msg); | 67 | ui_helpline__push(msg); |
61 | } | 68 | } |
69 | |||
70 | int ui_helpline__vshow(const char *fmt, va_list ap) | ||
71 | { | ||
72 | return helpline_fns->show(fmt, ap); | ||
73 | } | ||
diff --git a/tools/perf/ui/helpline.h b/tools/perf/ui/helpline.h index baa28a4d16b9..46181f4fc07e 100644 --- a/tools/perf/ui/helpline.h +++ b/tools/perf/ui/helpline.h | |||
@@ -9,6 +9,7 @@ | |||
9 | struct ui_helpline { | 9 | struct ui_helpline { |
10 | void (*pop)(void); | 10 | void (*pop)(void); |
11 | void (*push)(const char *msg); | 11 | void (*push)(const char *msg); |
12 | int (*show)(const char *fmt, va_list ap); | ||
12 | }; | 13 | }; |
13 | 14 | ||
14 | extern struct ui_helpline *helpline_fns; | 15 | extern struct ui_helpline *helpline_fns; |
@@ -20,28 +21,9 @@ void ui_helpline__push(const char *msg); | |||
20 | void ui_helpline__vpush(const char *fmt, va_list ap); | 21 | void ui_helpline__vpush(const char *fmt, va_list ap); |
21 | void ui_helpline__fpush(const char *fmt, ...); | 22 | void ui_helpline__fpush(const char *fmt, ...); |
22 | void ui_helpline__puts(const char *msg); | 23 | void ui_helpline__puts(const char *msg); |
24 | int ui_helpline__vshow(const char *fmt, va_list ap); | ||
23 | 25 | ||
24 | extern char ui_helpline__current[512]; | 26 | extern char ui_helpline__current[512]; |
25 | |||
26 | #ifdef NEWT_SUPPORT | ||
27 | extern char ui_helpline__last_msg[]; | 27 | extern char ui_helpline__last_msg[]; |
28 | int ui_helpline__show_help(const char *format, va_list ap); | ||
29 | #else | ||
30 | static inline int ui_helpline__show_help(const char *format __maybe_unused, | ||
31 | va_list ap __maybe_unused) | ||
32 | { | ||
33 | return 0; | ||
34 | } | ||
35 | #endif /* NEWT_SUPPORT */ | ||
36 | |||
37 | #ifdef GTK2_SUPPORT | ||
38 | int perf_gtk__show_helpline(const char *format, va_list ap); | ||
39 | #else | ||
40 | static inline int perf_gtk__show_helpline(const char *format __maybe_unused, | ||
41 | va_list ap __maybe_unused) | ||
42 | { | ||
43 | return 0; | ||
44 | } | ||
45 | #endif /* GTK2_SUPPORT */ | ||
46 | 28 | ||
47 | #endif /* _PERF_UI_HELPLINE_H_ */ | 29 | #endif /* _PERF_UI_HELPLINE_H_ */ |
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index aa84130024d5..d671e63aa351 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c | |||
@@ -3,151 +3,163 @@ | |||
3 | #include "../util/hist.h" | 3 | #include "../util/hist.h" |
4 | #include "../util/util.h" | 4 | #include "../util/util.h" |
5 | #include "../util/sort.h" | 5 | #include "../util/sort.h" |
6 | 6 | #include "../util/evsel.h" | |
7 | 7 | ||
8 | /* hist period print (hpp) functions */ | 8 | /* hist period print (hpp) functions */ |
9 | static int hpp__header_overhead(struct perf_hpp *hpp) | ||
10 | { | ||
11 | return scnprintf(hpp->buf, hpp->size, "Overhead"); | ||
12 | } | ||
13 | |||
14 | static int hpp__width_overhead(struct perf_hpp *hpp __maybe_unused) | ||
15 | { | ||
16 | return 8; | ||
17 | } | ||
18 | |||
19 | static int hpp__color_overhead(struct perf_hpp *hpp, struct hist_entry *he) | ||
20 | { | ||
21 | struct hists *hists = he->hists; | ||
22 | double percent = 100.0 * he->stat.period / hists->stats.total_period; | ||
23 | 9 | ||
24 | return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent); | 10 | typedef int (*hpp_snprint_fn)(char *buf, size_t size, const char *fmt, ...); |
25 | } | ||
26 | 11 | ||
27 | static int hpp__entry_overhead(struct perf_hpp *hpp, struct hist_entry *he) | 12 | static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, |
13 | u64 (*get_field)(struct hist_entry *), | ||
14 | const char *fmt, hpp_snprint_fn print_fn, | ||
15 | bool fmt_percent) | ||
28 | { | 16 | { |
17 | int ret; | ||
29 | struct hists *hists = he->hists; | 18 | struct hists *hists = he->hists; |
30 | double percent = 100.0 * he->stat.period / hists->stats.total_period; | ||
31 | const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%"; | ||
32 | |||
33 | return scnprintf(hpp->buf, hpp->size, fmt, percent); | ||
34 | } | ||
35 | 19 | ||
36 | static int hpp__header_overhead_sys(struct perf_hpp *hpp) | 20 | if (fmt_percent) { |
37 | { | 21 | double percent = 0.0; |
38 | const char *fmt = symbol_conf.field_sep ? "%s" : "%7s"; | ||
39 | |||
40 | return scnprintf(hpp->buf, hpp->size, fmt, "sys"); | ||
41 | } | ||
42 | 22 | ||
43 | static int hpp__width_overhead_sys(struct perf_hpp *hpp __maybe_unused) | 23 | if (hists->stats.total_period) |
44 | { | 24 | percent = 100.0 * get_field(he) / |
45 | return 7; | 25 | hists->stats.total_period; |
46 | } | ||
47 | 26 | ||
48 | static int hpp__color_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he) | 27 | ret = print_fn(hpp->buf, hpp->size, fmt, percent); |
49 | { | 28 | } else |
50 | struct hists *hists = he->hists; | 29 | ret = print_fn(hpp->buf, hpp->size, fmt, get_field(he)); |
51 | double percent = 100.0 * he->stat.period_sys / hists->stats.total_period; | ||
52 | 30 | ||
53 | return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent); | 31 | if (symbol_conf.event_group) { |
54 | } | 32 | int prev_idx, idx_delta; |
33 | struct perf_evsel *evsel = hists_to_evsel(hists); | ||
34 | struct hist_entry *pair; | ||
35 | int nr_members = evsel->nr_members; | ||
55 | 36 | ||
56 | static int hpp__entry_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he) | 37 | if (nr_members <= 1) |
57 | { | 38 | return ret; |
58 | struct hists *hists = he->hists; | ||
59 | double percent = 100.0 * he->stat.period_sys / hists->stats.total_period; | ||
60 | const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%"; | ||
61 | 39 | ||
62 | return scnprintf(hpp->buf, hpp->size, fmt, percent); | 40 | prev_idx = perf_evsel__group_idx(evsel); |
63 | } | ||
64 | 41 | ||
65 | static int hpp__header_overhead_us(struct perf_hpp *hpp) | 42 | list_for_each_entry(pair, &he->pairs.head, pairs.node) { |
66 | { | 43 | u64 period = get_field(pair); |
67 | const char *fmt = symbol_conf.field_sep ? "%s" : "%7s"; | 44 | u64 total = pair->hists->stats.total_period; |
68 | 45 | ||
69 | return scnprintf(hpp->buf, hpp->size, fmt, "user"); | 46 | if (!total) |
70 | } | 47 | continue; |
71 | 48 | ||
72 | static int hpp__width_overhead_us(struct perf_hpp *hpp __maybe_unused) | 49 | evsel = hists_to_evsel(pair->hists); |
73 | { | 50 | idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1; |
74 | return 7; | ||
75 | } | ||
76 | 51 | ||
77 | static int hpp__color_overhead_us(struct perf_hpp *hpp, struct hist_entry *he) | 52 | while (idx_delta--) { |
78 | { | 53 | /* |
79 | struct hists *hists = he->hists; | 54 | * zero-fill group members in the middle which |
80 | double percent = 100.0 * he->stat.period_us / hists->stats.total_period; | 55 | * have no sample |
56 | */ | ||
57 | ret += print_fn(hpp->buf + ret, hpp->size - ret, | ||
58 | fmt, 0); | ||
59 | } | ||
81 | 60 | ||
82 | return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent); | 61 | if (fmt_percent) |
83 | } | 62 | ret += print_fn(hpp->buf + ret, hpp->size - ret, |
63 | fmt, 100.0 * period / total); | ||
64 | else | ||
65 | ret += print_fn(hpp->buf + ret, hpp->size - ret, | ||
66 | fmt, period); | ||
84 | 67 | ||
85 | static int hpp__entry_overhead_us(struct perf_hpp *hpp, struct hist_entry *he) | 68 | prev_idx = perf_evsel__group_idx(evsel); |
86 | { | 69 | } |
87 | struct hists *hists = he->hists; | ||
88 | double percent = 100.0 * he->stat.period_us / hists->stats.total_period; | ||
89 | const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%"; | ||
90 | |||
91 | return scnprintf(hpp->buf, hpp->size, fmt, percent); | ||
92 | } | ||
93 | |||
94 | static int hpp__header_overhead_guest_sys(struct perf_hpp *hpp) | ||
95 | { | ||
96 | return scnprintf(hpp->buf, hpp->size, "guest sys"); | ||
97 | } | ||
98 | |||
99 | static int hpp__width_overhead_guest_sys(struct perf_hpp *hpp __maybe_unused) | ||
100 | { | ||
101 | return 9; | ||
102 | } | ||
103 | |||
104 | static int hpp__color_overhead_guest_sys(struct perf_hpp *hpp, | ||
105 | struct hist_entry *he) | ||
106 | { | ||
107 | struct hists *hists = he->hists; | ||
108 | double percent = 100.0 * he->stat.period_guest_sys / hists->stats.total_period; | ||
109 | |||
110 | return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent); | ||
111 | } | ||
112 | |||
113 | static int hpp__entry_overhead_guest_sys(struct perf_hpp *hpp, | ||
114 | struct hist_entry *he) | ||
115 | { | ||
116 | struct hists *hists = he->hists; | ||
117 | double percent = 100.0 * he->stat.period_guest_sys / hists->stats.total_period; | ||
118 | const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% "; | ||
119 | |||
120 | return scnprintf(hpp->buf, hpp->size, fmt, percent); | ||
121 | } | ||
122 | |||
123 | static int hpp__header_overhead_guest_us(struct perf_hpp *hpp) | ||
124 | { | ||
125 | return scnprintf(hpp->buf, hpp->size, "guest usr"); | ||
126 | } | ||
127 | 70 | ||
128 | static int hpp__width_overhead_guest_us(struct perf_hpp *hpp __maybe_unused) | 71 | idx_delta = nr_members - prev_idx - 1; |
129 | { | ||
130 | return 9; | ||
131 | } | ||
132 | 72 | ||
133 | static int hpp__color_overhead_guest_us(struct perf_hpp *hpp, | 73 | while (idx_delta--) { |
134 | struct hist_entry *he) | 74 | /* |
135 | { | 75 | * zero-fill group members at last which have no sample |
136 | struct hists *hists = he->hists; | 76 | */ |
137 | double percent = 100.0 * he->stat.period_guest_us / hists->stats.total_period; | 77 | ret += print_fn(hpp->buf + ret, hpp->size - ret, |
138 | 78 | fmt, 0); | |
139 | return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent); | 79 | } |
80 | } | ||
81 | return ret; | ||
140 | } | 82 | } |
141 | 83 | ||
142 | static int hpp__entry_overhead_guest_us(struct perf_hpp *hpp, | 84 | #define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ |
143 | struct hist_entry *he) | 85 | static int hpp__header_##_type(struct perf_hpp *hpp) \ |
144 | { | 86 | { \ |
145 | struct hists *hists = he->hists; | 87 | int len = _min_width; \ |
146 | double percent = 100.0 * he->stat.period_guest_us / hists->stats.total_period; | 88 | \ |
147 | const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% "; | 89 | if (symbol_conf.event_group) { \ |
90 | struct perf_evsel *evsel = hpp->ptr; \ | ||
91 | \ | ||
92 | len = max(len, evsel->nr_members * _unit_width); \ | ||
93 | } \ | ||
94 | return scnprintf(hpp->buf, hpp->size, "%*s", len, _str); \ | ||
95 | } | ||
96 | |||
97 | #define __HPP_WIDTH_FN(_type, _min_width, _unit_width) \ | ||
98 | static int hpp__width_##_type(struct perf_hpp *hpp __maybe_unused) \ | ||
99 | { \ | ||
100 | int len = _min_width; \ | ||
101 | \ | ||
102 | if (symbol_conf.event_group) { \ | ||
103 | struct perf_evsel *evsel = hpp->ptr; \ | ||
104 | \ | ||
105 | len = max(len, evsel->nr_members * _unit_width); \ | ||
106 | } \ | ||
107 | return len; \ | ||
108 | } | ||
109 | |||
110 | #define __HPP_COLOR_PERCENT_FN(_type, _field) \ | ||
111 | static u64 he_get_##_field(struct hist_entry *he) \ | ||
112 | { \ | ||
113 | return he->stat._field; \ | ||
114 | } \ | ||
115 | \ | ||
116 | static int hpp__color_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ | ||
117 | { \ | ||
118 | return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%", \ | ||
119 | (hpp_snprint_fn)percent_color_snprintf, true); \ | ||
120 | } | ||
121 | |||
122 | #define __HPP_ENTRY_PERCENT_FN(_type, _field) \ | ||
123 | static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ | ||
124 | { \ | ||
125 | const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \ | ||
126 | return __hpp__fmt(hpp, he, he_get_##_field, fmt, \ | ||
127 | scnprintf, true); \ | ||
128 | } | ||
129 | |||
130 | #define __HPP_ENTRY_RAW_FN(_type, _field) \ | ||
131 | static u64 he_get_raw_##_field(struct hist_entry *he) \ | ||
132 | { \ | ||
133 | return he->stat._field; \ | ||
134 | } \ | ||
135 | \ | ||
136 | static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ | ||
137 | { \ | ||
138 | const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64; \ | ||
139 | return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt, scnprintf, false); \ | ||
140 | } | ||
141 | |||
142 | #define HPP_PERCENT_FNS(_type, _str, _field, _min_width, _unit_width) \ | ||
143 | __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ | ||
144 | __HPP_WIDTH_FN(_type, _min_width, _unit_width) \ | ||
145 | __HPP_COLOR_PERCENT_FN(_type, _field) \ | ||
146 | __HPP_ENTRY_PERCENT_FN(_type, _field) | ||
147 | |||
148 | #define HPP_RAW_FNS(_type, _str, _field, _min_width, _unit_width) \ | ||
149 | __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ | ||
150 | __HPP_WIDTH_FN(_type, _min_width, _unit_width) \ | ||
151 | __HPP_ENTRY_RAW_FN(_type, _field) | ||
152 | |||
153 | |||
154 | HPP_PERCENT_FNS(overhead, "Overhead", period, 8, 8) | ||
155 | HPP_PERCENT_FNS(overhead_sys, "sys", period_sys, 8, 8) | ||
156 | HPP_PERCENT_FNS(overhead_us, "usr", period_us, 8, 8) | ||
157 | HPP_PERCENT_FNS(overhead_guest_sys, "guest sys", period_guest_sys, 9, 8) | ||
158 | HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8) | ||
159 | |||
160 | HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12) | ||
161 | HPP_RAW_FNS(period, "Period", period, 12, 12) | ||
148 | 162 | ||
149 | return scnprintf(hpp->buf, hpp->size, fmt, percent); | ||
150 | } | ||
151 | 163 | ||
152 | static int hpp__header_baseline(struct perf_hpp *hpp) | 164 | static int hpp__header_baseline(struct perf_hpp *hpp) |
153 | { | 165 | { |
@@ -179,7 +191,7 @@ static int hpp__color_baseline(struct perf_hpp *hpp, struct hist_entry *he) | |||
179 | { | 191 | { |
180 | double percent = baseline_percent(he); | 192 | double percent = baseline_percent(he); |
181 | 193 | ||
182 | if (hist_entry__has_pairs(he)) | 194 | if (hist_entry__has_pairs(he) || symbol_conf.field_sep) |
183 | return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent); | 195 | return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent); |
184 | else | 196 | else |
185 | return scnprintf(hpp->buf, hpp->size, " "); | 197 | return scnprintf(hpp->buf, hpp->size, " "); |
@@ -196,44 +208,6 @@ static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he) | |||
196 | return scnprintf(hpp->buf, hpp->size, " "); | 208 | return scnprintf(hpp->buf, hpp->size, " "); |
197 | } | 209 | } |
198 | 210 | ||
199 | static int hpp__header_samples(struct perf_hpp *hpp) | ||
200 | { | ||
201 | const char *fmt = symbol_conf.field_sep ? "%s" : "%11s"; | ||
202 | |||
203 | return scnprintf(hpp->buf, hpp->size, fmt, "Samples"); | ||
204 | } | ||
205 | |||
206 | static int hpp__width_samples(struct perf_hpp *hpp __maybe_unused) | ||
207 | { | ||
208 | return 11; | ||
209 | } | ||
210 | |||
211 | static int hpp__entry_samples(struct perf_hpp *hpp, struct hist_entry *he) | ||
212 | { | ||
213 | const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%11" PRIu64; | ||
214 | |||
215 | return scnprintf(hpp->buf, hpp->size, fmt, he->stat.nr_events); | ||
216 | } | ||
217 | |||
218 | static int hpp__header_period(struct perf_hpp *hpp) | ||
219 | { | ||
220 | const char *fmt = symbol_conf.field_sep ? "%s" : "%12s"; | ||
221 | |||
222 | return scnprintf(hpp->buf, hpp->size, fmt, "Period"); | ||
223 | } | ||
224 | |||
225 | static int hpp__width_period(struct perf_hpp *hpp __maybe_unused) | ||
226 | { | ||
227 | return 12; | ||
228 | } | ||
229 | |||
230 | static int hpp__entry_period(struct perf_hpp *hpp, struct hist_entry *he) | ||
231 | { | ||
232 | const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64; | ||
233 | |||
234 | return scnprintf(hpp->buf, hpp->size, fmt, he->stat.period); | ||
235 | } | ||
236 | |||
237 | static int hpp__header_period_baseline(struct perf_hpp *hpp) | 211 | static int hpp__header_period_baseline(struct perf_hpp *hpp) |
238 | { | 212 | { |
239 | const char *fmt = symbol_conf.field_sep ? "%s" : "%12s"; | 213 | const char *fmt = symbol_conf.field_sep ? "%s" : "%12s"; |
@@ -254,6 +228,7 @@ static int hpp__entry_period_baseline(struct perf_hpp *hpp, struct hist_entry *h | |||
254 | 228 | ||
255 | return scnprintf(hpp->buf, hpp->size, fmt, period); | 229 | return scnprintf(hpp->buf, hpp->size, fmt, period); |
256 | } | 230 | } |
231 | |||
257 | static int hpp__header_delta(struct perf_hpp *hpp) | 232 | static int hpp__header_delta(struct perf_hpp *hpp) |
258 | { | 233 | { |
259 | const char *fmt = symbol_conf.field_sep ? "%s" : "%7s"; | 234 | const char *fmt = symbol_conf.field_sep ? "%s" : "%7s"; |
@@ -268,14 +243,18 @@ static int hpp__width_delta(struct perf_hpp *hpp __maybe_unused) | |||
268 | 243 | ||
269 | static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he) | 244 | static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he) |
270 | { | 245 | { |
246 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
271 | const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s"; | 247 | const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s"; |
272 | char buf[32] = " "; | 248 | char buf[32] = " "; |
273 | double diff; | 249 | double diff = 0.0; |
274 | 250 | ||
275 | if (he->diff.computed) | 251 | if (pair) { |
276 | diff = he->diff.period_ratio_delta; | 252 | if (he->diff.computed) |
277 | else | 253 | diff = he->diff.period_ratio_delta; |
278 | diff = perf_diff__compute_delta(he); | 254 | else |
255 | diff = perf_diff__compute_delta(he, pair); | ||
256 | } else | ||
257 | diff = perf_diff__period_percent(he, he->stat.period); | ||
279 | 258 | ||
280 | if (fabs(diff) >= 0.01) | 259 | if (fabs(diff) >= 0.01) |
281 | scnprintf(buf, sizeof(buf), "%+4.2F%%", diff); | 260 | scnprintf(buf, sizeof(buf), "%+4.2F%%", diff); |
@@ -297,14 +276,17 @@ static int hpp__width_ratio(struct perf_hpp *hpp __maybe_unused) | |||
297 | 276 | ||
298 | static int hpp__entry_ratio(struct perf_hpp *hpp, struct hist_entry *he) | 277 | static int hpp__entry_ratio(struct perf_hpp *hpp, struct hist_entry *he) |
299 | { | 278 | { |
279 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
300 | const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; | 280 | const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; |
301 | char buf[32] = " "; | 281 | char buf[32] = " "; |
302 | double ratio; | 282 | double ratio = 0.0; |
303 | 283 | ||
304 | if (he->diff.computed) | 284 | if (pair) { |
305 | ratio = he->diff.period_ratio; | 285 | if (he->diff.computed) |
306 | else | 286 | ratio = he->diff.period_ratio; |
307 | ratio = perf_diff__compute_ratio(he); | 287 | else |
288 | ratio = perf_diff__compute_ratio(he, pair); | ||
289 | } | ||
308 | 290 | ||
309 | if (ratio > 0.0) | 291 | if (ratio > 0.0) |
310 | scnprintf(buf, sizeof(buf), "%+14.6F", ratio); | 292 | scnprintf(buf, sizeof(buf), "%+14.6F", ratio); |
@@ -326,14 +308,17 @@ static int hpp__width_wdiff(struct perf_hpp *hpp __maybe_unused) | |||
326 | 308 | ||
327 | static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he) | 309 | static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he) |
328 | { | 310 | { |
311 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
329 | const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; | 312 | const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; |
330 | char buf[32] = " "; | 313 | char buf[32] = " "; |
331 | s64 wdiff; | 314 | s64 wdiff = 0; |
332 | 315 | ||
333 | if (he->diff.computed) | 316 | if (pair) { |
334 | wdiff = he->diff.wdiff; | 317 | if (he->diff.computed) |
335 | else | 318 | wdiff = he->diff.wdiff; |
336 | wdiff = perf_diff__compute_wdiff(he); | 319 | else |
320 | wdiff = perf_diff__compute_wdiff(he, pair); | ||
321 | } | ||
337 | 322 | ||
338 | if (wdiff != 0) | 323 | if (wdiff != 0) |
339 | scnprintf(buf, sizeof(buf), "%14ld", wdiff); | 324 | scnprintf(buf, sizeof(buf), "%14ld", wdiff); |
@@ -341,30 +326,6 @@ static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he) | |||
341 | return scnprintf(hpp->buf, hpp->size, fmt, buf); | 326 | return scnprintf(hpp->buf, hpp->size, fmt, buf); |
342 | } | 327 | } |
343 | 328 | ||
344 | static int hpp__header_displ(struct perf_hpp *hpp) | ||
345 | { | ||
346 | return scnprintf(hpp->buf, hpp->size, "Displ."); | ||
347 | } | ||
348 | |||
349 | static int hpp__width_displ(struct perf_hpp *hpp __maybe_unused) | ||
350 | { | ||
351 | return 6; | ||
352 | } | ||
353 | |||
354 | static int hpp__entry_displ(struct perf_hpp *hpp, | ||
355 | struct hist_entry *he) | ||
356 | { | ||
357 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
358 | long displacement = pair ? pair->position - he->position : 0; | ||
359 | const char *fmt = symbol_conf.field_sep ? "%s" : "%6.6s"; | ||
360 | char buf[32] = " "; | ||
361 | |||
362 | if (displacement) | ||
363 | scnprintf(buf, sizeof(buf), "%+4ld", displacement); | ||
364 | |||
365 | return scnprintf(hpp->buf, hpp->size, fmt, buf); | ||
366 | } | ||
367 | |||
368 | static int hpp__header_formula(struct perf_hpp *hpp) | 329 | static int hpp__header_formula(struct perf_hpp *hpp) |
369 | { | 330 | { |
370 | const char *fmt = symbol_conf.field_sep ? "%s" : "%70s"; | 331 | const char *fmt = symbol_conf.field_sep ? "%s" : "%70s"; |
@@ -379,67 +340,91 @@ static int hpp__width_formula(struct perf_hpp *hpp __maybe_unused) | |||
379 | 340 | ||
380 | static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he) | 341 | static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he) |
381 | { | 342 | { |
343 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
382 | const char *fmt = symbol_conf.field_sep ? "%s" : "%-70s"; | 344 | const char *fmt = symbol_conf.field_sep ? "%s" : "%-70s"; |
383 | char buf[96] = " "; | 345 | char buf[96] = " "; |
384 | 346 | ||
385 | perf_diff__formula(buf, sizeof(buf), he); | 347 | if (pair) |
348 | perf_diff__formula(he, pair, buf, sizeof(buf)); | ||
349 | |||
386 | return scnprintf(hpp->buf, hpp->size, fmt, buf); | 350 | return scnprintf(hpp->buf, hpp->size, fmt, buf); |
387 | } | 351 | } |
388 | 352 | ||
389 | #define HPP__COLOR_PRINT_FNS(_name) \ | 353 | #define HPP__COLOR_PRINT_FNS(_name) \ |
390 | .header = hpp__header_ ## _name, \ | 354 | { \ |
391 | .width = hpp__width_ ## _name, \ | 355 | .header = hpp__header_ ## _name, \ |
392 | .color = hpp__color_ ## _name, \ | 356 | .width = hpp__width_ ## _name, \ |
393 | .entry = hpp__entry_ ## _name | 357 | .color = hpp__color_ ## _name, \ |
358 | .entry = hpp__entry_ ## _name \ | ||
359 | } | ||
394 | 360 | ||
395 | #define HPP__PRINT_FNS(_name) \ | 361 | #define HPP__PRINT_FNS(_name) \ |
396 | .header = hpp__header_ ## _name, \ | 362 | { \ |
397 | .width = hpp__width_ ## _name, \ | 363 | .header = hpp__header_ ## _name, \ |
398 | .entry = hpp__entry_ ## _name | 364 | .width = hpp__width_ ## _name, \ |
365 | .entry = hpp__entry_ ## _name \ | ||
366 | } | ||
399 | 367 | ||
400 | struct perf_hpp_fmt perf_hpp__format[] = { | 368 | struct perf_hpp_fmt perf_hpp__format[] = { |
401 | { .cond = false, HPP__COLOR_PRINT_FNS(baseline) }, | 369 | HPP__COLOR_PRINT_FNS(baseline), |
402 | { .cond = true, HPP__COLOR_PRINT_FNS(overhead) }, | 370 | HPP__COLOR_PRINT_FNS(overhead), |
403 | { .cond = false, HPP__COLOR_PRINT_FNS(overhead_sys) }, | 371 | HPP__COLOR_PRINT_FNS(overhead_sys), |
404 | { .cond = false, HPP__COLOR_PRINT_FNS(overhead_us) }, | 372 | HPP__COLOR_PRINT_FNS(overhead_us), |
405 | { .cond = false, HPP__COLOR_PRINT_FNS(overhead_guest_sys) }, | 373 | HPP__COLOR_PRINT_FNS(overhead_guest_sys), |
406 | { .cond = false, HPP__COLOR_PRINT_FNS(overhead_guest_us) }, | 374 | HPP__COLOR_PRINT_FNS(overhead_guest_us), |
407 | { .cond = false, HPP__PRINT_FNS(samples) }, | 375 | HPP__PRINT_FNS(samples), |
408 | { .cond = false, HPP__PRINT_FNS(period) }, | 376 | HPP__PRINT_FNS(period), |
409 | { .cond = false, HPP__PRINT_FNS(period_baseline) }, | 377 | HPP__PRINT_FNS(period_baseline), |
410 | { .cond = false, HPP__PRINT_FNS(delta) }, | 378 | HPP__PRINT_FNS(delta), |
411 | { .cond = false, HPP__PRINT_FNS(ratio) }, | 379 | HPP__PRINT_FNS(ratio), |
412 | { .cond = false, HPP__PRINT_FNS(wdiff) }, | 380 | HPP__PRINT_FNS(wdiff), |
413 | { .cond = false, HPP__PRINT_FNS(displ) }, | 381 | HPP__PRINT_FNS(formula) |
414 | { .cond = false, HPP__PRINT_FNS(formula) } | ||
415 | }; | 382 | }; |
416 | 383 | ||
384 | LIST_HEAD(perf_hpp__list); | ||
385 | |||
386 | |||
417 | #undef HPP__COLOR_PRINT_FNS | 387 | #undef HPP__COLOR_PRINT_FNS |
418 | #undef HPP__PRINT_FNS | 388 | #undef HPP__PRINT_FNS |
419 | 389 | ||
390 | #undef HPP_PERCENT_FNS | ||
391 | #undef HPP_RAW_FNS | ||
392 | |||
393 | #undef __HPP_HEADER_FN | ||
394 | #undef __HPP_WIDTH_FN | ||
395 | #undef __HPP_COLOR_PERCENT_FN | ||
396 | #undef __HPP_ENTRY_PERCENT_FN | ||
397 | #undef __HPP_ENTRY_RAW_FN | ||
398 | |||
399 | |||
420 | void perf_hpp__init(void) | 400 | void perf_hpp__init(void) |
421 | { | 401 | { |
422 | if (symbol_conf.show_cpu_utilization) { | 402 | if (symbol_conf.show_cpu_utilization) { |
423 | perf_hpp__format[PERF_HPP__OVERHEAD_SYS].cond = true; | 403 | perf_hpp__column_enable(PERF_HPP__OVERHEAD_SYS); |
424 | perf_hpp__format[PERF_HPP__OVERHEAD_US].cond = true; | 404 | perf_hpp__column_enable(PERF_HPP__OVERHEAD_US); |
425 | 405 | ||
426 | if (perf_guest) { | 406 | if (perf_guest) { |
427 | perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].cond = true; | 407 | perf_hpp__column_enable(PERF_HPP__OVERHEAD_GUEST_SYS); |
428 | perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].cond = true; | 408 | perf_hpp__column_enable(PERF_HPP__OVERHEAD_GUEST_US); |
429 | } | 409 | } |
430 | } | 410 | } |
431 | 411 | ||
432 | if (symbol_conf.show_nr_samples) | 412 | if (symbol_conf.show_nr_samples) |
433 | perf_hpp__format[PERF_HPP__SAMPLES].cond = true; | 413 | perf_hpp__column_enable(PERF_HPP__SAMPLES); |
434 | 414 | ||
435 | if (symbol_conf.show_total_period) | 415 | if (symbol_conf.show_total_period) |
436 | perf_hpp__format[PERF_HPP__PERIOD].cond = true; | 416 | perf_hpp__column_enable(PERF_HPP__PERIOD); |
417 | } | ||
418 | |||
419 | void perf_hpp__column_register(struct perf_hpp_fmt *format) | ||
420 | { | ||
421 | list_add_tail(&format->list, &perf_hpp__list); | ||
437 | } | 422 | } |
438 | 423 | ||
439 | void perf_hpp__column_enable(unsigned col, bool enable) | 424 | void perf_hpp__column_enable(unsigned col) |
440 | { | 425 | { |
441 | BUG_ON(col >= PERF_HPP__MAX_INDEX); | 426 | BUG_ON(col >= PERF_HPP__MAX_INDEX); |
442 | perf_hpp__format[col].cond = enable; | 427 | perf_hpp__column_register(&perf_hpp__format[col]); |
443 | } | 428 | } |
444 | 429 | ||
445 | static inline void advance_hpp(struct perf_hpp *hpp, int inc) | 430 | static inline void advance_hpp(struct perf_hpp *hpp, int inc) |
@@ -452,27 +437,29 @@ int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he, | |||
452 | bool color) | 437 | bool color) |
453 | { | 438 | { |
454 | const char *sep = symbol_conf.field_sep; | 439 | const char *sep = symbol_conf.field_sep; |
440 | struct perf_hpp_fmt *fmt; | ||
455 | char *start = hpp->buf; | 441 | char *start = hpp->buf; |
456 | int i, ret; | 442 | int ret; |
457 | bool first = true; | 443 | bool first = true; |
458 | 444 | ||
459 | if (symbol_conf.exclude_other && !he->parent) | 445 | if (symbol_conf.exclude_other && !he->parent) |
460 | return 0; | 446 | return 0; |
461 | 447 | ||
462 | for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { | 448 | perf_hpp__for_each_format(fmt) { |
463 | if (!perf_hpp__format[i].cond) | 449 | /* |
464 | continue; | 450 | * If there's no field_sep, we still need |
465 | 451 | * to display initial ' '. | |
452 | */ | ||
466 | if (!sep || !first) { | 453 | if (!sep || !first) { |
467 | ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " "); | 454 | ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " "); |
468 | advance_hpp(hpp, ret); | 455 | advance_hpp(hpp, ret); |
456 | } else | ||
469 | first = false; | 457 | first = false; |
470 | } | ||
471 | 458 | ||
472 | if (color && perf_hpp__format[i].color) | 459 | if (color && fmt->color) |
473 | ret = perf_hpp__format[i].color(hpp, he); | 460 | ret = fmt->color(hpp, he); |
474 | else | 461 | else |
475 | ret = perf_hpp__format[i].entry(hpp, he); | 462 | ret = fmt->entry(hpp, he); |
476 | 463 | ||
477 | advance_hpp(hpp, ret); | 464 | advance_hpp(hpp, ret); |
478 | } | 465 | } |
@@ -504,16 +491,18 @@ int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size, | |||
504 | */ | 491 | */ |
505 | unsigned int hists__sort_list_width(struct hists *hists) | 492 | unsigned int hists__sort_list_width(struct hists *hists) |
506 | { | 493 | { |
494 | struct perf_hpp_fmt *fmt; | ||
507 | struct sort_entry *se; | 495 | struct sort_entry *se; |
508 | int i, ret = 0; | 496 | int i = 0, ret = 0; |
497 | struct perf_hpp dummy_hpp = { | ||
498 | .ptr = hists_to_evsel(hists), | ||
499 | }; | ||
509 | 500 | ||
510 | for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { | 501 | perf_hpp__for_each_format(fmt) { |
511 | if (!perf_hpp__format[i].cond) | ||
512 | continue; | ||
513 | if (i) | 502 | if (i) |
514 | ret += 2; | 503 | ret += 2; |
515 | 504 | ||
516 | ret += perf_hpp__format[i].width(NULL); | 505 | ret += fmt->width(&dummy_hpp); |
517 | } | 506 | } |
518 | 507 | ||
519 | list_for_each_entry(se, &hist_entry__sort_list, list) | 508 | list_for_each_entry(se, &hist_entry__sort_list, list) |
diff --git a/tools/perf/ui/keysyms.h b/tools/perf/ui/keysyms.h index 809eca5707fa..65092d576b4e 100644 --- a/tools/perf/ui/keysyms.h +++ b/tools/perf/ui/keysyms.h | |||
@@ -23,5 +23,6 @@ | |||
23 | #define K_TIMER -1 | 23 | #define K_TIMER -1 |
24 | #define K_ERROR -2 | 24 | #define K_ERROR -2 |
25 | #define K_RESIZE -3 | 25 | #define K_RESIZE -3 |
26 | #define K_SWITCH_INPUT_DATA -4 | ||
26 | 27 | ||
27 | #endif /* _PERF_KEYSYMS_H_ */ | 28 | #endif /* _PERF_KEYSYMS_H_ */ |
diff --git a/tools/perf/ui/setup.c b/tools/perf/ui/setup.c index ebb4cc107876..ae6a789cb0f6 100644 --- a/tools/perf/ui/setup.c +++ b/tools/perf/ui/setup.c | |||
@@ -8,7 +8,7 @@ pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER; | |||
8 | 8 | ||
9 | void setup_browser(bool fallback_to_pager) | 9 | void setup_browser(bool fallback_to_pager) |
10 | { | 10 | { |
11 | if (!isatty(1) || dump_trace) | 11 | if (use_browser < 2 && (!isatty(1) || dump_trace)) |
12 | use_browser = 0; | 12 | use_browser = 0; |
13 | 13 | ||
14 | /* default to TUI */ | 14 | /* default to TUI */ |
@@ -30,6 +30,7 @@ void setup_browser(bool fallback_to_pager) | |||
30 | if (fallback_to_pager) | 30 | if (fallback_to_pager) |
31 | setup_pager(); | 31 | setup_pager(); |
32 | 32 | ||
33 | perf_hpp__column_enable(PERF_HPP__OVERHEAD); | ||
33 | perf_hpp__init(); | 34 | perf_hpp__init(); |
34 | break; | 35 | break; |
35 | } | 36 | } |
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index f0ee204f99bb..ff1f60cf442e 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c | |||
@@ -3,6 +3,7 @@ | |||
3 | #include "../../util/util.h" | 3 | #include "../../util/util.h" |
4 | #include "../../util/hist.h" | 4 | #include "../../util/hist.h" |
5 | #include "../../util/sort.h" | 5 | #include "../../util/sort.h" |
6 | #include "../../util/evsel.h" | ||
6 | 7 | ||
7 | 8 | ||
8 | static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) | 9 | static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) |
@@ -335,17 +336,19 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size, | |||
335 | size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, | 336 | size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, |
336 | int max_cols, FILE *fp) | 337 | int max_cols, FILE *fp) |
337 | { | 338 | { |
339 | struct perf_hpp_fmt *fmt; | ||
338 | struct sort_entry *se; | 340 | struct sort_entry *se; |
339 | struct rb_node *nd; | 341 | struct rb_node *nd; |
340 | size_t ret = 0; | 342 | size_t ret = 0; |
341 | unsigned int width; | 343 | unsigned int width; |
342 | const char *sep = symbol_conf.field_sep; | 344 | const char *sep = symbol_conf.field_sep; |
343 | const char *col_width = symbol_conf.col_width_list_str; | 345 | const char *col_width = symbol_conf.col_width_list_str; |
344 | int idx, nr_rows = 0; | 346 | int nr_rows = 0; |
345 | char bf[96]; | 347 | char bf[96]; |
346 | struct perf_hpp dummy_hpp = { | 348 | struct perf_hpp dummy_hpp = { |
347 | .buf = bf, | 349 | .buf = bf, |
348 | .size = sizeof(bf), | 350 | .size = sizeof(bf), |
351 | .ptr = hists_to_evsel(hists), | ||
349 | }; | 352 | }; |
350 | bool first = true; | 353 | bool first = true; |
351 | 354 | ||
@@ -355,16 +358,14 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, | |||
355 | goto print_entries; | 358 | goto print_entries; |
356 | 359 | ||
357 | fprintf(fp, "# "); | 360 | fprintf(fp, "# "); |
358 | for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) { | ||
359 | if (!perf_hpp__format[idx].cond) | ||
360 | continue; | ||
361 | 361 | ||
362 | perf_hpp__for_each_format(fmt) { | ||
362 | if (!first) | 363 | if (!first) |
363 | fprintf(fp, "%s", sep ?: " "); | 364 | fprintf(fp, "%s", sep ?: " "); |
364 | else | 365 | else |
365 | first = false; | 366 | first = false; |
366 | 367 | ||
367 | perf_hpp__format[idx].header(&dummy_hpp); | 368 | fmt->header(&dummy_hpp); |
368 | fprintf(fp, "%s", bf); | 369 | fprintf(fp, "%s", bf); |
369 | } | 370 | } |
370 | 371 | ||
@@ -400,18 +401,16 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, | |||
400 | first = true; | 401 | first = true; |
401 | 402 | ||
402 | fprintf(fp, "# "); | 403 | fprintf(fp, "# "); |
403 | for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) { | ||
404 | unsigned int i; | ||
405 | 404 | ||
406 | if (!perf_hpp__format[idx].cond) | 405 | perf_hpp__for_each_format(fmt) { |
407 | continue; | 406 | unsigned int i; |
408 | 407 | ||
409 | if (!first) | 408 | if (!first) |
410 | fprintf(fp, "%s", sep ?: " "); | 409 | fprintf(fp, "%s", sep ?: " "); |
411 | else | 410 | else |
412 | first = false; | 411 | first = false; |
413 | 412 | ||
414 | width = perf_hpp__format[idx].width(&dummy_hpp); | 413 | width = fmt->width(&dummy_hpp); |
415 | for (i = 0; i < width; i++) | 414 | for (i = 0; i < width; i++) |
416 | fprintf(fp, "."); | 415 | fprintf(fp, "."); |
417 | } | 416 | } |
@@ -462,7 +461,7 @@ out: | |||
462 | return ret; | 461 | return ret; |
463 | } | 462 | } |
464 | 463 | ||
465 | size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp) | 464 | size_t events_stats__fprintf(struct events_stats *stats, FILE *fp) |
466 | { | 465 | { |
467 | int i; | 466 | int i; |
468 | size_t ret = 0; | 467 | size_t ret = 0; |
@@ -470,7 +469,7 @@ size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp) | |||
470 | for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { | 469 | for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { |
471 | const char *name; | 470 | const char *name; |
472 | 471 | ||
473 | if (hists->stats.nr_events[i] == 0) | 472 | if (stats->nr_events[i] == 0) |
474 | continue; | 473 | continue; |
475 | 474 | ||
476 | name = perf_event__name(i); | 475 | name = perf_event__name(i); |
@@ -478,7 +477,7 @@ size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp) | |||
478 | continue; | 477 | continue; |
479 | 478 | ||
480 | ret += fprintf(fp, "%16s events: %10d\n", name, | 479 | ret += fprintf(fp, "%16s events: %10d\n", name, |
481 | hists->stats.nr_events[i]); | 480 | stats->nr_events[i]); |
482 | } | 481 | } |
483 | 482 | ||
484 | return ret; | 483 | return ret; |
diff --git a/tools/perf/ui/tui/helpline.c b/tools/perf/ui/tui/helpline.c index 2884d2f41e33..1c8b9afd5d6e 100644 --- a/tools/perf/ui/tui/helpline.c +++ b/tools/perf/ui/tui/helpline.c | |||
@@ -8,6 +8,8 @@ | |||
8 | #include "../ui.h" | 8 | #include "../ui.h" |
9 | #include "../libslang.h" | 9 | #include "../libslang.h" |
10 | 10 | ||
11 | char ui_helpline__last_msg[1024]; | ||
12 | |||
11 | static void tui_helpline__pop(void) | 13 | static void tui_helpline__pop(void) |
12 | { | 14 | { |
13 | } | 15 | } |
@@ -23,20 +25,7 @@ static void tui_helpline__push(const char *msg) | |||
23 | strncpy(ui_helpline__current, msg, sz)[sz - 1] = '\0'; | 25 | strncpy(ui_helpline__current, msg, sz)[sz - 1] = '\0'; |
24 | } | 26 | } |
25 | 27 | ||
26 | struct ui_helpline tui_helpline_fns = { | 28 | static int tui_helpline__show(const char *format, va_list ap) |
27 | .pop = tui_helpline__pop, | ||
28 | .push = tui_helpline__push, | ||
29 | }; | ||
30 | |||
31 | void ui_helpline__init(void) | ||
32 | { | ||
33 | helpline_fns = &tui_helpline_fns; | ||
34 | ui_helpline__puts(" "); | ||
35 | } | ||
36 | |||
37 | char ui_helpline__last_msg[1024]; | ||
38 | |||
39 | int ui_helpline__show_help(const char *format, va_list ap) | ||
40 | { | 29 | { |
41 | int ret; | 30 | int ret; |
42 | static int backlog; | 31 | static int backlog; |
@@ -55,3 +44,15 @@ int ui_helpline__show_help(const char *format, va_list ap) | |||
55 | 44 | ||
56 | return ret; | 45 | return ret; |
57 | } | 46 | } |
47 | |||
48 | struct ui_helpline tui_helpline_fns = { | ||
49 | .pop = tui_helpline__pop, | ||
50 | .push = tui_helpline__push, | ||
51 | .show = tui_helpline__show, | ||
52 | }; | ||
53 | |||
54 | void ui_helpline__init(void) | ||
55 | { | ||
56 | helpline_fns = &tui_helpline_fns; | ||
57 | ui_helpline__puts(" "); | ||
58 | } | ||
diff --git a/tools/perf/ui/util.c b/tools/perf/ui/util.c index 4f989774c8c6..e3e0a963d03a 100644 --- a/tools/perf/ui/util.c +++ b/tools/perf/ui/util.c | |||
@@ -52,7 +52,6 @@ int ui__warning(const char *format, ...) | |||
52 | return ret; | 52 | return ret; |
53 | } | 53 | } |
54 | 54 | ||
55 | |||
56 | /** | 55 | /** |
57 | * perf_error__register - Register error logging functions | 56 | * perf_error__register - Register error logging functions |
58 | * @eops: The pointer to error logging function struct | 57 | * @eops: The pointer to error logging function struct |
diff --git a/tools/perf/util/PERF-VERSION-GEN b/tools/perf/util/PERF-VERSION-GEN index 6aa34e5afdcf..055fef34b6f6 100755 --- a/tools/perf/util/PERF-VERSION-GEN +++ b/tools/perf/util/PERF-VERSION-GEN | |||
@@ -26,13 +26,13 @@ VN=$(expr "$VN" : v*'\(.*\)') | |||
26 | 26 | ||
27 | if test -r $GVF | 27 | if test -r $GVF |
28 | then | 28 | then |
29 | VC=$(sed -e 's/^PERF_VERSION = //' <$GVF) | 29 | VC=$(sed -e 's/^#define PERF_VERSION "\(.*\)"/\1/' <$GVF) |
30 | else | 30 | else |
31 | VC=unset | 31 | VC=unset |
32 | fi | 32 | fi |
33 | test "$VN" = "$VC" || { | 33 | test "$VN" = "$VC" || { |
34 | echo >&2 "PERF_VERSION = $VN" | 34 | echo >&2 "PERF_VERSION = $VN" |
35 | echo "PERF_VERSION = $VN" >$GVF | 35 | echo "#define PERF_VERSION \"$VN\"" >$GVF |
36 | } | 36 | } |
37 | 37 | ||
38 | 38 | ||
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 07aaeea60000..d33fe937e6f1 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
@@ -809,7 +809,7 @@ fallback: | |||
809 | pr_err("Can't annotate %s:\n\n" | 809 | pr_err("Can't annotate %s:\n\n" |
810 | "No vmlinux file%s\nwas found in the path.\n\n" | 810 | "No vmlinux file%s\nwas found in the path.\n\n" |
811 | "Please use:\n\n" | 811 | "Please use:\n\n" |
812 | " perf buildid-cache -av vmlinux\n\n" | 812 | " perf buildid-cache -vu vmlinux\n\n" |
813 | "or:\n\n" | 813 | "or:\n\n" |
814 | " --vmlinux vmlinux\n", | 814 | " --vmlinux vmlinux\n", |
815 | sym->name, build_id_msg ?: ""); | 815 | sym->name, build_id_msg ?: ""); |
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 8eec94358a4a..c422440fe611 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h | |||
@@ -6,6 +6,7 @@ | |||
6 | #include "types.h" | 6 | #include "types.h" |
7 | #include "symbol.h" | 7 | #include "symbol.h" |
8 | #include "hist.h" | 8 | #include "hist.h" |
9 | #include "sort.h" | ||
9 | #include <linux/list.h> | 10 | #include <linux/list.h> |
10 | #include <linux/rbtree.h> | 11 | #include <linux/rbtree.h> |
11 | #include <pthread.h> | 12 | #include <pthread.h> |
@@ -154,6 +155,29 @@ static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused, | |||
154 | } | 155 | } |
155 | #endif | 156 | #endif |
156 | 157 | ||
158 | #ifdef GTK2_SUPPORT | ||
159 | int symbol__gtk_annotate(struct symbol *sym, struct map *map, int evidx, | ||
160 | struct hist_browser_timer *hbt); | ||
161 | |||
162 | static inline int hist_entry__gtk_annotate(struct hist_entry *he, int evidx, | ||
163 | struct hist_browser_timer *hbt) | ||
164 | { | ||
165 | return symbol__gtk_annotate(he->ms.sym, he->ms.map, evidx, hbt); | ||
166 | } | ||
167 | |||
168 | void perf_gtk__show_annotations(void); | ||
169 | #else | ||
170 | static inline int hist_entry__gtk_annotate(struct hist_entry *he __maybe_unused, | ||
171 | int evidx __maybe_unused, | ||
172 | struct hist_browser_timer *hbt | ||
173 | __maybe_unused) | ||
174 | { | ||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | static inline void perf_gtk__show_annotations(void) {} | ||
179 | #endif | ||
180 | |||
157 | extern const char *disassembler_style; | 181 | extern const char *disassembler_style; |
158 | 182 | ||
159 | #endif /* __PERF_ANNOTATE_H */ | 183 | #endif /* __PERF_ANNOTATE_H */ |
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index d3b3f5d82137..42b6a632fe7b 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c | |||
@@ -444,7 +444,7 @@ int callchain_cursor_append(struct callchain_cursor *cursor, | |||
444 | struct callchain_cursor_node *node = *cursor->last; | 444 | struct callchain_cursor_node *node = *cursor->last; |
445 | 445 | ||
446 | if (!node) { | 446 | if (!node) { |
447 | node = calloc(sizeof(*node), 1); | 447 | node = calloc(1, sizeof(*node)); |
448 | if (!node) | 448 | if (!node) |
449 | return -ENOMEM; | 449 | return -ENOMEM; |
450 | 450 | ||
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index eb340571e7d6..3ee9f67d5af0 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h | |||
@@ -143,4 +143,9 @@ static inline void callchain_cursor_advance(struct callchain_cursor *cursor) | |||
143 | cursor->curr = cursor->curr->next; | 143 | cursor->curr = cursor->curr->next; |
144 | cursor->pos++; | 144 | cursor->pos++; |
145 | } | 145 | } |
146 | |||
147 | struct option; | ||
148 | |||
149 | int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset); | ||
150 | extern const char record_callchain_help[]; | ||
146 | #endif /* __PERF_CALLCHAIN_H */ | 151 | #endif /* __PERF_CALLCHAIN_H */ |
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c index 2b32ffa9ebdb..f817046e22b1 100644 --- a/tools/perf/util/cpumap.c +++ b/tools/perf/util/cpumap.c | |||
@@ -1,4 +1,5 @@ | |||
1 | #include "util.h" | 1 | #include "util.h" |
2 | #include "sysfs.h" | ||
2 | #include "../perf.h" | 3 | #include "../perf.h" |
3 | #include "cpumap.h" | 4 | #include "cpumap.h" |
4 | #include <assert.h> | 5 | #include <assert.h> |
@@ -201,3 +202,56 @@ void cpu_map__delete(struct cpu_map *map) | |||
201 | { | 202 | { |
202 | free(map); | 203 | free(map); |
203 | } | 204 | } |
205 | |||
206 | int cpu_map__get_socket(struct cpu_map *map, int idx) | ||
207 | { | ||
208 | FILE *fp; | ||
209 | const char *mnt; | ||
210 | char path[PATH_MAX]; | ||
211 | int cpu, ret; | ||
212 | |||
213 | if (idx > map->nr) | ||
214 | return -1; | ||
215 | |||
216 | cpu = map->map[idx]; | ||
217 | |||
218 | mnt = sysfs_find_mountpoint(); | ||
219 | if (!mnt) | ||
220 | return -1; | ||
221 | |||
222 | sprintf(path, | ||
223 | "%s/devices/system/cpu/cpu%d/topology/physical_package_id", | ||
224 | mnt, cpu); | ||
225 | |||
226 | fp = fopen(path, "r"); | ||
227 | if (!fp) | ||
228 | return -1; | ||
229 | ret = fscanf(fp, "%d", &cpu); | ||
230 | fclose(fp); | ||
231 | return ret == 1 ? cpu : -1; | ||
232 | } | ||
233 | |||
234 | int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp) | ||
235 | { | ||
236 | struct cpu_map *sock; | ||
237 | int nr = cpus->nr; | ||
238 | int cpu, s1, s2; | ||
239 | |||
240 | sock = calloc(1, sizeof(*sock) + nr * sizeof(int)); | ||
241 | if (!sock) | ||
242 | return -1; | ||
243 | |||
244 | for (cpu = 0; cpu < nr; cpu++) { | ||
245 | s1 = cpu_map__get_socket(cpus, cpu); | ||
246 | for (s2 = 0; s2 < sock->nr; s2++) { | ||
247 | if (s1 == sock->map[s2]) | ||
248 | break; | ||
249 | } | ||
250 | if (s2 == sock->nr) { | ||
251 | sock->map[sock->nr] = s1; | ||
252 | sock->nr++; | ||
253 | } | ||
254 | } | ||
255 | *sockp = sock; | ||
256 | return 0; | ||
257 | } | ||
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h index 2f68a3b8c285..161b00756a12 100644 --- a/tools/perf/util/cpumap.h +++ b/tools/perf/util/cpumap.h | |||
@@ -14,6 +14,15 @@ struct cpu_map *cpu_map__dummy_new(void); | |||
14 | void cpu_map__delete(struct cpu_map *map); | 14 | void cpu_map__delete(struct cpu_map *map); |
15 | struct cpu_map *cpu_map__read(FILE *file); | 15 | struct cpu_map *cpu_map__read(FILE *file); |
16 | size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); | 16 | size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); |
17 | int cpu_map__get_socket(struct cpu_map *map, int idx); | ||
18 | int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp); | ||
19 | |||
20 | static inline int cpu_map__socket(struct cpu_map *sock, int s) | ||
21 | { | ||
22 | if (!sock || s > sock->nr || s < 0) | ||
23 | return 0; | ||
24 | return sock->map[s]; | ||
25 | } | ||
17 | 26 | ||
18 | static inline int cpu_map__nr(const struct cpu_map *map) | 27 | static inline int cpu_map__nr(const struct cpu_map *map) |
19 | { | 28 | { |
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index 03f830b48148..399e74c34c1a 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c | |||
@@ -23,10 +23,8 @@ int eprintf(int level, const char *fmt, ...) | |||
23 | 23 | ||
24 | if (verbose >= level) { | 24 | if (verbose >= level) { |
25 | va_start(args, fmt); | 25 | va_start(args, fmt); |
26 | if (use_browser == 1) | 26 | if (use_browser >= 1) |
27 | ret = ui_helpline__show_help(fmt, args); | 27 | ui_helpline__vshow(fmt, args); |
28 | else if (use_browser == 2) | ||
29 | ret = perf_gtk__show_helpline(fmt, args); | ||
30 | else | 28 | else |
31 | ret = vfprintf(stderr, fmt, args); | 29 | ret = vfprintf(stderr, fmt, args); |
32 | va_end(args); | 30 | va_end(args); |
@@ -49,28 +47,6 @@ int dump_printf(const char *fmt, ...) | |||
49 | return ret; | 47 | return ret; |
50 | } | 48 | } |
51 | 49 | ||
52 | #if !defined(NEWT_SUPPORT) && !defined(GTK2_SUPPORT) | ||
53 | int ui__warning(const char *format, ...) | ||
54 | { | ||
55 | va_list args; | ||
56 | |||
57 | va_start(args, format); | ||
58 | vfprintf(stderr, format, args); | ||
59 | va_end(args); | ||
60 | return 0; | ||
61 | } | ||
62 | #endif | ||
63 | |||
64 | int ui__error_paranoid(void) | ||
65 | { | ||
66 | return ui__error("Permission error - are you root?\n" | ||
67 | "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n" | ||
68 | " -1 - Not paranoid at all\n" | ||
69 | " 0 - Disallow raw tracepoint access for unpriv\n" | ||
70 | " 1 - Disallow cpu events for unpriv\n" | ||
71 | " 2 - Disallow kernel profiling for unpriv\n"); | ||
72 | } | ||
73 | |||
74 | void trace_event(union perf_event *event) | 50 | void trace_event(union perf_event *event) |
75 | { | 51 | { |
76 | unsigned char *raw_event = (void *)event; | 52 | unsigned char *raw_event = (void *)event; |
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index 83e8d234af6b..efbd98805ad0 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h | |||
@@ -5,6 +5,8 @@ | |||
5 | #include <stdbool.h> | 5 | #include <stdbool.h> |
6 | #include "event.h" | 6 | #include "event.h" |
7 | #include "../ui/helpline.h" | 7 | #include "../ui/helpline.h" |
8 | #include "../ui/progress.h" | ||
9 | #include "../ui/util.h" | ||
8 | 10 | ||
9 | extern int verbose; | 11 | extern int verbose; |
10 | extern bool quiet, dump_trace; | 12 | extern bool quiet, dump_trace; |
@@ -12,39 +14,7 @@ extern bool quiet, dump_trace; | |||
12 | int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); | 14 | int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); |
13 | void trace_event(union perf_event *event); | 15 | void trace_event(union perf_event *event); |
14 | 16 | ||
15 | struct ui_progress; | ||
16 | struct perf_error_ops; | ||
17 | |||
18 | #if defined(NEWT_SUPPORT) || defined(GTK2_SUPPORT) | ||
19 | |||
20 | #include "../ui/progress.h" | ||
21 | int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); | 17 | int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); |
22 | #include "../ui/util.h" | ||
23 | |||
24 | #else | ||
25 | |||
26 | static inline void ui_progress__update(u64 curr __maybe_unused, | ||
27 | u64 total __maybe_unused, | ||
28 | const char *title __maybe_unused) {} | ||
29 | static inline void ui_progress__finish(void) {} | ||
30 | |||
31 | #define ui__error(format, arg...) ui__warning(format, ##arg) | ||
32 | |||
33 | static inline int | ||
34 | perf_error__register(struct perf_error_ops *eops __maybe_unused) | ||
35 | { | ||
36 | return 0; | ||
37 | } | ||
38 | |||
39 | static inline int | ||
40 | perf_error__unregister(struct perf_error_ops *eops __maybe_unused) | ||
41 | { | ||
42 | return 0; | ||
43 | } | ||
44 | |||
45 | #endif /* NEWT_SUPPORT || GTK2_SUPPORT */ | ||
46 | |||
47 | int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); | 18 | int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); |
48 | int ui__error_paranoid(void); | ||
49 | 19 | ||
50 | #endif /* __PERF_DEBUG_H */ | 20 | #endif /* __PERF_DEBUG_H */ |
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index d6d9a465acdb..6f7d5a9d6b05 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c | |||
@@ -539,13 +539,13 @@ struct dso *__dsos__findnew(struct list_head *head, const char *name) | |||
539 | } | 539 | } |
540 | 540 | ||
541 | size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, | 541 | size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, |
542 | bool with_hits) | 542 | bool (skip)(struct dso *dso, int parm), int parm) |
543 | { | 543 | { |
544 | struct dso *pos; | 544 | struct dso *pos; |
545 | size_t ret = 0; | 545 | size_t ret = 0; |
546 | 546 | ||
547 | list_for_each_entry(pos, head, node) { | 547 | list_for_each_entry(pos, head, node) { |
548 | if (with_hits && !pos->hit) | 548 | if (skip && skip(pos, parm)) |
549 | continue; | 549 | continue; |
550 | ret += dso__fprintf_buildid(pos, fp); | 550 | ret += dso__fprintf_buildid(pos, fp); |
551 | ret += fprintf(fp, " %s\n", pos->long_name); | 551 | ret += fprintf(fp, " %s\n", pos->long_name); |
@@ -583,7 +583,7 @@ size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp) | |||
583 | if (dso->short_name != dso->long_name) | 583 | if (dso->short_name != dso->long_name) |
584 | ret += fprintf(fp, "%s, ", dso->long_name); | 584 | ret += fprintf(fp, "%s, ", dso->long_name); |
585 | ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type], | 585 | ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type], |
586 | dso->loaded ? "" : "NOT "); | 586 | dso__loaded(dso, type) ? "" : "NOT "); |
587 | ret += dso__fprintf_buildid(dso, fp); | 587 | ret += dso__fprintf_buildid(dso, fp); |
588 | ret += fprintf(fp, ")\n"); | 588 | ret += fprintf(fp, ")\n"); |
589 | for (nd = rb_first(&dso->symbols[type]); nd; nd = rb_next(nd)) { | 589 | for (nd = rb_first(&dso->symbols[type]); nd; nd = rb_next(nd)) { |
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index e03276940b99..450199ab51b5 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h | |||
@@ -138,7 +138,7 @@ struct dso *__dsos__findnew(struct list_head *head, const char *name); | |||
138 | bool __dsos__read_build_ids(struct list_head *head, bool with_hits); | 138 | bool __dsos__read_build_ids(struct list_head *head, bool with_hits); |
139 | 139 | ||
140 | size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, | 140 | size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, |
141 | bool with_hits); | 141 | bool (skip)(struct dso *dso, int parm), int parm); |
142 | size_t __dsos__fprintf(struct list_head *head, FILE *fp); | 142 | size_t __dsos__fprintf(struct list_head *head, FILE *fp); |
143 | 143 | ||
144 | size_t dso__fprintf_buildid(struct dso *dso, FILE *fp); | 144 | size_t dso__fprintf_buildid(struct dso *dso, FILE *fp); |
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 3cf2c3e0605f..5cd13d768cec 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
@@ -476,8 +476,10 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, | |||
476 | } | 476 | } |
477 | } | 477 | } |
478 | 478 | ||
479 | if (kallsyms__parse(filename, &args, find_symbol_cb) <= 0) | 479 | if (kallsyms__parse(filename, &args, find_symbol_cb) <= 0) { |
480 | free(event); | ||
480 | return -ENOENT; | 481 | return -ENOENT; |
482 | } | ||
481 | 483 | ||
482 | map = machine->vmlinux_maps[MAP__FUNCTION]; | 484 | map = machine->vmlinux_maps[MAP__FUNCTION]; |
483 | size = snprintf(event->mmap.filename, sizeof(event->mmap.filename), | 485 | size = snprintf(event->mmap.filename, sizeof(event->mmap.filename), |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 705293489e3c..bc4ad7977438 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -49,10 +49,16 @@ struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, | |||
49 | return evlist; | 49 | return evlist; |
50 | } | 50 | } |
51 | 51 | ||
52 | void perf_evlist__config_attrs(struct perf_evlist *evlist, | 52 | void perf_evlist__config(struct perf_evlist *evlist, |
53 | struct perf_record_opts *opts) | 53 | struct perf_record_opts *opts) |
54 | { | 54 | { |
55 | struct perf_evsel *evsel; | 55 | struct perf_evsel *evsel; |
56 | /* | ||
57 | * Set the evsel leader links before we configure attributes, | ||
58 | * since some might depend on this info. | ||
59 | */ | ||
60 | if (opts->group) | ||
61 | perf_evlist__set_leader(evlist); | ||
56 | 62 | ||
57 | if (evlist->cpus->map[0] < 0) | 63 | if (evlist->cpus->map[0] < 0) |
58 | opts->no_inherit = true; | 64 | opts->no_inherit = true; |
@@ -61,7 +67,7 @@ void perf_evlist__config_attrs(struct perf_evlist *evlist, | |||
61 | perf_evsel__config(evsel, opts); | 67 | perf_evsel__config(evsel, opts); |
62 | 68 | ||
63 | if (evlist->nr_entries > 1) | 69 | if (evlist->nr_entries > 1) |
64 | evsel->attr.sample_type |= PERF_SAMPLE_ID; | 70 | perf_evsel__set_sample_id(evsel); |
65 | } | 71 | } |
66 | } | 72 | } |
67 | 73 | ||
@@ -111,18 +117,21 @@ void __perf_evlist__set_leader(struct list_head *list) | |||
111 | struct perf_evsel *evsel, *leader; | 117 | struct perf_evsel *evsel, *leader; |
112 | 118 | ||
113 | leader = list_entry(list->next, struct perf_evsel, node); | 119 | leader = list_entry(list->next, struct perf_evsel, node); |
114 | leader->leader = NULL; | 120 | evsel = list_entry(list->prev, struct perf_evsel, node); |
121 | |||
122 | leader->nr_members = evsel->idx - leader->idx + 1; | ||
115 | 123 | ||
116 | list_for_each_entry(evsel, list, node) { | 124 | list_for_each_entry(evsel, list, node) { |
117 | if (evsel != leader) | 125 | evsel->leader = leader; |
118 | evsel->leader = leader; | ||
119 | } | 126 | } |
120 | } | 127 | } |
121 | 128 | ||
122 | void perf_evlist__set_leader(struct perf_evlist *evlist) | 129 | void perf_evlist__set_leader(struct perf_evlist *evlist) |
123 | { | 130 | { |
124 | if (evlist->nr_entries) | 131 | if (evlist->nr_entries) { |
132 | evlist->nr_groups = evlist->nr_entries > 1 ? 1 : 0; | ||
125 | __perf_evlist__set_leader(&evlist->entries); | 133 | __perf_evlist__set_leader(&evlist->entries); |
134 | } | ||
126 | } | 135 | } |
127 | 136 | ||
128 | int perf_evlist__add_default(struct perf_evlist *evlist) | 137 | int perf_evlist__add_default(struct perf_evlist *evlist) |
@@ -222,7 +231,7 @@ void perf_evlist__disable(struct perf_evlist *evlist) | |||
222 | 231 | ||
223 | for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { | 232 | for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { |
224 | list_for_each_entry(pos, &evlist->entries, node) { | 233 | list_for_each_entry(pos, &evlist->entries, node) { |
225 | if (perf_evsel__is_group_member(pos)) | 234 | if (!perf_evsel__is_group_leader(pos)) |
226 | continue; | 235 | continue; |
227 | for (thread = 0; thread < evlist->threads->nr; thread++) | 236 | for (thread = 0; thread < evlist->threads->nr; thread++) |
228 | ioctl(FD(pos, cpu, thread), | 237 | ioctl(FD(pos, cpu, thread), |
@@ -238,7 +247,7 @@ void perf_evlist__enable(struct perf_evlist *evlist) | |||
238 | 247 | ||
239 | for (cpu = 0; cpu < cpu_map__nr(evlist->cpus); cpu++) { | 248 | for (cpu = 0; cpu < cpu_map__nr(evlist->cpus); cpu++) { |
240 | list_for_each_entry(pos, &evlist->entries, node) { | 249 | list_for_each_entry(pos, &evlist->entries, node) { |
241 | if (perf_evsel__is_group_member(pos)) | 250 | if (!perf_evsel__is_group_leader(pos)) |
242 | continue; | 251 | continue; |
243 | for (thread = 0; thread < evlist->threads->nr; thread++) | 252 | for (thread = 0; thread < evlist->threads->nr; thread++) |
244 | ioctl(FD(pos, cpu, thread), | 253 | ioctl(FD(pos, cpu, thread), |
@@ -366,7 +375,7 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) | |||
366 | if ((old & md->mask) + size != ((old + size) & md->mask)) { | 375 | if ((old & md->mask) + size != ((old + size) & md->mask)) { |
367 | unsigned int offset = old; | 376 | unsigned int offset = old; |
368 | unsigned int len = min(sizeof(*event), size), cpy; | 377 | unsigned int len = min(sizeof(*event), size), cpy; |
369 | void *dst = &evlist->event_copy; | 378 | void *dst = &md->event_copy; |
370 | 379 | ||
371 | do { | 380 | do { |
372 | cpy = min(md->mask + 1 - (offset & md->mask), len); | 381 | cpy = min(md->mask + 1 - (offset & md->mask), len); |
@@ -376,7 +385,7 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) | |||
376 | len -= cpy; | 385 | len -= cpy; |
377 | } while (len); | 386 | } while (len); |
378 | 387 | ||
379 | event = &evlist->event_copy; | 388 | event = &md->event_copy; |
380 | } | 389 | } |
381 | 390 | ||
382 | old += size; | 391 | old += size; |
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 56003f779e60..2dd07bd60b4f 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
@@ -17,10 +17,18 @@ struct perf_record_opts; | |||
17 | #define PERF_EVLIST__HLIST_BITS 8 | 17 | #define PERF_EVLIST__HLIST_BITS 8 |
18 | #define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS) | 18 | #define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS) |
19 | 19 | ||
20 | struct perf_mmap { | ||
21 | void *base; | ||
22 | int mask; | ||
23 | unsigned int prev; | ||
24 | union perf_event event_copy; | ||
25 | }; | ||
26 | |||
20 | struct perf_evlist { | 27 | struct perf_evlist { |
21 | struct list_head entries; | 28 | struct list_head entries; |
22 | struct hlist_head heads[PERF_EVLIST__HLIST_SIZE]; | 29 | struct hlist_head heads[PERF_EVLIST__HLIST_SIZE]; |
23 | int nr_entries; | 30 | int nr_entries; |
31 | int nr_groups; | ||
24 | int nr_fds; | 32 | int nr_fds; |
25 | int nr_mmaps; | 33 | int nr_mmaps; |
26 | int mmap_len; | 34 | int mmap_len; |
@@ -29,7 +37,6 @@ struct perf_evlist { | |||
29 | pid_t pid; | 37 | pid_t pid; |
30 | } workload; | 38 | } workload; |
31 | bool overwrite; | 39 | bool overwrite; |
32 | union perf_event event_copy; | ||
33 | struct perf_mmap *mmap; | 40 | struct perf_mmap *mmap; |
34 | struct pollfd *pollfd; | 41 | struct pollfd *pollfd; |
35 | struct thread_map *threads; | 42 | struct thread_map *threads; |
@@ -76,8 +83,8 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx); | |||
76 | 83 | ||
77 | int perf_evlist__open(struct perf_evlist *evlist); | 84 | int perf_evlist__open(struct perf_evlist *evlist); |
78 | 85 | ||
79 | void perf_evlist__config_attrs(struct perf_evlist *evlist, | 86 | void perf_evlist__config(struct perf_evlist *evlist, |
80 | struct perf_record_opts *opts); | 87 | struct perf_record_opts *opts); |
81 | 88 | ||
82 | int perf_evlist__prepare_workload(struct perf_evlist *evlist, | 89 | int perf_evlist__prepare_workload(struct perf_evlist *evlist, |
83 | struct perf_record_opts *opts, | 90 | struct perf_record_opts *opts, |
@@ -135,4 +142,25 @@ static inline struct perf_evsel *perf_evlist__last(struct perf_evlist *evlist) | |||
135 | } | 142 | } |
136 | 143 | ||
137 | size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp); | 144 | size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp); |
145 | |||
146 | static inline unsigned int perf_mmap__read_head(struct perf_mmap *mm) | ||
147 | { | ||
148 | struct perf_event_mmap_page *pc = mm->base; | ||
149 | int head = pc->data_head; | ||
150 | rmb(); | ||
151 | return head; | ||
152 | } | ||
153 | |||
154 | static inline void perf_mmap__write_tail(struct perf_mmap *md, | ||
155 | unsigned long tail) | ||
156 | { | ||
157 | struct perf_event_mmap_page *pc = md->base; | ||
158 | |||
159 | /* | ||
160 | * ensure all reads are done before we write the tail out. | ||
161 | */ | ||
162 | /* mb(); */ | ||
163 | pc->data_tail = tail; | ||
164 | } | ||
165 | |||
138 | #endif /* __PERF_EVLIST_H */ | 166 | #endif /* __PERF_EVLIST_H */ |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 1b16dd1edc8e..9c82f98f26de 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -22,6 +22,11 @@ | |||
22 | #include <linux/perf_event.h> | 22 | #include <linux/perf_event.h> |
23 | #include "perf_regs.h" | 23 | #include "perf_regs.h" |
24 | 24 | ||
25 | static struct { | ||
26 | bool sample_id_all; | ||
27 | bool exclude_guest; | ||
28 | } perf_missing_features; | ||
29 | |||
25 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) | 30 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) |
26 | 31 | ||
27 | static int __perf_evsel__sample_size(u64 sample_type) | 32 | static int __perf_evsel__sample_size(u64 sample_type) |
@@ -50,11 +55,36 @@ void hists__init(struct hists *hists) | |||
50 | pthread_mutex_init(&hists->lock, NULL); | 55 | pthread_mutex_init(&hists->lock, NULL); |
51 | } | 56 | } |
52 | 57 | ||
58 | void __perf_evsel__set_sample_bit(struct perf_evsel *evsel, | ||
59 | enum perf_event_sample_format bit) | ||
60 | { | ||
61 | if (!(evsel->attr.sample_type & bit)) { | ||
62 | evsel->attr.sample_type |= bit; | ||
63 | evsel->sample_size += sizeof(u64); | ||
64 | } | ||
65 | } | ||
66 | |||
67 | void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel, | ||
68 | enum perf_event_sample_format bit) | ||
69 | { | ||
70 | if (evsel->attr.sample_type & bit) { | ||
71 | evsel->attr.sample_type &= ~bit; | ||
72 | evsel->sample_size -= sizeof(u64); | ||
73 | } | ||
74 | } | ||
75 | |||
76 | void perf_evsel__set_sample_id(struct perf_evsel *evsel) | ||
77 | { | ||
78 | perf_evsel__set_sample_bit(evsel, ID); | ||
79 | evsel->attr.read_format |= PERF_FORMAT_ID; | ||
80 | } | ||
81 | |||
53 | void perf_evsel__init(struct perf_evsel *evsel, | 82 | void perf_evsel__init(struct perf_evsel *evsel, |
54 | struct perf_event_attr *attr, int idx) | 83 | struct perf_event_attr *attr, int idx) |
55 | { | 84 | { |
56 | evsel->idx = idx; | 85 | evsel->idx = idx; |
57 | evsel->attr = *attr; | 86 | evsel->attr = *attr; |
87 | evsel->leader = evsel; | ||
58 | INIT_LIST_HEAD(&evsel->node); | 88 | INIT_LIST_HEAD(&evsel->node); |
59 | hists__init(&evsel->hists); | 89 | hists__init(&evsel->hists); |
60 | evsel->sample_size = __perf_evsel__sample_size(attr->sample_type); | 90 | evsel->sample_size = __perf_evsel__sample_size(attr->sample_type); |
@@ -404,6 +434,31 @@ const char *perf_evsel__name(struct perf_evsel *evsel) | |||
404 | return evsel->name ?: "unknown"; | 434 | return evsel->name ?: "unknown"; |
405 | } | 435 | } |
406 | 436 | ||
437 | const char *perf_evsel__group_name(struct perf_evsel *evsel) | ||
438 | { | ||
439 | return evsel->group_name ?: "anon group"; | ||
440 | } | ||
441 | |||
442 | int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size) | ||
443 | { | ||
444 | int ret; | ||
445 | struct perf_evsel *pos; | ||
446 | const char *group_name = perf_evsel__group_name(evsel); | ||
447 | |||
448 | ret = scnprintf(buf, size, "%s", group_name); | ||
449 | |||
450 | ret += scnprintf(buf + ret, size - ret, " { %s", | ||
451 | perf_evsel__name(evsel)); | ||
452 | |||
453 | for_each_group_member(pos, evsel) | ||
454 | ret += scnprintf(buf + ret, size - ret, ", %s", | ||
455 | perf_evsel__name(pos)); | ||
456 | |||
457 | ret += scnprintf(buf + ret, size - ret, " }"); | ||
458 | |||
459 | return ret; | ||
460 | } | ||
461 | |||
407 | /* | 462 | /* |
408 | * The enable_on_exec/disabled value strategy: | 463 | * The enable_on_exec/disabled value strategy: |
409 | * | 464 | * |
@@ -438,13 +493,11 @@ void perf_evsel__config(struct perf_evsel *evsel, | |||
438 | struct perf_event_attr *attr = &evsel->attr; | 493 | struct perf_event_attr *attr = &evsel->attr; |
439 | int track = !evsel->idx; /* only the first counter needs these */ | 494 | int track = !evsel->idx; /* only the first counter needs these */ |
440 | 495 | ||
441 | attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1; | 496 | attr->sample_id_all = perf_missing_features.sample_id_all ? 0 : 1; |
442 | attr->inherit = !opts->no_inherit; | 497 | attr->inherit = !opts->no_inherit; |
443 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | | ||
444 | PERF_FORMAT_TOTAL_TIME_RUNNING | | ||
445 | PERF_FORMAT_ID; | ||
446 | 498 | ||
447 | attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; | 499 | perf_evsel__set_sample_bit(evsel, IP); |
500 | perf_evsel__set_sample_bit(evsel, TID); | ||
448 | 501 | ||
449 | /* | 502 | /* |
450 | * We default some events to a 1 default interval. But keep | 503 | * We default some events to a 1 default interval. But keep |
@@ -453,7 +506,7 @@ void perf_evsel__config(struct perf_evsel *evsel, | |||
453 | if (!attr->sample_period || (opts->user_freq != UINT_MAX && | 506 | if (!attr->sample_period || (opts->user_freq != UINT_MAX && |
454 | opts->user_interval != ULLONG_MAX)) { | 507 | opts->user_interval != ULLONG_MAX)) { |
455 | if (opts->freq) { | 508 | if (opts->freq) { |
456 | attr->sample_type |= PERF_SAMPLE_PERIOD; | 509 | perf_evsel__set_sample_bit(evsel, PERIOD); |
457 | attr->freq = 1; | 510 | attr->freq = 1; |
458 | attr->sample_freq = opts->freq; | 511 | attr->sample_freq = opts->freq; |
459 | } else { | 512 | } else { |
@@ -468,16 +521,16 @@ void perf_evsel__config(struct perf_evsel *evsel, | |||
468 | attr->inherit_stat = 1; | 521 | attr->inherit_stat = 1; |
469 | 522 | ||
470 | if (opts->sample_address) { | 523 | if (opts->sample_address) { |
471 | attr->sample_type |= PERF_SAMPLE_ADDR; | 524 | perf_evsel__set_sample_bit(evsel, ADDR); |
472 | attr->mmap_data = track; | 525 | attr->mmap_data = track; |
473 | } | 526 | } |
474 | 527 | ||
475 | if (opts->call_graph) { | 528 | if (opts->call_graph) { |
476 | attr->sample_type |= PERF_SAMPLE_CALLCHAIN; | 529 | perf_evsel__set_sample_bit(evsel, CALLCHAIN); |
477 | 530 | ||
478 | if (opts->call_graph == CALLCHAIN_DWARF) { | 531 | if (opts->call_graph == CALLCHAIN_DWARF) { |
479 | attr->sample_type |= PERF_SAMPLE_REGS_USER | | 532 | perf_evsel__set_sample_bit(evsel, REGS_USER); |
480 | PERF_SAMPLE_STACK_USER; | 533 | perf_evsel__set_sample_bit(evsel, STACK_USER); |
481 | attr->sample_regs_user = PERF_REGS_MASK; | 534 | attr->sample_regs_user = PERF_REGS_MASK; |
482 | attr->sample_stack_user = opts->stack_dump_size; | 535 | attr->sample_stack_user = opts->stack_dump_size; |
483 | attr->exclude_callchain_user = 1; | 536 | attr->exclude_callchain_user = 1; |
@@ -485,20 +538,20 @@ void perf_evsel__config(struct perf_evsel *evsel, | |||
485 | } | 538 | } |
486 | 539 | ||
487 | if (perf_target__has_cpu(&opts->target)) | 540 | if (perf_target__has_cpu(&opts->target)) |
488 | attr->sample_type |= PERF_SAMPLE_CPU; | 541 | perf_evsel__set_sample_bit(evsel, CPU); |
489 | 542 | ||
490 | if (opts->period) | 543 | if (opts->period) |
491 | attr->sample_type |= PERF_SAMPLE_PERIOD; | 544 | perf_evsel__set_sample_bit(evsel, PERIOD); |
492 | 545 | ||
493 | if (!opts->sample_id_all_missing && | 546 | if (!perf_missing_features.sample_id_all && |
494 | (opts->sample_time || !opts->no_inherit || | 547 | (opts->sample_time || !opts->no_inherit || |
495 | perf_target__has_cpu(&opts->target))) | 548 | perf_target__has_cpu(&opts->target))) |
496 | attr->sample_type |= PERF_SAMPLE_TIME; | 549 | perf_evsel__set_sample_bit(evsel, TIME); |
497 | 550 | ||
498 | if (opts->raw_samples) { | 551 | if (opts->raw_samples) { |
499 | attr->sample_type |= PERF_SAMPLE_TIME; | 552 | perf_evsel__set_sample_bit(evsel, TIME); |
500 | attr->sample_type |= PERF_SAMPLE_RAW; | 553 | perf_evsel__set_sample_bit(evsel, RAW); |
501 | attr->sample_type |= PERF_SAMPLE_CPU; | 554 | perf_evsel__set_sample_bit(evsel, CPU); |
502 | } | 555 | } |
503 | 556 | ||
504 | if (opts->no_delay) { | 557 | if (opts->no_delay) { |
@@ -506,7 +559,7 @@ void perf_evsel__config(struct perf_evsel *evsel, | |||
506 | attr->wakeup_events = 1; | 559 | attr->wakeup_events = 1; |
507 | } | 560 | } |
508 | if (opts->branch_stack) { | 561 | if (opts->branch_stack) { |
509 | attr->sample_type |= PERF_SAMPLE_BRANCH_STACK; | 562 | perf_evsel__set_sample_bit(evsel, BRANCH_STACK); |
510 | attr->branch_sample_type = opts->branch_stack; | 563 | attr->branch_sample_type = opts->branch_stack; |
511 | } | 564 | } |
512 | 565 | ||
@@ -519,14 +572,14 @@ void perf_evsel__config(struct perf_evsel *evsel, | |||
519 | * Disabling only independent events or group leaders, | 572 | * Disabling only independent events or group leaders, |
520 | * keeping group members enabled. | 573 | * keeping group members enabled. |
521 | */ | 574 | */ |
522 | if (!perf_evsel__is_group_member(evsel)) | 575 | if (perf_evsel__is_group_leader(evsel)) |
523 | attr->disabled = 1; | 576 | attr->disabled = 1; |
524 | 577 | ||
525 | /* | 578 | /* |
526 | * Setting enable_on_exec for independent events and | 579 | * Setting enable_on_exec for independent events and |
527 | * group leaders for traced executed by perf. | 580 | * group leaders for traced executed by perf. |
528 | */ | 581 | */ |
529 | if (perf_target__none(&opts->target) && !perf_evsel__is_group_member(evsel)) | 582 | if (perf_target__none(&opts->target) && perf_evsel__is_group_leader(evsel)) |
530 | attr->enable_on_exec = 1; | 583 | attr->enable_on_exec = 1; |
531 | } | 584 | } |
532 | 585 | ||
@@ -612,6 +665,11 @@ void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads) | |||
612 | } | 665 | } |
613 | } | 666 | } |
614 | 667 | ||
668 | void perf_evsel__free_counts(struct perf_evsel *evsel) | ||
669 | { | ||
670 | free(evsel->counts); | ||
671 | } | ||
672 | |||
615 | void perf_evsel__exit(struct perf_evsel *evsel) | 673 | void perf_evsel__exit(struct perf_evsel *evsel) |
616 | { | 674 | { |
617 | assert(list_empty(&evsel->node)); | 675 | assert(list_empty(&evsel->node)); |
@@ -631,6 +689,28 @@ void perf_evsel__delete(struct perf_evsel *evsel) | |||
631 | free(evsel); | 689 | free(evsel); |
632 | } | 690 | } |
633 | 691 | ||
692 | static inline void compute_deltas(struct perf_evsel *evsel, | ||
693 | int cpu, | ||
694 | struct perf_counts_values *count) | ||
695 | { | ||
696 | struct perf_counts_values tmp; | ||
697 | |||
698 | if (!evsel->prev_raw_counts) | ||
699 | return; | ||
700 | |||
701 | if (cpu == -1) { | ||
702 | tmp = evsel->prev_raw_counts->aggr; | ||
703 | evsel->prev_raw_counts->aggr = *count; | ||
704 | } else { | ||
705 | tmp = evsel->prev_raw_counts->cpu[cpu]; | ||
706 | evsel->prev_raw_counts->cpu[cpu] = *count; | ||
707 | } | ||
708 | |||
709 | count->val = count->val - tmp.val; | ||
710 | count->ena = count->ena - tmp.ena; | ||
711 | count->run = count->run - tmp.run; | ||
712 | } | ||
713 | |||
634 | int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, | 714 | int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, |
635 | int cpu, int thread, bool scale) | 715 | int cpu, int thread, bool scale) |
636 | { | 716 | { |
@@ -646,6 +726,8 @@ int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, | |||
646 | if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0) | 726 | if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0) |
647 | return -errno; | 727 | return -errno; |
648 | 728 | ||
729 | compute_deltas(evsel, cpu, &count); | ||
730 | |||
649 | if (scale) { | 731 | if (scale) { |
650 | if (count.run == 0) | 732 | if (count.run == 0) |
651 | count.val = 0; | 733 | count.val = 0; |
@@ -684,6 +766,8 @@ int __perf_evsel__read(struct perf_evsel *evsel, | |||
684 | } | 766 | } |
685 | } | 767 | } |
686 | 768 | ||
769 | compute_deltas(evsel, -1, aggr); | ||
770 | |||
687 | evsel->counts->scaled = 0; | 771 | evsel->counts->scaled = 0; |
688 | if (scale) { | 772 | if (scale) { |
689 | if (aggr->run == 0) { | 773 | if (aggr->run == 0) { |
@@ -707,7 +791,7 @@ static int get_group_fd(struct perf_evsel *evsel, int cpu, int thread) | |||
707 | struct perf_evsel *leader = evsel->leader; | 791 | struct perf_evsel *leader = evsel->leader; |
708 | int fd; | 792 | int fd; |
709 | 793 | ||
710 | if (!perf_evsel__is_group_member(evsel)) | 794 | if (perf_evsel__is_group_leader(evsel)) |
711 | return -1; | 795 | return -1; |
712 | 796 | ||
713 | /* | 797 | /* |
@@ -738,6 +822,13 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | |||
738 | pid = evsel->cgrp->fd; | 822 | pid = evsel->cgrp->fd; |
739 | } | 823 | } |
740 | 824 | ||
825 | fallback_missing_features: | ||
826 | if (perf_missing_features.exclude_guest) | ||
827 | evsel->attr.exclude_guest = evsel->attr.exclude_host = 0; | ||
828 | retry_sample_id: | ||
829 | if (perf_missing_features.sample_id_all) | ||
830 | evsel->attr.sample_id_all = 0; | ||
831 | |||
741 | for (cpu = 0; cpu < cpus->nr; cpu++) { | 832 | for (cpu = 0; cpu < cpus->nr; cpu++) { |
742 | 833 | ||
743 | for (thread = 0; thread < threads->nr; thread++) { | 834 | for (thread = 0; thread < threads->nr; thread++) { |
@@ -754,13 +845,26 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | |||
754 | group_fd, flags); | 845 | group_fd, flags); |
755 | if (FD(evsel, cpu, thread) < 0) { | 846 | if (FD(evsel, cpu, thread) < 0) { |
756 | err = -errno; | 847 | err = -errno; |
757 | goto out_close; | 848 | goto try_fallback; |
758 | } | 849 | } |
759 | } | 850 | } |
760 | } | 851 | } |
761 | 852 | ||
762 | return 0; | 853 | return 0; |
763 | 854 | ||
855 | try_fallback: | ||
856 | if (err != -EINVAL || cpu > 0 || thread > 0) | ||
857 | goto out_close; | ||
858 | |||
859 | if (!perf_missing_features.exclude_guest && | ||
860 | (evsel->attr.exclude_guest || evsel->attr.exclude_host)) { | ||
861 | perf_missing_features.exclude_guest = true; | ||
862 | goto fallback_missing_features; | ||
863 | } else if (!perf_missing_features.sample_id_all) { | ||
864 | perf_missing_features.sample_id_all = true; | ||
865 | goto retry_sample_id; | ||
866 | } | ||
867 | |||
764 | out_close: | 868 | out_close: |
765 | do { | 869 | do { |
766 | while (--thread >= 0) { | 870 | while (--thread >= 0) { |
@@ -1205,3 +1309,225 @@ u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample, | |||
1205 | 1309 | ||
1206 | return 0; | 1310 | return 0; |
1207 | } | 1311 | } |
1312 | |||
1313 | static int comma_fprintf(FILE *fp, bool *first, const char *fmt, ...) | ||
1314 | { | ||
1315 | va_list args; | ||
1316 | int ret = 0; | ||
1317 | |||
1318 | if (!*first) { | ||
1319 | ret += fprintf(fp, ","); | ||
1320 | } else { | ||
1321 | ret += fprintf(fp, ":"); | ||
1322 | *first = false; | ||
1323 | } | ||
1324 | |||
1325 | va_start(args, fmt); | ||
1326 | ret += vfprintf(fp, fmt, args); | ||
1327 | va_end(args); | ||
1328 | return ret; | ||
1329 | } | ||
1330 | |||
1331 | static int __if_fprintf(FILE *fp, bool *first, const char *field, u64 value) | ||
1332 | { | ||
1333 | if (value == 0) | ||
1334 | return 0; | ||
1335 | |||
1336 | return comma_fprintf(fp, first, " %s: %" PRIu64, field, value); | ||
1337 | } | ||
1338 | |||
1339 | #define if_print(field) printed += __if_fprintf(fp, &first, #field, evsel->attr.field) | ||
1340 | |||
1341 | struct bit_names { | ||
1342 | int bit; | ||
1343 | const char *name; | ||
1344 | }; | ||
1345 | |||
1346 | static int bits__fprintf(FILE *fp, const char *field, u64 value, | ||
1347 | struct bit_names *bits, bool *first) | ||
1348 | { | ||
1349 | int i = 0, printed = comma_fprintf(fp, first, " %s: ", field); | ||
1350 | bool first_bit = true; | ||
1351 | |||
1352 | do { | ||
1353 | if (value & bits[i].bit) { | ||
1354 | printed += fprintf(fp, "%s%s", first_bit ? "" : "|", bits[i].name); | ||
1355 | first_bit = false; | ||
1356 | } | ||
1357 | } while (bits[++i].name != NULL); | ||
1358 | |||
1359 | return printed; | ||
1360 | } | ||
1361 | |||
1362 | static int sample_type__fprintf(FILE *fp, bool *first, u64 value) | ||
1363 | { | ||
1364 | #define bit_name(n) { PERF_SAMPLE_##n, #n } | ||
1365 | struct bit_names bits[] = { | ||
1366 | bit_name(IP), bit_name(TID), bit_name(TIME), bit_name(ADDR), | ||
1367 | bit_name(READ), bit_name(CALLCHAIN), bit_name(ID), bit_name(CPU), | ||
1368 | bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW), | ||
1369 | bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER), | ||
1370 | { .name = NULL, } | ||
1371 | }; | ||
1372 | #undef bit_name | ||
1373 | return bits__fprintf(fp, "sample_type", value, bits, first); | ||
1374 | } | ||
1375 | |||
1376 | static int read_format__fprintf(FILE *fp, bool *first, u64 value) | ||
1377 | { | ||
1378 | #define bit_name(n) { PERF_FORMAT_##n, #n } | ||
1379 | struct bit_names bits[] = { | ||
1380 | bit_name(TOTAL_TIME_ENABLED), bit_name(TOTAL_TIME_RUNNING), | ||
1381 | bit_name(ID), bit_name(GROUP), | ||
1382 | { .name = NULL, } | ||
1383 | }; | ||
1384 | #undef bit_name | ||
1385 | return bits__fprintf(fp, "read_format", value, bits, first); | ||
1386 | } | ||
1387 | |||
1388 | int perf_evsel__fprintf(struct perf_evsel *evsel, | ||
1389 | struct perf_attr_details *details, FILE *fp) | ||
1390 | { | ||
1391 | bool first = true; | ||
1392 | int printed = 0; | ||
1393 | |||
1394 | if (details->event_group) { | ||
1395 | struct perf_evsel *pos; | ||
1396 | |||
1397 | if (!perf_evsel__is_group_leader(evsel)) | ||
1398 | return 0; | ||
1399 | |||
1400 | if (evsel->nr_members > 1) | ||
1401 | printed += fprintf(fp, "%s{", evsel->group_name ?: ""); | ||
1402 | |||
1403 | printed += fprintf(fp, "%s", perf_evsel__name(evsel)); | ||
1404 | for_each_group_member(pos, evsel) | ||
1405 | printed += fprintf(fp, ",%s", perf_evsel__name(pos)); | ||
1406 | |||
1407 | if (evsel->nr_members > 1) | ||
1408 | printed += fprintf(fp, "}"); | ||
1409 | goto out; | ||
1410 | } | ||
1411 | |||
1412 | printed += fprintf(fp, "%s", perf_evsel__name(evsel)); | ||
1413 | |||
1414 | if (details->verbose || details->freq) { | ||
1415 | printed += comma_fprintf(fp, &first, " sample_freq=%" PRIu64, | ||
1416 | (u64)evsel->attr.sample_freq); | ||
1417 | } | ||
1418 | |||
1419 | if (details->verbose) { | ||
1420 | if_print(type); | ||
1421 | if_print(config); | ||
1422 | if_print(config1); | ||
1423 | if_print(config2); | ||
1424 | if_print(size); | ||
1425 | printed += sample_type__fprintf(fp, &first, evsel->attr.sample_type); | ||
1426 | if (evsel->attr.read_format) | ||
1427 | printed += read_format__fprintf(fp, &first, evsel->attr.read_format); | ||
1428 | if_print(disabled); | ||
1429 | if_print(inherit); | ||
1430 | if_print(pinned); | ||
1431 | if_print(exclusive); | ||
1432 | if_print(exclude_user); | ||
1433 | if_print(exclude_kernel); | ||
1434 | if_print(exclude_hv); | ||
1435 | if_print(exclude_idle); | ||
1436 | if_print(mmap); | ||
1437 | if_print(comm); | ||
1438 | if_print(freq); | ||
1439 | if_print(inherit_stat); | ||
1440 | if_print(enable_on_exec); | ||
1441 | if_print(task); | ||
1442 | if_print(watermark); | ||
1443 | if_print(precise_ip); | ||
1444 | if_print(mmap_data); | ||
1445 | if_print(sample_id_all); | ||
1446 | if_print(exclude_host); | ||
1447 | if_print(exclude_guest); | ||
1448 | if_print(__reserved_1); | ||
1449 | if_print(wakeup_events); | ||
1450 | if_print(bp_type); | ||
1451 | if_print(branch_sample_type); | ||
1452 | } | ||
1453 | out: | ||
1454 | fputc('\n', fp); | ||
1455 | return ++printed; | ||
1456 | } | ||
1457 | |||
1458 | bool perf_evsel__fallback(struct perf_evsel *evsel, int err, | ||
1459 | char *msg, size_t msgsize) | ||
1460 | { | ||
1461 | if ((err == ENOENT || err == ENXIO) && | ||
1462 | evsel->attr.type == PERF_TYPE_HARDWARE && | ||
1463 | evsel->attr.config == PERF_COUNT_HW_CPU_CYCLES) { | ||
1464 | /* | ||
1465 | * If it's cycles then fall back to hrtimer based | ||
1466 | * cpu-clock-tick sw counter, which is always available even if | ||
1467 | * no PMU support. | ||
1468 | * | ||
1469 | * PPC returns ENXIO until 2.6.37 (behavior changed with commit | ||
1470 | * b0a873e). | ||
1471 | */ | ||
1472 | scnprintf(msg, msgsize, "%s", | ||
1473 | "The cycles event is not supported, trying to fall back to cpu-clock-ticks"); | ||
1474 | |||
1475 | evsel->attr.type = PERF_TYPE_SOFTWARE; | ||
1476 | evsel->attr.config = PERF_COUNT_SW_CPU_CLOCK; | ||
1477 | |||
1478 | free(evsel->name); | ||
1479 | evsel->name = NULL; | ||
1480 | return true; | ||
1481 | } | ||
1482 | |||
1483 | return false; | ||
1484 | } | ||
1485 | |||
1486 | int perf_evsel__open_strerror(struct perf_evsel *evsel, | ||
1487 | struct perf_target *target, | ||
1488 | int err, char *msg, size_t size) | ||
1489 | { | ||
1490 | switch (err) { | ||
1491 | case EPERM: | ||
1492 | case EACCES: | ||
1493 | return scnprintf(msg, size, "%s", | ||
1494 | "You may not have permission to collect %sstats.\n" | ||
1495 | "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n" | ||
1496 | " -1 - Not paranoid at all\n" | ||
1497 | " 0 - Disallow raw tracepoint access for unpriv\n" | ||
1498 | " 1 - Disallow cpu events for unpriv\n" | ||
1499 | " 2 - Disallow kernel profiling for unpriv", | ||
1500 | target->system_wide ? "system-wide " : ""); | ||
1501 | case ENOENT: | ||
1502 | return scnprintf(msg, size, "The %s event is not supported.", | ||
1503 | perf_evsel__name(evsel)); | ||
1504 | case EMFILE: | ||
1505 | return scnprintf(msg, size, "%s", | ||
1506 | "Too many events are opened.\n" | ||
1507 | "Try again after reducing the number of events."); | ||
1508 | case ENODEV: | ||
1509 | if (target->cpu_list) | ||
1510 | return scnprintf(msg, size, "%s", | ||
1511 | "No such device - did you specify an out-of-range profile CPU?\n"); | ||
1512 | break; | ||
1513 | case EOPNOTSUPP: | ||
1514 | if (evsel->attr.precise_ip) | ||
1515 | return scnprintf(msg, size, "%s", | ||
1516 | "\'precise\' request may not be supported. Try removing 'p' modifier."); | ||
1517 | #if defined(__i386__) || defined(__x86_64__) | ||
1518 | if (evsel->attr.type == PERF_TYPE_HARDWARE) | ||
1519 | return scnprintf(msg, size, "%s", | ||
1520 | "No hardware sampling interrupt available.\n" | ||
1521 | "No APIC? If so then you can boot the kernel with the \"lapic\" boot parameter to force-enable it."); | ||
1522 | #endif | ||
1523 | break; | ||
1524 | default: | ||
1525 | break; | ||
1526 | } | ||
1527 | |||
1528 | return scnprintf(msg, size, | ||
1529 | "The sys_perf_event_open() syscall returned with %d (%s) for event (%s). \n" | ||
1530 | "/bin/dmesg may provide additional information.\n" | ||
1531 | "No CONFIG_PERF_EVENTS=y kernel support configured?\n", | ||
1532 | err, strerror(err), perf_evsel__name(evsel)); | ||
1533 | } | ||
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 3d2b8017438c..52021c3087df 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
@@ -53,6 +53,7 @@ struct perf_evsel { | |||
53 | struct xyarray *sample_id; | 53 | struct xyarray *sample_id; |
54 | u64 *id; | 54 | u64 *id; |
55 | struct perf_counts *counts; | 55 | struct perf_counts *counts; |
56 | struct perf_counts *prev_raw_counts; | ||
56 | int idx; | 57 | int idx; |
57 | u32 ids; | 58 | u32 ids; |
58 | struct hists hists; | 59 | struct hists hists; |
@@ -73,10 +74,13 @@ struct perf_evsel { | |||
73 | bool needs_swap; | 74 | bool needs_swap; |
74 | /* parse modifier helper */ | 75 | /* parse modifier helper */ |
75 | int exclude_GH; | 76 | int exclude_GH; |
77 | int nr_members; | ||
76 | struct perf_evsel *leader; | 78 | struct perf_evsel *leader; |
77 | char *group_name; | 79 | char *group_name; |
78 | }; | 80 | }; |
79 | 81 | ||
82 | #define hists_to_evsel(h) container_of(h, struct perf_evsel, hists) | ||
83 | |||
80 | struct cpu_map; | 84 | struct cpu_map; |
81 | struct thread_map; | 85 | struct thread_map; |
82 | struct perf_evlist; | 86 | struct perf_evlist; |
@@ -110,14 +114,30 @@ extern const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX]; | |||
110 | int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result, | 114 | int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result, |
111 | char *bf, size_t size); | 115 | char *bf, size_t size); |
112 | const char *perf_evsel__name(struct perf_evsel *evsel); | 116 | const char *perf_evsel__name(struct perf_evsel *evsel); |
117 | const char *perf_evsel__group_name(struct perf_evsel *evsel); | ||
118 | int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size); | ||
113 | 119 | ||
114 | int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); | 120 | int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); |
115 | int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); | 121 | int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); |
116 | int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); | 122 | int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); |
117 | void perf_evsel__free_fd(struct perf_evsel *evsel); | 123 | void perf_evsel__free_fd(struct perf_evsel *evsel); |
118 | void perf_evsel__free_id(struct perf_evsel *evsel); | 124 | void perf_evsel__free_id(struct perf_evsel *evsel); |
125 | void perf_evsel__free_counts(struct perf_evsel *evsel); | ||
119 | void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); | 126 | void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); |
120 | 127 | ||
128 | void __perf_evsel__set_sample_bit(struct perf_evsel *evsel, | ||
129 | enum perf_event_sample_format bit); | ||
130 | void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel, | ||
131 | enum perf_event_sample_format bit); | ||
132 | |||
133 | #define perf_evsel__set_sample_bit(evsel, bit) \ | ||
134 | __perf_evsel__set_sample_bit(evsel, PERF_SAMPLE_##bit) | ||
135 | |||
136 | #define perf_evsel__reset_sample_bit(evsel, bit) \ | ||
137 | __perf_evsel__reset_sample_bit(evsel, PERF_SAMPLE_##bit) | ||
138 | |||
139 | void perf_evsel__set_sample_id(struct perf_evsel *evsel); | ||
140 | |||
121 | int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads, | 141 | int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads, |
122 | const char *filter); | 142 | const char *filter); |
123 | 143 | ||
@@ -226,8 +246,34 @@ static inline struct perf_evsel *perf_evsel__next(struct perf_evsel *evsel) | |||
226 | return list_entry(evsel->node.next, struct perf_evsel, node); | 246 | return list_entry(evsel->node.next, struct perf_evsel, node); |
227 | } | 247 | } |
228 | 248 | ||
229 | static inline bool perf_evsel__is_group_member(const struct perf_evsel *evsel) | 249 | static inline bool perf_evsel__is_group_leader(const struct perf_evsel *evsel) |
250 | { | ||
251 | return evsel->leader == evsel; | ||
252 | } | ||
253 | |||
254 | struct perf_attr_details { | ||
255 | bool freq; | ||
256 | bool verbose; | ||
257 | bool event_group; | ||
258 | }; | ||
259 | |||
260 | int perf_evsel__fprintf(struct perf_evsel *evsel, | ||
261 | struct perf_attr_details *details, FILE *fp); | ||
262 | |||
263 | bool perf_evsel__fallback(struct perf_evsel *evsel, int err, | ||
264 | char *msg, size_t msgsize); | ||
265 | int perf_evsel__open_strerror(struct perf_evsel *evsel, | ||
266 | struct perf_target *target, | ||
267 | int err, char *msg, size_t size); | ||
268 | |||
269 | static inline int perf_evsel__group_idx(struct perf_evsel *evsel) | ||
230 | { | 270 | { |
231 | return evsel->leader != NULL; | 271 | return evsel->idx - evsel->leader->idx; |
232 | } | 272 | } |
273 | |||
274 | #define for_each_group_member(_evsel, _leader) \ | ||
275 | for ((_evsel) = list_entry((_leader)->node.next, struct perf_evsel, node); \ | ||
276 | (_evsel) && (_evsel)->leader == (_leader); \ | ||
277 | (_evsel) = list_entry((_evsel)->node.next, struct perf_evsel, node)) | ||
278 | |||
233 | #endif /* __PERF_EVSEL_H */ | 279 | #endif /* __PERF_EVSEL_H */ |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index b7da4634a047..f4bfd79ef6a7 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -148,7 +148,7 @@ static char *do_read_string(int fd, struct perf_header *ph) | |||
148 | u32 len; | 148 | u32 len; |
149 | char *buf; | 149 | char *buf; |
150 | 150 | ||
151 | sz = read(fd, &len, sizeof(len)); | 151 | sz = readn(fd, &len, sizeof(len)); |
152 | if (sz < (ssize_t)sizeof(len)) | 152 | if (sz < (ssize_t)sizeof(len)) |
153 | return NULL; | 153 | return NULL; |
154 | 154 | ||
@@ -159,7 +159,7 @@ static char *do_read_string(int fd, struct perf_header *ph) | |||
159 | if (!buf) | 159 | if (!buf) |
160 | return NULL; | 160 | return NULL; |
161 | 161 | ||
162 | ret = read(fd, buf, len); | 162 | ret = readn(fd, buf, len); |
163 | if (ret == (ssize_t)len) { | 163 | if (ret == (ssize_t)len) { |
164 | /* | 164 | /* |
165 | * strings are padded by zeroes | 165 | * strings are padded by zeroes |
@@ -287,12 +287,12 @@ static int dsos__write_buildid_table(struct perf_header *header, int fd) | |||
287 | struct perf_session *session = container_of(header, | 287 | struct perf_session *session = container_of(header, |
288 | struct perf_session, header); | 288 | struct perf_session, header); |
289 | struct rb_node *nd; | 289 | struct rb_node *nd; |
290 | int err = machine__write_buildid_table(&session->host_machine, fd); | 290 | int err = machine__write_buildid_table(&session->machines.host, fd); |
291 | 291 | ||
292 | if (err) | 292 | if (err) |
293 | return err; | 293 | return err; |
294 | 294 | ||
295 | for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { | 295 | for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) { |
296 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | 296 | struct machine *pos = rb_entry(nd, struct machine, rb_node); |
297 | err = machine__write_buildid_table(pos, fd); | 297 | err = machine__write_buildid_table(pos, fd); |
298 | if (err) | 298 | if (err) |
@@ -313,7 +313,8 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, | |||
313 | if (is_kallsyms) { | 313 | if (is_kallsyms) { |
314 | if (symbol_conf.kptr_restrict) { | 314 | if (symbol_conf.kptr_restrict) { |
315 | pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n"); | 315 | pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n"); |
316 | return 0; | 316 | err = 0; |
317 | goto out_free; | ||
317 | } | 318 | } |
318 | realname = (char *) name; | 319 | realname = (char *) name; |
319 | } else | 320 | } else |
@@ -448,9 +449,9 @@ static int perf_session__cache_build_ids(struct perf_session *session) | |||
448 | if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) | 449 | if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) |
449 | return -1; | 450 | return -1; |
450 | 451 | ||
451 | ret = machine__cache_build_ids(&session->host_machine, debugdir); | 452 | ret = machine__cache_build_ids(&session->machines.host, debugdir); |
452 | 453 | ||
453 | for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { | 454 | for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) { |
454 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | 455 | struct machine *pos = rb_entry(nd, struct machine, rb_node); |
455 | ret |= machine__cache_build_ids(pos, debugdir); | 456 | ret |= machine__cache_build_ids(pos, debugdir); |
456 | } | 457 | } |
@@ -467,9 +468,9 @@ static bool machine__read_build_ids(struct machine *machine, bool with_hits) | |||
467 | static bool perf_session__read_build_ids(struct perf_session *session, bool with_hits) | 468 | static bool perf_session__read_build_ids(struct perf_session *session, bool with_hits) |
468 | { | 469 | { |
469 | struct rb_node *nd; | 470 | struct rb_node *nd; |
470 | bool ret = machine__read_build_ids(&session->host_machine, with_hits); | 471 | bool ret = machine__read_build_ids(&session->machines.host, with_hits); |
471 | 472 | ||
472 | for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { | 473 | for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) { |
473 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | 474 | struct machine *pos = rb_entry(nd, struct machine, rb_node); |
474 | ret |= machine__read_build_ids(pos, with_hits); | 475 | ret |= machine__read_build_ids(pos, with_hits); |
475 | } | 476 | } |
@@ -954,6 +955,7 @@ static int write_topo_node(int fd, int node) | |||
954 | } | 955 | } |
955 | 956 | ||
956 | fclose(fp); | 957 | fclose(fp); |
958 | fp = NULL; | ||
957 | 959 | ||
958 | ret = do_write(fd, &mem_total, sizeof(u64)); | 960 | ret = do_write(fd, &mem_total, sizeof(u64)); |
959 | if (ret) | 961 | if (ret) |
@@ -980,7 +982,8 @@ static int write_topo_node(int fd, int node) | |||
980 | ret = do_write_string(fd, buf); | 982 | ret = do_write_string(fd, buf); |
981 | done: | 983 | done: |
982 | free(buf); | 984 | free(buf); |
983 | fclose(fp); | 985 | if (fp) |
986 | fclose(fp); | ||
984 | return ret; | 987 | return ret; |
985 | } | 988 | } |
986 | 989 | ||
@@ -1051,16 +1054,25 @@ static int write_pmu_mappings(int fd, struct perf_header *h __maybe_unused, | |||
1051 | struct perf_pmu *pmu = NULL; | 1054 | struct perf_pmu *pmu = NULL; |
1052 | off_t offset = lseek(fd, 0, SEEK_CUR); | 1055 | off_t offset = lseek(fd, 0, SEEK_CUR); |
1053 | __u32 pmu_num = 0; | 1056 | __u32 pmu_num = 0; |
1057 | int ret; | ||
1054 | 1058 | ||
1055 | /* write real pmu_num later */ | 1059 | /* write real pmu_num later */ |
1056 | do_write(fd, &pmu_num, sizeof(pmu_num)); | 1060 | ret = do_write(fd, &pmu_num, sizeof(pmu_num)); |
1061 | if (ret < 0) | ||
1062 | return ret; | ||
1057 | 1063 | ||
1058 | while ((pmu = perf_pmu__scan(pmu))) { | 1064 | while ((pmu = perf_pmu__scan(pmu))) { |
1059 | if (!pmu->name) | 1065 | if (!pmu->name) |
1060 | continue; | 1066 | continue; |
1061 | pmu_num++; | 1067 | pmu_num++; |
1062 | do_write(fd, &pmu->type, sizeof(pmu->type)); | 1068 | |
1063 | do_write_string(fd, pmu->name); | 1069 | ret = do_write(fd, &pmu->type, sizeof(pmu->type)); |
1070 | if (ret < 0) | ||
1071 | return ret; | ||
1072 | |||
1073 | ret = do_write_string(fd, pmu->name); | ||
1074 | if (ret < 0) | ||
1075 | return ret; | ||
1064 | } | 1076 | } |
1065 | 1077 | ||
1066 | if (pwrite(fd, &pmu_num, sizeof(pmu_num), offset) != sizeof(pmu_num)) { | 1078 | if (pwrite(fd, &pmu_num, sizeof(pmu_num), offset) != sizeof(pmu_num)) { |
@@ -1073,6 +1085,52 @@ static int write_pmu_mappings(int fd, struct perf_header *h __maybe_unused, | |||
1073 | } | 1085 | } |
1074 | 1086 | ||
1075 | /* | 1087 | /* |
1088 | * File format: | ||
1089 | * | ||
1090 | * struct group_descs { | ||
1091 | * u32 nr_groups; | ||
1092 | * struct group_desc { | ||
1093 | * char name[]; | ||
1094 | * u32 leader_idx; | ||
1095 | * u32 nr_members; | ||
1096 | * }[nr_groups]; | ||
1097 | * }; | ||
1098 | */ | ||
1099 | static int write_group_desc(int fd, struct perf_header *h __maybe_unused, | ||
1100 | struct perf_evlist *evlist) | ||
1101 | { | ||
1102 | u32 nr_groups = evlist->nr_groups; | ||
1103 | struct perf_evsel *evsel; | ||
1104 | int ret; | ||
1105 | |||
1106 | ret = do_write(fd, &nr_groups, sizeof(nr_groups)); | ||
1107 | if (ret < 0) | ||
1108 | return ret; | ||
1109 | |||
1110 | list_for_each_entry(evsel, &evlist->entries, node) { | ||
1111 | if (perf_evsel__is_group_leader(evsel) && | ||
1112 | evsel->nr_members > 1) { | ||
1113 | const char *name = evsel->group_name ?: "{anon_group}"; | ||
1114 | u32 leader_idx = evsel->idx; | ||
1115 | u32 nr_members = evsel->nr_members; | ||
1116 | |||
1117 | ret = do_write_string(fd, name); | ||
1118 | if (ret < 0) | ||
1119 | return ret; | ||
1120 | |||
1121 | ret = do_write(fd, &leader_idx, sizeof(leader_idx)); | ||
1122 | if (ret < 0) | ||
1123 | return ret; | ||
1124 | |||
1125 | ret = do_write(fd, &nr_members, sizeof(nr_members)); | ||
1126 | if (ret < 0) | ||
1127 | return ret; | ||
1128 | } | ||
1129 | } | ||
1130 | return 0; | ||
1131 | } | ||
1132 | |||
1133 | /* | ||
1076 | * default get_cpuid(): nothing gets recorded | 1134 | * default get_cpuid(): nothing gets recorded |
1077 | * actual implementation must be in arch/$(ARCH)/util/header.c | 1135 | * actual implementation must be in arch/$(ARCH)/util/header.c |
1078 | */ | 1136 | */ |
@@ -1209,14 +1267,14 @@ read_event_desc(struct perf_header *ph, int fd) | |||
1209 | size_t msz; | 1267 | size_t msz; |
1210 | 1268 | ||
1211 | /* number of events */ | 1269 | /* number of events */ |
1212 | ret = read(fd, &nre, sizeof(nre)); | 1270 | ret = readn(fd, &nre, sizeof(nre)); |
1213 | if (ret != (ssize_t)sizeof(nre)) | 1271 | if (ret != (ssize_t)sizeof(nre)) |
1214 | goto error; | 1272 | goto error; |
1215 | 1273 | ||
1216 | if (ph->needs_swap) | 1274 | if (ph->needs_swap) |
1217 | nre = bswap_32(nre); | 1275 | nre = bswap_32(nre); |
1218 | 1276 | ||
1219 | ret = read(fd, &sz, sizeof(sz)); | 1277 | ret = readn(fd, &sz, sizeof(sz)); |
1220 | if (ret != (ssize_t)sizeof(sz)) | 1278 | if (ret != (ssize_t)sizeof(sz)) |
1221 | goto error; | 1279 | goto error; |
1222 | 1280 | ||
@@ -1244,7 +1302,7 @@ read_event_desc(struct perf_header *ph, int fd) | |||
1244 | * must read entire on-file attr struct to | 1302 | * must read entire on-file attr struct to |
1245 | * sync up with layout. | 1303 | * sync up with layout. |
1246 | */ | 1304 | */ |
1247 | ret = read(fd, buf, sz); | 1305 | ret = readn(fd, buf, sz); |
1248 | if (ret != (ssize_t)sz) | 1306 | if (ret != (ssize_t)sz) |
1249 | goto error; | 1307 | goto error; |
1250 | 1308 | ||
@@ -1253,7 +1311,7 @@ read_event_desc(struct perf_header *ph, int fd) | |||
1253 | 1311 | ||
1254 | memcpy(&evsel->attr, buf, msz); | 1312 | memcpy(&evsel->attr, buf, msz); |
1255 | 1313 | ||
1256 | ret = read(fd, &nr, sizeof(nr)); | 1314 | ret = readn(fd, &nr, sizeof(nr)); |
1257 | if (ret != (ssize_t)sizeof(nr)) | 1315 | if (ret != (ssize_t)sizeof(nr)) |
1258 | goto error; | 1316 | goto error; |
1259 | 1317 | ||
@@ -1274,7 +1332,7 @@ read_event_desc(struct perf_header *ph, int fd) | |||
1274 | evsel->id = id; | 1332 | evsel->id = id; |
1275 | 1333 | ||
1276 | for (j = 0 ; j < nr; j++) { | 1334 | for (j = 0 ; j < nr; j++) { |
1277 | ret = read(fd, id, sizeof(*id)); | 1335 | ret = readn(fd, id, sizeof(*id)); |
1278 | if (ret != (ssize_t)sizeof(*id)) | 1336 | if (ret != (ssize_t)sizeof(*id)) |
1279 | goto error; | 1337 | goto error; |
1280 | if (ph->needs_swap) | 1338 | if (ph->needs_swap) |
@@ -1435,6 +1493,31 @@ error: | |||
1435 | fprintf(fp, "# pmu mappings: unable to read\n"); | 1493 | fprintf(fp, "# pmu mappings: unable to read\n"); |
1436 | } | 1494 | } |
1437 | 1495 | ||
1496 | static void print_group_desc(struct perf_header *ph, int fd __maybe_unused, | ||
1497 | FILE *fp) | ||
1498 | { | ||
1499 | struct perf_session *session; | ||
1500 | struct perf_evsel *evsel; | ||
1501 | u32 nr = 0; | ||
1502 | |||
1503 | session = container_of(ph, struct perf_session, header); | ||
1504 | |||
1505 | list_for_each_entry(evsel, &session->evlist->entries, node) { | ||
1506 | if (perf_evsel__is_group_leader(evsel) && | ||
1507 | evsel->nr_members > 1) { | ||
1508 | fprintf(fp, "# group: %s{%s", evsel->group_name ?: "", | ||
1509 | perf_evsel__name(evsel)); | ||
1510 | |||
1511 | nr = evsel->nr_members - 1; | ||
1512 | } else if (nr) { | ||
1513 | fprintf(fp, ",%s", perf_evsel__name(evsel)); | ||
1514 | |||
1515 | if (--nr == 0) | ||
1516 | fprintf(fp, "}\n"); | ||
1517 | } | ||
1518 | } | ||
1519 | } | ||
1520 | |||
1438 | static int __event_process_build_id(struct build_id_event *bev, | 1521 | static int __event_process_build_id(struct build_id_event *bev, |
1439 | char *filename, | 1522 | char *filename, |
1440 | struct perf_session *session) | 1523 | struct perf_session *session) |
@@ -1506,14 +1589,14 @@ static int perf_header__read_build_ids_abi_quirk(struct perf_header *header, | |||
1506 | while (offset < limit) { | 1589 | while (offset < limit) { |
1507 | ssize_t len; | 1590 | ssize_t len; |
1508 | 1591 | ||
1509 | if (read(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev)) | 1592 | if (readn(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev)) |
1510 | return -1; | 1593 | return -1; |
1511 | 1594 | ||
1512 | if (header->needs_swap) | 1595 | if (header->needs_swap) |
1513 | perf_event_header__bswap(&old_bev.header); | 1596 | perf_event_header__bswap(&old_bev.header); |
1514 | 1597 | ||
1515 | len = old_bev.header.size - sizeof(old_bev); | 1598 | len = old_bev.header.size - sizeof(old_bev); |
1516 | if (read(input, filename, len) != len) | 1599 | if (readn(input, filename, len) != len) |
1517 | return -1; | 1600 | return -1; |
1518 | 1601 | ||
1519 | bev.header = old_bev.header; | 1602 | bev.header = old_bev.header; |
@@ -1548,14 +1631,14 @@ static int perf_header__read_build_ids(struct perf_header *header, | |||
1548 | while (offset < limit) { | 1631 | while (offset < limit) { |
1549 | ssize_t len; | 1632 | ssize_t len; |
1550 | 1633 | ||
1551 | if (read(input, &bev, sizeof(bev)) != sizeof(bev)) | 1634 | if (readn(input, &bev, sizeof(bev)) != sizeof(bev)) |
1552 | goto out; | 1635 | goto out; |
1553 | 1636 | ||
1554 | if (header->needs_swap) | 1637 | if (header->needs_swap) |
1555 | perf_event_header__bswap(&bev.header); | 1638 | perf_event_header__bswap(&bev.header); |
1556 | 1639 | ||
1557 | len = bev.header.size - sizeof(bev); | 1640 | len = bev.header.size - sizeof(bev); |
1558 | if (read(input, filename, len) != len) | 1641 | if (readn(input, filename, len) != len) |
1559 | goto out; | 1642 | goto out; |
1560 | /* | 1643 | /* |
1561 | * The a1645ce1 changeset: | 1644 | * The a1645ce1 changeset: |
@@ -1641,7 +1724,7 @@ static int process_nrcpus(struct perf_file_section *section __maybe_unused, | |||
1641 | size_t ret; | 1724 | size_t ret; |
1642 | u32 nr; | 1725 | u32 nr; |
1643 | 1726 | ||
1644 | ret = read(fd, &nr, sizeof(nr)); | 1727 | ret = readn(fd, &nr, sizeof(nr)); |
1645 | if (ret != sizeof(nr)) | 1728 | if (ret != sizeof(nr)) |
1646 | return -1; | 1729 | return -1; |
1647 | 1730 | ||
@@ -1650,7 +1733,7 @@ static int process_nrcpus(struct perf_file_section *section __maybe_unused, | |||
1650 | 1733 | ||
1651 | ph->env.nr_cpus_online = nr; | 1734 | ph->env.nr_cpus_online = nr; |
1652 | 1735 | ||
1653 | ret = read(fd, &nr, sizeof(nr)); | 1736 | ret = readn(fd, &nr, sizeof(nr)); |
1654 | if (ret != sizeof(nr)) | 1737 | if (ret != sizeof(nr)) |
1655 | return -1; | 1738 | return -1; |
1656 | 1739 | ||
@@ -1684,7 +1767,7 @@ static int process_total_mem(struct perf_file_section *section __maybe_unused, | |||
1684 | uint64_t mem; | 1767 | uint64_t mem; |
1685 | size_t ret; | 1768 | size_t ret; |
1686 | 1769 | ||
1687 | ret = read(fd, &mem, sizeof(mem)); | 1770 | ret = readn(fd, &mem, sizeof(mem)); |
1688 | if (ret != sizeof(mem)) | 1771 | if (ret != sizeof(mem)) |
1689 | return -1; | 1772 | return -1; |
1690 | 1773 | ||
@@ -1756,7 +1839,7 @@ static int process_cmdline(struct perf_file_section *section __maybe_unused, | |||
1756 | u32 nr, i; | 1839 | u32 nr, i; |
1757 | struct strbuf sb; | 1840 | struct strbuf sb; |
1758 | 1841 | ||
1759 | ret = read(fd, &nr, sizeof(nr)); | 1842 | ret = readn(fd, &nr, sizeof(nr)); |
1760 | if (ret != sizeof(nr)) | 1843 | if (ret != sizeof(nr)) |
1761 | return -1; | 1844 | return -1; |
1762 | 1845 | ||
@@ -1792,7 +1875,7 @@ static int process_cpu_topology(struct perf_file_section *section __maybe_unused | |||
1792 | char *str; | 1875 | char *str; |
1793 | struct strbuf sb; | 1876 | struct strbuf sb; |
1794 | 1877 | ||
1795 | ret = read(fd, &nr, sizeof(nr)); | 1878 | ret = readn(fd, &nr, sizeof(nr)); |
1796 | if (ret != sizeof(nr)) | 1879 | if (ret != sizeof(nr)) |
1797 | return -1; | 1880 | return -1; |
1798 | 1881 | ||
@@ -1813,7 +1896,7 @@ static int process_cpu_topology(struct perf_file_section *section __maybe_unused | |||
1813 | } | 1896 | } |
1814 | ph->env.sibling_cores = strbuf_detach(&sb, NULL); | 1897 | ph->env.sibling_cores = strbuf_detach(&sb, NULL); |
1815 | 1898 | ||
1816 | ret = read(fd, &nr, sizeof(nr)); | 1899 | ret = readn(fd, &nr, sizeof(nr)); |
1817 | if (ret != sizeof(nr)) | 1900 | if (ret != sizeof(nr)) |
1818 | return -1; | 1901 | return -1; |
1819 | 1902 | ||
@@ -1850,7 +1933,7 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse | |||
1850 | struct strbuf sb; | 1933 | struct strbuf sb; |
1851 | 1934 | ||
1852 | /* nr nodes */ | 1935 | /* nr nodes */ |
1853 | ret = read(fd, &nr, sizeof(nr)); | 1936 | ret = readn(fd, &nr, sizeof(nr)); |
1854 | if (ret != sizeof(nr)) | 1937 | if (ret != sizeof(nr)) |
1855 | goto error; | 1938 | goto error; |
1856 | 1939 | ||
@@ -1862,15 +1945,15 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse | |||
1862 | 1945 | ||
1863 | for (i = 0; i < nr; i++) { | 1946 | for (i = 0; i < nr; i++) { |
1864 | /* node number */ | 1947 | /* node number */ |
1865 | ret = read(fd, &node, sizeof(node)); | 1948 | ret = readn(fd, &node, sizeof(node)); |
1866 | if (ret != sizeof(node)) | 1949 | if (ret != sizeof(node)) |
1867 | goto error; | 1950 | goto error; |
1868 | 1951 | ||
1869 | ret = read(fd, &mem_total, sizeof(u64)); | 1952 | ret = readn(fd, &mem_total, sizeof(u64)); |
1870 | if (ret != sizeof(u64)) | 1953 | if (ret != sizeof(u64)) |
1871 | goto error; | 1954 | goto error; |
1872 | 1955 | ||
1873 | ret = read(fd, &mem_free, sizeof(u64)); | 1956 | ret = readn(fd, &mem_free, sizeof(u64)); |
1874 | if (ret != sizeof(u64)) | 1957 | if (ret != sizeof(u64)) |
1875 | goto error; | 1958 | goto error; |
1876 | 1959 | ||
@@ -1909,7 +1992,7 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused | |||
1909 | u32 type; | 1992 | u32 type; |
1910 | struct strbuf sb; | 1993 | struct strbuf sb; |
1911 | 1994 | ||
1912 | ret = read(fd, &pmu_num, sizeof(pmu_num)); | 1995 | ret = readn(fd, &pmu_num, sizeof(pmu_num)); |
1913 | if (ret != sizeof(pmu_num)) | 1996 | if (ret != sizeof(pmu_num)) |
1914 | return -1; | 1997 | return -1; |
1915 | 1998 | ||
@@ -1925,7 +2008,7 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused | |||
1925 | strbuf_init(&sb, 128); | 2008 | strbuf_init(&sb, 128); |
1926 | 2009 | ||
1927 | while (pmu_num) { | 2010 | while (pmu_num) { |
1928 | if (read(fd, &type, sizeof(type)) != sizeof(type)) | 2011 | if (readn(fd, &type, sizeof(type)) != sizeof(type)) |
1929 | goto error; | 2012 | goto error; |
1930 | if (ph->needs_swap) | 2013 | if (ph->needs_swap) |
1931 | type = bswap_32(type); | 2014 | type = bswap_32(type); |
@@ -1949,6 +2032,98 @@ error: | |||
1949 | return -1; | 2032 | return -1; |
1950 | } | 2033 | } |
1951 | 2034 | ||
2035 | static int process_group_desc(struct perf_file_section *section __maybe_unused, | ||
2036 | struct perf_header *ph, int fd, | ||
2037 | void *data __maybe_unused) | ||
2038 | { | ||
2039 | size_t ret = -1; | ||
2040 | u32 i, nr, nr_groups; | ||
2041 | struct perf_session *session; | ||
2042 | struct perf_evsel *evsel, *leader = NULL; | ||
2043 | struct group_desc { | ||
2044 | char *name; | ||
2045 | u32 leader_idx; | ||
2046 | u32 nr_members; | ||
2047 | } *desc; | ||
2048 | |||
2049 | if (readn(fd, &nr_groups, sizeof(nr_groups)) != sizeof(nr_groups)) | ||
2050 | return -1; | ||
2051 | |||
2052 | if (ph->needs_swap) | ||
2053 | nr_groups = bswap_32(nr_groups); | ||
2054 | |||
2055 | ph->env.nr_groups = nr_groups; | ||
2056 | if (!nr_groups) { | ||
2057 | pr_debug("group desc not available\n"); | ||
2058 | return 0; | ||
2059 | } | ||
2060 | |||
2061 | desc = calloc(nr_groups, sizeof(*desc)); | ||
2062 | if (!desc) | ||
2063 | return -1; | ||
2064 | |||
2065 | for (i = 0; i < nr_groups; i++) { | ||
2066 | desc[i].name = do_read_string(fd, ph); | ||
2067 | if (!desc[i].name) | ||
2068 | goto out_free; | ||
2069 | |||
2070 | if (readn(fd, &desc[i].leader_idx, sizeof(u32)) != sizeof(u32)) | ||
2071 | goto out_free; | ||
2072 | |||
2073 | if (readn(fd, &desc[i].nr_members, sizeof(u32)) != sizeof(u32)) | ||
2074 | goto out_free; | ||
2075 | |||
2076 | if (ph->needs_swap) { | ||
2077 | desc[i].leader_idx = bswap_32(desc[i].leader_idx); | ||
2078 | desc[i].nr_members = bswap_32(desc[i].nr_members); | ||
2079 | } | ||
2080 | } | ||
2081 | |||
2082 | /* | ||
2083 | * Rebuild group relationship based on the group_desc | ||
2084 | */ | ||
2085 | session = container_of(ph, struct perf_session, header); | ||
2086 | session->evlist->nr_groups = nr_groups; | ||
2087 | |||
2088 | i = nr = 0; | ||
2089 | list_for_each_entry(evsel, &session->evlist->entries, node) { | ||
2090 | if (evsel->idx == (int) desc[i].leader_idx) { | ||
2091 | evsel->leader = evsel; | ||
2092 | /* {anon_group} is a dummy name */ | ||
2093 | if (strcmp(desc[i].name, "{anon_group}")) | ||
2094 | evsel->group_name = desc[i].name; | ||
2095 | evsel->nr_members = desc[i].nr_members; | ||
2096 | |||
2097 | if (i >= nr_groups || nr > 0) { | ||
2098 | pr_debug("invalid group desc\n"); | ||
2099 | goto out_free; | ||
2100 | } | ||
2101 | |||
2102 | leader = evsel; | ||
2103 | nr = evsel->nr_members - 1; | ||
2104 | i++; | ||
2105 | } else if (nr) { | ||
2106 | /* This is a group member */ | ||
2107 | evsel->leader = leader; | ||
2108 | |||
2109 | nr--; | ||
2110 | } | ||
2111 | } | ||
2112 | |||
2113 | if (i != nr_groups || nr != 0) { | ||
2114 | pr_debug("invalid group desc\n"); | ||
2115 | goto out_free; | ||
2116 | } | ||
2117 | |||
2118 | ret = 0; | ||
2119 | out_free: | ||
2120 | while ((int) --i >= 0) | ||
2121 | free(desc[i].name); | ||
2122 | free(desc); | ||
2123 | |||
2124 | return ret; | ||
2125 | } | ||
2126 | |||
1952 | struct feature_ops { | 2127 | struct feature_ops { |
1953 | int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist); | 2128 | int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist); |
1954 | void (*print)(struct perf_header *h, int fd, FILE *fp); | 2129 | void (*print)(struct perf_header *h, int fd, FILE *fp); |
@@ -1988,6 +2163,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = { | |||
1988 | FEAT_OPF(HEADER_NUMA_TOPOLOGY, numa_topology), | 2163 | FEAT_OPF(HEADER_NUMA_TOPOLOGY, numa_topology), |
1989 | FEAT_OPA(HEADER_BRANCH_STACK, branch_stack), | 2164 | FEAT_OPA(HEADER_BRANCH_STACK, branch_stack), |
1990 | FEAT_OPP(HEADER_PMU_MAPPINGS, pmu_mappings), | 2165 | FEAT_OPP(HEADER_PMU_MAPPINGS, pmu_mappings), |
2166 | FEAT_OPP(HEADER_GROUP_DESC, group_desc), | ||
1991 | }; | 2167 | }; |
1992 | 2168 | ||
1993 | struct header_print_data { | 2169 | struct header_print_data { |
@@ -2077,7 +2253,7 @@ static int perf_header__adds_write(struct perf_header *header, | |||
2077 | if (!nr_sections) | 2253 | if (!nr_sections) |
2078 | return 0; | 2254 | return 0; |
2079 | 2255 | ||
2080 | feat_sec = p = calloc(sizeof(*feat_sec), nr_sections); | 2256 | feat_sec = p = calloc(nr_sections, sizeof(*feat_sec)); |
2081 | if (feat_sec == NULL) | 2257 | if (feat_sec == NULL) |
2082 | return -ENOMEM; | 2258 | return -ENOMEM; |
2083 | 2259 | ||
@@ -2249,7 +2425,7 @@ int perf_header__process_sections(struct perf_header *header, int fd, | |||
2249 | if (!nr_sections) | 2425 | if (!nr_sections) |
2250 | return 0; | 2426 | return 0; |
2251 | 2427 | ||
2252 | feat_sec = sec = calloc(sizeof(*feat_sec), nr_sections); | 2428 | feat_sec = sec = calloc(nr_sections, sizeof(*feat_sec)); |
2253 | if (!feat_sec) | 2429 | if (!feat_sec) |
2254 | return -1; | 2430 | return -1; |
2255 | 2431 | ||
@@ -2912,16 +3088,22 @@ int perf_event__process_tracing_data(union perf_event *event, | |||
2912 | session->repipe); | 3088 | session->repipe); |
2913 | padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read; | 3089 | padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read; |
2914 | 3090 | ||
2915 | if (read(session->fd, buf, padding) < 0) | 3091 | if (readn(session->fd, buf, padding) < 0) { |
2916 | die("reading input file"); | 3092 | pr_err("%s: reading input file", __func__); |
3093 | return -1; | ||
3094 | } | ||
2917 | if (session->repipe) { | 3095 | if (session->repipe) { |
2918 | int retw = write(STDOUT_FILENO, buf, padding); | 3096 | int retw = write(STDOUT_FILENO, buf, padding); |
2919 | if (retw <= 0 || retw != padding) | 3097 | if (retw <= 0 || retw != padding) { |
2920 | die("repiping tracing data padding"); | 3098 | pr_err("%s: repiping tracing data padding", __func__); |
3099 | return -1; | ||
3100 | } | ||
2921 | } | 3101 | } |
2922 | 3102 | ||
2923 | if (size_read + padding != size) | 3103 | if (size_read + padding != size) { |
2924 | die("tracing data size mismatch"); | 3104 | pr_err("%s: tracing data size mismatch", __func__); |
3105 | return -1; | ||
3106 | } | ||
2925 | 3107 | ||
2926 | perf_evlist__prepare_tracepoint_events(session->evlist, | 3108 | perf_evlist__prepare_tracepoint_events(session->evlist, |
2927 | session->pevent); | 3109 | session->pevent); |
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 20f0344accb1..c9fc55cada6d 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h | |||
@@ -29,6 +29,7 @@ enum { | |||
29 | HEADER_NUMA_TOPOLOGY, | 29 | HEADER_NUMA_TOPOLOGY, |
30 | HEADER_BRANCH_STACK, | 30 | HEADER_BRANCH_STACK, |
31 | HEADER_PMU_MAPPINGS, | 31 | HEADER_PMU_MAPPINGS, |
32 | HEADER_GROUP_DESC, | ||
32 | HEADER_LAST_FEATURE, | 33 | HEADER_LAST_FEATURE, |
33 | HEADER_FEAT_BITS = 256, | 34 | HEADER_FEAT_BITS = 256, |
34 | }; | 35 | }; |
@@ -79,6 +80,7 @@ struct perf_session_env { | |||
79 | char *numa_nodes; | 80 | char *numa_nodes; |
80 | int nr_pmu_mappings; | 81 | int nr_pmu_mappings; |
81 | char *pmu_mappings; | 82 | char *pmu_mappings; |
83 | int nr_groups; | ||
82 | }; | 84 | }; |
83 | 85 | ||
84 | struct perf_header { | 86 | struct perf_header { |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index cb17e2a8c6ed..f855941bebea 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -4,6 +4,7 @@ | |||
4 | #include "hist.h" | 4 | #include "hist.h" |
5 | #include "session.h" | 5 | #include "session.h" |
6 | #include "sort.h" | 6 | #include "sort.h" |
7 | #include "evsel.h" | ||
7 | #include <math.h> | 8 | #include <math.h> |
8 | 9 | ||
9 | static bool hists__filter_entry_by_dso(struct hists *hists, | 10 | static bool hists__filter_entry_by_dso(struct hists *hists, |
@@ -82,6 +83,9 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) | |||
82 | hists__new_col_len(hists, HISTC_DSO, len); | 83 | hists__new_col_len(hists, HISTC_DSO, len); |
83 | } | 84 | } |
84 | 85 | ||
86 | if (h->parent) | ||
87 | hists__new_col_len(hists, HISTC_PARENT, h->parent->namelen); | ||
88 | |||
85 | if (h->branch_info) { | 89 | if (h->branch_info) { |
86 | int symlen; | 90 | int symlen; |
87 | /* | 91 | /* |
@@ -242,6 +246,14 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template) | |||
242 | 246 | ||
243 | if (he->ms.map) | 247 | if (he->ms.map) |
244 | he->ms.map->referenced = true; | 248 | he->ms.map->referenced = true; |
249 | |||
250 | if (he->branch_info) { | ||
251 | if (he->branch_info->from.map) | ||
252 | he->branch_info->from.map->referenced = true; | ||
253 | if (he->branch_info->to.map) | ||
254 | he->branch_info->to.map->referenced = true; | ||
255 | } | ||
256 | |||
245 | if (symbol_conf.use_callchain) | 257 | if (symbol_conf.use_callchain) |
246 | callchain_init(he->callchain); | 258 | callchain_init(he->callchain); |
247 | 259 | ||
@@ -251,7 +263,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template) | |||
251 | return he; | 263 | return he; |
252 | } | 264 | } |
253 | 265 | ||
254 | static void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h) | 266 | void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h) |
255 | { | 267 | { |
256 | if (!h->filtered) { | 268 | if (!h->filtered) { |
257 | hists__calc_col_len(hists, h); | 269 | hists__calc_col_len(hists, h); |
@@ -285,7 +297,13 @@ static struct hist_entry *add_hist_entry(struct hists *hists, | |||
285 | parent = *p; | 297 | parent = *p; |
286 | he = rb_entry(parent, struct hist_entry, rb_node_in); | 298 | he = rb_entry(parent, struct hist_entry, rb_node_in); |
287 | 299 | ||
288 | cmp = hist_entry__cmp(entry, he); | 300 | /* |
301 | * Make sure that it receives arguments in a same order as | ||
302 | * hist_entry__collapse() so that we can use an appropriate | ||
303 | * function when searching an entry regardless which sort | ||
304 | * keys were used. | ||
305 | */ | ||
306 | cmp = hist_entry__cmp(he, entry); | ||
289 | 307 | ||
290 | if (!cmp) { | 308 | if (!cmp) { |
291 | he_stat__add_period(&he->stat, period); | 309 | he_stat__add_period(&he->stat, period); |
@@ -523,6 +541,62 @@ void hists__collapse_resort_threaded(struct hists *hists) | |||
523 | * reverse the map, sort on period. | 541 | * reverse the map, sort on period. |
524 | */ | 542 | */ |
525 | 543 | ||
544 | static int period_cmp(u64 period_a, u64 period_b) | ||
545 | { | ||
546 | if (period_a > period_b) | ||
547 | return 1; | ||
548 | if (period_a < period_b) | ||
549 | return -1; | ||
550 | return 0; | ||
551 | } | ||
552 | |||
553 | static int hist_entry__sort_on_period(struct hist_entry *a, | ||
554 | struct hist_entry *b) | ||
555 | { | ||
556 | int ret; | ||
557 | int i, nr_members; | ||
558 | struct perf_evsel *evsel; | ||
559 | struct hist_entry *pair; | ||
560 | u64 *periods_a, *periods_b; | ||
561 | |||
562 | ret = period_cmp(a->stat.period, b->stat.period); | ||
563 | if (ret || !symbol_conf.event_group) | ||
564 | return ret; | ||
565 | |||
566 | evsel = hists_to_evsel(a->hists); | ||
567 | nr_members = evsel->nr_members; | ||
568 | if (nr_members <= 1) | ||
569 | return ret; | ||
570 | |||
571 | periods_a = zalloc(sizeof(periods_a) * nr_members); | ||
572 | periods_b = zalloc(sizeof(periods_b) * nr_members); | ||
573 | |||
574 | if (!periods_a || !periods_b) | ||
575 | goto out; | ||
576 | |||
577 | list_for_each_entry(pair, &a->pairs.head, pairs.node) { | ||
578 | evsel = hists_to_evsel(pair->hists); | ||
579 | periods_a[perf_evsel__group_idx(evsel)] = pair->stat.period; | ||
580 | } | ||
581 | |||
582 | list_for_each_entry(pair, &b->pairs.head, pairs.node) { | ||
583 | evsel = hists_to_evsel(pair->hists); | ||
584 | periods_b[perf_evsel__group_idx(evsel)] = pair->stat.period; | ||
585 | } | ||
586 | |||
587 | for (i = 1; i < nr_members; i++) { | ||
588 | ret = period_cmp(periods_a[i], periods_b[i]); | ||
589 | if (ret) | ||
590 | break; | ||
591 | } | ||
592 | |||
593 | out: | ||
594 | free(periods_a); | ||
595 | free(periods_b); | ||
596 | |||
597 | return ret; | ||
598 | } | ||
599 | |||
526 | static void __hists__insert_output_entry(struct rb_root *entries, | 600 | static void __hists__insert_output_entry(struct rb_root *entries, |
527 | struct hist_entry *he, | 601 | struct hist_entry *he, |
528 | u64 min_callchain_hits) | 602 | u64 min_callchain_hits) |
@@ -539,7 +613,7 @@ static void __hists__insert_output_entry(struct rb_root *entries, | |||
539 | parent = *p; | 613 | parent = *p; |
540 | iter = rb_entry(parent, struct hist_entry, rb_node); | 614 | iter = rb_entry(parent, struct hist_entry, rb_node); |
541 | 615 | ||
542 | if (he->stat.period > iter->stat.period) | 616 | if (hist_entry__sort_on_period(he, iter) > 0) |
543 | p = &(*p)->rb_left; | 617 | p = &(*p)->rb_left; |
544 | else | 618 | else |
545 | p = &(*p)->rb_right; | 619 | p = &(*p)->rb_right; |
@@ -711,25 +785,38 @@ int hist_entry__annotate(struct hist_entry *he, size_t privsize) | |||
711 | return symbol__annotate(he->ms.sym, he->ms.map, privsize); | 785 | return symbol__annotate(he->ms.sym, he->ms.map, privsize); |
712 | } | 786 | } |
713 | 787 | ||
788 | void events_stats__inc(struct events_stats *stats, u32 type) | ||
789 | { | ||
790 | ++stats->nr_events[0]; | ||
791 | ++stats->nr_events[type]; | ||
792 | } | ||
793 | |||
714 | void hists__inc_nr_events(struct hists *hists, u32 type) | 794 | void hists__inc_nr_events(struct hists *hists, u32 type) |
715 | { | 795 | { |
716 | ++hists->stats.nr_events[0]; | 796 | events_stats__inc(&hists->stats, type); |
717 | ++hists->stats.nr_events[type]; | ||
718 | } | 797 | } |
719 | 798 | ||
720 | static struct hist_entry *hists__add_dummy_entry(struct hists *hists, | 799 | static struct hist_entry *hists__add_dummy_entry(struct hists *hists, |
721 | struct hist_entry *pair) | 800 | struct hist_entry *pair) |
722 | { | 801 | { |
723 | struct rb_node **p = &hists->entries.rb_node; | 802 | struct rb_root *root; |
803 | struct rb_node **p; | ||
724 | struct rb_node *parent = NULL; | 804 | struct rb_node *parent = NULL; |
725 | struct hist_entry *he; | 805 | struct hist_entry *he; |
726 | int cmp; | 806 | int cmp; |
727 | 807 | ||
808 | if (sort__need_collapse) | ||
809 | root = &hists->entries_collapsed; | ||
810 | else | ||
811 | root = hists->entries_in; | ||
812 | |||
813 | p = &root->rb_node; | ||
814 | |||
728 | while (*p != NULL) { | 815 | while (*p != NULL) { |
729 | parent = *p; | 816 | parent = *p; |
730 | he = rb_entry(parent, struct hist_entry, rb_node); | 817 | he = rb_entry(parent, struct hist_entry, rb_node_in); |
731 | 818 | ||
732 | cmp = hist_entry__cmp(pair, he); | 819 | cmp = hist_entry__collapse(he, pair); |
733 | 820 | ||
734 | if (!cmp) | 821 | if (!cmp) |
735 | goto out; | 822 | goto out; |
@@ -744,8 +831,8 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists, | |||
744 | if (he) { | 831 | if (he) { |
745 | memset(&he->stat, 0, sizeof(he->stat)); | 832 | memset(&he->stat, 0, sizeof(he->stat)); |
746 | he->hists = hists; | 833 | he->hists = hists; |
747 | rb_link_node(&he->rb_node, parent, p); | 834 | rb_link_node(&he->rb_node_in, parent, p); |
748 | rb_insert_color(&he->rb_node, &hists->entries); | 835 | rb_insert_color(&he->rb_node_in, root); |
749 | hists__inc_nr_entries(hists, he); | 836 | hists__inc_nr_entries(hists, he); |
750 | } | 837 | } |
751 | out: | 838 | out: |
@@ -755,11 +842,16 @@ out: | |||
755 | static struct hist_entry *hists__find_entry(struct hists *hists, | 842 | static struct hist_entry *hists__find_entry(struct hists *hists, |
756 | struct hist_entry *he) | 843 | struct hist_entry *he) |
757 | { | 844 | { |
758 | struct rb_node *n = hists->entries.rb_node; | 845 | struct rb_node *n; |
846 | |||
847 | if (sort__need_collapse) | ||
848 | n = hists->entries_collapsed.rb_node; | ||
849 | else | ||
850 | n = hists->entries_in->rb_node; | ||
759 | 851 | ||
760 | while (n) { | 852 | while (n) { |
761 | struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node); | 853 | struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node_in); |
762 | int64_t cmp = hist_entry__cmp(he, iter); | 854 | int64_t cmp = hist_entry__collapse(iter, he); |
763 | 855 | ||
764 | if (cmp < 0) | 856 | if (cmp < 0) |
765 | n = n->rb_left; | 857 | n = n->rb_left; |
@@ -777,15 +869,21 @@ static struct hist_entry *hists__find_entry(struct hists *hists, | |||
777 | */ | 869 | */ |
778 | void hists__match(struct hists *leader, struct hists *other) | 870 | void hists__match(struct hists *leader, struct hists *other) |
779 | { | 871 | { |
872 | struct rb_root *root; | ||
780 | struct rb_node *nd; | 873 | struct rb_node *nd; |
781 | struct hist_entry *pos, *pair; | 874 | struct hist_entry *pos, *pair; |
782 | 875 | ||
783 | for (nd = rb_first(&leader->entries); nd; nd = rb_next(nd)) { | 876 | if (sort__need_collapse) |
784 | pos = rb_entry(nd, struct hist_entry, rb_node); | 877 | root = &leader->entries_collapsed; |
878 | else | ||
879 | root = leader->entries_in; | ||
880 | |||
881 | for (nd = rb_first(root); nd; nd = rb_next(nd)) { | ||
882 | pos = rb_entry(nd, struct hist_entry, rb_node_in); | ||
785 | pair = hists__find_entry(other, pos); | 883 | pair = hists__find_entry(other, pos); |
786 | 884 | ||
787 | if (pair) | 885 | if (pair) |
788 | hist__entry_add_pair(pos, pair); | 886 | hist_entry__add_pair(pair, pos); |
789 | } | 887 | } |
790 | } | 888 | } |
791 | 889 | ||
@@ -796,17 +894,23 @@ void hists__match(struct hists *leader, struct hists *other) | |||
796 | */ | 894 | */ |
797 | int hists__link(struct hists *leader, struct hists *other) | 895 | int hists__link(struct hists *leader, struct hists *other) |
798 | { | 896 | { |
897 | struct rb_root *root; | ||
799 | struct rb_node *nd; | 898 | struct rb_node *nd; |
800 | struct hist_entry *pos, *pair; | 899 | struct hist_entry *pos, *pair; |
801 | 900 | ||
802 | for (nd = rb_first(&other->entries); nd; nd = rb_next(nd)) { | 901 | if (sort__need_collapse) |
803 | pos = rb_entry(nd, struct hist_entry, rb_node); | 902 | root = &other->entries_collapsed; |
903 | else | ||
904 | root = other->entries_in; | ||
905 | |||
906 | for (nd = rb_first(root); nd; nd = rb_next(nd)) { | ||
907 | pos = rb_entry(nd, struct hist_entry, rb_node_in); | ||
804 | 908 | ||
805 | if (!hist_entry__has_pairs(pos)) { | 909 | if (!hist_entry__has_pairs(pos)) { |
806 | pair = hists__add_dummy_entry(leader, pos); | 910 | pair = hists__add_dummy_entry(leader, pos); |
807 | if (pair == NULL) | 911 | if (pair == NULL) |
808 | return -1; | 912 | return -1; |
809 | hist__entry_add_pair(pair, pos); | 913 | hist_entry__add_pair(pos, pair); |
810 | } | 914 | } |
811 | } | 915 | } |
812 | 916 | ||
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 8b091a51e4a2..38624686ee9a 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -96,8 +96,10 @@ void hists__decay_entries_threaded(struct hists *hists, bool zap_user, | |||
96 | bool zap_kernel); | 96 | bool zap_kernel); |
97 | void hists__output_recalc_col_len(struct hists *hists, int max_rows); | 97 | void hists__output_recalc_col_len(struct hists *hists, int max_rows); |
98 | 98 | ||
99 | void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h); | ||
99 | void hists__inc_nr_events(struct hists *self, u32 type); | 100 | void hists__inc_nr_events(struct hists *self, u32 type); |
100 | size_t hists__fprintf_nr_events(struct hists *self, FILE *fp); | 101 | void events_stats__inc(struct events_stats *stats, u32 type); |
102 | size_t events_stats__fprintf(struct events_stats *stats, FILE *fp); | ||
101 | 103 | ||
102 | size_t hists__fprintf(struct hists *self, bool show_header, int max_rows, | 104 | size_t hists__fprintf(struct hists *self, bool show_header, int max_rows, |
103 | int max_cols, FILE *fp); | 105 | int max_cols, FILE *fp); |
@@ -126,13 +128,19 @@ struct perf_hpp { | |||
126 | }; | 128 | }; |
127 | 129 | ||
128 | struct perf_hpp_fmt { | 130 | struct perf_hpp_fmt { |
129 | bool cond; | ||
130 | int (*header)(struct perf_hpp *hpp); | 131 | int (*header)(struct perf_hpp *hpp); |
131 | int (*width)(struct perf_hpp *hpp); | 132 | int (*width)(struct perf_hpp *hpp); |
132 | int (*color)(struct perf_hpp *hpp, struct hist_entry *he); | 133 | int (*color)(struct perf_hpp *hpp, struct hist_entry *he); |
133 | int (*entry)(struct perf_hpp *hpp, struct hist_entry *he); | 134 | int (*entry)(struct perf_hpp *hpp, struct hist_entry *he); |
135 | |||
136 | struct list_head list; | ||
134 | }; | 137 | }; |
135 | 138 | ||
139 | extern struct list_head perf_hpp__list; | ||
140 | |||
141 | #define perf_hpp__for_each_format(format) \ | ||
142 | list_for_each_entry(format, &perf_hpp__list, list) | ||
143 | |||
136 | extern struct perf_hpp_fmt perf_hpp__format[]; | 144 | extern struct perf_hpp_fmt perf_hpp__format[]; |
137 | 145 | ||
138 | enum { | 146 | enum { |
@@ -148,14 +156,14 @@ enum { | |||
148 | PERF_HPP__DELTA, | 156 | PERF_HPP__DELTA, |
149 | PERF_HPP__RATIO, | 157 | PERF_HPP__RATIO, |
150 | PERF_HPP__WEIGHTED_DIFF, | 158 | PERF_HPP__WEIGHTED_DIFF, |
151 | PERF_HPP__DISPL, | ||
152 | PERF_HPP__FORMULA, | 159 | PERF_HPP__FORMULA, |
153 | 160 | ||
154 | PERF_HPP__MAX_INDEX | 161 | PERF_HPP__MAX_INDEX |
155 | }; | 162 | }; |
156 | 163 | ||
157 | void perf_hpp__init(void); | 164 | void perf_hpp__init(void); |
158 | void perf_hpp__column_enable(unsigned col, bool enable); | 165 | void perf_hpp__column_register(struct perf_hpp_fmt *format); |
166 | void perf_hpp__column_enable(unsigned col); | ||
159 | int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he, | 167 | int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he, |
160 | bool color); | 168 | bool color); |
161 | 169 | ||
@@ -219,8 +227,10 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused, | |||
219 | 227 | ||
220 | unsigned int hists__sort_list_width(struct hists *self); | 228 | unsigned int hists__sort_list_width(struct hists *self); |
221 | 229 | ||
222 | double perf_diff__compute_delta(struct hist_entry *he); | 230 | double perf_diff__compute_delta(struct hist_entry *he, struct hist_entry *pair); |
223 | double perf_diff__compute_ratio(struct hist_entry *he); | 231 | double perf_diff__compute_ratio(struct hist_entry *he, struct hist_entry *pair); |
224 | s64 perf_diff__compute_wdiff(struct hist_entry *he); | 232 | s64 perf_diff__compute_wdiff(struct hist_entry *he, struct hist_entry *pair); |
225 | int perf_diff__formula(char *buf, size_t size, struct hist_entry *he); | 233 | int perf_diff__formula(struct hist_entry *he, struct hist_entry *pair, |
234 | char *buf, size_t size); | ||
235 | double perf_diff__period_percent(struct hist_entry *he, u64 period); | ||
226 | #endif /* __PERF_HIST_H */ | 236 | #endif /* __PERF_HIST_H */ |
diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h index a55d8cf083c9..45cf10a562bd 100644 --- a/tools/perf/util/include/linux/bitops.h +++ b/tools/perf/util/include/linux/bitops.h | |||
@@ -14,6 +14,7 @@ | |||
14 | #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) | 14 | #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) |
15 | #define BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u64)) | 15 | #define BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u64)) |
16 | #define BITS_TO_U32(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u32)) | 16 | #define BITS_TO_U32(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u32)) |
17 | #define BITS_TO_BYTES(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE) | ||
17 | 18 | ||
18 | #define for_each_set_bit(bit, addr, size) \ | 19 | #define for_each_set_bit(bit, addr, size) \ |
19 | for ((bit) = find_first_bit((addr), (size)); \ | 20 | for ((bit) = find_first_bit((addr), (size)); \ |
diff --git a/tools/perf/util/intlist.c b/tools/perf/util/intlist.c index 9d0740024ba8..11a8d86f7fea 100644 --- a/tools/perf/util/intlist.c +++ b/tools/perf/util/intlist.c | |||
@@ -59,16 +59,40 @@ void intlist__remove(struct intlist *ilist, struct int_node *node) | |||
59 | 59 | ||
60 | struct int_node *intlist__find(struct intlist *ilist, int i) | 60 | struct int_node *intlist__find(struct intlist *ilist, int i) |
61 | { | 61 | { |
62 | struct int_node *node = NULL; | 62 | struct int_node *node; |
63 | struct rb_node *rb_node = rblist__find(&ilist->rblist, (void *)((long)i)); | 63 | struct rb_node *rb_node; |
64 | 64 | ||
65 | if (ilist == NULL) | ||
66 | return NULL; | ||
67 | |||
68 | node = NULL; | ||
69 | rb_node = rblist__find(&ilist->rblist, (void *)((long)i)); | ||
65 | if (rb_node) | 70 | if (rb_node) |
66 | node = container_of(rb_node, struct int_node, rb_node); | 71 | node = container_of(rb_node, struct int_node, rb_node); |
67 | 72 | ||
68 | return node; | 73 | return node; |
69 | } | 74 | } |
70 | 75 | ||
71 | struct intlist *intlist__new(void) | 76 | static int intlist__parse_list(struct intlist *ilist, const char *s) |
77 | { | ||
78 | char *sep; | ||
79 | int err; | ||
80 | |||
81 | do { | ||
82 | long value = strtol(s, &sep, 10); | ||
83 | err = -EINVAL; | ||
84 | if (*sep != ',' && *sep != '\0') | ||
85 | break; | ||
86 | err = intlist__add(ilist, value); | ||
87 | if (err) | ||
88 | break; | ||
89 | s = sep + 1; | ||
90 | } while (*sep != '\0'); | ||
91 | |||
92 | return err; | ||
93 | } | ||
94 | |||
95 | struct intlist *intlist__new(const char *slist) | ||
72 | { | 96 | { |
73 | struct intlist *ilist = malloc(sizeof(*ilist)); | 97 | struct intlist *ilist = malloc(sizeof(*ilist)); |
74 | 98 | ||
@@ -77,9 +101,15 @@ struct intlist *intlist__new(void) | |||
77 | ilist->rblist.node_cmp = intlist__node_cmp; | 101 | ilist->rblist.node_cmp = intlist__node_cmp; |
78 | ilist->rblist.node_new = intlist__node_new; | 102 | ilist->rblist.node_new = intlist__node_new; |
79 | ilist->rblist.node_delete = intlist__node_delete; | 103 | ilist->rblist.node_delete = intlist__node_delete; |
104 | |||
105 | if (slist && intlist__parse_list(ilist, slist)) | ||
106 | goto out_delete; | ||
80 | } | 107 | } |
81 | 108 | ||
82 | return ilist; | 109 | return ilist; |
110 | out_delete: | ||
111 | intlist__delete(ilist); | ||
112 | return NULL; | ||
83 | } | 113 | } |
84 | 114 | ||
85 | void intlist__delete(struct intlist *ilist) | 115 | void intlist__delete(struct intlist *ilist) |
diff --git a/tools/perf/util/intlist.h b/tools/perf/util/intlist.h index 6d63ab90db50..62351dad848f 100644 --- a/tools/perf/util/intlist.h +++ b/tools/perf/util/intlist.h | |||
@@ -15,7 +15,7 @@ struct intlist { | |||
15 | struct rblist rblist; | 15 | struct rblist rblist; |
16 | }; | 16 | }; |
17 | 17 | ||
18 | struct intlist *intlist__new(void); | 18 | struct intlist *intlist__new(const char *slist); |
19 | void intlist__delete(struct intlist *ilist); | 19 | void intlist__delete(struct intlist *ilist); |
20 | 20 | ||
21 | void intlist__remove(struct intlist *ilist, struct int_node *in); | 21 | void intlist__remove(struct intlist *ilist, struct int_node *in); |
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 1f09d0581e6b..efdb38e65a92 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
@@ -1,10 +1,15 @@ | |||
1 | #include "callchain.h" | ||
1 | #include "debug.h" | 2 | #include "debug.h" |
2 | #include "event.h" | 3 | #include "event.h" |
4 | #include "evsel.h" | ||
5 | #include "hist.h" | ||
3 | #include "machine.h" | 6 | #include "machine.h" |
4 | #include "map.h" | 7 | #include "map.h" |
8 | #include "sort.h" | ||
5 | #include "strlist.h" | 9 | #include "strlist.h" |
6 | #include "thread.h" | 10 | #include "thread.h" |
7 | #include <stdbool.h> | 11 | #include <stdbool.h> |
12 | #include "unwind.h" | ||
8 | 13 | ||
9 | int machine__init(struct machine *machine, const char *root_dir, pid_t pid) | 14 | int machine__init(struct machine *machine, const char *root_dir, pid_t pid) |
10 | { | 15 | { |
@@ -48,6 +53,29 @@ static void dsos__delete(struct list_head *dsos) | |||
48 | } | 53 | } |
49 | } | 54 | } |
50 | 55 | ||
56 | void machine__delete_dead_threads(struct machine *machine) | ||
57 | { | ||
58 | struct thread *n, *t; | ||
59 | |||
60 | list_for_each_entry_safe(t, n, &machine->dead_threads, node) { | ||
61 | list_del(&t->node); | ||
62 | thread__delete(t); | ||
63 | } | ||
64 | } | ||
65 | |||
66 | void machine__delete_threads(struct machine *machine) | ||
67 | { | ||
68 | struct rb_node *nd = rb_first(&machine->threads); | ||
69 | |||
70 | while (nd) { | ||
71 | struct thread *t = rb_entry(nd, struct thread, rb_node); | ||
72 | |||
73 | rb_erase(&t->rb_node, &machine->threads); | ||
74 | nd = rb_next(nd); | ||
75 | thread__delete(t); | ||
76 | } | ||
77 | } | ||
78 | |||
51 | void machine__exit(struct machine *machine) | 79 | void machine__exit(struct machine *machine) |
52 | { | 80 | { |
53 | map_groups__exit(&machine->kmaps); | 81 | map_groups__exit(&machine->kmaps); |
@@ -63,10 +91,22 @@ void machine__delete(struct machine *machine) | |||
63 | free(machine); | 91 | free(machine); |
64 | } | 92 | } |
65 | 93 | ||
66 | struct machine *machines__add(struct rb_root *machines, pid_t pid, | 94 | void machines__init(struct machines *machines) |
95 | { | ||
96 | machine__init(&machines->host, "", HOST_KERNEL_ID); | ||
97 | machines->guests = RB_ROOT; | ||
98 | } | ||
99 | |||
100 | void machines__exit(struct machines *machines) | ||
101 | { | ||
102 | machine__exit(&machines->host); | ||
103 | /* XXX exit guest */ | ||
104 | } | ||
105 | |||
106 | struct machine *machines__add(struct machines *machines, pid_t pid, | ||
67 | const char *root_dir) | 107 | const char *root_dir) |
68 | { | 108 | { |
69 | struct rb_node **p = &machines->rb_node; | 109 | struct rb_node **p = &machines->guests.rb_node; |
70 | struct rb_node *parent = NULL; | 110 | struct rb_node *parent = NULL; |
71 | struct machine *pos, *machine = malloc(sizeof(*machine)); | 111 | struct machine *pos, *machine = malloc(sizeof(*machine)); |
72 | 112 | ||
@@ -88,18 +128,21 @@ struct machine *machines__add(struct rb_root *machines, pid_t pid, | |||
88 | } | 128 | } |
89 | 129 | ||
90 | rb_link_node(&machine->rb_node, parent, p); | 130 | rb_link_node(&machine->rb_node, parent, p); |
91 | rb_insert_color(&machine->rb_node, machines); | 131 | rb_insert_color(&machine->rb_node, &machines->guests); |
92 | 132 | ||
93 | return machine; | 133 | return machine; |
94 | } | 134 | } |
95 | 135 | ||
96 | struct machine *machines__find(struct rb_root *machines, pid_t pid) | 136 | struct machine *machines__find(struct machines *machines, pid_t pid) |
97 | { | 137 | { |
98 | struct rb_node **p = &machines->rb_node; | 138 | struct rb_node **p = &machines->guests.rb_node; |
99 | struct rb_node *parent = NULL; | 139 | struct rb_node *parent = NULL; |
100 | struct machine *machine; | 140 | struct machine *machine; |
101 | struct machine *default_machine = NULL; | 141 | struct machine *default_machine = NULL; |
102 | 142 | ||
143 | if (pid == HOST_KERNEL_ID) | ||
144 | return &machines->host; | ||
145 | |||
103 | while (*p != NULL) { | 146 | while (*p != NULL) { |
104 | parent = *p; | 147 | parent = *p; |
105 | machine = rb_entry(parent, struct machine, rb_node); | 148 | machine = rb_entry(parent, struct machine, rb_node); |
@@ -116,7 +159,7 @@ struct machine *machines__find(struct rb_root *machines, pid_t pid) | |||
116 | return default_machine; | 159 | return default_machine; |
117 | } | 160 | } |
118 | 161 | ||
119 | struct machine *machines__findnew(struct rb_root *machines, pid_t pid) | 162 | struct machine *machines__findnew(struct machines *machines, pid_t pid) |
120 | { | 163 | { |
121 | char path[PATH_MAX]; | 164 | char path[PATH_MAX]; |
122 | const char *root_dir = ""; | 165 | const char *root_dir = ""; |
@@ -150,12 +193,12 @@ out: | |||
150 | return machine; | 193 | return machine; |
151 | } | 194 | } |
152 | 195 | ||
153 | void machines__process(struct rb_root *machines, | 196 | void machines__process_guests(struct machines *machines, |
154 | machine__process_t process, void *data) | 197 | machine__process_t process, void *data) |
155 | { | 198 | { |
156 | struct rb_node *nd; | 199 | struct rb_node *nd; |
157 | 200 | ||
158 | for (nd = rb_first(machines); nd; nd = rb_next(nd)) { | 201 | for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) { |
159 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | 202 | struct machine *pos = rb_entry(nd, struct machine, rb_node); |
160 | process(pos, data); | 203 | process(pos, data); |
161 | } | 204 | } |
@@ -175,12 +218,14 @@ char *machine__mmap_name(struct machine *machine, char *bf, size_t size) | |||
175 | return bf; | 218 | return bf; |
176 | } | 219 | } |
177 | 220 | ||
178 | void machines__set_id_hdr_size(struct rb_root *machines, u16 id_hdr_size) | 221 | void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size) |
179 | { | 222 | { |
180 | struct rb_node *node; | 223 | struct rb_node *node; |
181 | struct machine *machine; | 224 | struct machine *machine; |
182 | 225 | ||
183 | for (node = rb_first(machines); node; node = rb_next(node)) { | 226 | machines->host.id_hdr_size = id_hdr_size; |
227 | |||
228 | for (node = rb_first(&machines->guests); node; node = rb_next(node)) { | ||
184 | machine = rb_entry(node, struct machine, rb_node); | 229 | machine = rb_entry(node, struct machine, rb_node); |
185 | machine->id_hdr_size = id_hdr_size; | 230 | machine->id_hdr_size = id_hdr_size; |
186 | } | 231 | } |
@@ -264,6 +309,537 @@ int machine__process_lost_event(struct machine *machine __maybe_unused, | |||
264 | return 0; | 309 | return 0; |
265 | } | 310 | } |
266 | 311 | ||
312 | struct map *machine__new_module(struct machine *machine, u64 start, | ||
313 | const char *filename) | ||
314 | { | ||
315 | struct map *map; | ||
316 | struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename); | ||
317 | |||
318 | if (dso == NULL) | ||
319 | return NULL; | ||
320 | |||
321 | map = map__new2(start, dso, MAP__FUNCTION); | ||
322 | if (map == NULL) | ||
323 | return NULL; | ||
324 | |||
325 | if (machine__is_host(machine)) | ||
326 | dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE; | ||
327 | else | ||
328 | dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE; | ||
329 | map_groups__insert(&machine->kmaps, map); | ||
330 | return map; | ||
331 | } | ||
332 | |||
333 | size_t machines__fprintf_dsos(struct machines *machines, FILE *fp) | ||
334 | { | ||
335 | struct rb_node *nd; | ||
336 | size_t ret = __dsos__fprintf(&machines->host.kernel_dsos, fp) + | ||
337 | __dsos__fprintf(&machines->host.user_dsos, fp); | ||
338 | |||
339 | for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) { | ||
340 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | ||
341 | ret += __dsos__fprintf(&pos->kernel_dsos, fp); | ||
342 | ret += __dsos__fprintf(&pos->user_dsos, fp); | ||
343 | } | ||
344 | |||
345 | return ret; | ||
346 | } | ||
347 | |||
348 | size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, | ||
349 | bool (skip)(struct dso *dso, int parm), int parm) | ||
350 | { | ||
351 | return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, skip, parm) + | ||
352 | __dsos__fprintf_buildid(&machine->user_dsos, fp, skip, parm); | ||
353 | } | ||
354 | |||
355 | size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp, | ||
356 | bool (skip)(struct dso *dso, int parm), int parm) | ||
357 | { | ||
358 | struct rb_node *nd; | ||
359 | size_t ret = machine__fprintf_dsos_buildid(&machines->host, fp, skip, parm); | ||
360 | |||
361 | for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) { | ||
362 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | ||
363 | ret += machine__fprintf_dsos_buildid(pos, fp, skip, parm); | ||
364 | } | ||
365 | return ret; | ||
366 | } | ||
367 | |||
368 | size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp) | ||
369 | { | ||
370 | int i; | ||
371 | size_t printed = 0; | ||
372 | struct dso *kdso = machine->vmlinux_maps[MAP__FUNCTION]->dso; | ||
373 | |||
374 | if (kdso->has_build_id) { | ||
375 | char filename[PATH_MAX]; | ||
376 | if (dso__build_id_filename(kdso, filename, sizeof(filename))) | ||
377 | printed += fprintf(fp, "[0] %s\n", filename); | ||
378 | } | ||
379 | |||
380 | for (i = 0; i < vmlinux_path__nr_entries; ++i) | ||
381 | printed += fprintf(fp, "[%d] %s\n", | ||
382 | i + kdso->has_build_id, vmlinux_path[i]); | ||
383 | |||
384 | return printed; | ||
385 | } | ||
386 | |||
387 | size_t machine__fprintf(struct machine *machine, FILE *fp) | ||
388 | { | ||
389 | size_t ret = 0; | ||
390 | struct rb_node *nd; | ||
391 | |||
392 | for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) { | ||
393 | struct thread *pos = rb_entry(nd, struct thread, rb_node); | ||
394 | |||
395 | ret += thread__fprintf(pos, fp); | ||
396 | } | ||
397 | |||
398 | return ret; | ||
399 | } | ||
400 | |||
401 | static struct dso *machine__get_kernel(struct machine *machine) | ||
402 | { | ||
403 | const char *vmlinux_name = NULL; | ||
404 | struct dso *kernel; | ||
405 | |||
406 | if (machine__is_host(machine)) { | ||
407 | vmlinux_name = symbol_conf.vmlinux_name; | ||
408 | if (!vmlinux_name) | ||
409 | vmlinux_name = "[kernel.kallsyms]"; | ||
410 | |||
411 | kernel = dso__kernel_findnew(machine, vmlinux_name, | ||
412 | "[kernel]", | ||
413 | DSO_TYPE_KERNEL); | ||
414 | } else { | ||
415 | char bf[PATH_MAX]; | ||
416 | |||
417 | if (machine__is_default_guest(machine)) | ||
418 | vmlinux_name = symbol_conf.default_guest_vmlinux_name; | ||
419 | if (!vmlinux_name) | ||
420 | vmlinux_name = machine__mmap_name(machine, bf, | ||
421 | sizeof(bf)); | ||
422 | |||
423 | kernel = dso__kernel_findnew(machine, vmlinux_name, | ||
424 | "[guest.kernel]", | ||
425 | DSO_TYPE_GUEST_KERNEL); | ||
426 | } | ||
427 | |||
428 | if (kernel != NULL && (!kernel->has_build_id)) | ||
429 | dso__read_running_kernel_build_id(kernel, machine); | ||
430 | |||
431 | return kernel; | ||
432 | } | ||
433 | |||
434 | struct process_args { | ||
435 | u64 start; | ||
436 | }; | ||
437 | |||
438 | static int symbol__in_kernel(void *arg, const char *name, | ||
439 | char type __maybe_unused, u64 start) | ||
440 | { | ||
441 | struct process_args *args = arg; | ||
442 | |||
443 | if (strchr(name, '[')) | ||
444 | return 0; | ||
445 | |||
446 | args->start = start; | ||
447 | return 1; | ||
448 | } | ||
449 | |||
450 | /* Figure out the start address of kernel map from /proc/kallsyms */ | ||
451 | static u64 machine__get_kernel_start_addr(struct machine *machine) | ||
452 | { | ||
453 | const char *filename; | ||
454 | char path[PATH_MAX]; | ||
455 | struct process_args args; | ||
456 | |||
457 | if (machine__is_host(machine)) { | ||
458 | filename = "/proc/kallsyms"; | ||
459 | } else { | ||
460 | if (machine__is_default_guest(machine)) | ||
461 | filename = (char *)symbol_conf.default_guest_kallsyms; | ||
462 | else { | ||
463 | sprintf(path, "%s/proc/kallsyms", machine->root_dir); | ||
464 | filename = path; | ||
465 | } | ||
466 | } | ||
467 | |||
468 | if (symbol__restricted_filename(filename, "/proc/kallsyms")) | ||
469 | return 0; | ||
470 | |||
471 | if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0) | ||
472 | return 0; | ||
473 | |||
474 | return args.start; | ||
475 | } | ||
476 | |||
477 | int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel) | ||
478 | { | ||
479 | enum map_type type; | ||
480 | u64 start = machine__get_kernel_start_addr(machine); | ||
481 | |||
482 | for (type = 0; type < MAP__NR_TYPES; ++type) { | ||
483 | struct kmap *kmap; | ||
484 | |||
485 | machine->vmlinux_maps[type] = map__new2(start, kernel, type); | ||
486 | if (machine->vmlinux_maps[type] == NULL) | ||
487 | return -1; | ||
488 | |||
489 | machine->vmlinux_maps[type]->map_ip = | ||
490 | machine->vmlinux_maps[type]->unmap_ip = | ||
491 | identity__map_ip; | ||
492 | kmap = map__kmap(machine->vmlinux_maps[type]); | ||
493 | kmap->kmaps = &machine->kmaps; | ||
494 | map_groups__insert(&machine->kmaps, | ||
495 | machine->vmlinux_maps[type]); | ||
496 | } | ||
497 | |||
498 | return 0; | ||
499 | } | ||
500 | |||
501 | void machine__destroy_kernel_maps(struct machine *machine) | ||
502 | { | ||
503 | enum map_type type; | ||
504 | |||
505 | for (type = 0; type < MAP__NR_TYPES; ++type) { | ||
506 | struct kmap *kmap; | ||
507 | |||
508 | if (machine->vmlinux_maps[type] == NULL) | ||
509 | continue; | ||
510 | |||
511 | kmap = map__kmap(machine->vmlinux_maps[type]); | ||
512 | map_groups__remove(&machine->kmaps, | ||
513 | machine->vmlinux_maps[type]); | ||
514 | if (kmap->ref_reloc_sym) { | ||
515 | /* | ||
516 | * ref_reloc_sym is shared among all maps, so free just | ||
517 | * on one of them. | ||
518 | */ | ||
519 | if (type == MAP__FUNCTION) { | ||
520 | free((char *)kmap->ref_reloc_sym->name); | ||
521 | kmap->ref_reloc_sym->name = NULL; | ||
522 | free(kmap->ref_reloc_sym); | ||
523 | } | ||
524 | kmap->ref_reloc_sym = NULL; | ||
525 | } | ||
526 | |||
527 | map__delete(machine->vmlinux_maps[type]); | ||
528 | machine->vmlinux_maps[type] = NULL; | ||
529 | } | ||
530 | } | ||
531 | |||
532 | int machines__create_guest_kernel_maps(struct machines *machines) | ||
533 | { | ||
534 | int ret = 0; | ||
535 | struct dirent **namelist = NULL; | ||
536 | int i, items = 0; | ||
537 | char path[PATH_MAX]; | ||
538 | pid_t pid; | ||
539 | char *endp; | ||
540 | |||
541 | if (symbol_conf.default_guest_vmlinux_name || | ||
542 | symbol_conf.default_guest_modules || | ||
543 | symbol_conf.default_guest_kallsyms) { | ||
544 | machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID); | ||
545 | } | ||
546 | |||
547 | if (symbol_conf.guestmount) { | ||
548 | items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL); | ||
549 | if (items <= 0) | ||
550 | return -ENOENT; | ||
551 | for (i = 0; i < items; i++) { | ||
552 | if (!isdigit(namelist[i]->d_name[0])) { | ||
553 | /* Filter out . and .. */ | ||
554 | continue; | ||
555 | } | ||
556 | pid = (pid_t)strtol(namelist[i]->d_name, &endp, 10); | ||
557 | if ((*endp != '\0') || | ||
558 | (endp == namelist[i]->d_name) || | ||
559 | (errno == ERANGE)) { | ||
560 | pr_debug("invalid directory (%s). Skipping.\n", | ||
561 | namelist[i]->d_name); | ||
562 | continue; | ||
563 | } | ||
564 | sprintf(path, "%s/%s/proc/kallsyms", | ||
565 | symbol_conf.guestmount, | ||
566 | namelist[i]->d_name); | ||
567 | ret = access(path, R_OK); | ||
568 | if (ret) { | ||
569 | pr_debug("Can't access file %s\n", path); | ||
570 | goto failure; | ||
571 | } | ||
572 | machines__create_kernel_maps(machines, pid); | ||
573 | } | ||
574 | failure: | ||
575 | free(namelist); | ||
576 | } | ||
577 | |||
578 | return ret; | ||
579 | } | ||
580 | |||
581 | void machines__destroy_kernel_maps(struct machines *machines) | ||
582 | { | ||
583 | struct rb_node *next = rb_first(&machines->guests); | ||
584 | |||
585 | machine__destroy_kernel_maps(&machines->host); | ||
586 | |||
587 | while (next) { | ||
588 | struct machine *pos = rb_entry(next, struct machine, rb_node); | ||
589 | |||
590 | next = rb_next(&pos->rb_node); | ||
591 | rb_erase(&pos->rb_node, &machines->guests); | ||
592 | machine__delete(pos); | ||
593 | } | ||
594 | } | ||
595 | |||
596 | int machines__create_kernel_maps(struct machines *machines, pid_t pid) | ||
597 | { | ||
598 | struct machine *machine = machines__findnew(machines, pid); | ||
599 | |||
600 | if (machine == NULL) | ||
601 | return -1; | ||
602 | |||
603 | return machine__create_kernel_maps(machine); | ||
604 | } | ||
605 | |||
606 | int machine__load_kallsyms(struct machine *machine, const char *filename, | ||
607 | enum map_type type, symbol_filter_t filter) | ||
608 | { | ||
609 | struct map *map = machine->vmlinux_maps[type]; | ||
610 | int ret = dso__load_kallsyms(map->dso, filename, map, filter); | ||
611 | |||
612 | if (ret > 0) { | ||
613 | dso__set_loaded(map->dso, type); | ||
614 | /* | ||
615 | * Since /proc/kallsyms will have multiple sessions for the | ||
616 | * kernel, with modules between them, fixup the end of all | ||
617 | * sections. | ||
618 | */ | ||
619 | __map_groups__fixup_end(&machine->kmaps, type); | ||
620 | } | ||
621 | |||
622 | return ret; | ||
623 | } | ||
624 | |||
625 | int machine__load_vmlinux_path(struct machine *machine, enum map_type type, | ||
626 | symbol_filter_t filter) | ||
627 | { | ||
628 | struct map *map = machine->vmlinux_maps[type]; | ||
629 | int ret = dso__load_vmlinux_path(map->dso, map, filter); | ||
630 | |||
631 | if (ret > 0) { | ||
632 | dso__set_loaded(map->dso, type); | ||
633 | map__reloc_vmlinux(map); | ||
634 | } | ||
635 | |||
636 | return ret; | ||
637 | } | ||
638 | |||
639 | static void map_groups__fixup_end(struct map_groups *mg) | ||
640 | { | ||
641 | int i; | ||
642 | for (i = 0; i < MAP__NR_TYPES; ++i) | ||
643 | __map_groups__fixup_end(mg, i); | ||
644 | } | ||
645 | |||
646 | static char *get_kernel_version(const char *root_dir) | ||
647 | { | ||
648 | char version[PATH_MAX]; | ||
649 | FILE *file; | ||
650 | char *name, *tmp; | ||
651 | const char *prefix = "Linux version "; | ||
652 | |||
653 | sprintf(version, "%s/proc/version", root_dir); | ||
654 | file = fopen(version, "r"); | ||
655 | if (!file) | ||
656 | return NULL; | ||
657 | |||
658 | version[0] = '\0'; | ||
659 | tmp = fgets(version, sizeof(version), file); | ||
660 | fclose(file); | ||
661 | |||
662 | name = strstr(version, prefix); | ||
663 | if (!name) | ||
664 | return NULL; | ||
665 | name += strlen(prefix); | ||
666 | tmp = strchr(name, ' '); | ||
667 | if (tmp) | ||
668 | *tmp = '\0'; | ||
669 | |||
670 | return strdup(name); | ||
671 | } | ||
672 | |||
673 | static int map_groups__set_modules_path_dir(struct map_groups *mg, | ||
674 | const char *dir_name) | ||
675 | { | ||
676 | struct dirent *dent; | ||
677 | DIR *dir = opendir(dir_name); | ||
678 | int ret = 0; | ||
679 | |||
680 | if (!dir) { | ||
681 | pr_debug("%s: cannot open %s dir\n", __func__, dir_name); | ||
682 | return -1; | ||
683 | } | ||
684 | |||
685 | while ((dent = readdir(dir)) != NULL) { | ||
686 | char path[PATH_MAX]; | ||
687 | struct stat st; | ||
688 | |||
689 | /*sshfs might return bad dent->d_type, so we have to stat*/ | ||
690 | snprintf(path, sizeof(path), "%s/%s", dir_name, dent->d_name); | ||
691 | if (stat(path, &st)) | ||
692 | continue; | ||
693 | |||
694 | if (S_ISDIR(st.st_mode)) { | ||
695 | if (!strcmp(dent->d_name, ".") || | ||
696 | !strcmp(dent->d_name, "..")) | ||
697 | continue; | ||
698 | |||
699 | ret = map_groups__set_modules_path_dir(mg, path); | ||
700 | if (ret < 0) | ||
701 | goto out; | ||
702 | } else { | ||
703 | char *dot = strrchr(dent->d_name, '.'), | ||
704 | dso_name[PATH_MAX]; | ||
705 | struct map *map; | ||
706 | char *long_name; | ||
707 | |||
708 | if (dot == NULL || strcmp(dot, ".ko")) | ||
709 | continue; | ||
710 | snprintf(dso_name, sizeof(dso_name), "[%.*s]", | ||
711 | (int)(dot - dent->d_name), dent->d_name); | ||
712 | |||
713 | strxfrchar(dso_name, '-', '_'); | ||
714 | map = map_groups__find_by_name(mg, MAP__FUNCTION, | ||
715 | dso_name); | ||
716 | if (map == NULL) | ||
717 | continue; | ||
718 | |||
719 | long_name = strdup(path); | ||
720 | if (long_name == NULL) { | ||
721 | ret = -1; | ||
722 | goto out; | ||
723 | } | ||
724 | dso__set_long_name(map->dso, long_name); | ||
725 | map->dso->lname_alloc = 1; | ||
726 | dso__kernel_module_get_build_id(map->dso, ""); | ||
727 | } | ||
728 | } | ||
729 | |||
730 | out: | ||
731 | closedir(dir); | ||
732 | return ret; | ||
733 | } | ||
734 | |||
735 | static int machine__set_modules_path(struct machine *machine) | ||
736 | { | ||
737 | char *version; | ||
738 | char modules_path[PATH_MAX]; | ||
739 | |||
740 | version = get_kernel_version(machine->root_dir); | ||
741 | if (!version) | ||
742 | return -1; | ||
743 | |||
744 | snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel", | ||
745 | machine->root_dir, version); | ||
746 | free(version); | ||
747 | |||
748 | return map_groups__set_modules_path_dir(&machine->kmaps, modules_path); | ||
749 | } | ||
750 | |||
751 | static int machine__create_modules(struct machine *machine) | ||
752 | { | ||
753 | char *line = NULL; | ||
754 | size_t n; | ||
755 | FILE *file; | ||
756 | struct map *map; | ||
757 | const char *modules; | ||
758 | char path[PATH_MAX]; | ||
759 | |||
760 | if (machine__is_default_guest(machine)) | ||
761 | modules = symbol_conf.default_guest_modules; | ||
762 | else { | ||
763 | sprintf(path, "%s/proc/modules", machine->root_dir); | ||
764 | modules = path; | ||
765 | } | ||
766 | |||
767 | if (symbol__restricted_filename(path, "/proc/modules")) | ||
768 | return -1; | ||
769 | |||
770 | file = fopen(modules, "r"); | ||
771 | if (file == NULL) | ||
772 | return -1; | ||
773 | |||
774 | while (!feof(file)) { | ||
775 | char name[PATH_MAX]; | ||
776 | u64 start; | ||
777 | char *sep; | ||
778 | int line_len; | ||
779 | |||
780 | line_len = getline(&line, &n, file); | ||
781 | if (line_len < 0) | ||
782 | break; | ||
783 | |||
784 | if (!line) | ||
785 | goto out_failure; | ||
786 | |||
787 | line[--line_len] = '\0'; /* \n */ | ||
788 | |||
789 | sep = strrchr(line, 'x'); | ||
790 | if (sep == NULL) | ||
791 | continue; | ||
792 | |||
793 | hex2u64(sep + 1, &start); | ||
794 | |||
795 | sep = strchr(line, ' '); | ||
796 | if (sep == NULL) | ||
797 | continue; | ||
798 | |||
799 | *sep = '\0'; | ||
800 | |||
801 | snprintf(name, sizeof(name), "[%s]", line); | ||
802 | map = machine__new_module(machine, start, name); | ||
803 | if (map == NULL) | ||
804 | goto out_delete_line; | ||
805 | dso__kernel_module_get_build_id(map->dso, machine->root_dir); | ||
806 | } | ||
807 | |||
808 | free(line); | ||
809 | fclose(file); | ||
810 | |||
811 | return machine__set_modules_path(machine); | ||
812 | |||
813 | out_delete_line: | ||
814 | free(line); | ||
815 | out_failure: | ||
816 | return -1; | ||
817 | } | ||
818 | |||
819 | int machine__create_kernel_maps(struct machine *machine) | ||
820 | { | ||
821 | struct dso *kernel = machine__get_kernel(machine); | ||
822 | |||
823 | if (kernel == NULL || | ||
824 | __machine__create_kernel_maps(machine, kernel) < 0) | ||
825 | return -1; | ||
826 | |||
827 | if (symbol_conf.use_modules && machine__create_modules(machine) < 0) { | ||
828 | if (machine__is_host(machine)) | ||
829 | pr_debug("Problems creating module maps, " | ||
830 | "continuing anyway...\n"); | ||
831 | else | ||
832 | pr_debug("Problems creating module maps for guest %d, " | ||
833 | "continuing anyway...\n", machine->pid); | ||
834 | } | ||
835 | |||
836 | /* | ||
837 | * Now that we have all the maps created, just set the ->end of them: | ||
838 | */ | ||
839 | map_groups__fixup_end(&machine->kmaps); | ||
840 | return 0; | ||
841 | } | ||
842 | |||
267 | static void machine__set_kernel_mmap_len(struct machine *machine, | 843 | static void machine__set_kernel_mmap_len(struct machine *machine, |
268 | union perf_event *event) | 844 | union perf_event *event) |
269 | { | 845 | { |
@@ -462,3 +1038,189 @@ int machine__process_event(struct machine *machine, union perf_event *event) | |||
462 | 1038 | ||
463 | return ret; | 1039 | return ret; |
464 | } | 1040 | } |
1041 | |||
1042 | void machine__remove_thread(struct machine *machine, struct thread *th) | ||
1043 | { | ||
1044 | machine->last_match = NULL; | ||
1045 | rb_erase(&th->rb_node, &machine->threads); | ||
1046 | /* | ||
1047 | * We may have references to this thread, for instance in some hist_entry | ||
1048 | * instances, so just move them to a separate list. | ||
1049 | */ | ||
1050 | list_add_tail(&th->node, &machine->dead_threads); | ||
1051 | } | ||
1052 | |||
1053 | static bool symbol__match_parent_regex(struct symbol *sym) | ||
1054 | { | ||
1055 | if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0)) | ||
1056 | return 1; | ||
1057 | |||
1058 | return 0; | ||
1059 | } | ||
1060 | |||
1061 | static const u8 cpumodes[] = { | ||
1062 | PERF_RECORD_MISC_USER, | ||
1063 | PERF_RECORD_MISC_KERNEL, | ||
1064 | PERF_RECORD_MISC_GUEST_USER, | ||
1065 | PERF_RECORD_MISC_GUEST_KERNEL | ||
1066 | }; | ||
1067 | #define NCPUMODES (sizeof(cpumodes)/sizeof(u8)) | ||
1068 | |||
1069 | static void ip__resolve_ams(struct machine *machine, struct thread *thread, | ||
1070 | struct addr_map_symbol *ams, | ||
1071 | u64 ip) | ||
1072 | { | ||
1073 | struct addr_location al; | ||
1074 | size_t i; | ||
1075 | u8 m; | ||
1076 | |||
1077 | memset(&al, 0, sizeof(al)); | ||
1078 | |||
1079 | for (i = 0; i < NCPUMODES; i++) { | ||
1080 | m = cpumodes[i]; | ||
1081 | /* | ||
1082 | * We cannot use the header.misc hint to determine whether a | ||
1083 | * branch stack address is user, kernel, guest, hypervisor. | ||
1084 | * Branches may straddle the kernel/user/hypervisor boundaries. | ||
1085 | * Thus, we have to try consecutively until we find a match | ||
1086 | * or else, the symbol is unknown | ||
1087 | */ | ||
1088 | thread__find_addr_location(thread, machine, m, MAP__FUNCTION, | ||
1089 | ip, &al, NULL); | ||
1090 | if (al.sym) | ||
1091 | goto found; | ||
1092 | } | ||
1093 | found: | ||
1094 | ams->addr = ip; | ||
1095 | ams->al_addr = al.addr; | ||
1096 | ams->sym = al.sym; | ||
1097 | ams->map = al.map; | ||
1098 | } | ||
1099 | |||
1100 | struct branch_info *machine__resolve_bstack(struct machine *machine, | ||
1101 | struct thread *thr, | ||
1102 | struct branch_stack *bs) | ||
1103 | { | ||
1104 | struct branch_info *bi; | ||
1105 | unsigned int i; | ||
1106 | |||
1107 | bi = calloc(bs->nr, sizeof(struct branch_info)); | ||
1108 | if (!bi) | ||
1109 | return NULL; | ||
1110 | |||
1111 | for (i = 0; i < bs->nr; i++) { | ||
1112 | ip__resolve_ams(machine, thr, &bi[i].to, bs->entries[i].to); | ||
1113 | ip__resolve_ams(machine, thr, &bi[i].from, bs->entries[i].from); | ||
1114 | bi[i].flags = bs->entries[i].flags; | ||
1115 | } | ||
1116 | return bi; | ||
1117 | } | ||
1118 | |||
1119 | static int machine__resolve_callchain_sample(struct machine *machine, | ||
1120 | struct thread *thread, | ||
1121 | struct ip_callchain *chain, | ||
1122 | struct symbol **parent) | ||
1123 | |||
1124 | { | ||
1125 | u8 cpumode = PERF_RECORD_MISC_USER; | ||
1126 | unsigned int i; | ||
1127 | int err; | ||
1128 | |||
1129 | callchain_cursor_reset(&callchain_cursor); | ||
1130 | |||
1131 | if (chain->nr > PERF_MAX_STACK_DEPTH) { | ||
1132 | pr_warning("corrupted callchain. skipping...\n"); | ||
1133 | return 0; | ||
1134 | } | ||
1135 | |||
1136 | for (i = 0; i < chain->nr; i++) { | ||
1137 | u64 ip; | ||
1138 | struct addr_location al; | ||
1139 | |||
1140 | if (callchain_param.order == ORDER_CALLEE) | ||
1141 | ip = chain->ips[i]; | ||
1142 | else | ||
1143 | ip = chain->ips[chain->nr - i - 1]; | ||
1144 | |||
1145 | if (ip >= PERF_CONTEXT_MAX) { | ||
1146 | switch (ip) { | ||
1147 | case PERF_CONTEXT_HV: | ||
1148 | cpumode = PERF_RECORD_MISC_HYPERVISOR; | ||
1149 | break; | ||
1150 | case PERF_CONTEXT_KERNEL: | ||
1151 | cpumode = PERF_RECORD_MISC_KERNEL; | ||
1152 | break; | ||
1153 | case PERF_CONTEXT_USER: | ||
1154 | cpumode = PERF_RECORD_MISC_USER; | ||
1155 | break; | ||
1156 | default: | ||
1157 | pr_debug("invalid callchain context: " | ||
1158 | "%"PRId64"\n", (s64) ip); | ||
1159 | /* | ||
1160 | * It seems the callchain is corrupted. | ||
1161 | * Discard all. | ||
1162 | */ | ||
1163 | callchain_cursor_reset(&callchain_cursor); | ||
1164 | return 0; | ||
1165 | } | ||
1166 | continue; | ||
1167 | } | ||
1168 | |||
1169 | al.filtered = false; | ||
1170 | thread__find_addr_location(thread, machine, cpumode, | ||
1171 | MAP__FUNCTION, ip, &al, NULL); | ||
1172 | if (al.sym != NULL) { | ||
1173 | if (sort__has_parent && !*parent && | ||
1174 | symbol__match_parent_regex(al.sym)) | ||
1175 | *parent = al.sym; | ||
1176 | if (!symbol_conf.use_callchain) | ||
1177 | break; | ||
1178 | } | ||
1179 | |||
1180 | err = callchain_cursor_append(&callchain_cursor, | ||
1181 | ip, al.map, al.sym); | ||
1182 | if (err) | ||
1183 | return err; | ||
1184 | } | ||
1185 | |||
1186 | return 0; | ||
1187 | } | ||
1188 | |||
1189 | static int unwind_entry(struct unwind_entry *entry, void *arg) | ||
1190 | { | ||
1191 | struct callchain_cursor *cursor = arg; | ||
1192 | return callchain_cursor_append(cursor, entry->ip, | ||
1193 | entry->map, entry->sym); | ||
1194 | } | ||
1195 | |||
1196 | int machine__resolve_callchain(struct machine *machine, | ||
1197 | struct perf_evsel *evsel, | ||
1198 | struct thread *thread, | ||
1199 | struct perf_sample *sample, | ||
1200 | struct symbol **parent) | ||
1201 | |||
1202 | { | ||
1203 | int ret; | ||
1204 | |||
1205 | callchain_cursor_reset(&callchain_cursor); | ||
1206 | |||
1207 | ret = machine__resolve_callchain_sample(machine, thread, | ||
1208 | sample->callchain, parent); | ||
1209 | if (ret) | ||
1210 | return ret; | ||
1211 | |||
1212 | /* Can we do dwarf post unwind? */ | ||
1213 | if (!((evsel->attr.sample_type & PERF_SAMPLE_REGS_USER) && | ||
1214 | (evsel->attr.sample_type & PERF_SAMPLE_STACK_USER))) | ||
1215 | return 0; | ||
1216 | |||
1217 | /* Bail out if nothing was captured. */ | ||
1218 | if ((!sample->user_regs.regs) || | ||
1219 | (!sample->user_stack.size)) | ||
1220 | return 0; | ||
1221 | |||
1222 | return unwind__get_entries(unwind_entry, &callchain_cursor, machine, | ||
1223 | thread, evsel->attr.sample_regs_user, | ||
1224 | sample); | ||
1225 | |||
1226 | } | ||
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index b7cde7467d55..5ac5892f2326 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h | |||
@@ -47,23 +47,32 @@ int machine__process_event(struct machine *machine, union perf_event *event); | |||
47 | 47 | ||
48 | typedef void (*machine__process_t)(struct machine *machine, void *data); | 48 | typedef void (*machine__process_t)(struct machine *machine, void *data); |
49 | 49 | ||
50 | void machines__process(struct rb_root *machines, | 50 | struct machines { |
51 | machine__process_t process, void *data); | 51 | struct machine host; |
52 | struct rb_root guests; | ||
53 | }; | ||
54 | |||
55 | void machines__init(struct machines *machines); | ||
56 | void machines__exit(struct machines *machines); | ||
52 | 57 | ||
53 | struct machine *machines__add(struct rb_root *machines, pid_t pid, | 58 | void machines__process_guests(struct machines *machines, |
59 | machine__process_t process, void *data); | ||
60 | |||
61 | struct machine *machines__add(struct machines *machines, pid_t pid, | ||
54 | const char *root_dir); | 62 | const char *root_dir); |
55 | struct machine *machines__find_host(struct rb_root *machines); | 63 | struct machine *machines__find_host(struct machines *machines); |
56 | struct machine *machines__find(struct rb_root *machines, pid_t pid); | 64 | struct machine *machines__find(struct machines *machines, pid_t pid); |
57 | struct machine *machines__findnew(struct rb_root *machines, pid_t pid); | 65 | struct machine *machines__findnew(struct machines *machines, pid_t pid); |
58 | 66 | ||
59 | void machines__set_id_hdr_size(struct rb_root *machines, u16 id_hdr_size); | 67 | void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size); |
60 | char *machine__mmap_name(struct machine *machine, char *bf, size_t size); | 68 | char *machine__mmap_name(struct machine *machine, char *bf, size_t size); |
61 | 69 | ||
62 | int machine__init(struct machine *machine, const char *root_dir, pid_t pid); | 70 | int machine__init(struct machine *machine, const char *root_dir, pid_t pid); |
63 | void machine__exit(struct machine *machine); | 71 | void machine__exit(struct machine *machine); |
72 | void machine__delete_dead_threads(struct machine *machine); | ||
73 | void machine__delete_threads(struct machine *machine); | ||
64 | void machine__delete(struct machine *machine); | 74 | void machine__delete(struct machine *machine); |
65 | 75 | ||
66 | |||
67 | struct branch_info *machine__resolve_bstack(struct machine *machine, | 76 | struct branch_info *machine__resolve_bstack(struct machine *machine, |
68 | struct thread *thread, | 77 | struct thread *thread, |
69 | struct branch_stack *bs); | 78 | struct branch_stack *bs); |
@@ -129,19 +138,19 @@ int machine__load_kallsyms(struct machine *machine, const char *filename, | |||
129 | int machine__load_vmlinux_path(struct machine *machine, enum map_type type, | 138 | int machine__load_vmlinux_path(struct machine *machine, enum map_type type, |
130 | symbol_filter_t filter); | 139 | symbol_filter_t filter); |
131 | 140 | ||
132 | size_t machine__fprintf_dsos_buildid(struct machine *machine, | 141 | size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, |
133 | FILE *fp, bool with_hits); | 142 | bool (skip)(struct dso *dso, int parm), int parm); |
134 | size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp); | 143 | size_t machines__fprintf_dsos(struct machines *machines, FILE *fp); |
135 | size_t machines__fprintf_dsos_buildid(struct rb_root *machines, | 144 | size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp, |
136 | FILE *fp, bool with_hits); | 145 | bool (skip)(struct dso *dso, int parm), int parm); |
137 | 146 | ||
138 | void machine__destroy_kernel_maps(struct machine *machine); | 147 | void machine__destroy_kernel_maps(struct machine *machine); |
139 | int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel); | 148 | int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel); |
140 | int machine__create_kernel_maps(struct machine *machine); | 149 | int machine__create_kernel_maps(struct machine *machine); |
141 | 150 | ||
142 | int machines__create_kernel_maps(struct rb_root *machines, pid_t pid); | 151 | int machines__create_kernel_maps(struct machines *machines, pid_t pid); |
143 | int machines__create_guest_kernel_maps(struct rb_root *machines); | 152 | int machines__create_guest_kernel_maps(struct machines *machines); |
144 | void machines__destroy_guest_kernel_maps(struct rb_root *machines); | 153 | void machines__destroy_kernel_maps(struct machines *machines); |
145 | 154 | ||
146 | size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp); | 155 | size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp); |
147 | 156 | ||
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 0328d45c4f2a..6fcb9de62340 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include "strlist.h" | 11 | #include "strlist.h" |
12 | #include "vdso.h" | 12 | #include "vdso.h" |
13 | #include "build-id.h" | 13 | #include "build-id.h" |
14 | #include <linux/string.h> | ||
14 | 15 | ||
15 | const char *map_type__name[MAP__NR_TYPES] = { | 16 | const char *map_type__name[MAP__NR_TYPES] = { |
16 | [MAP__FUNCTION] = "Functions", | 17 | [MAP__FUNCTION] = "Functions", |
@@ -19,7 +20,8 @@ const char *map_type__name[MAP__NR_TYPES] = { | |||
19 | 20 | ||
20 | static inline int is_anon_memory(const char *filename) | 21 | static inline int is_anon_memory(const char *filename) |
21 | { | 22 | { |
22 | return strcmp(filename, "//anon") == 0; | 23 | return !strcmp(filename, "//anon") || |
24 | !strcmp(filename, "/anon_hugepage (deleted)"); | ||
23 | } | 25 | } |
24 | 26 | ||
25 | static inline int is_no_dso_memory(const char *filename) | 27 | static inline int is_no_dso_memory(const char *filename) |
@@ -28,29 +30,29 @@ static inline int is_no_dso_memory(const char *filename) | |||
28 | !strcmp(filename, "[heap]"); | 30 | !strcmp(filename, "[heap]"); |
29 | } | 31 | } |
30 | 32 | ||
31 | void map__init(struct map *self, enum map_type type, | 33 | void map__init(struct map *map, enum map_type type, |
32 | u64 start, u64 end, u64 pgoff, struct dso *dso) | 34 | u64 start, u64 end, u64 pgoff, struct dso *dso) |
33 | { | 35 | { |
34 | self->type = type; | 36 | map->type = type; |
35 | self->start = start; | 37 | map->start = start; |
36 | self->end = end; | 38 | map->end = end; |
37 | self->pgoff = pgoff; | 39 | map->pgoff = pgoff; |
38 | self->dso = dso; | 40 | map->dso = dso; |
39 | self->map_ip = map__map_ip; | 41 | map->map_ip = map__map_ip; |
40 | self->unmap_ip = map__unmap_ip; | 42 | map->unmap_ip = map__unmap_ip; |
41 | RB_CLEAR_NODE(&self->rb_node); | 43 | RB_CLEAR_NODE(&map->rb_node); |
42 | self->groups = NULL; | 44 | map->groups = NULL; |
43 | self->referenced = false; | 45 | map->referenced = false; |
44 | self->erange_warned = false; | 46 | map->erange_warned = false; |
45 | } | 47 | } |
46 | 48 | ||
47 | struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, | 49 | struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, |
48 | u64 pgoff, u32 pid, char *filename, | 50 | u64 pgoff, u32 pid, char *filename, |
49 | enum map_type type) | 51 | enum map_type type) |
50 | { | 52 | { |
51 | struct map *self = malloc(sizeof(*self)); | 53 | struct map *map = malloc(sizeof(*map)); |
52 | 54 | ||
53 | if (self != NULL) { | 55 | if (map != NULL) { |
54 | char newfilename[PATH_MAX]; | 56 | char newfilename[PATH_MAX]; |
55 | struct dso *dso; | 57 | struct dso *dso; |
56 | int anon, no_dso, vdso; | 58 | int anon, no_dso, vdso; |
@@ -73,10 +75,10 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, | |||
73 | if (dso == NULL) | 75 | if (dso == NULL) |
74 | goto out_delete; | 76 | goto out_delete; |
75 | 77 | ||
76 | map__init(self, type, start, start + len, pgoff, dso); | 78 | map__init(map, type, start, start + len, pgoff, dso); |
77 | 79 | ||
78 | if (anon || no_dso) { | 80 | if (anon || no_dso) { |
79 | self->map_ip = self->unmap_ip = identity__map_ip; | 81 | map->map_ip = map->unmap_ip = identity__map_ip; |
80 | 82 | ||
81 | /* | 83 | /* |
82 | * Set memory without DSO as loaded. All map__find_* | 84 | * Set memory without DSO as loaded. All map__find_* |
@@ -84,12 +86,12 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, | |||
84 | * unnecessary map__load warning. | 86 | * unnecessary map__load warning. |
85 | */ | 87 | */ |
86 | if (no_dso) | 88 | if (no_dso) |
87 | dso__set_loaded(dso, self->type); | 89 | dso__set_loaded(dso, map->type); |
88 | } | 90 | } |
89 | } | 91 | } |
90 | return self; | 92 | return map; |
91 | out_delete: | 93 | out_delete: |
92 | free(self); | 94 | free(map); |
93 | return NULL; | 95 | return NULL; |
94 | } | 96 | } |
95 | 97 | ||
@@ -112,48 +114,48 @@ struct map *map__new2(u64 start, struct dso *dso, enum map_type type) | |||
112 | return map; | 114 | return map; |
113 | } | 115 | } |
114 | 116 | ||
115 | void map__delete(struct map *self) | 117 | void map__delete(struct map *map) |
116 | { | 118 | { |
117 | free(self); | 119 | free(map); |
118 | } | 120 | } |
119 | 121 | ||
120 | void map__fixup_start(struct map *self) | 122 | void map__fixup_start(struct map *map) |
121 | { | 123 | { |
122 | struct rb_root *symbols = &self->dso->symbols[self->type]; | 124 | struct rb_root *symbols = &map->dso->symbols[map->type]; |
123 | struct rb_node *nd = rb_first(symbols); | 125 | struct rb_node *nd = rb_first(symbols); |
124 | if (nd != NULL) { | 126 | if (nd != NULL) { |
125 | struct symbol *sym = rb_entry(nd, struct symbol, rb_node); | 127 | struct symbol *sym = rb_entry(nd, struct symbol, rb_node); |
126 | self->start = sym->start; | 128 | map->start = sym->start; |
127 | } | 129 | } |
128 | } | 130 | } |
129 | 131 | ||
130 | void map__fixup_end(struct map *self) | 132 | void map__fixup_end(struct map *map) |
131 | { | 133 | { |
132 | struct rb_root *symbols = &self->dso->symbols[self->type]; | 134 | struct rb_root *symbols = &map->dso->symbols[map->type]; |
133 | struct rb_node *nd = rb_last(symbols); | 135 | struct rb_node *nd = rb_last(symbols); |
134 | if (nd != NULL) { | 136 | if (nd != NULL) { |
135 | struct symbol *sym = rb_entry(nd, struct symbol, rb_node); | 137 | struct symbol *sym = rb_entry(nd, struct symbol, rb_node); |
136 | self->end = sym->end; | 138 | map->end = sym->end; |
137 | } | 139 | } |
138 | } | 140 | } |
139 | 141 | ||
140 | #define DSO__DELETED "(deleted)" | 142 | #define DSO__DELETED "(deleted)" |
141 | 143 | ||
142 | int map__load(struct map *self, symbol_filter_t filter) | 144 | int map__load(struct map *map, symbol_filter_t filter) |
143 | { | 145 | { |
144 | const char *name = self->dso->long_name; | 146 | const char *name = map->dso->long_name; |
145 | int nr; | 147 | int nr; |
146 | 148 | ||
147 | if (dso__loaded(self->dso, self->type)) | 149 | if (dso__loaded(map->dso, map->type)) |
148 | return 0; | 150 | return 0; |
149 | 151 | ||
150 | nr = dso__load(self->dso, self, filter); | 152 | nr = dso__load(map->dso, map, filter); |
151 | if (nr < 0) { | 153 | if (nr < 0) { |
152 | if (self->dso->has_build_id) { | 154 | if (map->dso->has_build_id) { |
153 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; | 155 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; |
154 | 156 | ||
155 | build_id__sprintf(self->dso->build_id, | 157 | build_id__sprintf(map->dso->build_id, |
156 | sizeof(self->dso->build_id), | 158 | sizeof(map->dso->build_id), |
157 | sbuild_id); | 159 | sbuild_id); |
158 | pr_warning("%s with build id %s not found", | 160 | pr_warning("%s with build id %s not found", |
159 | name, sbuild_id); | 161 | name, sbuild_id); |
@@ -183,43 +185,36 @@ int map__load(struct map *self, symbol_filter_t filter) | |||
183 | * Only applies to the kernel, as its symtabs aren't relative like the | 185 | * Only applies to the kernel, as its symtabs aren't relative like the |
184 | * module ones. | 186 | * module ones. |
185 | */ | 187 | */ |
186 | if (self->dso->kernel) | 188 | if (map->dso->kernel) |
187 | map__reloc_vmlinux(self); | 189 | map__reloc_vmlinux(map); |
188 | 190 | ||
189 | return 0; | 191 | return 0; |
190 | } | 192 | } |
191 | 193 | ||
192 | struct symbol *map__find_symbol(struct map *self, u64 addr, | 194 | struct symbol *map__find_symbol(struct map *map, u64 addr, |
193 | symbol_filter_t filter) | 195 | symbol_filter_t filter) |
194 | { | 196 | { |
195 | if (map__load(self, filter) < 0) | 197 | if (map__load(map, filter) < 0) |
196 | return NULL; | 198 | return NULL; |
197 | 199 | ||
198 | return dso__find_symbol(self->dso, self->type, addr); | 200 | return dso__find_symbol(map->dso, map->type, addr); |
199 | } | 201 | } |
200 | 202 | ||
201 | struct symbol *map__find_symbol_by_name(struct map *self, const char *name, | 203 | struct symbol *map__find_symbol_by_name(struct map *map, const char *name, |
202 | symbol_filter_t filter) | 204 | symbol_filter_t filter) |
203 | { | 205 | { |
204 | if (map__load(self, filter) < 0) | 206 | if (map__load(map, filter) < 0) |
205 | return NULL; | 207 | return NULL; |
206 | 208 | ||
207 | if (!dso__sorted_by_name(self->dso, self->type)) | 209 | if (!dso__sorted_by_name(map->dso, map->type)) |
208 | dso__sort_by_name(self->dso, self->type); | 210 | dso__sort_by_name(map->dso, map->type); |
209 | 211 | ||
210 | return dso__find_symbol_by_name(self->dso, self->type, name); | 212 | return dso__find_symbol_by_name(map->dso, map->type, name); |
211 | } | 213 | } |
212 | 214 | ||
213 | struct map *map__clone(struct map *self) | 215 | struct map *map__clone(struct map *map) |
214 | { | 216 | { |
215 | struct map *map = malloc(sizeof(*self)); | 217 | return memdup(map, sizeof(*map)); |
216 | |||
217 | if (!map) | ||
218 | return NULL; | ||
219 | |||
220 | memcpy(map, self, sizeof(*self)); | ||
221 | |||
222 | return map; | ||
223 | } | 218 | } |
224 | 219 | ||
225 | int map__overlap(struct map *l, struct map *r) | 220 | int map__overlap(struct map *l, struct map *r) |
@@ -236,10 +231,10 @@ int map__overlap(struct map *l, struct map *r) | |||
236 | return 0; | 231 | return 0; |
237 | } | 232 | } |
238 | 233 | ||
239 | size_t map__fprintf(struct map *self, FILE *fp) | 234 | size_t map__fprintf(struct map *map, FILE *fp) |
240 | { | 235 | { |
241 | return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s\n", | 236 | return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s\n", |
242 | self->start, self->end, self->pgoff, self->dso->name); | 237 | map->start, map->end, map->pgoff, map->dso->name); |
243 | } | 238 | } |
244 | 239 | ||
245 | size_t map__fprintf_dsoname(struct map *map, FILE *fp) | 240 | size_t map__fprintf_dsoname(struct map *map, FILE *fp) |
@@ -527,9 +522,9 @@ static u64 map__reloc_unmap_ip(struct map *map, u64 ip) | |||
527 | return ip - (s64)map->pgoff; | 522 | return ip - (s64)map->pgoff; |
528 | } | 523 | } |
529 | 524 | ||
530 | void map__reloc_vmlinux(struct map *self) | 525 | void map__reloc_vmlinux(struct map *map) |
531 | { | 526 | { |
532 | struct kmap *kmap = map__kmap(self); | 527 | struct kmap *kmap = map__kmap(map); |
533 | s64 reloc; | 528 | s64 reloc; |
534 | 529 | ||
535 | if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->unrelocated_addr) | 530 | if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->unrelocated_addr) |
@@ -541,9 +536,9 @@ void map__reloc_vmlinux(struct map *self) | |||
541 | if (!reloc) | 536 | if (!reloc) |
542 | return; | 537 | return; |
543 | 538 | ||
544 | self->map_ip = map__reloc_map_ip; | 539 | map->map_ip = map__reloc_map_ip; |
545 | self->unmap_ip = map__reloc_unmap_ip; | 540 | map->unmap_ip = map__reloc_unmap_ip; |
546 | self->pgoff = reloc; | 541 | map->pgoff = reloc; |
547 | } | 542 | } |
548 | 543 | ||
549 | void maps__insert(struct rb_root *maps, struct map *map) | 544 | void maps__insert(struct rb_root *maps, struct map *map) |
@@ -566,9 +561,9 @@ void maps__insert(struct rb_root *maps, struct map *map) | |||
566 | rb_insert_color(&map->rb_node, maps); | 561 | rb_insert_color(&map->rb_node, maps); |
567 | } | 562 | } |
568 | 563 | ||
569 | void maps__remove(struct rb_root *self, struct map *map) | 564 | void maps__remove(struct rb_root *maps, struct map *map) |
570 | { | 565 | { |
571 | rb_erase(&map->rb_node, self); | 566 | rb_erase(&map->rb_node, maps); |
572 | } | 567 | } |
573 | 568 | ||
574 | struct map *maps__find(struct rb_root *maps, u64 ip) | 569 | struct map *maps__find(struct rb_root *maps, u64 ip) |
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index bcb39e2a6965..a887f2c9dfbb 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h | |||
@@ -57,9 +57,9 @@ struct map_groups { | |||
57 | struct machine *machine; | 57 | struct machine *machine; |
58 | }; | 58 | }; |
59 | 59 | ||
60 | static inline struct kmap *map__kmap(struct map *self) | 60 | static inline struct kmap *map__kmap(struct map *map) |
61 | { | 61 | { |
62 | return (struct kmap *)(self + 1); | 62 | return (struct kmap *)(map + 1); |
63 | } | 63 | } |
64 | 64 | ||
65 | static inline u64 map__map_ip(struct map *map, u64 ip) | 65 | static inline u64 map__map_ip(struct map *map, u64 ip) |
@@ -85,27 +85,27 @@ struct symbol; | |||
85 | 85 | ||
86 | typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); | 86 | typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); |
87 | 87 | ||
88 | void map__init(struct map *self, enum map_type type, | 88 | void map__init(struct map *map, enum map_type type, |
89 | u64 start, u64 end, u64 pgoff, struct dso *dso); | 89 | u64 start, u64 end, u64 pgoff, struct dso *dso); |
90 | struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, | 90 | struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, |
91 | u64 pgoff, u32 pid, char *filename, | 91 | u64 pgoff, u32 pid, char *filename, |
92 | enum map_type type); | 92 | enum map_type type); |
93 | struct map *map__new2(u64 start, struct dso *dso, enum map_type type); | 93 | struct map *map__new2(u64 start, struct dso *dso, enum map_type type); |
94 | void map__delete(struct map *self); | 94 | void map__delete(struct map *map); |
95 | struct map *map__clone(struct map *self); | 95 | struct map *map__clone(struct map *map); |
96 | int map__overlap(struct map *l, struct map *r); | 96 | int map__overlap(struct map *l, struct map *r); |
97 | size_t map__fprintf(struct map *self, FILE *fp); | 97 | size_t map__fprintf(struct map *map, FILE *fp); |
98 | size_t map__fprintf_dsoname(struct map *map, FILE *fp); | 98 | size_t map__fprintf_dsoname(struct map *map, FILE *fp); |
99 | 99 | ||
100 | int map__load(struct map *self, symbol_filter_t filter); | 100 | int map__load(struct map *map, symbol_filter_t filter); |
101 | struct symbol *map__find_symbol(struct map *self, | 101 | struct symbol *map__find_symbol(struct map *map, |
102 | u64 addr, symbol_filter_t filter); | 102 | u64 addr, symbol_filter_t filter); |
103 | struct symbol *map__find_symbol_by_name(struct map *self, const char *name, | 103 | struct symbol *map__find_symbol_by_name(struct map *map, const char *name, |
104 | symbol_filter_t filter); | 104 | symbol_filter_t filter); |
105 | void map__fixup_start(struct map *self); | 105 | void map__fixup_start(struct map *map); |
106 | void map__fixup_end(struct map *self); | 106 | void map__fixup_end(struct map *map); |
107 | 107 | ||
108 | void map__reloc_vmlinux(struct map *self); | 108 | void map__reloc_vmlinux(struct map *map); |
109 | 109 | ||
110 | size_t __map_groups__fprintf_maps(struct map_groups *mg, | 110 | size_t __map_groups__fprintf_maps(struct map_groups *mg, |
111 | enum map_type type, int verbose, FILE *fp); | 111 | enum map_type type, int verbose, FILE *fp); |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 2d8d53bec17e..c84f48cf9678 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -380,8 +380,8 @@ static int add_tracepoint(struct list_head **listp, int *idx, | |||
380 | return 0; | 380 | return 0; |
381 | } | 381 | } |
382 | 382 | ||
383 | static int add_tracepoint_multi(struct list_head **list, int *idx, | 383 | static int add_tracepoint_multi_event(struct list_head **list, int *idx, |
384 | char *sys_name, char *evt_name) | 384 | char *sys_name, char *evt_name) |
385 | { | 385 | { |
386 | char evt_path[MAXPATHLEN]; | 386 | char evt_path[MAXPATHLEN]; |
387 | struct dirent *evt_ent; | 387 | struct dirent *evt_ent; |
@@ -408,6 +408,47 @@ static int add_tracepoint_multi(struct list_head **list, int *idx, | |||
408 | ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name); | 408 | ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name); |
409 | } | 409 | } |
410 | 410 | ||
411 | closedir(evt_dir); | ||
412 | return ret; | ||
413 | } | ||
414 | |||
415 | static int add_tracepoint_event(struct list_head **list, int *idx, | ||
416 | char *sys_name, char *evt_name) | ||
417 | { | ||
418 | return strpbrk(evt_name, "*?") ? | ||
419 | add_tracepoint_multi_event(list, idx, sys_name, evt_name) : | ||
420 | add_tracepoint(list, idx, sys_name, evt_name); | ||
421 | } | ||
422 | |||
423 | static int add_tracepoint_multi_sys(struct list_head **list, int *idx, | ||
424 | char *sys_name, char *evt_name) | ||
425 | { | ||
426 | struct dirent *events_ent; | ||
427 | DIR *events_dir; | ||
428 | int ret = 0; | ||
429 | |||
430 | events_dir = opendir(tracing_events_path); | ||
431 | if (!events_dir) { | ||
432 | perror("Can't open event dir"); | ||
433 | return -1; | ||
434 | } | ||
435 | |||
436 | while (!ret && (events_ent = readdir(events_dir))) { | ||
437 | if (!strcmp(events_ent->d_name, ".") | ||
438 | || !strcmp(events_ent->d_name, "..") | ||
439 | || !strcmp(events_ent->d_name, "enable") | ||
440 | || !strcmp(events_ent->d_name, "header_event") | ||
441 | || !strcmp(events_ent->d_name, "header_page")) | ||
442 | continue; | ||
443 | |||
444 | if (!strglobmatch(events_ent->d_name, sys_name)) | ||
445 | continue; | ||
446 | |||
447 | ret = add_tracepoint_event(list, idx, events_ent->d_name, | ||
448 | evt_name); | ||
449 | } | ||
450 | |||
451 | closedir(events_dir); | ||
411 | return ret; | 452 | return ret; |
412 | } | 453 | } |
413 | 454 | ||
@@ -420,9 +461,10 @@ int parse_events_add_tracepoint(struct list_head **list, int *idx, | |||
420 | if (ret) | 461 | if (ret) |
421 | return ret; | 462 | return ret; |
422 | 463 | ||
423 | return strpbrk(event, "*?") ? | 464 | if (strpbrk(sys, "*?")) |
424 | add_tracepoint_multi(list, idx, sys, event) : | 465 | return add_tracepoint_multi_sys(list, idx, sys, event); |
425 | add_tracepoint(list, idx, sys, event); | 466 | else |
467 | return add_tracepoint_event(list, idx, sys, event); | ||
426 | } | 468 | } |
427 | 469 | ||
428 | static int | 470 | static int |
@@ -492,7 +534,7 @@ int parse_events_add_breakpoint(struct list_head **list, int *idx, | |||
492 | } | 534 | } |
493 | 535 | ||
494 | static int config_term(struct perf_event_attr *attr, | 536 | static int config_term(struct perf_event_attr *attr, |
495 | struct parse_events__term *term) | 537 | struct parse_events_term *term) |
496 | { | 538 | { |
497 | #define CHECK_TYPE_VAL(type) \ | 539 | #define CHECK_TYPE_VAL(type) \ |
498 | do { \ | 540 | do { \ |
@@ -537,7 +579,7 @@ do { \ | |||
537 | static int config_attr(struct perf_event_attr *attr, | 579 | static int config_attr(struct perf_event_attr *attr, |
538 | struct list_head *head, int fail) | 580 | struct list_head *head, int fail) |
539 | { | 581 | { |
540 | struct parse_events__term *term; | 582 | struct parse_events_term *term; |
541 | 583 | ||
542 | list_for_each_entry(term, head, list) | 584 | list_for_each_entry(term, head, list) |
543 | if (config_term(attr, term) && fail) | 585 | if (config_term(attr, term) && fail) |
@@ -563,14 +605,14 @@ int parse_events_add_numeric(struct list_head **list, int *idx, | |||
563 | return add_event(list, idx, &attr, NULL); | 605 | return add_event(list, idx, &attr, NULL); |
564 | } | 606 | } |
565 | 607 | ||
566 | static int parse_events__is_name_term(struct parse_events__term *term) | 608 | static int parse_events__is_name_term(struct parse_events_term *term) |
567 | { | 609 | { |
568 | return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME; | 610 | return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME; |
569 | } | 611 | } |
570 | 612 | ||
571 | static char *pmu_event_name(struct list_head *head_terms) | 613 | static char *pmu_event_name(struct list_head *head_terms) |
572 | { | 614 | { |
573 | struct parse_events__term *term; | 615 | struct parse_events_term *term; |
574 | 616 | ||
575 | list_for_each_entry(term, head_terms, list) | 617 | list_for_each_entry(term, head_terms, list) |
576 | if (parse_events__is_name_term(term)) | 618 | if (parse_events__is_name_term(term)) |
@@ -657,14 +699,6 @@ static int get_event_modifier(struct event_modifier *mod, char *str, | |||
657 | int exclude = eu | ek | eh; | 699 | int exclude = eu | ek | eh; |
658 | int exclude_GH = evsel ? evsel->exclude_GH : 0; | 700 | int exclude_GH = evsel ? evsel->exclude_GH : 0; |
659 | 701 | ||
660 | /* | ||
661 | * We are here for group and 'GH' was not set as event | ||
662 | * modifier and whatever event/group modifier override | ||
663 | * default 'GH' setup. | ||
664 | */ | ||
665 | if (evsel && !exclude_GH) | ||
666 | eH = eG = 0; | ||
667 | |||
668 | memset(mod, 0, sizeof(*mod)); | 702 | memset(mod, 0, sizeof(*mod)); |
669 | 703 | ||
670 | while (*str) { | 704 | while (*str) { |
@@ -814,7 +848,7 @@ static int parse_events__scanner(const char *str, void *data, int start_token) | |||
814 | */ | 848 | */ |
815 | int parse_events_terms(struct list_head *terms, const char *str) | 849 | int parse_events_terms(struct list_head *terms, const char *str) |
816 | { | 850 | { |
817 | struct parse_events_data__terms data = { | 851 | struct parse_events_terms data = { |
818 | .terms = NULL, | 852 | .terms = NULL, |
819 | }; | 853 | }; |
820 | int ret; | 854 | int ret; |
@@ -830,10 +864,9 @@ int parse_events_terms(struct list_head *terms, const char *str) | |||
830 | return ret; | 864 | return ret; |
831 | } | 865 | } |
832 | 866 | ||
833 | int parse_events(struct perf_evlist *evlist, const char *str, | 867 | int parse_events(struct perf_evlist *evlist, const char *str) |
834 | int unset __maybe_unused) | ||
835 | { | 868 | { |
836 | struct parse_events_data__events data = { | 869 | struct parse_events_evlist data = { |
837 | .list = LIST_HEAD_INIT(data.list), | 870 | .list = LIST_HEAD_INIT(data.list), |
838 | .idx = evlist->nr_entries, | 871 | .idx = evlist->nr_entries, |
839 | }; | 872 | }; |
@@ -843,6 +876,7 @@ int parse_events(struct perf_evlist *evlist, const char *str, | |||
843 | if (!ret) { | 876 | if (!ret) { |
844 | int entries = data.idx - evlist->nr_entries; | 877 | int entries = data.idx - evlist->nr_entries; |
845 | perf_evlist__splice_list_tail(evlist, &data.list, entries); | 878 | perf_evlist__splice_list_tail(evlist, &data.list, entries); |
879 | evlist->nr_groups += data.nr_groups; | ||
846 | return 0; | 880 | return 0; |
847 | } | 881 | } |
848 | 882 | ||
@@ -858,7 +892,7 @@ int parse_events_option(const struct option *opt, const char *str, | |||
858 | int unset __maybe_unused) | 892 | int unset __maybe_unused) |
859 | { | 893 | { |
860 | struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; | 894 | struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; |
861 | int ret = parse_events(evlist, str, unset); | 895 | int ret = parse_events(evlist, str); |
862 | 896 | ||
863 | if (ret) { | 897 | if (ret) { |
864 | fprintf(stderr, "invalid or unsupported event: '%s'\n", str); | 898 | fprintf(stderr, "invalid or unsupported event: '%s'\n", str); |
@@ -1121,16 +1155,16 @@ void print_events(const char *event_glob, bool name_only) | |||
1121 | print_tracepoint_events(NULL, NULL, name_only); | 1155 | print_tracepoint_events(NULL, NULL, name_only); |
1122 | } | 1156 | } |
1123 | 1157 | ||
1124 | int parse_events__is_hardcoded_term(struct parse_events__term *term) | 1158 | int parse_events__is_hardcoded_term(struct parse_events_term *term) |
1125 | { | 1159 | { |
1126 | return term->type_term != PARSE_EVENTS__TERM_TYPE_USER; | 1160 | return term->type_term != PARSE_EVENTS__TERM_TYPE_USER; |
1127 | } | 1161 | } |
1128 | 1162 | ||
1129 | static int new_term(struct parse_events__term **_term, int type_val, | 1163 | static int new_term(struct parse_events_term **_term, int type_val, |
1130 | int type_term, char *config, | 1164 | int type_term, char *config, |
1131 | char *str, u64 num) | 1165 | char *str, u64 num) |
1132 | { | 1166 | { |
1133 | struct parse_events__term *term; | 1167 | struct parse_events_term *term; |
1134 | 1168 | ||
1135 | term = zalloc(sizeof(*term)); | 1169 | term = zalloc(sizeof(*term)); |
1136 | if (!term) | 1170 | if (!term) |
@@ -1156,21 +1190,21 @@ static int new_term(struct parse_events__term **_term, int type_val, | |||
1156 | return 0; | 1190 | return 0; |
1157 | } | 1191 | } |
1158 | 1192 | ||
1159 | int parse_events__term_num(struct parse_events__term **term, | 1193 | int parse_events_term__num(struct parse_events_term **term, |
1160 | int type_term, char *config, u64 num) | 1194 | int type_term, char *config, u64 num) |
1161 | { | 1195 | { |
1162 | return new_term(term, PARSE_EVENTS__TERM_TYPE_NUM, type_term, | 1196 | return new_term(term, PARSE_EVENTS__TERM_TYPE_NUM, type_term, |
1163 | config, NULL, num); | 1197 | config, NULL, num); |
1164 | } | 1198 | } |
1165 | 1199 | ||
1166 | int parse_events__term_str(struct parse_events__term **term, | 1200 | int parse_events_term__str(struct parse_events_term **term, |
1167 | int type_term, char *config, char *str) | 1201 | int type_term, char *config, char *str) |
1168 | { | 1202 | { |
1169 | return new_term(term, PARSE_EVENTS__TERM_TYPE_STR, type_term, | 1203 | return new_term(term, PARSE_EVENTS__TERM_TYPE_STR, type_term, |
1170 | config, str, 0); | 1204 | config, str, 0); |
1171 | } | 1205 | } |
1172 | 1206 | ||
1173 | int parse_events__term_sym_hw(struct parse_events__term **term, | 1207 | int parse_events_term__sym_hw(struct parse_events_term **term, |
1174 | char *config, unsigned idx) | 1208 | char *config, unsigned idx) |
1175 | { | 1209 | { |
1176 | struct event_symbol *sym; | 1210 | struct event_symbol *sym; |
@@ -1188,8 +1222,8 @@ int parse_events__term_sym_hw(struct parse_events__term **term, | |||
1188 | (char *) "event", (char *) sym->symbol, 0); | 1222 | (char *) "event", (char *) sym->symbol, 0); |
1189 | } | 1223 | } |
1190 | 1224 | ||
1191 | int parse_events__term_clone(struct parse_events__term **new, | 1225 | int parse_events_term__clone(struct parse_events_term **new, |
1192 | struct parse_events__term *term) | 1226 | struct parse_events_term *term) |
1193 | { | 1227 | { |
1194 | return new_term(new, term->type_val, term->type_term, term->config, | 1228 | return new_term(new, term->type_val, term->type_term, term->config, |
1195 | term->val.str, term->val.num); | 1229 | term->val.str, term->val.num); |
@@ -1197,7 +1231,7 @@ int parse_events__term_clone(struct parse_events__term **new, | |||
1197 | 1231 | ||
1198 | void parse_events__free_terms(struct list_head *terms) | 1232 | void parse_events__free_terms(struct list_head *terms) |
1199 | { | 1233 | { |
1200 | struct parse_events__term *term, *h; | 1234 | struct parse_events_term *term, *h; |
1201 | 1235 | ||
1202 | list_for_each_entry_safe(term, h, terms, list) | 1236 | list_for_each_entry_safe(term, h, terms, list) |
1203 | free(term); | 1237 | free(term); |
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index b7af80b8bdda..8a4859315fd9 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h | |||
@@ -29,8 +29,7 @@ const char *event_type(int type); | |||
29 | 29 | ||
30 | extern int parse_events_option(const struct option *opt, const char *str, | 30 | extern int parse_events_option(const struct option *opt, const char *str, |
31 | int unset); | 31 | int unset); |
32 | extern int parse_events(struct perf_evlist *evlist, const char *str, | 32 | extern int parse_events(struct perf_evlist *evlist, const char *str); |
33 | int unset); | ||
34 | extern int parse_events_terms(struct list_head *terms, const char *str); | 33 | extern int parse_events_terms(struct list_head *terms, const char *str); |
35 | extern int parse_filter(const struct option *opt, const char *str, int unset); | 34 | extern int parse_filter(const struct option *opt, const char *str, int unset); |
36 | 35 | ||
@@ -51,7 +50,7 @@ enum { | |||
51 | PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE, | 50 | PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE, |
52 | }; | 51 | }; |
53 | 52 | ||
54 | struct parse_events__term { | 53 | struct parse_events_term { |
55 | char *config; | 54 | char *config; |
56 | union { | 55 | union { |
57 | char *str; | 56 | char *str; |
@@ -62,24 +61,25 @@ struct parse_events__term { | |||
62 | struct list_head list; | 61 | struct list_head list; |
63 | }; | 62 | }; |
64 | 63 | ||
65 | struct parse_events_data__events { | 64 | struct parse_events_evlist { |
66 | struct list_head list; | 65 | struct list_head list; |
67 | int idx; | 66 | int idx; |
67 | int nr_groups; | ||
68 | }; | 68 | }; |
69 | 69 | ||
70 | struct parse_events_data__terms { | 70 | struct parse_events_terms { |
71 | struct list_head *terms; | 71 | struct list_head *terms; |
72 | }; | 72 | }; |
73 | 73 | ||
74 | int parse_events__is_hardcoded_term(struct parse_events__term *term); | 74 | int parse_events__is_hardcoded_term(struct parse_events_term *term); |
75 | int parse_events__term_num(struct parse_events__term **_term, | 75 | int parse_events_term__num(struct parse_events_term **_term, |
76 | int type_term, char *config, u64 num); | 76 | int type_term, char *config, u64 num); |
77 | int parse_events__term_str(struct parse_events__term **_term, | 77 | int parse_events_term__str(struct parse_events_term **_term, |
78 | int type_term, char *config, char *str); | 78 | int type_term, char *config, char *str); |
79 | int parse_events__term_sym_hw(struct parse_events__term **term, | 79 | int parse_events_term__sym_hw(struct parse_events_term **term, |
80 | char *config, unsigned idx); | 80 | char *config, unsigned idx); |
81 | int parse_events__term_clone(struct parse_events__term **new, | 81 | int parse_events_term__clone(struct parse_events_term **new, |
82 | struct parse_events__term *term); | 82 | struct parse_events_term *term); |
83 | void parse_events__free_terms(struct list_head *terms); | 83 | void parse_events__free_terms(struct list_head *terms); |
84 | int parse_events__modifier_event(struct list_head *list, char *str, bool add); | 84 | int parse_events__modifier_event(struct list_head *list, char *str, bool add); |
85 | int parse_events__modifier_group(struct list_head *list, char *event_mod); | 85 | int parse_events__modifier_group(struct list_head *list, char *event_mod); |
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 0f9914ae6bac..afc44c18dfe1 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y | |||
@@ -1,5 +1,4 @@ | |||
1 | %pure-parser | 1 | %pure-parser |
2 | %name-prefix "parse_events_" | ||
3 | %parse-param {void *_data} | 2 | %parse-param {void *_data} |
4 | %parse-param {void *scanner} | 3 | %parse-param {void *scanner} |
5 | %lex-param {void* scanner} | 4 | %lex-param {void* scanner} |
@@ -23,6 +22,14 @@ do { \ | |||
23 | YYABORT; \ | 22 | YYABORT; \ |
24 | } while (0) | 23 | } while (0) |
25 | 24 | ||
25 | static inc_group_count(struct list_head *list, | ||
26 | struct parse_events_evlist *data) | ||
27 | { | ||
28 | /* Count groups only have more than 1 members */ | ||
29 | if (!list_is_last(list->next, list)) | ||
30 | data->nr_groups++; | ||
31 | } | ||
32 | |||
26 | %} | 33 | %} |
27 | 34 | ||
28 | %token PE_START_EVENTS PE_START_TERMS | 35 | %token PE_START_EVENTS PE_START_TERMS |
@@ -68,7 +75,7 @@ do { \ | |||
68 | char *str; | 75 | char *str; |
69 | u64 num; | 76 | u64 num; |
70 | struct list_head *head; | 77 | struct list_head *head; |
71 | struct parse_events__term *term; | 78 | struct parse_events_term *term; |
72 | } | 79 | } |
73 | %% | 80 | %% |
74 | 81 | ||
@@ -79,7 +86,7 @@ PE_START_TERMS start_terms | |||
79 | 86 | ||
80 | start_events: groups | 87 | start_events: groups |
81 | { | 88 | { |
82 | struct parse_events_data__events *data = _data; | 89 | struct parse_events_evlist *data = _data; |
83 | 90 | ||
84 | parse_events_update_lists($1, &data->list); | 91 | parse_events_update_lists($1, &data->list); |
85 | } | 92 | } |
@@ -123,6 +130,7 @@ PE_NAME '{' events '}' | |||
123 | { | 130 | { |
124 | struct list_head *list = $3; | 131 | struct list_head *list = $3; |
125 | 132 | ||
133 | inc_group_count(list, _data); | ||
126 | parse_events__set_leader($1, list); | 134 | parse_events__set_leader($1, list); |
127 | $$ = list; | 135 | $$ = list; |
128 | } | 136 | } |
@@ -131,6 +139,7 @@ PE_NAME '{' events '}' | |||
131 | { | 139 | { |
132 | struct list_head *list = $2; | 140 | struct list_head *list = $2; |
133 | 141 | ||
142 | inc_group_count(list, _data); | ||
134 | parse_events__set_leader(NULL, list); | 143 | parse_events__set_leader(NULL, list); |
135 | $$ = list; | 144 | $$ = list; |
136 | } | 145 | } |
@@ -186,7 +195,7 @@ event_def: event_pmu | | |||
186 | event_pmu: | 195 | event_pmu: |
187 | PE_NAME '/' event_config '/' | 196 | PE_NAME '/' event_config '/' |
188 | { | 197 | { |
189 | struct parse_events_data__events *data = _data; | 198 | struct parse_events_evlist *data = _data; |
190 | struct list_head *list = NULL; | 199 | struct list_head *list = NULL; |
191 | 200 | ||
192 | ABORT_ON(parse_events_add_pmu(&list, &data->idx, $1, $3)); | 201 | ABORT_ON(parse_events_add_pmu(&list, &data->idx, $1, $3)); |
@@ -202,7 +211,7 @@ PE_VALUE_SYM_SW | |||
202 | event_legacy_symbol: | 211 | event_legacy_symbol: |
203 | value_sym '/' event_config '/' | 212 | value_sym '/' event_config '/' |
204 | { | 213 | { |
205 | struct parse_events_data__events *data = _data; | 214 | struct parse_events_evlist *data = _data; |
206 | struct list_head *list = NULL; | 215 | struct list_head *list = NULL; |
207 | int type = $1 >> 16; | 216 | int type = $1 >> 16; |
208 | int config = $1 & 255; | 217 | int config = $1 & 255; |
@@ -215,7 +224,7 @@ value_sym '/' event_config '/' | |||
215 | | | 224 | | |
216 | value_sym sep_slash_dc | 225 | value_sym sep_slash_dc |
217 | { | 226 | { |
218 | struct parse_events_data__events *data = _data; | 227 | struct parse_events_evlist *data = _data; |
219 | struct list_head *list = NULL; | 228 | struct list_head *list = NULL; |
220 | int type = $1 >> 16; | 229 | int type = $1 >> 16; |
221 | int config = $1 & 255; | 230 | int config = $1 & 255; |
@@ -228,7 +237,7 @@ value_sym sep_slash_dc | |||
228 | event_legacy_cache: | 237 | event_legacy_cache: |
229 | PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT | 238 | PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT |
230 | { | 239 | { |
231 | struct parse_events_data__events *data = _data; | 240 | struct parse_events_evlist *data = _data; |
232 | struct list_head *list = NULL; | 241 | struct list_head *list = NULL; |
233 | 242 | ||
234 | ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, $5)); | 243 | ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, $5)); |
@@ -237,7 +246,7 @@ PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT | |||
237 | | | 246 | | |
238 | PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT | 247 | PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT |
239 | { | 248 | { |
240 | struct parse_events_data__events *data = _data; | 249 | struct parse_events_evlist *data = _data; |
241 | struct list_head *list = NULL; | 250 | struct list_head *list = NULL; |
242 | 251 | ||
243 | ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, NULL)); | 252 | ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, NULL)); |
@@ -246,7 +255,7 @@ PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT | |||
246 | | | 255 | | |
247 | PE_NAME_CACHE_TYPE | 256 | PE_NAME_CACHE_TYPE |
248 | { | 257 | { |
249 | struct parse_events_data__events *data = _data; | 258 | struct parse_events_evlist *data = _data; |
250 | struct list_head *list = NULL; | 259 | struct list_head *list = NULL; |
251 | 260 | ||
252 | ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, NULL, NULL)); | 261 | ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, NULL, NULL)); |
@@ -256,7 +265,7 @@ PE_NAME_CACHE_TYPE | |||
256 | event_legacy_mem: | 265 | event_legacy_mem: |
257 | PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc | 266 | PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc |
258 | { | 267 | { |
259 | struct parse_events_data__events *data = _data; | 268 | struct parse_events_evlist *data = _data; |
260 | struct list_head *list = NULL; | 269 | struct list_head *list = NULL; |
261 | 270 | ||
262 | ABORT_ON(parse_events_add_breakpoint(&list, &data->idx, | 271 | ABORT_ON(parse_events_add_breakpoint(&list, &data->idx, |
@@ -266,7 +275,7 @@ PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc | |||
266 | | | 275 | | |
267 | PE_PREFIX_MEM PE_VALUE sep_dc | 276 | PE_PREFIX_MEM PE_VALUE sep_dc |
268 | { | 277 | { |
269 | struct parse_events_data__events *data = _data; | 278 | struct parse_events_evlist *data = _data; |
270 | struct list_head *list = NULL; | 279 | struct list_head *list = NULL; |
271 | 280 | ||
272 | ABORT_ON(parse_events_add_breakpoint(&list, &data->idx, | 281 | ABORT_ON(parse_events_add_breakpoint(&list, &data->idx, |
@@ -277,7 +286,7 @@ PE_PREFIX_MEM PE_VALUE sep_dc | |||
277 | event_legacy_tracepoint: | 286 | event_legacy_tracepoint: |
278 | PE_NAME ':' PE_NAME | 287 | PE_NAME ':' PE_NAME |
279 | { | 288 | { |
280 | struct parse_events_data__events *data = _data; | 289 | struct parse_events_evlist *data = _data; |
281 | struct list_head *list = NULL; | 290 | struct list_head *list = NULL; |
282 | 291 | ||
283 | ABORT_ON(parse_events_add_tracepoint(&list, &data->idx, $1, $3)); | 292 | ABORT_ON(parse_events_add_tracepoint(&list, &data->idx, $1, $3)); |
@@ -287,7 +296,7 @@ PE_NAME ':' PE_NAME | |||
287 | event_legacy_numeric: | 296 | event_legacy_numeric: |
288 | PE_VALUE ':' PE_VALUE | 297 | PE_VALUE ':' PE_VALUE |
289 | { | 298 | { |
290 | struct parse_events_data__events *data = _data; | 299 | struct parse_events_evlist *data = _data; |
291 | struct list_head *list = NULL; | 300 | struct list_head *list = NULL; |
292 | 301 | ||
293 | ABORT_ON(parse_events_add_numeric(&list, &data->idx, (u32)$1, $3, NULL)); | 302 | ABORT_ON(parse_events_add_numeric(&list, &data->idx, (u32)$1, $3, NULL)); |
@@ -297,7 +306,7 @@ PE_VALUE ':' PE_VALUE | |||
297 | event_legacy_raw: | 306 | event_legacy_raw: |
298 | PE_RAW | 307 | PE_RAW |
299 | { | 308 | { |
300 | struct parse_events_data__events *data = _data; | 309 | struct parse_events_evlist *data = _data; |
301 | struct list_head *list = NULL; | 310 | struct list_head *list = NULL; |
302 | 311 | ||
303 | ABORT_ON(parse_events_add_numeric(&list, &data->idx, | 312 | ABORT_ON(parse_events_add_numeric(&list, &data->idx, |
@@ -307,7 +316,7 @@ PE_RAW | |||
307 | 316 | ||
308 | start_terms: event_config | 317 | start_terms: event_config |
309 | { | 318 | { |
310 | struct parse_events_data__terms *data = _data; | 319 | struct parse_events_terms *data = _data; |
311 | data->terms = $1; | 320 | data->terms = $1; |
312 | } | 321 | } |
313 | 322 | ||
@@ -315,7 +324,7 @@ event_config: | |||
315 | event_config ',' event_term | 324 | event_config ',' event_term |
316 | { | 325 | { |
317 | struct list_head *head = $1; | 326 | struct list_head *head = $1; |
318 | struct parse_events__term *term = $3; | 327 | struct parse_events_term *term = $3; |
319 | 328 | ||
320 | ABORT_ON(!head); | 329 | ABORT_ON(!head); |
321 | list_add_tail(&term->list, head); | 330 | list_add_tail(&term->list, head); |
@@ -325,7 +334,7 @@ event_config ',' event_term | |||
325 | event_term | 334 | event_term |
326 | { | 335 | { |
327 | struct list_head *head = malloc(sizeof(*head)); | 336 | struct list_head *head = malloc(sizeof(*head)); |
328 | struct parse_events__term *term = $1; | 337 | struct parse_events_term *term = $1; |
329 | 338 | ||
330 | ABORT_ON(!head); | 339 | ABORT_ON(!head); |
331 | INIT_LIST_HEAD(head); | 340 | INIT_LIST_HEAD(head); |
@@ -336,70 +345,70 @@ event_term | |||
336 | event_term: | 345 | event_term: |
337 | PE_NAME '=' PE_NAME | 346 | PE_NAME '=' PE_NAME |
338 | { | 347 | { |
339 | struct parse_events__term *term; | 348 | struct parse_events_term *term; |
340 | 349 | ||
341 | ABORT_ON(parse_events__term_str(&term, PARSE_EVENTS__TERM_TYPE_USER, | 350 | ABORT_ON(parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_USER, |
342 | $1, $3)); | 351 | $1, $3)); |
343 | $$ = term; | 352 | $$ = term; |
344 | } | 353 | } |
345 | | | 354 | | |
346 | PE_NAME '=' PE_VALUE | 355 | PE_NAME '=' PE_VALUE |
347 | { | 356 | { |
348 | struct parse_events__term *term; | 357 | struct parse_events_term *term; |
349 | 358 | ||
350 | ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER, | 359 | ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER, |
351 | $1, $3)); | 360 | $1, $3)); |
352 | $$ = term; | 361 | $$ = term; |
353 | } | 362 | } |
354 | | | 363 | | |
355 | PE_NAME '=' PE_VALUE_SYM_HW | 364 | PE_NAME '=' PE_VALUE_SYM_HW |
356 | { | 365 | { |
357 | struct parse_events__term *term; | 366 | struct parse_events_term *term; |
358 | int config = $3 & 255; | 367 | int config = $3 & 255; |
359 | 368 | ||
360 | ABORT_ON(parse_events__term_sym_hw(&term, $1, config)); | 369 | ABORT_ON(parse_events_term__sym_hw(&term, $1, config)); |
361 | $$ = term; | 370 | $$ = term; |
362 | } | 371 | } |
363 | | | 372 | | |
364 | PE_NAME | 373 | PE_NAME |
365 | { | 374 | { |
366 | struct parse_events__term *term; | 375 | struct parse_events_term *term; |
367 | 376 | ||
368 | ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER, | 377 | ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER, |
369 | $1, 1)); | 378 | $1, 1)); |
370 | $$ = term; | 379 | $$ = term; |
371 | } | 380 | } |
372 | | | 381 | | |
373 | PE_VALUE_SYM_HW | 382 | PE_VALUE_SYM_HW |
374 | { | 383 | { |
375 | struct parse_events__term *term; | 384 | struct parse_events_term *term; |
376 | int config = $1 & 255; | 385 | int config = $1 & 255; |
377 | 386 | ||
378 | ABORT_ON(parse_events__term_sym_hw(&term, NULL, config)); | 387 | ABORT_ON(parse_events_term__sym_hw(&term, NULL, config)); |
379 | $$ = term; | 388 | $$ = term; |
380 | } | 389 | } |
381 | | | 390 | | |
382 | PE_TERM '=' PE_NAME | 391 | PE_TERM '=' PE_NAME |
383 | { | 392 | { |
384 | struct parse_events__term *term; | 393 | struct parse_events_term *term; |
385 | 394 | ||
386 | ABORT_ON(parse_events__term_str(&term, (int)$1, NULL, $3)); | 395 | ABORT_ON(parse_events_term__str(&term, (int)$1, NULL, $3)); |
387 | $$ = term; | 396 | $$ = term; |
388 | } | 397 | } |
389 | | | 398 | | |
390 | PE_TERM '=' PE_VALUE | 399 | PE_TERM '=' PE_VALUE |
391 | { | 400 | { |
392 | struct parse_events__term *term; | 401 | struct parse_events_term *term; |
393 | 402 | ||
394 | ABORT_ON(parse_events__term_num(&term, (int)$1, NULL, $3)); | 403 | ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, $3)); |
395 | $$ = term; | 404 | $$ = term; |
396 | } | 405 | } |
397 | | | 406 | | |
398 | PE_TERM | 407 | PE_TERM |
399 | { | 408 | { |
400 | struct parse_events__term *term; | 409 | struct parse_events_term *term; |
401 | 410 | ||
402 | ABORT_ON(parse_events__term_num(&term, (int)$1, NULL, 1)); | 411 | ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, 1)); |
403 | $$ = term; | 412 | $$ = term; |
404 | } | 413 | } |
405 | 414 | ||
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 9bdc60c6f138..4c6f9c490a8d 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c | |||
@@ -1,4 +1,3 @@ | |||
1 | |||
2 | #include <linux/list.h> | 1 | #include <linux/list.h> |
3 | #include <sys/types.h> | 2 | #include <sys/types.h> |
4 | #include <sys/stat.h> | 3 | #include <sys/stat.h> |
@@ -11,6 +10,19 @@ | |||
11 | #include "parse-events.h" | 10 | #include "parse-events.h" |
12 | #include "cpumap.h" | 11 | #include "cpumap.h" |
13 | 12 | ||
13 | struct perf_pmu_alias { | ||
14 | char *name; | ||
15 | struct list_head terms; | ||
16 | struct list_head list; | ||
17 | }; | ||
18 | |||
19 | struct perf_pmu_format { | ||
20 | char *name; | ||
21 | int value; | ||
22 | DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS); | ||
23 | struct list_head list; | ||
24 | }; | ||
25 | |||
14 | #define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/" | 26 | #define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/" |
15 | 27 | ||
16 | int perf_pmu_parse(struct list_head *list, char *name); | 28 | int perf_pmu_parse(struct list_head *list, char *name); |
@@ -85,7 +97,7 @@ static int pmu_format(char *name, struct list_head *format) | |||
85 | 97 | ||
86 | static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file) | 98 | static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file) |
87 | { | 99 | { |
88 | struct perf_pmu__alias *alias; | 100 | struct perf_pmu_alias *alias; |
89 | char buf[256]; | 101 | char buf[256]; |
90 | int ret; | 102 | int ret; |
91 | 103 | ||
@@ -172,15 +184,15 @@ static int pmu_aliases(char *name, struct list_head *head) | |||
172 | return 0; | 184 | return 0; |
173 | } | 185 | } |
174 | 186 | ||
175 | static int pmu_alias_terms(struct perf_pmu__alias *alias, | 187 | static int pmu_alias_terms(struct perf_pmu_alias *alias, |
176 | struct list_head *terms) | 188 | struct list_head *terms) |
177 | { | 189 | { |
178 | struct parse_events__term *term, *clone; | 190 | struct parse_events_term *term, *clone; |
179 | LIST_HEAD(list); | 191 | LIST_HEAD(list); |
180 | int ret; | 192 | int ret; |
181 | 193 | ||
182 | list_for_each_entry(term, &alias->terms, list) { | 194 | list_for_each_entry(term, &alias->terms, list) { |
183 | ret = parse_events__term_clone(&clone, term); | 195 | ret = parse_events_term__clone(&clone, term); |
184 | if (ret) { | 196 | if (ret) { |
185 | parse_events__free_terms(&list); | 197 | parse_events__free_terms(&list); |
186 | return ret; | 198 | return ret; |
@@ -360,10 +372,10 @@ struct perf_pmu *perf_pmu__find(char *name) | |||
360 | return pmu_lookup(name); | 372 | return pmu_lookup(name); |
361 | } | 373 | } |
362 | 374 | ||
363 | static struct perf_pmu__format* | 375 | static struct perf_pmu_format * |
364 | pmu_find_format(struct list_head *formats, char *name) | 376 | pmu_find_format(struct list_head *formats, char *name) |
365 | { | 377 | { |
366 | struct perf_pmu__format *format; | 378 | struct perf_pmu_format *format; |
367 | 379 | ||
368 | list_for_each_entry(format, formats, list) | 380 | list_for_each_entry(format, formats, list) |
369 | if (!strcmp(format->name, name)) | 381 | if (!strcmp(format->name, name)) |
@@ -403,9 +415,9 @@ static __u64 pmu_format_value(unsigned long *format, __u64 value) | |||
403 | */ | 415 | */ |
404 | static int pmu_config_term(struct list_head *formats, | 416 | static int pmu_config_term(struct list_head *formats, |
405 | struct perf_event_attr *attr, | 417 | struct perf_event_attr *attr, |
406 | struct parse_events__term *term) | 418 | struct parse_events_term *term) |
407 | { | 419 | { |
408 | struct perf_pmu__format *format; | 420 | struct perf_pmu_format *format; |
409 | __u64 *vp; | 421 | __u64 *vp; |
410 | 422 | ||
411 | /* | 423 | /* |
@@ -450,7 +462,7 @@ int perf_pmu__config_terms(struct list_head *formats, | |||
450 | struct perf_event_attr *attr, | 462 | struct perf_event_attr *attr, |
451 | struct list_head *head_terms) | 463 | struct list_head *head_terms) |
452 | { | 464 | { |
453 | struct parse_events__term *term; | 465 | struct parse_events_term *term; |
454 | 466 | ||
455 | list_for_each_entry(term, head_terms, list) | 467 | list_for_each_entry(term, head_terms, list) |
456 | if (pmu_config_term(formats, attr, term)) | 468 | if (pmu_config_term(formats, attr, term)) |
@@ -471,10 +483,10 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, | |||
471 | return perf_pmu__config_terms(&pmu->format, attr, head_terms); | 483 | return perf_pmu__config_terms(&pmu->format, attr, head_terms); |
472 | } | 484 | } |
473 | 485 | ||
474 | static struct perf_pmu__alias *pmu_find_alias(struct perf_pmu *pmu, | 486 | static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu, |
475 | struct parse_events__term *term) | 487 | struct parse_events_term *term) |
476 | { | 488 | { |
477 | struct perf_pmu__alias *alias; | 489 | struct perf_pmu_alias *alias; |
478 | char *name; | 490 | char *name; |
479 | 491 | ||
480 | if (parse_events__is_hardcoded_term(term)) | 492 | if (parse_events__is_hardcoded_term(term)) |
@@ -507,8 +519,8 @@ static struct perf_pmu__alias *pmu_find_alias(struct perf_pmu *pmu, | |||
507 | */ | 519 | */ |
508 | int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms) | 520 | int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms) |
509 | { | 521 | { |
510 | struct parse_events__term *term, *h; | 522 | struct parse_events_term *term, *h; |
511 | struct perf_pmu__alias *alias; | 523 | struct perf_pmu_alias *alias; |
512 | int ret; | 524 | int ret; |
513 | 525 | ||
514 | list_for_each_entry_safe(term, h, head_terms, list) { | 526 | list_for_each_entry_safe(term, h, head_terms, list) { |
@@ -527,7 +539,7 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms) | |||
527 | int perf_pmu__new_format(struct list_head *list, char *name, | 539 | int perf_pmu__new_format(struct list_head *list, char *name, |
528 | int config, unsigned long *bits) | 540 | int config, unsigned long *bits) |
529 | { | 541 | { |
530 | struct perf_pmu__format *format; | 542 | struct perf_pmu_format *format; |
531 | 543 | ||
532 | format = zalloc(sizeof(*format)); | 544 | format = zalloc(sizeof(*format)); |
533 | if (!format) | 545 | if (!format) |
@@ -548,7 +560,7 @@ void perf_pmu__set_format(unsigned long *bits, long from, long to) | |||
548 | if (!to) | 560 | if (!to) |
549 | to = from; | 561 | to = from; |
550 | 562 | ||
551 | memset(bits, 0, BITS_TO_LONGS(PERF_PMU_FORMAT_BITS)); | 563 | memset(bits, 0, BITS_TO_BYTES(PERF_PMU_FORMAT_BITS)); |
552 | for (b = from; b <= to; b++) | 564 | for (b = from; b <= to; b++) |
553 | set_bit(b, bits); | 565 | set_bit(b, bits); |
554 | } | 566 | } |
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index a313ed76a49a..32fe55b659fa 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h | |||
@@ -12,19 +12,6 @@ enum { | |||
12 | 12 | ||
13 | #define PERF_PMU_FORMAT_BITS 64 | 13 | #define PERF_PMU_FORMAT_BITS 64 |
14 | 14 | ||
15 | struct perf_pmu__format { | ||
16 | char *name; | ||
17 | int value; | ||
18 | DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS); | ||
19 | struct list_head list; | ||
20 | }; | ||
21 | |||
22 | struct perf_pmu__alias { | ||
23 | char *name; | ||
24 | struct list_head terms; | ||
25 | struct list_head list; | ||
26 | }; | ||
27 | |||
28 | struct perf_pmu { | 15 | struct perf_pmu { |
29 | char *name; | 16 | char *name; |
30 | __u32 type; | 17 | __u32 type; |
@@ -42,7 +29,7 @@ int perf_pmu__config_terms(struct list_head *formats, | |||
42 | struct list_head *head_terms); | 29 | struct list_head *head_terms); |
43 | int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms); | 30 | int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms); |
44 | struct list_head *perf_pmu__alias(struct perf_pmu *pmu, | 31 | struct list_head *perf_pmu__alias(struct perf_pmu *pmu, |
45 | struct list_head *head_terms); | 32 | struct list_head *head_terms); |
46 | int perf_pmu_wrap(void); | 33 | int perf_pmu_wrap(void); |
47 | void perf_pmu_error(struct list_head *list, char *name, char const *msg); | 34 | void perf_pmu_error(struct list_head *list, char *name, char const *msg); |
48 | 35 | ||
diff --git a/tools/perf/util/pmu.y b/tools/perf/util/pmu.y index ec898047ebb9..bfd7e8509869 100644 --- a/tools/perf/util/pmu.y +++ b/tools/perf/util/pmu.y | |||
@@ -1,5 +1,4 @@ | |||
1 | 1 | ||
2 | %name-prefix "perf_pmu_" | ||
3 | %parse-param {struct list_head *format} | 2 | %parse-param {struct list_head *format} |
4 | %parse-param {char *name} | 3 | %parse-param {char *name} |
5 | 4 | ||
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 1daf5c14e751..be0329394d56 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -413,12 +413,12 @@ static int convert_variable_type(Dwarf_Die *vr_die, | |||
413 | dwarf_diename(vr_die), dwarf_diename(&type)); | 413 | dwarf_diename(vr_die), dwarf_diename(&type)); |
414 | return -EINVAL; | 414 | return -EINVAL; |
415 | } | 415 | } |
416 | if (die_get_real_type(&type, &type) == NULL) { | ||
417 | pr_warning("Failed to get a type" | ||
418 | " information.\n"); | ||
419 | return -ENOENT; | ||
420 | } | ||
416 | if (ret == DW_TAG_pointer_type) { | 421 | if (ret == DW_TAG_pointer_type) { |
417 | if (die_get_real_type(&type, &type) == NULL) { | ||
418 | pr_warning("Failed to get a type" | ||
419 | " information.\n"); | ||
420 | return -ENOENT; | ||
421 | } | ||
422 | while (*ref_ptr) | 422 | while (*ref_ptr) |
423 | ref_ptr = &(*ref_ptr)->next; | 423 | ref_ptr = &(*ref_ptr)->next; |
424 | /* Add new reference with offset +0 */ | 424 | /* Add new reference with offset +0 */ |
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources index c40c2d33199e..64536a993f4a 100644 --- a/tools/perf/util/python-ext-sources +++ b/tools/perf/util/python-ext-sources | |||
@@ -18,4 +18,5 @@ util/cgroup.c | |||
18 | util/debugfs.c | 18 | util/debugfs.c |
19 | util/rblist.c | 19 | util/rblist.c |
20 | util/strlist.c | 20 | util/strlist.c |
21 | util/sysfs.c | ||
21 | ../../lib/rbtree.c | 22 | ../../lib/rbtree.c |
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index a2657fd96837..925e0c3e6d91 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c | |||
@@ -1045,3 +1045,12 @@ error: | |||
1045 | if (PyErr_Occurred()) | 1045 | if (PyErr_Occurred()) |
1046 | PyErr_SetString(PyExc_ImportError, "perf: Init failed!"); | 1046 | PyErr_SetString(PyExc_ImportError, "perf: Init failed!"); |
1047 | } | 1047 | } |
1048 | |||
1049 | /* | ||
1050 | * Dummy, to avoid dragging all the test_attr infrastructure in the python | ||
1051 | * binding. | ||
1052 | */ | ||
1053 | void test_attr__open(struct perf_event_attr *attr, pid_t pid, int cpu, | ||
1054 | int fd, int group_fd, unsigned long flags) | ||
1055 | { | ||
1056 | } | ||
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index f80605eb1855..eacec859f299 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c | |||
@@ -292,6 +292,7 @@ static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused, | |||
292 | ns = nsecs - s * NSECS_PER_SEC; | 292 | ns = nsecs - s * NSECS_PER_SEC; |
293 | 293 | ||
294 | scripting_context->event_data = data; | 294 | scripting_context->event_data = data; |
295 | scripting_context->pevent = evsel->tp_format->pevent; | ||
295 | 296 | ||
296 | ENTER; | 297 | ENTER; |
297 | SAVETMPS; | 298 | SAVETMPS; |
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 14683dfca2ee..e87aa5d9696b 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c | |||
@@ -265,6 +265,7 @@ static void python_process_tracepoint(union perf_event *perf_event | |||
265 | ns = nsecs - s * NSECS_PER_SEC; | 265 | ns = nsecs - s * NSECS_PER_SEC; |
266 | 266 | ||
267 | scripting_context->event_data = data; | 267 | scripting_context->event_data = data; |
268 | scripting_context->pevent = evsel->tp_format->pevent; | ||
268 | 269 | ||
269 | context = PyCObject_FromVoidPtr(scripting_context, NULL); | 270 | context = PyCObject_FromVoidPtr(scripting_context, NULL); |
270 | 271 | ||
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index ce6f51162386..bd85280bb6e8 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -16,7 +16,6 @@ | |||
16 | #include "cpumap.h" | 16 | #include "cpumap.h" |
17 | #include "event-parse.h" | 17 | #include "event-parse.h" |
18 | #include "perf_regs.h" | 18 | #include "perf_regs.h" |
19 | #include "unwind.h" | ||
20 | #include "vdso.h" | 19 | #include "vdso.h" |
21 | 20 | ||
22 | static int perf_session__open(struct perf_session *self, bool force) | 21 | static int perf_session__open(struct perf_session *self, bool force) |
@@ -87,13 +86,12 @@ void perf_session__set_id_hdr_size(struct perf_session *session) | |||
87 | { | 86 | { |
88 | u16 id_hdr_size = perf_evlist__id_hdr_size(session->evlist); | 87 | u16 id_hdr_size = perf_evlist__id_hdr_size(session->evlist); |
89 | 88 | ||
90 | session->host_machine.id_hdr_size = id_hdr_size; | ||
91 | machines__set_id_hdr_size(&session->machines, id_hdr_size); | 89 | machines__set_id_hdr_size(&session->machines, id_hdr_size); |
92 | } | 90 | } |
93 | 91 | ||
94 | int perf_session__create_kernel_maps(struct perf_session *self) | 92 | int perf_session__create_kernel_maps(struct perf_session *self) |
95 | { | 93 | { |
96 | int ret = machine__create_kernel_maps(&self->host_machine); | 94 | int ret = machine__create_kernel_maps(&self->machines.host); |
97 | 95 | ||
98 | if (ret >= 0) | 96 | if (ret >= 0) |
99 | ret = machines__create_guest_kernel_maps(&self->machines); | 97 | ret = machines__create_guest_kernel_maps(&self->machines); |
@@ -102,8 +100,7 @@ int perf_session__create_kernel_maps(struct perf_session *self) | |||
102 | 100 | ||
103 | static void perf_session__destroy_kernel_maps(struct perf_session *self) | 101 | static void perf_session__destroy_kernel_maps(struct perf_session *self) |
104 | { | 102 | { |
105 | machine__destroy_kernel_maps(&self->host_machine); | 103 | machines__destroy_kernel_maps(&self->machines); |
106 | machines__destroy_guest_kernel_maps(&self->machines); | ||
107 | } | 104 | } |
108 | 105 | ||
109 | struct perf_session *perf_session__new(const char *filename, int mode, | 106 | struct perf_session *perf_session__new(const char *filename, int mode, |
@@ -128,22 +125,11 @@ struct perf_session *perf_session__new(const char *filename, int mode, | |||
128 | goto out; | 125 | goto out; |
129 | 126 | ||
130 | memcpy(self->filename, filename, len); | 127 | memcpy(self->filename, filename, len); |
131 | /* | ||
132 | * On 64bit we can mmap the data file in one go. No need for tiny mmap | ||
133 | * slices. On 32bit we use 32MB. | ||
134 | */ | ||
135 | #if BITS_PER_LONG == 64 | ||
136 | self->mmap_window = ULLONG_MAX; | ||
137 | #else | ||
138 | self->mmap_window = 32 * 1024 * 1024ULL; | ||
139 | #endif | ||
140 | self->machines = RB_ROOT; | ||
141 | self->repipe = repipe; | 128 | self->repipe = repipe; |
142 | INIT_LIST_HEAD(&self->ordered_samples.samples); | 129 | INIT_LIST_HEAD(&self->ordered_samples.samples); |
143 | INIT_LIST_HEAD(&self->ordered_samples.sample_cache); | 130 | INIT_LIST_HEAD(&self->ordered_samples.sample_cache); |
144 | INIT_LIST_HEAD(&self->ordered_samples.to_free); | 131 | INIT_LIST_HEAD(&self->ordered_samples.to_free); |
145 | machine__init(&self->host_machine, "", HOST_KERNEL_ID); | 132 | machines__init(&self->machines); |
146 | hists__init(&self->hists); | ||
147 | 133 | ||
148 | if (mode == O_RDONLY) { | 134 | if (mode == O_RDONLY) { |
149 | if (perf_session__open(self, force) < 0) | 135 | if (perf_session__open(self, force) < 0) |
@@ -171,37 +157,30 @@ out_delete: | |||
171 | return NULL; | 157 | return NULL; |
172 | } | 158 | } |
173 | 159 | ||
174 | static void machine__delete_dead_threads(struct machine *machine) | ||
175 | { | ||
176 | struct thread *n, *t; | ||
177 | |||
178 | list_for_each_entry_safe(t, n, &machine->dead_threads, node) { | ||
179 | list_del(&t->node); | ||
180 | thread__delete(t); | ||
181 | } | ||
182 | } | ||
183 | |||
184 | static void perf_session__delete_dead_threads(struct perf_session *session) | 160 | static void perf_session__delete_dead_threads(struct perf_session *session) |
185 | { | 161 | { |
186 | machine__delete_dead_threads(&session->host_machine); | 162 | machine__delete_dead_threads(&session->machines.host); |
187 | } | 163 | } |
188 | 164 | ||
189 | static void machine__delete_threads(struct machine *self) | 165 | static void perf_session__delete_threads(struct perf_session *session) |
190 | { | 166 | { |
191 | struct rb_node *nd = rb_first(&self->threads); | 167 | machine__delete_threads(&session->machines.host); |
192 | |||
193 | while (nd) { | ||
194 | struct thread *t = rb_entry(nd, struct thread, rb_node); | ||
195 | |||
196 | rb_erase(&t->rb_node, &self->threads); | ||
197 | nd = rb_next(nd); | ||
198 | thread__delete(t); | ||
199 | } | ||
200 | } | 168 | } |
201 | 169 | ||
202 | static void perf_session__delete_threads(struct perf_session *session) | 170 | static void perf_session_env__delete(struct perf_session_env *env) |
203 | { | 171 | { |
204 | machine__delete_threads(&session->host_machine); | 172 | free(env->hostname); |
173 | free(env->os_release); | ||
174 | free(env->version); | ||
175 | free(env->arch); | ||
176 | free(env->cpu_desc); | ||
177 | free(env->cpuid); | ||
178 | |||
179 | free(env->cmdline); | ||
180 | free(env->sibling_cores); | ||
181 | free(env->sibling_threads); | ||
182 | free(env->numa_nodes); | ||
183 | free(env->pmu_mappings); | ||
205 | } | 184 | } |
206 | 185 | ||
207 | void perf_session__delete(struct perf_session *self) | 186 | void perf_session__delete(struct perf_session *self) |
@@ -209,198 +188,13 @@ void perf_session__delete(struct perf_session *self) | |||
209 | perf_session__destroy_kernel_maps(self); | 188 | perf_session__destroy_kernel_maps(self); |
210 | perf_session__delete_dead_threads(self); | 189 | perf_session__delete_dead_threads(self); |
211 | perf_session__delete_threads(self); | 190 | perf_session__delete_threads(self); |
212 | machine__exit(&self->host_machine); | 191 | perf_session_env__delete(&self->header.env); |
192 | machines__exit(&self->machines); | ||
213 | close(self->fd); | 193 | close(self->fd); |
214 | free(self); | 194 | free(self); |
215 | vdso__exit(); | 195 | vdso__exit(); |
216 | } | 196 | } |
217 | 197 | ||
218 | void machine__remove_thread(struct machine *self, struct thread *th) | ||
219 | { | ||
220 | self->last_match = NULL; | ||
221 | rb_erase(&th->rb_node, &self->threads); | ||
222 | /* | ||
223 | * We may have references to this thread, for instance in some hist_entry | ||
224 | * instances, so just move them to a separate list. | ||
225 | */ | ||
226 | list_add_tail(&th->node, &self->dead_threads); | ||
227 | } | ||
228 | |||
229 | static bool symbol__match_parent_regex(struct symbol *sym) | ||
230 | { | ||
231 | if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0)) | ||
232 | return 1; | ||
233 | |||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | static const u8 cpumodes[] = { | ||
238 | PERF_RECORD_MISC_USER, | ||
239 | PERF_RECORD_MISC_KERNEL, | ||
240 | PERF_RECORD_MISC_GUEST_USER, | ||
241 | PERF_RECORD_MISC_GUEST_KERNEL | ||
242 | }; | ||
243 | #define NCPUMODES (sizeof(cpumodes)/sizeof(u8)) | ||
244 | |||
245 | static void ip__resolve_ams(struct machine *self, struct thread *thread, | ||
246 | struct addr_map_symbol *ams, | ||
247 | u64 ip) | ||
248 | { | ||
249 | struct addr_location al; | ||
250 | size_t i; | ||
251 | u8 m; | ||
252 | |||
253 | memset(&al, 0, sizeof(al)); | ||
254 | |||
255 | for (i = 0; i < NCPUMODES; i++) { | ||
256 | m = cpumodes[i]; | ||
257 | /* | ||
258 | * We cannot use the header.misc hint to determine whether a | ||
259 | * branch stack address is user, kernel, guest, hypervisor. | ||
260 | * Branches may straddle the kernel/user/hypervisor boundaries. | ||
261 | * Thus, we have to try consecutively until we find a match | ||
262 | * or else, the symbol is unknown | ||
263 | */ | ||
264 | thread__find_addr_location(thread, self, m, MAP__FUNCTION, | ||
265 | ip, &al, NULL); | ||
266 | if (al.sym) | ||
267 | goto found; | ||
268 | } | ||
269 | found: | ||
270 | ams->addr = ip; | ||
271 | ams->al_addr = al.addr; | ||
272 | ams->sym = al.sym; | ||
273 | ams->map = al.map; | ||
274 | } | ||
275 | |||
276 | struct branch_info *machine__resolve_bstack(struct machine *self, | ||
277 | struct thread *thr, | ||
278 | struct branch_stack *bs) | ||
279 | { | ||
280 | struct branch_info *bi; | ||
281 | unsigned int i; | ||
282 | |||
283 | bi = calloc(bs->nr, sizeof(struct branch_info)); | ||
284 | if (!bi) | ||
285 | return NULL; | ||
286 | |||
287 | for (i = 0; i < bs->nr; i++) { | ||
288 | ip__resolve_ams(self, thr, &bi[i].to, bs->entries[i].to); | ||
289 | ip__resolve_ams(self, thr, &bi[i].from, bs->entries[i].from); | ||
290 | bi[i].flags = bs->entries[i].flags; | ||
291 | } | ||
292 | return bi; | ||
293 | } | ||
294 | |||
295 | static int machine__resolve_callchain_sample(struct machine *machine, | ||
296 | struct thread *thread, | ||
297 | struct ip_callchain *chain, | ||
298 | struct symbol **parent) | ||
299 | |||
300 | { | ||
301 | u8 cpumode = PERF_RECORD_MISC_USER; | ||
302 | unsigned int i; | ||
303 | int err; | ||
304 | |||
305 | callchain_cursor_reset(&callchain_cursor); | ||
306 | |||
307 | if (chain->nr > PERF_MAX_STACK_DEPTH) { | ||
308 | pr_warning("corrupted callchain. skipping...\n"); | ||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | for (i = 0; i < chain->nr; i++) { | ||
313 | u64 ip; | ||
314 | struct addr_location al; | ||
315 | |||
316 | if (callchain_param.order == ORDER_CALLEE) | ||
317 | ip = chain->ips[i]; | ||
318 | else | ||
319 | ip = chain->ips[chain->nr - i - 1]; | ||
320 | |||
321 | if (ip >= PERF_CONTEXT_MAX) { | ||
322 | switch (ip) { | ||
323 | case PERF_CONTEXT_HV: | ||
324 | cpumode = PERF_RECORD_MISC_HYPERVISOR; | ||
325 | break; | ||
326 | case PERF_CONTEXT_KERNEL: | ||
327 | cpumode = PERF_RECORD_MISC_KERNEL; | ||
328 | break; | ||
329 | case PERF_CONTEXT_USER: | ||
330 | cpumode = PERF_RECORD_MISC_USER; | ||
331 | break; | ||
332 | default: | ||
333 | pr_debug("invalid callchain context: " | ||
334 | "%"PRId64"\n", (s64) ip); | ||
335 | /* | ||
336 | * It seems the callchain is corrupted. | ||
337 | * Discard all. | ||
338 | */ | ||
339 | callchain_cursor_reset(&callchain_cursor); | ||
340 | return 0; | ||
341 | } | ||
342 | continue; | ||
343 | } | ||
344 | |||
345 | al.filtered = false; | ||
346 | thread__find_addr_location(thread, machine, cpumode, | ||
347 | MAP__FUNCTION, ip, &al, NULL); | ||
348 | if (al.sym != NULL) { | ||
349 | if (sort__has_parent && !*parent && | ||
350 | symbol__match_parent_regex(al.sym)) | ||
351 | *parent = al.sym; | ||
352 | if (!symbol_conf.use_callchain) | ||
353 | break; | ||
354 | } | ||
355 | |||
356 | err = callchain_cursor_append(&callchain_cursor, | ||
357 | ip, al.map, al.sym); | ||
358 | if (err) | ||
359 | return err; | ||
360 | } | ||
361 | |||
362 | return 0; | ||
363 | } | ||
364 | |||
365 | static int unwind_entry(struct unwind_entry *entry, void *arg) | ||
366 | { | ||
367 | struct callchain_cursor *cursor = arg; | ||
368 | return callchain_cursor_append(cursor, entry->ip, | ||
369 | entry->map, entry->sym); | ||
370 | } | ||
371 | |||
372 | int machine__resolve_callchain(struct machine *machine, | ||
373 | struct perf_evsel *evsel, | ||
374 | struct thread *thread, | ||
375 | struct perf_sample *sample, | ||
376 | struct symbol **parent) | ||
377 | |||
378 | { | ||
379 | int ret; | ||
380 | |||
381 | callchain_cursor_reset(&callchain_cursor); | ||
382 | |||
383 | ret = machine__resolve_callchain_sample(machine, thread, | ||
384 | sample->callchain, parent); | ||
385 | if (ret) | ||
386 | return ret; | ||
387 | |||
388 | /* Can we do dwarf post unwind? */ | ||
389 | if (!((evsel->attr.sample_type & PERF_SAMPLE_REGS_USER) && | ||
390 | (evsel->attr.sample_type & PERF_SAMPLE_STACK_USER))) | ||
391 | return 0; | ||
392 | |||
393 | /* Bail out if nothing was captured. */ | ||
394 | if ((!sample->user_regs.regs) || | ||
395 | (!sample->user_stack.size)) | ||
396 | return 0; | ||
397 | |||
398 | return unwind__get_entries(unwind_entry, &callchain_cursor, machine, | ||
399 | thread, evsel->attr.sample_regs_user, | ||
400 | sample); | ||
401 | |||
402 | } | ||
403 | |||
404 | static int process_event_synth_tracing_data_stub(union perf_event *event | 198 | static int process_event_synth_tracing_data_stub(union perf_event *event |
405 | __maybe_unused, | 199 | __maybe_unused, |
406 | struct perf_session *session | 200 | struct perf_session *session |
@@ -1027,7 +821,7 @@ static struct machine * | |||
1027 | return perf_session__findnew_machine(session, pid); | 821 | return perf_session__findnew_machine(session, pid); |
1028 | } | 822 | } |
1029 | 823 | ||
1030 | return perf_session__find_host_machine(session); | 824 | return &session->machines.host; |
1031 | } | 825 | } |
1032 | 826 | ||
1033 | static int perf_session_deliver_event(struct perf_session *session, | 827 | static int perf_session_deliver_event(struct perf_session *session, |
@@ -1065,11 +859,11 @@ static int perf_session_deliver_event(struct perf_session *session, | |||
1065 | case PERF_RECORD_SAMPLE: | 859 | case PERF_RECORD_SAMPLE: |
1066 | dump_sample(evsel, event, sample); | 860 | dump_sample(evsel, event, sample); |
1067 | if (evsel == NULL) { | 861 | if (evsel == NULL) { |
1068 | ++session->hists.stats.nr_unknown_id; | 862 | ++session->stats.nr_unknown_id; |
1069 | return 0; | 863 | return 0; |
1070 | } | 864 | } |
1071 | if (machine == NULL) { | 865 | if (machine == NULL) { |
1072 | ++session->hists.stats.nr_unprocessable_samples; | 866 | ++session->stats.nr_unprocessable_samples; |
1073 | return 0; | 867 | return 0; |
1074 | } | 868 | } |
1075 | return tool->sample(tool, event, sample, evsel, machine); | 869 | return tool->sample(tool, event, sample, evsel, machine); |
@@ -1083,7 +877,7 @@ static int perf_session_deliver_event(struct perf_session *session, | |||
1083 | return tool->exit(tool, event, sample, machine); | 877 | return tool->exit(tool, event, sample, machine); |
1084 | case PERF_RECORD_LOST: | 878 | case PERF_RECORD_LOST: |
1085 | if (tool->lost == perf_event__process_lost) | 879 | if (tool->lost == perf_event__process_lost) |
1086 | session->hists.stats.total_lost += event->lost.lost; | 880 | session->stats.total_lost += event->lost.lost; |
1087 | return tool->lost(tool, event, sample, machine); | 881 | return tool->lost(tool, event, sample, machine); |
1088 | case PERF_RECORD_READ: | 882 | case PERF_RECORD_READ: |
1089 | return tool->read(tool, event, sample, evsel, machine); | 883 | return tool->read(tool, event, sample, evsel, machine); |
@@ -1092,7 +886,7 @@ static int perf_session_deliver_event(struct perf_session *session, | |||
1092 | case PERF_RECORD_UNTHROTTLE: | 886 | case PERF_RECORD_UNTHROTTLE: |
1093 | return tool->unthrottle(tool, event, sample, machine); | 887 | return tool->unthrottle(tool, event, sample, machine); |
1094 | default: | 888 | default: |
1095 | ++session->hists.stats.nr_unknown_events; | 889 | ++session->stats.nr_unknown_events; |
1096 | return -1; | 890 | return -1; |
1097 | } | 891 | } |
1098 | } | 892 | } |
@@ -1106,8 +900,8 @@ static int perf_session__preprocess_sample(struct perf_session *session, | |||
1106 | 900 | ||
1107 | if (!ip_callchain__valid(sample->callchain, event)) { | 901 | if (!ip_callchain__valid(sample->callchain, event)) { |
1108 | pr_debug("call-chain problem with event, skipping it.\n"); | 902 | pr_debug("call-chain problem with event, skipping it.\n"); |
1109 | ++session->hists.stats.nr_invalid_chains; | 903 | ++session->stats.nr_invalid_chains; |
1110 | session->hists.stats.total_invalid_chains += sample->period; | 904 | session->stats.total_invalid_chains += sample->period; |
1111 | return -EINVAL; | 905 | return -EINVAL; |
1112 | } | 906 | } |
1113 | return 0; | 907 | return 0; |
@@ -1165,7 +959,7 @@ static int perf_session__process_event(struct perf_session *session, | |||
1165 | if (event->header.type >= PERF_RECORD_HEADER_MAX) | 959 | if (event->header.type >= PERF_RECORD_HEADER_MAX) |
1166 | return -EINVAL; | 960 | return -EINVAL; |
1167 | 961 | ||
1168 | hists__inc_nr_events(&session->hists, event->header.type); | 962 | events_stats__inc(&session->stats, event->header.type); |
1169 | 963 | ||
1170 | if (event->header.type >= PERF_RECORD_USER_TYPE_START) | 964 | if (event->header.type >= PERF_RECORD_USER_TYPE_START) |
1171 | return perf_session__process_user_event(session, event, tool, file_offset); | 965 | return perf_session__process_user_event(session, event, tool, file_offset); |
@@ -1201,7 +995,7 @@ void perf_event_header__bswap(struct perf_event_header *self) | |||
1201 | 995 | ||
1202 | struct thread *perf_session__findnew(struct perf_session *session, pid_t pid) | 996 | struct thread *perf_session__findnew(struct perf_session *session, pid_t pid) |
1203 | { | 997 | { |
1204 | return machine__findnew_thread(&session->host_machine, pid); | 998 | return machine__findnew_thread(&session->machines.host, pid); |
1205 | } | 999 | } |
1206 | 1000 | ||
1207 | static struct thread *perf_session__register_idle_thread(struct perf_session *self) | 1001 | static struct thread *perf_session__register_idle_thread(struct perf_session *self) |
@@ -1220,39 +1014,39 @@ static void perf_session__warn_about_errors(const struct perf_session *session, | |||
1220 | const struct perf_tool *tool) | 1014 | const struct perf_tool *tool) |
1221 | { | 1015 | { |
1222 | if (tool->lost == perf_event__process_lost && | 1016 | if (tool->lost == perf_event__process_lost && |
1223 | session->hists.stats.nr_events[PERF_RECORD_LOST] != 0) { | 1017 | session->stats.nr_events[PERF_RECORD_LOST] != 0) { |
1224 | ui__warning("Processed %d events and lost %d chunks!\n\n" | 1018 | ui__warning("Processed %d events and lost %d chunks!\n\n" |
1225 | "Check IO/CPU overload!\n\n", | 1019 | "Check IO/CPU overload!\n\n", |
1226 | session->hists.stats.nr_events[0], | 1020 | session->stats.nr_events[0], |
1227 | session->hists.stats.nr_events[PERF_RECORD_LOST]); | 1021 | session->stats.nr_events[PERF_RECORD_LOST]); |
1228 | } | 1022 | } |
1229 | 1023 | ||
1230 | if (session->hists.stats.nr_unknown_events != 0) { | 1024 | if (session->stats.nr_unknown_events != 0) { |
1231 | ui__warning("Found %u unknown events!\n\n" | 1025 | ui__warning("Found %u unknown events!\n\n" |
1232 | "Is this an older tool processing a perf.data " | 1026 | "Is this an older tool processing a perf.data " |
1233 | "file generated by a more recent tool?\n\n" | 1027 | "file generated by a more recent tool?\n\n" |
1234 | "If that is not the case, consider " | 1028 | "If that is not the case, consider " |
1235 | "reporting to linux-kernel@vger.kernel.org.\n\n", | 1029 | "reporting to linux-kernel@vger.kernel.org.\n\n", |
1236 | session->hists.stats.nr_unknown_events); | 1030 | session->stats.nr_unknown_events); |
1237 | } | 1031 | } |
1238 | 1032 | ||
1239 | if (session->hists.stats.nr_unknown_id != 0) { | 1033 | if (session->stats.nr_unknown_id != 0) { |
1240 | ui__warning("%u samples with id not present in the header\n", | 1034 | ui__warning("%u samples with id not present in the header\n", |
1241 | session->hists.stats.nr_unknown_id); | 1035 | session->stats.nr_unknown_id); |
1242 | } | 1036 | } |
1243 | 1037 | ||
1244 | if (session->hists.stats.nr_invalid_chains != 0) { | 1038 | if (session->stats.nr_invalid_chains != 0) { |
1245 | ui__warning("Found invalid callchains!\n\n" | 1039 | ui__warning("Found invalid callchains!\n\n" |
1246 | "%u out of %u events were discarded for this reason.\n\n" | 1040 | "%u out of %u events were discarded for this reason.\n\n" |
1247 | "Consider reporting to linux-kernel@vger.kernel.org.\n\n", | 1041 | "Consider reporting to linux-kernel@vger.kernel.org.\n\n", |
1248 | session->hists.stats.nr_invalid_chains, | 1042 | session->stats.nr_invalid_chains, |
1249 | session->hists.stats.nr_events[PERF_RECORD_SAMPLE]); | 1043 | session->stats.nr_events[PERF_RECORD_SAMPLE]); |
1250 | } | 1044 | } |
1251 | 1045 | ||
1252 | if (session->hists.stats.nr_unprocessable_samples != 0) { | 1046 | if (session->stats.nr_unprocessable_samples != 0) { |
1253 | ui__warning("%u unprocessable samples recorded.\n" | 1047 | ui__warning("%u unprocessable samples recorded.\n" |
1254 | "Do you have a KVM guest running and not using 'perf kvm'?\n", | 1048 | "Do you have a KVM guest running and not using 'perf kvm'?\n", |
1255 | session->hists.stats.nr_unprocessable_samples); | 1049 | session->stats.nr_unprocessable_samples); |
1256 | } | 1050 | } |
1257 | } | 1051 | } |
1258 | 1052 | ||
@@ -1369,6 +1163,18 @@ fetch_mmaped_event(struct perf_session *session, | |||
1369 | return event; | 1163 | return event; |
1370 | } | 1164 | } |
1371 | 1165 | ||
1166 | /* | ||
1167 | * On 64bit we can mmap the data file in one go. No need for tiny mmap | ||
1168 | * slices. On 32bit we use 32MB. | ||
1169 | */ | ||
1170 | #if BITS_PER_LONG == 64 | ||
1171 | #define MMAP_SIZE ULLONG_MAX | ||
1172 | #define NUM_MMAPS 1 | ||
1173 | #else | ||
1174 | #define MMAP_SIZE (32 * 1024 * 1024ULL) | ||
1175 | #define NUM_MMAPS 128 | ||
1176 | #endif | ||
1177 | |||
1372 | int __perf_session__process_events(struct perf_session *session, | 1178 | int __perf_session__process_events(struct perf_session *session, |
1373 | u64 data_offset, u64 data_size, | 1179 | u64 data_offset, u64 data_size, |
1374 | u64 file_size, struct perf_tool *tool) | 1180 | u64 file_size, struct perf_tool *tool) |
@@ -1376,7 +1182,7 @@ int __perf_session__process_events(struct perf_session *session, | |||
1376 | u64 head, page_offset, file_offset, file_pos, progress_next; | 1182 | u64 head, page_offset, file_offset, file_pos, progress_next; |
1377 | int err, mmap_prot, mmap_flags, map_idx = 0; | 1183 | int err, mmap_prot, mmap_flags, map_idx = 0; |
1378 | size_t mmap_size; | 1184 | size_t mmap_size; |
1379 | char *buf, *mmaps[8]; | 1185 | char *buf, *mmaps[NUM_MMAPS]; |
1380 | union perf_event *event; | 1186 | union perf_event *event; |
1381 | uint32_t size; | 1187 | uint32_t size; |
1382 | 1188 | ||
@@ -1391,7 +1197,7 @@ int __perf_session__process_events(struct perf_session *session, | |||
1391 | 1197 | ||
1392 | progress_next = file_size / 16; | 1198 | progress_next = file_size / 16; |
1393 | 1199 | ||
1394 | mmap_size = session->mmap_window; | 1200 | mmap_size = MMAP_SIZE; |
1395 | if (mmap_size > file_size) | 1201 | if (mmap_size > file_size) |
1396 | mmap_size = file_size; | 1202 | mmap_size = file_size; |
1397 | 1203 | ||
@@ -1526,16 +1332,13 @@ int maps__set_kallsyms_ref_reloc_sym(struct map **maps, | |||
1526 | 1332 | ||
1527 | size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp) | 1333 | size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp) |
1528 | { | 1334 | { |
1529 | return __dsos__fprintf(&self->host_machine.kernel_dsos, fp) + | 1335 | return machines__fprintf_dsos(&self->machines, fp); |
1530 | __dsos__fprintf(&self->host_machine.user_dsos, fp) + | ||
1531 | machines__fprintf_dsos(&self->machines, fp); | ||
1532 | } | 1336 | } |
1533 | 1337 | ||
1534 | size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp, | 1338 | size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp, |
1535 | bool with_hits) | 1339 | bool (skip)(struct dso *dso, int parm), int parm) |
1536 | { | 1340 | { |
1537 | size_t ret = machine__fprintf_dsos_buildid(&self->host_machine, fp, with_hits); | 1341 | return machines__fprintf_dsos_buildid(&self->machines, fp, skip, parm); |
1538 | return ret + machines__fprintf_dsos_buildid(&self->machines, fp, with_hits); | ||
1539 | } | 1342 | } |
1540 | 1343 | ||
1541 | size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) | 1344 | size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) |
@@ -1543,11 +1346,11 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) | |||
1543 | struct perf_evsel *pos; | 1346 | struct perf_evsel *pos; |
1544 | size_t ret = fprintf(fp, "Aggregated stats:\n"); | 1347 | size_t ret = fprintf(fp, "Aggregated stats:\n"); |
1545 | 1348 | ||
1546 | ret += hists__fprintf_nr_events(&session->hists, fp); | 1349 | ret += events_stats__fprintf(&session->stats, fp); |
1547 | 1350 | ||
1548 | list_for_each_entry(pos, &session->evlist->entries, node) { | 1351 | list_for_each_entry(pos, &session->evlist->entries, node) { |
1549 | ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos)); | 1352 | ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos)); |
1550 | ret += hists__fprintf_nr_events(&pos->hists, fp); | 1353 | ret += events_stats__fprintf(&pos->hists.stats, fp); |
1551 | } | 1354 | } |
1552 | 1355 | ||
1553 | return ret; | 1356 | return ret; |
@@ -1559,7 +1362,7 @@ size_t perf_session__fprintf(struct perf_session *session, FILE *fp) | |||
1559 | * FIXME: Here we have to actually print all the machines in this | 1362 | * FIXME: Here we have to actually print all the machines in this |
1560 | * session, not just the host... | 1363 | * session, not just the host... |
1561 | */ | 1364 | */ |
1562 | return machine__fprintf(&session->host_machine, fp); | 1365 | return machine__fprintf(&session->machines.host, fp); |
1563 | } | 1366 | } |
1564 | 1367 | ||
1565 | void perf_session__remove_thread(struct perf_session *session, | 1368 | void perf_session__remove_thread(struct perf_session *session, |
@@ -1568,10 +1371,10 @@ void perf_session__remove_thread(struct perf_session *session, | |||
1568 | /* | 1371 | /* |
1569 | * FIXME: This one makes no sense, we need to remove the thread from | 1372 | * FIXME: This one makes no sense, we need to remove the thread from |
1570 | * the machine it belongs to, perf_session can have many machines, so | 1373 | * the machine it belongs to, perf_session can have many machines, so |
1571 | * doing it always on ->host_machine is wrong. Fix when auditing all | 1374 | * doing it always on ->machines.host is wrong. Fix when auditing all |
1572 | * the 'perf kvm' code. | 1375 | * the 'perf kvm' code. |
1573 | */ | 1376 | */ |
1574 | machine__remove_thread(&session->host_machine, th); | 1377 | machine__remove_thread(&session->machines.host, th); |
1575 | } | 1378 | } |
1576 | 1379 | ||
1577 | struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, | 1380 | struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, |
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index cea133a6bdf1..b5c0847edfa9 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -30,16 +30,10 @@ struct ordered_samples { | |||
30 | struct perf_session { | 30 | struct perf_session { |
31 | struct perf_header header; | 31 | struct perf_header header; |
32 | unsigned long size; | 32 | unsigned long size; |
33 | unsigned long mmap_window; | 33 | struct machines machines; |
34 | struct machine host_machine; | ||
35 | struct rb_root machines; | ||
36 | struct perf_evlist *evlist; | 34 | struct perf_evlist *evlist; |
37 | struct pevent *pevent; | 35 | struct pevent *pevent; |
38 | /* | 36 | struct events_stats stats; |
39 | * FIXME: Need to split this up further, we need global | ||
40 | * stats + per event stats. | ||
41 | */ | ||
42 | struct hists hists; | ||
43 | int fd; | 37 | int fd; |
44 | bool fd_pipe; | 38 | bool fd_pipe; |
45 | bool repipe; | 39 | bool repipe; |
@@ -54,7 +48,7 @@ struct perf_tool; | |||
54 | struct perf_session *perf_session__new(const char *filename, int mode, | 48 | struct perf_session *perf_session__new(const char *filename, int mode, |
55 | bool force, bool repipe, | 49 | bool force, bool repipe, |
56 | struct perf_tool *tool); | 50 | struct perf_tool *tool); |
57 | void perf_session__delete(struct perf_session *self); | 51 | void perf_session__delete(struct perf_session *session); |
58 | 52 | ||
59 | void perf_event_header__bswap(struct perf_event_header *self); | 53 | void perf_event_header__bswap(struct perf_event_header *self); |
60 | 54 | ||
@@ -81,43 +75,24 @@ void perf_session__set_id_hdr_size(struct perf_session *session); | |||
81 | void perf_session__remove_thread(struct perf_session *self, struct thread *th); | 75 | void perf_session__remove_thread(struct perf_session *self, struct thread *th); |
82 | 76 | ||
83 | static inline | 77 | static inline |
84 | struct machine *perf_session__find_host_machine(struct perf_session *self) | ||
85 | { | ||
86 | return &self->host_machine; | ||
87 | } | ||
88 | |||
89 | static inline | ||
90 | struct machine *perf_session__find_machine(struct perf_session *self, pid_t pid) | 78 | struct machine *perf_session__find_machine(struct perf_session *self, pid_t pid) |
91 | { | 79 | { |
92 | if (pid == HOST_KERNEL_ID) | ||
93 | return &self->host_machine; | ||
94 | return machines__find(&self->machines, pid); | 80 | return machines__find(&self->machines, pid); |
95 | } | 81 | } |
96 | 82 | ||
97 | static inline | 83 | static inline |
98 | struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t pid) | 84 | struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t pid) |
99 | { | 85 | { |
100 | if (pid == HOST_KERNEL_ID) | ||
101 | return &self->host_machine; | ||
102 | return machines__findnew(&self->machines, pid); | 86 | return machines__findnew(&self->machines, pid); |
103 | } | 87 | } |
104 | 88 | ||
105 | static inline | ||
106 | void perf_session__process_machines(struct perf_session *self, | ||
107 | struct perf_tool *tool, | ||
108 | machine__process_t process) | ||
109 | { | ||
110 | process(&self->host_machine, tool); | ||
111 | return machines__process(&self->machines, process, tool); | ||
112 | } | ||
113 | |||
114 | struct thread *perf_session__findnew(struct perf_session *self, pid_t pid); | 89 | struct thread *perf_session__findnew(struct perf_session *self, pid_t pid); |
115 | size_t perf_session__fprintf(struct perf_session *self, FILE *fp); | 90 | size_t perf_session__fprintf(struct perf_session *self, FILE *fp); |
116 | 91 | ||
117 | size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp); | 92 | size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp); |
118 | 93 | ||
119 | size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, | 94 | size_t perf_session__fprintf_dsos_buildid(struct perf_session *session, FILE *fp, |
120 | FILE *fp, bool with_hits); | 95 | bool (fn)(struct dso *dso, int parm), int parm); |
121 | 96 | ||
122 | size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp); | 97 | size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp); |
123 | 98 | ||
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index cfd1c0feb32d..d41926cb9e3f 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
@@ -60,7 +60,7 @@ sort__thread_cmp(struct hist_entry *left, struct hist_entry *right) | |||
60 | static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf, | 60 | static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf, |
61 | size_t size, unsigned int width) | 61 | size_t size, unsigned int width) |
62 | { | 62 | { |
63 | return repsep_snprintf(bf, size, "%*s:%5d", width, | 63 | return repsep_snprintf(bf, size, "%*s:%5d", width - 6, |
64 | self->thread->comm ?: "", self->thread->pid); | 64 | self->thread->comm ?: "", self->thread->pid); |
65 | } | 65 | } |
66 | 66 | ||
@@ -97,6 +97,16 @@ static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf, | |||
97 | return repsep_snprintf(bf, size, "%*s", width, self->thread->comm); | 97 | return repsep_snprintf(bf, size, "%*s", width, self->thread->comm); |
98 | } | 98 | } |
99 | 99 | ||
100 | struct sort_entry sort_comm = { | ||
101 | .se_header = "Command", | ||
102 | .se_cmp = sort__comm_cmp, | ||
103 | .se_collapse = sort__comm_collapse, | ||
104 | .se_snprintf = hist_entry__comm_snprintf, | ||
105 | .se_width_idx = HISTC_COMM, | ||
106 | }; | ||
107 | |||
108 | /* --sort dso */ | ||
109 | |||
100 | static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r) | 110 | static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r) |
101 | { | 111 | { |
102 | struct dso *dso_l = map_l ? map_l->dso : NULL; | 112 | struct dso *dso_l = map_l ? map_l->dso : NULL; |
@@ -117,40 +127,12 @@ static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r) | |||
117 | return strcmp(dso_name_l, dso_name_r); | 127 | return strcmp(dso_name_l, dso_name_r); |
118 | } | 128 | } |
119 | 129 | ||
120 | struct sort_entry sort_comm = { | ||
121 | .se_header = "Command", | ||
122 | .se_cmp = sort__comm_cmp, | ||
123 | .se_collapse = sort__comm_collapse, | ||
124 | .se_snprintf = hist_entry__comm_snprintf, | ||
125 | .se_width_idx = HISTC_COMM, | ||
126 | }; | ||
127 | |||
128 | /* --sort dso */ | ||
129 | |||
130 | static int64_t | 130 | static int64_t |
131 | sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) | 131 | sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) |
132 | { | 132 | { |
133 | return _sort__dso_cmp(left->ms.map, right->ms.map); | 133 | return _sort__dso_cmp(left->ms.map, right->ms.map); |
134 | } | 134 | } |
135 | 135 | ||
136 | |||
137 | static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r, | ||
138 | u64 ip_l, u64 ip_r) | ||
139 | { | ||
140 | if (!sym_l || !sym_r) | ||
141 | return cmp_null(sym_l, sym_r); | ||
142 | |||
143 | if (sym_l == sym_r) | ||
144 | return 0; | ||
145 | |||
146 | if (sym_l) | ||
147 | ip_l = sym_l->start; | ||
148 | if (sym_r) | ||
149 | ip_r = sym_r->start; | ||
150 | |||
151 | return (int64_t)(ip_r - ip_l); | ||
152 | } | ||
153 | |||
154 | static int _hist_entry__dso_snprintf(struct map *map, char *bf, | 136 | static int _hist_entry__dso_snprintf(struct map *map, char *bf, |
155 | size_t size, unsigned int width) | 137 | size_t size, unsigned int width) |
156 | { | 138 | { |
@@ -169,9 +151,43 @@ static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf, | |||
169 | return _hist_entry__dso_snprintf(self->ms.map, bf, size, width); | 151 | return _hist_entry__dso_snprintf(self->ms.map, bf, size, width); |
170 | } | 152 | } |
171 | 153 | ||
154 | struct sort_entry sort_dso = { | ||
155 | .se_header = "Shared Object", | ||
156 | .se_cmp = sort__dso_cmp, | ||
157 | .se_snprintf = hist_entry__dso_snprintf, | ||
158 | .se_width_idx = HISTC_DSO, | ||
159 | }; | ||
160 | |||
161 | /* --sort symbol */ | ||
162 | |||
163 | static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r) | ||
164 | { | ||
165 | u64 ip_l, ip_r; | ||
166 | |||
167 | if (!sym_l || !sym_r) | ||
168 | return cmp_null(sym_l, sym_r); | ||
169 | |||
170 | if (sym_l == sym_r) | ||
171 | return 0; | ||
172 | |||
173 | ip_l = sym_l->start; | ||
174 | ip_r = sym_r->start; | ||
175 | |||
176 | return (int64_t)(ip_r - ip_l); | ||
177 | } | ||
178 | |||
179 | static int64_t | ||
180 | sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) | ||
181 | { | ||
182 | if (!left->ms.sym && !right->ms.sym) | ||
183 | return right->level - left->level; | ||
184 | |||
185 | return _sort__sym_cmp(left->ms.sym, right->ms.sym); | ||
186 | } | ||
187 | |||
172 | static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym, | 188 | static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym, |
173 | u64 ip, char level, char *bf, size_t size, | 189 | u64 ip, char level, char *bf, size_t size, |
174 | unsigned int width __maybe_unused) | 190 | unsigned int width) |
175 | { | 191 | { |
176 | size_t ret = 0; | 192 | size_t ret = 0; |
177 | 193 | ||
@@ -197,43 +213,13 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym, | |||
197 | return ret; | 213 | return ret; |
198 | } | 214 | } |
199 | 215 | ||
200 | |||
201 | struct sort_entry sort_dso = { | ||
202 | .se_header = "Shared Object", | ||
203 | .se_cmp = sort__dso_cmp, | ||
204 | .se_snprintf = hist_entry__dso_snprintf, | ||
205 | .se_width_idx = HISTC_DSO, | ||
206 | }; | ||
207 | |||
208 | static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf, | 216 | static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf, |
209 | size_t size, | 217 | size_t size, unsigned int width) |
210 | unsigned int width __maybe_unused) | ||
211 | { | 218 | { |
212 | return _hist_entry__sym_snprintf(self->ms.map, self->ms.sym, self->ip, | 219 | return _hist_entry__sym_snprintf(self->ms.map, self->ms.sym, self->ip, |
213 | self->level, bf, size, width); | 220 | self->level, bf, size, width); |
214 | } | 221 | } |
215 | 222 | ||
216 | /* --sort symbol */ | ||
217 | static int64_t | ||
218 | sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) | ||
219 | { | ||
220 | u64 ip_l, ip_r; | ||
221 | |||
222 | if (!left->ms.sym && !right->ms.sym) | ||
223 | return right->level - left->level; | ||
224 | |||
225 | if (!left->ms.sym || !right->ms.sym) | ||
226 | return cmp_null(left->ms.sym, right->ms.sym); | ||
227 | |||
228 | if (left->ms.sym == right->ms.sym) | ||
229 | return 0; | ||
230 | |||
231 | ip_l = left->ms.sym->start; | ||
232 | ip_r = right->ms.sym->start; | ||
233 | |||
234 | return _sort__sym_cmp(left->ms.sym, right->ms.sym, ip_l, ip_r); | ||
235 | } | ||
236 | |||
237 | struct sort_entry sort_sym = { | 223 | struct sort_entry sort_sym = { |
238 | .se_header = "Symbol", | 224 | .se_header = "Symbol", |
239 | .se_cmp = sort__sym_cmp, | 225 | .se_cmp = sort__sym_cmp, |
@@ -253,7 +239,7 @@ static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf, | |||
253 | size_t size, | 239 | size_t size, |
254 | unsigned int width __maybe_unused) | 240 | unsigned int width __maybe_unused) |
255 | { | 241 | { |
256 | FILE *fp; | 242 | FILE *fp = NULL; |
257 | char cmd[PATH_MAX + 2], *path = self->srcline, *nl; | 243 | char cmd[PATH_MAX + 2], *path = self->srcline, *nl; |
258 | size_t line_len; | 244 | size_t line_len; |
259 | 245 | ||
@@ -274,7 +260,6 @@ static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf, | |||
274 | 260 | ||
275 | if (getline(&path, &line_len, fp) < 0 || !line_len) | 261 | if (getline(&path, &line_len, fp) < 0 || !line_len) |
276 | goto out_ip; | 262 | goto out_ip; |
277 | fclose(fp); | ||
278 | self->srcline = strdup(path); | 263 | self->srcline = strdup(path); |
279 | if (self->srcline == NULL) | 264 | if (self->srcline == NULL) |
280 | goto out_ip; | 265 | goto out_ip; |
@@ -284,8 +269,12 @@ static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf, | |||
284 | *nl = '\0'; | 269 | *nl = '\0'; |
285 | path = self->srcline; | 270 | path = self->srcline; |
286 | out_path: | 271 | out_path: |
272 | if (fp) | ||
273 | pclose(fp); | ||
287 | return repsep_snprintf(bf, size, "%s", path); | 274 | return repsep_snprintf(bf, size, "%s", path); |
288 | out_ip: | 275 | out_ip: |
276 | if (fp) | ||
277 | pclose(fp); | ||
289 | return repsep_snprintf(bf, size, "%-#*llx", BITS_PER_LONG / 4, self->ip); | 278 | return repsep_snprintf(bf, size, "%-#*llx", BITS_PER_LONG / 4, self->ip); |
290 | } | 279 | } |
291 | 280 | ||
@@ -335,7 +324,7 @@ sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right) | |||
335 | static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf, | 324 | static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf, |
336 | size_t size, unsigned int width) | 325 | size_t size, unsigned int width) |
337 | { | 326 | { |
338 | return repsep_snprintf(bf, size, "%-*d", width, self->cpu); | 327 | return repsep_snprintf(bf, size, "%*d", width, self->cpu); |
339 | } | 328 | } |
340 | 329 | ||
341 | struct sort_entry sort_cpu = { | 330 | struct sort_entry sort_cpu = { |
@@ -345,6 +334,8 @@ struct sort_entry sort_cpu = { | |||
345 | .se_width_idx = HISTC_CPU, | 334 | .se_width_idx = HISTC_CPU, |
346 | }; | 335 | }; |
347 | 336 | ||
337 | /* sort keys for branch stacks */ | ||
338 | |||
348 | static int64_t | 339 | static int64_t |
349 | sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right) | 340 | sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right) |
350 | { | 341 | { |
@@ -359,13 +350,6 @@ static int hist_entry__dso_from_snprintf(struct hist_entry *self, char *bf, | |||
359 | bf, size, width); | 350 | bf, size, width); |
360 | } | 351 | } |
361 | 352 | ||
362 | struct sort_entry sort_dso_from = { | ||
363 | .se_header = "Source Shared Object", | ||
364 | .se_cmp = sort__dso_from_cmp, | ||
365 | .se_snprintf = hist_entry__dso_from_snprintf, | ||
366 | .se_width_idx = HISTC_DSO_FROM, | ||
367 | }; | ||
368 | |||
369 | static int64_t | 353 | static int64_t |
370 | sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right) | 354 | sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right) |
371 | { | 355 | { |
@@ -389,8 +373,7 @@ sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right) | |||
389 | if (!from_l->sym && !from_r->sym) | 373 | if (!from_l->sym && !from_r->sym) |
390 | return right->level - left->level; | 374 | return right->level - left->level; |
391 | 375 | ||
392 | return _sort__sym_cmp(from_l->sym, from_r->sym, from_l->addr, | 376 | return _sort__sym_cmp(from_l->sym, from_r->sym); |
393 | from_r->addr); | ||
394 | } | 377 | } |
395 | 378 | ||
396 | static int64_t | 379 | static int64_t |
@@ -402,12 +385,11 @@ sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right) | |||
402 | if (!to_l->sym && !to_r->sym) | 385 | if (!to_l->sym && !to_r->sym) |
403 | return right->level - left->level; | 386 | return right->level - left->level; |
404 | 387 | ||
405 | return _sort__sym_cmp(to_l->sym, to_r->sym, to_l->addr, to_r->addr); | 388 | return _sort__sym_cmp(to_l->sym, to_r->sym); |
406 | } | 389 | } |
407 | 390 | ||
408 | static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf, | 391 | static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf, |
409 | size_t size, | 392 | size_t size, unsigned int width) |
410 | unsigned int width __maybe_unused) | ||
411 | { | 393 | { |
412 | struct addr_map_symbol *from = &self->branch_info->from; | 394 | struct addr_map_symbol *from = &self->branch_info->from; |
413 | return _hist_entry__sym_snprintf(from->map, from->sym, from->addr, | 395 | return _hist_entry__sym_snprintf(from->map, from->sym, from->addr, |
@@ -416,8 +398,7 @@ static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf, | |||
416 | } | 398 | } |
417 | 399 | ||
418 | static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf, | 400 | static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf, |
419 | size_t size, | 401 | size_t size, unsigned int width) |
420 | unsigned int width __maybe_unused) | ||
421 | { | 402 | { |
422 | struct addr_map_symbol *to = &self->branch_info->to; | 403 | struct addr_map_symbol *to = &self->branch_info->to; |
423 | return _hist_entry__sym_snprintf(to->map, to->sym, to->addr, | 404 | return _hist_entry__sym_snprintf(to->map, to->sym, to->addr, |
@@ -425,6 +406,13 @@ static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf, | |||
425 | 406 | ||
426 | } | 407 | } |
427 | 408 | ||
409 | struct sort_entry sort_dso_from = { | ||
410 | .se_header = "Source Shared Object", | ||
411 | .se_cmp = sort__dso_from_cmp, | ||
412 | .se_snprintf = hist_entry__dso_from_snprintf, | ||
413 | .se_width_idx = HISTC_DSO_FROM, | ||
414 | }; | ||
415 | |||
428 | struct sort_entry sort_dso_to = { | 416 | struct sort_entry sort_dso_to = { |
429 | .se_header = "Target Shared Object", | 417 | .se_header = "Target Shared Object", |
430 | .se_cmp = sort__dso_to_cmp, | 418 | .se_cmp = sort__dso_to_cmp, |
@@ -484,30 +472,40 @@ struct sort_dimension { | |||
484 | 472 | ||
485 | #define DIM(d, n, func) [d] = { .name = n, .entry = &(func) } | 473 | #define DIM(d, n, func) [d] = { .name = n, .entry = &(func) } |
486 | 474 | ||
487 | static struct sort_dimension sort_dimensions[] = { | 475 | static struct sort_dimension common_sort_dimensions[] = { |
488 | DIM(SORT_PID, "pid", sort_thread), | 476 | DIM(SORT_PID, "pid", sort_thread), |
489 | DIM(SORT_COMM, "comm", sort_comm), | 477 | DIM(SORT_COMM, "comm", sort_comm), |
490 | DIM(SORT_DSO, "dso", sort_dso), | 478 | DIM(SORT_DSO, "dso", sort_dso), |
491 | DIM(SORT_DSO_FROM, "dso_from", sort_dso_from), | ||
492 | DIM(SORT_DSO_TO, "dso_to", sort_dso_to), | ||
493 | DIM(SORT_SYM, "symbol", sort_sym), | 479 | DIM(SORT_SYM, "symbol", sort_sym), |
494 | DIM(SORT_SYM_TO, "symbol_from", sort_sym_from), | ||
495 | DIM(SORT_SYM_FROM, "symbol_to", sort_sym_to), | ||
496 | DIM(SORT_PARENT, "parent", sort_parent), | 480 | DIM(SORT_PARENT, "parent", sort_parent), |
497 | DIM(SORT_CPU, "cpu", sort_cpu), | 481 | DIM(SORT_CPU, "cpu", sort_cpu), |
498 | DIM(SORT_MISPREDICT, "mispredict", sort_mispredict), | ||
499 | DIM(SORT_SRCLINE, "srcline", sort_srcline), | 482 | DIM(SORT_SRCLINE, "srcline", sort_srcline), |
500 | }; | 483 | }; |
501 | 484 | ||
485 | #undef DIM | ||
486 | |||
487 | #define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) } | ||
488 | |||
489 | static struct sort_dimension bstack_sort_dimensions[] = { | ||
490 | DIM(SORT_DSO_FROM, "dso_from", sort_dso_from), | ||
491 | DIM(SORT_DSO_TO, "dso_to", sort_dso_to), | ||
492 | DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from), | ||
493 | DIM(SORT_SYM_TO, "symbol_to", sort_sym_to), | ||
494 | DIM(SORT_MISPREDICT, "mispredict", sort_mispredict), | ||
495 | }; | ||
496 | |||
497 | #undef DIM | ||
498 | |||
502 | int sort_dimension__add(const char *tok) | 499 | int sort_dimension__add(const char *tok) |
503 | { | 500 | { |
504 | unsigned int i; | 501 | unsigned int i; |
505 | 502 | ||
506 | for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) { | 503 | for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) { |
507 | struct sort_dimension *sd = &sort_dimensions[i]; | 504 | struct sort_dimension *sd = &common_sort_dimensions[i]; |
508 | 505 | ||
509 | if (strncasecmp(tok, sd->name, strlen(tok))) | 506 | if (strncasecmp(tok, sd->name, strlen(tok))) |
510 | continue; | 507 | continue; |
508 | |||
511 | if (sd->entry == &sort_parent) { | 509 | if (sd->entry == &sort_parent) { |
512 | int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED); | 510 | int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED); |
513 | if (ret) { | 511 | if (ret) { |
@@ -518,9 +516,7 @@ int sort_dimension__add(const char *tok) | |||
518 | return -EINVAL; | 516 | return -EINVAL; |
519 | } | 517 | } |
520 | sort__has_parent = 1; | 518 | sort__has_parent = 1; |
521 | } else if (sd->entry == &sort_sym || | 519 | } else if (sd->entry == &sort_sym) { |
522 | sd->entry == &sort_sym_from || | ||
523 | sd->entry == &sort_sym_to) { | ||
524 | sort__has_sym = 1; | 520 | sort__has_sym = 1; |
525 | } | 521 | } |
526 | 522 | ||
@@ -530,52 +526,69 @@ int sort_dimension__add(const char *tok) | |||
530 | if (sd->entry->se_collapse) | 526 | if (sd->entry->se_collapse) |
531 | sort__need_collapse = 1; | 527 | sort__need_collapse = 1; |
532 | 528 | ||
533 | if (list_empty(&hist_entry__sort_list)) { | 529 | if (list_empty(&hist_entry__sort_list)) |
534 | if (!strcmp(sd->name, "pid")) | 530 | sort__first_dimension = i; |
535 | sort__first_dimension = SORT_PID; | ||
536 | else if (!strcmp(sd->name, "comm")) | ||
537 | sort__first_dimension = SORT_COMM; | ||
538 | else if (!strcmp(sd->name, "dso")) | ||
539 | sort__first_dimension = SORT_DSO; | ||
540 | else if (!strcmp(sd->name, "symbol")) | ||
541 | sort__first_dimension = SORT_SYM; | ||
542 | else if (!strcmp(sd->name, "parent")) | ||
543 | sort__first_dimension = SORT_PARENT; | ||
544 | else if (!strcmp(sd->name, "cpu")) | ||
545 | sort__first_dimension = SORT_CPU; | ||
546 | else if (!strcmp(sd->name, "symbol_from")) | ||
547 | sort__first_dimension = SORT_SYM_FROM; | ||
548 | else if (!strcmp(sd->name, "symbol_to")) | ||
549 | sort__first_dimension = SORT_SYM_TO; | ||
550 | else if (!strcmp(sd->name, "dso_from")) | ||
551 | sort__first_dimension = SORT_DSO_FROM; | ||
552 | else if (!strcmp(sd->name, "dso_to")) | ||
553 | sort__first_dimension = SORT_DSO_TO; | ||
554 | else if (!strcmp(sd->name, "mispredict")) | ||
555 | sort__first_dimension = SORT_MISPREDICT; | ||
556 | } | ||
557 | 531 | ||
558 | list_add_tail(&sd->entry->list, &hist_entry__sort_list); | 532 | list_add_tail(&sd->entry->list, &hist_entry__sort_list); |
559 | sd->taken = 1; | 533 | sd->taken = 1; |
560 | 534 | ||
561 | return 0; | 535 | return 0; |
562 | } | 536 | } |
537 | |||
538 | for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) { | ||
539 | struct sort_dimension *sd = &bstack_sort_dimensions[i]; | ||
540 | |||
541 | if (strncasecmp(tok, sd->name, strlen(tok))) | ||
542 | continue; | ||
543 | |||
544 | if (sort__branch_mode != 1) | ||
545 | return -EINVAL; | ||
546 | |||
547 | if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to) | ||
548 | sort__has_sym = 1; | ||
549 | |||
550 | if (sd->taken) | ||
551 | return 0; | ||
552 | |||
553 | if (sd->entry->se_collapse) | ||
554 | sort__need_collapse = 1; | ||
555 | |||
556 | if (list_empty(&hist_entry__sort_list)) | ||
557 | sort__first_dimension = i + __SORT_BRANCH_STACK; | ||
558 | |||
559 | list_add_tail(&sd->entry->list, &hist_entry__sort_list); | ||
560 | sd->taken = 1; | ||
561 | |||
562 | return 0; | ||
563 | } | ||
564 | |||
563 | return -ESRCH; | 565 | return -ESRCH; |
564 | } | 566 | } |
565 | 567 | ||
566 | void setup_sorting(const char * const usagestr[], const struct option *opts) | 568 | int setup_sorting(void) |
567 | { | 569 | { |
568 | char *tmp, *tok, *str = strdup(sort_order); | 570 | char *tmp, *tok, *str = strdup(sort_order); |
571 | int ret = 0; | ||
572 | |||
573 | if (str == NULL) { | ||
574 | error("Not enough memory to setup sort keys"); | ||
575 | return -ENOMEM; | ||
576 | } | ||
569 | 577 | ||
570 | for (tok = strtok_r(str, ", ", &tmp); | 578 | for (tok = strtok_r(str, ", ", &tmp); |
571 | tok; tok = strtok_r(NULL, ", ", &tmp)) { | 579 | tok; tok = strtok_r(NULL, ", ", &tmp)) { |
572 | if (sort_dimension__add(tok) < 0) { | 580 | ret = sort_dimension__add(tok); |
581 | if (ret == -EINVAL) { | ||
582 | error("Invalid --sort key: `%s'", tok); | ||
583 | break; | ||
584 | } else if (ret == -ESRCH) { | ||
573 | error("Unknown --sort key: `%s'", tok); | 585 | error("Unknown --sort key: `%s'", tok); |
574 | usage_with_options(usagestr, opts); | 586 | break; |
575 | } | 587 | } |
576 | } | 588 | } |
577 | 589 | ||
578 | free(str); | 590 | free(str); |
591 | return ret; | ||
579 | } | 592 | } |
580 | 593 | ||
581 | void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, | 594 | void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, |
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index b4e8c3ba559d..b13e56f6ccbe 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h | |||
@@ -55,9 +55,6 @@ struct he_stat { | |||
55 | struct hist_entry_diff { | 55 | struct hist_entry_diff { |
56 | bool computed; | 56 | bool computed; |
57 | 57 | ||
58 | /* PERF_HPP__DISPL */ | ||
59 | int displacement; | ||
60 | |||
61 | /* PERF_HPP__DELTA */ | 58 | /* PERF_HPP__DELTA */ |
62 | double period_ratio_delta; | 59 | double period_ratio_delta; |
63 | 60 | ||
@@ -118,25 +115,29 @@ static inline struct hist_entry *hist_entry__next_pair(struct hist_entry *he) | |||
118 | return NULL; | 115 | return NULL; |
119 | } | 116 | } |
120 | 117 | ||
121 | static inline void hist__entry_add_pair(struct hist_entry *he, | 118 | static inline void hist_entry__add_pair(struct hist_entry *he, |
122 | struct hist_entry *pair) | 119 | struct hist_entry *pair) |
123 | { | 120 | { |
124 | list_add_tail(&he->pairs.head, &pair->pairs.node); | 121 | list_add_tail(&he->pairs.head, &pair->pairs.node); |
125 | } | 122 | } |
126 | 123 | ||
127 | enum sort_type { | 124 | enum sort_type { |
125 | /* common sort keys */ | ||
128 | SORT_PID, | 126 | SORT_PID, |
129 | SORT_COMM, | 127 | SORT_COMM, |
130 | SORT_DSO, | 128 | SORT_DSO, |
131 | SORT_SYM, | 129 | SORT_SYM, |
132 | SORT_PARENT, | 130 | SORT_PARENT, |
133 | SORT_CPU, | 131 | SORT_CPU, |
134 | SORT_DSO_FROM, | 132 | SORT_SRCLINE, |
133 | |||
134 | /* branch stack specific sort keys */ | ||
135 | __SORT_BRANCH_STACK, | ||
136 | SORT_DSO_FROM = __SORT_BRANCH_STACK, | ||
135 | SORT_DSO_TO, | 137 | SORT_DSO_TO, |
136 | SORT_SYM_FROM, | 138 | SORT_SYM_FROM, |
137 | SORT_SYM_TO, | 139 | SORT_SYM_TO, |
138 | SORT_MISPREDICT, | 140 | SORT_MISPREDICT, |
139 | SORT_SRCLINE, | ||
140 | }; | 141 | }; |
141 | 142 | ||
142 | /* | 143 | /* |
@@ -159,7 +160,7 @@ struct sort_entry { | |||
159 | extern struct sort_entry sort_thread; | 160 | extern struct sort_entry sort_thread; |
160 | extern struct list_head hist_entry__sort_list; | 161 | extern struct list_head hist_entry__sort_list; |
161 | 162 | ||
162 | void setup_sorting(const char * const usagestr[], const struct option *opts); | 163 | int setup_sorting(void); |
163 | extern int sort_dimension__add(const char *); | 164 | extern int sort_dimension__add(const char *); |
164 | void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, | 165 | void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, |
165 | const char *list_name, FILE *fp); | 166 | const char *list_name, FILE *fp); |
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c index 346707df04b9..29c7b2cb2521 100644 --- a/tools/perf/util/string.c +++ b/tools/perf/util/string.c | |||
@@ -332,6 +332,24 @@ char *strxfrchar(char *s, char from, char to) | |||
332 | } | 332 | } |
333 | 333 | ||
334 | /** | 334 | /** |
335 | * ltrim - Removes leading whitespace from @s. | ||
336 | * @s: The string to be stripped. | ||
337 | * | ||
338 | * Return pointer to the first non-whitespace character in @s. | ||
339 | */ | ||
340 | char *ltrim(char *s) | ||
341 | { | ||
342 | int len = strlen(s); | ||
343 | |||
344 | while (len && isspace(*s)) { | ||
345 | len--; | ||
346 | s++; | ||
347 | } | ||
348 | |||
349 | return s; | ||
350 | } | ||
351 | |||
352 | /** | ||
335 | * rtrim - Removes trailing whitespace from @s. | 353 | * rtrim - Removes trailing whitespace from @s. |
336 | * @s: The string to be stripped. | 354 | * @s: The string to be stripped. |
337 | * | 355 | * |
diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c index 155d8b7078a7..55433aa42c8f 100644 --- a/tools/perf/util/strlist.c +++ b/tools/perf/util/strlist.c | |||
@@ -35,11 +35,11 @@ out_delete: | |||
35 | return NULL; | 35 | return NULL; |
36 | } | 36 | } |
37 | 37 | ||
38 | static void str_node__delete(struct str_node *self, bool dupstr) | 38 | static void str_node__delete(struct str_node *snode, bool dupstr) |
39 | { | 39 | { |
40 | if (dupstr) | 40 | if (dupstr) |
41 | free((void *)self->s); | 41 | free((void *)snode->s); |
42 | free(self); | 42 | free(snode); |
43 | } | 43 | } |
44 | 44 | ||
45 | static | 45 | static |
@@ -59,12 +59,12 @@ static int strlist__node_cmp(struct rb_node *rb_node, const void *entry) | |||
59 | return strcmp(snode->s, str); | 59 | return strcmp(snode->s, str); |
60 | } | 60 | } |
61 | 61 | ||
62 | int strlist__add(struct strlist *self, const char *new_entry) | 62 | int strlist__add(struct strlist *slist, const char *new_entry) |
63 | { | 63 | { |
64 | return rblist__add_node(&self->rblist, new_entry); | 64 | return rblist__add_node(&slist->rblist, new_entry); |
65 | } | 65 | } |
66 | 66 | ||
67 | int strlist__load(struct strlist *self, const char *filename) | 67 | int strlist__load(struct strlist *slist, const char *filename) |
68 | { | 68 | { |
69 | char entry[1024]; | 69 | char entry[1024]; |
70 | int err; | 70 | int err; |
@@ -80,7 +80,7 @@ int strlist__load(struct strlist *self, const char *filename) | |||
80 | continue; | 80 | continue; |
81 | entry[len - 1] = '\0'; | 81 | entry[len - 1] = '\0'; |
82 | 82 | ||
83 | err = strlist__add(self, entry); | 83 | err = strlist__add(slist, entry); |
84 | if (err != 0) | 84 | if (err != 0) |
85 | goto out; | 85 | goto out; |
86 | } | 86 | } |
@@ -107,56 +107,56 @@ struct str_node *strlist__find(struct strlist *slist, const char *entry) | |||
107 | return snode; | 107 | return snode; |
108 | } | 108 | } |
109 | 109 | ||
110 | static int strlist__parse_list_entry(struct strlist *self, const char *s) | 110 | static int strlist__parse_list_entry(struct strlist *slist, const char *s) |
111 | { | 111 | { |
112 | if (strncmp(s, "file://", 7) == 0) | 112 | if (strncmp(s, "file://", 7) == 0) |
113 | return strlist__load(self, s + 7); | 113 | return strlist__load(slist, s + 7); |
114 | 114 | ||
115 | return strlist__add(self, s); | 115 | return strlist__add(slist, s); |
116 | } | 116 | } |
117 | 117 | ||
118 | int strlist__parse_list(struct strlist *self, const char *s) | 118 | int strlist__parse_list(struct strlist *slist, const char *s) |
119 | { | 119 | { |
120 | char *sep; | 120 | char *sep; |
121 | int err; | 121 | int err; |
122 | 122 | ||
123 | while ((sep = strchr(s, ',')) != NULL) { | 123 | while ((sep = strchr(s, ',')) != NULL) { |
124 | *sep = '\0'; | 124 | *sep = '\0'; |
125 | err = strlist__parse_list_entry(self, s); | 125 | err = strlist__parse_list_entry(slist, s); |
126 | *sep = ','; | 126 | *sep = ','; |
127 | if (err != 0) | 127 | if (err != 0) |
128 | return err; | 128 | return err; |
129 | s = sep + 1; | 129 | s = sep + 1; |
130 | } | 130 | } |
131 | 131 | ||
132 | return *s ? strlist__parse_list_entry(self, s) : 0; | 132 | return *s ? strlist__parse_list_entry(slist, s) : 0; |
133 | } | 133 | } |
134 | 134 | ||
135 | struct strlist *strlist__new(bool dupstr, const char *slist) | 135 | struct strlist *strlist__new(bool dupstr, const char *list) |
136 | { | 136 | { |
137 | struct strlist *self = malloc(sizeof(*self)); | 137 | struct strlist *slist = malloc(sizeof(*slist)); |
138 | 138 | ||
139 | if (self != NULL) { | 139 | if (slist != NULL) { |
140 | rblist__init(&self->rblist); | 140 | rblist__init(&slist->rblist); |
141 | self->rblist.node_cmp = strlist__node_cmp; | 141 | slist->rblist.node_cmp = strlist__node_cmp; |
142 | self->rblist.node_new = strlist__node_new; | 142 | slist->rblist.node_new = strlist__node_new; |
143 | self->rblist.node_delete = strlist__node_delete; | 143 | slist->rblist.node_delete = strlist__node_delete; |
144 | 144 | ||
145 | self->dupstr = dupstr; | 145 | slist->dupstr = dupstr; |
146 | if (slist && strlist__parse_list(self, slist) != 0) | 146 | if (slist && strlist__parse_list(slist, list) != 0) |
147 | goto out_error; | 147 | goto out_error; |
148 | } | 148 | } |
149 | 149 | ||
150 | return self; | 150 | return slist; |
151 | out_error: | 151 | out_error: |
152 | free(self); | 152 | free(slist); |
153 | return NULL; | 153 | return NULL; |
154 | } | 154 | } |
155 | 155 | ||
156 | void strlist__delete(struct strlist *self) | 156 | void strlist__delete(struct strlist *slist) |
157 | { | 157 | { |
158 | if (self != NULL) | 158 | if (slist != NULL) |
159 | rblist__delete(&self->rblist); | 159 | rblist__delete(&slist->rblist); |
160 | } | 160 | } |
161 | 161 | ||
162 | struct str_node *strlist__entry(const struct strlist *slist, unsigned int idx) | 162 | struct str_node *strlist__entry(const struct strlist *slist, unsigned int idx) |
diff --git a/tools/perf/util/strlist.h b/tools/perf/util/strlist.h index dd9f922ec67c..5c7f87069d9c 100644 --- a/tools/perf/util/strlist.h +++ b/tools/perf/util/strlist.h | |||
@@ -17,34 +17,34 @@ struct strlist { | |||
17 | }; | 17 | }; |
18 | 18 | ||
19 | struct strlist *strlist__new(bool dupstr, const char *slist); | 19 | struct strlist *strlist__new(bool dupstr, const char *slist); |
20 | void strlist__delete(struct strlist *self); | 20 | void strlist__delete(struct strlist *slist); |
21 | 21 | ||
22 | void strlist__remove(struct strlist *self, struct str_node *sn); | 22 | void strlist__remove(struct strlist *slist, struct str_node *sn); |
23 | int strlist__load(struct strlist *self, const char *filename); | 23 | int strlist__load(struct strlist *slist, const char *filename); |
24 | int strlist__add(struct strlist *self, const char *str); | 24 | int strlist__add(struct strlist *slist, const char *str); |
25 | 25 | ||
26 | struct str_node *strlist__entry(const struct strlist *self, unsigned int idx); | 26 | struct str_node *strlist__entry(const struct strlist *slist, unsigned int idx); |
27 | struct str_node *strlist__find(struct strlist *self, const char *entry); | 27 | struct str_node *strlist__find(struct strlist *slist, const char *entry); |
28 | 28 | ||
29 | static inline bool strlist__has_entry(struct strlist *self, const char *entry) | 29 | static inline bool strlist__has_entry(struct strlist *slist, const char *entry) |
30 | { | 30 | { |
31 | return strlist__find(self, entry) != NULL; | 31 | return strlist__find(slist, entry) != NULL; |
32 | } | 32 | } |
33 | 33 | ||
34 | static inline bool strlist__empty(const struct strlist *self) | 34 | static inline bool strlist__empty(const struct strlist *slist) |
35 | { | 35 | { |
36 | return rblist__empty(&self->rblist); | 36 | return rblist__empty(&slist->rblist); |
37 | } | 37 | } |
38 | 38 | ||
39 | static inline unsigned int strlist__nr_entries(const struct strlist *self) | 39 | static inline unsigned int strlist__nr_entries(const struct strlist *slist) |
40 | { | 40 | { |
41 | return rblist__nr_entries(&self->rblist); | 41 | return rblist__nr_entries(&slist->rblist); |
42 | } | 42 | } |
43 | 43 | ||
44 | /* For strlist iteration */ | 44 | /* For strlist iteration */ |
45 | static inline struct str_node *strlist__first(struct strlist *self) | 45 | static inline struct str_node *strlist__first(struct strlist *slist) |
46 | { | 46 | { |
47 | struct rb_node *rn = rb_first(&self->rblist.entries); | 47 | struct rb_node *rn = rb_first(&slist->rblist.entries); |
48 | return rn ? rb_entry(rn, struct str_node, rb_node) : NULL; | 48 | return rn ? rb_entry(rn, struct str_node, rb_node) : NULL; |
49 | } | 49 | } |
50 | static inline struct str_node *strlist__next(struct str_node *sn) | 50 | static inline struct str_node *strlist__next(struct str_node *sn) |
@@ -59,21 +59,21 @@ static inline struct str_node *strlist__next(struct str_node *sn) | |||
59 | /** | 59 | /** |
60 | * strlist_for_each - iterate over a strlist | 60 | * strlist_for_each - iterate over a strlist |
61 | * @pos: the &struct str_node to use as a loop cursor. | 61 | * @pos: the &struct str_node to use as a loop cursor. |
62 | * @self: the &struct strlist for loop. | 62 | * @slist: the &struct strlist for loop. |
63 | */ | 63 | */ |
64 | #define strlist__for_each(pos, self) \ | 64 | #define strlist__for_each(pos, slist) \ |
65 | for (pos = strlist__first(self); pos; pos = strlist__next(pos)) | 65 | for (pos = strlist__first(slist); pos; pos = strlist__next(pos)) |
66 | 66 | ||
67 | /** | 67 | /** |
68 | * strlist_for_each_safe - iterate over a strlist safe against removal of | 68 | * strlist_for_each_safe - iterate over a strlist safe against removal of |
69 | * str_node | 69 | * str_node |
70 | * @pos: the &struct str_node to use as a loop cursor. | 70 | * @pos: the &struct str_node to use as a loop cursor. |
71 | * @n: another &struct str_node to use as temporary storage. | 71 | * @n: another &struct str_node to use as temporary storage. |
72 | * @self: the &struct strlist for loop. | 72 | * @slist: the &struct strlist for loop. |
73 | */ | 73 | */ |
74 | #define strlist__for_each_safe(pos, n, self) \ | 74 | #define strlist__for_each_safe(pos, n, slist) \ |
75 | for (pos = strlist__first(self), n = strlist__next(pos); pos;\ | 75 | for (pos = strlist__first(slist), n = strlist__next(pos); pos;\ |
76 | pos = n, n = strlist__next(n)) | 76 | pos = n, n = strlist__next(n)) |
77 | 77 | ||
78 | int strlist__parse_list(struct strlist *self, const char *s); | 78 | int strlist__parse_list(struct strlist *slist, const char *s); |
79 | #endif /* __PERF_STRLIST_H */ | 79 | #endif /* __PERF_STRLIST_H */ |
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index db0cc92cf2ea..54efcb5659ac 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c | |||
@@ -1,6 +1,3 @@ | |||
1 | #include <libelf.h> | ||
2 | #include <gelf.h> | ||
3 | #include <elf.h> | ||
4 | #include <fcntl.h> | 1 | #include <fcntl.h> |
5 | #include <stdio.h> | 2 | #include <stdio.h> |
6 | #include <errno.h> | 3 | #include <errno.h> |
@@ -718,6 +715,17 @@ int dso__load_sym(struct dso *dso, struct map *map, | |||
718 | sym.st_value); | 715 | sym.st_value); |
719 | used_opd = true; | 716 | used_opd = true; |
720 | } | 717 | } |
718 | /* | ||
719 | * When loading symbols in a data mapping, ABS symbols (which | ||
720 | * has a value of SHN_ABS in its st_shndx) failed at | ||
721 | * elf_getscn(). And it marks the loading as a failure so | ||
722 | * already loaded symbols cannot be fixed up. | ||
723 | * | ||
724 | * I'm not sure what should be done. Just ignore them for now. | ||
725 | * - Namhyung Kim | ||
726 | */ | ||
727 | if (sym.st_shndx == SHN_ABS) | ||
728 | continue; | ||
721 | 729 | ||
722 | sec = elf_getscn(runtime_ss->elf, sym.st_shndx); | 730 | sec = elf_getscn(runtime_ss->elf, sym.st_shndx); |
723 | if (!sec) | 731 | if (!sec) |
diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c index 259f8f2ea9c9..a7390cde63bc 100644 --- a/tools/perf/util/symbol-minimal.c +++ b/tools/perf/util/symbol-minimal.c | |||
@@ -1,6 +1,5 @@ | |||
1 | #include "symbol.h" | 1 | #include "symbol.h" |
2 | 2 | ||
3 | #include <elf.h> | ||
4 | #include <stdio.h> | 3 | #include <stdio.h> |
5 | #include <fcntl.h> | 4 | #include <fcntl.h> |
6 | #include <string.h> | 5 | #include <string.h> |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 295f8d4feedf..e6432d85b43d 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -28,8 +28,8 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map, | |||
28 | symbol_filter_t filter); | 28 | symbol_filter_t filter); |
29 | static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, | 29 | static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, |
30 | symbol_filter_t filter); | 30 | symbol_filter_t filter); |
31 | static int vmlinux_path__nr_entries; | 31 | int vmlinux_path__nr_entries; |
32 | static char **vmlinux_path; | 32 | char **vmlinux_path; |
33 | 33 | ||
34 | struct symbol_conf symbol_conf = { | 34 | struct symbol_conf symbol_conf = { |
35 | .exclude_other = true, | 35 | .exclude_other = true, |
@@ -202,13 +202,6 @@ void __map_groups__fixup_end(struct map_groups *mg, enum map_type type) | |||
202 | curr->end = ~0ULL; | 202 | curr->end = ~0ULL; |
203 | } | 203 | } |
204 | 204 | ||
205 | static void map_groups__fixup_end(struct map_groups *mg) | ||
206 | { | ||
207 | int i; | ||
208 | for (i = 0; i < MAP__NR_TYPES; ++i) | ||
209 | __map_groups__fixup_end(mg, i); | ||
210 | } | ||
211 | |||
212 | struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name) | 205 | struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name) |
213 | { | 206 | { |
214 | size_t namelen = strlen(name) + 1; | 207 | size_t namelen = strlen(name) + 1; |
@@ -652,8 +645,8 @@ discard_symbol: rb_erase(&pos->rb_node, root); | |||
652 | return count + moved; | 645 | return count + moved; |
653 | } | 646 | } |
654 | 647 | ||
655 | static bool symbol__restricted_filename(const char *filename, | 648 | bool symbol__restricted_filename(const char *filename, |
656 | const char *restricted_filename) | 649 | const char *restricted_filename) |
657 | { | 650 | { |
658 | bool restricted = false; | 651 | bool restricted = false; |
659 | 652 | ||
@@ -775,10 +768,6 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) | |||
775 | else | 768 | else |
776 | machine = NULL; | 769 | machine = NULL; |
777 | 770 | ||
778 | name = malloc(PATH_MAX); | ||
779 | if (!name) | ||
780 | return -1; | ||
781 | |||
782 | dso->adjust_symbols = 0; | 771 | dso->adjust_symbols = 0; |
783 | 772 | ||
784 | if (strncmp(dso->name, "/tmp/perf-", 10) == 0) { | 773 | if (strncmp(dso->name, "/tmp/perf-", 10) == 0) { |
@@ -802,6 +791,10 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) | |||
802 | if (machine) | 791 | if (machine) |
803 | root_dir = machine->root_dir; | 792 | root_dir = machine->root_dir; |
804 | 793 | ||
794 | name = malloc(PATH_MAX); | ||
795 | if (!name) | ||
796 | return -1; | ||
797 | |||
805 | /* Iterate over candidate debug images. | 798 | /* Iterate over candidate debug images. |
806 | * Keep track of "interesting" ones (those which have a symtab, dynsym, | 799 | * Keep track of "interesting" ones (those which have a symtab, dynsym, |
807 | * and/or opd section) for processing. | 800 | * and/or opd section) for processing. |
@@ -887,200 +880,6 @@ struct map *map_groups__find_by_name(struct map_groups *mg, | |||
887 | return NULL; | 880 | return NULL; |
888 | } | 881 | } |
889 | 882 | ||
890 | static int map_groups__set_modules_path_dir(struct map_groups *mg, | ||
891 | const char *dir_name) | ||
892 | { | ||
893 | struct dirent *dent; | ||
894 | DIR *dir = opendir(dir_name); | ||
895 | int ret = 0; | ||
896 | |||
897 | if (!dir) { | ||
898 | pr_debug("%s: cannot open %s dir\n", __func__, dir_name); | ||
899 | return -1; | ||
900 | } | ||
901 | |||
902 | while ((dent = readdir(dir)) != NULL) { | ||
903 | char path[PATH_MAX]; | ||
904 | struct stat st; | ||
905 | |||
906 | /*sshfs might return bad dent->d_type, so we have to stat*/ | ||
907 | snprintf(path, sizeof(path), "%s/%s", dir_name, dent->d_name); | ||
908 | if (stat(path, &st)) | ||
909 | continue; | ||
910 | |||
911 | if (S_ISDIR(st.st_mode)) { | ||
912 | if (!strcmp(dent->d_name, ".") || | ||
913 | !strcmp(dent->d_name, "..")) | ||
914 | continue; | ||
915 | |||
916 | ret = map_groups__set_modules_path_dir(mg, path); | ||
917 | if (ret < 0) | ||
918 | goto out; | ||
919 | } else { | ||
920 | char *dot = strrchr(dent->d_name, '.'), | ||
921 | dso_name[PATH_MAX]; | ||
922 | struct map *map; | ||
923 | char *long_name; | ||
924 | |||
925 | if (dot == NULL || strcmp(dot, ".ko")) | ||
926 | continue; | ||
927 | snprintf(dso_name, sizeof(dso_name), "[%.*s]", | ||
928 | (int)(dot - dent->d_name), dent->d_name); | ||
929 | |||
930 | strxfrchar(dso_name, '-', '_'); | ||
931 | map = map_groups__find_by_name(mg, MAP__FUNCTION, | ||
932 | dso_name); | ||
933 | if (map == NULL) | ||
934 | continue; | ||
935 | |||
936 | long_name = strdup(path); | ||
937 | if (long_name == NULL) { | ||
938 | ret = -1; | ||
939 | goto out; | ||
940 | } | ||
941 | dso__set_long_name(map->dso, long_name); | ||
942 | map->dso->lname_alloc = 1; | ||
943 | dso__kernel_module_get_build_id(map->dso, ""); | ||
944 | } | ||
945 | } | ||
946 | |||
947 | out: | ||
948 | closedir(dir); | ||
949 | return ret; | ||
950 | } | ||
951 | |||
952 | static char *get_kernel_version(const char *root_dir) | ||
953 | { | ||
954 | char version[PATH_MAX]; | ||
955 | FILE *file; | ||
956 | char *name, *tmp; | ||
957 | const char *prefix = "Linux version "; | ||
958 | |||
959 | sprintf(version, "%s/proc/version", root_dir); | ||
960 | file = fopen(version, "r"); | ||
961 | if (!file) | ||
962 | return NULL; | ||
963 | |||
964 | version[0] = '\0'; | ||
965 | tmp = fgets(version, sizeof(version), file); | ||
966 | fclose(file); | ||
967 | |||
968 | name = strstr(version, prefix); | ||
969 | if (!name) | ||
970 | return NULL; | ||
971 | name += strlen(prefix); | ||
972 | tmp = strchr(name, ' '); | ||
973 | if (tmp) | ||
974 | *tmp = '\0'; | ||
975 | |||
976 | return strdup(name); | ||
977 | } | ||
978 | |||
979 | static int machine__set_modules_path(struct machine *machine) | ||
980 | { | ||
981 | char *version; | ||
982 | char modules_path[PATH_MAX]; | ||
983 | |||
984 | version = get_kernel_version(machine->root_dir); | ||
985 | if (!version) | ||
986 | return -1; | ||
987 | |||
988 | snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel", | ||
989 | machine->root_dir, version); | ||
990 | free(version); | ||
991 | |||
992 | return map_groups__set_modules_path_dir(&machine->kmaps, modules_path); | ||
993 | } | ||
994 | |||
995 | struct map *machine__new_module(struct machine *machine, u64 start, | ||
996 | const char *filename) | ||
997 | { | ||
998 | struct map *map; | ||
999 | struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename); | ||
1000 | |||
1001 | if (dso == NULL) | ||
1002 | return NULL; | ||
1003 | |||
1004 | map = map__new2(start, dso, MAP__FUNCTION); | ||
1005 | if (map == NULL) | ||
1006 | return NULL; | ||
1007 | |||
1008 | if (machine__is_host(machine)) | ||
1009 | dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE; | ||
1010 | else | ||
1011 | dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE; | ||
1012 | map_groups__insert(&machine->kmaps, map); | ||
1013 | return map; | ||
1014 | } | ||
1015 | |||
1016 | static int machine__create_modules(struct machine *machine) | ||
1017 | { | ||
1018 | char *line = NULL; | ||
1019 | size_t n; | ||
1020 | FILE *file; | ||
1021 | struct map *map; | ||
1022 | const char *modules; | ||
1023 | char path[PATH_MAX]; | ||
1024 | |||
1025 | if (machine__is_default_guest(machine)) | ||
1026 | modules = symbol_conf.default_guest_modules; | ||
1027 | else { | ||
1028 | sprintf(path, "%s/proc/modules", machine->root_dir); | ||
1029 | modules = path; | ||
1030 | } | ||
1031 | |||
1032 | if (symbol__restricted_filename(path, "/proc/modules")) | ||
1033 | return -1; | ||
1034 | |||
1035 | file = fopen(modules, "r"); | ||
1036 | if (file == NULL) | ||
1037 | return -1; | ||
1038 | |||
1039 | while (!feof(file)) { | ||
1040 | char name[PATH_MAX]; | ||
1041 | u64 start; | ||
1042 | char *sep; | ||
1043 | int line_len; | ||
1044 | |||
1045 | line_len = getline(&line, &n, file); | ||
1046 | if (line_len < 0) | ||
1047 | break; | ||
1048 | |||
1049 | if (!line) | ||
1050 | goto out_failure; | ||
1051 | |||
1052 | line[--line_len] = '\0'; /* \n */ | ||
1053 | |||
1054 | sep = strrchr(line, 'x'); | ||
1055 | if (sep == NULL) | ||
1056 | continue; | ||
1057 | |||
1058 | hex2u64(sep + 1, &start); | ||
1059 | |||
1060 | sep = strchr(line, ' '); | ||
1061 | if (sep == NULL) | ||
1062 | continue; | ||
1063 | |||
1064 | *sep = '\0'; | ||
1065 | |||
1066 | snprintf(name, sizeof(name), "[%s]", line); | ||
1067 | map = machine__new_module(machine, start, name); | ||
1068 | if (map == NULL) | ||
1069 | goto out_delete_line; | ||
1070 | dso__kernel_module_get_build_id(map->dso, machine->root_dir); | ||
1071 | } | ||
1072 | |||
1073 | free(line); | ||
1074 | fclose(file); | ||
1075 | |||
1076 | return machine__set_modules_path(machine); | ||
1077 | |||
1078 | out_delete_line: | ||
1079 | free(line); | ||
1080 | out_failure: | ||
1081 | return -1; | ||
1082 | } | ||
1083 | |||
1084 | int dso__load_vmlinux(struct dso *dso, struct map *map, | 883 | int dso__load_vmlinux(struct dso *dso, struct map *map, |
1085 | const char *vmlinux, symbol_filter_t filter) | 884 | const char *vmlinux, symbol_filter_t filter) |
1086 | { | 885 | { |
@@ -1124,8 +923,10 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map, | |||
1124 | filename = dso__build_id_filename(dso, NULL, 0); | 923 | filename = dso__build_id_filename(dso, NULL, 0); |
1125 | if (filename != NULL) { | 924 | if (filename != NULL) { |
1126 | err = dso__load_vmlinux(dso, map, filename, filter); | 925 | err = dso__load_vmlinux(dso, map, filename, filter); |
1127 | if (err > 0) | 926 | if (err > 0) { |
927 | dso->lname_alloc = 1; | ||
1128 | goto out; | 928 | goto out; |
929 | } | ||
1129 | free(filename); | 930 | free(filename); |
1130 | } | 931 | } |
1131 | 932 | ||
@@ -1133,6 +934,7 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map, | |||
1133 | err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter); | 934 | err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter); |
1134 | if (err > 0) { | 935 | if (err > 0) { |
1135 | dso__set_long_name(dso, strdup(vmlinux_path[i])); | 936 | dso__set_long_name(dso, strdup(vmlinux_path[i])); |
937 | dso->lname_alloc = 1; | ||
1136 | break; | 938 | break; |
1137 | } | 939 | } |
1138 | } | 940 | } |
@@ -1172,6 +974,7 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map, | |||
1172 | if (err > 0) { | 974 | if (err > 0) { |
1173 | dso__set_long_name(dso, | 975 | dso__set_long_name(dso, |
1174 | strdup(symbol_conf.vmlinux_name)); | 976 | strdup(symbol_conf.vmlinux_name)); |
977 | dso->lname_alloc = 1; | ||
1175 | goto out_fixup; | 978 | goto out_fixup; |
1176 | } | 979 | } |
1177 | return err; | 980 | return err; |
@@ -1300,195 +1103,6 @@ out_try_fixup: | |||
1300 | return err; | 1103 | return err; |
1301 | } | 1104 | } |
1302 | 1105 | ||
1303 | size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp) | ||
1304 | { | ||
1305 | struct rb_node *nd; | ||
1306 | size_t ret = 0; | ||
1307 | |||
1308 | for (nd = rb_first(machines); nd; nd = rb_next(nd)) { | ||
1309 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | ||
1310 | ret += __dsos__fprintf(&pos->kernel_dsos, fp); | ||
1311 | ret += __dsos__fprintf(&pos->user_dsos, fp); | ||
1312 | } | ||
1313 | |||
1314 | return ret; | ||
1315 | } | ||
1316 | |||
1317 | size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, | ||
1318 | bool with_hits) | ||
1319 | { | ||
1320 | return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, with_hits) + | ||
1321 | __dsos__fprintf_buildid(&machine->user_dsos, fp, with_hits); | ||
1322 | } | ||
1323 | |||
1324 | size_t machines__fprintf_dsos_buildid(struct rb_root *machines, | ||
1325 | FILE *fp, bool with_hits) | ||
1326 | { | ||
1327 | struct rb_node *nd; | ||
1328 | size_t ret = 0; | ||
1329 | |||
1330 | for (nd = rb_first(machines); nd; nd = rb_next(nd)) { | ||
1331 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | ||
1332 | ret += machine__fprintf_dsos_buildid(pos, fp, with_hits); | ||
1333 | } | ||
1334 | return ret; | ||
1335 | } | ||
1336 | |||
1337 | static struct dso *machine__get_kernel(struct machine *machine) | ||
1338 | { | ||
1339 | const char *vmlinux_name = NULL; | ||
1340 | struct dso *kernel; | ||
1341 | |||
1342 | if (machine__is_host(machine)) { | ||
1343 | vmlinux_name = symbol_conf.vmlinux_name; | ||
1344 | if (!vmlinux_name) | ||
1345 | vmlinux_name = "[kernel.kallsyms]"; | ||
1346 | |||
1347 | kernel = dso__kernel_findnew(machine, vmlinux_name, | ||
1348 | "[kernel]", | ||
1349 | DSO_TYPE_KERNEL); | ||
1350 | } else { | ||
1351 | char bf[PATH_MAX]; | ||
1352 | |||
1353 | if (machine__is_default_guest(machine)) | ||
1354 | vmlinux_name = symbol_conf.default_guest_vmlinux_name; | ||
1355 | if (!vmlinux_name) | ||
1356 | vmlinux_name = machine__mmap_name(machine, bf, | ||
1357 | sizeof(bf)); | ||
1358 | |||
1359 | kernel = dso__kernel_findnew(machine, vmlinux_name, | ||
1360 | "[guest.kernel]", | ||
1361 | DSO_TYPE_GUEST_KERNEL); | ||
1362 | } | ||
1363 | |||
1364 | if (kernel != NULL && (!kernel->has_build_id)) | ||
1365 | dso__read_running_kernel_build_id(kernel, machine); | ||
1366 | |||
1367 | return kernel; | ||
1368 | } | ||
1369 | |||
1370 | struct process_args { | ||
1371 | u64 start; | ||
1372 | }; | ||
1373 | |||
1374 | static int symbol__in_kernel(void *arg, const char *name, | ||
1375 | char type __maybe_unused, u64 start) | ||
1376 | { | ||
1377 | struct process_args *args = arg; | ||
1378 | |||
1379 | if (strchr(name, '[')) | ||
1380 | return 0; | ||
1381 | |||
1382 | args->start = start; | ||
1383 | return 1; | ||
1384 | } | ||
1385 | |||
1386 | /* Figure out the start address of kernel map from /proc/kallsyms */ | ||
1387 | static u64 machine__get_kernel_start_addr(struct machine *machine) | ||
1388 | { | ||
1389 | const char *filename; | ||
1390 | char path[PATH_MAX]; | ||
1391 | struct process_args args; | ||
1392 | |||
1393 | if (machine__is_host(machine)) { | ||
1394 | filename = "/proc/kallsyms"; | ||
1395 | } else { | ||
1396 | if (machine__is_default_guest(machine)) | ||
1397 | filename = (char *)symbol_conf.default_guest_kallsyms; | ||
1398 | else { | ||
1399 | sprintf(path, "%s/proc/kallsyms", machine->root_dir); | ||
1400 | filename = path; | ||
1401 | } | ||
1402 | } | ||
1403 | |||
1404 | if (symbol__restricted_filename(filename, "/proc/kallsyms")) | ||
1405 | return 0; | ||
1406 | |||
1407 | if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0) | ||
1408 | return 0; | ||
1409 | |||
1410 | return args.start; | ||
1411 | } | ||
1412 | |||
1413 | int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel) | ||
1414 | { | ||
1415 | enum map_type type; | ||
1416 | u64 start = machine__get_kernel_start_addr(machine); | ||
1417 | |||
1418 | for (type = 0; type < MAP__NR_TYPES; ++type) { | ||
1419 | struct kmap *kmap; | ||
1420 | |||
1421 | machine->vmlinux_maps[type] = map__new2(start, kernel, type); | ||
1422 | if (machine->vmlinux_maps[type] == NULL) | ||
1423 | return -1; | ||
1424 | |||
1425 | machine->vmlinux_maps[type]->map_ip = | ||
1426 | machine->vmlinux_maps[type]->unmap_ip = | ||
1427 | identity__map_ip; | ||
1428 | kmap = map__kmap(machine->vmlinux_maps[type]); | ||
1429 | kmap->kmaps = &machine->kmaps; | ||
1430 | map_groups__insert(&machine->kmaps, | ||
1431 | machine->vmlinux_maps[type]); | ||
1432 | } | ||
1433 | |||
1434 | return 0; | ||
1435 | } | ||
1436 | |||
1437 | void machine__destroy_kernel_maps(struct machine *machine) | ||
1438 | { | ||
1439 | enum map_type type; | ||
1440 | |||
1441 | for (type = 0; type < MAP__NR_TYPES; ++type) { | ||
1442 | struct kmap *kmap; | ||
1443 | |||
1444 | if (machine->vmlinux_maps[type] == NULL) | ||
1445 | continue; | ||
1446 | |||
1447 | kmap = map__kmap(machine->vmlinux_maps[type]); | ||
1448 | map_groups__remove(&machine->kmaps, | ||
1449 | machine->vmlinux_maps[type]); | ||
1450 | if (kmap->ref_reloc_sym) { | ||
1451 | /* | ||
1452 | * ref_reloc_sym is shared among all maps, so free just | ||
1453 | * on one of them. | ||
1454 | */ | ||
1455 | if (type == MAP__FUNCTION) { | ||
1456 | free((char *)kmap->ref_reloc_sym->name); | ||
1457 | kmap->ref_reloc_sym->name = NULL; | ||
1458 | free(kmap->ref_reloc_sym); | ||
1459 | } | ||
1460 | kmap->ref_reloc_sym = NULL; | ||
1461 | } | ||
1462 | |||
1463 | map__delete(machine->vmlinux_maps[type]); | ||
1464 | machine->vmlinux_maps[type] = NULL; | ||
1465 | } | ||
1466 | } | ||
1467 | |||
1468 | int machine__create_kernel_maps(struct machine *machine) | ||
1469 | { | ||
1470 | struct dso *kernel = machine__get_kernel(machine); | ||
1471 | |||
1472 | if (kernel == NULL || | ||
1473 | __machine__create_kernel_maps(machine, kernel) < 0) | ||
1474 | return -1; | ||
1475 | |||
1476 | if (symbol_conf.use_modules && machine__create_modules(machine) < 0) { | ||
1477 | if (machine__is_host(machine)) | ||
1478 | pr_debug("Problems creating module maps, " | ||
1479 | "continuing anyway...\n"); | ||
1480 | else | ||
1481 | pr_debug("Problems creating module maps for guest %d, " | ||
1482 | "continuing anyway...\n", machine->pid); | ||
1483 | } | ||
1484 | |||
1485 | /* | ||
1486 | * Now that we have all the maps created, just set the ->end of them: | ||
1487 | */ | ||
1488 | map_groups__fixup_end(&machine->kmaps); | ||
1489 | return 0; | ||
1490 | } | ||
1491 | |||
1492 | static void vmlinux_path__exit(void) | 1106 | static void vmlinux_path__exit(void) |
1493 | { | 1107 | { |
1494 | while (--vmlinux_path__nr_entries >= 0) { | 1108 | while (--vmlinux_path__nr_entries >= 0) { |
@@ -1549,25 +1163,6 @@ out_fail: | |||
1549 | return -1; | 1163 | return -1; |
1550 | } | 1164 | } |
1551 | 1165 | ||
1552 | size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp) | ||
1553 | { | ||
1554 | int i; | ||
1555 | size_t printed = 0; | ||
1556 | struct dso *kdso = machine->vmlinux_maps[MAP__FUNCTION]->dso; | ||
1557 | |||
1558 | if (kdso->has_build_id) { | ||
1559 | char filename[PATH_MAX]; | ||
1560 | if (dso__build_id_filename(kdso, filename, sizeof(filename))) | ||
1561 | printed += fprintf(fp, "[0] %s\n", filename); | ||
1562 | } | ||
1563 | |||
1564 | for (i = 0; i < vmlinux_path__nr_entries; ++i) | ||
1565 | printed += fprintf(fp, "[%d] %s\n", | ||
1566 | i + kdso->has_build_id, vmlinux_path[i]); | ||
1567 | |||
1568 | return printed; | ||
1569 | } | ||
1570 | |||
1571 | static int setup_list(struct strlist **list, const char *list_str, | 1166 | static int setup_list(struct strlist **list, const char *list_str, |
1572 | const char *list_name) | 1167 | const char *list_name) |
1573 | { | 1168 | { |
@@ -1671,108 +1266,3 @@ void symbol__exit(void) | |||
1671 | symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; | 1266 | symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; |
1672 | symbol_conf.initialized = false; | 1267 | symbol_conf.initialized = false; |
1673 | } | 1268 | } |
1674 | |||
1675 | int machines__create_kernel_maps(struct rb_root *machines, pid_t pid) | ||
1676 | { | ||
1677 | struct machine *machine = machines__findnew(machines, pid); | ||
1678 | |||
1679 | if (machine == NULL) | ||
1680 | return -1; | ||
1681 | |||
1682 | return machine__create_kernel_maps(machine); | ||
1683 | } | ||
1684 | |||
1685 | int machines__create_guest_kernel_maps(struct rb_root *machines) | ||
1686 | { | ||
1687 | int ret = 0; | ||
1688 | struct dirent **namelist = NULL; | ||
1689 | int i, items = 0; | ||
1690 | char path[PATH_MAX]; | ||
1691 | pid_t pid; | ||
1692 | char *endp; | ||
1693 | |||
1694 | if (symbol_conf.default_guest_vmlinux_name || | ||
1695 | symbol_conf.default_guest_modules || | ||
1696 | symbol_conf.default_guest_kallsyms) { | ||
1697 | machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID); | ||
1698 | } | ||
1699 | |||
1700 | if (symbol_conf.guestmount) { | ||
1701 | items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL); | ||
1702 | if (items <= 0) | ||
1703 | return -ENOENT; | ||
1704 | for (i = 0; i < items; i++) { | ||
1705 | if (!isdigit(namelist[i]->d_name[0])) { | ||
1706 | /* Filter out . and .. */ | ||
1707 | continue; | ||
1708 | } | ||
1709 | pid = (pid_t)strtol(namelist[i]->d_name, &endp, 10); | ||
1710 | if ((*endp != '\0') || | ||
1711 | (endp == namelist[i]->d_name) || | ||
1712 | (errno == ERANGE)) { | ||
1713 | pr_debug("invalid directory (%s). Skipping.\n", | ||
1714 | namelist[i]->d_name); | ||
1715 | continue; | ||
1716 | } | ||
1717 | sprintf(path, "%s/%s/proc/kallsyms", | ||
1718 | symbol_conf.guestmount, | ||
1719 | namelist[i]->d_name); | ||
1720 | ret = access(path, R_OK); | ||
1721 | if (ret) { | ||
1722 | pr_debug("Can't access file %s\n", path); | ||
1723 | goto failure; | ||
1724 | } | ||
1725 | machines__create_kernel_maps(machines, pid); | ||
1726 | } | ||
1727 | failure: | ||
1728 | free(namelist); | ||
1729 | } | ||
1730 | |||
1731 | return ret; | ||
1732 | } | ||
1733 | |||
1734 | void machines__destroy_guest_kernel_maps(struct rb_root *machines) | ||
1735 | { | ||
1736 | struct rb_node *next = rb_first(machines); | ||
1737 | |||
1738 | while (next) { | ||
1739 | struct machine *pos = rb_entry(next, struct machine, rb_node); | ||
1740 | |||
1741 | next = rb_next(&pos->rb_node); | ||
1742 | rb_erase(&pos->rb_node, machines); | ||
1743 | machine__delete(pos); | ||
1744 | } | ||
1745 | } | ||
1746 | |||
1747 | int machine__load_kallsyms(struct machine *machine, const char *filename, | ||
1748 | enum map_type type, symbol_filter_t filter) | ||
1749 | { | ||
1750 | struct map *map = machine->vmlinux_maps[type]; | ||
1751 | int ret = dso__load_kallsyms(map->dso, filename, map, filter); | ||
1752 | |||
1753 | if (ret > 0) { | ||
1754 | dso__set_loaded(map->dso, type); | ||
1755 | /* | ||
1756 | * Since /proc/kallsyms will have multiple sessions for the | ||
1757 | * kernel, with modules between them, fixup the end of all | ||
1758 | * sections. | ||
1759 | */ | ||
1760 | __map_groups__fixup_end(&machine->kmaps, type); | ||
1761 | } | ||
1762 | |||
1763 | return ret; | ||
1764 | } | ||
1765 | |||
1766 | int machine__load_vmlinux_path(struct machine *machine, enum map_type type, | ||
1767 | symbol_filter_t filter) | ||
1768 | { | ||
1769 | struct map *map = machine->vmlinux_maps[type]; | ||
1770 | int ret = dso__load_vmlinux_path(map->dso, map, filter); | ||
1771 | |||
1772 | if (ret > 0) { | ||
1773 | dso__set_loaded(map->dso, type); | ||
1774 | map__reloc_vmlinux(map); | ||
1775 | } | ||
1776 | |||
1777 | return ret; | ||
1778 | } | ||
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index de68f98b236d..b62ca37c4b77 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -16,8 +16,8 @@ | |||
16 | #ifdef LIBELF_SUPPORT | 16 | #ifdef LIBELF_SUPPORT |
17 | #include <libelf.h> | 17 | #include <libelf.h> |
18 | #include <gelf.h> | 18 | #include <gelf.h> |
19 | #include <elf.h> | ||
20 | #endif | 19 | #endif |
20 | #include <elf.h> | ||
21 | 21 | ||
22 | #include "dso.h" | 22 | #include "dso.h" |
23 | 23 | ||
@@ -96,7 +96,8 @@ struct symbol_conf { | |||
96 | initialized, | 96 | initialized, |
97 | kptr_restrict, | 97 | kptr_restrict, |
98 | annotate_asm_raw, | 98 | annotate_asm_raw, |
99 | annotate_src; | 99 | annotate_src, |
100 | event_group; | ||
100 | const char *vmlinux_name, | 101 | const char *vmlinux_name, |
101 | *kallsyms_name, | 102 | *kallsyms_name, |
102 | *source_prefix, | 103 | *source_prefix, |
@@ -120,6 +121,8 @@ struct symbol_conf { | |||
120 | }; | 121 | }; |
121 | 122 | ||
122 | extern struct symbol_conf symbol_conf; | 123 | extern struct symbol_conf symbol_conf; |
124 | extern int vmlinux_path__nr_entries; | ||
125 | extern char **vmlinux_path; | ||
123 | 126 | ||
124 | static inline void *symbol__priv(struct symbol *sym) | 127 | static inline void *symbol__priv(struct symbol *sym) |
125 | { | 128 | { |
@@ -223,6 +226,8 @@ size_t symbol__fprintf_symname_offs(const struct symbol *sym, | |||
223 | size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp); | 226 | size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp); |
224 | size_t symbol__fprintf(struct symbol *sym, FILE *fp); | 227 | size_t symbol__fprintf(struct symbol *sym, FILE *fp); |
225 | bool symbol_type__is_a(char symbol_type, enum map_type map_type); | 228 | bool symbol_type__is_a(char symbol_type, enum map_type map_type); |
229 | bool symbol__restricted_filename(const char *filename, | ||
230 | const char *restricted_filename); | ||
226 | 231 | ||
227 | int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, | 232 | int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, |
228 | struct symsrc *runtime_ss, symbol_filter_t filter, | 233 | struct symsrc *runtime_ss, symbol_filter_t filter, |
diff --git a/tools/perf/util/sysfs.c b/tools/perf/util/sysfs.c index 48c6902e749f..f71e9eafe15a 100644 --- a/tools/perf/util/sysfs.c +++ b/tools/perf/util/sysfs.c | |||
@@ -8,7 +8,7 @@ static const char * const sysfs_known_mountpoints[] = { | |||
8 | }; | 8 | }; |
9 | 9 | ||
10 | static int sysfs_found; | 10 | static int sysfs_found; |
11 | char sysfs_mountpoint[PATH_MAX]; | 11 | char sysfs_mountpoint[PATH_MAX + 1]; |
12 | 12 | ||
13 | static int sysfs_valid_mountpoint(const char *sysfs) | 13 | static int sysfs_valid_mountpoint(const char *sysfs) |
14 | { | 14 | { |
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index df59623ac763..632e40e5ceca 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c | |||
@@ -54,10 +54,10 @@ int thread__comm_len(struct thread *self) | |||
54 | return self->comm_len; | 54 | return self->comm_len; |
55 | } | 55 | } |
56 | 56 | ||
57 | static size_t thread__fprintf(struct thread *self, FILE *fp) | 57 | size_t thread__fprintf(struct thread *thread, FILE *fp) |
58 | { | 58 | { |
59 | return fprintf(fp, "Thread %d %s\n", self->pid, self->comm) + | 59 | return fprintf(fp, "Thread %d %s\n", thread->pid, thread->comm) + |
60 | map_groups__fprintf(&self->mg, verbose, fp); | 60 | map_groups__fprintf(&thread->mg, verbose, fp); |
61 | } | 61 | } |
62 | 62 | ||
63 | void thread__insert_map(struct thread *self, struct map *map) | 63 | void thread__insert_map(struct thread *self, struct map *map) |
@@ -84,17 +84,3 @@ int thread__fork(struct thread *self, struct thread *parent) | |||
84 | return -ENOMEM; | 84 | return -ENOMEM; |
85 | return 0; | 85 | return 0; |
86 | } | 86 | } |
87 | |||
88 | size_t machine__fprintf(struct machine *machine, FILE *fp) | ||
89 | { | ||
90 | size_t ret = 0; | ||
91 | struct rb_node *nd; | ||
92 | |||
93 | for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) { | ||
94 | struct thread *pos = rb_entry(nd, struct thread, rb_node); | ||
95 | |||
96 | ret += thread__fprintf(pos, fp); | ||
97 | } | ||
98 | |||
99 | return ret; | ||
100 | } | ||
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index f2fa17caa7d5..5ad266403098 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h | |||
@@ -30,6 +30,7 @@ int thread__set_comm(struct thread *self, const char *comm); | |||
30 | int thread__comm_len(struct thread *self); | 30 | int thread__comm_len(struct thread *self); |
31 | void thread__insert_map(struct thread *self, struct map *map); | 31 | void thread__insert_map(struct thread *self, struct map *map); |
32 | int thread__fork(struct thread *self, struct thread *parent); | 32 | int thread__fork(struct thread *self, struct thread *parent); |
33 | size_t thread__fprintf(struct thread *thread, FILE *fp); | ||
33 | 34 | ||
34 | static inline struct map *thread__find_map(struct thread *self, | 35 | static inline struct map *thread__find_map(struct thread *self, |
35 | enum map_type type, u64 addr) | 36 | enum map_type type, u64 addr) |
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c index 884dde9b9bc1..54d37a4753c5 100644 --- a/tools/perf/util/top.c +++ b/tools/perf/util/top.c | |||
@@ -26,6 +26,8 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) | |||
26 | float samples_per_sec = top->samples / top->delay_secs; | 26 | float samples_per_sec = top->samples / top->delay_secs; |
27 | float ksamples_per_sec = top->kernel_samples / top->delay_secs; | 27 | float ksamples_per_sec = top->kernel_samples / top->delay_secs; |
28 | float esamples_percent = (100.0 * top->exact_samples) / top->samples; | 28 | float esamples_percent = (100.0 * top->exact_samples) / top->samples; |
29 | struct perf_record_opts *opts = &top->record_opts; | ||
30 | struct perf_target *target = &opts->target; | ||
29 | size_t ret = 0; | 31 | size_t ret = 0; |
30 | 32 | ||
31 | if (!perf_guest) { | 33 | if (!perf_guest) { |
@@ -61,31 +63,31 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) | |||
61 | struct perf_evsel *first = perf_evlist__first(top->evlist); | 63 | struct perf_evsel *first = perf_evlist__first(top->evlist); |
62 | ret += SNPRINTF(bf + ret, size - ret, "%" PRIu64 "%s ", | 64 | ret += SNPRINTF(bf + ret, size - ret, "%" PRIu64 "%s ", |
63 | (uint64_t)first->attr.sample_period, | 65 | (uint64_t)first->attr.sample_period, |
64 | top->freq ? "Hz" : ""); | 66 | opts->freq ? "Hz" : ""); |
65 | } | 67 | } |
66 | 68 | ||
67 | ret += SNPRINTF(bf + ret, size - ret, "%s", perf_evsel__name(top->sym_evsel)); | 69 | ret += SNPRINTF(bf + ret, size - ret, "%s", perf_evsel__name(top->sym_evsel)); |
68 | 70 | ||
69 | ret += SNPRINTF(bf + ret, size - ret, "], "); | 71 | ret += SNPRINTF(bf + ret, size - ret, "], "); |
70 | 72 | ||
71 | if (top->target.pid) | 73 | if (target->pid) |
72 | ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %s", | 74 | ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %s", |
73 | top->target.pid); | 75 | target->pid); |
74 | else if (top->target.tid) | 76 | else if (target->tid) |
75 | ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %s", | 77 | ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %s", |
76 | top->target.tid); | 78 | target->tid); |
77 | else if (top->target.uid_str != NULL) | 79 | else if (target->uid_str != NULL) |
78 | ret += SNPRINTF(bf + ret, size - ret, " (uid: %s", | 80 | ret += SNPRINTF(bf + ret, size - ret, " (uid: %s", |
79 | top->target.uid_str); | 81 | target->uid_str); |
80 | else | 82 | else |
81 | ret += SNPRINTF(bf + ret, size - ret, " (all"); | 83 | ret += SNPRINTF(bf + ret, size - ret, " (all"); |
82 | 84 | ||
83 | if (top->target.cpu_list) | 85 | if (target->cpu_list) |
84 | ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)", | 86 | ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)", |
85 | top->evlist->cpus->nr > 1 ? "s" : "", | 87 | top->evlist->cpus->nr > 1 ? "s" : "", |
86 | top->target.cpu_list); | 88 | target->cpu_list); |
87 | else { | 89 | else { |
88 | if (top->target.tid) | 90 | if (target->tid) |
89 | ret += SNPRINTF(bf + ret, size - ret, ")"); | 91 | ret += SNPRINTF(bf + ret, size - ret, ")"); |
90 | else | 92 | else |
91 | ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)", | 93 | ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)", |
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h index 86ff1b15059b..7ebf357dc9e1 100644 --- a/tools/perf/util/top.h +++ b/tools/perf/util/top.h | |||
@@ -14,7 +14,7 @@ struct perf_session; | |||
14 | struct perf_top { | 14 | struct perf_top { |
15 | struct perf_tool tool; | 15 | struct perf_tool tool; |
16 | struct perf_evlist *evlist; | 16 | struct perf_evlist *evlist; |
17 | struct perf_target target; | 17 | struct perf_record_opts record_opts; |
18 | /* | 18 | /* |
19 | * Symbols will be added here in perf_event__process_sample and will | 19 | * Symbols will be added here in perf_event__process_sample and will |
20 | * get out after decayed. | 20 | * get out after decayed. |
@@ -24,24 +24,16 @@ struct perf_top { | |||
24 | u64 exact_samples; | 24 | u64 exact_samples; |
25 | u64 guest_us_samples, guest_kernel_samples; | 25 | u64 guest_us_samples, guest_kernel_samples; |
26 | int print_entries, count_filter, delay_secs; | 26 | int print_entries, count_filter, delay_secs; |
27 | int freq; | ||
28 | bool hide_kernel_symbols, hide_user_symbols, zero; | 27 | bool hide_kernel_symbols, hide_user_symbols, zero; |
29 | bool use_tui, use_stdio; | 28 | bool use_tui, use_stdio; |
30 | bool sort_has_symbols; | 29 | bool sort_has_symbols; |
31 | bool dont_use_callchains; | ||
32 | bool kptr_restrict_warned; | 30 | bool kptr_restrict_warned; |
33 | bool vmlinux_warned; | 31 | bool vmlinux_warned; |
34 | bool inherit; | ||
35 | bool group; | ||
36 | bool sample_id_all_missing; | ||
37 | bool exclude_guest_missing; | ||
38 | bool dump_symtab; | 32 | bool dump_symtab; |
39 | struct hist_entry *sym_filter_entry; | 33 | struct hist_entry *sym_filter_entry; |
40 | struct perf_evsel *sym_evsel; | 34 | struct perf_evsel *sym_evsel; |
41 | struct perf_session *session; | 35 | struct perf_session *session; |
42 | struct winsize winsize; | 36 | struct winsize winsize; |
43 | unsigned int mmap_pages; | ||
44 | int default_interval; | ||
45 | int realtime_prio; | 37 | int realtime_prio; |
46 | int sym_pcnt_filter; | 38 | int sym_pcnt_filter; |
47 | const char *sym_filter; | 39 | const char *sym_filter; |
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 5906e8426cc7..805d1f52c5b4 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c | |||
@@ -12,6 +12,8 @@ | |||
12 | */ | 12 | */ |
13 | unsigned int page_size; | 13 | unsigned int page_size; |
14 | 14 | ||
15 | bool test_attr__enabled; | ||
16 | |||
15 | bool perf_host = true; | 17 | bool perf_host = true; |
16 | bool perf_guest = false; | 18 | bool perf_guest = false; |
17 | 19 | ||
@@ -218,3 +220,25 @@ void dump_stack(void) | |||
218 | #else | 220 | #else |
219 | void dump_stack(void) {} | 221 | void dump_stack(void) {} |
220 | #endif | 222 | #endif |
223 | |||
224 | void get_term_dimensions(struct winsize *ws) | ||
225 | { | ||
226 | char *s = getenv("LINES"); | ||
227 | |||
228 | if (s != NULL) { | ||
229 | ws->ws_row = atoi(s); | ||
230 | s = getenv("COLUMNS"); | ||
231 | if (s != NULL) { | ||
232 | ws->ws_col = atoi(s); | ||
233 | if (ws->ws_row && ws->ws_col) | ||
234 | return; | ||
235 | } | ||
236 | } | ||
237 | #ifdef TIOCGWINSZ | ||
238 | if (ioctl(1, TIOCGWINSZ, ws) == 0 && | ||
239 | ws->ws_row && ws->ws_col) | ||
240 | return; | ||
241 | #endif | ||
242 | ws->ws_row = 25; | ||
243 | ws->ws_col = 80; | ||
244 | } | ||
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index c2330918110c..09b4c26b71aa 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h | |||
@@ -265,10 +265,14 @@ bool is_power_of_2(unsigned long n) | |||
265 | size_t hex_width(u64 v); | 265 | size_t hex_width(u64 v); |
266 | int hex2u64(const char *ptr, u64 *val); | 266 | int hex2u64(const char *ptr, u64 *val); |
267 | 267 | ||
268 | char *ltrim(char *s); | ||
268 | char *rtrim(char *s); | 269 | char *rtrim(char *s); |
269 | 270 | ||
270 | void dump_stack(void); | 271 | void dump_stack(void); |
271 | 272 | ||
272 | extern unsigned int page_size; | 273 | extern unsigned int page_size; |
273 | 274 | ||
275 | struct winsize; | ||
276 | void get_term_dimensions(struct winsize *ws); | ||
277 | |||
274 | #endif | 278 | #endif |