David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ |
Andrew Scull | b4b6d4a | 2019-01-02 15:54:55 +0000 | [diff] [blame] | 2 | /* |
| 3 | * drmem.h: Power specific logical memory block representation |
| 4 | * |
| 5 | * Copyright 2017 IBM Corporation |
Andrew Scull | b4b6d4a | 2019-01-02 15:54:55 +0000 | [diff] [blame] | 6 | */ |
| 7 | |
| 8 | #ifndef _ASM_POWERPC_LMB_H |
| 9 | #define _ASM_POWERPC_LMB_H |
| 10 | |
Olivier Deprez | 0e64123 | 2021-09-23 10:07:05 +0200 | [diff] [blame] | 11 | #include <linux/sched.h> |
| 12 | |
Andrew Scull | b4b6d4a | 2019-01-02 15:54:55 +0000 | [diff] [blame] | 13 | struct drmem_lmb { |
| 14 | u64 base_addr; |
| 15 | u32 drc_index; |
| 16 | u32 aa_index; |
| 17 | u32 flags; |
| 18 | }; |
| 19 | |
| 20 | struct drmem_lmb_info { |
| 21 | struct drmem_lmb *lmbs; |
| 22 | int n_lmbs; |
Olivier Deprez | 0e64123 | 2021-09-23 10:07:05 +0200 | [diff] [blame] | 23 | u64 lmb_size; |
Andrew Scull | b4b6d4a | 2019-01-02 15:54:55 +0000 | [diff] [blame] | 24 | }; |
| 25 | |
| 26 | extern struct drmem_lmb_info *drmem_info; |
| 27 | |
Olivier Deprez | 0e64123 | 2021-09-23 10:07:05 +0200 | [diff] [blame] | 28 | static inline struct drmem_lmb *drmem_lmb_next(struct drmem_lmb *lmb, |
| 29 | const struct drmem_lmb *start) |
| 30 | { |
| 31 | /* |
| 32 | * DLPAR code paths can take several milliseconds per element |
| 33 | * when interacting with firmware. Ensure that we don't |
| 34 | * unfairly monopolize the CPU. |
| 35 | */ |
| 36 | if (((++lmb - start) % 16) == 0) |
| 37 | cond_resched(); |
| 38 | |
| 39 | return lmb; |
| 40 | } |
| 41 | |
Andrew Scull | b4b6d4a | 2019-01-02 15:54:55 +0000 | [diff] [blame] | 42 | #define for_each_drmem_lmb_in_range(lmb, start, end) \ |
Olivier Deprez | 0e64123 | 2021-09-23 10:07:05 +0200 | [diff] [blame] | 43 | for ((lmb) = (start); (lmb) < (end); lmb = drmem_lmb_next(lmb, start)) |
Andrew Scull | b4b6d4a | 2019-01-02 15:54:55 +0000 | [diff] [blame] | 44 | |
| 45 | #define for_each_drmem_lmb(lmb) \ |
| 46 | for_each_drmem_lmb_in_range((lmb), \ |
| 47 | &drmem_info->lmbs[0], \ |
Olivier Deprez | 0e64123 | 2021-09-23 10:07:05 +0200 | [diff] [blame] | 48 | &drmem_info->lmbs[drmem_info->n_lmbs]) |
Andrew Scull | b4b6d4a | 2019-01-02 15:54:55 +0000 | [diff] [blame] | 49 | |
| 50 | /* |
| 51 | * The of_drconf_cell_v1 struct defines the layout of the LMB data |
| 52 | * specified in the ibm,dynamic-memory device tree property. |
| 53 | * The property itself is a 32-bit value specifying the number of |
| 54 | * LMBs followed by an array of of_drconf_cell_v1 entries, one |
| 55 | * per LMB. |
| 56 | */ |
| 57 | struct of_drconf_cell_v1 { |
| 58 | __be64 base_addr; |
| 59 | __be32 drc_index; |
| 60 | __be32 reserved; |
| 61 | __be32 aa_index; |
| 62 | __be32 flags; |
| 63 | }; |
| 64 | |
| 65 | /* |
| 66 | * Version 2 of the ibm,dynamic-memory property is defined as a |
| 67 | * 32-bit value specifying the number of LMB sets followed by an |
| 68 | * array of of_drconf_cell_v2 entries, one per LMB set. |
| 69 | */ |
| 70 | struct of_drconf_cell_v2 { |
| 71 | u32 seq_lmbs; |
| 72 | u64 base_addr; |
| 73 | u32 drc_index; |
| 74 | u32 aa_index; |
| 75 | u32 flags; |
| 76 | } __packed; |
| 77 | |
| 78 | #define DRCONF_MEM_ASSIGNED 0x00000008 |
| 79 | #define DRCONF_MEM_AI_INVALID 0x00000040 |
| 80 | #define DRCONF_MEM_RESERVED 0x00000080 |
Olivier Deprez | 157378f | 2022-04-04 15:47:50 +0200 | [diff] [blame^] | 81 | #define DRCONF_MEM_HOTREMOVABLE 0x00000100 |
Andrew Scull | b4b6d4a | 2019-01-02 15:54:55 +0000 | [diff] [blame] | 82 | |
Olivier Deprez | 0e64123 | 2021-09-23 10:07:05 +0200 | [diff] [blame] | 83 | static inline u64 drmem_lmb_size(void) |
Andrew Scull | b4b6d4a | 2019-01-02 15:54:55 +0000 | [diff] [blame] | 84 | { |
| 85 | return drmem_info->lmb_size; |
| 86 | } |
| 87 | |
| 88 | #define DRMEM_LMB_RESERVED 0x80000000 |
| 89 | |
| 90 | static inline void drmem_mark_lmb_reserved(struct drmem_lmb *lmb) |
| 91 | { |
| 92 | lmb->flags |= DRMEM_LMB_RESERVED; |
| 93 | } |
| 94 | |
| 95 | static inline void drmem_remove_lmb_reservation(struct drmem_lmb *lmb) |
| 96 | { |
| 97 | lmb->flags &= ~DRMEM_LMB_RESERVED; |
| 98 | } |
| 99 | |
| 100 | static inline bool drmem_lmb_reserved(struct drmem_lmb *lmb) |
| 101 | { |
| 102 | return lmb->flags & DRMEM_LMB_RESERVED; |
| 103 | } |
| 104 | |
| 105 | u64 drmem_lmb_memory_max(void); |
Olivier Deprez | 157378f | 2022-04-04 15:47:50 +0200 | [diff] [blame^] | 106 | int walk_drmem_lmbs(struct device_node *dn, void *data, |
| 107 | int (*func)(struct drmem_lmb *, const __be32 **, void *)); |
Andrew Scull | b4b6d4a | 2019-01-02 15:54:55 +0000 | [diff] [blame] | 108 | int drmem_update_dt(void); |
| 109 | |
| 110 | #ifdef CONFIG_PPC_PSERIES |
Olivier Deprez | 157378f | 2022-04-04 15:47:50 +0200 | [diff] [blame^] | 111 | int __init |
| 112 | walk_drmem_lmbs_early(unsigned long node, void *data, |
| 113 | int (*func)(struct drmem_lmb *, const __be32 **, void *)); |
Andrew Scull | b4b6d4a | 2019-01-02 15:54:55 +0000 | [diff] [blame] | 114 | #endif |
| 115 | |
David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame] | 116 | static inline void invalidate_lmb_associativity_index(struct drmem_lmb *lmb) |
| 117 | { |
| 118 | lmb->aa_index = 0xffffffff; |
| 119 | } |
| 120 | |
Andrew Scull | b4b6d4a | 2019-01-02 15:54:55 +0000 | [diff] [blame] | 121 | #endif /* _ASM_POWERPC_LMB_H */ |