* [PATCH 2/6] powerpc/powernv: Remove some OPAL function declaration duplication
2014-04-22 5:01 [PATCH 1/6] powerpc/powernv: Use uint64_t instead of size_t in OPAL APIs Anton Blanchard
@ 2014-04-22 5:01 ` Anton Blanchard
2014-04-22 5:01 ` [PATCH 3/6] powerpc/powernv: Fix little endian issues with opal_do_notifier calls Anton Blanchard
` (3 subsequent siblings)
4 siblings, 0 replies; 12+ messages in thread
From: Anton Blanchard @ 2014-04-22 5:01 UTC (permalink / raw)
To: benh, paulus, hegdevasant, stewart; +Cc: linuxppc-dev
We had some duplication of the internal OPAL functions.
Signed-off-by: Anton Blanchard <anton@samba.org>
---
arch/powerpc/include/asm/opal.h | 12 ++----------
1 file changed, 2 insertions(+), 10 deletions(-)
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index 2a34485..cb7d52e 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -884,7 +884,8 @@ int64_t opal_set_param(uint64_t token, uint32_t param_id, uint64_t buffer,
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);
--
1.8.3.2
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 3/6] powerpc/powernv: Fix little endian issues with opal_do_notifier calls
2014-04-22 5:01 [PATCH 1/6] powerpc/powernv: Use uint64_t instead of size_t in OPAL APIs Anton Blanchard
2014-04-22 5:01 ` [PATCH 2/6] powerpc/powernv: Remove some OPAL function declaration duplication Anton Blanchard
@ 2014-04-22 5:01 ` Anton Blanchard
2014-04-22 5:01 ` [PATCH 4/6] powerpc/powernv: Fix little endian issues in OPAL error log code Anton Blanchard
` (2 subsequent siblings)
4 siblings, 0 replies; 12+ messages in thread
From: Anton Blanchard @ 2014-04-22 5:01 UTC (permalink / raw)
To: benh, paulus, hegdevasant, stewart; +Cc: linuxppc-dev
The bitmap in opal_poll_events and opal_handle_interrupt is
big endian, so we need to byteswap it on little endian builds.
Signed-off-by: Anton Blanchard <anton@samba.org>
---
arch/powerpc/platforms/powernv/opal.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index 49d2f00..17cfc70 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -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;
}
--
1.8.3.2
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 4/6] powerpc/powernv: Fix little endian issues in OPAL error log code
2014-04-22 5:01 [PATCH 1/6] powerpc/powernv: Use uint64_t instead of size_t in OPAL APIs Anton Blanchard
2014-04-22 5:01 ` [PATCH 2/6] powerpc/powernv: Remove some OPAL function declaration duplication Anton Blanchard
2014-04-22 5:01 ` [PATCH 3/6] powerpc/powernv: Fix little endian issues with opal_do_notifier calls Anton Blanchard
@ 2014-04-22 5:01 ` Anton Blanchard
2014-04-22 8:10 ` Vasant Hegde
2014-04-22 5:01 ` [PATCH 5/6] powerpc/powernv: Create OPAL sglist helper functions and fix endian issues Anton Blanchard
2014-04-22 5:01 ` [PATCH 6/6] powerpc/powernv: Fix little endian issues in OPAL dump code Anton Blanchard
4 siblings, 1 reply; 12+ messages in thread
From: Anton Blanchard @ 2014-04-22 5:01 UTC (permalink / raw)
To: benh, paulus, hegdevasant, stewart; +Cc: linuxppc-dev
Fix little endian issues with the OPAL error log code.
Signed-off-by: Anton Blanchard <anton@samba.org>
Reviewed-by: Stewart Smith <stewart@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/opal.h | 2 +-
arch/powerpc/platforms/powernv/opal-elog.c | 9 ++++++++-
2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index cb7d52e..1a752ac 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -859,7 +859,7 @@ 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, uint64_t size, uint64_t log_id);
-int64_t opal_get_elog_size(uint64_t *log_id, uint64_t *size, uint64_t *elog_type);
+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);
diff --git a/arch/powerpc/platforms/powernv/opal-elog.c b/arch/powerpc/platforms/powernv/opal-elog.c
index 7e3821e..10268c4 100644
--- a/arch/powerpc/platforms/powernv/opal-elog.c
+++ b/arch/powerpc/platforms/powernv/opal-elog.c
@@ -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)
{
+ __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)
--
1.8.3.2
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH 4/6] powerpc/powernv: Fix little endian issues in OPAL error log code
2014-04-22 5:01 ` [PATCH 4/6] powerpc/powernv: Fix little endian issues in OPAL error log code Anton Blanchard
@ 2014-04-22 8:10 ` Vasant Hegde
0 siblings, 0 replies; 12+ messages in thread
From: Vasant Hegde @ 2014-04-22 8:10 UTC (permalink / raw)
To: Anton Blanchard, benh, paulus, stewart; +Cc: linuxppc-dev
On 04/22/2014 10:31 AM, Anton Blanchard wrote:
> Fix little endian issues with the OPAL error log code.
>
> Signed-off-by: Anton Blanchard <anton@samba.org>
> Reviewed-by: Stewart Smith <stewart@linux.vnet.ibm.com>
> ---
> arch/powerpc/include/asm/opal.h | 2 +-
> arch/powerpc/platforms/powernv/opal-elog.c | 9 ++++++++-
> 2 files changed, 9 insertions(+), 2 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
> index cb7d52e..1a752ac 100644
> --- a/arch/powerpc/include/asm/opal.h
> +++ b/arch/powerpc/include/asm/opal.h
> @@ -859,7 +859,7 @@ 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, uint64_t size, uint64_t log_id);
> -int64_t opal_get_elog_size(uint64_t *log_id, uint64_t *size, uint64_t *elog_type);
> +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);
> diff --git a/arch/powerpc/platforms/powernv/opal-elog.c b/arch/powerpc/platforms/powernv/opal-elog.c
> index 7e3821e..10268c4 100644
> --- a/arch/powerpc/platforms/powernv/opal-elog.c
> +++ b/arch/powerpc/platforms/powernv/opal-elog.c
> @@ -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)
> {
> + __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);
Anton,
Shouldn't we covert Log ID back to BE format in ACK function (elog_ack_store() ) ?
Rest looks good.
-Vasant
> + elog_type = be64_to_cpu(type);
> +
> BUG_ON(elog_size > OPAL_MAX_ERRLOG_SIZE);
>
> if (elog_size >= OPAL_MAX_ERRLOG_SIZE)
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 5/6] powerpc/powernv: Create OPAL sglist helper functions and fix endian issues
2014-04-22 5:01 [PATCH 1/6] powerpc/powernv: Use uint64_t instead of size_t in OPAL APIs Anton Blanchard
` (2 preceding siblings ...)
2014-04-22 5:01 ` [PATCH 4/6] powerpc/powernv: Fix little endian issues in OPAL error log code Anton Blanchard
@ 2014-04-22 5:01 ` Anton Blanchard
2014-04-22 9:16 ` Vasant Hegde
2014-04-22 5:01 ` [PATCH 6/6] powerpc/powernv: Fix little endian issues in OPAL dump code Anton Blanchard
4 siblings, 1 reply; 12+ messages in thread
From: Anton Blanchard @ 2014-04-22 5:01 UTC (permalink / raw)
To: benh, paulus, hegdevasant, stewart; +Cc: linuxppc-dev
We have two copies of code that creates an OPAL sg list. Consolidate
these into a common set of helpers and fix the endian issues.
The flash interface embedded a version number in the num_entries
field, whereas the dump interface did did not. Since versioning
wasn't added to the flash interface and it is impossible to add
this in a backwards compatible way, just remove it.
Signed-off-by: Anton Blanchard <anton@samba.org>
---
arch/powerpc/include/asm/opal.h | 14 ++--
arch/powerpc/platforms/powernv/opal-dump.c | 81 +--------------------
arch/powerpc/platforms/powernv/opal-flash.c | 106 +---------------------------
arch/powerpc/platforms/powernv/opal.c | 63 +++++++++++++++++
4 files changed, 76 insertions(+), 188 deletions(-)
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index 1a752ac..afb0fed 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -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[];
};
@@ -929,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 */
diff --git a/arch/powerpc/platforms/powernv/opal-dump.c b/arch/powerpc/platforms/powernv/opal-dump.c
index b9827b0..f0b4724 100644
--- a/arch/powerpc/platforms/powernv/opal-dump.c
+++ b/arch/powerpc/platforms/powernv/opal-dump.c
@@ -209,80 +209,6 @@ 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)
{
int rc;
@@ -314,15 +240,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 +264,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;
diff --git a/arch/powerpc/platforms/powernv/opal-flash.c b/arch/powerpc/platforms/powernv/opal-flash.c
index 714ef97..0ae9e5f 100644
--- a/arch/powerpc/platforms/powernv/opal-flash.c
+++ b/arch/powerpc/platforms/powernv/opal-flash.c
@@ -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,
@@ -268,93 +265,11 @@ static ssize_t manage_store(struct kobject *kobj,
}
/*
- * 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 +279,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");
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index 17cfc70..360ad80c 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -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;
+ }
+}
--
1.8.3.2
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH 5/6] powerpc/powernv: Create OPAL sglist helper functions and fix endian issues
2014-04-22 5:01 ` [PATCH 5/6] powerpc/powernv: Create OPAL sglist helper functions and fix endian issues Anton Blanchard
@ 2014-04-22 9:16 ` Vasant Hegde
2014-04-22 21:34 ` Anton Blanchard
0 siblings, 1 reply; 12+ messages in thread
From: Vasant Hegde @ 2014-04-22 9:16 UTC (permalink / raw)
To: Anton Blanchard, benh, paulus, stewart; +Cc: linuxppc-dev
On 04/22/2014 10:31 AM, Anton Blanchard wrote:
> We have two copies of code that creates an OPAL sg list. Consolidate
> these into a common set of helpers and fix the endian issues.
>
> The flash interface embedded a version number in the num_entries
> field, whereas the dump interface did did not. Since versioning
> wasn't added to the flash interface and it is impossible to add
> this in a backwards compatible way, just remove it.
>
> Signed-off-by: Anton Blanchard <anton@samba.org>
> ---
> arch/powerpc/include/asm/opal.h | 14 ++--
> arch/powerpc/platforms/powernv/opal-dump.c | 81 +--------------------
> arch/powerpc/platforms/powernv/opal-flash.c | 106 +---------------------------
> arch/powerpc/platforms/powernv/opal.c | 63 +++++++++++++++++
> 4 files changed, 76 insertions(+), 188 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
> index 1a752ac..afb0fed 100644
> --- a/arch/powerpc/include/asm/opal.h
> +++ b/arch/powerpc/include/asm/opal.h
> @@ -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[];
> };
>
> @@ -929,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 */
> diff --git a/arch/powerpc/platforms/powernv/opal-dump.c b/arch/powerpc/platforms/powernv/opal-dump.c
> index b9827b0..f0b4724 100644
> --- a/arch/powerpc/platforms/powernv/opal-dump.c
> +++ b/arch/powerpc/platforms/powernv/opal-dump.c
> @@ -209,80 +209,6 @@ 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)
> {
> int rc;
> @@ -314,15 +240,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 +264,7 @@ static int64_t dump_read_data(struct dump_obj *dump)
> __func__, dump->id);
>
Shouldn't we convert addr and id before passing to opal_dump_read() here ?
> /* Free SG list */
> - free_dump_sg_list(list);
> + opal_free_sg_list(list);
>
> out:
> return rc;
> diff --git a/arch/powerpc/platforms/powernv/opal-flash.c b/arch/powerpc/platforms/powernv/opal-flash.c
> index 714ef97..0ae9e5f 100644
> --- a/arch/powerpc/platforms/powernv/opal-flash.c
> +++ b/arch/powerpc/platforms/powernv/opal-flash.c
> @@ -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,
> @@ -268,93 +265,11 @@ static ssize_t manage_store(struct kobject *kobj,
> }
>
> /*
> - * 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 +279,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");
> diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
> index 17cfc70..360ad80c 100644
> --- a/arch/powerpc/platforms/powernv/opal.c
> +++ b/arch/powerpc/platforms/powernv/opal.c
> @@ -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);
This for this fix..
-Vasant
> + else
> + sg = NULL;
> + }
> +}
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 5/6] powerpc/powernv: Create OPAL sglist helper functions and fix endian issues
2014-04-22 9:16 ` Vasant Hegde
@ 2014-04-22 21:34 ` Anton Blanchard
0 siblings, 0 replies; 12+ messages in thread
From: Anton Blanchard @ 2014-04-22 21:34 UTC (permalink / raw)
To: Vasant Hegde; +Cc: stewart, paulus, linuxppc-dev
Hi,
> Shouldn't we convert addr and id before passing to opal_dump_read()
> here ?
int64_t opal_dump_read(uint32_t dump_id, uint64_t buffer);
All arguments are passed via register, so byteswaping the arguments
would break it.
Anton
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 6/6] powerpc/powernv: Fix little endian issues in OPAL dump code
2014-04-22 5:01 [PATCH 1/6] powerpc/powernv: Use uint64_t instead of size_t in OPAL APIs Anton Blanchard
` (3 preceding siblings ...)
2014-04-22 5:01 ` [PATCH 5/6] powerpc/powernv: Create OPAL sglist helper functions and fix endian issues Anton Blanchard
@ 2014-04-22 5:01 ` Anton Blanchard
2014-04-22 8:32 ` Vasant Hegde
4 siblings, 1 reply; 12+ messages in thread
From: Anton Blanchard @ 2014-04-22 5:01 UTC (permalink / raw)
To: benh, paulus, hegdevasant, stewart; +Cc: linuxppc-dev
Signed-off-by: Anton Blanchard <anton@samba.org>
---
arch/powerpc/include/asm/opal.h | 4 ++--
arch/powerpc/platforms/powernv/opal-dump.c | 13 +++++++++----
2 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index afb0fed..66ad7a7 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -868,8 +868,8 @@ 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);
diff --git a/arch/powerpc/platforms/powernv/opal-dump.c b/arch/powerpc/platforms/powernv/opal-dump.c
index f0b4724..788a197 100644
--- a/arch/powerpc/platforms/powernv/opal-dump.c
+++ b/arch/powerpc/platforms/powernv/opal-dump.c
@@ -209,15 +209,20 @@ static struct kobj_type dump_ktype = {
.default_attrs = dump_default_attrs,
};
-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",
--
1.8.3.2
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH 6/6] powerpc/powernv: Fix little endian issues in OPAL dump code
2014-04-22 5:01 ` [PATCH 6/6] powerpc/powernv: Fix little endian issues in OPAL dump code Anton Blanchard
@ 2014-04-22 8:32 ` Vasant Hegde
2014-04-22 21:31 ` Anton Blanchard
0 siblings, 1 reply; 12+ messages in thread
From: Vasant Hegde @ 2014-04-22 8:32 UTC (permalink / raw)
To: Anton Blanchard, benh, paulus, stewart; +Cc: linuxppc-dev
On 04/22/2014 10:31 AM, Anton Blanchard wrote:
> Signed-off-by: Anton Blanchard <anton@samba.org>
> ---
> arch/powerpc/include/asm/opal.h | 4 ++--
> arch/powerpc/platforms/powernv/opal-dump.c | 13 +++++++++----
> 2 files changed, 11 insertions(+), 6 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
> index afb0fed..66ad7a7 100644
> --- a/arch/powerpc/include/asm/opal.h
> +++ b/arch/powerpc/include/asm/opal.h
> @@ -868,8 +868,8 @@ 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);
Shouldn't we change above two functions as well ?
> int64_t opal_dump_resend_notification(void);
> diff --git a/arch/powerpc/platforms/powernv/opal-dump.c b/arch/powerpc/platforms/powernv/opal-dump.c
> index f0b4724..788a197 100644
> --- a/arch/powerpc/platforms/powernv/opal-dump.c
> +++ b/arch/powerpc/platforms/powernv/opal-dump.c
> @@ -209,15 +209,20 @@ static struct kobj_type dump_ktype = {
> .default_attrs = dump_default_attrs,
> };
>
> -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);
>
Should we convert ID back to BE format in dump_send_ack() ?
-Vasant
> if (rc)
> pr_warn("%s: Failed to get dump info (%d)\n",
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 6/6] powerpc/powernv: Fix little endian issues in OPAL dump code
2014-04-22 8:32 ` Vasant Hegde
@ 2014-04-22 21:31 ` Anton Blanchard
2014-04-23 4:36 ` Vasant Hegde
0 siblings, 1 reply; 12+ messages in thread
From: Anton Blanchard @ 2014-04-22 21:31 UTC (permalink / raw)
To: Vasant Hegde; +Cc: stewart, paulus, linuxppc-dev
Hi,
> -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);
>
> Shouldn't we change above two functions as well ?
No, there are no endian issues here because we pass the values via
register. The only endian issues are for values we pass via pointer.
> Should we convert ID back to BE format in dump_send_ack() ?
Same as above.
Anton
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 6/6] powerpc/powernv: Fix little endian issues in OPAL dump code
2014-04-22 21:31 ` Anton Blanchard
@ 2014-04-23 4:36 ` Vasant Hegde
0 siblings, 0 replies; 12+ messages in thread
From: Vasant Hegde @ 2014-04-23 4:36 UTC (permalink / raw)
To: Anton Blanchard; +Cc: stewart, paulus, linuxppc-dev
On 04/23/2014 03:01 AM, Anton Blanchard wrote:
> Hi,
>
>> -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);
>>
>> Shouldn't we change above two functions as well ?
>
> No, there are no endian issues here because we pass the values via
> register. The only endian issues are for values we pass via pointer.
>
Anton,
Thanks for the clarification..
-Vasant
^ permalink raw reply [flat|nested] 12+ messages in thread