提交 838b4c02 编写于 作者: L Linus Torvalds

Merge branch 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc

Pull powerpc fixes from Ben Herrenschmidt:
 "Here is a bunch of post-merge window fixes that have been accumulating
  in patchwork while I was on vacation or buried under other stuff last
  week.

  We have the now usual batch of LE fixes from Anton (sadly some new
  stuff that went into this merge window had endian issues, we'll try to
  make sure we do better next time)

  Some fixes and cleanups to the new 24x7 performance monitoring stuff
  (mostly typos and cleaning up printk's)

  A series of fixes for an issue with our runlatch bit, which wasn't set
  properly for offlined threads/cores and under KVM, causing potentially
  some counters to misbehave along with possible power management
  issues.

  A fix for kexec nasty race where the new kernel wouldn't "see" the
  secondary processors having reached back into firmware in time.

  And finally a few other misc (and pretty simple) bug fixes"

* 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc: (33 commits)
  powerpc/4xx: Fix section mismatch in ppc4xx_pci.c
  ppc/kvm: Clear the runlatch bit of a vcpu before napping
  ppc/kvm: Set the runlatch bit of a CPU just before starting guest
  ppc/powernv: Set the runlatch bits correctly for offline cpus
  powerpc/pseries: Protect remove_memory() with device hotplug lock
  powerpc: Fix error return in rtas_flash module init
  powerpc: Bump BOOT_COMMAND_LINE_SIZE to 2048
  powerpc: Bump COMMAND_LINE_SIZE to 2048
  powerpc: Rename duplicate COMMAND_LINE_SIZE define
  powerpc/perf/hv-24x7: Catalog version number is be64, not be32
  powerpc/perf/hv-24x7: Remove [static 4096], sparse chokes on it
  powerpc/perf/hv-24x7: Use (unsigned long) not (u32) values when calling plpar_hcall_norets()
  powerpc/perf/hv-gpci: Make device attr static
  powerpc/perf/hv_gpci: Probe failures use pr_debug(), and padding reduced
  powerpc/perf/hv_24x7: Probe errors changed to pr_debug(), padding fixed
  powerpc/mm: Fix tlbie to add AVAL fields for 64K pages
  powerpc/powernv: Fix little endian issues in OPAL dump code
  powerpc/powernv: Create OPAL sglist helper functions and fix endian issues
  powerpc/powernv: Fix little endian issues in OPAL error log code
  powerpc/powernv: Fix little endian issues with opal_do_notifier calls
  ...
......@@ -139,18 +139,18 @@ static struct addr_range prep_initrd(struct addr_range vmlinux, void *chosen,
* edit the command line passed to vmlinux (by setting /chosen/bootargs).
* The buffer is put in it's own section so that tools may locate it easier.
*/
static char cmdline[COMMAND_LINE_SIZE]
static char cmdline[BOOT_COMMAND_LINE_SIZE]
__attribute__((__section__("__builtin_cmdline")));
static void prep_cmdline(void *chosen)
{
if (cmdline[0] == '\0')
getprop(chosen, "bootargs", cmdline, COMMAND_LINE_SIZE-1);
getprop(chosen, "bootargs", cmdline, BOOT_COMMAND_LINE_SIZE-1);
printf("\n\rLinux/PowerPC load: %s", cmdline);
/* If possible, edit the command line */
if (console_ops.edit_cmdline)
console_ops.edit_cmdline(cmdline, COMMAND_LINE_SIZE);
console_ops.edit_cmdline(cmdline, BOOT_COMMAND_LINE_SIZE);
printf("\n\r");
/* Put the command line back into the devtree for the kernel */
......@@ -174,7 +174,7 @@ void start(void)
* built-in command line wasn't set by an external tool */
if ((loader_info.cmdline_len > 0) && (cmdline[0] == '\0'))
memmove(cmdline, loader_info.cmdline,
min(loader_info.cmdline_len, COMMAND_LINE_SIZE-1));
min(loader_info.cmdline_len, BOOT_COMMAND_LINE_SIZE-1));
if (console_ops.open && (console_ops.open() < 0))
exit();
......
......@@ -15,7 +15,7 @@
#include "types.h"
#include "string.h"
#define COMMAND_LINE_SIZE 512
#define BOOT_COMMAND_LINE_SIZE 2048
#define MAX_PATH_LEN 256
#define MAX_PROP_LEN 256 /* What should this be? */
......
......@@ -47,13 +47,13 @@ BSS_STACK(4096);
* The buffer is put in it's own section so that tools may locate it easier.
*/
static char cmdline[COMMAND_LINE_SIZE]
static char cmdline[BOOT_COMMAND_LINE_SIZE]
__attribute__((__section__("__builtin_cmdline")));
static void prep_cmdline(void *chosen)
{
if (cmdline[0] == '\0')
getprop(chosen, "bootargs", cmdline, COMMAND_LINE_SIZE-1);
getprop(chosen, "bootargs", cmdline, BOOT_COMMAND_LINE_SIZE-1);
else
setprop_str(chosen, "bootargs", cmdline);
......
......@@ -41,14 +41,14 @@ struct opal_takeover_args {
* size except the last one in the list to be as well.
*/
struct opal_sg_entry {
void *data;
long length;
__be64 data;
__be64 length;
};
/* sg list */
/* SG list */
struct opal_sg_list {
unsigned long num_entries;
struct opal_sg_list *next;
__be64 length;
__be64 next;
struct opal_sg_entry entry[];
};
......@@ -858,8 +858,8 @@ int64_t opal_lpc_write(uint32_t chip_id, enum OpalLPCAddressType addr_type,
int64_t opal_lpc_read(uint32_t chip_id, enum OpalLPCAddressType addr_type,
uint32_t addr, __be32 *data, uint32_t sz);
int64_t opal_read_elog(uint64_t buffer, size_t size, uint64_t log_id);
int64_t opal_get_elog_size(uint64_t *log_id, size_t *size, uint64_t *elog_type);
int64_t opal_read_elog(uint64_t buffer, uint64_t size, uint64_t log_id);
int64_t opal_get_elog_size(__be64 *log_id, __be64 *size, __be64 *elog_type);
int64_t opal_write_elog(uint64_t buffer, uint64_t size, uint64_t offset);
int64_t opal_send_ack_elog(uint64_t log_id);
void opal_resend_pending_logs(void);
......@@ -868,23 +868,24 @@ int64_t opal_validate_flash(uint64_t buffer, uint32_t *size, uint32_t *result);
int64_t opal_manage_flash(uint8_t op);
int64_t opal_update_flash(uint64_t blk_list);
int64_t opal_dump_init(uint8_t dump_type);
int64_t opal_dump_info(uint32_t *dump_id, uint32_t *dump_size);
int64_t opal_dump_info2(uint32_t *dump_id, uint32_t *dump_size, uint32_t *dump_type);
int64_t opal_dump_info(__be32 *dump_id, __be32 *dump_size);
int64_t opal_dump_info2(__be32 *dump_id, __be32 *dump_size, __be32 *dump_type);
int64_t opal_dump_read(uint32_t dump_id, uint64_t buffer);
int64_t opal_dump_ack(uint32_t dump_id);
int64_t opal_dump_resend_notification(void);
int64_t opal_get_msg(uint64_t buffer, size_t size);
int64_t opal_check_completion(uint64_t buffer, size_t size, uint64_t token);
int64_t opal_get_msg(uint64_t buffer, uint64_t size);
int64_t opal_check_completion(uint64_t buffer, uint64_t size, uint64_t token);
int64_t opal_sync_host_reboot(void);
int64_t opal_get_param(uint64_t token, uint32_t param_id, uint64_t buffer,
size_t length);
uint64_t length);
int64_t opal_set_param(uint64_t token, uint32_t param_id, uint64_t buffer,
size_t length);
uint64_t length);
int64_t opal_sensor_read(uint32_t sensor_hndl, int token, __be32 *sensor_data);
/* Internal functions */
extern int early_init_dt_scan_opal(unsigned long node, const char *uname, int depth, void *data);
extern int early_init_dt_scan_opal(unsigned long node, const char *uname,
int depth, void *data);
extern int early_init_dt_scan_recoverable_ranges(unsigned long node,
const char *uname, int depth, void *data);
......@@ -893,10 +894,6 @@ extern int opal_put_chars(uint32_t vtermno, const char *buf, int total_len);
extern void hvc_opal_init_early(void);
/* Internal functions */
extern int early_init_dt_scan_opal(unsigned long node, const char *uname,
int depth, void *data);
extern int opal_notifier_register(struct notifier_block *nb);
extern int opal_notifier_unregister(struct notifier_block *nb);
......@@ -906,9 +903,6 @@ extern void opal_notifier_enable(void);
extern void opal_notifier_disable(void);
extern void opal_notifier_update_evt(uint64_t evt_mask, uint64_t evt_val);
extern int opal_get_chars(uint32_t vtermno, char *buf, int count);
extern int opal_put_chars(uint32_t vtermno, const char *buf, int total_len);
extern int __opal_async_get_token(void);
extern int opal_async_get_token_interruptible(void);
extern int __opal_async_release_token(int token);
......@@ -916,8 +910,6 @@ extern int opal_async_release_token(int token);
extern int opal_async_wait_response(uint64_t token, struct opal_msg *msg);
extern int opal_get_sensor_data(u32 sensor_hndl, u32 *sensor_data);
extern void hvc_opal_init_early(void);
struct rtc_time;
extern int opal_set_rtc_time(struct rtc_time *tm);
extern void opal_get_rtc_time(struct rtc_time *tm);
......@@ -937,6 +929,10 @@ extern int opal_resync_timebase(void);
extern void opal_lpc_init(void);
struct opal_sg_list *opal_vmalloc_to_sg_list(void *vmalloc_addr,
unsigned long vmalloc_size);
void opal_free_sg_list(struct opal_sg_list *sg);
#endif /* __ASSEMBLY__ */
#endif /* __OPAL_H */
#include <asm-generic/setup.h>
#ifndef _UAPI_ASM_POWERPC_SETUP_H
#define _UAPI_ASM_POWERPC_SETUP_H
#define COMMAND_LINE_SIZE 2048
#endif /* _UAPI_ASM_POWERPC_SETUP_H */
......@@ -120,6 +120,7 @@ EXPORT_SYMBOL(giveup_spe);
EXPORT_SYMBOL(flush_instruction_cache);
#endif
EXPORT_SYMBOL(flush_dcache_range);
EXPORT_SYMBOL(flush_icache_range);
#ifdef CONFIG_SMP
#ifdef CONFIG_PPC32
......
......@@ -705,7 +705,7 @@ static int __init rtas_flash_init(void)
if (rtas_token("ibm,update-flash-64-and-reboot") ==
RTAS_UNKNOWN_SERVICE) {
pr_info("rtas_flash: no firmware flash support\n");
return 1;
return -EINVAL;
}
rtas_validate_flash_data.buf = kzalloc(VALIDATE_BUF_SIZE, GFP_KERNEL);
......
......@@ -242,6 +242,12 @@ kvm_novcpu_exit:
*/
.globl kvm_start_guest
kvm_start_guest:
/* Set runlatch bit the minute you wake up from nap */
mfspr r1, SPRN_CTRLF
ori r1, r1, 1
mtspr SPRN_CTRLT, r1
ld r2,PACATOC(r13)
li r0,KVM_HWTHREAD_IN_KVM
......@@ -309,6 +315,11 @@ kvm_no_guest:
li r0, KVM_HWTHREAD_IN_NAP
stb r0, HSTATE_HWTHREAD_STATE(r13)
kvm_do_nap:
/* Clear the runlatch bit before napping */
mfspr r2, SPRN_CTRLF
clrrdi r2, r2, 1
mtspr SPRN_CTRLT, r2
li r3, LPCR_PECE0
mfspr r4, SPRN_LPCR
rlwimi r4, r3, 0, LPCR_PECE0 | LPCR_PECE1
......@@ -1999,8 +2010,13 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_206)
/*
* Take a nap until a decrementer or external or doobell interrupt
* occurs, with PECE1, PECE0 and PECEDP set in LPCR
* occurs, with PECE1, PECE0 and PECEDP set in LPCR. Also clear the
* runlatch bit before napping.
*/
mfspr r2, SPRN_CTRLF
clrrdi r2, r2, 1
mtspr SPRN_CTRLT, r2
li r0,1
stb r0,HSTATE_HWTHREAD_REQ(r13)
mfspr r5,SPRN_LPCR
......
......@@ -82,17 +82,14 @@ static inline void __tlbie(unsigned long vpn, int psize, int apsize, int ssize)
va &= ~((1ul << mmu_psize_defs[apsize].shift) - 1);
va |= penc << 12;
va |= ssize << 8;
/* Add AVAL part */
if (psize != apsize) {
/*
* MPSS, 64K base page size and 16MB parge page size
* We don't need all the bits, but rest of the bits
* must be ignored by the processor.
* vpn cover upto 65 bits of va. (0...65) and we need
* 58..64 bits of va.
*/
va |= (vpn & 0xfe);
}
/*
* AVAL bits:
* We don't need all the bits, but rest of the bits
* must be ignored by the processor.
* vpn cover upto 65 bits of va. (0...65) and we need
* 58..64 bits of va.
*/
va |= (vpn & 0xfe); /* AVAL */
va |= 1; /* L */
asm volatile(ASM_FTR_IFCLR("tlbie %0,1", PPC_TLBIE(%1,%0), %2)
: : "r" (va), "r"(0), "i" (CPU_FTR_ARCH_206)
......@@ -133,17 +130,14 @@ static inline void __tlbiel(unsigned long vpn, int psize, int apsize, int ssize)
va &= ~((1ul << mmu_psize_defs[apsize].shift) - 1);
va |= penc << 12;
va |= ssize << 8;
/* Add AVAL part */
if (psize != apsize) {
/*
* MPSS, 64K base page size and 16MB parge page size
* We don't need all the bits, but rest of the bits
* must be ignored by the processor.
* vpn cover upto 65 bits of va. (0...65) and we need
* 58..64 bits of va.
*/
va |= (vpn & 0xfe);
}
/*
* AVAL bits:
* We don't need all the bits, but rest of the bits
* must be ignored by the processor.
* vpn cover upto 65 bits of va. (0...65) and we need
* 58..64 bits of va.
*/
va |= (vpn & 0xfe);
va |= 1; /* L */
asm volatile(".long 0x7c000224 | (%0 << 11) | (1 << 21)"
: : "r"(va) : "memory");
......
......@@ -155,16 +155,28 @@ static ssize_t read_offset_data(void *dest, size_t dest_len,
return copy_len;
}
static unsigned long h_get_24x7_catalog_page(char page[static 4096],
u32 version, u32 index)
static unsigned long h_get_24x7_catalog_page_(unsigned long phys_4096,
unsigned long version,
unsigned long index)
{
WARN_ON(!IS_ALIGNED((unsigned long)page, 4096));
pr_devel("h_get_24x7_catalog_page(0x%lx, %lu, %lu)",
phys_4096,
version,
index);
WARN_ON(!IS_ALIGNED(phys_4096, 4096));
return plpar_hcall_norets(H_GET_24X7_CATALOG_PAGE,
virt_to_phys(page),
phys_4096,
version,
index);
}
static unsigned long h_get_24x7_catalog_page(char page[],
u64 version, u32 index)
{
return h_get_24x7_catalog_page_(virt_to_phys(page),
version, index);
}
static ssize_t catalog_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr, char *buf,
loff_t offset, size_t count)
......@@ -173,7 +185,7 @@ static ssize_t catalog_read(struct file *filp, struct kobject *kobj,
ssize_t ret = 0;
size_t catalog_len = 0, catalog_page_len = 0, page_count = 0;
loff_t page_offset = 0;
uint32_t catalog_version_num = 0;
uint64_t catalog_version_num = 0;
void *page = kmem_cache_alloc(hv_page_cache, GFP_USER);
struct hv_24x7_catalog_page_0 *page_0 = page;
if (!page)
......@@ -185,7 +197,7 @@ static ssize_t catalog_read(struct file *filp, struct kobject *kobj,
goto e_free;
}
catalog_version_num = be32_to_cpu(page_0->version);
catalog_version_num = be64_to_cpu(page_0->version);
catalog_page_len = be32_to_cpu(page_0->length);
catalog_len = catalog_page_len * 4096;
......@@ -208,8 +220,9 @@ static ssize_t catalog_read(struct file *filp, struct kobject *kobj,
page, 4096, page_offset * 4096);
e_free:
if (hret)
pr_err("h_get_24x7_catalog_page(ver=%d, page=%lld) failed: rc=%ld\n",
catalog_version_num, page_offset, hret);
pr_err("h_get_24x7_catalog_page(ver=%lld, page=%lld) failed:"
" rc=%ld\n",
catalog_version_num, page_offset, hret);
kfree(page);
pr_devel("catalog_read: offset=%lld(%lld) count=%zu(%zu) catalog_len=%zu(%zu) => %zd\n",
......@@ -243,7 +256,7 @@ e_free: \
static DEVICE_ATTR_RO(_name)
PAGE_0_ATTR(catalog_version, "%lld\n",
(unsigned long long)be32_to_cpu(page_0->version));
(unsigned long long)be64_to_cpu(page_0->version));
PAGE_0_ATTR(catalog_len, "%lld\n",
(unsigned long long)be32_to_cpu(page_0->length) * 4096);
static BIN_ATTR_RO(catalog, 0/* real length varies */);
......@@ -485,13 +498,13 @@ static int hv_24x7_init(void)
struct hv_perf_caps caps;
if (!firmware_has_feature(FW_FEATURE_LPAR)) {
pr_info("not a virtualized system, not enabling\n");
pr_debug("not a virtualized system, not enabling\n");
return -ENODEV;
}
hret = hv_perf_caps_get(&caps);
if (hret) {
pr_info("could not obtain capabilities, error 0x%80lx, not enabling\n",
pr_debug("could not obtain capabilities, not enabling, rc=%ld\n",
hret);
return -ENODEV;
}
......
......@@ -78,7 +78,7 @@ static ssize_t kernel_version_show(struct device *dev,
return sprintf(page, "0x%x\n", COUNTER_INFO_VERSION_CURRENT);
}
DEVICE_ATTR_RO(kernel_version);
static DEVICE_ATTR_RO(kernel_version);
HV_CAPS_ATTR(version, "0x%x\n");
HV_CAPS_ATTR(ga, "%d\n");
HV_CAPS_ATTR(expanded, "%d\n");
......@@ -273,13 +273,13 @@ static int hv_gpci_init(void)
struct hv_perf_caps caps;
if (!firmware_has_feature(FW_FEATURE_LPAR)) {
pr_info("not a virtualized system, not enabling\n");
pr_debug("not a virtualized system, not enabling\n");
return -ENODEV;
}
hret = hv_perf_caps_get(&caps);
if (hret) {
pr_info("could not obtain capabilities, error 0x%80lx, not enabling\n",
pr_debug("could not obtain capabilities, not enabling, rc=%ld\n",
hret);
return -ENODEV;
}
......
......@@ -209,89 +209,20 @@ static struct kobj_type dump_ktype = {
.default_attrs = dump_default_attrs,
};
static void free_dump_sg_list(struct opal_sg_list *list)
{
struct opal_sg_list *sg1;
while (list) {
sg1 = list->next;
kfree(list);
list = sg1;
}
list = NULL;
}
static struct opal_sg_list *dump_data_to_sglist(struct dump_obj *dump)
{
struct opal_sg_list *sg1, *list = NULL;
void *addr;
int64_t size;
addr = dump->buffer;
size = dump->size;
sg1 = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!sg1)
goto nomem;
list = sg1;
sg1->num_entries = 0;
while (size > 0) {
/* Translate virtual address to physical address */
sg1->entry[sg1->num_entries].data =
(void *)(vmalloc_to_pfn(addr) << PAGE_SHIFT);
if (size > PAGE_SIZE)
sg1->entry[sg1->num_entries].length = PAGE_SIZE;
else
sg1->entry[sg1->num_entries].length = size;
sg1->num_entries++;
if (sg1->num_entries >= SG_ENTRIES_PER_NODE) {
sg1->next = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!sg1->next)
goto nomem;
sg1 = sg1->next;
sg1->num_entries = 0;
}
addr += PAGE_SIZE;
size -= PAGE_SIZE;
}
return list;
nomem:
pr_err("%s : Failed to allocate memory\n", __func__);
free_dump_sg_list(list);
return NULL;
}
static void sglist_to_phy_addr(struct opal_sg_list *list)
{
struct opal_sg_list *sg, *next;
for (sg = list; sg; sg = next) {
next = sg->next;
/* Don't translate NULL pointer for last entry */
if (sg->next)
sg->next = (struct opal_sg_list *)__pa(sg->next);
else
sg->next = NULL;
/* Convert num_entries to length */
sg->num_entries =
sg->num_entries * sizeof(struct opal_sg_entry) + 16;
}
}
static int64_t dump_read_info(uint32_t *id, uint32_t *size, uint32_t *type)
static int64_t dump_read_info(uint32_t *dump_id, uint32_t *dump_size, uint32_t *dump_type)
{
__be32 id, size, type;
int rc;
*type = 0xffffffff;
rc = opal_dump_info2(id, size, type);
type = cpu_to_be32(0xffffffff);
rc = opal_dump_info2(&id, &size, &type);
if (rc == OPAL_PARAMETER)
rc = opal_dump_info(id, size);
rc = opal_dump_info(&id, &size);
*dump_id = be32_to_cpu(id);
*dump_size = be32_to_cpu(size);
*dump_type = be32_to_cpu(type);
if (rc)
pr_warn("%s: Failed to get dump info (%d)\n",
......@@ -314,15 +245,12 @@ static int64_t dump_read_data(struct dump_obj *dump)
}
/* Generate SG list */
list = dump_data_to_sglist(dump);
list = opal_vmalloc_to_sg_list(dump->buffer, dump->size);
if (!list) {
rc = -ENOMEM;
goto out;
}
/* Translate sg list addr to real address */
sglist_to_phy_addr(list);
/* First entry address */
addr = __pa(list);
......@@ -341,7 +269,7 @@ static int64_t dump_read_data(struct dump_obj *dump)
__func__, dump->id);
/* Free SG list */
free_dump_sg_list(list);
opal_free_sg_list(list);
out:
return rc;
......
......@@ -238,18 +238,25 @@ static struct elog_obj *create_elog_obj(uint64_t id, size_t size, uint64_t type)
static void elog_work_fn(struct work_struct *work)
{
size_t elog_size;
__be64 size;
__be64 id;
__be64 type;
uint64_t elog_size;
uint64_t log_id;
uint64_t elog_type;
int rc;
char name[2+16+1];
rc = opal_get_elog_size(&log_id, &elog_size, &elog_type);
rc = opal_get_elog_size(&id, &size, &type);
if (rc != OPAL_SUCCESS) {
pr_err("ELOG: Opal log read failed\n");
return;
}
elog_size = be64_to_cpu(size);
log_id = be64_to_cpu(id);
elog_type = be64_to_cpu(type);
BUG_ON(elog_size > OPAL_MAX_ERRLOG_SIZE);
if (elog_size >= OPAL_MAX_ERRLOG_SIZE)
......
......@@ -79,9 +79,6 @@
/* XXX: Assume candidate image size is <= 1GB */
#define MAX_IMAGE_SIZE 0x40000000
/* Flash sg list version */
#define SG_LIST_VERSION (1UL)
/* Image status */
enum {
IMAGE_INVALID,
......@@ -131,11 +128,15 @@ static DEFINE_MUTEX(image_data_mutex);
*/
static inline void opal_flash_validate(void)
{
struct validate_flash_t *args_buf = &validate_flash_data;
long ret;
void *buf = validate_flash_data.buf;
__be32 size, result;
args_buf->status = opal_validate_flash(__pa(args_buf->buf),
&(args_buf->buf_size),
&(args_buf->result));
ret = opal_validate_flash(__pa(buf), &size, &result);
validate_flash_data.status = ret;
validate_flash_data.buf_size = be32_to_cpu(size);
validate_flash_data.result = be32_to_cpu(result);
}
/*
......@@ -267,94 +268,12 @@ static ssize_t manage_store(struct kobject *kobj,
return count;
}
/*
* Free sg list
*/
static void free_sg_list(struct opal_sg_list *list)
{
struct opal_sg_list *sg1;
while (list) {
sg1 = list->next;
kfree(list);
list = sg1;
}
list = NULL;
}
/*
* Build candidate image scatter gather list
*
* list format:
* -----------------------------------
* | VER (8) | Entry length in bytes |
* -----------------------------------
* | Pointer to next entry |
* -----------------------------------
* | Address of memory area 1 |
* -----------------------------------
* | Length of memory area 1 |
* -----------------------------------
* | ......... |
* -----------------------------------
* | ......... |
* -----------------------------------
* | Address of memory area N |
* -----------------------------------
* | Length of memory area N |
* -----------------------------------
*/
static struct opal_sg_list *image_data_to_sglist(void)
{
struct opal_sg_list *sg1, *list = NULL;
void *addr;
int size;
addr = image_data.data;
size = image_data.size;
sg1 = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!sg1)
return NULL;
list = sg1;
sg1->num_entries = 0;
while (size > 0) {
/* Translate virtual address to physical address */
sg1->entry[sg1->num_entries].data =
(void *)(vmalloc_to_pfn(addr) << PAGE_SHIFT);
if (size > PAGE_SIZE)
sg1->entry[sg1->num_entries].length = PAGE_SIZE;
else
sg1->entry[sg1->num_entries].length = size;
sg1->num_entries++;
if (sg1->num_entries >= SG_ENTRIES_PER_NODE) {
sg1->next = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!sg1->next) {
pr_err("%s : Failed to allocate memory\n",
__func__);
goto nomem;
}
sg1 = sg1->next;
sg1->num_entries = 0;
}
addr += PAGE_SIZE;
size -= PAGE_SIZE;
}
return list;
nomem:
free_sg_list(list);
return NULL;
}
/*
* OPAL update flash
*/
static int opal_flash_update(int op)
{
struct opal_sg_list *sg, *list, *next;
struct opal_sg_list *list;
unsigned long addr;
int64_t rc = OPAL_PARAMETER;
......@@ -364,30 +283,13 @@ static int opal_flash_update(int op)
goto flash;
}
list = image_data_to_sglist();
list = opal_vmalloc_to_sg_list(image_data.data, image_data.size);
if (!list)
goto invalid_img;
/* First entry address */
addr = __pa(list);
/* Translate sg list address to absolute */
for (sg = list; sg; sg = next) {
next = sg->next;
/* Don't translate NULL pointer for last entry */
if (sg->next)
sg->next = (struct opal_sg_list *)__pa(sg->next);
else
sg->next = NULL;
/*
* Convert num_entries to version/length format
* to satisfy OPAL.
*/
sg->num_entries = (SG_LIST_VERSION << 56) |
(sg->num_entries * sizeof(struct opal_sg_entry) + 16);
}
pr_alert("FLASH: Image is %u bytes\n", image_data.size);
pr_alert("FLASH: Image update requested\n");
pr_alert("FLASH: Image will be updated during system reboot\n");
......
......@@ -39,10 +39,11 @@ struct param_attr {
struct kobj_attribute kobj_attr;
};
static int opal_get_sys_param(u32 param_id, u32 length, void *buffer)
static ssize_t opal_get_sys_param(u32 param_id, u32 length, void *buffer)
{
struct opal_msg msg;
int ret, token;
ssize_t ret;
int token;
token = opal_async_get_token_interruptible();
if (token < 0) {
......@@ -59,7 +60,7 @@ static int opal_get_sys_param(u32 param_id, u32 length, void *buffer)
ret = opal_async_wait_response(token, &msg);
if (ret) {
pr_err("%s: Failed to wait for the async response, %d\n",
pr_err("%s: Failed to wait for the async response, %zd\n",
__func__, ret);
goto out_token;
}
......@@ -111,7 +112,7 @@ static ssize_t sys_param_show(struct kobject *kobj,
{
struct param_attr *attr = container_of(kobj_attr, struct param_attr,
kobj_attr);
int ret;
ssize_t ret;
mutex_lock(&opal_sysparam_mutex);
ret = opal_get_sys_param(attr->param_id, attr->param_size,
......@@ -121,9 +122,10 @@ static ssize_t sys_param_show(struct kobject *kobj,
memcpy(buf, param_data_buf, attr->param_size);
ret = attr->param_size;
out:
mutex_unlock(&opal_sysparam_mutex);
return ret ? ret : attr->param_size;
return ret;
}
static ssize_t sys_param_store(struct kobject *kobj,
......@@ -131,14 +133,20 @@ static ssize_t sys_param_store(struct kobject *kobj,
{
struct param_attr *attr = container_of(kobj_attr, struct param_attr,
kobj_attr);
int ret;
ssize_t ret;
/* MAX_PARAM_DATA_LEN is sizeof(param_data_buf) */
if (count > MAX_PARAM_DATA_LEN)
count = MAX_PARAM_DATA_LEN;
mutex_lock(&opal_sysparam_mutex);
memcpy(param_data_buf, buf, count);
ret = opal_set_sys_param(attr->param_id, attr->param_size,
param_data_buf);
mutex_unlock(&opal_sysparam_mutex);
return ret ? ret : count;
if (!ret)
ret = count;
return ret;
}
void __init opal_sys_param_init(void)
......@@ -214,13 +222,13 @@ void __init opal_sys_param_init(void)
}
if (of_property_read_u32_array(sysparam, "param-len", size, count)) {
pr_err("SYSPARAM: Missing propery param-len in the DT\n");
pr_err("SYSPARAM: Missing property param-len in the DT\n");
goto out_free_perm;
}
if (of_property_read_u8_array(sysparam, "param-perm", perm, count)) {
pr_err("SYSPARAM: Missing propery param-perm in the DT\n");
pr_err("SYSPARAM: Missing property param-perm in the DT\n");
goto out_free_perm;
}
......@@ -233,6 +241,12 @@ void __init opal_sys_param_init(void)
/* For each of the parameters, populate the parameter attributes */
for (i = 0; i < count; i++) {
if (size[i] > MAX_PARAM_DATA_LEN) {
pr_warn("SYSPARAM: Not creating parameter %d as size "
"exceeds buffer length\n", i);
continue;
}
sysfs_attr_init(&attr[i].kobj_attr.attr);
attr[i].param_id = id[i];
attr[i].param_size = size[i];
......
......@@ -242,14 +242,14 @@ void opal_notifier_update_evt(uint64_t evt_mask,
void opal_notifier_enable(void)
{
int64_t rc;
uint64_t evt = 0;
__be64 evt = 0;
atomic_set(&opal_notifier_hold, 0);
/* Process pending events */
rc = opal_poll_events(&evt);
if (rc == OPAL_SUCCESS && evt)
opal_do_notifier(evt);
opal_do_notifier(be64_to_cpu(evt));
}
void opal_notifier_disable(void)
......@@ -529,7 +529,7 @@ static irqreturn_t opal_interrupt(int irq, void *data)
opal_handle_interrupt(virq_to_hw(irq), &events);
opal_do_notifier(events);
opal_do_notifier(be64_to_cpu(events));
return IRQ_HANDLED;
}
......@@ -638,3 +638,66 @@ void opal_shutdown(void)
/* Export this so that test modules can use it */
EXPORT_SYMBOL_GPL(opal_invalid_call);
/* Convert a region of vmalloc memory to an opal sg list */
struct opal_sg_list *opal_vmalloc_to_sg_list(void *vmalloc_addr,
unsigned long vmalloc_size)
{
struct opal_sg_list *sg, *first = NULL;
unsigned long i = 0;
sg = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!sg)
goto nomem;
first = sg;
while (vmalloc_size > 0) {
uint64_t data = vmalloc_to_pfn(vmalloc_addr) << PAGE_SHIFT;
uint64_t length = min(vmalloc_size, PAGE_SIZE);
sg->entry[i].data = cpu_to_be64(data);
sg->entry[i].length = cpu_to_be64(length);
i++;
if (i >= SG_ENTRIES_PER_NODE) {
struct opal_sg_list *next;
next = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!next)
goto nomem;
sg->length = cpu_to_be64(
i * sizeof(struct opal_sg_entry) + 16);
i = 0;
sg->next = cpu_to_be64(__pa(next));
sg = next;
}
vmalloc_addr += length;
vmalloc_size -= length;
}
sg->length = cpu_to_be64(i * sizeof(struct opal_sg_entry) + 16);
return first;
nomem:
pr_err("%s : Failed to allocate memory\n", __func__);
opal_free_sg_list(first);
return NULL;
}
void opal_free_sg_list(struct opal_sg_list *sg)
{
while (sg) {
uint64_t next = be64_to_cpu(sg->next);
kfree(sg);
if (next)
sg = __va(next);
else
sg = NULL;
}
}
......@@ -343,7 +343,6 @@ static void pnv_ioda_setup_same_PE(struct pci_bus *bus, struct pnv_ioda_pe *pe)
pci_name(dev));
continue;
}
pci_dev_get(dev);
pdn->pcidev = dev;
pdn->pe_number = pe->pe_number;
pe->dma_weight += pnv_ioda_dma_weight(dev);
......@@ -462,7 +461,7 @@ static void pnv_pci_ioda_dma_dev_setup(struct pnv_phb *phb, struct pci_dev *pdev
pe = &phb->ioda.pe_array[pdn->pe_number];
WARN_ON(get_dma_ops(&pdev->dev) != &dma_iommu_ops);
set_iommu_table_base_and_group(&pdev->dev, &pe->tce32_table);
set_iommu_table_base(&pdev->dev, &pe->tce32_table);
}
static int pnv_pci_ioda_dma_set_mask(struct pnv_phb *phb,
......
......@@ -162,18 +162,62 @@ static void pnv_shutdown(void)
}
#ifdef CONFIG_KEXEC
static void pnv_kexec_wait_secondaries_down(void)
{
int my_cpu, i, notified = -1;
my_cpu = get_cpu();
for_each_online_cpu(i) {
uint8_t status;
int64_t rc;
if (i == my_cpu)
continue;
for (;;) {
rc = opal_query_cpu_status(get_hard_smp_processor_id(i),
&status);
if (rc != OPAL_SUCCESS || status != OPAL_THREAD_STARTED)
break;
barrier();
if (i != notified) {
printk(KERN_INFO "kexec: waiting for cpu %d "
"(physical %d) to enter OPAL\n",
i, paca[i].hw_cpu_id);
notified = i;
}
}
}
}
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) {
/* On OPAL v3, we return all CPUs to firmware */
if (!firmware_has_feature(FW_FEATURE_OPALv3))
return;
if (secondary) {
/* Return secondary CPUs to firmware on OPAL v3 */
mb();
get_paca()->kexec_state = KEXEC_STATE_REAL_MODE;
mb();
/* Return the CPU to OPAL */
opal_return_cpu();
} else if (crash_shutdown) {
/*
* On crash, we don't wait for secondaries to go
* down as they might be unreachable or hung, so
* instead we just wait a bit and move on.
*/
mdelay(1);
} else {
/* Primary waits for the secondaries to have reached OPAL */
pnv_kexec_wait_secondaries_down();
}
}
#endif /* CONFIG_KEXEC */
......
......@@ -30,6 +30,7 @@
#include <asm/cputhreads.h>
#include <asm/xics.h>
#include <asm/opal.h>
#include <asm/runlatch.h>
#include "powernv.h"
......@@ -156,7 +157,9 @@ static void pnv_smp_cpu_kill_self(void)
*/
mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) & ~(u64)LPCR_PECE1);
while (!generic_check_cpu_restart(cpu)) {
ppc64_runlatch_off();
power7_nap();
ppc64_runlatch_on();
if (!generic_check_cpu_restart(cpu)) {
DBG("CPU%d Unexpected exit while offline !\n", cpu);
/* We may be getting an IPI, so we re-enable
......
......@@ -88,13 +88,14 @@ void set_default_offline_state(int cpu)
static void rtas_stop_self(void)
{
struct rtas_args args = {
.token = cpu_to_be32(rtas_stop_self_token),
static struct rtas_args args = {
.nargs = 0,
.nret = 1,
.rets = &args.args[0],
};
args.token = cpu_to_be32(rtas_stop_self_token);
local_irq_disable();
BUG_ON(rtas_stop_self_token == RTAS_UNKNOWN_SERVICE);
......
......@@ -100,10 +100,10 @@ static int pseries_remove_memblock(unsigned long base, unsigned int memblock_siz
start_pfn = base >> PAGE_SHIFT;
if (!pfn_valid(start_pfn)) {
memblock_remove(base, memblock_size);
return 0;
}
lock_device_hotplug();
if (!pfn_valid(start_pfn))
goto out;
block_sz = memory_block_size_bytes();
sections_per_block = block_sz / MIN_MEMORY_BLOCK_SIZE;
......@@ -114,8 +114,10 @@ static int pseries_remove_memblock(unsigned long base, unsigned int memblock_siz
base += MIN_MEMORY_BLOCK_SIZE;
}
out:
/* Update memory regions for memory remove */
memblock_remove(base, memblock_size);
unlock_device_hotplug();
return 0;
}
......
......@@ -1058,7 +1058,7 @@ static int __init apm821xx_pciex_core_init(struct device_node *np)
return 1;
}
static int apm821xx_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
static int __init apm821xx_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
{
u32 val;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册