Commit fb5fe0fd authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'powerpc-4.11-4' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux

Pull some more powerpc fixes from Michael Ellerman:
 "The main item is the addition of the Power9 Machine Check handler.
  This was delayed to make sure some details were correct, and is as
  minimal as possible.

  The rest is small fixes, two for the Power9 PMU, two dealing with
  obscure toolchain problems, two for the PowerNV IOMMU code (used by
  VFIO), and one to fix a crash on 32-bit machines with macio devices
  due to missing dma_ops.

  Thanks to:
    Alexey Kardashevskiy, Cyril Bur, Larry Finger, Madhavan Srinivasan,
    Nicholas Piggin"

* tag 'powerpc-4.11-4' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux:
  powerpc/64s: POWER9 machine check handler
  powerpc/64s: allow machine check handler to set severity and initiator
  powerpc/64s: fix handling of non-synchronous machine checks
  powerpc/pmac: Fix crash in dma-mapping.h with NULL dma_ops
  powerpc/powernv/ioda2: Update iommu table base on ownership change
  powerpc/powernv/ioda2: Gracefully fail if too many TCE levels requested
  selftests/powerpc: Replace stxvx and lxvx with stxvd2x/lxvd2x
  powerpc/perf: Handle sdar_mode for marked event in power9
  powerpc/perf: Fix perf_get_data_addr() for power9 DD1
  powerpc/boot: Fix zImage TOC alignment
parents 065f3e49 7b9f71f9
...@@ -68,6 +68,7 @@ SECTIONS ...@@ -68,6 +68,7 @@ SECTIONS
} }
#ifdef CONFIG_PPC64_BOOT_WRAPPER #ifdef CONFIG_PPC64_BOOT_WRAPPER
. = ALIGN(256);
.got : .got :
{ {
__toc_start = .; __toc_start = .;
......
...@@ -51,6 +51,10 @@ ...@@ -51,6 +51,10 @@
#define PPC_BIT(bit) (1UL << PPC_BITLSHIFT(bit)) #define PPC_BIT(bit) (1UL << PPC_BITLSHIFT(bit))
#define PPC_BITMASK(bs, be) ((PPC_BIT(bs) - PPC_BIT(be)) | PPC_BIT(bs)) #define PPC_BITMASK(bs, be) ((PPC_BIT(bs) - PPC_BIT(be)) | PPC_BIT(bs))
/* Put a PPC bit into a "normal" bit position */
#define PPC_BITEXTRACT(bits, ppc_bit, dst_bit) \
((((bits) >> PPC_BITLSHIFT(ppc_bit)) & 1) << (dst_bit))
#include <asm/barrier.h> #include <asm/barrier.h>
/* Macro for generating the ***_bits() functions */ /* Macro for generating the ***_bits() functions */
......
...@@ -66,6 +66,55 @@ ...@@ -66,6 +66,55 @@
#define P8_DSISR_MC_SLB_ERRORS (P7_DSISR_MC_SLB_ERRORS | \ #define P8_DSISR_MC_SLB_ERRORS (P7_DSISR_MC_SLB_ERRORS | \
P8_DSISR_MC_ERAT_MULTIHIT_SEC) P8_DSISR_MC_ERAT_MULTIHIT_SEC)
/*
* Machine Check bits on power9
*/
#define P9_SRR1_MC_LOADSTORE(srr1) (((srr1) >> PPC_BITLSHIFT(42)) & 1)
#define P9_SRR1_MC_IFETCH(srr1) ( \
PPC_BITEXTRACT(srr1, 45, 0) | \
PPC_BITEXTRACT(srr1, 44, 1) | \
PPC_BITEXTRACT(srr1, 43, 2) | \
PPC_BITEXTRACT(srr1, 36, 3) )
/* 0 is reserved */
#define P9_SRR1_MC_IFETCH_UE 1
#define P9_SRR1_MC_IFETCH_SLB_PARITY 2
#define P9_SRR1_MC_IFETCH_SLB_MULTIHIT 3
#define P9_SRR1_MC_IFETCH_ERAT_MULTIHIT 4
#define P9_SRR1_MC_IFETCH_TLB_MULTIHIT 5
#define P9_SRR1_MC_IFETCH_UE_TLB_RELOAD 6
/* 7 is reserved */
#define P9_SRR1_MC_IFETCH_LINK_TIMEOUT 8
#define P9_SRR1_MC_IFETCH_LINK_TABLEWALK_TIMEOUT 9
/* 10 ? */
#define P9_SRR1_MC_IFETCH_RA 11
#define P9_SRR1_MC_IFETCH_RA_TABLEWALK 12
#define P9_SRR1_MC_IFETCH_RA_ASYNC_STORE 13
#define P9_SRR1_MC_IFETCH_LINK_ASYNC_STORE_TIMEOUT 14
#define P9_SRR1_MC_IFETCH_RA_TABLEWALK_FOREIGN 15
/* DSISR bits for machine check (On Power9) */
#define P9_DSISR_MC_UE (PPC_BIT(48))
#define P9_DSISR_MC_UE_TABLEWALK (PPC_BIT(49))
#define P9_DSISR_MC_LINK_LOAD_TIMEOUT (PPC_BIT(50))
#define P9_DSISR_MC_LINK_TABLEWALK_TIMEOUT (PPC_BIT(51))
#define P9_DSISR_MC_ERAT_MULTIHIT (PPC_BIT(52))
#define P9_DSISR_MC_TLB_MULTIHIT_MFTLB (PPC_BIT(53))
#define P9_DSISR_MC_USER_TLBIE (PPC_BIT(54))
#define P9_DSISR_MC_SLB_PARITY_MFSLB (PPC_BIT(55))
#define P9_DSISR_MC_SLB_MULTIHIT_MFSLB (PPC_BIT(56))
#define P9_DSISR_MC_RA_LOAD (PPC_BIT(57))
#define P9_DSISR_MC_RA_TABLEWALK (PPC_BIT(58))
#define P9_DSISR_MC_RA_TABLEWALK_FOREIGN (PPC_BIT(59))
#define P9_DSISR_MC_RA_FOREIGN (PPC_BIT(60))
/* SLB error bits */
#define P9_DSISR_MC_SLB_ERRORS (P9_DSISR_MC_ERAT_MULTIHIT | \
P9_DSISR_MC_SLB_PARITY_MFSLB | \
P9_DSISR_MC_SLB_MULTIHIT_MFSLB)
enum MCE_Version { enum MCE_Version {
MCE_V1 = 1, MCE_V1 = 1,
}; };
...@@ -93,6 +142,9 @@ enum MCE_ErrorType { ...@@ -93,6 +142,9 @@ enum MCE_ErrorType {
MCE_ERROR_TYPE_SLB = 2, MCE_ERROR_TYPE_SLB = 2,
MCE_ERROR_TYPE_ERAT = 3, MCE_ERROR_TYPE_ERAT = 3,
MCE_ERROR_TYPE_TLB = 4, MCE_ERROR_TYPE_TLB = 4,
MCE_ERROR_TYPE_USER = 5,
MCE_ERROR_TYPE_RA = 6,
MCE_ERROR_TYPE_LINK = 7,
}; };
enum MCE_UeErrorType { enum MCE_UeErrorType {
...@@ -121,6 +173,32 @@ enum MCE_TlbErrorType { ...@@ -121,6 +173,32 @@ enum MCE_TlbErrorType {
MCE_TLB_ERROR_MULTIHIT = 2, MCE_TLB_ERROR_MULTIHIT = 2,
}; };
enum MCE_UserErrorType {
MCE_USER_ERROR_INDETERMINATE = 0,
MCE_USER_ERROR_TLBIE = 1,
};
enum MCE_RaErrorType {
MCE_RA_ERROR_INDETERMINATE = 0,
MCE_RA_ERROR_IFETCH = 1,
MCE_RA_ERROR_PAGE_TABLE_WALK_IFETCH = 2,
MCE_RA_ERROR_PAGE_TABLE_WALK_IFETCH_FOREIGN = 3,
MCE_RA_ERROR_LOAD = 4,
MCE_RA_ERROR_STORE = 5,
MCE_RA_ERROR_PAGE_TABLE_WALK_LOAD_STORE = 6,
MCE_RA_ERROR_PAGE_TABLE_WALK_LOAD_STORE_FOREIGN = 7,
MCE_RA_ERROR_LOAD_STORE_FOREIGN = 8,
};
enum MCE_LinkErrorType {
MCE_LINK_ERROR_INDETERMINATE = 0,
MCE_LINK_ERROR_IFETCH_TIMEOUT = 1,
MCE_LINK_ERROR_PAGE_TABLE_WALK_IFETCH_TIMEOUT = 2,
MCE_LINK_ERROR_LOAD_TIMEOUT = 3,
MCE_LINK_ERROR_STORE_TIMEOUT = 4,
MCE_LINK_ERROR_PAGE_TABLE_WALK_LOAD_STORE_TIMEOUT = 5,
};
struct machine_check_event { struct machine_check_event {
enum MCE_Version version:8; /* 0x00 */ enum MCE_Version version:8; /* 0x00 */
uint8_t in_use; /* 0x01 */ uint8_t in_use; /* 0x01 */
...@@ -166,6 +244,30 @@ struct machine_check_event { ...@@ -166,6 +244,30 @@ struct machine_check_event {
uint64_t effective_address; uint64_t effective_address;
uint8_t reserved_2[16]; uint8_t reserved_2[16];
} tlb_error; } tlb_error;
struct {
enum MCE_UserErrorType user_error_type:8;
uint8_t effective_address_provided;
uint8_t reserved_1[6];
uint64_t effective_address;
uint8_t reserved_2[16];
} user_error;
struct {
enum MCE_RaErrorType ra_error_type:8;
uint8_t effective_address_provided;
uint8_t reserved_1[6];
uint64_t effective_address;
uint8_t reserved_2[16];
} ra_error;
struct {
enum MCE_LinkErrorType link_error_type:8;
uint8_t effective_address_provided;
uint8_t reserved_1[6];
uint64_t effective_address;
uint8_t reserved_2[16];
} link_error;
} u; } u;
}; };
...@@ -176,8 +278,12 @@ struct mce_error_info { ...@@ -176,8 +278,12 @@ struct mce_error_info {
enum MCE_SlbErrorType slb_error_type:8; enum MCE_SlbErrorType slb_error_type:8;
enum MCE_EratErrorType erat_error_type:8; enum MCE_EratErrorType erat_error_type:8;
enum MCE_TlbErrorType tlb_error_type:8; enum MCE_TlbErrorType tlb_error_type:8;
enum MCE_UserErrorType user_error_type:8;
enum MCE_RaErrorType ra_error_type:8;
enum MCE_LinkErrorType link_error_type:8;
} u; } u;
uint8_t reserved[2]; enum MCE_Severity severity:8;
enum MCE_Initiator initiator:8;
}; };
#define MAX_MC_EVT 100 #define MAX_MC_EVT 100
......
...@@ -77,6 +77,7 @@ extern void __flush_tlb_power8(unsigned int action); ...@@ -77,6 +77,7 @@ extern void __flush_tlb_power8(unsigned int action);
extern void __flush_tlb_power9(unsigned int action); extern void __flush_tlb_power9(unsigned int action);
extern long __machine_check_early_realmode_p7(struct pt_regs *regs); extern long __machine_check_early_realmode_p7(struct pt_regs *regs);
extern long __machine_check_early_realmode_p8(struct pt_regs *regs); extern long __machine_check_early_realmode_p8(struct pt_regs *regs);
extern long __machine_check_early_realmode_p9(struct pt_regs *regs);
#endif /* CONFIG_PPC64 */ #endif /* CONFIG_PPC64 */
#if defined(CONFIG_E500) #if defined(CONFIG_E500)
extern void __setup_cpu_e5500(unsigned long offset, struct cpu_spec* spec); extern void __setup_cpu_e5500(unsigned long offset, struct cpu_spec* spec);
...@@ -540,6 +541,7 @@ static struct cpu_spec __initdata cpu_specs[] = { ...@@ -540,6 +541,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.cpu_setup = __setup_cpu_power9, .cpu_setup = __setup_cpu_power9,
.cpu_restore = __restore_cpu_power9, .cpu_restore = __restore_cpu_power9,
.flush_tlb = __flush_tlb_power9, .flush_tlb = __flush_tlb_power9,
.machine_check_early = __machine_check_early_realmode_p9,
.platform = "power9", .platform = "power9",
}, },
{ /* Power9 */ { /* Power9 */
...@@ -559,6 +561,7 @@ static struct cpu_spec __initdata cpu_specs[] = { ...@@ -559,6 +561,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.cpu_setup = __setup_cpu_power9, .cpu_setup = __setup_cpu_power9,
.cpu_restore = __restore_cpu_power9, .cpu_restore = __restore_cpu_power9,
.flush_tlb = __flush_tlb_power9, .flush_tlb = __flush_tlb_power9,
.machine_check_early = __machine_check_early_realmode_p9,
.platform = "power9", .platform = "power9",
}, },
{ /* Cell Broadband Engine */ { /* Cell Broadband Engine */
......
...@@ -58,6 +58,15 @@ static void mce_set_error_info(struct machine_check_event *mce, ...@@ -58,6 +58,15 @@ static void mce_set_error_info(struct machine_check_event *mce,
case MCE_ERROR_TYPE_TLB: case MCE_ERROR_TYPE_TLB:
mce->u.tlb_error.tlb_error_type = mce_err->u.tlb_error_type; mce->u.tlb_error.tlb_error_type = mce_err->u.tlb_error_type;
break; break;
case MCE_ERROR_TYPE_USER:
mce->u.user_error.user_error_type = mce_err->u.user_error_type;
break;
case MCE_ERROR_TYPE_RA:
mce->u.ra_error.ra_error_type = mce_err->u.ra_error_type;
break;
case MCE_ERROR_TYPE_LINK:
mce->u.link_error.link_error_type = mce_err->u.link_error_type;
break;
case MCE_ERROR_TYPE_UNKNOWN: case MCE_ERROR_TYPE_UNKNOWN:
default: default:
break; break;
...@@ -90,13 +99,14 @@ void save_mce_event(struct pt_regs *regs, long handled, ...@@ -90,13 +99,14 @@ void save_mce_event(struct pt_regs *regs, long handled,
mce->gpr3 = regs->gpr[3]; mce->gpr3 = regs->gpr[3];
mce->in_use = 1; mce->in_use = 1;
mce->initiator = MCE_INITIATOR_CPU;
/* Mark it recovered if we have handled it and MSR(RI=1). */ /* Mark it recovered if we have handled it and MSR(RI=1). */
if (handled && (regs->msr & MSR_RI)) if (handled && (regs->msr & MSR_RI))
mce->disposition = MCE_DISPOSITION_RECOVERED; mce->disposition = MCE_DISPOSITION_RECOVERED;
else else
mce->disposition = MCE_DISPOSITION_NOT_RECOVERED; mce->disposition = MCE_DISPOSITION_NOT_RECOVERED;
mce->severity = MCE_SEV_ERROR_SYNC;
mce->initiator = mce_err->initiator;
mce->severity = mce_err->severity;
/* /*
* Populate the mce error_type and type-specific error_type. * Populate the mce error_type and type-specific error_type.
...@@ -115,6 +125,15 @@ void save_mce_event(struct pt_regs *regs, long handled, ...@@ -115,6 +125,15 @@ void save_mce_event(struct pt_regs *regs, long handled,
} else if (mce->error_type == MCE_ERROR_TYPE_ERAT) { } else if (mce->error_type == MCE_ERROR_TYPE_ERAT) {
mce->u.erat_error.effective_address_provided = true; mce->u.erat_error.effective_address_provided = true;
mce->u.erat_error.effective_address = addr; mce->u.erat_error.effective_address = addr;
} else if (mce->error_type == MCE_ERROR_TYPE_USER) {
mce->u.user_error.effective_address_provided = true;
mce->u.user_error.effective_address = addr;
} else if (mce->error_type == MCE_ERROR_TYPE_RA) {
mce->u.ra_error.effective_address_provided = true;
mce->u.ra_error.effective_address = addr;
} else if (mce->error_type == MCE_ERROR_TYPE_LINK) {
mce->u.link_error.effective_address_provided = true;
mce->u.link_error.effective_address = addr;
} else if (mce->error_type == MCE_ERROR_TYPE_UE) { } else if (mce->error_type == MCE_ERROR_TYPE_UE) {
mce->u.ue_error.effective_address_provided = true; mce->u.ue_error.effective_address_provided = true;
mce->u.ue_error.effective_address = addr; mce->u.ue_error.effective_address = addr;
...@@ -239,6 +258,29 @@ void machine_check_print_event_info(struct machine_check_event *evt) ...@@ -239,6 +258,29 @@ void machine_check_print_event_info(struct machine_check_event *evt)
"Parity", "Parity",
"Multihit", "Multihit",
}; };
static const char *mc_user_types[] = {
"Indeterminate",
"tlbie(l) invalid",
};
static const char *mc_ra_types[] = {
"Indeterminate",
"Instruction fetch (bad)",
"Page table walk ifetch (bad)",
"Page table walk ifetch (foreign)",
"Load (bad)",
"Store (bad)",
"Page table walk Load/Store (bad)",
"Page table walk Load/Store (foreign)",
"Load/Store (foreign)",
};
static const char *mc_link_types[] = {
"Indeterminate",
"Instruction fetch (timeout)",
"Page table walk ifetch (timeout)",
"Load (timeout)",
"Store (timeout)",
"Page table walk Load/Store (timeout)",
};
/* Print things out */ /* Print things out */
if (evt->version != MCE_V1) { if (evt->version != MCE_V1) {
...@@ -315,6 +357,36 @@ void machine_check_print_event_info(struct machine_check_event *evt) ...@@ -315,6 +357,36 @@ void machine_check_print_event_info(struct machine_check_event *evt)
printk("%s Effective address: %016llx\n", printk("%s Effective address: %016llx\n",
level, evt->u.tlb_error.effective_address); level, evt->u.tlb_error.effective_address);
break; break;
case MCE_ERROR_TYPE_USER:
subtype = evt->u.user_error.user_error_type <
ARRAY_SIZE(mc_user_types) ?
mc_user_types[evt->u.user_error.user_error_type]
: "Unknown";
printk("%s Error type: User [%s]\n", level, subtype);
if (evt->u.user_error.effective_address_provided)
printk("%s Effective address: %016llx\n",
level, evt->u.user_error.effective_address);
break;
case MCE_ERROR_TYPE_RA:
subtype = evt->u.ra_error.ra_error_type <
ARRAY_SIZE(mc_ra_types) ?
mc_ra_types[evt->u.ra_error.ra_error_type]
: "Unknown";
printk("%s Error type: Real address [%s]\n", level, subtype);
if (evt->u.ra_error.effective_address_provided)
printk("%s Effective address: %016llx\n",
level, evt->u.ra_error.effective_address);
break;
case MCE_ERROR_TYPE_LINK:
subtype = evt->u.link_error.link_error_type <
ARRAY_SIZE(mc_link_types) ?
mc_link_types[evt->u.link_error.link_error_type]
: "Unknown";
printk("%s Error type: Link [%s]\n", level, subtype);
if (evt->u.link_error.effective_address_provided)
printk("%s Effective address: %016llx\n",
level, evt->u.link_error.effective_address);
break;
default: default:
case MCE_ERROR_TYPE_UNKNOWN: case MCE_ERROR_TYPE_UNKNOWN:
printk("%s Error type: Unknown\n", level); printk("%s Error type: Unknown\n", level);
...@@ -341,6 +413,18 @@ uint64_t get_mce_fault_addr(struct machine_check_event *evt) ...@@ -341,6 +413,18 @@ uint64_t get_mce_fault_addr(struct machine_check_event *evt)
if (evt->u.tlb_error.effective_address_provided) if (evt->u.tlb_error.effective_address_provided)
return evt->u.tlb_error.effective_address; return evt->u.tlb_error.effective_address;
break; break;
case MCE_ERROR_TYPE_USER:
if (evt->u.user_error.effective_address_provided)
return evt->u.user_error.effective_address;
break;
case MCE_ERROR_TYPE_RA:
if (evt->u.ra_error.effective_address_provided)
return evt->u.ra_error.effective_address;
break;
case MCE_ERROR_TYPE_LINK:
if (evt->u.link_error.effective_address_provided)
return evt->u.link_error.effective_address;
break;
default: default:
case MCE_ERROR_TYPE_UNKNOWN: case MCE_ERROR_TYPE_UNKNOWN:
break; break;
......
...@@ -116,6 +116,51 @@ static void flush_and_reload_slb(void) ...@@ -116,6 +116,51 @@ static void flush_and_reload_slb(void)
} }
#endif #endif
static void flush_erat(void)
{
asm volatile(PPC_INVALIDATE_ERAT : : :"memory");
}
#define MCE_FLUSH_SLB 1
#define MCE_FLUSH_TLB 2
#define MCE_FLUSH_ERAT 3
static int mce_flush(int what)
{
#ifdef CONFIG_PPC_STD_MMU_64
if (what == MCE_FLUSH_SLB) {
flush_and_reload_slb();
return 1;
}
#endif
if (what == MCE_FLUSH_ERAT) {
flush_erat();
return 1;
}
if (what == MCE_FLUSH_TLB) {
if (cur_cpu_spec && cur_cpu_spec->flush_tlb) {
cur_cpu_spec->flush_tlb(TLB_INVAL_SCOPE_GLOBAL);
return 1;
}
}
return 0;
}
static int mce_handle_flush_derrors(uint64_t dsisr, uint64_t slb, uint64_t tlb, uint64_t erat)
{
if ((dsisr & slb) && mce_flush(MCE_FLUSH_SLB))
dsisr &= ~slb;
if ((dsisr & erat) && mce_flush(MCE_FLUSH_ERAT))
dsisr &= ~erat;
if ((dsisr & tlb) && mce_flush(MCE_FLUSH_TLB))
dsisr &= ~tlb;
/* Any other errors we don't understand? */
if (dsisr)
return 0;
return 1;
}
static long mce_handle_derror(uint64_t dsisr, uint64_t slb_error_bits) static long mce_handle_derror(uint64_t dsisr, uint64_t slb_error_bits)
{ {
long handled = 1; long handled = 1;
...@@ -281,6 +326,9 @@ long __machine_check_early_realmode_p7(struct pt_regs *regs) ...@@ -281,6 +326,9 @@ long __machine_check_early_realmode_p7(struct pt_regs *regs)
long handled = 1; long handled = 1;
struct mce_error_info mce_error_info = { 0 }; struct mce_error_info mce_error_info = { 0 };
mce_error_info.severity = MCE_SEV_ERROR_SYNC;
mce_error_info.initiator = MCE_INITIATOR_CPU;
srr1 = regs->msr; srr1 = regs->msr;
nip = regs->nip; nip = regs->nip;
...@@ -352,6 +400,9 @@ long __machine_check_early_realmode_p8(struct pt_regs *regs) ...@@ -352,6 +400,9 @@ long __machine_check_early_realmode_p8(struct pt_regs *regs)
long handled = 1; long handled = 1;
struct mce_error_info mce_error_info = { 0 }; struct mce_error_info mce_error_info = { 0 };
mce_error_info.severity = MCE_SEV_ERROR_SYNC;
mce_error_info.initiator = MCE_INITIATOR_CPU;
srr1 = regs->msr; srr1 = regs->msr;
nip = regs->nip; nip = regs->nip;
...@@ -372,3 +423,189 @@ long __machine_check_early_realmode_p8(struct pt_regs *regs) ...@@ -372,3 +423,189 @@ long __machine_check_early_realmode_p8(struct pt_regs *regs)
save_mce_event(regs, handled, &mce_error_info, nip, addr); save_mce_event(regs, handled, &mce_error_info, nip, addr);
return handled; return handled;
} }
static int mce_handle_derror_p9(struct pt_regs *regs)
{
uint64_t dsisr = regs->dsisr;
return mce_handle_flush_derrors(dsisr,
P9_DSISR_MC_SLB_PARITY_MFSLB |
P9_DSISR_MC_SLB_MULTIHIT_MFSLB,
P9_DSISR_MC_TLB_MULTIHIT_MFTLB,
P9_DSISR_MC_ERAT_MULTIHIT);
}
static int mce_handle_ierror_p9(struct pt_regs *regs)
{
uint64_t srr1 = regs->msr;
switch (P9_SRR1_MC_IFETCH(srr1)) {
case P9_SRR1_MC_IFETCH_SLB_PARITY:
case P9_SRR1_MC_IFETCH_SLB_MULTIHIT:
return mce_flush(MCE_FLUSH_SLB);
case P9_SRR1_MC_IFETCH_TLB_MULTIHIT:
return mce_flush(MCE_FLUSH_TLB);
case P9_SRR1_MC_IFETCH_ERAT_MULTIHIT:
return mce_flush(MCE_FLUSH_ERAT);
default:
return 0;
}
}
static void mce_get_derror_p9(struct pt_regs *regs,
struct mce_error_info *mce_err, uint64_t *addr)
{
uint64_t dsisr = regs->dsisr;
mce_err->severity = MCE_SEV_ERROR_SYNC;
mce_err->initiator = MCE_INITIATOR_CPU;
if (dsisr & P9_DSISR_MC_USER_TLBIE)
*addr = regs->nip;
else
*addr = regs->dar;
if (dsisr & P9_DSISR_MC_UE) {
mce_err->error_type = MCE_ERROR_TYPE_UE;
mce_err->u.ue_error_type = MCE_UE_ERROR_LOAD_STORE;
} else if (dsisr & P9_DSISR_MC_UE_TABLEWALK) {
mce_err->error_type = MCE_ERROR_TYPE_UE;
mce_err->u.ue_error_type = MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE;
} else if (dsisr & P9_DSISR_MC_LINK_LOAD_TIMEOUT) {
mce_err->error_type = MCE_ERROR_TYPE_LINK;
mce_err->u.link_error_type = MCE_LINK_ERROR_LOAD_TIMEOUT;
} else if (dsisr & P9_DSISR_MC_LINK_TABLEWALK_TIMEOUT) {
mce_err->error_type = MCE_ERROR_TYPE_LINK;
mce_err->u.link_error_type = MCE_LINK_ERROR_PAGE_TABLE_WALK_LOAD_STORE_TIMEOUT;
} else if (dsisr & P9_DSISR_MC_ERAT_MULTIHIT) {
mce_err->error_type = MCE_ERROR_TYPE_ERAT;
mce_err->u.erat_error_type = MCE_ERAT_ERROR_MULTIHIT;
} else if (dsisr & P9_DSISR_MC_TLB_MULTIHIT_MFTLB) {
mce_err->error_type = MCE_ERROR_TYPE_TLB;
mce_err->u.tlb_error_type = MCE_TLB_ERROR_MULTIHIT;
} else if (dsisr & P9_DSISR_MC_USER_TLBIE) {
mce_err->error_type = MCE_ERROR_TYPE_USER;
mce_err->u.user_error_type = MCE_USER_ERROR_TLBIE;
} else if (dsisr & P9_DSISR_MC_SLB_PARITY_MFSLB) {
mce_err->error_type = MCE_ERROR_TYPE_SLB;
mce_err->u.slb_error_type = MCE_SLB_ERROR_PARITY;
} else if (dsisr & P9_DSISR_MC_SLB_MULTIHIT_MFSLB) {
mce_err->error_type = MCE_ERROR_TYPE_SLB;
mce_err->u.slb_error_type = MCE_SLB_ERROR_MULTIHIT;
} else if (dsisr & P9_DSISR_MC_RA_LOAD) {
mce_err->error_type = MCE_ERROR_TYPE_RA;
mce_err->u.ra_error_type = MCE_RA_ERROR_LOAD;
} else if (dsisr & P9_DSISR_MC_RA_TABLEWALK) {
mce_err->error_type = MCE_ERROR_TYPE_RA;
mce_err->u.ra_error_type = MCE_RA_ERROR_PAGE_TABLE_WALK_LOAD_STORE;
} else if (dsisr & P9_DSISR_MC_RA_TABLEWALK_FOREIGN) {
mce_err->error_type = MCE_ERROR_TYPE_RA;
mce_err->u.ra_error_type = MCE_RA_ERROR_PAGE_TABLE_WALK_LOAD_STORE_FOREIGN;
} else if (dsisr & P9_DSISR_MC_RA_FOREIGN) {
mce_err->error_type = MCE_ERROR_TYPE_RA;
mce_err->u.ra_error_type = MCE_RA_ERROR_LOAD_STORE_FOREIGN;
}
}
static void mce_get_ierror_p9(struct pt_regs *regs,
struct mce_error_info *mce_err, uint64_t *addr)
{
uint64_t srr1 = regs->msr;
switch (P9_SRR1_MC_IFETCH(srr1)) {
case P9_SRR1_MC_IFETCH_RA_ASYNC_STORE:
case P9_SRR1_MC_IFETCH_LINK_ASYNC_STORE_TIMEOUT:
mce_err->severity = MCE_SEV_FATAL;
break;
default:
mce_err->severity = MCE_SEV_ERROR_SYNC;
break;
}
mce_err->initiator = MCE_INITIATOR_CPU;
*addr = regs->nip;
switch (P9_SRR1_MC_IFETCH(srr1)) {
case P9_SRR1_MC_IFETCH_UE:
mce_err->error_type = MCE_ERROR_TYPE_UE;
mce_err->u.ue_error_type = MCE_UE_ERROR_IFETCH;
break;
case P9_SRR1_MC_IFETCH_SLB_PARITY:
mce_err->error_type = MCE_ERROR_TYPE_SLB;
mce_err->u.slb_error_type = MCE_SLB_ERROR_PARITY;
break;
case P9_SRR1_MC_IFETCH_SLB_MULTIHIT:
mce_err->error_type = MCE_ERROR_TYPE_SLB;
mce_err->u.slb_error_type = MCE_SLB_ERROR_MULTIHIT;
break;
case P9_SRR1_MC_IFETCH_ERAT_MULTIHIT:
mce_err->error_type = MCE_ERROR_TYPE_ERAT;
mce_err->u.erat_error_type = MCE_ERAT_ERROR_MULTIHIT;
break;
case P9_SRR1_MC_IFETCH_TLB_MULTIHIT:
mce_err->error_type = MCE_ERROR_TYPE_TLB;
mce_err->u.tlb_error_type = MCE_TLB_ERROR_MULTIHIT;
break;
case P9_SRR1_MC_IFETCH_UE_TLB_RELOAD:
mce_err->error_type = MCE_ERROR_TYPE_UE;
mce_err->u.ue_error_type = MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH;
break;
case P9_SRR1_MC_IFETCH_LINK_TIMEOUT:
mce_err->error_type = MCE_ERROR_TYPE_LINK;
mce_err->u.link_error_type = MCE_LINK_ERROR_IFETCH_TIMEOUT;
break;
case P9_SRR1_MC_IFETCH_LINK_TABLEWALK_TIMEOUT:
mce_err->error_type = MCE_ERROR_TYPE_LINK;
mce_err->u.link_error_type = MCE_LINK_ERROR_PAGE_TABLE_WALK_IFETCH_TIMEOUT;
break;
case P9_SRR1_MC_IFETCH_RA:
mce_err->error_type = MCE_ERROR_TYPE_RA;
mce_err->u.ra_error_type = MCE_RA_ERROR_IFETCH;
break;
case P9_SRR1_MC_IFETCH_RA_TABLEWALK:
mce_err->error_type = MCE_ERROR_TYPE_RA;
mce_err->u.ra_error_type = MCE_RA_ERROR_PAGE_TABLE_WALK_IFETCH;
break;
case P9_SRR1_MC_IFETCH_RA_ASYNC_STORE:
mce_err->error_type = MCE_ERROR_TYPE_RA;
mce_err->u.ra_error_type = MCE_RA_ERROR_STORE;
break;
case P9_SRR1_MC_IFETCH_LINK_ASYNC_STORE_TIMEOUT:
mce_err->error_type = MCE_ERROR_TYPE_LINK;
mce_err->u.link_error_type = MCE_LINK_ERROR_STORE_TIMEOUT;
break;
case P9_SRR1_MC_IFETCH_RA_TABLEWALK_FOREIGN:
mce_err->error_type = MCE_ERROR_TYPE_RA;
mce_err->u.ra_error_type = MCE_RA_ERROR_PAGE_TABLE_WALK_IFETCH_FOREIGN;
break;
default:
break;
}
}
long __machine_check_early_realmode_p9(struct pt_regs *regs)
{
uint64_t nip, addr;
long handled;
struct mce_error_info mce_error_info = { 0 };
nip = regs->nip;
if (P9_SRR1_MC_LOADSTORE(regs->msr)) {
handled = mce_handle_derror_p9(regs);
mce_get_derror_p9(regs, &mce_error_info, &addr);
} else {
handled = mce_handle_ierror_p9(regs);
mce_get_ierror_p9(regs, &mce_error_info, &addr);
}
/* Handle UE error. */
if (mce_error_info.error_type == MCE_ERROR_TYPE_UE)
handled = mce_handle_ue_error(regs);
save_mce_event(regs, handled, &mce_error_info, nip, addr);
return handled;
}
...@@ -188,6 +188,8 @@ static inline void perf_get_data_addr(struct pt_regs *regs, u64 *addrp) ...@@ -188,6 +188,8 @@ static inline void perf_get_data_addr(struct pt_regs *regs, u64 *addrp)
sdsync = POWER7P_MMCRA_SDAR_VALID; sdsync = POWER7P_MMCRA_SDAR_VALID;
else if (ppmu->flags & PPMU_ALT_SIPR) else if (ppmu->flags & PPMU_ALT_SIPR)
sdsync = POWER6_MMCRA_SDSYNC; sdsync = POWER6_MMCRA_SDSYNC;
else if (ppmu->flags & PPMU_NO_SIAR)
sdsync = MMCRA_SAMPLE_ENABLE;
else else
sdsync = MMCRA_SDSYNC; sdsync = MMCRA_SDSYNC;
......
...@@ -65,12 +65,41 @@ static bool is_event_valid(u64 event) ...@@ -65,12 +65,41 @@ static bool is_event_valid(u64 event)
return !(event & ~valid_mask); return !(event & ~valid_mask);
} }
static u64 mmcra_sdar_mode(u64 event) static inline bool is_event_marked(u64 event)
{ {
if (cpu_has_feature(CPU_FTR_ARCH_300) && !cpu_has_feature(CPU_FTR_POWER9_DD1)) if (event & EVENT_IS_MARKED)
return p9_SDAR_MODE(event) << MMCRA_SDAR_MODE_SHIFT; return true;
return false;
}
return MMCRA_SDAR_MODE_TLB; static void mmcra_sdar_mode(u64 event, unsigned long *mmcra)
{
/*
* MMCRA[SDAR_MODE] specifices how the SDAR should be updated in
* continous sampling mode.
*
* Incase of Power8:
* MMCRA[SDAR_MODE] will be programmed as "0b01" for continous sampling
* mode and will be un-changed when setting MMCRA[63] (Marked events).
*
* Incase of Power9:
* Marked event: MMCRA[SDAR_MODE] will be set to 0b00 ('No Updates'),
* or if group already have any marked events.
* Non-Marked events (for DD1):
* MMCRA[SDAR_MODE] will be set to 0b01
* For rest
* MMCRA[SDAR_MODE] will be set from event code.
*/
if (cpu_has_feature(CPU_FTR_ARCH_300)) {
if (is_event_marked(event) || (*mmcra & MMCRA_SAMPLE_ENABLE))
*mmcra &= MMCRA_SDAR_MODE_NO_UPDATES;
else if (!cpu_has_feature(CPU_FTR_POWER9_DD1))
*mmcra |= p9_SDAR_MODE(event) << MMCRA_SDAR_MODE_SHIFT;
else if (cpu_has_feature(CPU_FTR_POWER9_DD1))
*mmcra |= MMCRA_SDAR_MODE_TLB;
} else
*mmcra |= MMCRA_SDAR_MODE_TLB;
} }
static u64 thresh_cmp_val(u64 value) static u64 thresh_cmp_val(u64 value)
...@@ -180,7 +209,7 @@ int isa207_get_constraint(u64 event, unsigned long *maskp, unsigned long *valp) ...@@ -180,7 +209,7 @@ int isa207_get_constraint(u64 event, unsigned long *maskp, unsigned long *valp)
value |= CNST_L1_QUAL_VAL(cache); value |= CNST_L1_QUAL_VAL(cache);
} }
if (event & EVENT_IS_MARKED) { if (is_event_marked(event)) {
mask |= CNST_SAMPLE_MASK; mask |= CNST_SAMPLE_MASK;
value |= CNST_SAMPLE_VAL(event >> EVENT_SAMPLE_SHIFT); value |= CNST_SAMPLE_VAL(event >> EVENT_SAMPLE_SHIFT);
} }
...@@ -276,7 +305,7 @@ int isa207_compute_mmcr(u64 event[], int n_ev, ...@@ -276,7 +305,7 @@ int isa207_compute_mmcr(u64 event[], int n_ev,
} }
/* In continuous sampling mode, update SDAR on TLB miss */ /* In continuous sampling mode, update SDAR on TLB miss */
mmcra |= mmcra_sdar_mode(event[i]); mmcra_sdar_mode(event[i], &mmcra);
if (event[i] & EVENT_IS_L1) { if (event[i] & EVENT_IS_L1) {
cache = event[i] >> EVENT_CACHE_SEL_SHIFT; cache = event[i] >> EVENT_CACHE_SEL_SHIFT;
...@@ -285,7 +314,7 @@ int isa207_compute_mmcr(u64 event[], int n_ev, ...@@ -285,7 +314,7 @@ int isa207_compute_mmcr(u64 event[], int n_ev,
mmcr1 |= (cache & 1) << MMCR1_DC_QUAL_SHIFT; mmcr1 |= (cache & 1) << MMCR1_DC_QUAL_SHIFT;
} }
if (event[i] & EVENT_IS_MARKED) { if (is_event_marked(event[i])) {
mmcra |= MMCRA_SAMPLE_ENABLE; mmcra |= MMCRA_SAMPLE_ENABLE;
val = (event[i] >> EVENT_SAMPLE_SHIFT) & EVENT_SAMPLE_MASK; val = (event[i] >> EVENT_SAMPLE_SHIFT) & EVENT_SAMPLE_MASK;
......
...@@ -246,6 +246,7 @@ ...@@ -246,6 +246,7 @@
#define MMCRA_THR_CMP_SHIFT 32 #define MMCRA_THR_CMP_SHIFT 32
#define MMCRA_SDAR_MODE_SHIFT 42 #define MMCRA_SDAR_MODE_SHIFT 42
#define MMCRA_SDAR_MODE_TLB (1ull << MMCRA_SDAR_MODE_SHIFT) #define MMCRA_SDAR_MODE_TLB (1ull << MMCRA_SDAR_MODE_SHIFT)
#define MMCRA_SDAR_MODE_NO_UPDATES ~(0x3ull << MMCRA_SDAR_MODE_SHIFT)
#define MMCRA_IFM_SHIFT 30 #define MMCRA_IFM_SHIFT 30
/* MMCR1 Threshold Compare bit constant for power9 */ /* MMCR1 Threshold Compare bit constant for power9 */
......
...@@ -395,7 +395,6 @@ static int opal_recover_mce(struct pt_regs *regs, ...@@ -395,7 +395,6 @@ static int opal_recover_mce(struct pt_regs *regs,
struct machine_check_event *evt) struct machine_check_event *evt)
{ {
int recovered = 0; int recovered = 0;
uint64_t ea = get_mce_fault_addr(evt);
if (!(regs->msr & MSR_RI)) { if (!(regs->msr & MSR_RI)) {
/* If MSR_RI isn't set, we cannot recover */ /* If MSR_RI isn't set, we cannot recover */
...@@ -404,26 +403,18 @@ static int opal_recover_mce(struct pt_regs *regs, ...@@ -404,26 +403,18 @@ static int opal_recover_mce(struct pt_regs *regs,
} else if (evt->disposition == MCE_DISPOSITION_RECOVERED) { } else if (evt->disposition == MCE_DISPOSITION_RECOVERED) {
/* Platform corrected itself */ /* Platform corrected itself */
recovered = 1; recovered = 1;
} else if (ea && !is_kernel_addr(ea)) { } else if (evt->severity == MCE_SEV_FATAL) {
/* Fatal machine check */
pr_err("Machine check interrupt is fatal\n");
recovered = 0;
} else if ((evt->severity == MCE_SEV_ERROR_SYNC) &&
(user_mode(regs) && !is_global_init(current))) {
/* /*
* Faulting address is not in kernel text. We should be fine.
* We need to find which process uses this address.
* For now, kill the task if we have received exception when * For now, kill the task if we have received exception when
* in userspace. * in userspace.
* *
* TODO: Queue up this address for hwpoisioning later. * TODO: Queue up this address for hwpoisioning later.
*/ */
if (user_mode(regs) && !is_global_init(current)) {
_exception(SIGBUS, regs, BUS_MCEERR_AR, regs->nip);
recovered = 1;
} else
recovered = 0;
} else if (user_mode(regs) && !is_global_init(current) &&
evt->severity == MCE_SEV_ERROR_SYNC) {
/*
* If we have received a synchronous error when in userspace
* kill the task.
*/
_exception(SIGBUS, regs, BUS_MCEERR_AR, regs->nip); _exception(SIGBUS, regs, BUS_MCEERR_AR, regs->nip);
recovered = 1; recovered = 1;
} }
......
...@@ -1775,17 +1775,20 @@ static u64 pnv_pci_ioda_dma_get_required_mask(struct pci_dev *pdev) ...@@ -1775,17 +1775,20 @@ static u64 pnv_pci_ioda_dma_get_required_mask(struct pci_dev *pdev)
} }
static void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe, static void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe,
struct pci_bus *bus) struct pci_bus *bus,
bool add_to_group)
{ {
struct pci_dev *dev; struct pci_dev *dev;
list_for_each_entry(dev, &bus->devices, bus_list) { list_for_each_entry(dev, &bus->devices, bus_list) {
set_iommu_table_base(&dev->dev, pe->table_group.tables[0]); set_iommu_table_base(&dev->dev, pe->table_group.tables[0]);
set_dma_offset(&dev->dev, pe->tce_bypass_base); set_dma_offset(&dev->dev, pe->tce_bypass_base);
iommu_add_device(&dev->dev); if (add_to_group)
iommu_add_device(&dev->dev);
if ((pe->flags & PNV_IODA_PE_BUS_ALL) && dev->subordinate) if ((pe->flags & PNV_IODA_PE_BUS_ALL) && dev->subordinate)
pnv_ioda_setup_bus_dma(pe, dev->subordinate); pnv_ioda_setup_bus_dma(pe, dev->subordinate,
add_to_group);
} }
} }
...@@ -2191,7 +2194,7 @@ static void pnv_pci_ioda1_setup_dma_pe(struct pnv_phb *phb, ...@@ -2191,7 +2194,7 @@ static void pnv_pci_ioda1_setup_dma_pe(struct pnv_phb *phb,
set_iommu_table_base(&pe->pdev->dev, tbl); set_iommu_table_base(&pe->pdev->dev, tbl);
iommu_add_device(&pe->pdev->dev); iommu_add_device(&pe->pdev->dev);
} else if (pe->flags & (PNV_IODA_PE_BUS | PNV_IODA_PE_BUS_ALL)) } else if (pe->flags & (PNV_IODA_PE_BUS | PNV_IODA_PE_BUS_ALL))
pnv_ioda_setup_bus_dma(pe, pe->pbus); pnv_ioda_setup_bus_dma(pe, pe->pbus, true);
return; return;
fail: fail:
...@@ -2426,6 +2429,8 @@ static void pnv_ioda2_take_ownership(struct iommu_table_group *table_group) ...@@ -2426,6 +2429,8 @@ static void pnv_ioda2_take_ownership(struct iommu_table_group *table_group)
pnv_pci_ioda2_set_bypass(pe, false); pnv_pci_ioda2_set_bypass(pe, false);
pnv_pci_ioda2_unset_window(&pe->table_group, 0); pnv_pci_ioda2_unset_window(&pe->table_group, 0);
if (pe->pbus)
pnv_ioda_setup_bus_dma(pe, pe->pbus, false);
pnv_ioda2_table_free(tbl); pnv_ioda2_table_free(tbl);
} }
...@@ -2435,6 +2440,8 @@ static void pnv_ioda2_release_ownership(struct iommu_table_group *table_group) ...@@ -2435,6 +2440,8 @@ static void pnv_ioda2_release_ownership(struct iommu_table_group *table_group)
table_group); table_group);
pnv_pci_ioda2_setup_default_config(pe); pnv_pci_ioda2_setup_default_config(pe);
if (pe->pbus)
pnv_ioda_setup_bus_dma(pe, pe->pbus, false);
} }
static struct iommu_table_group_ops pnv_pci_ioda2_ops = { static struct iommu_table_group_ops pnv_pci_ioda2_ops = {
...@@ -2624,6 +2631,9 @@ static long pnv_pci_ioda2_table_alloc_pages(int nid, __u64 bus_offset, ...@@ -2624,6 +2631,9 @@ static long pnv_pci_ioda2_table_alloc_pages(int nid, __u64 bus_offset,
level_shift = entries_shift + 3; level_shift = entries_shift + 3;
level_shift = max_t(unsigned, level_shift, PAGE_SHIFT); level_shift = max_t(unsigned, level_shift, PAGE_SHIFT);
if ((level_shift - 3) * levels + page_shift >= 60)
return -EINVAL;
/* Allocate TCE table */ /* Allocate TCE table */
addr = pnv_pci_ioda2_table_do_alloc_pages(nid, level_shift, addr = pnv_pci_ioda2_table_do_alloc_pages(nid, level_shift,
levels, tce_table_size, &offset, &total_allocated); levels, tce_table_size, &offset, &total_allocated);
...@@ -2728,7 +2738,7 @@ static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb, ...@@ -2728,7 +2738,7 @@ static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb,
if (pe->flags & PNV_IODA_PE_DEV) if (pe->flags & PNV_IODA_PE_DEV)
iommu_add_device(&pe->pdev->dev); iommu_add_device(&pe->pdev->dev);
else if (pe->flags & (PNV_IODA_PE_BUS | PNV_IODA_PE_BUS_ALL)) else if (pe->flags & (PNV_IODA_PE_BUS | PNV_IODA_PE_BUS_ALL))
pnv_ioda_setup_bus_dma(pe, pe->pbus); pnv_ioda_setup_bus_dma(pe, pe->pbus, true);
} }
#ifdef CONFIG_PCI_MSI #ifdef CONFIG_PCI_MSI
......
...@@ -392,6 +392,7 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip, ...@@ -392,6 +392,7 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip,
* To get all the fields, copy all archdata * To get all the fields, copy all archdata
*/ */
dev->ofdev.dev.archdata = chip->lbus.pdev->dev.archdata; dev->ofdev.dev.archdata = chip->lbus.pdev->dev.archdata;
dev->ofdev.dev.dma_ops = chip->lbus.pdev->dev.dma_ops;
#endif /* CONFIG_PCI */ #endif /* CONFIG_PCI */
#ifdef DEBUG #ifdef DEBUG
......
...@@ -16,56 +16,56 @@ ...@@ -16,56 +16,56 @@
*/ */
FUNC_START(load_vsx) FUNC_START(load_vsx)
li r5,0 li r5,0
lxvx vs20,r5,r3 lxvd2x vs20,r5,r3
addi r5,r5,16 addi r5,r5,16
lxvx vs21,r5,r3 lxvd2x vs21,r5,r3
addi r5,r5,16 addi r5,r5,16
lxvx vs22,r5,r3 lxvd2x vs22,r5,r3
addi r5,r5,16 addi r5,r5,16
lxvx vs23,r5,r3 lxvd2x vs23,r5,r3
addi r5,r5,16 addi r5,r5,16
lxvx vs24,r5,r3 lxvd2x vs24,r5,r3
addi r5,r5,16 addi r5,r5,16
lxvx vs25,r5,r3 lxvd2x vs25,r5,r3
addi r5,r5,16 addi r5,r5,16
lxvx vs26,r5,r3 lxvd2x vs26,r5,r3
addi r5,r5,16 addi r5,r5,16
lxvx vs27,r5,r3 lxvd2x vs27,r5,r3
addi r5,r5,16 addi r5,r5,16
lxvx vs28,r5,r3 lxvd2x vs28,r5,r3
addi r5,r5,16 addi r5,r5,16
lxvx vs29,r5,r3 lxvd2x vs29,r5,r3
addi r5,r5,16 addi r5,r5,16
lxvx vs30,r5,r3 lxvd2x vs30,r5,r3
addi r5,r5,16 addi r5,r5,16
lxvx vs31,r5,r3 lxvd2x vs31,r5,r3
blr blr
FUNC_END(load_vsx) FUNC_END(load_vsx)
FUNC_START(store_vsx) FUNC_START(store_vsx)
li r5,0 li r5,0
stxvx vs20,r5,r3 stxvd2x vs20,r5,r3
addi r5,r5,16 addi r5,r5,16
stxvx vs21,r5,r3 stxvd2x vs21,r5,r3
addi r5,r5,16 addi r5,r5,16
stxvx vs22,r5,r3 stxvd2x vs22,r5,r3
addi r5,r5,16 addi r5,r5,16
stxvx vs23,r5,r3 stxvd2x vs23,r5,r3
addi r5,r5,16 addi r5,r5,16
stxvx vs24,r5,r3 stxvd2x vs24,r5,r3
addi r5,r5,16 addi r5,r5,16
stxvx vs25,r5,r3 stxvd2x vs25,r5,r3
addi r5,r5,16 addi r5,r5,16
stxvx vs26,r5,r3 stxvd2x vs26,r5,r3
addi r5,r5,16 addi r5,r5,16
stxvx vs27,r5,r3 stxvd2x vs27,r5,r3
addi r5,r5,16 addi r5,r5,16
stxvx vs28,r5,r3 stxvd2x vs28,r5,r3
addi r5,r5,16 addi r5,r5,16
stxvx vs29,r5,r3 stxvd2x vs29,r5,r3
addi r5,r5,16 addi r5,r5,16
stxvx vs30,r5,r3 stxvd2x vs30,r5,r3
addi r5,r5,16 addi r5,r5,16
stxvx vs31,r5,r3 stxvd2x vs31,r5,r3
blr blr
FUNC_END(store_vsx) FUNC_END(store_vsx)
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