| /* SPDX-License-Identifier: GPL-2.0-or-later */ |
| /* |
| * drmem.h: Power specific logical memory block representation |
| * |
| * Copyright 2017 IBM Corporation |
| */ |
| |
| #ifndef _ASM_POWERPC_LMB_H |
| #define _ASM_POWERPC_LMB_H |
| |
| #include <linux/sched.h> |
| |
| struct drmem_lmb { |
| u64 base_addr; |
| u32 drc_index; |
| u32 aa_index; |
| u32 flags; |
| }; |
| |
| struct drmem_lmb_info { |
| struct drmem_lmb *lmbs; |
| int n_lmbs; |
| u64 lmb_size; |
| }; |
| |
| extern struct drmem_lmb_info *drmem_info; |
| |
| static inline struct drmem_lmb *drmem_lmb_next(struct drmem_lmb *lmb, |
| const struct drmem_lmb *start) |
| { |
| /* |
| * DLPAR code paths can take several milliseconds per element |
| * when interacting with firmware. Ensure that we don't |
| * unfairly monopolize the CPU. |
| */ |
| if (((++lmb - start) % 16) == 0) |
| cond_resched(); |
| |
| return lmb; |
| } |
| |
| #define for_each_drmem_lmb_in_range(lmb, start, end) \ |
| for ((lmb) = (start); (lmb) < (end); lmb = drmem_lmb_next(lmb, start)) |
| |
| #define for_each_drmem_lmb(lmb) \ |
| for_each_drmem_lmb_in_range((lmb), \ |
| &drmem_info->lmbs[0], \ |
| &drmem_info->lmbs[drmem_info->n_lmbs]) |
| |
| /* |
| * The of_drconf_cell_v1 struct defines the layout of the LMB data |
| * specified in the ibm,dynamic-memory device tree property. |
| * The property itself is a 32-bit value specifying the number of |
| * LMBs followed by an array of of_drconf_cell_v1 entries, one |
| * per LMB. |
| */ |
| struct of_drconf_cell_v1 { |
| __be64 base_addr; |
| __be32 drc_index; |
| __be32 reserved; |
| __be32 aa_index; |
| __be32 flags; |
| }; |
| |
| /* |
| * Version 2 of the ibm,dynamic-memory property is defined as a |
| * 32-bit value specifying the number of LMB sets followed by an |
| * array of of_drconf_cell_v2 entries, one per LMB set. |
| */ |
| struct of_drconf_cell_v2 { |
| u32 seq_lmbs; |
| u64 base_addr; |
| u32 drc_index; |
| u32 aa_index; |
| u32 flags; |
| } __packed; |
| |
| #define DRCONF_MEM_ASSIGNED 0x00000008 |
| #define DRCONF_MEM_AI_INVALID 0x00000040 |
| #define DRCONF_MEM_RESERVED 0x00000080 |
| #define DRCONF_MEM_HOTREMOVABLE 0x00000100 |
| |
| static inline u64 drmem_lmb_size(void) |
| { |
| return drmem_info->lmb_size; |
| } |
| |
| #define DRMEM_LMB_RESERVED 0x80000000 |
| |
| static inline void drmem_mark_lmb_reserved(struct drmem_lmb *lmb) |
| { |
| lmb->flags |= DRMEM_LMB_RESERVED; |
| } |
| |
| static inline void drmem_remove_lmb_reservation(struct drmem_lmb *lmb) |
| { |
| lmb->flags &= ~DRMEM_LMB_RESERVED; |
| } |
| |
| static inline bool drmem_lmb_reserved(struct drmem_lmb *lmb) |
| { |
| return lmb->flags & DRMEM_LMB_RESERVED; |
| } |
| |
| u64 drmem_lmb_memory_max(void); |
| int walk_drmem_lmbs(struct device_node *dn, void *data, |
| int (*func)(struct drmem_lmb *, const __be32 **, void *)); |
| int drmem_update_dt(void); |
| |
| #ifdef CONFIG_PPC_PSERIES |
| int __init |
| walk_drmem_lmbs_early(unsigned long node, void *data, |
| int (*func)(struct drmem_lmb *, const __be32 **, void *)); |
| #endif |
| |
| static inline void invalidate_lmb_associativity_index(struct drmem_lmb *lmb) |
| { |
| lmb->aa_index = 0xffffffff; |
| } |
| |
| #endif /* _ASM_POWERPC_LMB_H */ |