Commit 3441f04b4b62758a798f9fbbf2047dfedf0329a5

Authored by Anton Blanchard
Committed by Benjamin Herrenschmidt
1 parent 14ad0c58d5

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>

Showing 4 changed files with 76 additions and 188 deletions Side-by-side Diff

arch/powerpc/include/asm/opal.h
... ... @@ -41,14 +41,14 @@
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,6 +928,10 @@
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  
arch/powerpc/platforms/powernv/opal-dump.c
... ... @@ -209,80 +209,6 @@
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;
289 215  
... ... @@ -314,15 +240,12 @@
314 240 }
315 241  
316 242 /* Generate SG list */
317   - list = dump_data_to_sglist(dump);
  243 + list = opal_vmalloc_to_sg_list(dump->buffer, dump->size);
318 244 if (!list) {
319 245 rc = -ENOMEM;
320 246 goto out;
321 247 }
322 248  
323   - /* Translate sg list addr to real address */
324   - sglist_to_phy_addr(list);
325   -
326 249 /* First entry address */
327 250 addr = __pa(list);
328 251  
... ... @@ -341,7 +264,7 @@
341 264 __func__, dump->id);
342 265  
343 266 /* Free SG list */
344   - free_dump_sg_list(list);
  267 + opal_free_sg_list(list);
345 268  
346 269 out:
347 270 return rc;
arch/powerpc/platforms/powernv/opal-flash.c
... ... @@ -79,9 +79,6 @@
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,
88 85  
... ... @@ -272,93 +269,11 @@
272 269 }
273 270  
274 271 /*
275   - * Free sg list
276   - */
277   -static void free_sg_list(struct opal_sg_list *list)
278   -{
279   - struct opal_sg_list *sg1;
280   - while (list) {
281   - sg1 = list->next;
282   - kfree(list);
283   - list = sg1;
284   - }
285   - list = NULL;
286   -}
287   -
288   -/*
289   - * Build candidate image scatter gather list
290   - *
291   - * list format:
292   - * -----------------------------------
293   - * | VER (8) | Entry length in bytes |
294   - * -----------------------------------
295   - * | Pointer to next entry |
296   - * -----------------------------------
297   - * | Address of memory area 1 |
298   - * -----------------------------------
299   - * | Length of memory area 1 |
300   - * -----------------------------------
301   - * | ......... |
302   - * -----------------------------------
303   - * | ......... |
304   - * -----------------------------------
305   - * | Address of memory area N |
306   - * -----------------------------------
307   - * | Length of memory area N |
308   - * -----------------------------------
309   - */
310   -static struct opal_sg_list *image_data_to_sglist(void)
311   -{
312   - struct opal_sg_list *sg1, *list = NULL;
313   - void *addr;
314   - int size;
315   -
316   - addr = image_data.data;
317   - size = image_data.size;
318   -
319   - sg1 = kzalloc(PAGE_SIZE, GFP_KERNEL);
320   - if (!sg1)
321   - return NULL;
322   -
323   - list = sg1;
324   - sg1->num_entries = 0;
325   - while (size > 0) {
326   - /* Translate virtual address to physical address */
327   - sg1->entry[sg1->num_entries].data =
328   - (void *)(vmalloc_to_pfn(addr) << PAGE_SHIFT);
329   -
330   - if (size > PAGE_SIZE)
331   - sg1->entry[sg1->num_entries].length = PAGE_SIZE;
332   - else
333   - sg1->entry[sg1->num_entries].length = size;
334   -
335   - sg1->num_entries++;
336   - if (sg1->num_entries >= SG_ENTRIES_PER_NODE) {
337   - sg1->next = kzalloc(PAGE_SIZE, GFP_KERNEL);
338   - if (!sg1->next) {
339   - pr_err("%s : Failed to allocate memory\n",
340   - __func__);
341   - goto nomem;
342   - }
343   -
344   - sg1 = sg1->next;
345   - sg1->num_entries = 0;
346   - }
347   - addr += PAGE_SIZE;
348   - size -= PAGE_SIZE;
349   - }
350   - return list;
351   -nomem:
352   - free_sg_list(list);
353   - return NULL;
354   -}
355   -
356   -/*
357 272 * OPAL update flash
358 273 */
359 274 static int opal_flash_update(int op)
360 275 {
361   - struct opal_sg_list *sg, *list, *next;
  276 + struct opal_sg_list *list;
362 277 unsigned long addr;
363 278 int64_t rc = OPAL_PARAMETER;
364 279  
365 280  
... ... @@ -368,29 +283,12 @@
368 283 goto flash;
369 284 }
370 285  
371   - list = image_data_to_sglist();
  286 + list = opal_vmalloc_to_sg_list(image_data.data, image_data.size);
372 287 if (!list)
373 288 goto invalid_img;
374 289  
375 290 /* First entry address */
376 291 addr = __pa(list);
377   -
378   - /* Translate sg list address to absolute */
379   - for (sg = list; sg; sg = next) {
380   - next = sg->next;
381   - /* Don't translate NULL pointer for last entry */
382   - if (sg->next)
383   - sg->next = (struct opal_sg_list *)__pa(sg->next);
384   - else
385   - sg->next = NULL;
386   -
387   - /*
388   - * Convert num_entries to version/length format
389   - * to satisfy OPAL.
390   - */
391   - sg->num_entries = (SG_LIST_VERSION << 56) |
392   - (sg->num_entries * sizeof(struct opal_sg_entry) + 16);
393   - }
394 292  
395 293 pr_alert("FLASH: Image is %u bytes\n", image_data.size);
396 294 pr_alert("FLASH: Image update requested\n");
arch/powerpc/platforms/powernv/opal.c
... ... @@ -638,4 +638,67 @@
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 +}