mirror of
https://github.com/fail0verflow/switch-linux.git
synced 2025-05-04 02:34:21 -04:00
powerpc/powernv: Create OPAL sglist helper functions and fix endian issues
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> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
This commit is contained in:
parent
14ad0c58d5
commit
3441f04b4b
4 changed files with 76 additions and 188 deletions
|
@ -41,14 +41,14 @@ struct opal_takeover_args {
|
||||||
* size except the last one in the list to be as well.
|
* size except the last one in the list to be as well.
|
||||||
*/
|
*/
|
||||||
struct opal_sg_entry {
|
struct opal_sg_entry {
|
||||||
void *data;
|
__be64 data;
|
||||||
long length;
|
__be64 length;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* sg list */
|
/* SG list */
|
||||||
struct opal_sg_list {
|
struct opal_sg_list {
|
||||||
unsigned long num_entries;
|
__be64 length;
|
||||||
struct opal_sg_list *next;
|
__be64 next;
|
||||||
struct opal_sg_entry entry[];
|
struct opal_sg_entry entry[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -929,6 +929,10 @@ extern int opal_resync_timebase(void);
|
||||||
|
|
||||||
extern void opal_lpc_init(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 /* __ASSEMBLY__ */
|
||||||
|
|
||||||
#endif /* __OPAL_H */
|
#endif /* __OPAL_H */
|
||||||
|
|
|
@ -209,80 +209,6 @@ static struct kobj_type dump_ktype = {
|
||||||
.default_attrs = dump_default_attrs,
|
.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 *id, uint32_t *size, uint32_t *type)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
@ -314,15 +240,12 @@ static int64_t dump_read_data(struct dump_obj *dump)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Generate SG list */
|
/* Generate SG list */
|
||||||
list = dump_data_to_sglist(dump);
|
list = opal_vmalloc_to_sg_list(dump->buffer, dump->size);
|
||||||
if (!list) {
|
if (!list) {
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Translate sg list addr to real address */
|
|
||||||
sglist_to_phy_addr(list);
|
|
||||||
|
|
||||||
/* First entry address */
|
/* First entry address */
|
||||||
addr = __pa(list);
|
addr = __pa(list);
|
||||||
|
|
||||||
|
@ -341,7 +264,7 @@ static int64_t dump_read_data(struct dump_obj *dump)
|
||||||
__func__, dump->id);
|
__func__, dump->id);
|
||||||
|
|
||||||
/* Free SG list */
|
/* Free SG list */
|
||||||
free_dump_sg_list(list);
|
opal_free_sg_list(list);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
return rc;
|
return rc;
|
||||||
|
|
|
@ -79,9 +79,6 @@
|
||||||
/* XXX: Assume candidate image size is <= 1GB */
|
/* XXX: Assume candidate image size is <= 1GB */
|
||||||
#define MAX_IMAGE_SIZE 0x40000000
|
#define MAX_IMAGE_SIZE 0x40000000
|
||||||
|
|
||||||
/* Flash sg list version */
|
|
||||||
#define SG_LIST_VERSION (1UL)
|
|
||||||
|
|
||||||
/* Image status */
|
/* Image status */
|
||||||
enum {
|
enum {
|
||||||
IMAGE_INVALID,
|
IMAGE_INVALID,
|
||||||
|
@ -271,94 +268,12 @@ static ssize_t manage_store(struct kobject *kobj,
|
||||||
return count;
|
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
|
* OPAL update flash
|
||||||
*/
|
*/
|
||||||
static int opal_flash_update(int op)
|
static int opal_flash_update(int op)
|
||||||
{
|
{
|
||||||
struct opal_sg_list *sg, *list, *next;
|
struct opal_sg_list *list;
|
||||||
unsigned long addr;
|
unsigned long addr;
|
||||||
int64_t rc = OPAL_PARAMETER;
|
int64_t rc = OPAL_PARAMETER;
|
||||||
|
|
||||||
|
@ -368,30 +283,13 @@ static int opal_flash_update(int op)
|
||||||
goto flash;
|
goto flash;
|
||||||
}
|
}
|
||||||
|
|
||||||
list = image_data_to_sglist();
|
list = opal_vmalloc_to_sg_list(image_data.data, image_data.size);
|
||||||
if (!list)
|
if (!list)
|
||||||
goto invalid_img;
|
goto invalid_img;
|
||||||
|
|
||||||
/* First entry address */
|
/* First entry address */
|
||||||
addr = __pa(list);
|
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 is %u bytes\n", image_data.size);
|
||||||
pr_alert("FLASH: Image update requested\n");
|
pr_alert("FLASH: Image update requested\n");
|
||||||
pr_alert("FLASH: Image will be updated during system reboot\n");
|
pr_alert("FLASH: Image will be updated during system reboot\n");
|
||||||
|
|
|
@ -638,3 +638,66 @@ void opal_shutdown(void)
|
||||||
|
|
||||||
/* Export this so that test modules can use it */
|
/* Export this so that test modules can use it */
|
||||||
EXPORT_SYMBOL_GPL(opal_invalid_call);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue