235c7b9feb
Pull main powerpc updates from Ben Herrenschmidt: "This time around, the powerpc merges are going to be a little bit more complicated than usual. This is the main pull request with most of the work for this merge window. I will describe it a bit more further down. There is some additional cpuidle driver work, however I haven't included it in this tree as it depends on some work in tip/timer-core which Thomas accidentally forgot to put in a topic branch. Since I didn't want to carry all of that tip timer stuff in powerpc -next, I setup a separate branch on top of Thomas tree with just that cpuidle driver in it, and Stephen has been carrying that in next separately for a while now. I'll send a separate pull request for it. Additionally, two new pieces in this tree add users for a sysfs API that Tejun and Greg have been deprecating in drivers-core-next. Thankfully Greg reverted the patch that removes the old API so this merge can happen cleanly, but once merged, I will send a patch adjusting our new code to the new API so that Greg can send you the removal patch. Now as for the content of this branch, we have a lot of perf work for power8 new counters including support for our new "nest" counters (also called 24x7) under pHyp (not natively yet). We have new functionality when running under the OPAL firmware (non-virtualized or KVM host), such as access to the firmware error logs and service processor dumps, system parameters and sensors, along with a hwmon driver for the latter. There's also a bunch of bug fixes accross the board, some LE fixes, and a nice set of selftests for validating our various types of copy loops. On the Freescale side, we see mostly new chip/board revisions, some clock updates, better support for machine checks and debug exceptions, etc..." * 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc: (70 commits) powerpc/book3s: Fix CFAR clobbering issue in machine check handler. powerpc/compat: 32-bit little endian machine name is ppcle, not ppc powerpc/le: Big endian arguments for ppc_rtas() powerpc: Use default set of netfilter modules (CONFIG_NETFILTER_ADVANCED=n) powerpc/defconfigs: Enable THP in pseries defconfig powerpc/mm: Make sure a local_irq_disable prevent a parallel THP split powerpc: Rate-limit users spamming kernel log buffer powerpc/perf: Fix handling of L3 events with bank == 1 powerpc/perf/hv_{gpci, 24x7}: Add documentation of device attributes powerpc/perf: Add kconfig option for hypervisor provided counters powerpc/perf: Add support for the hv 24x7 interface powerpc/perf: Add support for the hv gpci (get performance counter info) interface powerpc/perf: Add macros for defining event fields & formats powerpc/perf: Add a shared interface to get gpci version and capabilities powerpc/perf: Add 24x7 interface headers powerpc/perf: Add hv_gpci interface header powerpc: Add hvcalls for 24x7 and gpci (Get Performance Counter Info) sysfs: create bin_attributes under the requested group powerpc/perf: Enable BHRB access for EBB events powerpc/perf: Add BHRB constraint and IFM MMCRA handling for EBB ...
244 lines
5.3 KiB
C
244 lines
5.3 KiB
C
/*
|
|
* PowerNV setup code.
|
|
*
|
|
* Copyright 2011 IBM Corp.
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#undef DEBUG
|
|
|
|
#include <linux/cpu.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/tty.h>
|
|
#include <linux/reboot.h>
|
|
#include <linux/init.h>
|
|
#include <linux/console.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/irq.h>
|
|
#include <linux/seq_file.h>
|
|
#include <linux/of.h>
|
|
#include <linux/of_fdt.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/bug.h>
|
|
#include <linux/pci.h>
|
|
|
|
#include <asm/machdep.h>
|
|
#include <asm/firmware.h>
|
|
#include <asm/xics.h>
|
|
#include <asm/rtas.h>
|
|
#include <asm/opal.h>
|
|
#include <asm/kexec.h>
|
|
|
|
#include "powernv.h"
|
|
|
|
static void __init pnv_setup_arch(void)
|
|
{
|
|
/* Initialize SMP */
|
|
pnv_smp_init();
|
|
|
|
/* Setup PCI */
|
|
pnv_pci_init();
|
|
|
|
/* Setup RTC and NVRAM callbacks */
|
|
if (firmware_has_feature(FW_FEATURE_OPAL))
|
|
opal_nvram_init();
|
|
|
|
/* Enable NAP mode */
|
|
powersave_nap = 1;
|
|
|
|
/* XXX PMCS */
|
|
}
|
|
|
|
static void __init pnv_init_early(void)
|
|
{
|
|
/*
|
|
* Initialize the LPC bus now so that legacy serial
|
|
* ports can be found on it
|
|
*/
|
|
opal_lpc_init();
|
|
|
|
#ifdef CONFIG_HVC_OPAL
|
|
if (firmware_has_feature(FW_FEATURE_OPAL))
|
|
hvc_opal_init_early();
|
|
else
|
|
#endif
|
|
add_preferred_console("hvc", 0, NULL);
|
|
}
|
|
|
|
static void __init pnv_init_IRQ(void)
|
|
{
|
|
xics_init();
|
|
|
|
WARN_ON(!ppc_md.get_irq);
|
|
}
|
|
|
|
static void pnv_show_cpuinfo(struct seq_file *m)
|
|
{
|
|
struct device_node *root;
|
|
const char *model = "";
|
|
|
|
root = of_find_node_by_path("/");
|
|
if (root)
|
|
model = of_get_property(root, "model", NULL);
|
|
seq_printf(m, "machine\t\t: PowerNV %s\n", model);
|
|
if (firmware_has_feature(FW_FEATURE_OPALv3))
|
|
seq_printf(m, "firmware\t: OPAL v3\n");
|
|
else if (firmware_has_feature(FW_FEATURE_OPALv2))
|
|
seq_printf(m, "firmware\t: OPAL v2\n");
|
|
else if (firmware_has_feature(FW_FEATURE_OPAL))
|
|
seq_printf(m, "firmware\t: OPAL v1\n");
|
|
else
|
|
seq_printf(m, "firmware\t: BML\n");
|
|
of_node_put(root);
|
|
}
|
|
|
|
static void __noreturn pnv_restart(char *cmd)
|
|
{
|
|
long rc = OPAL_BUSY;
|
|
|
|
opal_notifier_disable();
|
|
|
|
while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) {
|
|
rc = opal_cec_reboot();
|
|
if (rc == OPAL_BUSY_EVENT)
|
|
opal_poll_events(NULL);
|
|
else
|
|
mdelay(10);
|
|
}
|
|
for (;;)
|
|
opal_poll_events(NULL);
|
|
}
|
|
|
|
static void __noreturn pnv_power_off(void)
|
|
{
|
|
long rc = OPAL_BUSY;
|
|
|
|
opal_notifier_disable();
|
|
|
|
while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) {
|
|
rc = opal_cec_power_down(0);
|
|
if (rc == OPAL_BUSY_EVENT)
|
|
opal_poll_events(NULL);
|
|
else
|
|
mdelay(10);
|
|
}
|
|
for (;;)
|
|
opal_poll_events(NULL);
|
|
}
|
|
|
|
static void __noreturn pnv_halt(void)
|
|
{
|
|
pnv_power_off();
|
|
}
|
|
|
|
static void pnv_progress(char *s, unsigned short hex)
|
|
{
|
|
}
|
|
|
|
static int pnv_dma_set_mask(struct device *dev, u64 dma_mask)
|
|
{
|
|
if (dev_is_pci(dev))
|
|
return pnv_pci_dma_set_mask(to_pci_dev(dev), dma_mask);
|
|
return __dma_set_mask(dev, dma_mask);
|
|
}
|
|
|
|
static void pnv_shutdown(void)
|
|
{
|
|
/* Let the PCI code clear up IODA tables */
|
|
pnv_pci_shutdown();
|
|
|
|
/*
|
|
* Stop OPAL activity: Unregister all OPAL interrupts so they
|
|
* don't fire up while we kexec and make sure all potentially
|
|
* DMA'ing ops are complete (such as dump retrieval).
|
|
*/
|
|
opal_shutdown();
|
|
}
|
|
|
|
#ifdef CONFIG_KEXEC
|
|
static void pnv_kexec_cpu_down(int crash_shutdown, int secondary)
|
|
{
|
|
xics_kexec_teardown_cpu(secondary);
|
|
|
|
/* Return secondary CPUs to firmware on OPAL v3 */
|
|
if (firmware_has_feature(FW_FEATURE_OPALv3) && secondary) {
|
|
mb();
|
|
get_paca()->kexec_state = KEXEC_STATE_REAL_MODE;
|
|
mb();
|
|
|
|
/* Return the CPU to OPAL */
|
|
opal_return_cpu();
|
|
}
|
|
}
|
|
#endif /* CONFIG_KEXEC */
|
|
|
|
static void __init pnv_setup_machdep_opal(void)
|
|
{
|
|
ppc_md.get_boot_time = opal_get_boot_time;
|
|
ppc_md.get_rtc_time = opal_get_rtc_time;
|
|
ppc_md.set_rtc_time = opal_set_rtc_time;
|
|
ppc_md.restart = pnv_restart;
|
|
ppc_md.power_off = pnv_power_off;
|
|
ppc_md.halt = pnv_halt;
|
|
ppc_md.machine_check_exception = opal_machine_check;
|
|
ppc_md.mce_check_early_recovery = opal_mce_check_early_recovery;
|
|
}
|
|
|
|
#ifdef CONFIG_PPC_POWERNV_RTAS
|
|
static void __init pnv_setup_machdep_rtas(void)
|
|
{
|
|
if (rtas_token("get-time-of-day") != RTAS_UNKNOWN_SERVICE) {
|
|
ppc_md.get_boot_time = rtas_get_boot_time;
|
|
ppc_md.get_rtc_time = rtas_get_rtc_time;
|
|
ppc_md.set_rtc_time = rtas_set_rtc_time;
|
|
}
|
|
ppc_md.restart = rtas_restart;
|
|
ppc_md.power_off = rtas_power_off;
|
|
ppc_md.halt = rtas_halt;
|
|
}
|
|
#endif /* CONFIG_PPC_POWERNV_RTAS */
|
|
|
|
static int __init pnv_probe(void)
|
|
{
|
|
unsigned long root = of_get_flat_dt_root();
|
|
|
|
if (!of_flat_dt_is_compatible(root, "ibm,powernv"))
|
|
return 0;
|
|
|
|
hpte_init_native();
|
|
|
|
if (firmware_has_feature(FW_FEATURE_OPAL))
|
|
pnv_setup_machdep_opal();
|
|
#ifdef CONFIG_PPC_POWERNV_RTAS
|
|
else if (rtas.base)
|
|
pnv_setup_machdep_rtas();
|
|
#endif /* CONFIG_PPC_POWERNV_RTAS */
|
|
|
|
pr_debug("PowerNV detected !\n");
|
|
|
|
return 1;
|
|
}
|
|
|
|
define_machine(powernv) {
|
|
.name = "PowerNV",
|
|
.probe = pnv_probe,
|
|
.init_early = pnv_init_early,
|
|
.setup_arch = pnv_setup_arch,
|
|
.init_IRQ = pnv_init_IRQ,
|
|
.show_cpuinfo = pnv_show_cpuinfo,
|
|
.progress = pnv_progress,
|
|
.machine_shutdown = pnv_shutdown,
|
|
.power_save = power7_idle,
|
|
.calibrate_decr = generic_calibrate_decr,
|
|
.dma_set_mask = pnv_dma_set_mask,
|
|
#ifdef CONFIG_KEXEC
|
|
.kexec_cpu_down = pnv_kexec_cpu_down,
|
|
#endif
|
|
};
|