18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * drmem.h: Power specific logical memory block representation
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright 2017 IBM Corporation
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#ifndef _ASM_POWERPC_LMB_H
98c2ecf20Sopenharmony_ci#define _ASM_POWERPC_LMB_H
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/sched.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_cistruct drmem_lmb {
148c2ecf20Sopenharmony_ci	u64     base_addr;
158c2ecf20Sopenharmony_ci	u32     drc_index;
168c2ecf20Sopenharmony_ci	u32     aa_index;
178c2ecf20Sopenharmony_ci	u32     flags;
188c2ecf20Sopenharmony_ci};
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistruct drmem_lmb_info {
218c2ecf20Sopenharmony_ci	struct drmem_lmb        *lmbs;
228c2ecf20Sopenharmony_ci	int                     n_lmbs;
238c2ecf20Sopenharmony_ci	u64                     lmb_size;
248c2ecf20Sopenharmony_ci};
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ciextern struct drmem_lmb_info *drmem_info;
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistatic inline struct drmem_lmb *drmem_lmb_next(struct drmem_lmb *lmb,
298c2ecf20Sopenharmony_ci					       const struct drmem_lmb *start)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci	/*
328c2ecf20Sopenharmony_ci	 * DLPAR code paths can take several milliseconds per element
338c2ecf20Sopenharmony_ci	 * when interacting with firmware. Ensure that we don't
348c2ecf20Sopenharmony_ci	 * unfairly monopolize the CPU.
358c2ecf20Sopenharmony_ci	 */
368c2ecf20Sopenharmony_ci	if (((++lmb - start) % 16) == 0)
378c2ecf20Sopenharmony_ci		cond_resched();
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	return lmb;
408c2ecf20Sopenharmony_ci}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci#define for_each_drmem_lmb_in_range(lmb, start, end)		\
438c2ecf20Sopenharmony_ci	for ((lmb) = (start); (lmb) < (end); lmb = drmem_lmb_next(lmb, start))
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci#define for_each_drmem_lmb(lmb)					\
468c2ecf20Sopenharmony_ci	for_each_drmem_lmb_in_range((lmb),			\
478c2ecf20Sopenharmony_ci		&drmem_info->lmbs[0],				\
488c2ecf20Sopenharmony_ci		&drmem_info->lmbs[drmem_info->n_lmbs])
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci/*
518c2ecf20Sopenharmony_ci * The of_drconf_cell_v1 struct defines the layout of the LMB data
528c2ecf20Sopenharmony_ci * specified in the ibm,dynamic-memory device tree property.
538c2ecf20Sopenharmony_ci * The property itself is a 32-bit value specifying the number of
548c2ecf20Sopenharmony_ci * LMBs followed by an array of of_drconf_cell_v1 entries, one
558c2ecf20Sopenharmony_ci * per LMB.
568c2ecf20Sopenharmony_ci */
578c2ecf20Sopenharmony_cistruct of_drconf_cell_v1 {
588c2ecf20Sopenharmony_ci	__be64	base_addr;
598c2ecf20Sopenharmony_ci	__be32	drc_index;
608c2ecf20Sopenharmony_ci	__be32	reserved;
618c2ecf20Sopenharmony_ci	__be32	aa_index;
628c2ecf20Sopenharmony_ci	__be32	flags;
638c2ecf20Sopenharmony_ci};
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci/*
668c2ecf20Sopenharmony_ci * Version 2 of the ibm,dynamic-memory property is defined as a
678c2ecf20Sopenharmony_ci * 32-bit value specifying the number of LMB sets followed by an
688c2ecf20Sopenharmony_ci * array of of_drconf_cell_v2 entries, one per LMB set.
698c2ecf20Sopenharmony_ci */
708c2ecf20Sopenharmony_cistruct of_drconf_cell_v2 {
718c2ecf20Sopenharmony_ci	u32	seq_lmbs;
728c2ecf20Sopenharmony_ci	u64	base_addr;
738c2ecf20Sopenharmony_ci	u32	drc_index;
748c2ecf20Sopenharmony_ci	u32	aa_index;
758c2ecf20Sopenharmony_ci	u32	flags;
768c2ecf20Sopenharmony_ci} __packed;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci#define DRCONF_MEM_ASSIGNED	0x00000008
798c2ecf20Sopenharmony_ci#define DRCONF_MEM_AI_INVALID	0x00000040
808c2ecf20Sopenharmony_ci#define DRCONF_MEM_RESERVED	0x00000080
818c2ecf20Sopenharmony_ci#define DRCONF_MEM_HOTREMOVABLE	0x00000100
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_cistatic inline u64 drmem_lmb_size(void)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	return drmem_info->lmb_size;
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci#define DRMEM_LMB_RESERVED	0x80000000
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic inline void drmem_mark_lmb_reserved(struct drmem_lmb *lmb)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	lmb->flags |= DRMEM_LMB_RESERVED;
938c2ecf20Sopenharmony_ci}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_cistatic inline void drmem_remove_lmb_reservation(struct drmem_lmb *lmb)
968c2ecf20Sopenharmony_ci{
978c2ecf20Sopenharmony_ci	lmb->flags &= ~DRMEM_LMB_RESERVED;
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_cistatic inline bool drmem_lmb_reserved(struct drmem_lmb *lmb)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	return lmb->flags & DRMEM_LMB_RESERVED;
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ciu64 drmem_lmb_memory_max(void);
1068c2ecf20Sopenharmony_ciint walk_drmem_lmbs(struct device_node *dn, void *data,
1078c2ecf20Sopenharmony_ci		    int (*func)(struct drmem_lmb *, const __be32 **, void *));
1088c2ecf20Sopenharmony_ciint drmem_update_dt(void);
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_PSERIES
1118c2ecf20Sopenharmony_ciint __init
1128c2ecf20Sopenharmony_ciwalk_drmem_lmbs_early(unsigned long node, void *data,
1138c2ecf20Sopenharmony_ci		      int (*func)(struct drmem_lmb *, const __be32 **, void *));
1148c2ecf20Sopenharmony_ci#endif
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cistatic inline void invalidate_lmb_associativity_index(struct drmem_lmb *lmb)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	lmb->aa_index = 0xffffffff;
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci#endif /* _ASM_POWERPC_LMB_H */
122