Commit 8a97577a authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mpe/linux

Pull powerpc fixes from Michael Ellerman:
 "Some more powerpc fixes if you please"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mpe/linux:
  powerpc: use device_online/offline() instead of cpu_up/down()
  powerpc/powernv: Properly fix LPC debugfs endianness
  powerpc: do_notify_resume can be called with bad thread_info flags argument
  powerpc/fadump: Fix endianess issues in firmware assisted dump handling
  powerpc: Fix section mismatch warning
parents 1efa82ec 10ccaf17
...@@ -72,37 +72,37 @@ ...@@ -72,37 +72,37 @@
/* Utility macros */ /* Utility macros */
#define SKIP_TO_NEXT_CPU(reg_entry) \ #define SKIP_TO_NEXT_CPU(reg_entry) \
({ \ ({ \
while (reg_entry->reg_id != REG_ID("CPUEND")) \ while (be64_to_cpu(reg_entry->reg_id) != REG_ID("CPUEND")) \
reg_entry++; \ reg_entry++; \
reg_entry++; \ reg_entry++; \
}) })
/* Kernel Dump section info */ /* Kernel Dump section info */
struct fadump_section { struct fadump_section {
u32 request_flag; __be32 request_flag;
u16 source_data_type; __be16 source_data_type;
u16 error_flags; __be16 error_flags;
u64 source_address; __be64 source_address;
u64 source_len; __be64 source_len;
u64 bytes_dumped; __be64 bytes_dumped;
u64 destination_address; __be64 destination_address;
}; };
/* ibm,configure-kernel-dump header. */ /* ibm,configure-kernel-dump header. */
struct fadump_section_header { struct fadump_section_header {
u32 dump_format_version; __be32 dump_format_version;
u16 dump_num_sections; __be16 dump_num_sections;
u16 dump_status_flag; __be16 dump_status_flag;
u32 offset_first_dump_section; __be32 offset_first_dump_section;
/* Fields for disk dump option. */ /* Fields for disk dump option. */
u32 dd_block_size; __be32 dd_block_size;
u64 dd_block_offset; __be64 dd_block_offset;
u64 dd_num_blocks; __be64 dd_num_blocks;
u32 dd_offset_disk_path; __be32 dd_offset_disk_path;
/* Maximum time allowed to prevent an automatic dump-reboot. */ /* Maximum time allowed to prevent an automatic dump-reboot. */
u32 max_time_auto; __be32 max_time_auto;
}; };
/* /*
...@@ -174,15 +174,15 @@ static inline u64 str_to_u64(const char *str) ...@@ -174,15 +174,15 @@ static inline u64 str_to_u64(const char *str)
/* Register save area header. */ /* Register save area header. */
struct fadump_reg_save_area_header { struct fadump_reg_save_area_header {
u64 magic_number; __be64 magic_number;
u32 version; __be32 version;
u32 num_cpu_offset; __be32 num_cpu_offset;
}; };
/* Register entry. */ /* Register entry. */
struct fadump_reg_entry { struct fadump_reg_entry {
u64 reg_id; __be64 reg_id;
u64 reg_value; __be64 reg_value;
}; };
/* fadump crash info structure */ /* fadump crash info structure */
......
...@@ -659,7 +659,13 @@ _GLOBAL(ret_from_except_lite) ...@@ -659,7 +659,13 @@ _GLOBAL(ret_from_except_lite)
3: 3:
#endif #endif
bl save_nvgprs bl save_nvgprs
/*
* Use a non volatile GPR to save and restore our thread_info flags
* across the call to restore_interrupts.
*/
mr r30,r4
bl restore_interrupts bl restore_interrupts
mr r4,r30
addi r3,r1,STACK_FRAME_OVERHEAD addi r3,r1,STACK_FRAME_OVERHEAD
bl do_notify_resume bl do_notify_resume
b ret_from_except b ret_from_except
......
This diff is collapsed.
...@@ -103,7 +103,7 @@ unsigned long __max_low_memory = MAX_LOW_MEM; ...@@ -103,7 +103,7 @@ unsigned long __max_low_memory = MAX_LOW_MEM;
/* /*
* Check for command-line options that affect what MMU_init will do. * Check for command-line options that affect what MMU_init will do.
*/ */
void MMU_setup(void) void __init MMU_setup(void)
{ {
/* Check for nobats option (used in mapin_ram). */ /* Check for nobats option (used in mapin_ram). */
if (strstr(boot_command_line, "nobats")) { if (strstr(boot_command_line, "nobats")) {
......
...@@ -216,14 +216,54 @@ static ssize_t lpc_debug_read(struct file *filp, char __user *ubuf, ...@@ -216,14 +216,54 @@ static ssize_t lpc_debug_read(struct file *filp, char __user *ubuf,
&data, len); &data, len);
if (rc) if (rc)
return -ENXIO; return -ENXIO;
/*
* Now there is some trickery with the data returned by OPAL
* as it's the desired data right justified in a 32-bit BE
* word.
*
* This is a very bad interface and I'm to blame for it :-(
*
* So we can't just apply a 32-bit swap to what comes from OPAL,
* because user space expects the *bytes* to be in their proper
* respective positions (ie, LPC position).
*
* So what we really want to do here is to shift data right
* appropriately on a LE kernel.
*
* IE. If the LPC transaction has bytes B0, B1, B2 and B3 in that
* order, we have in memory written to by OPAL at the "data"
* pointer:
*
* Bytes: OPAL "data" LE "data"
* 32-bit: B0 B1 B2 B3 B0B1B2B3 B3B2B1B0
* 16-bit: B0 B1 0000B0B1 B1B00000
* 8-bit: B0 000000B0 B0000000
*
* So a BE kernel will have the leftmost of the above in the MSB
* and rightmost in the LSB and can just then "cast" the u32 "data"
* down to the appropriate quantity and write it.
*
* However, an LE kernel can't. It doesn't need to swap because a
* load from data followed by a store to user are going to preserve
* the byte ordering which is the wire byte order which is what the
* user wants, but in order to "crop" to the right size, we need to
* shift right first.
*/
switch(len) { switch(len) {
case 4: case 4:
rc = __put_user((u32)data, (u32 __user *)ubuf); rc = __put_user((u32)data, (u32 __user *)ubuf);
break; break;
case 2: case 2:
#ifdef __LITTLE_ENDIAN__
data >>= 16;
#endif
rc = __put_user((u16)data, (u16 __user *)ubuf); rc = __put_user((u16)data, (u16 __user *)ubuf);
break; break;
default: default:
#ifdef __LITTLE_ENDIAN__
data >>= 24;
#endif
rc = __put_user((u8)data, (u8 __user *)ubuf); rc = __put_user((u8)data, (u8 __user *)ubuf);
break; break;
} }
...@@ -263,12 +303,31 @@ static ssize_t lpc_debug_write(struct file *filp, const char __user *ubuf, ...@@ -263,12 +303,31 @@ static ssize_t lpc_debug_write(struct file *filp, const char __user *ubuf,
else if (todo > 1 && (pos & 1) == 0) else if (todo > 1 && (pos & 1) == 0)
len = 2; len = 2;
} }
/*
* Similarly to the read case, we have some trickery here but
* it's different to handle. We need to pass the value to OPAL in
* a register whose layout depends on the access size. We want
* to reproduce the memory layout of the user, however we aren't
* doing a load from user and a store to another memory location
* which would achieve that. Here we pass the value to OPAL via
* a register which is expected to contain the "BE" interpretation
* of the byte sequence. IE: for a 32-bit access, byte 0 should be
* in the MSB. So here we *do* need to byteswap on LE.
*
* User bytes: LE "data" OPAL "data"
* 32-bit: B0 B1 B2 B3 B3B2B1B0 B0B1B2B3
* 16-bit: B0 B1 0000B1B0 0000B0B1
* 8-bit: B0 000000B0 000000B0
*/
switch(len) { switch(len) {
case 4: case 4:
rc = __get_user(data, (u32 __user *)ubuf); rc = __get_user(data, (u32 __user *)ubuf);
data = cpu_to_be32(data);
break; break;
case 2: case 2:
rc = __get_user(data, (u16 __user *)ubuf); rc = __get_user(data, (u16 __user *)ubuf);
data = cpu_to_be16(data);
break; break;
default: default:
rc = __get_user(data, (u8 __user *)ubuf); rc = __get_user(data, (u8 __user *)ubuf);
......
...@@ -382,7 +382,7 @@ static int dlpar_online_cpu(struct device_node *dn) ...@@ -382,7 +382,7 @@ static int dlpar_online_cpu(struct device_node *dn)
BUG_ON(get_cpu_current_state(cpu) BUG_ON(get_cpu_current_state(cpu)
!= CPU_STATE_OFFLINE); != CPU_STATE_OFFLINE);
cpu_maps_update_done(); cpu_maps_update_done();
rc = cpu_up(cpu); rc = device_online(get_cpu_device(cpu));
if (rc) if (rc)
goto out; goto out;
cpu_maps_update_begin(); cpu_maps_update_begin();
...@@ -467,7 +467,7 @@ static int dlpar_offline_cpu(struct device_node *dn) ...@@ -467,7 +467,7 @@ static int dlpar_offline_cpu(struct device_node *dn)
if (get_cpu_current_state(cpu) == CPU_STATE_ONLINE) { if (get_cpu_current_state(cpu) == CPU_STATE_ONLINE) {
set_preferred_offline_state(cpu, CPU_STATE_OFFLINE); set_preferred_offline_state(cpu, CPU_STATE_OFFLINE);
cpu_maps_update_done(); cpu_maps_update_done();
rc = cpu_down(cpu); rc = device_offline(get_cpu_device(cpu));
if (rc) if (rc)
goto out; goto out;
cpu_maps_update_begin(); cpu_maps_update_begin();
......
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
#include <asm/trace.h> #include <asm/trace.h>
#include <asm/firmware.h> #include <asm/firmware.h>
#include <asm/plpar_wrappers.h> #include <asm/plpar_wrappers.h>
#include <asm/fadump.h>
#include "pseries.h" #include "pseries.h"
...@@ -247,8 +248,17 @@ static void pSeries_lpar_hptab_clear(void) ...@@ -247,8 +248,17 @@ static void pSeries_lpar_hptab_clear(void)
} }
#ifdef __LITTLE_ENDIAN__ #ifdef __LITTLE_ENDIAN__
/* Reset exceptions to big endian */ /*
if (firmware_has_feature(FW_FEATURE_SET_MODE)) { * Reset exceptions to big endian.
*
* FIXME this is a hack for kexec, we need to reset the exception
* endian before starting the new kernel and this is a convenient place
* to do it.
*
* This is also called on boot when a fadump happens. In that case we
* must not change the exception endian mode.
*/
if (firmware_has_feature(FW_FEATURE_SET_MODE) && !is_fadump_active()) {
long rc; long rc;
rc = pseries_big_endian_exceptions(); rc = pseries_big_endian_exceptions();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment