* [PATCH v4 1/1] powerpc/embedded6xx: Add support for Motorola/Emerson MVME5100
From: Stephen Chivers @ 2013-12-03 22:00 UTC (permalink / raw)
To: benh; +Cc: schivers, linuxppc-dev, cproctor
Add support for the Motorola/Emerson MVME5100 Single Board Computer.
The MVME5100 is a 6U form factor VME64 computer with:
- A single MPC7410 or MPC750 CPU
- A HAWK Processor Host Bridge (CPU to PCI) and
MultiProcessor Interrupt Controller (MPIC)
- Up to 500Mb of onboard memory
- A M48T37 Real Time Clock (RTC) and Non-Volatile Memory chip
- Two 16550 compatible UARTS
- Two Intel E100 Fast Ethernets
- Two PCI Mezzanine Card (PMC) Slots
- PPCBug Firmware
The HAWK PHB/MPIC is compatible with the MPC10x devices.
There is no onboard disk support. This is usually provided by installing a PMC
in first PMC slot.
This patch revives the board support, it was present in early 2.6
series kernels. The board support in those days was by Matt Porter of
MontaVista Software.
CSC Australia has around 31 of these boards in service. The kernel in use
for the boards is based on 2.6.31. The boards are operated without disks
from a file server.
This patch is based on linux-3.13-rc2 and has been boot tested.
Only boards with 512 Mb of memory are known to work.
V1->V2:
Address comments by Kular Gama and Scott Wood.
Minor adjustment to platforms/embedded6xx/Kconfig to ensure
correct indentation where possible.
V2->V3:
Address comments by Scott Wood and Ben Herrenschmidt.
Address errors reported by checkpatch.
V3->V4:
Address comment by Geert Uytterhoeven
Add tested by Alessio Bogani.
Signed-off-by: Stephen Chivers <schivers@csc.com>
Tested-by: Alessio Igor Bogani <alessio.bogani@elettra.eu>
---
arch/powerpc/boot/Makefile | 3 +-
arch/powerpc/boot/dts/mvme5100.dts | 185 +++++++++++++++++++++
arch/powerpc/boot/mvme5100.c | 27 +++
arch/powerpc/boot/wrapper | 4 +
arch/powerpc/configs/mvme5100_defconfig | 144 ++++++++++++++++
arch/powerpc/platforms/embedded6xx/Kconfig | 13 ++-
arch/powerpc/platforms/embedded6xx/Makefile | 1 +
arch/powerpc/platforms/embedded6xx/mvme5100.c | 221 +++++++++++++++++++++++++
8 files changed, 596 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index ca7f08c..cd9ea99 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -95,7 +95,7 @@ src-plat-$(CONFIG_FSL_SOC_BOOKE) += cuboot-85xx.c cuboot-85xx-cpm2.c
src-plat-$(CONFIG_EMBEDDED6xx) += cuboot-pq2.c cuboot-mpc7448hpc2.c \
cuboot-c2k.c gamecube-head.S \
gamecube.c wii-head.S wii.c holly.c \
- prpmc2800.c
+ prpmc2800.c fixed-head.S mvme5100.c
src-plat-$(CONFIG_AMIGAONE) += cuboot-amigaone.c
src-plat-$(CONFIG_PPC_PS3) += ps3-head.S ps3-hvcall.S ps3.c
src-plat-$(CONFIG_EPAPR_BOOT) += epapr.c epapr-wrapper.c
@@ -286,6 +286,7 @@ image-$(CONFIG_MPC7448HPC2) += cuImage.mpc7448hpc2
image-$(CONFIG_PPC_C2K) += cuImage.c2k
image-$(CONFIG_GAMECUBE) += dtbImage.gamecube
image-$(CONFIG_WII) += dtbImage.wii
+image-$(CONFIG_MVME5100) += dtbImage.mvme5100
# Board port in arch/powerpc/platform/amigaone/Kconfig
image-$(CONFIG_AMIGAONE) += cuImage.amigaone
diff --git a/arch/powerpc/boot/dts/mvme5100.dts b/arch/powerpc/boot/dts/mvme5100.dts
new file mode 100644
index 0000000..1ecb341
--- /dev/null
+++ b/arch/powerpc/boot/dts/mvme5100.dts
@@ -0,0 +1,185 @@
+/*
+ * Device Tree Source for Motorola/Emerson MVME5100.
+ *
+ * Copyright 2013 CSC Australia Pty. Ltd.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without
+ * any warranty of any kind, whether express or implied.
+ */
+
+/dts-v1/;
+
+/ {
+ model = "MVME5100";
+ compatible = "MVME5100";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ aliases {
+ serial0 = &serial0;
+ pci0 = &pci0;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ PowerPC,7410 {
+ device_type = "cpu";
+ reg = <0x0>;
+ /* Following required by dtc but not used */
+ d-cache-line-size = <32>;
+ i-cache-line-size = <32>;
+ i-cache-size = <32768>;
+ d-cache-size = <32768>;
+ timebase-frequency = <25000000>;
+ clock-frequency = <500000000>;
+ bus-frequency = <100000000>;
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x0 0x20000000>;
+ };
+
+ hawk@fef80000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "hawk-bridge", "simple-bus";
+ ranges = <0x0 0xfef80000 0x10000>;
+ reg = <0xfef80000 0x10000>;
+
+ serial0: serial@8000 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <0x8000 0x80>;
+ reg-shift = <4>;
+ clock-frequency = <1843200>;
+ current-speed = <9600>;
+ interrupts = <1 1>; // IRQ1 Level Active Low.
+ interrupt-parent = <&mpic>;
+ };
+
+ serial1: serial@8200 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <0x8200 0x80>;
+ reg-shift = <4>;
+ clock-frequency = <1843200>;
+ current-speed = <9600>;
+ interrupts = <1 1>; // IRQ1 Level Active Low.
+ interrupt-parent = <&mpic>;
+ };
+
+ mpic: interrupt-controller@f3f80000 {
+ #interrupt-cells = <2>;
+ #address-cells = <0>;
+ device_type = "open-pic";
+ compatible = "chrp,open-pic";
+ interrupt-controller;
+ reg = <0xf3f80000 0x40000>;
+ };
+ };
+
+ pci0: pci@feff0000 {
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ device_type = "pci";
+ compatible = "hawk-pci";
+ reg = <0xfec00000 0x400000>;
+ 8259-interrupt-acknowledge = <0xfeff0030>;
+ ranges = <0x1000000 0x0 0x0 0xfe000000 0x0 0x800000
+ 0x2000000 0x0 0x80000000 0x80000000 0x0 0x74000000>;
+ bus-range = <0 255>;
+ clock-frequency = <33333333>;
+ interrupt-parent = <&mpic>;
+ interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+ interrupt-map = <
+
+ /*
+ * This definition (IDSEL 11) duplicates the
+ * interrupts definition in the i8259
+ * interrupt controller below.
+ *
+ * Do not change the interrupt sense/polarity from
+ * 0x2 to anything else, doing so will cause endless
+ * "spurious" i8259 interrupts to be fielded.
+ */
+ // IDSEL 11 - iPMC712 PCI/ISA Bridge
+ 0x5800 0x0 0x0 0x1 &mpic 0x0 0x2
+ 0x5800 0x0 0x0 0x2 &mpic 0x0 0x2
+ 0x5800 0x0 0x0 0x3 &mpic 0x0 0x2
+ 0x5800 0x0 0x0 0x4 &mpic 0x0 0x2
+
+ /* IDSEL 12 - Not Used */
+
+ /* IDSEL 13 - Universe VME Bridge */
+ 0x6800 0x0 0x0 0x1 &mpic 0x5 0x1
+ 0x6800 0x0 0x0 0x2 &mpic 0x6 0x1
+ 0x6800 0x0 0x0 0x3 &mpic 0x7 0x1
+ 0x6800 0x0 0x0 0x4 &mpic 0x8 0x1
+
+ /* IDSEL 14 - ENET 1 */
+ 0x7000 0x0 0x0 0x1 &mpic 0x2 0x1
+
+ /* IDSEL 15 - Not Used */
+
+ /* IDSEL 16 - PMC Slot 1 */
+ 0x8000 0x0 0x0 0x1 &mpic 0x9 0x1
+ 0x8000 0x0 0x0 0x2 &mpic 0xa 0x1
+ 0x8000 0x0 0x0 0x3 &mpic 0xb 0x1
+ 0x8000 0x0 0x0 0x4 &mpic 0xc 0x1
+
+ /* IDSEL 17 - PMC Slot 2 */
+ 0x8800 0x0 0x0 0x1 &mpic 0xc 0x1
+ 0x8800 0x0 0x0 0x2 &mpic 0x9 0x1
+ 0x8800 0x0 0x0 0x3 &mpic 0xa 0x1
+ 0x8800 0x0 0x0 0x4 &mpic 0xb 0x1
+
+ /* IDSEL 18 - Not Used */
+
+ /* IDSEL 19 - ENET 2 */
+ 0x9800 0x0 0x0 0x1 &mpic 0xd 0x1
+
+ /* IDSEL 20 - PMCSPAN (PCI-X) */
+ 0xa000 0x0 0x0 0x1 &mpic 0x9 0x1
+ 0xa000 0x0 0x0 0x2 &mpic 0xa 0x1
+ 0xa000 0x0 0x0 0x3 &mpic 0xb 0x1
+ 0xa000 0x0 0x0 0x4 &mpic 0xc 0x1
+
+ >;
+
+ isa {
+ #address-cells = <2>;
+ #size-cells = <1>;
+ #interrupt-cells = <2>;
+ device_type = "isa";
+ compatible = "isa";
+ ranges = <0x00000001 0 0x01000000 0 0x00000000 0x00001000>;
+ interrupt-parent = <&i8259>;
+
+ i8259: interrupt-controller@20 {
+ #interrupt-cells = <2>;
+ #address-cells = <0>;
+ interrupts = <0 2>;
+ device_type = "interrupt-controller";
+ compatible = "chrp,iic";
+ interrupt-controller;
+ reg = <1 0x00000020 0x00000002
+ 1 0x000000a0 0x00000002
+ 1 0x000004d0 0x00000002>;
+ interrupt-parent = <&mpic>;
+ };
+
+ };
+
+ };
+
+ chosen {
+ linux,stdout-path = &serial0;
+ };
+
+};
diff --git a/arch/powerpc/boot/mvme5100.c b/arch/powerpc/boot/mvme5100.c
new file mode 100644
index 0000000..cb865f8
--- /dev/null
+++ b/arch/powerpc/boot/mvme5100.c
@@ -0,0 +1,27 @@
+/*
+ * Motorola/Emerson MVME5100 with PPCBug firmware.
+ *
+ * Author: Stephen Chivers <schivers@csc.com>
+ *
+ * Copyright 2013 CSC Australia Pty. Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ */
+#include "types.h"
+#include "ops.h"
+#include "io.h"
+
+BSS_STACK(4096);
+
+void platform_init(unsigned long r3, unsigned long r4, unsigned long r5)
+{
+ u32 heapsize;
+
+ heapsize = 0x8000000 - (u32)_end; /* 128M */
+ simple_alloc_init(_end, heapsize, 32, 64);
+ fdt_init(_dtb_start);
+ serial_console_init();
+}
diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper
index 2e1af74..d27a255 100755
--- a/arch/powerpc/boot/wrapper
+++ b/arch/powerpc/boot/wrapper
@@ -265,6 +265,10 @@ epapr)
link_address='0x20000000'
pie=-pie
;;
+mvme5100)
+ platformo="$object/fixed-head.o $object/mvme5100.o"
+ binary=y
+ ;;
esac
vmz="$tmpdir/`basename \"$kernel\"`.$ext"
diff --git a/arch/powerpc/configs/mvme5100_defconfig b/arch/powerpc/configs/mvme5100_defconfig
new file mode 100644
index 0000000..93c7752
--- /dev/null
+++ b/arch/powerpc/configs/mvme5100_defconfig
@@ -0,0 +1,144 @@
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
+CONFIG_EMBEDDED6xx=y
+CONFIG_MVME5100=y
+CONFIG_KVM_GUEST=y
+CONFIG_HZ_100=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_COMPACTION is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0,9600 ip=dhcp root=/dev/nfs"
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_INET_LRO is not set
+# CONFIG_IPV6 is not set
+CONFIG_NETFILTER=y
+CONFIG_NF_CONNTRACK=m
+CONFIG_NF_CT_PROTO_SCTP=m
+CONFIG_NF_CONNTRACK_AMANDA=m
+CONFIG_NF_CONNTRACK_FTP=m
+CONFIG_NF_CONNTRACK_H323=m
+CONFIG_NF_CONNTRACK_IRC=m
+CONFIG_NF_CONNTRACK_NETBIOS_NS=m
+CONFIG_NF_CONNTRACK_PPTP=m
+CONFIG_NF_CONNTRACK_SIP=m
+CONFIG_NF_CONNTRACK_TFTP=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NF_CONNTRACK_IPV4=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+CONFIG_LAPB=m
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_PROC_DEVICETREE=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=2
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_EEPROM_LEGACY=m
+CONFIG_NETDEVICES=y
+CONFIG_TUN=m
+# CONFIG_NET_VENDOR_3COM is not set
+CONFIG_E100=y
+# CONFIG_WLAN is not set
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=10
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_HW_RANDOM=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_MPC=y
+# CONFIG_HWMON is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_HID is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_VME_BUS=m
+CONFIG_VME_CA91CX42=m
+CONFIG_EXT2_FS=m
+CONFIG_EXT3_FS=m
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_XFS_FS=m
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_ROOT_NFS=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+CONFIG_CIFS=m
+CONFIG_NLS=y
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_UTF8=m
+CONFIG_CRC_CCITT=m
+CONFIG_CRC_T10DIF=y
+CONFIG_XZ_DEC=y
+CONFIG_XZ_DEC_X86=y
+CONFIG_XZ_DEC_IA64=y
+CONFIG_XZ_DEC_ARM=y
+CONFIG_XZ_DEC_ARMTHUMB=y
+CONFIG_XZ_DEC_SPARC=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DETECT_HUNG_TASK=y
+CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=20
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_DEFLATE=m
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
diff --git a/arch/powerpc/platforms/embedded6xx/Kconfig b/arch/powerpc/platforms/embedded6xx/Kconfig
index 302ba43..6d3c7a9 100644
--- a/arch/powerpc/platforms/embedded6xx/Kconfig
+++ b/arch/powerpc/platforms/embedded6xx/Kconfig
@@ -67,6 +67,18 @@ config PPC_C2K
This option enables support for the GE Fanuc C2K board (formerly
an SBS board).
+config MVME5100
+ bool "Motorola/Emerson MVME5100"
+ depends on EMBEDDED6xx
+ select MPIC
+ select PCI
+ select PPC_INDIRECT_PCI
+ select PPC_I8259
+ select PPC_NATIVE
+ help
+ This option enables support for the Motorola (now Emerson) MVME5100
+ board.
+
config TSI108_BRIDGE
bool
select PCI
@@ -113,4 +125,3 @@ config WII
help
Select WII if configuring for the Nintendo Wii.
More information at: <http://gc-linux.sourceforge.net/>
-
diff --git a/arch/powerpc/platforms/embedded6xx/Makefile b/arch/powerpc/platforms/embedded6xx/Makefile
index 66c23e4..cdd48d4 100644
--- a/arch/powerpc/platforms/embedded6xx/Makefile
+++ b/arch/powerpc/platforms/embedded6xx/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_USBGECKO_UDBG) += usbgecko_udbg.o
obj-$(CONFIG_GAMECUBE_COMMON) += flipper-pic.o
obj-$(CONFIG_GAMECUBE) += gamecube.o
obj-$(CONFIG_WII) += wii.o hlwd-pic.o
+obj-$(CONFIG_MVME5100) += mvme5100.o
diff --git a/arch/powerpc/platforms/embedded6xx/mvme5100.c b/arch/powerpc/platforms/embedded6xx/mvme5100.c
new file mode 100644
index 0000000..25e3bfb
--- /dev/null
+++ b/arch/powerpc/platforms/embedded6xx/mvme5100.c
@@ -0,0 +1,221 @@
+/*
+ * Board setup routines for the Motorola/Emerson MVME5100.
+ *
+ * Copyright 2013 CSC Australia Pty. Ltd.
+ *
+ * Based on earlier code by:
+ *
+ * Matt Porter, MontaVista Software Inc.
+ * Copyright 2001 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * Author: Stephen Chivers <schivers@csc.com>
+ *
+ */
+
+#include <linux/of_platform.h>
+
+#include <asm/i8259.h>
+#include <asm/pci-bridge.h>
+#include <asm/mpic.h>
+#include <asm/prom.h>
+#include <mm/mmu_decl.h>
+#include <asm/udbg.h>
+
+#define HAWK_MPIC_SIZE 0x00040000U
+#define MVME5100_PCI_MEM_OFFSET 0x00000000
+
+/* Board register addresses. */
+#define BOARD_STATUS_REG 0xfef88080
+#define BOARD_MODFAIL_REG 0xfef88090
+#define BOARD_MODRST_REG 0xfef880a0
+#define BOARD_TBEN_REG 0xfef880c0
+#define BOARD_SW_READ_REG 0xfef880e0
+#define BOARD_GEO_ADDR_REG 0xfef880e8
+#define BOARD_EXT_FEATURE1_REG 0xfef880f0
+#define BOARD_EXT_FEATURE2_REG 0xfef88100
+
+static phys_addr_t pci_membase;
+static u_char *restart;
+
+static void mvme5100_8259_cascade(unsigned int irq, struct irq_desc *desc)
+{
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ unsigned int cascade_irq = i8259_irq();
+
+ if (cascade_irq != NO_IRQ)
+ generic_handle_irq(cascade_irq);
+
+ chip->irq_eoi(&desc->irq_data);
+}
+
+static void __init mvme5100_pic_init(void)
+{
+ struct mpic *mpic;
+ struct device_node *np;
+ struct device_node *cp = NULL;
+ unsigned int cirq;
+ unsigned long intack = 0;
+ const u32 *prop = NULL;
+
+ np = of_find_node_by_type(NULL, "open-pic");
+ if (!np) {
+ pr_err("Could not find open-pic node\n");
+ return;
+ }
+
+ mpic = mpic_alloc(np, pci_membase, 0, 16, 256, " OpenPIC ");
+
+ BUG_ON(mpic == NULL);
+ of_node_put(np);
+
+ mpic_assign_isu(mpic, 0, pci_membase + 0x10000);
+
+ mpic_init(mpic);
+
+ cp = of_find_compatible_node(NULL, NULL, "chrp,iic");
+ if (cp == NULL) {
+ pr_warn("mvme5100_pic_init: couldn't find i8259\n");
+ return;
+ }
+
+ cirq = irq_of_parse_and_map(cp, 0);
+ if (cirq == NO_IRQ) {
+ pr_warn("mvme5100_pic_init: no cascade interrupt?\n");
+ return;
+ }
+
+ np = of_find_compatible_node(NULL, "pci", "mpc10x-pci");
+ if (np) {
+ prop = of_get_property(np, "8259-interrupt-acknowledge", NULL);
+
+ if (prop)
+ intack = prop[0];
+
+ of_node_put(np);
+ }
+
+ if (intack)
+ pr_debug("mvme5100_pic_init: PCI 8259 intack at 0x%016lx\n",
+ intack);
+
+ i8259_init(cp, intack);
+ of_node_put(cp);
+ irq_set_chained_handler(cirq, mvme5100_8259_cascade);
+}
+
+static int __init mvme5100_add_bridge(struct device_node *dev)
+{
+ const int *bus_range;
+ int len;
+ struct pci_controller *hose;
+ unsigned short devid;
+
+ pr_info("Adding PCI host bridge %s\n", dev->full_name);
+
+ bus_range = of_get_property(dev, "bus-range", &len);
+
+ hose = pcibios_alloc_controller(dev);
+ if (hose == NULL)
+ return -ENOMEM;
+
+ hose->first_busno = bus_range ? bus_range[0] : 0;
+ hose->last_busno = bus_range ? bus_range[1] : 0xff;
+
+ setup_indirect_pci(hose, 0xfe000cf8, 0xfe000cfc, 0);
+
+ pci_process_bridge_OF_ranges(hose, dev, 1);
+
+ early_read_config_word(hose, 0, 0, PCI_DEVICE_ID, &devid);
+
+ if (devid != PCI_DEVICE_ID_MOTOROLA_HAWK) {
+ pr_err("HAWK PHB not present?\n");
+ return 0;
+ }
+
+ early_read_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_1, &pci_membase);
+
+ if (pci_membase == 0) {
+ pr_err("HAWK PHB mibar not correctly set?\n");
+ return 0;
+ }
+
+ pr_info("mvme5100_pic_init: pci_membase: %x\n", pci_membase);
+
+ return 0;
+}
+
+static struct of_device_id mvme5100_of_bus_ids[] __initdata = {
+ { .compatible = "hawk-bridge", },
+ {},
+};
+
+/*
+ * Setup the architecture
+ */
+static void __init mvme5100_setup_arch(void)
+{
+ struct device_node *np;
+
+ if (ppc_md.progress)
+ ppc_md.progress("mvme5100_setup_arch()", 0);
+
+ for_each_compatible_node(np, "pci", "hawk-pci")
+ mvme5100_add_bridge(np);
+
+ restart = ioremap(BOARD_MODRST_REG, 4);
+}
+
+
+static void mvme5100_show_cpuinfo(struct seq_file *m)
+{
+ seq_puts(m, "Vendor\t\t: Motorola/Emerson\n");
+ seq_puts(m, "Machine\t\t: MVME5100\n");
+}
+
+static void mvme5100_restart(char *cmd)
+{
+
+ local_irq_disable();
+ mtmsr(mfmsr() | MSR_IP);
+
+ out_8((u_char *) restart, 0x01);
+
+ while (1)
+ ;
+}
+
+/*
+ * Called very early, device-tree isn't unflattened
+ */
+static int __init mvme5100_probe(void)
+{
+ unsigned long root = of_get_flat_dt_root();
+
+ return of_flat_dt_is_compatible(root, "MVME5100");
+}
+
+static int __init probe_of_platform_devices(void)
+{
+
+ of_platform_bus_probe(NULL, mvme5100_of_bus_ids, NULL);
+ return 0;
+}
+
+machine_device_initcall(mvme5100, probe_of_platform_devices);
+
+define_machine(mvme5100) {
+ .name = "MVME5100",
+ .probe = mvme5100_probe,
+ .setup_arch = mvme5100_setup_arch,
+ .init_IRQ = mvme5100_pic_init,
+ .show_cpuinfo = mvme5100_show_cpuinfo,
+ .get_irq = mpic_get_irq,
+ .restart = mvme5100_restart,
+ .calibrate_decr = generic_calibrate_decr,
+ .progress = udbg_progress,
+};
^ permalink raw reply related
* Re: Error in frreing hugepages with preemption enabled
From: Andrea Arcangeli @ 2013-12-03 22:21 UTC (permalink / raw)
To: Alexander Graf
Cc: kvm@vger.kernel.org, kvm-ppc@vger.kernel.org, Bharat Bhushan,
Scott Wood, linuxppc-dev@lists.ozlabs.org
In-Reply-To: <EDB02D3B-6B03-4CCB-95C8-FDF2F2932E1D@suse.de>
Hi everyone,
On Fri, Nov 29, 2013 at 12:13:03PM +0100, Alexander Graf wrote:
>
> On 29.11.2013, at 05:38, Bharat Bhushan <Bharat.Bhushan@freescale.com> wrote:
>
> > Hi Alex,
> >
> > I am running KVM guest with host kernel having CONFIG_PREEMPT enabled. With allocated pages things seems to work fine but I uses hugepages for guest I see below prints when "quit" from qemu.
> >
> > (qemu) QEMU waiting for connection on: telnet:0.0.0.0:4444,server
> > qemu-system-ppc64: pci_add_option_rom: failed to find romfile "efi-virtio.rom"
> > q
> > debug_smp_processor_id: 15 callbacks suppressed
> > BUG: using smp_processor_id() in preemptible [00000000] code: qemu-system-ppc/2504
> > caller is .free_hugepd_range+0xb0/0x21c
> > CPU: 1 PID: 2504 Comm: qemu-system-ppc Not tainted 3.12.0-rc3-07733-gabf4907 #175
> > Call Trace:
> > [c0000000fb433400] [c000000000007d38] .show_stack+0x7c/0x1cc (unreliable)
> > [c0000000fb4334d0] [c0000000005e8ce0] .dump_stack+0x9c/0xf4
> > [c0000000fb433560] [c0000000002de5ec] .debug_smp_processor_id+0x108/0x11c
> > [c0000000fb4335f0] [c000000000025e10] .free_hugepd_range+0xb0/0x21c
> > [c0000000fb433680] [c0000000000265bc] .hugetlb_free_pgd_range+0x2c8/0x3b0
> > [c0000000fb4337a0] [c0000000000e428c] .free_pgtables+0x14c/0x158
> > [c0000000fb433840] [c0000000000ef320] .exit_mmap+0xec/0x194
> > [c0000000fb433960] [c00000000004d780] .mmput+0x64/0x124
> > [c0000000fb4339e0] [c000000000051f40] .do_exit+0x29c/0x9c8
> > [c0000000fb433ae0] [c0000000000527c8] .do_group_exit+0x50/0xc4
> > [c0000000fb433b70] [c0000000000606a0] .get_signal_to_deliver+0x21c/0x5d8
> > [c0000000fb433c70] [c000000000009b08] .do_signal+0x54/0x278
> > [c0000000fb433db0] [c000000000009e50] .do_notify_resume+0x64/0x78
> > [c0000000fb433e30] [c000000000000b44] .ret_from_except_lite+0x70/0x74
> >
> >
> > This mean that free_hugepd_range() must be called with preemption enabled.
>
> with preemption disabled.
>
> > I tried below change and this seems to work fine (I am not having expertise in this area so not sure this is correct way)
>
> Not sure - the scope looks odd to me. Let's ask Andrea - I'm sure he knows what to do :).
:) So I had a look at the top of this function (0xb0) in the upstream
kernel and no smp_processor_id() call is apparent, is this stock git
or a ppc tree? The first few calls seem not to call it but I may have
overlooked something. It's just quicker if somebody with vmlinux finds
the location of it.
static void free_hugepd_range(struct mmu_gather *tlb, hugepd_t *hpdp, int pdshift,
unsigned long start, unsigned long end,
unsigned long floor, unsigned long ceiling)
{
pte_t *hugepte = hugepd_page(*hpdp);
int i;
unsigned long pdmask = ~((1UL << pdshift) - 1);
unsigned int num_hugepd = 1;
#ifdef CONFIG_PPC_FSL_BOOK3E
/* Note: On fsl the hpdp may be the first of several */
num_hugepd = (1 << (hugepd_shift(*hpdp) - pdshift));
#else
unsigned int shift = hugepd_shift(*hpdp);
#endif
start &= pdmask;
if (start < floor)
return;
if (ceiling) {
ceiling &= pdmask;
if (! ceiling)
return;
}
if (end - 1 > ceiling - 1)
return;
for (i = 0; i < num_hugepd; i++, hpdp++)
hpdp->pd = 0;
tlb->need_flush = 1;
#ifdef CONFIG_PPC_FSL_BOOK3E
hugepd_free(tlb, hugepte);
#else
pgtable_free_tlb(tlb, hugepte, pdshift - shift);
#endif
}
Generally smp_processor_id should never be used, exactly to avoid
problems like above with preempion enabled in .config.
Instead it should be replaced with a get_cpu()/put_cpu() pair that is
exactly meant to fix bugs like this and define proper critical
sections around the per-cpu variables.
#define get_cpu() ({ preempt_disable(); smp_processor_id(); })
#define put_cpu() preempt_enable()
After you find where that smp_processor_id() is located, you should
simply replace it with a get_cpu() and then you should insert a
put_cpu immediately after the "cpu" info is not used anymore. That
will define a proper and strict critical section around the use of the
per-cpu variables.
With a ppc vmlinux it should be immediate to find the location of
smp_processor_id but I don't have the ppc vmlinux here.
Thanks!
Andrea
>
>
> Alex
>
> >
> > diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
> > index d67db4b..6bf8459 100644
> > --- a/arch/powerpc/mm/hugetlbpage.c
> > +++ b/arch/powerpc/mm/hugetlbpage.c
> > @@ -563,8 +563,10 @@ static void hugetlb_free_pmd_range(struct mmu_gather *tlb, pud_t *pud,
> > */
> > next = addr + (1 << hugepd_shift(*(hugepd_t *)pmd));
> > #endif
> > + preempt_disable();
> > free_hugepd_range(tlb, (hugepd_t *)pmd, PMD_SHIFT,
> > addr, next, floor, ceiling);
> > + preempt_enable();
> > } while (addr = next, addr != end);
> >
> > start &= PUD_MASK;
> >
> >
> > Thanks
> > -Bharat
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe kvm-ppc" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* Re: Error in frreing hugepages with preemption enabled
From: Benjamin Herrenschmidt @ 2013-12-04 2:22 UTC (permalink / raw)
To: Andrea Arcangeli
Cc: kvm@vger.kernel.org, Alexander Graf, kvm-ppc@vger.kernel.org,
Bharat Bhushan, Scott Wood, linuxppc-dev@lists.ozlabs.org
In-Reply-To: <20131203222121.GB18764@redhat.com>
On Tue, 2013-12-03 at 23:21 +0100, Andrea Arcangeli wrote:
> #ifdef CONFIG_PPC_FSL_BOOK3E
> hugepd_free(tlb, hugepte);
^^^^^^^^^^^^^^^^^^^^^^^^^^
This is the culprit
(Alex, you didn't specify this was embedded or did I miss it ?)
> #else
> pgtable_free_tlb(tlb, hugepte, pdshift - shift);
> #endif
> }
That function does:
batchp = &__get_cpu_var(hugepd_freelist_cur);
IE, it tries to use a per-CPU batch. Basically, it's duplicating the
logic in mm/memory.c for RCU freeing using a per-cpu freelist. I suppose
it assumes being called under something like the page table lock ?
This code also never "flushes" the batch, which is a concern...
Alex, this is Freescale stuff, can you followup with them ?
Cheers,
Ben.
^ permalink raw reply
* Re: [V3 00/10] perf: New conditional branch filter
From: Michael Ellerman @ 2013-12-04 2:50 UTC (permalink / raw)
To: Anshuman Khandual
Cc: mikey, linux-kernel, eranian, linuxppc-dev,
Arnaldo Carvalho de Melo, sukadev
In-Reply-To: <1381906617-11392-1-git-send-email-khandual@linux.vnet.ibm.com>
On Wed, 2013-10-16 at 12:26 +0530, Anshuman Khandual wrote:
> This patchset is the re-spin of the original branch stack sampling
> patchset which introduced new PERF_SAMPLE_BRANCH_COND branch filter. This patchset
> also enables SW based branch filtering support for book3s powerpc platforms which
> have PMU HW backed branch stack sampling support.
>
> Summary of code changes in this patchset:
>
> (1) Introduces a new PERF_SAMPLE_BRANCH_COND branch filter
> (2) Add the "cond" branch filter options in the "perf record" tool
> (3) Enable PERF_SAMPLE_BRANCH_COND in X86 platforms
> (4) Enable PERF_SAMPLE_BRANCH_COND in POWER8 platform
> (5) Update the documentation regarding "perf record" tool
Can you please address my comments and then resend patches 1-5. And make sure
you send them to the perf maintainers.
Those three touch the generic code, powerpc and x86, so we'll get those merged
first, and then focus on the remaining patches, which are powerpc specific.
cheers
^ permalink raw reply
* Re: [PATCH -V2 3/5] mm: Move change_prot_numa outside CONFIG_ARCH_USES_NUMA_PROT_NONE
From: Benjamin Herrenschmidt @ 2013-12-04 3:13 UTC (permalink / raw)
To: Aneesh Kumar K.V; +Cc: linux-mm, paulus, linuxppc-dev
In-Reply-To: <1384766893-10189-4-git-send-email-aneesh.kumar@linux.vnet.ibm.com>
On Mon, 2013-11-18 at 14:58 +0530, Aneesh Kumar K.V wrote:
> From: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
>
> change_prot_numa should work even if _PAGE_NUMA != _PAGE_PROTNONE.
> On archs like ppc64 that don't use _PAGE_PROTNONE and also have
> a separate page table outside linux pagetable, we just need to
> make sure that when calling change_prot_numa we flush the
> hardware page table entry so that next page access result in a numa
> fault.
That patch doesn't look right...
You are essentially making change_prot_numa() do whatever it does (which
I don't completely understand) *for all architectures* now, whether they
have CONFIG_ARCH_USES_NUMA_PROT_NONE or not ... So because you want that
behaviour on powerpc book3s64, you change everybody.
Is that correct ?
Also what exactly is that doing, can you explain ? From what I can see,
it calls back into the core of mprotect to change the protection to
vma->vm_page_prot, which I would have expected is already the protection
there, with the added "prot_numa" flag passed down.
Your changeset comment says "On archs like ppc64 [...] we just need to
make sure that when calling change_prot_numa we flush the
hardware page table entry so that next page access result in a numa
fault."
But change_prot_numa() does a lot more than that ... it does
pte_mknuma(), do we need it ? I assume we do or we wouldn't have added
that PTE bit to begin with...
Now it *might* be allright and it might be that no other architecture
cares anyway etc... but I need at least some mm folks to ack on that
patch before I can take it because it *will* change behaviour of other
architectures.
Cheers,
Ben.
> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
> ---
> include/linux/mm.h | 3 ---
> mm/mempolicy.c | 9 ---------
> 2 files changed, 12 deletions(-)
>
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index 0548eb201e05..51794c1a1d7e 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -1851,11 +1851,8 @@ static inline pgprot_t vm_get_page_prot(unsigned long vm_flags)
> }
> #endif
>
> -#ifdef CONFIG_ARCH_USES_NUMA_PROT_NONE
> unsigned long change_prot_numa(struct vm_area_struct *vma,
> unsigned long start, unsigned long end);
> -#endif
> -
> struct vm_area_struct *find_extend_vma(struct mm_struct *, unsigned long addr);
> int remap_pfn_range(struct vm_area_struct *, unsigned long addr,
> unsigned long pfn, unsigned long size, pgprot_t);
> diff --git a/mm/mempolicy.c b/mm/mempolicy.c
> index c4403cdf3433..cae10af4fdc4 100644
> --- a/mm/mempolicy.c
> +++ b/mm/mempolicy.c
> @@ -613,7 +613,6 @@ static inline int queue_pages_pgd_range(struct vm_area_struct *vma,
> return 0;
> }
>
> -#ifdef CONFIG_ARCH_USES_NUMA_PROT_NONE
> /*
> * This is used to mark a range of virtual addresses to be inaccessible.
> * These are later cleared by a NUMA hinting fault. Depending on these
> @@ -627,7 +626,6 @@ unsigned long change_prot_numa(struct vm_area_struct *vma,
> unsigned long addr, unsigned long end)
> {
> int nr_updated;
> - BUILD_BUG_ON(_PAGE_NUMA != _PAGE_PROTNONE);
>
> nr_updated = change_protection(vma, addr, end, vma->vm_page_prot, 0, 1);
> if (nr_updated)
> @@ -635,13 +633,6 @@ unsigned long change_prot_numa(struct vm_area_struct *vma,
>
> return nr_updated;
> }
> -#else
> -static unsigned long change_prot_numa(struct vm_area_struct *vma,
> - unsigned long addr, unsigned long end)
> -{
> - return 0;
> -}
> -#endif /* CONFIG_ARCH_USES_NUMA_PROT_NONE */
>
> /*
> * Walk through page tables and collect pages to be migrated.
^ permalink raw reply
* Re: [PATCH v2] watchdog: mpc8xxx_wdt convert to watchdog core
From: Guenter Roeck @ 2013-12-04 5:10 UTC (permalink / raw)
To: Christophe Leroy, Wim Van Sebroeck, scottwood
Cc: linuxppc-dev, linux-kernel, linux-watchdog
In-Reply-To: <20131203133140.5E9DF1A2BEA@localhost.localdomain>
On 12/03/2013 05:31 AM, Christophe Leroy wrote:
> Convert mpc8xxx_wdt.c to the new watchdog API.
>
> Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
>
> diff -ur a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c
> --- a/drivers/watchdog/mpc8xxx_wdt.c 2013-05-11 22:57:46.000000000 +0200
> +++ b/drivers/watchdog/mpc8xxx_wdt.c 2013-11-30 16:14:53.803495472 +0100
> @@ -72,53 +72,36 @@
> * to 0
> */
> static int prescale = 1;
> -static unsigned int timeout_sec;
>
> -static unsigned long wdt_is_open;
> static DEFINE_SPINLOCK(wdt_spinlock);
>
> -static void mpc8xxx_wdt_keepalive(void)
> +static int mpc8xxx_wdt_ping(struct watchdog_device *w)
> {
> /* Ping the WDT */
> spin_lock(&wdt_spinlock);
> out_be16(&wd_base->swsrr, 0x556c);
> out_be16(&wd_base->swsrr, 0xaa39);
> spin_unlock(&wdt_spinlock);
> + return 0;
> }
>
Ok, now I understand a bit better.
I think it would be better to keep the original mpc8xxx_wdt_keepalive()
function and add
static int mpc8xxx_wdt_ping(struct watchdog_device *w)
{
mpc8xxx_wdt_keepalive();
}
since the parameter is not used. Then you can call mpc8xxx_wdt_keepalive()
from mpc8xxx_wdt_timer_ping(), and you don't have to add the dummy argument.
Otherwise looks good.
Note there is a problem in the probe function with
u32 freq = fsl_get_sys_freq();
and
if (!freq || freq == -1)
^^^^^^^^^^^
but fixing that would be a different patch.
Guenter
> +static struct watchdog_device mpc8xxx_wdt_dev;
> static void mpc8xxx_wdt_timer_ping(unsigned long arg);
> -static DEFINE_TIMER(wdt_timer, mpc8xxx_wdt_timer_ping, 0, 0);
> +static DEFINE_TIMER(wdt_timer, mpc8xxx_wdt_timer_ping, 0,
> + (unsigned long)&mpc8xxx_wdt_dev);
>
> static void mpc8xxx_wdt_timer_ping(unsigned long arg)
> {
> - mpc8xxx_wdt_keepalive();
> - /* We're pinging it twice faster than needed, just to be sure. */
> - mod_timer(&wdt_timer, jiffies + HZ * timeout_sec / 2);
> -}
> + struct watchdog_device *w = (struct watchdog_device *)arg;
>
> -static void mpc8xxx_wdt_pr_warn(const char *msg)
> -{
> - pr_crit("%s, expect the %s soon!\n", msg,
> - reset ? "reset" : "machine check exception");
> -}
> -
> -static ssize_t mpc8xxx_wdt_write(struct file *file, const char __user *buf,
> - size_t count, loff_t *ppos)
> -{
> - if (count)
> - mpc8xxx_wdt_keepalive();
> - return count;
> + mpc8xxx_wdt_ping(w);
> + /* We're pinging it twice faster than needed, just to be sure. */
> + mod_timer(&wdt_timer, jiffies + HZ * w->timeout / 2);
> }
>
> -static int mpc8xxx_wdt_open(struct inode *inode, struct file *file)
> +static int mpc8xxx_wdt_start(struct watchdog_device *w)
> {
> u32 tmp = SWCRR_SWEN;
> - if (test_and_set_bit(0, &wdt_is_open))
> - return -EBUSY;
> -
> - /* Once we start the watchdog we can't stop it */
> - if (nowayout)
> - __module_get(THIS_MODULE);
>
> /* Good, fire up the show */
> if (prescale)
> @@ -132,59 +115,31 @@
>
> del_timer_sync(&wdt_timer);
>
> - return nonseekable_open(inode, file);
> + return 0;
> }
>
> -static int mpc8xxx_wdt_release(struct inode *inode, struct file *file)
> +static int mpc8xxx_wdt_stop(struct watchdog_device *w)
> {
> - if (!nowayout)
> - mpc8xxx_wdt_timer_ping(0);
> - else
> - mpc8xxx_wdt_pr_warn("watchdog closed");
> - clear_bit(0, &wdt_is_open);
> + mod_timer(&wdt_timer, jiffies);
> return 0;
> }
>
> -static long mpc8xxx_wdt_ioctl(struct file *file, unsigned int cmd,
> - unsigned long arg)
> -{
> - void __user *argp = (void __user *)arg;
> - int __user *p = argp;
> - static const struct watchdog_info ident = {
> - .options = WDIOF_KEEPALIVEPING,
> - .firmware_version = 1,
> - .identity = "MPC8xxx",
> - };
> -
> - switch (cmd) {
> - case WDIOC_GETSUPPORT:
> - return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
> - case WDIOC_GETSTATUS:
> - case WDIOC_GETBOOTSTATUS:
> - return put_user(0, p);
> - case WDIOC_KEEPALIVE:
> - mpc8xxx_wdt_keepalive();
> - return 0;
> - case WDIOC_GETTIMEOUT:
> - return put_user(timeout_sec, p);
> - default:
> - return -ENOTTY;
> - }
> -}
> +static struct watchdog_info mpc8xxx_wdt_info = {
> + .options = WDIOF_KEEPALIVEPING,
> + .firmware_version = 1,
> + .identity = "MPC8xxx",
> +};
>
> -static const struct file_operations mpc8xxx_wdt_fops = {
> - .owner = THIS_MODULE,
> - .llseek = no_llseek,
> - .write = mpc8xxx_wdt_write,
> - .unlocked_ioctl = mpc8xxx_wdt_ioctl,
> - .open = mpc8xxx_wdt_open,
> - .release = mpc8xxx_wdt_release,
> +static struct watchdog_ops mpc8xxx_wdt_ops = {
> + .owner = THIS_MODULE,
> + .start = mpc8xxx_wdt_start,
> + .ping = mpc8xxx_wdt_ping,
> + .stop = mpc8xxx_wdt_stop,
> };
>
> -static struct miscdevice mpc8xxx_wdt_miscdev = {
> - .minor = WATCHDOG_MINOR,
> - .name = "watchdog",
> - .fops = &mpc8xxx_wdt_fops,
> +static struct watchdog_device mpc8xxx_wdt_dev = {
> + .info = &mpc8xxx_wdt_info,
> + .ops = &mpc8xxx_wdt_ops,
> };
>
> static const struct of_device_id mpc8xxx_wdt_match[];
> @@ -196,6 +151,7 @@
> const struct mpc8xxx_wdt_type *wdt_type;
> u32 freq = fsl_get_sys_freq();
> bool enabled;
> + unsigned int timeout_sec;
>
> match = of_match_device(mpc8xxx_wdt_match, &ofdev->dev);
> if (!match)
> @@ -222,6 +178,7 @@
> else
> timeout_sec = timeout / freq;
>
> + mpc8xxx_wdt_dev.timeout = timeout_sec;
> #ifdef MODULE
> ret = mpc8xxx_wdt_init_late();
> if (ret)
> @@ -237,7 +194,7 @@
> * userspace handles it.
> */
> if (enabled)
> - mpc8xxx_wdt_timer_ping(0);
> + mod_timer(&wdt_timer, jiffies);
> return 0;
> err_unmap:
> iounmap(wd_base);
> @@ -247,9 +204,10 @@
>
> static int mpc8xxx_wdt_remove(struct platform_device *ofdev)
> {
> - mpc8xxx_wdt_pr_warn("watchdog removed");
> + pr_crit("Watchdog removed, expect the %s soon!\n",
> + reset ? "reset" : "machine check exception");
> del_timer_sync(&wdt_timer);
> - misc_deregister(&mpc8xxx_wdt_miscdev);
> + watchdog_unregister_device(&mpc8xxx_wdt_dev);
> iounmap(wd_base);
>
> return 0;
> @@ -301,10 +259,11 @@
> if (!wd_base)
> return -ENODEV;
>
> - ret = misc_register(&mpc8xxx_wdt_miscdev);
> + watchdog_set_nowayout(&mpc8xxx_wdt_dev, nowayout);
> +
> + ret = watchdog_register_device(&mpc8xxx_wdt_dev);
> if (ret) {
> - pr_err("cannot register miscdev on minor=%d (err=%d)\n",
> - WATCHDOG_MINOR, ret);
> + pr_err("cannot register watchdog device (err=%d)\n", ret);
> return ret;
> }
> return 0;
> diff -ur a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
> --- a/drivers/watchdog/Kconfig
> +++ b/drivers/watchdog/Kconfig
> @@ -1146,6 +1146,7 @@
> config 8xxx_WDT
> tristate "MPC8xxx Platform Watchdog Timer"
> depends on PPC_8xx || PPC_83xx || PPC_86xx
> + select WATCHDOG_CORE
> help
> This driver is for a SoC level watchdog that exists on some
> Freescale PowerPC processors. So far this driver supports:
>
>
^ permalink raw reply
* [PATCH v3] watchdog: mpc8xxx_wdt convert to watchdog core
From: Christophe Leroy @ 2013-12-04 6:32 UTC (permalink / raw)
To: Wim Van Sebroeck, scottwood, Guenter Roeck
Cc: linuxppc-dev, linux-kernel, linux-watchdog
Convert mpc8xxx_wdt.c to the new watchdog API.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
diff -ur a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c
--- a/drivers/watchdog/mpc8xxx_wdt.c 2013-05-11 22:57:46.000000000 +0200
+++ b/drivers/watchdog/mpc8xxx_wdt.c 2013-11-30 16:14:53.803495472 +0100
@@ -72,9 +72,7 @@
* to 0
*/
static int prescale = 1;
-static unsigned int timeout_sec;
-static unsigned long wdt_is_open;
static DEFINE_SPINLOCK(wdt_spinlock);
static void mpc8xxx_wdt_keepalive(void)
@@ -86,39 +84,23 @@
spin_unlock(&wdt_spinlock);
}
+static struct watchdog_device mpc8xxx_wdt_dev;
static void mpc8xxx_wdt_timer_ping(unsigned long arg);
-static DEFINE_TIMER(wdt_timer, mpc8xxx_wdt_timer_ping, 0, 0);
+static DEFINE_TIMER(wdt_timer, mpc8xxx_wdt_timer_ping, 0,
+ (unsigned long)&mpc8xxx_wdt_dev);
static void mpc8xxx_wdt_timer_ping(unsigned long arg)
{
+ struct watchdog_device *w = (struct watchdog_device *)arg;
+
mpc8xxx_wdt_keepalive();
/* We're pinging it twice faster than needed, just to be sure. */
- mod_timer(&wdt_timer, jiffies + HZ * timeout_sec / 2);
-}
-
-static void mpc8xxx_wdt_pr_warn(const char *msg)
-{
- pr_crit("%s, expect the %s soon!\n", msg,
- reset ? "reset" : "machine check exception");
+ mod_timer(&wdt_timer, jiffies + HZ * w->timeout / 2);
}
-static ssize_t mpc8xxx_wdt_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
-{
- if (count)
- mpc8xxx_wdt_keepalive();
- return count;
-}
-
-static int mpc8xxx_wdt_open(struct inode *inode, struct file *file)
+static int mpc8xxx_wdt_start(struct watchdog_device *w)
{
u32 tmp = SWCRR_SWEN;
- if (test_and_set_bit(0, &wdt_is_open))
- return -EBUSY;
-
- /* Once we start the watchdog we can't stop it */
- if (nowayout)
- __module_get(THIS_MODULE);
/* Good, fire up the show */
if (prescale)
@@ -132,59 +114,37 @@
del_timer_sync(&wdt_timer);
- return nonseekable_open(inode, file);
+ return 0;
}
-static int mpc8xxx_wdt_release(struct inode *inode, struct file *file)
+static int mpc8xxx_wdt_ping(struct watchdog_device *w)
{
- if (!nowayout)
- mpc8xxx_wdt_timer_ping(0);
- else
- mpc8xxx_wdt_pr_warn("watchdog closed");
- clear_bit(0, &wdt_is_open);
+ mpc8xxx_wdt_keepalive();
return 0;
}
-static long mpc8xxx_wdt_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
+static int mpc8xxx_wdt_stop(struct watchdog_device *w)
{
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
- static const struct watchdog_info ident = {
- .options = WDIOF_KEEPALIVEPING,
- .firmware_version = 1,
- .identity = "MPC8xxx",
- };
-
- switch (cmd) {
- case WDIOC_GETSUPPORT:
- return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
- case WDIOC_GETSTATUS:
- case WDIOC_GETBOOTSTATUS:
- return put_user(0, p);
- case WDIOC_KEEPALIVE:
- mpc8xxx_wdt_keepalive();
- return 0;
- case WDIOC_GETTIMEOUT:
- return put_user(timeout_sec, p);
- default:
- return -ENOTTY;
- }
+ mod_timer(&wdt_timer, jiffies);
+ return 0;
}
-static const struct file_operations mpc8xxx_wdt_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .write = mpc8xxx_wdt_write,
- .unlocked_ioctl = mpc8xxx_wdt_ioctl,
- .open = mpc8xxx_wdt_open,
- .release = mpc8xxx_wdt_release,
+static struct watchdog_info mpc8xxx_wdt_info = {
+ .options = WDIOF_KEEPALIVEPING,
+ .firmware_version = 1,
+ .identity = "MPC8xxx",
};
-static struct miscdevice mpc8xxx_wdt_miscdev = {
- .minor = WATCHDOG_MINOR,
- .name = "watchdog",
- .fops = &mpc8xxx_wdt_fops,
+static struct watchdog_ops mpc8xxx_wdt_ops = {
+ .owner = THIS_MODULE,
+ .start = mpc8xxx_wdt_start,
+ .ping = mpc8xxx_wdt_ping,
+ .stop = mpc8xxx_wdt_stop,
+};
+
+static struct watchdog_device mpc8xxx_wdt_dev = {
+ .info = &mpc8xxx_wdt_info,
+ .ops = &mpc8xxx_wdt_ops,
};
static const struct of_device_id mpc8xxx_wdt_match[];
@@ -196,6 +156,7 @@
const struct mpc8xxx_wdt_type *wdt_type;
u32 freq = fsl_get_sys_freq();
bool enabled;
+ unsigned int timeout_sec;
match = of_match_device(mpc8xxx_wdt_match, &ofdev->dev);
if (!match)
@@ -222,6 +183,7 @@
else
timeout_sec = timeout / freq;
+ mpc8xxx_wdt_dev.timeout = timeout_sec;
#ifdef MODULE
ret = mpc8xxx_wdt_init_late();
if (ret)
@@ -237,7 +199,7 @@
* userspace handles it.
*/
if (enabled)
- mpc8xxx_wdt_timer_ping(0);
+ mod_timer(&wdt_timer, jiffies);
return 0;
err_unmap:
iounmap(wd_base);
@@ -247,9 +209,10 @@
static int mpc8xxx_wdt_remove(struct platform_device *ofdev)
{
- mpc8xxx_wdt_pr_warn("watchdog removed");
+ pr_crit("Watchdog removed, expect the %s soon!\n",
+ reset ? "reset" : "machine check exception");
del_timer_sync(&wdt_timer);
- misc_deregister(&mpc8xxx_wdt_miscdev);
+ watchdog_unregister_device(&mpc8xxx_wdt_dev);
iounmap(wd_base);
return 0;
@@ -301,10 +264,11 @@
if (!wd_base)
return -ENODEV;
- ret = misc_register(&mpc8xxx_wdt_miscdev);
+ watchdog_set_nowayout(&mpc8xxx_wdt_dev, nowayout);
+
+ ret = watchdog_register_device(&mpc8xxx_wdt_dev);
if (ret) {
- pr_err("cannot register miscdev on minor=%d (err=%d)\n",
- WATCHDOG_MINOR, ret);
+ pr_err("cannot register watchdog device (err=%d)\n", ret);
return ret;
}
return 0;
diff -ur a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -1146,6 +1146,7 @@
config 8xxx_WDT
tristate "MPC8xxx Platform Watchdog Timer"
depends on PPC_8xx || PPC_83xx || PPC_86xx
+ select WATCHDOG_CORE
help
This driver is for a SoC level watchdog that exists on some
Freescale PowerPC processors. So far this driver supports:
^ permalink raw reply
* [PATCH 0/3] optimize for powerpc _PAGE_NUMA
From: Liu Ping Fan @ 2013-12-04 6:59 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Aneesh Kumar K.V
I saw Aneesh had implemented Numa faults on ppc64. Most of them have been reviewed-by.
So I just diff mine and his to form some trivial modification.
Based on Aneesh's series "[PATCH -V2 0/5] powerpc: mm: Numa faults support for ppc64"
Liu Ping Fan (3):
powerpc: mm: make _PAGE_NUMA take effect
mm: export numa_migrate_prep()
powerpc: mm: optimize for the correctly placed page
arch/powerpc/mm/hash_utils_64.c | 32 ++++++++++++++++++++++++++++++++
include/linux/mm.h | 2 ++
2 files changed, 34 insertions(+)
--
1.8.1.4
^ permalink raw reply
* [PATCH 1/3] powerpc: mm: make _PAGE_NUMA take effect
From: Liu Ping Fan @ 2013-12-04 6:59 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Aneesh Kumar K.V
In-Reply-To: <1386140348-7854-1-git-send-email-pingfank@linux.vnet.ibm.com>
To enable the do_numa_page(), we should not fix _PAGE_NUMA in
hash_page(), so bail out for the case of pte_numa().
Signed-off-by: Liu Ping Fan <pingfank@linux.vnet.ibm.com>
---
arch/powerpc/mm/hash_utils_64.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index fb176e9..9bf1195 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -1033,7 +1033,7 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
/* Get PTE and page size from page tables */
ptep = find_linux_pte_or_hugepte(pgdir, ea, &hugeshift);
- if (ptep == NULL || !pte_present(*ptep)) {
+ if (ptep == NULL || !pte_present(*ptep) || pte_numa(*ptep)) {
DBG_LOW(" no PTE !\n");
rc = 1;
goto bail;
--
1.8.1.4
^ permalink raw reply related
* [PATCH 2/3] mm: export numa_migrate_prep()
From: Liu Ping Fan @ 2013-12-04 6:59 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Aneesh Kumar K.V
In-Reply-To: <1386140348-7854-1-git-send-email-pingfank@linux.vnet.ibm.com>
powerpc will use it in fast path.
Signed-off-by: Liu Ping Fan <pingfank@linux.vnet.ibm.com>
---
include/linux/mm.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 5ab0e22..420fb77 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1092,6 +1092,8 @@ extern unsigned long change_protection(struct vm_area_struct *vma, unsigned long
extern int mprotect_fixup(struct vm_area_struct *vma,
struct vm_area_struct **pprev, unsigned long start,
unsigned long end, unsigned long newflags);
+extern int numa_migrate_prep(struct page *page, struct vm_area_struct *vma,
+ unsigned long addr, int page_nid);
/*
* doesn't attempt to fault and will return short.
--
1.8.1.4
^ permalink raw reply related
* [PATCH 3/3] powerpc: mm: optimize for the correctly placed page
From: Liu Ping Fan @ 2013-12-04 6:59 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Aneesh Kumar K.V
In-Reply-To: <1386140348-7854-1-git-send-email-pingfank@linux.vnet.ibm.com>
The period check of _PAGE_NUMA can probably trigger the check on
the correctly placed page. For this case, we can just insert hpte and
do fast exception return.
Signed-off-by: Liu Ping Fan <pingfank@linux.vnet.ibm.com>
---
arch/powerpc/mm/hash_utils_64.c | 34 +++++++++++++++++++++++++++++++++-
1 file changed, 33 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index 9bf1195..735678c 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -965,6 +965,10 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
const struct cpumask *tmp;
int rc, user_region = 0, local = 0;
int psize, ssize;
+ pte_t old, new;
+ struct vm_area_struct *vma;
+ int page_nid, target_nid;
+ struct page *test_page;
DBG_LOW("hash_page(ea=%016lx, access=%lx, trap=%lx\n",
ea, access, trap);
@@ -1033,12 +1037,40 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
/* Get PTE and page size from page tables */
ptep = find_linux_pte_or_hugepte(pgdir, ea, &hugeshift);
- if (ptep == NULL || !pte_present(*ptep) || pte_numa(*ptep)) {
+ if (ptep == NULL || !pte_present(*ptep)) {
DBG_LOW(" no PTE !\n");
rc = 1;
goto bail;
}
+ old = pte_val(*ptep);
+ if (pte_numa(old)) {
+ /* If fail to lock, let do_page_fault() to handle it */
+ if (down_read_trylock(&mm->mmap_sem)) {
+ vma = find_vma(mm, ea);
+ up_read(&mm->mmap_sem);
+ test_page = pte_page(old);
+ page_nid = page_to_nid(test_page);
+ target_nid = numa_migrate_prep(test_page, vma, ea,
+ page_nid);
+ if (target_nid < 0) {
+ new = pte_mknonnuma(old);
+ /* If ptep is modified under us,
+ * just retry the access
+ */
+ if (unlikely(cmpxchg(ptep, old, new) != old)) {
+ put_page(test_page);
+ return 0;
+ }
+ put_page(test_page);
+ }
+ } else {
+ put_page(test_page);
+ rc = 1;
+ goto bail;
+ }
+ }
+
/* Add _PAGE_PRESENT to the required access perm */
access |= _PAGE_PRESENT;
--
1.8.1.4
^ permalink raw reply related
* Re: [PATCH v3] watchdog: mpc8xxx_wdt convert to watchdog core
From: Guenter Roeck @ 2013-12-04 7:15 UTC (permalink / raw)
To: Christophe Leroy, Wim Van Sebroeck, scottwood
Cc: linuxppc-dev, linux-kernel, linux-watchdog
In-Reply-To: <20131204063214.D1DB01A2BEA@localhost.localdomain>
On 12/03/2013 10:32 PM, Christophe Leroy wrote:
> Convert mpc8xxx_wdt.c to the new watchdog API.
>
> Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
^ permalink raw reply
* Re: [PATCH] ASoC: fsl_ssi: Implement symmetric_channels and symmetric_samplebits
From: Nicolin Chen @ 2013-12-04 7:27 UTC (permalink / raw)
To: Mark Brown; +Cc: alsa-devel, lgirdwood, tiwai, timur, perex, linuxppc-dev
In-Reply-To: <20131203145833.GV27568@sirena.org.uk>
On Tue, Dec 03, 2013 at 02:58:33PM +0000, Mark Brown wrote:
> On Tue, Dec 03, 2013 at 06:38:07PM +0800, Nicolin Chen wrote:
> > Since we introduced symmetric_channels and symmetric_samplebits, we implement
> > these two features to fsl_ssi so as to drop some no-more-needed code and make
> > the driver neat and clean.
>
> Applied, thanks.
Sir, shall we also implement these two to other drivers like codecs?
I know this symmetry is a new feature and might be still immature.
By implementing it might bring some side effects. But meanwhile, it
would also allows us to engage more people to test it, although myself
have done a branch of tests with different user cases on my platform.
Or we just wait for people engaging by themselves?
Thank you,
Nicolin Chen
^ permalink raw reply
* Re: [PATCH v4 1/1] powerpc/embedded6xx: Add support for Motorola/Emerson MVME5100
From: Geert Uytterhoeven @ 2013-12-04 9:50 UTC (permalink / raw)
To: Stephen Chivers; +Cc: linuxppc-dev@lists.ozlabs.org, cproctor
In-Reply-To: <20131203220056.36011E0729@canberra.localdomain>
On Tue, Dec 3, 2013 at 11:00 PM, Stephen Chivers <schivers@csc.com> wrote:
> Address comments by Kular Gama and Scott Wood.
Kumar Gala.
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* [PATCH V4 02/10] powerpc, perf: Enable conditional branch filter for POWER8
From: Anshuman Khandual @ 2013-12-04 10:32 UTC (permalink / raw)
To: linuxppc-dev, linux-kernel
Cc: mikey, ak, eranian, michael, acme, sukadev, mingo
In-Reply-To: <1386153162-11225-1-git-send-email-khandual@linux.vnet.ibm.com>
Enables conditional branch filter support for POWER8
utilizing MMCRA register based filter and also invalidates
any BHRB branch filter combination.
Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
---
arch/powerpc/perf/power8-pmu.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/arch/powerpc/perf/power8-pmu.c b/arch/powerpc/perf/power8-pmu.c
index a3f7abd..e88b9cb 100644
--- a/arch/powerpc/perf/power8-pmu.c
+++ b/arch/powerpc/perf/power8-pmu.c
@@ -586,6 +586,16 @@ static u64 power8_bhrb_filter_map(u64 branch_sample_type)
return pmu_bhrb_filter;
}
+ if (branch_sample_type & PERF_SAMPLE_BRANCH_COND) {
+ pmu_bhrb_filter |= POWER8_MMCRA_IFM3;
+ return pmu_bhrb_filter;
+ }
+
+ /* PMU does not support ANY combination of HW BHRB filters */
+ if ((branch_sample_type & PERF_SAMPLE_BRANCH_ANY_CALL) &&
+ (branch_sample_type & PERF_SAMPLE_BRANCH_COND))
+ return -1;
+
/* Every thing else is unsupported */
return -1;
}
--
1.7.11.7
^ permalink raw reply related
* [PATCH V4 05/10] perf, documentation: Description for conditional branch filter
From: Anshuman Khandual @ 2013-12-04 10:32 UTC (permalink / raw)
To: linuxppc-dev, linux-kernel
Cc: mikey, ak, eranian, michael, acme, sukadev, mingo
In-Reply-To: <1386153162-11225-1-git-send-email-khandual@linux.vnet.ibm.com>
Adding documentation support for conditional branch filter.
Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
Reviewed-by: Stephane Eranian <eranian@google.com>
---
tools/perf/Documentation/perf-record.txt | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index 43b42c4..5ecc405 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -183,9 +183,10 @@ following filters are defined:
- in_tx: only when the target is in a hardware transaction
- no_tx: only when the target is not in a hardware transaction
- abort_tx: only when the target is a hardware transaction abort
+ - cond: conditional branches
+
-The option requires at least one branch type among any, any_call, any_ret, ind_call.
+The option requires at least one branch type among any, any_call, any_ret, ind_call, cond.
The privilege levels may be omitted, in which case, the privilege levels of the associated
event are applied to the branch filter. Both kernel (k) and hypervisor (hv) privilege
levels are subject to permissions. When sampling on multiple events, branch stack sampling
--
1.7.11.7
^ permalink raw reply related
* [PATCH V4 08/10] powerpc, perf: Enable SW filtering in branch stack sampling framework
From: Anshuman Khandual @ 2013-12-04 10:32 UTC (permalink / raw)
To: linuxppc-dev, linux-kernel
Cc: mikey, ak, eranian, michael, acme, sukadev, mingo
In-Reply-To: <1386153162-11225-1-git-send-email-khandual@linux.vnet.ibm.com>
This patch enables SW based post processing of BHRB captured branches
to be able to meet more user defined branch filtration criteria in perf
branch stack sampling framework. These changes increase the number of
branch filters and their valid combinations on any powerpc64 server
platform with BHRB support. Find the summary of code changes here.
(1) struct cpu_hw_events
Introduced two new variables track various filter values and mask
(a) bhrb_sw_filter Tracks SW implemented branch filter flags
(b) filter_mask Tracks both (SW and HW) branch filter flags
(2) Event creation
Kernel will figure out supported BHRB branch filters through a PMU call
back 'bhrb_filter_map'. This function will find out how many of the
requested branch filters can be supported in the PMU HW. It will not
try to invalidate any branch filter combinations. Event creation will not
error out because of lack of HW based branch filters. Meanwhile it will
track the overall supported branch filters in the "filter_mask" variable.
Once the PMU call back returns kernel will process the user branch filter
request against available SW filters while looking at the "filter_mask".
During this phase all the branch filters which are still pending from the
user requested list will have to be supported in SW failing which the
event creation will error out.
(3) SW branch filter
During the BHRB data capture inside the PMU interrupt context, each
of the captured 'perf_branch_entry.from' will be checked for compliance
with applicable SW branch filters. If the entry does not conform to the
filter requirements, it will be discarded from the final perf branch
stack buffer.
(4) Supported SW based branch filters
(a) PERF_SAMPLE_BRANCH_ANY_RETURN
(b) PERF_SAMPLE_BRANCH_IND_CALL
(c) PERF_SAMPLE_BRANCH_ANY_CALL
(d) PERF_SAMPLE_BRANCH_COND
Please refer patch to understand the classification of instructions into
these branch filter categories.
(5) Multiple branch filter semantics
Book3 sever implementation follows the same OR semantics (as implemented in
x86) while dealing with multiple branch filters at any point of time. SW
branch filter analysis is carried on the data set captured in the PMU HW.
So the resulting set of data (after applying the SW filters) will inherently
be an AND with the HW captured set. Hence any combination of HW and SW branch
filters will be invalid. HW based branch filters are more efficient and faster
compared to SW implemented branch filters. So at first the PMU should decide
whether it can support all the requested branch filters itself or not. In case
it can support all the branch filters in an OR manner, we dont apply any SW
branch filter on top of the HW captured set (which is the final set). This
preserves the OR semantic of multiple branch filters as required. But in case
where the PMU cannot support all the requested branch filters in an OR manner,
it should not apply any it's filters and leave it upto the SW to handle them
all. Its the PMU code's responsibility to uphold this protocol to be able to
conform to the overall OR semantic of perf branch stack sampling framework.
Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/perf_event_server.h | 6 +-
arch/powerpc/perf/core-book3s.c | 266 ++++++++++++++++++++++++++-
arch/powerpc/perf/power8-pmu.c | 2 +-
3 files changed, 262 insertions(+), 12 deletions(-)
diff --git a/arch/powerpc/include/asm/perf_event_server.h b/arch/powerpc/include/asm/perf_event_server.h
index 3fd2f1b..846d710 100644
--- a/arch/powerpc/include/asm/perf_event_server.h
+++ b/arch/powerpc/include/asm/perf_event_server.h
@@ -18,6 +18,10 @@
#define MAX_EVENT_ALTERNATIVES 8
#define MAX_LIMITED_HWCOUNTERS 2
+#define for_each_branch_sample_type(x) \
+ for ((x) = PERF_SAMPLE_BRANCH_USER; \
+ (x) < PERF_SAMPLE_BRANCH_MAX; (x) <<= 1)
+
/*
* This struct provides the constants and functions needed to
* describe the PMU on a particular POWER-family CPU.
@@ -34,7 +38,7 @@ struct power_pmu {
unsigned long *valp);
int (*get_alternatives)(u64 event_id, unsigned int flags,
u64 alt[]);
- u64 (*bhrb_filter_map)(u64 branch_sample_type);
+ u64 (*bhrb_filter_map)(u64 branch_sample_type, u64 *filter_mask);
void (*config_bhrb)(u64 pmu_bhrb_filter);
void (*disable_pmc)(unsigned int pmc, unsigned long mmcr[]);
int (*limited_pmc_event)(u64 event_id);
diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c
index 2de7d48..54d39a5 100644
--- a/arch/powerpc/perf/core-book3s.c
+++ b/arch/powerpc/perf/core-book3s.c
@@ -48,6 +48,8 @@ struct cpu_hw_events {
/* BHRB bits */
u64 bhrb_hw_filter; /* BHRB HW branch filter */
+ u64 bhrb_sw_filter; /* BHRB SW branch filter */
+ u64 filter_mask; /* Branch filter mask */
int bhrb_users;
void *bhrb_context;
struct perf_branch_stack bhrb_stack;
@@ -400,6 +402,228 @@ static __u64 power_pmu_bhrb_to(u64 addr)
return target - (unsigned long)&instr + addr;
}
+/*
+ * Instruction opcode analysis
+ *
+ * Analyse instruction opcodes and classify them
+ * into various branch filter options available.
+ * This follows the standard semantics of OR which
+ * means that instructions which conforms to `any`
+ * of the requested branch filters get picked up.
+ */
+static bool validate_instruction(unsigned int *addr, u64 bhrb_sw_filter)
+{
+ bool result = false;
+
+ if (bhrb_sw_filter & PERF_SAMPLE_BRANCH_ANY_RETURN) {
+
+ /* XL-form instruction */
+ if (instr_is_branch_xlform(*addr)) {
+
+ /* LR should not be set */
+ if (!is_branch_link_set(*addr)) {
+ /*
+ * Conditional and unconditional
+ * branch to LR register.
+ */
+ if (is_xlform_lr(*addr))
+ result = true;
+ }
+ }
+ }
+
+ if (bhrb_sw_filter & PERF_SAMPLE_BRANCH_IND_CALL) {
+ /* XL-form instruction */
+ if (instr_is_branch_xlform(*addr)) {
+
+ /* LR should be set */
+ if (is_branch_link_set(*addr)) {
+ /*
+ * Conditional and unconditional
+ * branch to CTR.
+ */
+ if (is_xlform_ctr(*addr))
+ result = true;
+
+ /*
+ * Conditional and unconditional
+ * branch to LR.
+ */
+ if (is_xlform_lr(*addr))
+ result = true;
+
+ /*
+ * Conditional and unconditional
+ * branch to TAR.
+ */
+ if (is_xlform_tar(*addr))
+ result = true;
+ }
+ }
+ }
+
+ /* Any-form branch */
+ if (bhrb_sw_filter & PERF_SAMPLE_BRANCH_ANY_CALL) {
+ /* LR should be set */
+ if (is_branch_link_set(*addr))
+ result = true;
+ }
+
+ if (bhrb_sw_filter & PERF_SAMPLE_BRANCH_COND) {
+
+ /* I-form instruction - excluded */
+ if (instr_is_branch_iform(*addr))
+ goto out;
+
+ /* B-form or XL-form instruction */
+ if (instr_is_branch_bform(*addr) || instr_is_branch_xlform(*addr)) {
+
+ /* Not branch always */
+ if (!is_bo_always(*addr)) {
+
+ /* Conditional branch to CTR register */
+ if (is_bo_ctr(*addr))
+ goto out;
+
+ /* CR[BI] conditional branch with static hint */
+ if (is_bo_crbi_off(*addr) || is_bo_crbi_on(*addr)) {
+ if (is_bo_crbi_hint(*addr))
+ goto out;
+ }
+
+ result = true;
+ }
+ }
+ }
+out:
+ return result;
+}
+
+static bool check_instruction(u64 addr, u64 bhrb_sw_filter)
+{
+ unsigned int instr;
+ bool ret;
+
+ if (bhrb_sw_filter == 0)
+ return true;
+
+ if (is_kernel_addr(addr)) {
+ ret = validate_instruction((unsigned int *) addr, bhrb_sw_filter);
+ } else {
+ /*
+ * Userspace address needs to be
+ * copied first before analysis.
+ */
+ pagefault_disable();
+ ret = __get_user_inatomic(instr, (unsigned int __user *)addr);
+
+ /*
+ * If the instruction could not be accessible
+ * from user space, we still 'okay' the entry.
+ */
+ if (ret) {
+ pagefault_enable();
+ return true;
+ }
+ pagefault_enable();
+ ret = validate_instruction(&instr, bhrb_sw_filter);
+ }
+ return ret;
+}
+
+/*
+ * Validate whether all requested branch filters
+ * are getting processed either in the PMU or in SW.
+ */
+static int match_filters(u64 branch_sample_type, u64 filter_mask)
+{
+ u64 x;
+
+ if (filter_mask == PERF_SAMPLE_BRANCH_ANY)
+ return true;
+
+ for_each_branch_sample_type(x) {
+ if (!(branch_sample_type & x))
+ continue;
+ /*
+ * Privilege filter requests have been already
+ * taken care during the base PMU configuration.
+ */
+ if (x == PERF_SAMPLE_BRANCH_USER)
+ continue;
+ if (x == PERF_SAMPLE_BRANCH_KERNEL)
+ continue;
+ if (x == PERF_SAMPLE_BRANCH_HV)
+ continue;
+
+ /*
+ * Requested filter not available either
+ * in PMU or in SW.
+ */
+ if (!(filter_mask & x))
+ return false;
+ }
+ return true;
+}
+
+/*
+ * Required SW based branch filters
+ *
+ * This is called after figuring out what all branch filters the
+ * PMU HW supports for the requested branch filter set. Here we
+ * will go through all the SW implemented branch filters one by
+ * one and pick them up if its not already supported in the PMU.
+ */
+static u64 branch_filter_map(u64 branch_sample_type, u64 pmu_bhrb_filter,
+ u64 *filter_mask)
+{
+ u64 branch_sw_filter = 0;
+
+ /* No branch filter requested */
+ if (branch_sample_type & PERF_SAMPLE_BRANCH_ANY) {
+ WARN_ON(pmu_bhrb_filter != 0);
+ WARN_ON(*filter_mask != PERF_SAMPLE_BRANCH_ANY);
+ return branch_sw_filter;
+ }
+
+ /*
+ * PMU supported branch filters must also be implemented in SW
+ * in the event when the PMU is unable to process them for some
+ * reason. This all those branch filters can be satisfied with
+ * SW implemented filters. But right now, there is now way to
+ * initimate the user about this decision.
+ */
+ if (branch_sample_type & PERF_SAMPLE_BRANCH_ANY_CALL) {
+ if (!(pmu_bhrb_filter & PERF_SAMPLE_BRANCH_ANY_CALL)) {
+ branch_sw_filter |= PERF_SAMPLE_BRANCH_ANY_CALL;
+ *filter_mask |= PERF_SAMPLE_BRANCH_ANY_CALL;
+ }
+ }
+
+ if (branch_sample_type & PERF_SAMPLE_BRANCH_COND) {
+ if (!(pmu_bhrb_filter & PERF_SAMPLE_BRANCH_COND)) {
+ branch_sw_filter |= PERF_SAMPLE_BRANCH_COND;
+ *filter_mask |= PERF_SAMPLE_BRANCH_COND;
+ }
+ }
+
+ if (branch_sample_type & PERF_SAMPLE_BRANCH_ANY_RETURN) {
+ if (!(pmu_bhrb_filter & PERF_SAMPLE_BRANCH_ANY_RETURN)) {
+ branch_sw_filter |= PERF_SAMPLE_BRANCH_ANY_RETURN;
+ *filter_mask |= PERF_SAMPLE_BRANCH_ANY_RETURN;
+ }
+ }
+
+ if (branch_sample_type & PERF_SAMPLE_BRANCH_IND_CALL) {
+ if (!(pmu_bhrb_filter & PERF_SAMPLE_BRANCH_IND_CALL)) {
+ branch_sw_filter |= PERF_SAMPLE_BRANCH_IND_CALL;
+ *filter_mask |= PERF_SAMPLE_BRANCH_IND_CALL;
+ }
+ }
+
+ return branch_sw_filter;
+}
+
/* Processing BHRB entries */
void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw)
{
@@ -459,17 +683,29 @@ void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw)
addr = 0;
}
cpuhw->bhrb_entries[u_index].from = addr;
+
+ if (!check_instruction(cpuhw->
+ bhrb_entries[u_index].from,
+ cpuhw->bhrb_sw_filter))
+ u_index--;
} else {
/* Branches to immediate field
(ie I or B form) */
cpuhw->bhrb_entries[u_index].from = addr;
- cpuhw->bhrb_entries[u_index].to =
- power_pmu_bhrb_to(addr);
- cpuhw->bhrb_entries[u_index].mispred = pred;
- cpuhw->bhrb_entries[u_index].predicted = ~pred;
+ if (check_instruction(cpuhw->
+ bhrb_entries[u_index].from,
+ cpuhw->bhrb_sw_filter)) {
+ cpuhw->bhrb_entries[u_index].
+ to = power_pmu_bhrb_to(addr);
+ cpuhw->bhrb_entries[u_index].
+ mispred = pred;
+ cpuhw->bhrb_entries[u_index].
+ predicted = ~pred;
+ } else {
+ u_index--;
+ }
}
u_index++;
-
}
}
cpuhw->bhrb_stack.nr = u_index;
@@ -1255,7 +1491,11 @@ nocheck:
if (has_branch_stack(event)) {
power_pmu_bhrb_enable(event);
cpuhw->bhrb_hw_filter = ppmu->bhrb_filter_map(
- event->attr.branch_sample_type);
+ event->attr.branch_sample_type,
+ &cpuhw->filter_mask);
+ cpuhw->bhrb_sw_filter = branch_filter_map
+ (event->attr.branch_sample_type,
+ cpuhw->bhrb_hw_filter, &cpuhw->filter_mask);
}
perf_pmu_enable(event->pmu);
@@ -1637,10 +1877,16 @@ static int power_pmu_event_init(struct perf_event *event)
err = power_check_constraints(cpuhw, events, cflags, n + 1);
if (has_branch_stack(event)) {
- cpuhw->bhrb_hw_filter = ppmu->bhrb_filter_map(
- event->attr.branch_sample_type);
-
- if(cpuhw->bhrb_hw_filter == -1)
+ cpuhw->bhrb_hw_filter = ppmu->bhrb_filter_map
+ (event->attr.branch_sample_type,
+ &cpuhw->filter_mask);
+ cpuhw->bhrb_sw_filter = branch_filter_map
+ (event->attr.branch_sample_type,
+ cpuhw->bhrb_hw_filter,
+ &cpuhw->filter_mask);
+
+ if(!match_filters(event->attr.branch_sample_type,
+ cpuhw->filter_mask))
return -EOPNOTSUPP;
}
diff --git a/arch/powerpc/perf/power8-pmu.c b/arch/powerpc/perf/power8-pmu.c
index e88b9cb..03c5b8d 100644
--- a/arch/powerpc/perf/power8-pmu.c
+++ b/arch/powerpc/perf/power8-pmu.c
@@ -559,7 +559,7 @@ static int power8_generic_events[] = {
[PERF_COUNT_HW_BRANCH_MISSES] = PM_BR_MPRED_CMPL,
};
-static u64 power8_bhrb_filter_map(u64 branch_sample_type)
+static u64 power8_bhrb_filter_map(u64 branch_sample_type, u64 *filter_mask)
{
u64 pmu_bhrb_filter = 0;
--
1.7.11.7
^ permalink raw reply related
* [PATCH V4 00/10] perf: New conditional branch filter
From: Anshuman Khandual @ 2013-12-04 10:32 UTC (permalink / raw)
To: linuxppc-dev, linux-kernel
Cc: mikey, ak, eranian, michael, acme, sukadev, mingo
This patchset is the re-spin of the original branch stack sampling
patchset which introduced new PERF_SAMPLE_BRANCH_COND branch filter. This patchset
also enables SW based branch filtering support for book3s powerpc platforms which
have PMU HW backed branch stack sampling support.
Summary of code changes in this patchset:
(1) Introduces a new PERF_SAMPLE_BRANCH_COND branch filter
(2) Add the "cond" branch filter options in the "perf record" tool
(3) Enable PERF_SAMPLE_BRANCH_COND in X86 platforms
(4) Enable PERF_SAMPLE_BRANCH_COND in POWER8 platform
(5) Update the documentation regarding "perf record" tool
(6) Add some new powerpc instruction analysis functions in code-patching library
(7) Enable SW based branch filter support for powerpc book3s
(8) Changed BHRB configuration in POWER8 to accommodate SW branch filters
With this new SW enablement, the branch filter support for book3s platforms have
been extended to include all these combinations discussed below with a sample test
application program (included here).
Changes in V2
=============
(1) Enabled PPC64 SW branch filtering support
(2) Incorporated changes required for all previous comments
Changes in V3
=============
(1) Split the SW branch filter enablement into multiple patches
(2) Added PMU neutral SW branch filtering code, PMU specific HW branch filtering code
(3) Added new instruction analysis functionality into powerpc code-patching library
(4) Changed name for some of the functions
(5) Fixed couple of spelling mistakes
(6) Changed code documentation in multiple places
Changes in V4
=============
(1) Changed the commit message for patch (01/10)
(2) Changed the patch (02/10) to accommodate review comments from Michael Ellerman
(3) Rebased the patchset against latest Linus's tree
PMU HW branch filters
=====================
(1) perf record -j any_call -e branch-misses:u ./cprog
# Overhead Command Source Shared Object Source Symbol Target Shared Object Target Symbol
# ........ ....... .................... ..................... .................... ........................
#
7.00% cprog cprog [.] sw_3_1 cprog [.] sw_3_1_2
6.99% cprog cprog [.] hw_1_1 cprog [.] symbol1
6.52% cprog cprog [.] sw_3_1 cprog [.] success_3_1_2
5.41% cprog cprog [.] sw_3_1 cprog [.] sw_3_1_3
5.40% cprog cprog [.] hw_1_2 cprog [.] symbol2
5.40% cprog cprog [.] callme cprog [.] hw_1_2
5.40% cprog cprog [.] sw_3_1 cprog [.] success_3_1_1
5.40% cprog cprog [.] callme cprog [.] hw_1_1
5.39% cprog cprog [.] sw_3_1 cprog [.] sw_3_1_1
5.39% cprog cprog [.] sw_4_2 cprog [.] lr_addr
5.39% cprog cprog [.] callme cprog [.] sw_4_2
5.37% cprog [unknown] [.] 00000000 cprog [.] ctr_addr
4.30% cprog cprog [.] callme cprog [.] hw_2_1
4.28% cprog cprog [.] callme cprog [.] sw_3_1
3.82% cprog cprog [.] sw_3_1 cprog [.] success_3_1_3
3.81% cprog cprog [.] callme cprog [.] hw_2_2
3.81% cprog cprog [.] callme cprog [.] sw_3_2
2.71% cprog [unknown] [.] 00000000 cprog [.] lr_addr
2.70% cprog cprog [.] main cprog [.] callme
2.70% cprog cprog [.] sw_4_1 cprog [.] ctr_addr
2.70% cprog cprog [.] callme cprog [.] sw_4_1
0.08% cprog [unknown] [.] 0xf78676c4 [unknown] [.] 0xf78522c0
0.02% cprog [unknown] [k] 00000000 cprog [k] ctr_addr
0.01% cprog [kernel.kallsyms] [.] .power_pmu_enable [kernel.kallsyms] [.] .power8_compute_mmcr
0.00% cprog ld-2.11.2.so [.] malloc [unknown] [.] 0xf786b380
0.00% cprog ld-2.11.2.so [.] calloc [unknown] [.] 0xf786b390
0.00% cprog cprog [.] main [unknown] [.] 0x10000950
0.00% cprog [unknown] [.] 00000000 [kernel.kallsyms] [.] .power_pmu_enable
(2) perf record -j cond -e branch-misses:u ./cprog
# Overhead Command Source Shared Object Source Symbol Target Shared Object Target Symbol
# ........ ....... .................... ....................... .................... .......................
#
27.73% cprog [unknown] [.] 00000000 cprog [.] callme
13.03% cprog cprog [.] sw_3_1 cprog [.] sw_3_1
5.64% cprog [unknown] [.] 00000000 cprog [.] main
5.62% cprog [unknown] [.] 00000000 cprog [.] sw_4_2
5.46% cprog cprog [.] sw_4_2 cprog [.] lr_addr
5.40% cprog [unknown] [.] 00000000 cprog [.] sw_4_1
3.72% cprog cprog [.] hw_2_1 cprog [.] callme
3.71% cprog cprog [.] main cprog [.] hw_1_1
3.71% cprog cprog [.] sw_3_1_2 cprog [.] sw_3_1
3.70% cprog cprog [.] sw_3_1_3 cprog [.] sw_3_1
3.70% cprog cprog [.] sw_4_1 cprog [.] ctr_addr
3.69% cprog cprog [.] hw_1_2 cprog [.] hw_1_2
3.69% cprog cprog [.] hw_2_2 cprog [.] callme
3.68% cprog cprog [.] sw_3_1_1 cprog [.] sw_3_1
1.93% cprog [unknown] [.] 00000000 cprog [.] lr_addr
1.78% cprog [unknown] [.] 00000000 cprog [.] hw_1_2
1.78% cprog [unknown] [.] 00000000 cprog [.] sw_3_1
1.76% cprog [unknown] [.] 00000000 cprog [.] hw_1_1
0.12% cprog [unknown] [.] 0xf7bb25dc [unknown] [.] 0xf7bb27e4
0.07% cprog [unknown] [k] 00000000 cprog [k] callme
0.07% cprog [unknown] [k] 00000000 cprog [k] sw_4_1
0.00% cprog libc-2.11.2.so [.] _IO_file_doallocate libc-2.11.2.so [.] _IO_file_doallocate
0.00% cprog libc-2.11.2.so [.] _IO_file_doallocate libc-2.11.2.so [.] isatty
0.00% cprog [unknown] [.] 00000000 libc-2.11.2.so [.] _IO_file_doallocate
SW based branch filters
=======================
(3) perf record -j any_ret -e branch-misses:u ./cprog
# Overhead Command Source Shared Object Source Symbol Target Shared Object Target Symbol
# ........ ....... .................... .................... .................... .....................
#
15.37% cprog [unknown] [.] 00000000 cprog [.] sw_3_1
6.46% cprog cprog [.] success_3_1_3 cprog [.] sw_3_1
6.45% cprog cprog [.] symbol1 cprog [.] hw_1_1
6.41% cprog [unknown] [.] 00000000 cprog [.] callme
6.39% cprog cprog [.] ctr_addr cprog [.] sw_4_1
6.37% cprog cprog [.] symbol2 cprog [.] hw_1_2
6.36% cprog cprog [.] sw_4_2 cprog [.] callme
6.35% cprog cprog [.] lr_addr cprog [.] sw_4_2
3.97% cprog cprog [.] back1 cprog [.] callme
3.93% cprog cprog [.] sw_3_1_2 cprog [.] sw_3_1
3.93% cprog cprog [.] sw_3_1 cprog [.] callme
3.86% cprog cprog [.] sw_3_1_3 cprog [.] sw_3_1
3.84% cprog cprog [.] sw_3_1_1 cprog [.] sw_3_1
2.54% cprog cprog [.] success_3_1_1 cprog [.] sw_3_1
2.54% cprog cprog [.] sw_4_1 cprog [.] callme
2.54% cprog cprog [.] hw_1_1 cprog [.] callme
2.53% cprog cprog [.] sw_3_2 cprog [.] callme
2.52% cprog cprog [.] callme cprog [.] main
2.51% cprog cprog [.] hw_1_2 cprog [.] callme
2.51% cprog cprog [.] back2 cprog [.] callme
2.51% cprog cprog [.] success_3_1_2 cprog [.] sw_3_1
0.07% cprog [unknown] [k] 00000000 cprog [k] callme
0.02% cprog [unknown] [.] 00000000 [unknown] [.] 0xf7e5c004
0.01% cprog libc-2.11.2.so [.] __errno_location libc-2.11.2.so [.] vfprintf
0.01% cprog [unknown] [.] 00000000 libc-2.11.2.so [.] _IO_file_overflow
(4) perf record -j ind_call -e branch-misses:u ./cprog
# Overhead Command Source Shared Object Source Symbol Target Shared Object Target Symbol
# ........ ....... .................... ................... .................... .....................
#
48.04% cprog [unknown] [.] 00000000 cprog [.] sw_3_1
19.96% cprog cprog [.] sw_4_2 cprog [.] lr_addr
19.69% cprog [unknown] [.] 00000000 cprog [.] callme
12.04% cprog cprog [.] sw_4_1 cprog [.] ctr_addr
0.18% cprog [unknown] [k] 00000000 cprog [k] callme
0.02% cprog libc-2.11.2.so [.] _IO_file_xsputn libc-2.11.2.so [.] _IO_file_overflow
0.02% cprog [unknown] [.] 00000000 libc-2.11.2.so [.] _IO_file_xsputn
0.02% cprog [unknown] [.] 00000000 ld-2.11.2.so [.] malloc
0.02% cprog [unknown] [k] 00000000 cprog [k] sw_3_1
(5) perf record -j any_call,any_ret -e branch-misses:u ./cprog
# Overhead Command Source Shared Object Source Symbol Target Shared Object Target Symbol
# ........ ....... .................... ....................... .................... .......................
#
10.36% cprog [unknown] [.] 00000000 cprog [.] sw_3_1
4.18% cprog cprog [.] symbol1 cprog [.] hw_1_1
4.18% cprog cprog [.] success_3_1_3 cprog [.] sw_3_1
4.17% cprog cprog [.] sw_4_2 cprog [.] lr_addr
4.16% cprog cprog [.] sw_4_2 cprog [.] callme
4.15% cprog cprog [.] ctr_addr cprog [.] sw_4_1
4.15% cprog cprog [.] lr_addr cprog [.] sw_4_2
4.14% cprog cprog [.] symbol2 cprog [.] hw_1_2
4.14% cprog [unknown] [.] 00000000 cprog [.] callme
2.15% cprog cprog [.] sw_3_1 cprog [.] callme
2.14% cprog cprog [.] hw_1_1 cprog [.] symbol1
2.14% cprog cprog [.] callme cprog [.] hw_1_1
2.14% cprog cprog [.] callme cprog [.] sw_4_2
2.13% cprog cprog [.] back1 cprog [.] callme
2.12% cprog cprog [.] sw_3_1_2 cprog [.] sw_3_1
2.12% cprog cprog [.] sw_3_1 cprog [.] sw_3_1_2
2.11% cprog cprog [.] sw_3_1_3 cprog [.] sw_3_1
2.11% cprog cprog [.] sw_3_1 cprog [.] sw_3_1_3
2.11% cprog cprog [.] sw_4_1 cprog [.] ctr_addr
2.10% cprog cprog [.] hw_1_2 cprog [.] symbol2
2.10% cprog cprog [.] sw_3_1_1 cprog [.] sw_3_1
2.10% cprog cprog [.] sw_3_1 cprog [.] sw_3_1_1
2.10% cprog cprog [.] callme cprog [.] hw_1_2
2.10% cprog cprog [.] callme cprog [.] sw_3_1
2.05% cprog cprog [.] success_3_1_1 cprog [.] sw_3_1
2.05% cprog cprog [.] sw_3_1 cprog [.] success_3_1_1
2.05% cprog cprog [.] success_3_1_2 cprog [.] sw_3_1
2.05% cprog cprog [.] sw_3_1 cprog [.] success_3_1_2
2.04% cprog cprog [.] hw_1_1 cprog [.] callme
2.04% cprog cprog [.] back2 cprog [.] callme
2.04% cprog cprog [.] sw_4_1 cprog [.] callme
2.04% cprog cprog [.] callme cprog [.] main
2.04% cprog cprog [.] hw_1_2 cprog [.] callme
2.04% cprog cprog [.] sw_3_2 cprog [.] callme
2.04% cprog cprog [.] callme cprog [.] sw_3_2
2.03% cprog cprog [.] sw_3_1 cprog [.] success_3_1_3
0.03% cprog [unknown] [k] 00000000 cprog [k] callme
0.01% cprog [unknown] [.] 0xf7e79bb0 [unknown] [.] 0xf7e64088
0.00% cprog libc-2.11.2.so [.] _IO_file_doallocate libc-2.11.2.so [.] mmap
0.00% cprog libc-2.11.2.so [.] mmap libc-2.11.2.so [.] _IO_file_doallocate
0.00% cprog [unknown] [.] 0xf7e7589c libc-2.11.2.so [.] printf
0.00% cprog [unknown] [k] 00000000 cprog [k] sw_3_1
(6) perf record -j any_call,ind_call -e branch-misses:u ./cprog
# Overhead Command Source Shared Object Source Symbol Target Shared Object Target Symbol
# ........ ....... .................... .............. .................... .................
#
23.09% cprog [unknown] [.] 00000000 cprog [.] sw_3_1
8.99% cprog cprog [.] sw_4_2 cprog [.] lr_addr
8.92% cprog [unknown] [.] 00000000 cprog [.] callme
5.18% cprog cprog [.] sw_3_1 cprog [.] success_3_1_2
5.16% cprog cprog [.] sw_3_1 cprog [.] success_3_1_1
5.16% cprog cprog [.] callme cprog [.] sw_3_2
5.12% cprog cprog [.] sw_3_1 cprog [.] success_3_1_3
3.85% cprog cprog [.] sw_3_1 cprog [.] sw_3_1_1
3.85% cprog cprog [.] callme cprog [.] sw_3_1
3.84% cprog cprog [.] sw_4_1 cprog [.] ctr_addr
3.82% cprog cprog [.] hw_1_1 cprog [.] symbol1
3.82% cprog cprog [.] sw_3_1 cprog [.] sw_3_1_2
3.82% cprog cprog [.] sw_3_1 cprog [.] sw_3_1_3
3.82% cprog cprog [.] callme cprog [.] hw_1_1
3.81% cprog cprog [.] hw_1_2 cprog [.] symbol2
3.81% cprog cprog [.] callme cprog [.] hw_1_2
3.81% cprog cprog [.] callme cprog [.] sw_4_2
0.05% cprog [unknown] [k] 00000000 cprog [k] callme
0.03% cprog [unknown] [.] 0xf7f7232c [unknown] [.] 0xf7f72334
0.01% cprog ld-2.11.2.so [.] malloc [unknown] [.] 0xf7f8b380
0.01% cprog cprog [.] main [unknown] [.] 0x10000950
0.01% cprog [unknown] [.] 00000000 ld-2.11.2.so [.] malloc
0.01% cprog [unknown] [.] 00000000 cprog [.] main
(7) perf record -j cond,any_ret -e branch-misses:u ./cprog
# Overhead Command Source Shared Object Source Symbol Target Shared Object Target Symbol
# ........ ....... .................... ..................... .................... .....................
#
12.18% cprog [unknown] [.] 00000000 cprog [.] sw_3_1
4.90% cprog cprog [.] sw_4_2 cprog [.] lr_addr
4.88% cprog [unknown] [.] 00000000 cprog [.] callme
4.88% cprog cprog [.] lr_addr cprog [.] sw_4_2
4.88% cprog cprog [.] sw_4_2 cprog [.] callme
4.86% cprog cprog [.] symbol1 cprog [.] hw_1_1
4.86% cprog cprog [.] success_3_1_3 cprog [.] sw_3_1
4.85% cprog cprog [.] symbol2 cprog [.] hw_1_2
4.85% cprog cprog [.] ctr_addr cprog [.] sw_4_1
2.47% cprog cprog [.] sw_3_1_3 cprog [.] sw_3_1
2.46% cprog cprog [.] back1 cprog [.] callme
2.45% cprog cprog [.] hw_1_1 cprog [.] callme
2.45% cprog cprog [.] hw_2_1 cprog [.] address1
2.44% cprog cprog [.] hw_1_2 cprog [.] symbol2
2.44% cprog cprog [.] sw_3_1_1 cprog [.] sw_3_1
2.44% cprog cprog [.] sw_3_2 cprog [.] callme
2.44% cprog cprog [.] success_3_1_1 cprog [.] sw_3_1
2.44% cprog cprog [.] sw_3_1 cprog [.] success_3_1_1
2.44% cprog cprog [.] sw_3_1 cprog [.] success_3_1_3
2.43% cprog cprog [.] callme cprog [.] main
2.43% cprog cprog [.] hw_2_2 cprog [.] address2
2.43% cprog cprog [.] sw_3_1_2 cprog [.] sw_3_1
2.43% cprog cprog [.] success_3_1_2 cprog [.] sw_3_1
2.43% cprog cprog [.] sw_3_1 cprog [.] success_3_1_2
2.43% cprog cprog [.] sw_4_1 cprog [.] callme
2.42% cprog cprog [.] sw_3_1 cprog [.] callme
2.42% cprog cprog [.] sw_4_1 cprog [.] ctr_addr
2.42% cprog cprog [.] back2 cprog [.] callme
2.40% cprog cprog [.] hw_1_2 cprog [.] callme
0.10% cprog [unknown] [.] 0xf78923e0 [unknown] [.] 0xf78923c0
0.03% cprog [unknown] [k] 00000000 cprog [k] callme
0.01% cprog [unknown] [k] 00000000 cprog [k] sw_3_1
0.01% cprog libc-2.11.2.so [.] vfprintf libc-2.11.2.so [.] vfprintf
0.01% cprog libc-2.11.2.so [.] _IO_file_overflow [unknown] [.] 0x0fee0100
0.01% cprog libc-2.11.2.so [.] strchrnul libc-2.11.2.so [.] vfprintf
0.01% cprog libc-2.11.2.so [.] strchrnul libc-2.11.2.so [.] strchrnul
0.01% cprog [unknown] [.] 00000000 libc-2.11.2.so [.] _IO_file_overflow
(8) perf record -j cond,ind_call -e branch-misses:u ./cprog
# Overhead Command Source Shared Object Source Symbol Target Shared Object Target Symbol
# ........ ....... .................... .............. .................... ...................
#
26.21% cprog [unknown] [.] 00000000 cprog [.] sw_3_1
10.50% cprog cprog [.] sw_4_2 cprog [.] lr_addr
10.38% cprog [unknown] [.] 00000000 cprog [.] callme
5.31% cprog cprog [.] sw_3_1_2 cprog [.] sw_3_1
5.30% cprog cprog [.] sw_3_1_1 cprog [.] sw_3_1
5.27% cprog cprog [.] sw_3_1 cprog [.] success_3_1_2
5.26% cprog cprog [.] hw_2_2 cprog [.] address2
5.25% cprog cprog [.] hw_1_2 cprog [.] symbol2
5.25% cprog cprog [.] sw_3_1 cprog [.] success_3_1_3
5.24% cprog cprog [.] hw_2_1 cprog [.] address1
5.23% cprog cprog [.] sw_4_1 cprog [.] ctr_addr
5.20% cprog cprog [.] sw_3_1_3 cprog [.] sw_3_1
5.19% cprog cprog [.] sw_3_1 cprog [.] success_3_1_1
0.24% cprog [unknown] [.] 0xf7cf23e0 [unknown] [.] 0xf7cf23c0
0.11% cprog [unknown] [k] 00000000 cprog [k] callme
0.01% cprog libc-2.11.2.so [.] vfprintf libc-2.11.2.so [.] vfprintf
0.01% cprog libc-2.11.2.so [.] vfprintf libc-2.11.2.so [.] _IO_file_xsputn
0.01% cprog [unknown] [.] 00000000 libc-2.11.2.so [.] vfprintf
0.01% cprog [unknown] [k] 00000000 cprog [k] sw_3_1
(9) perf record -j any_call,cond,any_ret -e branch-misses:u ./cprog
# Overhead Command Source Shared Object Source Symbol Target Shared Object Target Symbol
# ........ ....... .................... ................. .................... .....................
#
9.96% cprog [unknown] [.] 00000000 cprog [.] sw_3_1
4.06% cprog cprog [.] sw_4_2 cprog [.] lr_addr
4.04% cprog cprog [.] lr_addr cprog [.] sw_4_2
4.03% cprog cprog [.] symbol1 cprog [.] hw_1_1
4.02% cprog [unknown] [.] 00000000 cprog [.] callme
3.96% cprog cprog [.] ctr_addr cprog [.] sw_4_1
3.94% cprog cprog [.] symbol2 cprog [.] hw_1_2
3.94% cprog cprog [.] success_3_1_3 cprog [.] sw_3_1
3.93% cprog cprog [.] sw_4_2 cprog [.] callme
2.08% cprog cprog [.] sw_3_2 cprog [.] callme
2.08% cprog cprog [.] callme cprog [.] sw_3_2
2.07% cprog cprog [.] hw_2_2 cprog [.] address2
2.07% cprog cprog [.] success_3_1_2 cprog [.] sw_3_1
2.07% cprog cprog [.] sw_3_1 cprog [.] success_3_1_2
2.07% cprog cprog [.] back2 cprog [.] callme
2.06% cprog cprog [.] hw_1_1 cprog [.] callme
1.99% cprog cprog [.] sw_4_1 cprog [.] ctr_addr
1.98% cprog cprog [.] sw_3_1_3 cprog [.] sw_3_1
1.98% cprog cprog [.] success_3_1_1 cprog [.] sw_3_1
1.98% cprog cprog [.] sw_3_1 cprog [.] sw_3_1_3
1.98% cprog cprog [.] sw_3_1 cprog [.] success_3_1_1
1.98% cprog cprog [.] callme cprog [.] sw_4_2
1.98% cprog cprog [.] back1 cprog [.] callme
1.97% cprog cprog [.] hw_1_1 cprog [.] symbol1
1.97% cprog cprog [.] hw_2_1 cprog [.] address1
1.97% cprog cprog [.] sw_3_1_1 cprog [.] sw_3_1
1.97% cprog cprog [.] sw_3_1 cprog [.] sw_3_1_1
1.97% cprog cprog [.] sw_3_1 cprog [.] success_3_1_3
1.97% cprog cprog [.] callme cprog [.] hw_1_1
1.97% cprog cprog [.] callme cprog [.] sw_3_1
1.97% cprog cprog [.] hw_1_2 cprog [.] symbol2
1.97% cprog cprog [.] hw_1_2 cprog [.] callme
1.97% cprog cprog [.] sw_4_1 cprog [.] callme
1.97% cprog cprog [.] callme cprog [.] main
1.97% cprog cprog [.] callme cprog [.] hw_1_2
1.96% cprog cprog [.] sw_3_1 cprog [.] callme
1.96% cprog cprog [.] sw_3_1_2 cprog [.] sw_3_1
1.96% cprog cprog [.] sw_3_1 cprog [.] sw_3_1_2
0.12% cprog [unknown] [.] 0xf7ab23e0 [unknown] [.] 0xf7ab23c0
0.04% cprog [unknown] [k] 00000000 cprog [k] callme
0.01% cprog [unknown] [k] 00000000 cprog [k] sw_3_1
0.00% cprog libc-2.11.2.so [.] vfprintf libc-2.11.2.so [.] vfprintf
0.00% cprog libc-2.11.2.so [.] _IO_do_write libc-2.11.2.so [.] _IO_do_write
0.00% cprog libc-2.11.2.so [.] _IO_do_write libc-2.11.2.so [.] _IO_file_overflow
0.00% cprog libc-2.11.2.so [.] strchrnul libc-2.11.2.so [.] vfprintf
0.00% cprog libc-2.11.2.so [.] strchrnul libc-2.11.2.so [.] strchrnul
0.00% cprog cprog [.] callme cprog [.] hw_2_2
0.00% cprog [unknown] [.] 00000000 libc-2.11.2.so [.] _IO_do_write
(10) perf record -j any_call,cond,ind_call -e branch-misses:u ./cprog
# Overhead Command Source Shared Object Source Symbol Target Shared Object Target Symbol
# ........ ....... .................... ..................... .................... .....................
#
17.81% cprog [unknown] [.] 00000000 cprog [.] sw_3_1
7.19% cprog cprog [.] sw_4_2 cprog [.] lr_addr
7.12% cprog [unknown] [.] 00000000 cprog [.] callme
3.71% cprog cprog [.] sw_3_1 cprog [.] success_3_1_2
3.68% cprog cprog [.] callme cprog [.] sw_3_2
3.67% cprog cprog [.] hw_2_2 cprog [.] address2
3.57% cprog cprog [.] hw_2_1 cprog [.] address1
3.55% cprog cprog [.] hw_1_1 cprog [.] symbol1
3.55% cprog cprog [.] sw_3_1 cprog [.] success_3_1_1
3.55% cprog cprog [.] callme cprog [.] hw_1_1
3.54% cprog cprog [.] sw_3_1_1 cprog [.] sw_3_1
3.54% cprog cprog [.] sw_3_1 cprog [.] sw_3_1_1
3.54% cprog cprog [.] sw_4_1 cprog [.] ctr_addr
3.54% cprog cprog [.] callme cprog [.] sw_3_1
3.52% cprog cprog [.] sw_3_1_3 cprog [.] sw_3_1
3.52% cprog cprog [.] sw_3_1 cprog [.] sw_3_1_3
3.52% cprog cprog [.] sw_3_1 cprog [.] success_3_1_3
3.52% cprog cprog [.] sw_3_1_2 cprog [.] sw_3_1
3.52% cprog cprog [.] sw_3_1 cprog [.] sw_3_1_2
3.51% cprog cprog [.] hw_1_2 cprog [.] symbol2
3.51% cprog cprog [.] callme cprog [.] hw_1_2
3.49% cprog cprog [.] callme cprog [.] sw_4_2
0.22% cprog [unknown] [.] 0xf7ca23f4 [unknown] [.] 0xf7ca25d0
0.05% cprog [unknown] [k] 00000000 cprog [k] callme
0.01% cprog libc-2.11.2.so [.] vfprintf libc-2.11.2.so [.] vfprintf
0.01% cprog libc-2.11.2.so [.] vfprintf libc-2.11.2.so [.] strchrnul
0.01% cprog libc-2.11.2.so [.] _IO_file_overflow libc-2.11.2.so [.] _IO_file_overflow
0.01% cprog libc-2.11.2.so [.] strchrnul libc-2.11.2.so [.] strchrnul
0.01% cprog [unknown] [.] 00000000 libc-2.11.2.so [.] _IO_file_overflow
0.01% cprog [unknown] [k] 00000000 cprog [k] sw_3_1
(11) perf record -j any_call,cond,any_ret,ind_call -e branch-misses:u ./cprog
# Overhead Command Source Shared Object Source Symbol Target Shared Object Target Symbol
# ........ ....... .................... ................. .................... ...................
#
9.72% cprog [unknown] [.] 00000000 cprog [.] sw_3_1
3.99% cprog cprog [.] ctr_addr cprog [.] sw_4_1
3.98% cprog cprog [.] success_3_1_3 cprog [.] sw_3_1
3.98% cprog cprog [.] symbol1 cprog [.] hw_1_1
3.98% cprog cprog [.] symbol2 cprog [.] hw_1_2
3.98% cprog cprog [.] sw_4_2 cprog [.] lr_addr
3.98% cprog cprog [.] sw_4_2 cprog [.] callme
3.97% cprog cprog [.] lr_addr cprog [.] sw_4_2
3.91% cprog [unknown] [.] 00000000 cprog [.] callme
2.22% cprog cprog [.] sw_4_1 cprog [.] ctr_addr
2.22% cprog cprog [.] callme cprog [.] sw_4_2
2.22% cprog cprog [.] hw_2_1 cprog [.] address1
2.22% cprog cprog [.] back1 cprog [.] callme
2.21% cprog cprog [.] hw_1_2 cprog [.] symbol2
2.21% cprog cprog [.] sw_3_1 cprog [.] callme
2.21% cprog cprog [.] callme cprog [.] hw_1_2
2.21% cprog cprog [.] sw_3_1_1 cprog [.] sw_3_1
2.21% cprog cprog [.] sw_3_1_3 cprog [.] sw_3_1
2.21% cprog cprog [.] sw_3_1 cprog [.] sw_3_1_1
2.21% cprog cprog [.] sw_3_1 cprog [.] sw_3_1_3
2.21% cprog cprog [.] callme cprog [.] sw_3_1
2.20% cprog cprog [.] hw_1_1 cprog [.] symbol1
2.20% cprog cprog [.] sw_3_1_2 cprog [.] sw_3_1
2.20% cprog cprog [.] sw_3_1 cprog [.] sw_3_1_2
2.20% cprog cprog [.] callme cprog [.] hw_1_1
1.77% cprog cprog [.] hw_1_1 cprog [.] callme
1.77% cprog cprog [.] success_3_1_1 cprog [.] sw_3_1
1.77% cprog cprog [.] sw_3_1 cprog [.] success_3_1_1
1.77% cprog cprog [.] success_3_1_2 cprog [.] sw_3_1
1.77% cprog cprog [.] sw_3_1 cprog [.] success_3_1_2
1.77% cprog cprog [.] sw_3_1 cprog [.] success_3_1_3
1.76% cprog cprog [.] hw_1_2 cprog [.] callme
1.76% cprog cprog [.] sw_4_1 cprog [.] callme
1.76% cprog cprog [.] sw_3_2 cprog [.] callme
1.76% cprog cprog [.] callme cprog [.] main
1.76% cprog cprog [.] callme cprog [.] sw_3_2
1.75% cprog cprog [.] hw_2_2 cprog [.] address2
1.75% cprog cprog [.] back2 cprog [.] callme
0.13% cprog [unknown] [.] 0xf7dd23e0 [unknown] [.] 0xf7dd23c0
0.07% cprog [unknown] [k] 00000000 cprog [k] callme
0.00% cprog libc-2.11.2.so [.] vfprintf libc-2.11.2.so [.] vfprintf
0.00% cprog libc-2.11.2.so [.] vfprintf libc-2.11.2.so [.] _IO_file_xsputn
0.00% cprog [unknown] [.] 00000000 libc-2.11.2.so [.] vfprintf
Test application program
========================
(1) Makefile:
--------------------------------------------
all: sample.o cprog of.cprog of.sample
sample.o: sample.s
as -o sample.o sample.s
cprog: cprog.c sample.o
gcc -o cprog cprog.c sample.o
of.sample: sample.o
objdump -d sample.o > of.sample
of.cprog: cprog
objdump -d cprog > of.cprog
clean:
rm sample.o cprog of.sample of.cprog
---------------------------------------------
(2) cprog.c
---------------------------------------------
#include <stdio.h>
#define LOOP_COUNT 10000
extern void callme(void);
int main(int argc, char *argv[])
{
int i;
for(i = 0; i < LOOP_COUNT; i++)
callme();
printf("end");
return 0;
}
---------------------------------------------
(3) sample.S
---------------------------------------------
# r25, r26, r27 will be used as first level, second level
# and third level stack for LR. Register r20, r21, r22, r23
# r24 will be used for general programming purpose.
.data
msg:
.string "BHRB filter tests\n"
len = . - msg
msg_1_1:
.string "Test: hw_1_1\n"
len_1_1 = 13
msg_1_2:
.string "Test: hw_1_2\n"
len_1_2 = 13
msg_2_1:
.string "Test: hw_2_1\n"
len_2_1 = 13
msg_2_2:
.string "Test: hw_2_2\n"
len_2_2 = 13
msg_3_1:
.string "Test: sw_3_1\n"
len_3_1 = 13
msg_3_1_1:
.string "Test: sw_3_1_1\n"
len_3_1_1 = 15
msg_3_1_2:
.string "Test: sw_3_1_2\n"
len_3_1_2 = 15
msg_3_1_3:
.string "Test: sw_3_1_3\n"
len_3_1_3 = 15
msg_3_2:
.string "Test: sw_3_2\n"
len_3_3 = 13
msg_4_1:
.string "Test: sw_4_1\n"
len_4_1 = 13
msg_4_2:
.string "Test: sw_4_2\n"
len_4_2 = 13
hw_3_1_1_passed:
.string "\thw_3_1_1_passed\n\n"
len_hw_3_1_1_passed = 18
hw_3_1_2_passed:
.string "\thw_3_1_2_passed\n\n"
len_hw_3_1_2_passed = 18
hw_3_1_3_passed:
.string "\thw_3_1_3_passed\n\n"
len_hw_3_1_3_passed = 18
hw_2_1_passed:
.string "\thw_2_1_passed\n\n"
len_hw_2_1_passed = 16
hw_2_2_passed:
.string "\thw_2_2_passed\n\n"
len_hw_2_2_passed = 16
hw_1_1_passed:
.string "\thw_1_1_passed\n\n"
len_hw_1_1_passed = 16
hw_1_2_passed:
.string "\thw_1_2_passed\n\n"
len_hw_1_2_passed = 16
hw_4_1_passed:
.string "\thw_4_1_passed\n\n"
len_hw_4_1_passed = 16
hw_4_2_passed:
.string "\thw_4_2_passed\n\n"
len_hw_4_2_passed = 16
msg_error:
.string "\tError\n"
len_error = 7
.text
.global callme
.global hw_1_1
.global hw_1_2
.global hw_2_1
.global hw_2_2
# HW filter test symbols
symbol1:
# Print "hw_1_1_passed"
li 0, 4
li 3, 1
lis 4, hw_1_1_passed@ha
addi 4, 4, hw_1_1_passed@l
li 5, len_hw_1_1_passed
sc
blr # PERF_SAMPLE_BRANCH_ANY_RET
hw_1_1:
# Save LR - second level
mflr 26
# Print "hw_1_1 called"
li 0, 4
li 3, 1
lis 4, msg_1_1@ha
addi 4, 4, msg_1_1@l
li 5, len_1_1
sc
bl symbol1 # PERF_SAMPLE_BRANCH_ANY_CALL
# Restore LR
mtlr 26
blr # PERF_SAMPLE_BRANCH_ANY_RET
symbol2:
# Print "Symbol2 taken"
li 0, 4
li 3, 1
lis 4, hw_1_2_passed@ha
addi 4, 4, hw_1_2_passed@l
li 5, len_hw_1_2_passed
sc
blr # PERF_SAMPLE_BRANCH_ANY_RET
hw_1_2:
# Save LR - second level
mflr 26
# Print "hw_1_2 called"
li 0, 4
li 3, 1
lis 4, msg_1_2@ha
addi 4, 4, msg_1_2@l
li 5, len_1_2
sc
li 4,20
cmpi 0,4,20
bcl 12, 4*cr0+2, symbol2 # PERF_SAMPLE_BRANCH_ANY_CALL | PERF_SAMPLE_BRANCH_COND
mtlr 26
blr # PERF_SAMPLE_BRANCH_ANY_RET
# HW filter test
address1:
# Print "hw_2_1_passed"
li 0, 4
li 3, 1
lis 4, hw_2_1_passed@ha
addi 4, 4, hw_2_1_passed@l
li 5, len_hw_2_1_passed
sc
b back1 # PERF_SAMPLE_BRANCH_ANY
hw_2_1:
# Print "hw_2_1 called"
li 0, 4
li 3, 1
lis 4, msg_2_1@ha
addi 4, 4, msg_2_1@l
li 5, len_2_1
sc
# Simple conditional branch (equal)
li 20, 12
cmpi 3, 20, 12
bc 12, 4*cr3+2, address1 # PERF_SAMPLE_BRANCH_COND
back1:
blr # PERF_SAMPLE_BRANCH_ANY_RET
address2:
# Print "hw_2_2_passed"
li 0, 4
li 3, 1
lis 4, hw_2_2_passed@ha
addi 4, 4, hw_2_2_passed@l
li 5, len_hw_2_2_passed
sc
b back2 # PERF_SAMPLE_BRANCH_ANY
hw_2_2:
# Print "hw_2_2 called"
li 0, 4
li 3, 1
lis 4, msg_2_2@ha
addi 4, 4, msg_2_2@l
li 5, len_2_2
sc
# Simple conditional branch (less than)
li 20, 12
cmpi 4, 20, 20
bc 12, 4*cr4+0, address2 # PERF_SAMPLE_BRANCH_COND
back2:
blr # PERF_SAMPLE_BRANCH_ANY_RET
# SW filter test symbols
sw_3_1_1:
# Print "Test: sw_3_1_1"
li 0, 4
li 3, 1
lis 4, msg_3_1_1@ha
addi 4, 4, msg_3_1_1@l
li 5, len_3_1_1
sc
li 22,0
# Test the condition and return
li 21, 10
cmpi 0, 21, 10
bclr 12, 2 # PERF_SAMPLE_BRANCH_ANY_RET | PERF_SAMPLE_BRANCH_COND
# Should not have come here
li 0, 4
li 3, 1
lis 4, msg_error@ha
addi 4, 4, msg_error@l
li 5, len_error
sc
# Mark the error
li 22, 1
# Safe fall back
blr # PERF_SAMPLE_BRANCH_ANY_RET
sw_3_1_2:
# Print "Test: sw_3_1_2"
li 0, 4
li 3, 1
lis 4, msg_3_1_2@ha
addi 4, 4, msg_3_1_2@l
li 5, len_3_1_2
sc
li 23, 0
# Test the condition and return
li 21, 10
cmpi 0, 21, 20
bclr 12, 0 # PERF_SAMPLE_BRANCH_ANY_RET | PERF_SAMPLE_BRANCH_COND
# Should not have come here
li 0, 4
li 3, 1
lis 4, msg_error@ha
addi 4, 4, msg_error@l
li 5, len_error
sc
# Mark the error
li 23, 1
# Safe fall back
blr # PERF_SAMPLE_BRANCH_ANY_RET
sw_3_1_3:
# Print "Test: sw_3_1_3"
li 0, 4
li 3, 1
lis 4, msg_3_1_3@ha
addi 4, 4, msg_3_1_3@l
li 5, len_3_1_3
sc
li 24, 0
# Test the condition and return
li 21, 10
cmpi 0, 21, 5
bclr 12, 1 # PERF_SAMPLE_BRANCH_ANY_RET | PERF_SAMPLE_BRANCH_COND
# Mark the error
li 24, 1
# Should not have come here
li 0, 4
li 3, 1
lis 4, msg_error@ha
addi 4, 4, msg_error@l
li 5, len_error
sc
# Safe fall back
blr # PERF_SAMPLE_BRANCH_ANY_RET
success_3_1_1:
li 0, 4
li 3, 1
lis 4, hw_3_1_1_passed@ha
addi 4, 4, hw_3_1_1_passed@l
li 5, len_hw_3_1_1_passed
sc
blr
success_3_1_2:
li 0, 4
li 3, 1
lis 4, hw_3_1_2_passed@ha
addi 4, 4, hw_3_1_2_passed@l
li 5, len_hw_3_1_2_passed
sc
blr
success_3_1_3:
li 0, 4
li 3, 1
lis 4, hw_3_1_3_passed@ha
addi 4, 4, hw_3_1_3_passed@l
li 5, len_hw_3_1_3_passed
sc
blr
sw_3_1:
# Save LR
mflr 26
# Print "Test: sw_3_1"
li 0, 4
li 3, 1
lis 4, msg_3_1@ha
addi 4, 4, msg_3_1@l
li 5, len_3_1
sc
# Equal comparison condition
bl sw_3_1_1 # PERF_SAMPLE_BRANCH_ANY_CALL
cmpi 0, 22, 0
bcl 12, 2, success_3_1_1 # PERF_SAMPLE_BRANCH_ANY_CALL | PERF_SAMPLE_BRANCH_COND
# LT comparison condition
bl sw_3_1_2 # PERF_SAMPLE_BRANCH_ANY_CALL
cmpi 0, 23, 0
bcl 12, 2, success_3_1_2 # PERF_SAMPLE_BRANCH_ANY_CALL | PERF_SAMPLE_BRANCH_COND
# GT comparison condition
bl sw_3_1_3 # PERF_SAMPLE_BRANCH_ANY_CALL
cmpi 0, 24, 0
bcl 12, 2, success_3_1_3 # PERF_SAMPLE_BRANCH_ANY_CALL | PERF_SAMPLE_BRANCH_COND
mtlr 26
blr # PERF_SAMPLE_BRANCH_ANY_RET
sw_3_2:
# Print "Test: sw_3_2"
li 0, 4
li 3, 1
lis 4, msg_3_2@ha
addi 4, 4, msg_3_2@l
li 5, len_3_1
sc
# FIXME: Anything more here ?
blr # PERF_SAMPLE_BRANCH_ANY_RET
# Indirect call tests
# CTR
ctr_addr:
# Print "bcctr taken"
li 0, 4
li 3, 1
lis 4, hw_4_1_passed@ha
addi 4, 4, hw_4_1_passed@l
li 5, len_hw_4_1_passed
sc
blr # PERF_SAMPLE_BRANCH_ANY_RET
sw_4_1:
# Save LR
mflr 26
# Print "sw_4_1 called"
li 0, 4
li 3, 1
lis 4, msg_4_1@ha
addi 4, 4, msg_4_1@l
li 5, len_4_1
sc
# Save address in CTR
lis 20, ctr_addr@ha
addi 20, 20, ctr_addr@l
mtctr 20
# Compare and jump to CTR
li 21, 10
cmpi 0, 21, 10
bcctrl 12, 4*cr0+2 # PERF_SAMPLE_BRANCH_IND_CALL
mtlr 26
blr # PERF_SAMPLE_BRANCH_ANY_RET
# LR
lr_addr:
# Print "bclrl taken"
li 0, 4
li 3, 1
lis 4, hw_4_2_passed@ha
addi 4, 4, hw_4_2_passed@l
li 5, len_hw_4_2_passed
sc
blr # PERF_SAMPLE_BRANCH_ANY_RET
sw_4_2:
# Save LR
mflr 26
# Print "Test: sw_4_2"
li 0, 4
li 3, 1
lis 4, msg_4_2@ha
addi 4, 4, msg_4_2@l
li 5, len_4_2
sc
# Save address in LR
lis 20, lr_addr@ha
addi 20, 20, lr_addr@l
mtlr 20
# Compare and jump to CTR
li 21, 10
cmpi 0, 21, 10
bclrl 12, 4*cr0+2 # PERF_SAMPLE_BRANCH_IND_CALL
# Restore LR
mtlr 26
blr # PERF_SAMPLE_BRANCH_ANY_RET
callme:
# Save LR
mflr 25
# Print "Branch filter Test"
li 0, 4
li 3, 1
lis 4, msg@ha
addi 4, 4, msg@l
li 5, len
sc
# PERF_SAMPLE_BRANCH_ANY_CALL
bl hw_1_1 # PERF_SAMPLE_BRANCH_ANY_CALL
bl hw_1_2 # PERF_SAMPLE_BRANCH_ANY_CALL
# PERF_SAMPLE_BRANCH_COND
bl hw_2_1 # PERF_SAMPLE_BRANCH_ANY_CALL
bl hw_2_2 # PERF_SAMPLE_BRANCH_ANY_CALL
# PERF_SAMPLE_BRANCH_ANY_RET
bl sw_3_1 # PERF_SAMPLE_BRANCH_ANY_CALL
bl sw_3_2 # PERF_SAMPLE_BRANCH_ANY_CALL
# PERF_SAMPLE_BRANCH_IND_CALL
bl sw_4_1 # PERF_SAMPLE_BRANCH_ANY_CALL
bl sw_4_2 # PERF_SAMPLE_BRANCH_ANY_CALL
# Restore LR
mtlr 25
blr # PERF_SAMPLE_BRANCH_ANY_RET
--------------------------------------------------------------------
Anshuman Khandual (10):
perf: Add PERF_SAMPLE_BRANCH_COND
powerpc, perf: Enable conditional branch filter for POWER8
perf, tool: Conditional branch filter 'cond' added to perf record
x86, perf: Add conditional branch filtering support
perf, documentation: Description for conditional branch filter
powerpc, perf: Change the name of HW PMU branch filter tracking
variable
powerpc, lib: Add new branch instruction analysis support functions
powerpc, perf: Enable SW filtering in branch stack sampling framework
power8, perf: Change BHRB branch filter configuration
powerpc, perf: Cleanup SW branch filter list look up
arch/powerpc/include/asm/code-patching.h | 30 ++++
arch/powerpc/include/asm/perf_event_server.h | 6 +-
arch/powerpc/lib/code-patching.c | 54 +++++-
arch/powerpc/perf/core-book3s.c | 260 +++++++++++++++++++++++++--
arch/powerpc/perf/power8-pmu.c | 75 ++++++--
arch/x86/kernel/cpu/perf_event_intel_lbr.c | 5 +
include/uapi/linux/perf_event.h | 3 +-
tools/perf/Documentation/perf-record.txt | 3 +-
tools/perf/builtin-record.c | 1 +
9 files changed, 404 insertions(+), 33 deletions(-)
--
1.7.11.7
^ permalink raw reply
* [PATCH V4 01/10] perf: Add PERF_SAMPLE_BRANCH_COND
From: Anshuman Khandual @ 2013-12-04 10:32 UTC (permalink / raw)
To: linuxppc-dev, linux-kernel
Cc: mikey, ak, eranian, michael, acme, sukadev, mingo
In-Reply-To: <1386153162-11225-1-git-send-email-khandual@linux.vnet.ibm.com>
POWER8 PMU based BHRB supports filtering for conditional branches.
This patch introduces new branch filter PERF_SAMPLE_BRANCH_COND which
will extend the existing perf ABI. Other architectures can provide
this functionality with either HW filtering support (if present) or
with SW filtering of instructions.
Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
Reviewed-by: Stephane Eranian <eranian@google.com>
---
include/uapi/linux/perf_event.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
index e1802d6..e2d8b8b 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -163,8 +163,9 @@ enum perf_branch_sample_type {
PERF_SAMPLE_BRANCH_ABORT_TX = 1U << 7, /* transaction aborts */
PERF_SAMPLE_BRANCH_IN_TX = 1U << 8, /* in transaction */
PERF_SAMPLE_BRANCH_NO_TX = 1U << 9, /* not in transaction */
+ PERF_SAMPLE_BRANCH_COND = 1U << 10, /* conditional branches */
- PERF_SAMPLE_BRANCH_MAX = 1U << 10, /* non-ABI */
+ PERF_SAMPLE_BRANCH_MAX = 1U << 11, /* non-ABI */
};
#define PERF_SAMPLE_BRANCH_PLM_ALL \
--
1.7.11.7
^ permalink raw reply related
* [PATCH V4 07/10] powerpc, lib: Add new branch instruction analysis support functions
From: Anshuman Khandual @ 2013-12-04 10:32 UTC (permalink / raw)
To: linuxppc-dev, linux-kernel
Cc: mikey, ak, eranian, michael, acme, sukadev, mingo
In-Reply-To: <1386153162-11225-1-git-send-email-khandual@linux.vnet.ibm.com>
Generic powerpc branch instruction analysis support added in the code
patching library which will help the subsequent patch on SW based
filtering of branch records in perf. This patch also converts and
exports some of the existing local static functions through the header
file to be used else where.
Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/code-patching.h | 30 ++++++++++++++++++
arch/powerpc/lib/code-patching.c | 54 ++++++++++++++++++++++++++++++--
2 files changed, 82 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/include/asm/code-patching.h b/arch/powerpc/include/asm/code-patching.h
index a6f8c7a..8bab417 100644
--- a/arch/powerpc/include/asm/code-patching.h
+++ b/arch/powerpc/include/asm/code-patching.h
@@ -22,6 +22,36 @@
#define BRANCH_SET_LINK 0x1
#define BRANCH_ABSOLUTE 0x2
+#define XL_FORM_LR 0x4C000020
+#define XL_FORM_CTR 0x4C000420
+#define XL_FORM_TAR 0x4C000460
+
+#define BO_ALWAYS 0x02800000
+#define BO_CTR 0x02000000
+#define BO_CRBI_OFF 0x00800000
+#define BO_CRBI_ON 0x01800000
+#define BO_CRBI_HINT 0x00400000
+
+/* Forms of branch instruction */
+int instr_is_branch_iform(unsigned int instr);
+int instr_is_branch_bform(unsigned int instr);
+int instr_is_branch_xlform(unsigned int instr);
+
+/* Classification of XL-form instruction */
+int is_xlform_lr(unsigned int instr);
+int is_xlform_ctr(unsigned int instr);
+int is_xlform_tar(unsigned int instr);
+
+/* Branch instruction is a call */
+int is_branch_link_set(unsigned int instr);
+
+/* BO field analysis (B-form or XL-form) */
+int is_bo_always(unsigned int instr);
+int is_bo_ctr(unsigned int instr);
+int is_bo_crbi_off(unsigned int instr);
+int is_bo_crbi_on(unsigned int instr);
+int is_bo_crbi_hint(unsigned int instr);
+
unsigned int create_branch(const unsigned int *addr,
unsigned long target, int flags);
unsigned int create_cond_branch(const unsigned int *addr,
diff --git a/arch/powerpc/lib/code-patching.c b/arch/powerpc/lib/code-patching.c
index 17e5b23..cb62bd8 100644
--- a/arch/powerpc/lib/code-patching.c
+++ b/arch/powerpc/lib/code-patching.c
@@ -77,16 +77,66 @@ static unsigned int branch_opcode(unsigned int instr)
return (instr >> 26) & 0x3F;
}
-static int instr_is_branch_iform(unsigned int instr)
+int instr_is_branch_iform(unsigned int instr)
{
return branch_opcode(instr) == 18;
}
-static int instr_is_branch_bform(unsigned int instr)
+int instr_is_branch_bform(unsigned int instr)
{
return branch_opcode(instr) == 16;
}
+int instr_is_branch_xlform(unsigned int instr)
+{
+ return branch_opcode(instr) == 19;
+}
+
+int is_xlform_lr(unsigned int instr)
+{
+ return (instr & XL_FORM_LR) == XL_FORM_LR;
+}
+
+int is_xlform_ctr(unsigned int instr)
+{
+ return (instr & XL_FORM_CTR) == XL_FORM_CTR;
+}
+
+int is_xlform_tar(unsigned int instr)
+{
+ return (instr & XL_FORM_TAR) == XL_FORM_TAR;
+}
+
+int is_branch_link_set(unsigned int instr)
+{
+ return (instr & BRANCH_SET_LINK) == BRANCH_SET_LINK;
+}
+
+int is_bo_always(unsigned int instr)
+{
+ return (instr & BO_ALWAYS) == BO_ALWAYS;
+}
+
+int is_bo_ctr(unsigned int instr)
+{
+ return (instr & BO_CTR) == BO_CTR;
+}
+
+int is_bo_crbi_off(unsigned int instr)
+{
+ return (instr & BO_CRBI_OFF) == BO_CRBI_OFF;
+}
+
+int is_bo_crbi_on(unsigned int instr)
+{
+ return (instr & BO_CRBI_ON) == BO_CRBI_ON;
+}
+
+int is_bo_crbi_hint(unsigned int instr)
+{
+ return (instr & BO_CRBI_HINT) == BO_CRBI_HINT;
+}
+
int instr_is_relative_branch(unsigned int instr)
{
if (instr & BRANCH_ABSOLUTE)
--
1.7.11.7
^ permalink raw reply related
* [PATCH V4 03/10] perf, tool: Conditional branch filter 'cond' added to perf record
From: Anshuman Khandual @ 2013-12-04 10:32 UTC (permalink / raw)
To: linuxppc-dev, linux-kernel
Cc: mikey, ak, eranian, michael, acme, sukadev, mingo
In-Reply-To: <1386153162-11225-1-git-send-email-khandual@linux.vnet.ibm.com>
Adding perf record support for new branch stack filter criteria
PERF_SAMPLE_BRANCH_COND.
Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
Reviewed-by: Stephane Eranian <eranian@google.com>
---
tools/perf/builtin-record.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 7c8020a..34040f7 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -583,6 +583,7 @@ static const struct branch_mode branch_modes[] = {
BRANCH_OPT("abort_tx", PERF_SAMPLE_BRANCH_ABORT_TX),
BRANCH_OPT("in_tx", PERF_SAMPLE_BRANCH_IN_TX),
BRANCH_OPT("no_tx", PERF_SAMPLE_BRANCH_NO_TX),
+ BRANCH_OPT("cond", PERF_SAMPLE_BRANCH_COND),
BRANCH_END
};
--
1.7.11.7
^ permalink raw reply related
* [PATCH V4 10/10] powerpc, perf: Cleanup SW branch filter list look up
From: Anshuman Khandual @ 2013-12-04 10:32 UTC (permalink / raw)
To: linuxppc-dev, linux-kernel
Cc: mikey, ak, eranian, michael, acme, sukadev, mingo
In-Reply-To: <1386153162-11225-1-git-send-email-khandual@linux.vnet.ibm.com>
This patch adds enumeration for all available SW branch filters
in powerpc book3s code and also streamlines the look for the
SW branch filter entries while trying to figure out which all
branch filters can be supported in SW.
Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
---
arch/powerpc/perf/core-book3s.c | 38 +++++++++++++-------------------------
1 file changed, 13 insertions(+), 25 deletions(-)
diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c
index 54d39a5..42c6428 100644
--- a/arch/powerpc/perf/core-book3s.c
+++ b/arch/powerpc/perf/core-book3s.c
@@ -566,6 +566,12 @@ static int match_filters(u64 branch_sample_type, u64 filter_mask)
return true;
}
+/* SW implemented branch filters */
+static unsigned int power_sw_filter[] = { PERF_SAMPLE_BRANCH_ANY_CALL,
+ PERF_SAMPLE_BRANCH_COND,
+ PERF_SAMPLE_BRANCH_ANY_RETURN,
+ PERF_SAMPLE_BRANCH_IND_CALL };
+
/*
* Required SW based branch filters
*
@@ -578,6 +584,7 @@ static u64 branch_filter_map(u64 branch_sample_type, u64 pmu_bhrb_filter,
u64 *filter_mask)
{
u64 branch_sw_filter = 0;
+ unsigned int i;
/* No branch filter requested */
if (branch_sample_type & PERF_SAMPLE_BRANCH_ANY) {
@@ -593,34 +600,15 @@ static u64 branch_filter_map(u64 branch_sample_type, u64 pmu_bhrb_filter,
* SW implemented filters. But right now, there is now way to
* initimate the user about this decision.
*/
- if (branch_sample_type & PERF_SAMPLE_BRANCH_ANY_CALL) {
- if (!(pmu_bhrb_filter & PERF_SAMPLE_BRANCH_ANY_CALL)) {
- branch_sw_filter |= PERF_SAMPLE_BRANCH_ANY_CALL;
- *filter_mask |= PERF_SAMPLE_BRANCH_ANY_CALL;
- }
- }
-
- if (branch_sample_type & PERF_SAMPLE_BRANCH_COND) {
- if (!(pmu_bhrb_filter & PERF_SAMPLE_BRANCH_COND)) {
- branch_sw_filter |= PERF_SAMPLE_BRANCH_COND;
- *filter_mask |= PERF_SAMPLE_BRANCH_COND;
- }
- }
- if (branch_sample_type & PERF_SAMPLE_BRANCH_ANY_RETURN) {
- if (!(pmu_bhrb_filter & PERF_SAMPLE_BRANCH_ANY_RETURN)) {
- branch_sw_filter |= PERF_SAMPLE_BRANCH_ANY_RETURN;
- *filter_mask |= PERF_SAMPLE_BRANCH_ANY_RETURN;
- }
- }
-
- if (branch_sample_type & PERF_SAMPLE_BRANCH_IND_CALL) {
- if (!(pmu_bhrb_filter & PERF_SAMPLE_BRANCH_IND_CALL)) {
- branch_sw_filter |= PERF_SAMPLE_BRANCH_IND_CALL;
- *filter_mask |= PERF_SAMPLE_BRANCH_IND_CALL;
+ for (i = 0; i < ARRAY_SIZE(power_sw_filter); i++) {
+ if (branch_sample_type & power_sw_filter[i]) {
+ if (!(pmu_bhrb_filter & power_sw_filter[i])) {
+ branch_sw_filter |= power_sw_filter[i];
+ *filter_mask |= power_sw_filter[i];
+ }
}
}
-
return branch_sw_filter;
}
--
1.7.11.7
^ permalink raw reply related
* [PATCH V4 04/10] x86, perf: Add conditional branch filtering support
From: Anshuman Khandual @ 2013-12-04 10:32 UTC (permalink / raw)
To: linuxppc-dev, linux-kernel
Cc: mikey, ak, eranian, michael, acme, sukadev, mingo
In-Reply-To: <1386153162-11225-1-git-send-email-khandual@linux.vnet.ibm.com>
This patch adds conditional branch filtering support,
enabling it for PERF_SAMPLE_BRANCH_COND in perf branch
stack sampling framework by utilizing an available
software filter X86_BR_JCC.
Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
Reviewed-by: Stephane Eranian <eranian@google.com>
---
arch/x86/kernel/cpu/perf_event_intel_lbr.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/arch/x86/kernel/cpu/perf_event_intel_lbr.c b/arch/x86/kernel/cpu/perf_event_intel_lbr.c
index d82d155..9dd2459 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_lbr.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_lbr.c
@@ -384,6 +384,9 @@ static void intel_pmu_setup_sw_lbr_filter(struct perf_event *event)
if (br_type & PERF_SAMPLE_BRANCH_NO_TX)
mask |= X86_BR_NO_TX;
+ if (br_type & PERF_SAMPLE_BRANCH_COND)
+ mask |= X86_BR_JCC;
+
/*
* stash actual user request into reg, it may
* be used by fixup code for some CPU
@@ -678,6 +681,7 @@ static const int nhm_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX] = {
* NHM/WSM erratum: must include IND_JMP to capture IND_CALL
*/
[PERF_SAMPLE_BRANCH_IND_CALL] = LBR_IND_CALL | LBR_IND_JMP,
+ [PERF_SAMPLE_BRANCH_COND] = LBR_JCC,
};
static const int snb_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX] = {
@@ -689,6 +693,7 @@ static const int snb_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX] = {
[PERF_SAMPLE_BRANCH_ANY_CALL] = LBR_REL_CALL | LBR_IND_CALL
| LBR_FAR,
[PERF_SAMPLE_BRANCH_IND_CALL] = LBR_IND_CALL,
+ [PERF_SAMPLE_BRANCH_COND] = LBR_JCC,
};
/* core */
--
1.7.11.7
^ permalink raw reply related
* [PATCH V4 09/10] power8, perf: Change BHRB branch filter configuration
From: Anshuman Khandual @ 2013-12-04 10:32 UTC (permalink / raw)
To: linuxppc-dev, linux-kernel
Cc: mikey, ak, eranian, michael, acme, sukadev, mingo
In-Reply-To: <1386153162-11225-1-git-send-email-khandual@linux.vnet.ibm.com>
Powerpc kernel now supports SW based branch filters for book3s systems with some
specifc requirements while dealing with HW supported branch filters in order to
achieve overall OR semantics prevailing in perf branch stack sampling framework.
This patch adapts the BHRB branch filter configuration to meet those protocols.
POWER8 PMU does support 3 branch filters (out of which two are getting used in
perf branch stack) which are mutually exclussive and cannot be ORed with each
other. This implies that PMU can only handle one HW based branch filter request
at any point of time. For all other combinations PMU will pass it on to the SW.
Also the combination of PERF_SAMPLE_BRANCH_ANY_CALL and PERF_SAMPLE_BRANCH_COND
can now be handled in SW, hence we dont error them out anymore.
Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
---
arch/powerpc/perf/power8-pmu.c | 73 +++++++++++++++++++++++++++++++-----------
1 file changed, 54 insertions(+), 19 deletions(-)
diff --git a/arch/powerpc/perf/power8-pmu.c b/arch/powerpc/perf/power8-pmu.c
index 03c5b8d..6021349 100644
--- a/arch/powerpc/perf/power8-pmu.c
+++ b/arch/powerpc/perf/power8-pmu.c
@@ -561,7 +561,56 @@ static int power8_generic_events[] = {
static u64 power8_bhrb_filter_map(u64 branch_sample_type, u64 *filter_mask)
{
- u64 pmu_bhrb_filter = 0;
+ u64 x, tmp, pmu_bhrb_filter = 0;
+ *filter_mask = 0;
+
+ /* No branch filter requested */
+ if (branch_sample_type & PERF_SAMPLE_BRANCH_ANY) {
+ *filter_mask = PERF_SAMPLE_BRANCH_ANY;
+ return pmu_bhrb_filter;
+ }
+
+ /*
+ * P8 does not support oring of PMU HW branch filters. Hence
+ * if multiple branch filters are requested which includes filters
+ * supported in PMU, still go ahead and clear the PMU based HW branch
+ * filter component as in this case all the filters will be processed
+ * in SW.
+ */
+ tmp = branch_sample_type;
+
+ /* Remove privilege filters before comparison */
+ tmp &= ~PERF_SAMPLE_BRANCH_USER;
+ tmp &= ~PERF_SAMPLE_BRANCH_KERNEL;
+ tmp &= ~PERF_SAMPLE_BRANCH_HV;
+
+ for_each_branch_sample_type(x) {
+ /* Ignore privilege requests */
+ if ((x == PERF_SAMPLE_BRANCH_USER) || (x == PERF_SAMPLE_BRANCH_KERNEL) || (x == PERF_SAMPLE_BRANCH_HV))
+ continue;
+
+ if (!(tmp & x))
+ continue;
+
+ /* Supported HW PMU filters */
+ if (tmp & PERF_SAMPLE_BRANCH_ANY_CALL) {
+ tmp &= ~PERF_SAMPLE_BRANCH_ANY_CALL;
+ if (tmp) {
+ pmu_bhrb_filter = 0;
+ *filter_mask = 0;
+ return pmu_bhrb_filter;
+ }
+ }
+
+ if (tmp & PERF_SAMPLE_BRANCH_COND) {
+ tmp &= ~PERF_SAMPLE_BRANCH_COND;
+ if (tmp) {
+ pmu_bhrb_filter = 0;
+ *filter_mask = 0;
+ return pmu_bhrb_filter;
+ }
+ }
+ }
/* BHRB and regular PMU events share the same privilege state
* filter configuration. BHRB is always recorded along with a
@@ -570,34 +619,20 @@ static u64 power8_bhrb_filter_map(u64 branch_sample_type, u64 *filter_mask)
* PMU event, we ignore any separate BHRB specific request.
*/
- /* No branch filter requested */
- if (branch_sample_type & PERF_SAMPLE_BRANCH_ANY)
- return pmu_bhrb_filter;
-
- /* Invalid branch filter options - HW does not support */
- if (branch_sample_type & PERF_SAMPLE_BRANCH_ANY_RETURN)
- return -1;
-
- if (branch_sample_type & PERF_SAMPLE_BRANCH_IND_CALL)
- return -1;
-
+ /* Supported individual branch filters */
if (branch_sample_type & PERF_SAMPLE_BRANCH_ANY_CALL) {
pmu_bhrb_filter |= POWER8_MMCRA_IFM1;
+ *filter_mask |= PERF_SAMPLE_BRANCH_ANY_CALL;
return pmu_bhrb_filter;
}
if (branch_sample_type & PERF_SAMPLE_BRANCH_COND) {
pmu_bhrb_filter |= POWER8_MMCRA_IFM3;
+ *filter_mask |= PERF_SAMPLE_BRANCH_COND;
return pmu_bhrb_filter;
}
- /* PMU does not support ANY combination of HW BHRB filters */
- if ((branch_sample_type & PERF_SAMPLE_BRANCH_ANY_CALL) &&
- (branch_sample_type & PERF_SAMPLE_BRANCH_COND))
- return -1;
-
- /* Every thing else is unsupported */
- return -1;
+ return pmu_bhrb_filter;
}
static void power8_config_bhrb(u64 pmu_bhrb_filter)
--
1.7.11.7
^ permalink raw reply related
* [PATCH V4 06/10] powerpc, perf: Change the name of HW PMU branch filter tracking variable
From: Anshuman Khandual @ 2013-12-04 10:32 UTC (permalink / raw)
To: linuxppc-dev, linux-kernel
Cc: mikey, ak, eranian, michael, acme, sukadev, mingo
In-Reply-To: <1386153162-11225-1-git-send-email-khandual@linux.vnet.ibm.com>
This patch simply changes the name of the variable from "bhrb_filter" to
"bhrb_hw_filter" in order to add one more variable which will track SW
filters in generic powerpc book3s code which will be implemented in the
subsequent patch.
Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
---
arch/powerpc/perf/core-book3s.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c
index 29b89e8..2de7d48 100644
--- a/arch/powerpc/perf/core-book3s.c
+++ b/arch/powerpc/perf/core-book3s.c
@@ -47,7 +47,7 @@ struct cpu_hw_events {
int n_txn_start;
/* BHRB bits */
- u64 bhrb_filter; /* BHRB HW branch filter */
+ u64 bhrb_hw_filter; /* BHRB HW branch filter */
int bhrb_users;
void *bhrb_context;
struct perf_branch_stack bhrb_stack;
@@ -1159,7 +1159,7 @@ static void power_pmu_enable(struct pmu *pmu)
out:
if (cpuhw->bhrb_users)
- ppmu->config_bhrb(cpuhw->bhrb_filter);
+ ppmu->config_bhrb(cpuhw->bhrb_hw_filter);
local_irq_restore(flags);
}
@@ -1254,7 +1254,7 @@ nocheck:
out:
if (has_branch_stack(event)) {
power_pmu_bhrb_enable(event);
- cpuhw->bhrb_filter = ppmu->bhrb_filter_map(
+ cpuhw->bhrb_hw_filter = ppmu->bhrb_filter_map(
event->attr.branch_sample_type);
}
@@ -1637,10 +1637,10 @@ static int power_pmu_event_init(struct perf_event *event)
err = power_check_constraints(cpuhw, events, cflags, n + 1);
if (has_branch_stack(event)) {
- cpuhw->bhrb_filter = ppmu->bhrb_filter_map(
+ cpuhw->bhrb_hw_filter = ppmu->bhrb_filter_map(
event->attr.branch_sample_type);
- if(cpuhw->bhrb_filter == -1)
+ if(cpuhw->bhrb_hw_filter == -1)
return -EOPNOTSUPP;
}
--
1.7.11.7
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox