summaryrefslogtreecommitdiff
path: root/arch/powerpc/platforms/powernv
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/platforms/powernv')
-rw-r--r--arch/powerpc/platforms/powernv/copy-paste.h6
-rw-r--r--arch/powerpc/platforms/powernv/idle.c4
-rw-r--r--arch/powerpc/platforms/powernv/memtrace.c2
-rw-r--r--arch/powerpc/platforms/powernv/npu-dma.c5
-rw-r--r--arch/powerpc/platforms/powernv/ocxl.c4
-rw-r--r--arch/powerpc/platforms/powernv/opal-hmi.c2
-rw-r--r--arch/powerpc/platforms/powernv/opal-imc.c22
-rw-r--r--arch/powerpc/platforms/powernv/opal-irqchip.c89
-rw-r--r--arch/powerpc/platforms/powernv/opal-nvram.c14
-rw-r--r--arch/powerpc/platforms/powernv/opal-rtc.c5
-rw-r--r--arch/powerpc/platforms/powernv/opal-sensor.c53
-rw-r--r--arch/powerpc/platforms/powernv/opal-sysparam.c8
-rw-r--r--arch/powerpc/platforms/powernv/opal-wrappers.S2
-rw-r--r--arch/powerpc/platforms/powernv/opal.c23
-rw-r--r--arch/powerpc/platforms/powernv/pci-ioda.c46
-rw-r--r--arch/powerpc/platforms/powernv/powernv.h3
-rw-r--r--arch/powerpc/platforms/powernv/setup.c12
-rw-r--r--arch/powerpc/platforms/powernv/smp.c17
18 files changed, 212 insertions, 105 deletions
diff --git a/arch/powerpc/platforms/powernv/copy-paste.h b/arch/powerpc/platforms/powernv/copy-paste.h
index c9a503623431..cb36f9fbcef3 100644
--- a/arch/powerpc/platforms/powernv/copy-paste.h
+++ b/arch/powerpc/platforms/powernv/copy-paste.h
@@ -7,9 +7,8 @@
* 2 of the License, or (at your option) any later version.
*/
#include <asm/ppc-opcode.h>
+#include <asm/reg.h>
-#define CR0_SHIFT 28
-#define CR0_MASK 0xF
/*
* Copy/paste instructions:
*
@@ -42,5 +41,6 @@ static inline int vas_paste(void *paste_address, int offset)
: "b" (offset), "b" (paste_address)
: "memory", "cr0");
- return (cr >> CR0_SHIFT) & CR0_MASK;
+ /* We mask with 0xE to ignore SO */
+ return (cr >> CR0_SHIFT) & 0xE;
}
diff --git a/arch/powerpc/platforms/powernv/idle.c b/arch/powerpc/platforms/powernv/idle.c
index 1f12ab1e6030..1c5d0675b43c 100644
--- a/arch/powerpc/platforms/powernv/idle.c
+++ b/arch/powerpc/platforms/powernv/idle.c
@@ -79,7 +79,7 @@ static int pnv_save_sprs_for_deep_states(void)
uint64_t msr_val = MSR_IDLE;
uint64_t psscr_val = pnv_deepest_stop_psscr_val;
- for_each_possible_cpu(cpu) {
+ for_each_present_cpu(cpu) {
uint64_t pir = get_hard_smp_processor_id(cpu);
uint64_t hsprg0_val = (uint64_t)paca_ptrs[cpu];
@@ -814,7 +814,7 @@ static int __init pnv_init_idle_states(void)
int cpu;
pr_info("powernv: idle: Saving PACA pointers of all CPUs in their thread sibling PACA\n");
- for_each_possible_cpu(cpu) {
+ for_each_present_cpu(cpu) {
int base_cpu = cpu_first_thread_sibling(cpu);
int idx = cpu_thread_in_core(cpu);
int i;
diff --git a/arch/powerpc/platforms/powernv/memtrace.c b/arch/powerpc/platforms/powernv/memtrace.c
index fc222a0c2ac4..b99283df8584 100644
--- a/arch/powerpc/platforms/powernv/memtrace.c
+++ b/arch/powerpc/platforms/powernv/memtrace.c
@@ -131,7 +131,7 @@ static u64 memtrace_alloc_node(u32 nid, u64 size)
u64 start_pfn, end_pfn, nr_pages;
u64 base_pfn;
- if (!NODE_DATA(nid) || !node_spanned_pages(nid))
+ if (!node_spanned_pages(nid))
return 0;
start_pfn = node_start_pfn(nid);
diff --git a/arch/powerpc/platforms/powernv/npu-dma.c b/arch/powerpc/platforms/powernv/npu-dma.c
index 525e966dce34..8cdf91f5d3a4 100644
--- a/arch/powerpc/platforms/powernv/npu-dma.c
+++ b/arch/powerpc/platforms/powernv/npu-dma.c
@@ -459,10 +459,9 @@ static void mmio_launch_invalidate(struct mmio_atsd_reg *mmio_atsd_reg,
struct npu *npu = mmio_atsd_reg->npu;
int reg = mmio_atsd_reg->reg;
- __raw_writeq(cpu_to_be64(va),
- npu->mmio_atsd_regs[reg] + XTS_ATSD_AVA);
+ __raw_writeq_be(va, npu->mmio_atsd_regs[reg] + XTS_ATSD_AVA);
eieio();
- __raw_writeq(cpu_to_be64(launch), npu->mmio_atsd_regs[reg]);
+ __raw_writeq_be(launch, npu->mmio_atsd_regs[reg]);
}
static void mmio_invalidate_pid(struct mmio_atsd_reg mmio_atsd_reg[NV_MAX_NPUS],
diff --git a/arch/powerpc/platforms/powernv/ocxl.c b/arch/powerpc/platforms/powernv/ocxl.c
index fa9b53af3c7b..8c65aacda9c8 100644
--- a/arch/powerpc/platforms/powernv/ocxl.c
+++ b/arch/powerpc/platforms/powernv/ocxl.c
@@ -475,7 +475,7 @@ void pnv_ocxl_spa_release(void *platform_data)
}
EXPORT_SYMBOL_GPL(pnv_ocxl_spa_release);
-int pnv_ocxl_spa_remove_pe(void *platform_data, int pe_handle)
+int pnv_ocxl_spa_remove_pe_from_cache(void *platform_data, int pe_handle)
{
struct spa_data *data = (struct spa_data *) platform_data;
int rc;
@@ -483,7 +483,7 @@ int pnv_ocxl_spa_remove_pe(void *platform_data, int pe_handle)
rc = opal_npu_spa_clear_cache(data->phb_opal_id, data->bdfn, pe_handle);
return rc;
}
-EXPORT_SYMBOL_GPL(pnv_ocxl_spa_remove_pe);
+EXPORT_SYMBOL_GPL(pnv_ocxl_spa_remove_pe_from_cache);
int pnv_ocxl_alloc_xive_irq(u32 *irq, u64 *trigger_addr)
{
diff --git a/arch/powerpc/platforms/powernv/opal-hmi.c b/arch/powerpc/platforms/powernv/opal-hmi.c
index 4efc95b4c7d4..586ec71a4e17 100644
--- a/arch/powerpc/platforms/powernv/opal-hmi.c
+++ b/arch/powerpc/platforms/powernv/opal-hmi.c
@@ -177,7 +177,7 @@ static void print_hmi_event_info(struct OpalHMIEvent *hmi_evt)
"Processor recovery occurred for masked error",
"Timer facility experienced an error",
"TFMR SPR is corrupted",
- "UPS (Uniterrupted Power System) Overflow indication",
+ "UPS (Uninterrupted Power System) Overflow indication",
"An XSCOM operation failure",
"An XSCOM operation completed",
"SCOM has set a reserved FIR bit to cause recovery",
diff --git a/arch/powerpc/platforms/powernv/opal-imc.c b/arch/powerpc/platforms/powernv/opal-imc.c
index 2a14fda5ea26..58a07948c76e 100644
--- a/arch/powerpc/platforms/powernv/opal-imc.c
+++ b/arch/powerpc/platforms/powernv/opal-imc.c
@@ -115,8 +115,10 @@ static int imc_get_mem_addr_nest(struct device_node *node,
return -ENOMEM;
chipid_arr = kcalloc(nr_chips, sizeof(*chipid_arr), GFP_KERNEL);
- if (!chipid_arr)
+ if (!chipid_arr) {
+ kfree(base_addr_arr);
return -ENOMEM;
+ }
if (of_property_read_u32_array(node, "chip-id", chipid_arr, nr_chips))
goto error;
@@ -143,7 +145,6 @@ static int imc_get_mem_addr_nest(struct device_node *node,
return 0;
error:
- kfree(pmu_ptr->mem_info);
kfree(base_addr_arr);
kfree(chipid_arr);
return -1;
@@ -183,8 +184,14 @@ static int imc_pmu_create(struct device_node *parent, int pmu_index, int domain)
/* Function to register IMC pmu */
ret = init_imc_pmu(parent, pmu_ptr, pmu_index);
- if (ret)
+ if (ret) {
pr_err("IMC PMU %s Register failed\n", pmu_ptr->pmu.name);
+ kfree(pmu_ptr->pmu.name);
+ if (pmu_ptr->domain == IMC_DOMAIN_NEST)
+ kfree(pmu_ptr->mem_info);
+ kfree(pmu_ptr);
+ return ret;
+ }
return 0;
@@ -248,6 +255,7 @@ static int opal_imc_counters_probe(struct platform_device *pdev)
{
struct device_node *imc_dev = pdev->dev.of_node;
int pmu_count = 0, domain;
+ bool core_imc_reg = false, thread_imc_reg = false;
u32 type;
/*
@@ -285,6 +293,10 @@ static int opal_imc_counters_probe(struct platform_device *pdev)
if (!imc_pmu_create(imc_dev, pmu_count, domain)) {
if (domain == IMC_DOMAIN_NEST)
pmu_count++;
+ if (domain == IMC_DOMAIN_CORE)
+ core_imc_reg = true;
+ if (domain == IMC_DOMAIN_THREAD)
+ thread_imc_reg = true;
}
}
@@ -292,6 +304,10 @@ static int opal_imc_counters_probe(struct platform_device *pdev)
if (pmu_count == 0)
debugfs_remove_recursive(imc_debugfs_parent);
+ /* If core imc is not registered, unregister thread-imc */
+ if (!core_imc_reg && thread_imc_reg)
+ unregister_thread_imc();
+
return 0;
}
diff --git a/arch/powerpc/platforms/powernv/opal-irqchip.c b/arch/powerpc/platforms/powernv/opal-irqchip.c
index 9d1b8c0aaf93..605c7e5d52c2 100644
--- a/arch/powerpc/platforms/powernv/opal-irqchip.c
+++ b/arch/powerpc/platforms/powernv/opal-irqchip.c
@@ -22,7 +22,6 @@
#include <linux/kthread.h>
#include <linux/delay.h>
#include <linux/slab.h>
-#include <linux/irq_work.h>
#include <asm/machdep.h>
#include <asm/opal.h>
@@ -38,37 +37,47 @@ struct opal_event_irqchip {
unsigned long mask;
};
static struct opal_event_irqchip opal_event_irqchip;
-
+static u64 last_outstanding_events;
static unsigned int opal_irq_count;
static unsigned int *opal_irqs;
-static void opal_handle_irq_work(struct irq_work *work);
-static u64 last_outstanding_events;
-static struct irq_work opal_event_irq_work = {
- .func = opal_handle_irq_work,
-};
-
-void opal_handle_events(uint64_t events)
+void opal_handle_events(void)
{
- int virq, hwirq = 0;
- u64 mask = opal_event_irqchip.mask;
+ __be64 events = 0;
+ u64 e;
+
+ e = READ_ONCE(last_outstanding_events) & opal_event_irqchip.mask;
+again:
+ while (e) {
+ int virq, hwirq;
+
+ hwirq = fls64(e) - 1;
+ e &= ~BIT_ULL(hwirq);
+
+ local_irq_disable();
+ virq = irq_find_mapping(opal_event_irqchip.domain, hwirq);
+ if (virq) {
+ irq_enter();
+ generic_handle_irq(virq);
+ irq_exit();
+ }
+ local_irq_enable();
- if (!in_irq() && (events & mask)) {
- last_outstanding_events = events;
- irq_work_queue(&opal_event_irq_work);
- return;
+ cond_resched();
}
+ last_outstanding_events = 0;
+ if (opal_poll_events(&events) != OPAL_SUCCESS)
+ return;
+ e = be64_to_cpu(events) & opal_event_irqchip.mask;
+ if (e)
+ goto again;
+}
- while (events & mask) {
- hwirq = fls64(events) - 1;
- if (BIT_ULL(hwirq) & mask) {
- virq = irq_find_mapping(opal_event_irqchip.domain,
- hwirq);
- if (virq)
- generic_handle_irq(virq);
- }
- events &= ~BIT_ULL(hwirq);
- }
+bool opal_have_pending_events(void)
+{
+ if (last_outstanding_events & opal_event_irqchip.mask)
+ return true;
+ return false;
}
static void opal_event_mask(struct irq_data *d)
@@ -78,24 +87,9 @@ static void opal_event_mask(struct irq_data *d)
static void opal_event_unmask(struct irq_data *d)
{
- __be64 events;
-
set_bit(d->hwirq, &opal_event_irqchip.mask);
-
- opal_poll_events(&events);
- last_outstanding_events = be64_to_cpu(events);
-
- /*
- * We can't just handle the events now with opal_handle_events().
- * If we did we would deadlock when opal_event_unmask() is called from
- * handle_level_irq() with the irq descriptor lock held, because
- * calling opal_handle_events() would call generic_handle_irq() and
- * then handle_level_irq() which would try to take the descriptor lock
- * again. Instead queue the events for later.
- */
- if (last_outstanding_events & opal_event_irqchip.mask)
- /* Need to retrigger the interrupt */
- irq_work_queue(&opal_event_irq_work);
+ if (opal_have_pending_events())
+ opal_wake_poller();
}
static int opal_event_set_type(struct irq_data *d, unsigned int flow_type)
@@ -136,16 +130,13 @@ static irqreturn_t opal_interrupt(int irq, void *data)
__be64 events;
opal_handle_interrupt(virq_to_hw(irq), &events);
- opal_handle_events(be64_to_cpu(events));
+ last_outstanding_events = be64_to_cpu(events);
+ if (opal_have_pending_events())
+ opal_wake_poller();
return IRQ_HANDLED;
}
-static void opal_handle_irq_work(struct irq_work *work)
-{
- opal_handle_events(last_outstanding_events);
-}
-
static int opal_event_match(struct irq_domain *h, struct device_node *node,
enum irq_domain_bus_token bus_token)
{
@@ -177,7 +168,7 @@ void opal_event_shutdown(void)
if (!opal_irqs[i])
continue;
- if (in_interrupt())
+ if (in_interrupt() || irqs_disabled())
disable_irq_nosync(opal_irqs[i]);
else
free_irq(opal_irqs[i], NULL);
diff --git a/arch/powerpc/platforms/powernv/opal-nvram.c b/arch/powerpc/platforms/powernv/opal-nvram.c
index 1bceb95f422d..5584247f5029 100644
--- a/arch/powerpc/platforms/powernv/opal-nvram.c
+++ b/arch/powerpc/platforms/powernv/opal-nvram.c
@@ -44,6 +44,10 @@ static ssize_t opal_nvram_read(char *buf, size_t count, loff_t *index)
return count;
}
+/*
+ * This can be called in the panic path with interrupts off, so use
+ * mdelay in that case.
+ */
static ssize_t opal_nvram_write(char *buf, size_t count, loff_t *index)
{
s64 rc = OPAL_BUSY;
@@ -58,10 +62,16 @@ static ssize_t opal_nvram_write(char *buf, size_t count, loff_t *index)
while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) {
rc = opal_write_nvram(__pa(buf), count, off);
if (rc == OPAL_BUSY_EVENT) {
- msleep(OPAL_BUSY_DELAY_MS);
+ if (in_interrupt() || irqs_disabled())
+ mdelay(OPAL_BUSY_DELAY_MS);
+ else
+ msleep(OPAL_BUSY_DELAY_MS);
opal_poll_events(NULL);
} else if (rc == OPAL_BUSY) {
- msleep(OPAL_BUSY_DELAY_MS);
+ if (in_interrupt() || irqs_disabled())
+ mdelay(OPAL_BUSY_DELAY_MS);
+ else
+ msleep(OPAL_BUSY_DELAY_MS);
}
}
diff --git a/arch/powerpc/platforms/powernv/opal-rtc.c b/arch/powerpc/platforms/powernv/opal-rtc.c
index aa2a5139462e..42ec642a3eba 100644
--- a/arch/powerpc/platforms/powernv/opal-rtc.c
+++ b/arch/powerpc/platforms/powernv/opal-rtc.c
@@ -34,7 +34,7 @@ static void opal_to_tm(u32 y_m_d, u64 h_m_s_ms, struct rtc_time *tm)
tm->tm_wday = -1;
}
-unsigned long __init opal_get_boot_time(void)
+time64_t __init opal_get_boot_time(void)
{
struct rtc_time tm;
u32 y_m_d;
@@ -61,8 +61,7 @@ unsigned long __init opal_get_boot_time(void)
y_m_d = be32_to_cpu(__y_m_d);
h_m_s_ms = be64_to_cpu(__h_m_s_ms);
opal_to_tm(y_m_d, h_m_s_ms, &tm);
- return mktime(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
- tm.tm_hour, tm.tm_min, tm.tm_sec);
+ return rtc_tm_to_time64(&tm);
}
static __init int opal_time_init(void)
diff --git a/arch/powerpc/platforms/powernv/opal-sensor.c b/arch/powerpc/platforms/powernv/opal-sensor.c
index 0a7074bb91dc..35a5f4b9aeb5 100644
--- a/arch/powerpc/platforms/powernv/opal-sensor.c
+++ b/arch/powerpc/platforms/powernv/opal-sensor.c
@@ -72,6 +72,59 @@ out:
}
EXPORT_SYMBOL_GPL(opal_get_sensor_data);
+int opal_get_sensor_data_u64(u32 sensor_hndl, u64 *sensor_data)
+{
+ int ret, token;
+ struct opal_msg msg;
+ __be64 data;
+
+ if (!opal_check_token(OPAL_SENSOR_READ_U64)) {
+ u32 sdata;
+
+ ret = opal_get_sensor_data(sensor_hndl, &sdata);
+ if (!ret)
+ *sensor_data = sdata;
+ return ret;
+ }
+
+ token = opal_async_get_token_interruptible();
+ if (token < 0)
+ return token;
+
+ ret = opal_sensor_read_u64(sensor_hndl, token, &data);
+ switch (ret) {
+ case OPAL_ASYNC_COMPLETION:
+ ret = opal_async_wait_response(token, &msg);
+ if (ret) {
+ pr_err("%s: Failed to wait for the async response, %d\n",
+ __func__, ret);
+ goto out_token;
+ }
+
+ ret = opal_error_code(opal_get_async_rc(msg));
+ *sensor_data = be64_to_cpu(data);
+ break;
+
+ case OPAL_SUCCESS:
+ ret = 0;
+ *sensor_data = be64_to_cpu(data);
+ break;
+
+ case OPAL_WRONG_STATE:
+ ret = -EIO;
+ break;
+
+ default:
+ ret = opal_error_code(ret);
+ break;
+ }
+
+out_token:
+ opal_async_release_token(token);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(opal_get_sensor_data_u64);
+
int __init opal_sensor_init(void)
{
struct platform_device *pdev;
diff --git a/arch/powerpc/platforms/powernv/opal-sysparam.c b/arch/powerpc/platforms/powernv/opal-sysparam.c
index 6fd4092798d5..9aa87df114fd 100644
--- a/arch/powerpc/platforms/powernv/opal-sysparam.c
+++ b/arch/powerpc/platforms/powernv/opal-sysparam.c
@@ -198,21 +198,21 @@ void __init opal_sys_param_init(void)
goto out_param_buf;
}
- id = kzalloc(sizeof(*id) * count, GFP_KERNEL);
+ id = kcalloc(count, sizeof(*id), GFP_KERNEL);
if (!id) {
pr_err("SYSPARAM: Failed to allocate memory to read parameter "
"id\n");
goto out_param_buf;
}
- size = kzalloc(sizeof(*size) * count, GFP_KERNEL);
+ size = kcalloc(count, sizeof(*size), GFP_KERNEL);
if (!size) {
pr_err("SYSPARAM: Failed to allocate memory to read parameter "
"size\n");
goto out_free_id;
}
- perm = kzalloc(sizeof(*perm) * count, GFP_KERNEL);
+ perm = kcalloc(count, sizeof(*perm), GFP_KERNEL);
if (!perm) {
pr_err("SYSPARAM: Failed to allocate memory to read supported "
"action on the parameter");
@@ -235,7 +235,7 @@ void __init opal_sys_param_init(void)
goto out_free_perm;
}
- attr = kzalloc(sizeof(*attr) * count, GFP_KERNEL);
+ attr = kcalloc(count, sizeof(*attr), GFP_KERNEL);
if (!attr) {
pr_err("SYSPARAM: Failed to allocate memory for parameter "
"attributes\n");
diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S
index 3da30c2f26b4..a8d9b4089c31 100644
--- a/arch/powerpc/platforms/powernv/opal-wrappers.S
+++ b/arch/powerpc/platforms/powernv/opal-wrappers.S
@@ -320,8 +320,10 @@ OPAL_CALL(opal_set_powercap, OPAL_SET_POWERCAP);
OPAL_CALL(opal_get_power_shift_ratio, OPAL_GET_POWER_SHIFT_RATIO);
OPAL_CALL(opal_set_power_shift_ratio, OPAL_SET_POWER_SHIFT_RATIO);
OPAL_CALL(opal_sensor_group_clear, OPAL_SENSOR_GROUP_CLEAR);
+OPAL_CALL(opal_quiesce, OPAL_QUIESCE);
OPAL_CALL(opal_npu_spa_setup, OPAL_NPU_SPA_SETUP);
OPAL_CALL(opal_npu_spa_clear_cache, OPAL_NPU_SPA_CLEAR_CACHE);
OPAL_CALL(opal_npu_tl_set, OPAL_NPU_TL_SET);
OPAL_CALL(opal_pci_get_pbcq_tunnel_bar, OPAL_PCI_GET_PBCQ_TUNNEL_BAR);
OPAL_CALL(opal_pci_set_pbcq_tunnel_bar, OPAL_PCI_SET_PBCQ_TUNNEL_BAR);
+OPAL_CALL(opal_sensor_read_u64, OPAL_SENSOR_READ_U64);
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index 48fbb41af5d1..0d539c661748 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -540,21 +540,15 @@ int opal_hmi_exception_early(struct pt_regs *regs)
/* HMI exception handler called in virtual mode during check_irq_replay. */
int opal_handle_hmi_exception(struct pt_regs *regs)
{
- s64 rc;
- __be64 evt = 0;
-
/*
* Check if HMI event is available.
- * if Yes, then call opal_poll_events to pull opal messages and
- * process them.
+ * if Yes, then wake kopald to process them.
*/
if (!local_paca->hmi_event_available)
return 0;
local_paca->hmi_event_available = 0;
- rc = opal_poll_events(&evt);
- if (rc == OPAL_SUCCESS && evt)
- opal_handle_events(be64_to_cpu(evt));
+ opal_wake_poller();
return 1;
}
@@ -757,14 +751,19 @@ static void __init opal_imc_init_dev(void)
static int kopald(void *unused)
{
unsigned long timeout = msecs_to_jiffies(opal_heartbeat) + 1;
- __be64 events;
set_freezable();
do {
try_to_freeze();
- opal_poll_events(&events);
- opal_handle_events(be64_to_cpu(events));
- schedule_timeout_interruptible(timeout);
+
+ opal_handle_events();
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (opal_have_pending_events())
+ __set_current_state(TASK_RUNNING);
+ else
+ schedule_timeout(timeout);
+
} while (!kthread_should_stop());
return 0;
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index 3f9c69d7623a..5bd0eb6681bc 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -1976,9 +1976,10 @@ static void pnv_pci_p7ioc_tce_invalidate(struct iommu_table *tbl,
mb(); /* Ensure above stores are visible */
while (start <= end) {
if (rm)
- __raw_rm_writeq(cpu_to_be64(start), invalidate);
+ __raw_rm_writeq_be(start, invalidate);
else
- __raw_writeq(cpu_to_be64(start), invalidate);
+ __raw_writeq_be(start, invalidate);
+
start += inc;
}
@@ -2055,9 +2056,9 @@ static void pnv_pci_phb3_tce_invalidate_entire(struct pnv_phb *phb, bool rm)
mb(); /* Ensure previous TCE table stores are visible */
if (rm)
- __raw_rm_writeq(cpu_to_be64(val), invalidate);
+ __raw_rm_writeq_be(val, invalidate);
else
- __raw_writeq(cpu_to_be64(val), invalidate);
+ __raw_writeq_be(val, invalidate);
}
static inline void pnv_pci_phb3_tce_invalidate_pe(struct pnv_ioda_pe *pe)
@@ -2067,7 +2068,7 @@ static inline void pnv_pci_phb3_tce_invalidate_pe(struct pnv_ioda_pe *pe)
unsigned long val = PHB3_TCE_KILL_INVAL_PE | (pe->pe_number & 0xFF);
mb(); /* Ensure above stores are visible */
- __raw_writeq(cpu_to_be64(val), invalidate);
+ __raw_writeq_be(val, invalidate);
}
static void pnv_pci_phb3_tce_invalidate(struct pnv_ioda_pe *pe, bool rm,
@@ -2090,9 +2091,9 @@ static void pnv_pci_phb3_tce_invalidate(struct pnv_ioda_pe *pe, bool rm,
while (start <= end) {
if (rm)
- __raw_rm_writeq(cpu_to_be64(start), invalidate);
+ __raw_rm_writeq_be(start, invalidate);
else
- __raw_writeq(cpu_to_be64(start), invalidate);
+ __raw_writeq_be(start, invalidate);
start += inc;
}
}
@@ -2910,6 +2911,34 @@ static void pnv_pci_ioda2_table_free_pages(struct iommu_table *tbl)
tbl->it_indirect_levels);
}
+static unsigned long pnv_ioda_parse_tce_sizes(struct pnv_phb *phb)
+{
+ struct pci_controller *hose = phb->hose;
+ struct device_node *dn = hose->dn;
+ unsigned long mask = 0;
+ int i, rc, count;
+ u32 val;
+
+ count = of_property_count_u32_elems(dn, "ibm,supported-tce-sizes");
+ if (count <= 0) {
+ mask = SZ_4K | SZ_64K;
+ /* Add 16M for POWER8 by default */
+ if (cpu_has_feature(CPU_FTR_ARCH_207S) &&
+ !cpu_has_feature(CPU_FTR_ARCH_300))
+ mask |= SZ_16M;
+ return mask;
+ }
+
+ for (i = 0; i < count; i++) {
+ rc = of_property_read_u32_index(dn, "ibm,supported-tce-sizes",
+ i, &val);
+ if (rc == 0)
+ mask |= 1ULL << val;
+ }
+
+ return mask;
+}
+
static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb,
struct pnv_ioda_pe *pe)
{
@@ -2934,7 +2963,7 @@ static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb,
pe->table_group.max_dynamic_windows_supported =
IOMMU_TABLE_GROUP_MAX_TABLES;
pe->table_group.max_levels = POWERNV_IOMMU_MAX_LEVELS;
- pe->table_group.pgsizes = SZ_4K | SZ_64K | SZ_16M;
+ pe->table_group.pgsizes = pnv_ioda_parse_tce_sizes(phb);
#ifdef CONFIG_IOMMU_API
pe->table_group.ops = &pnv_pci_ioda2_ops;
#endif
@@ -3642,7 +3671,6 @@ static void pnv_pci_ioda2_release_pe_dma(struct pnv_ioda_pe *pe)
WARN_ON(pe->table_group.group);
}
- pnv_pci_ioda2_table_free_pages(tbl);
iommu_tce_table_put(tbl);
}
diff --git a/arch/powerpc/platforms/powernv/powernv.h b/arch/powerpc/platforms/powernv/powernv.h
index 94f17ab1374b..fd4a1c5a6369 100644
--- a/arch/powerpc/platforms/powernv/powernv.h
+++ b/arch/powerpc/platforms/powernv/powernv.h
@@ -24,7 +24,8 @@ extern u32 pnv_get_supported_cpuidle_states(void);
extern void pnv_lpc_init(void);
-extern void opal_handle_events(uint64_t events);
+extern void opal_handle_events(void);
+extern bool opal_have_pending_events(void);
extern void opal_event_shutdown(void);
bool cpu_core_split_required(void);
diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c
index ef8c9ce53a61..f96df0a25d05 100644
--- a/arch/powerpc/platforms/powernv/setup.c
+++ b/arch/powerpc/platforms/powernv/setup.c
@@ -124,6 +124,7 @@ static void pnv_setup_rfi_flush(void)
security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV));
setup_rfi_flush(type, enable);
+ setup_barrier_nospec();
}
static void __init pnv_setup_arch(void)
@@ -131,6 +132,7 @@ static void __init pnv_setup_arch(void)
set_arch_panic_timeout(10, ARCH_PANIC_TIMEOUT);
pnv_setup_rfi_flush();
+ setup_stf_barrier();
/* Initialize SMP */
pnv_smp_init();
@@ -356,15 +358,7 @@ static void pnv_kexec_cpu_down(int crash_shutdown, int secondary)
#ifdef CONFIG_MEMORY_HOTPLUG_SPARSE
static unsigned long pnv_memory_block_size(void)
{
- /*
- * We map the kernel linear region with 1GB large pages on radix. For
- * memory hot unplug to work our memory block size must be at least
- * this size.
- */
- if (radix_enabled())
- return 1UL * 1024 * 1024 * 1024;
- else
- return 256UL * 1024 * 1024;
+ return 256UL * 1024 * 1024;
}
#endif
diff --git a/arch/powerpc/platforms/powernv/smp.c b/arch/powerpc/platforms/powernv/smp.c
index 19af6de6b6f0..b80909957792 100644
--- a/arch/powerpc/platforms/powernv/smp.c
+++ b/arch/powerpc/platforms/powernv/smp.c
@@ -334,7 +334,16 @@ static int pnv_cause_nmi_ipi(int cpu)
int64_t rc;
if (cpu >= 0) {
- rc = opal_signal_system_reset(get_hard_smp_processor_id(cpu));
+ int h = get_hard_smp_processor_id(cpu);
+
+ if (opal_check_token(OPAL_QUIESCE))
+ opal_quiesce(QUIESCE_HOLD, h);
+
+ rc = opal_signal_system_reset(h);
+
+ if (opal_check_token(OPAL_QUIESCE))
+ opal_quiesce(QUIESCE_RESUME, h);
+
if (rc != OPAL_SUCCESS)
return 0;
return 1;
@@ -343,6 +352,8 @@ static int pnv_cause_nmi_ipi(int cpu)
bool success = true;
int c;
+ if (opal_check_token(OPAL_QUIESCE))
+ opal_quiesce(QUIESCE_HOLD, -1);
/*
* We do not use broadcasts (yet), because it's not clear
@@ -358,6 +369,10 @@ static int pnv_cause_nmi_ipi(int cpu)
if (rc != OPAL_SUCCESS)
success = false;
}
+
+ if (opal_check_token(OPAL_QUIESCE))
+ opal_quiesce(QUIESCE_RESUME, -1);
+
if (success)
return 1;