Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Anton Blanchard and committed by
Benjamin Herrenschmidt
3441f04b 14ad0c58

+76 -188
+9 -5
arch/powerpc/include/asm/opal.h
··· 41 41 * size except the last one in the list to be as well. 42 42 */ 43 43 struct opal_sg_entry { 44 - void *data; 45 - long length; 44 + __be64 data; 45 + __be64 length; 46 46 }; 47 47 48 - /* sg list */ 48 + /* SG list */ 49 49 struct opal_sg_list { 50 - unsigned long num_entries; 51 - struct opal_sg_list *next; 50 + __be64 length; 51 + __be64 next; 52 52 struct opal_sg_entry entry[]; 53 53 }; 54 54 ··· 928 928 extern int opal_resync_timebase(void); 929 929 930 930 extern void opal_lpc_init(void); 931 + 932 + struct opal_sg_list *opal_vmalloc_to_sg_list(void *vmalloc_addr, 933 + unsigned long vmalloc_size); 934 + void opal_free_sg_list(struct opal_sg_list *sg); 931 935 932 936 #endif /* __ASSEMBLY__ */ 933 937
+2 -79
arch/powerpc/platforms/powernv/opal-dump.c
··· 209 209 .default_attrs = dump_default_attrs, 210 210 }; 211 211 212 - static void free_dump_sg_list(struct opal_sg_list *list) 213 - { 214 - struct opal_sg_list *sg1; 215 - while (list) { 216 - sg1 = list->next; 217 - kfree(list); 218 - list = sg1; 219 - } 220 - list = NULL; 221 - } 222 - 223 - static struct opal_sg_list *dump_data_to_sglist(struct dump_obj *dump) 224 - { 225 - struct opal_sg_list *sg1, *list = NULL; 226 - void *addr; 227 - int64_t size; 228 - 229 - addr = dump->buffer; 230 - size = dump->size; 231 - 232 - sg1 = kzalloc(PAGE_SIZE, GFP_KERNEL); 233 - if (!sg1) 234 - goto nomem; 235 - 236 - list = sg1; 237 - sg1->num_entries = 0; 238 - while (size > 0) { 239 - /* Translate virtual address to physical address */ 240 - sg1->entry[sg1->num_entries].data = 241 - (void *)(vmalloc_to_pfn(addr) << PAGE_SHIFT); 242 - 243 - if (size > PAGE_SIZE) 244 - sg1->entry[sg1->num_entries].length = PAGE_SIZE; 245 - else 246 - sg1->entry[sg1->num_entries].length = size; 247 - 248 - sg1->num_entries++; 249 - if (sg1->num_entries >= SG_ENTRIES_PER_NODE) { 250 - sg1->next = kzalloc(PAGE_SIZE, GFP_KERNEL); 251 - if (!sg1->next) 252 - goto nomem; 253 - 254 - sg1 = sg1->next; 255 - sg1->num_entries = 0; 256 - } 257 - addr += PAGE_SIZE; 258 - size -= PAGE_SIZE; 259 - } 260 - return list; 261 - 262 - nomem: 263 - pr_err("%s : Failed to allocate memory\n", __func__); 264 - free_dump_sg_list(list); 265 - return NULL; 266 - } 267 - 268 - static void sglist_to_phy_addr(struct opal_sg_list *list) 269 - { 270 - struct opal_sg_list *sg, *next; 271 - 272 - for (sg = list; sg; sg = next) { 273 - next = sg->next; 274 - /* Don't translate NULL pointer for last entry */ 275 - if (sg->next) 276 - sg->next = (struct opal_sg_list *)__pa(sg->next); 277 - else 278 - sg->next = NULL; 279 - 280 - /* Convert num_entries to length */ 281 - sg->num_entries = 282 - sg->num_entries * sizeof(struct opal_sg_entry) + 16; 283 - } 284 - } 285 - 286 212 static int64_t dump_read_info(uint32_t *id, uint32_t *size, uint32_t *type) 287 213 { 288 214 int rc; ··· 240 314 } 241 315 242 316 /* Generate SG list */ 243 - list = dump_data_to_sglist(dump); 317 + list = opal_vmalloc_to_sg_list(dump->buffer, dump->size); 244 318 if (!list) { 245 319 rc = -ENOMEM; 246 320 goto out; 247 321 } 248 - 249 - /* Translate sg list addr to real address */ 250 - sglist_to_phy_addr(list); 251 322 252 323 /* First entry address */ 253 324 addr = __pa(list); ··· 264 341 __func__, dump->id); 265 342 266 343 /* Free SG list */ 267 - free_dump_sg_list(list); 344 + opal_free_sg_list(list); 268 345 269 346 out: 270 347 return rc;
+2 -104
arch/powerpc/platforms/powernv/opal-flash.c
··· 79 79 /* XXX: Assume candidate image size is <= 1GB */ 80 80 #define MAX_IMAGE_SIZE 0x40000000 81 81 82 - /* Flash sg list version */ 83 - #define SG_LIST_VERSION (1UL) 84 - 85 82 /* Image status */ 86 83 enum { 87 84 IMAGE_INVALID, ··· 269 272 } 270 273 271 274 /* 272 - * Free sg list 273 - */ 274 - static void free_sg_list(struct opal_sg_list *list) 275 - { 276 - struct opal_sg_list *sg1; 277 - while (list) { 278 - sg1 = list->next; 279 - kfree(list); 280 - list = sg1; 281 - } 282 - list = NULL; 283 - } 284 - 285 - /* 286 - * Build candidate image scatter gather list 287 - * 288 - * list format: 289 - * ----------------------------------- 290 - * | VER (8) | Entry length in bytes | 291 - * ----------------------------------- 292 - * | Pointer to next entry | 293 - * ----------------------------------- 294 - * | Address of memory area 1 | 295 - * ----------------------------------- 296 - * | Length of memory area 1 | 297 - * ----------------------------------- 298 - * | ......... | 299 - * ----------------------------------- 300 - * | ......... | 301 - * ----------------------------------- 302 - * | Address of memory area N | 303 - * ----------------------------------- 304 - * | Length of memory area N | 305 - * ----------------------------------- 306 - */ 307 - static struct opal_sg_list *image_data_to_sglist(void) 308 - { 309 - struct opal_sg_list *sg1, *list = NULL; 310 - void *addr; 311 - int size; 312 - 313 - addr = image_data.data; 314 - size = image_data.size; 315 - 316 - sg1 = kzalloc(PAGE_SIZE, GFP_KERNEL); 317 - if (!sg1) 318 - return NULL; 319 - 320 - list = sg1; 321 - sg1->num_entries = 0; 322 - while (size > 0) { 323 - /* Translate virtual address to physical address */ 324 - sg1->entry[sg1->num_entries].data = 325 - (void *)(vmalloc_to_pfn(addr) << PAGE_SHIFT); 326 - 327 - if (size > PAGE_SIZE) 328 - sg1->entry[sg1->num_entries].length = PAGE_SIZE; 329 - else 330 - sg1->entry[sg1->num_entries].length = size; 331 - 332 - sg1->num_entries++; 333 - if (sg1->num_entries >= SG_ENTRIES_PER_NODE) { 334 - sg1->next = kzalloc(PAGE_SIZE, GFP_KERNEL); 335 - if (!sg1->next) { 336 - pr_err("%s : Failed to allocate memory\n", 337 - __func__); 338 - goto nomem; 339 - } 340 - 341 - sg1 = sg1->next; 342 - sg1->num_entries = 0; 343 - } 344 - addr += PAGE_SIZE; 345 - size -= PAGE_SIZE; 346 - } 347 - return list; 348 - nomem: 349 - free_sg_list(list); 350 - return NULL; 351 - } 352 - 353 - /* 354 275 * OPAL update flash 355 276 */ 356 277 static int opal_flash_update(int op) 357 278 { 358 - struct opal_sg_list *sg, *list, *next; 279 + struct opal_sg_list *list; 359 280 unsigned long addr; 360 281 int64_t rc = OPAL_PARAMETER; 361 282 ··· 283 368 goto flash; 284 369 } 285 370 286 - list = image_data_to_sglist(); 371 + list = opal_vmalloc_to_sg_list(image_data.data, image_data.size); 287 372 if (!list) 288 373 goto invalid_img; 289 374 290 375 /* First entry address */ 291 376 addr = __pa(list); 292 - 293 - /* Translate sg list address to absolute */ 294 - for (sg = list; sg; sg = next) { 295 - next = sg->next; 296 - /* Don't translate NULL pointer for last entry */ 297 - if (sg->next) 298 - sg->next = (struct opal_sg_list *)__pa(sg->next); 299 - else 300 - sg->next = NULL; 301 - 302 - /* 303 - * Convert num_entries to version/length format 304 - * to satisfy OPAL. 305 - */ 306 - sg->num_entries = (SG_LIST_VERSION << 56) | 307 - (sg->num_entries * sizeof(struct opal_sg_entry) + 16); 308 - } 309 377 310 378 pr_alert("FLASH: Image is %u bytes\n", image_data.size); 311 379 pr_alert("FLASH: Image update requested\n");
+63
arch/powerpc/platforms/powernv/opal.c
··· 638 638 639 639 /* Export this so that test modules can use it */ 640 640 EXPORT_SYMBOL_GPL(opal_invalid_call); 641 + 642 + /* Convert a region of vmalloc memory to an opal sg list */ 643 + struct opal_sg_list *opal_vmalloc_to_sg_list(void *vmalloc_addr, 644 + unsigned long vmalloc_size) 645 + { 646 + struct opal_sg_list *sg, *first = NULL; 647 + unsigned long i = 0; 648 + 649 + sg = kzalloc(PAGE_SIZE, GFP_KERNEL); 650 + if (!sg) 651 + goto nomem; 652 + 653 + first = sg; 654 + 655 + while (vmalloc_size > 0) { 656 + uint64_t data = vmalloc_to_pfn(vmalloc_addr) << PAGE_SHIFT; 657 + uint64_t length = min(vmalloc_size, PAGE_SIZE); 658 + 659 + sg->entry[i].data = cpu_to_be64(data); 660 + sg->entry[i].length = cpu_to_be64(length); 661 + i++; 662 + 663 + if (i >= SG_ENTRIES_PER_NODE) { 664 + struct opal_sg_list *next; 665 + 666 + next = kzalloc(PAGE_SIZE, GFP_KERNEL); 667 + if (!next) 668 + goto nomem; 669 + 670 + sg->length = cpu_to_be64( 671 + i * sizeof(struct opal_sg_entry) + 16); 672 + i = 0; 673 + sg->next = cpu_to_be64(__pa(next)); 674 + sg = next; 675 + } 676 + 677 + vmalloc_addr += length; 678 + vmalloc_size -= length; 679 + } 680 + 681 + sg->length = cpu_to_be64(i * sizeof(struct opal_sg_entry) + 16); 682 + 683 + return first; 684 + 685 + nomem: 686 + pr_err("%s : Failed to allocate memory\n", __func__); 687 + opal_free_sg_list(first); 688 + return NULL; 689 + } 690 + 691 + void opal_free_sg_list(struct opal_sg_list *sg) 692 + { 693 + while (sg) { 694 + uint64_t next = be64_to_cpu(sg->next); 695 + 696 + kfree(sg); 697 + 698 + if (next) 699 + sg = __va(next); 700 + else 701 + sg = NULL; 702 + } 703 + }