1/* SPDX-License-Identifier: GPL-2.0 */ 2#ifndef _ASM_POWERPC_PLPAR_WRAPPERS_H 3#define _ASM_POWERPC_PLPAR_WRAPPERS_H 4 5#ifdef CONFIG_PPC_PSERIES 6 7#include <linux/string.h> 8#include <linux/irqflags.h> 9 10#include <asm/hvcall.h> 11#include <asm/paca.h> 12#include <asm/lppaca.h> 13#include <asm/page.h> 14 15static inline long poll_pending(void) 16{ 17 return plpar_hcall_norets(H_POLL_PENDING); 18} 19 20static inline u8 get_cede_latency_hint(void) 21{ 22 return get_lppaca()->cede_latency_hint; 23} 24 25static inline void set_cede_latency_hint(u8 latency_hint) 26{ 27 get_lppaca()->cede_latency_hint = latency_hint; 28} 29 30static inline long cede_processor(void) 31{ 32 return plpar_hcall_norets(H_CEDE); 33} 34 35static inline long extended_cede_processor(unsigned long latency_hint) 36{ 37 long rc; 38 u8 old_latency_hint = get_cede_latency_hint(); 39 40 set_cede_latency_hint(latency_hint); 41 42 rc = cede_processor(); 43#ifdef CONFIG_PPC_IRQ_SOFT_MASK_DEBUG 44 /* Ensure that H_CEDE returns with IRQs on */ 45 if (WARN_ON(!(mfmsr() & MSR_EE))) 46 __hard_irq_enable(); 47#endif 48 49 set_cede_latency_hint(old_latency_hint); 50 51 return rc; 52} 53 54static inline long vpa_call(unsigned long flags, unsigned long cpu, 55 unsigned long vpa) 56{ 57 flags = flags << H_VPA_FUNC_SHIFT; 58 59 return plpar_hcall_norets(H_REGISTER_VPA, flags, cpu, vpa); 60} 61 62static inline long unregister_vpa(unsigned long cpu) 63{ 64 return vpa_call(H_VPA_DEREG_VPA, cpu, 0); 65} 66 67static inline long register_vpa(unsigned long cpu, unsigned long vpa) 68{ 69 return vpa_call(H_VPA_REG_VPA, cpu, vpa); 70} 71 72static inline long unregister_slb_shadow(unsigned long cpu) 73{ 74 return vpa_call(H_VPA_DEREG_SLB, cpu, 0); 75} 76 77static inline long register_slb_shadow(unsigned long cpu, unsigned long vpa) 78{ 79 return vpa_call(H_VPA_REG_SLB, cpu, vpa); 80} 81 82static inline long unregister_dtl(unsigned long cpu) 83{ 84 return vpa_call(H_VPA_DEREG_DTL, cpu, 0); 85} 86 87static inline long register_dtl(unsigned long cpu, unsigned long vpa) 88{ 89 return vpa_call(H_VPA_REG_DTL, cpu, vpa); 90} 91 92extern void vpa_init(int cpu); 93 94static inline long plpar_pte_enter(unsigned long flags, 95 unsigned long hpte_group, unsigned long hpte_v, 96 unsigned long hpte_r, unsigned long *slot) 97{ 98 long rc; 99 unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; 100 101 rc = plpar_hcall(H_ENTER, retbuf, flags, hpte_group, hpte_v, hpte_r); 102 103 *slot = retbuf[0]; 104 105 return rc; 106} 107 108static inline long plpar_pte_remove(unsigned long flags, unsigned long ptex, 109 unsigned long avpn, unsigned long *old_pteh_ret, 110 unsigned long *old_ptel_ret) 111{ 112 long rc; 113 unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; 114 115 rc = plpar_hcall(H_REMOVE, retbuf, flags, ptex, avpn); 116 117 *old_pteh_ret = retbuf[0]; 118 *old_ptel_ret = retbuf[1]; 119 120 return rc; 121} 122 123/* plpar_pte_remove_raw can be called in real mode. It calls plpar_hcall_raw */ 124static inline long plpar_pte_remove_raw(unsigned long flags, unsigned long ptex, 125 unsigned long avpn, unsigned long *old_pteh_ret, 126 unsigned long *old_ptel_ret) 127{ 128 long rc; 129 unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; 130 131 rc = plpar_hcall_raw(H_REMOVE, retbuf, flags, ptex, avpn); 132 133 *old_pteh_ret = retbuf[0]; 134 *old_ptel_ret = retbuf[1]; 135 136 return rc; 137} 138 139static inline long plpar_pte_read(unsigned long flags, unsigned long ptex, 140 unsigned long *old_pteh_ret, unsigned long *old_ptel_ret) 141{ 142 long rc; 143 unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; 144 145 rc = plpar_hcall(H_READ, retbuf, flags, ptex); 146 147 *old_pteh_ret = retbuf[0]; 148 *old_ptel_ret = retbuf[1]; 149 150 return rc; 151} 152 153/* plpar_pte_read_raw can be called in real mode. It calls plpar_hcall_raw */ 154static inline long plpar_pte_read_raw(unsigned long flags, unsigned long ptex, 155 unsigned long *old_pteh_ret, unsigned long *old_ptel_ret) 156{ 157 long rc; 158 unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; 159 160 rc = plpar_hcall_raw(H_READ, retbuf, flags, ptex); 161 162 *old_pteh_ret = retbuf[0]; 163 *old_ptel_ret = retbuf[1]; 164 165 return rc; 166} 167 168/* 169 * ptes must be 8*sizeof(unsigned long) 170 */ 171static inline long plpar_pte_read_4(unsigned long flags, unsigned long ptex, 172 unsigned long *ptes) 173 174{ 175 long rc; 176 unsigned long retbuf[PLPAR_HCALL9_BUFSIZE]; 177 178 rc = plpar_hcall9(H_READ, retbuf, flags | H_READ_4, ptex); 179 180 memcpy(ptes, retbuf, 8*sizeof(unsigned long)); 181 182 return rc; 183} 184 185/* 186 * plpar_pte_read_4_raw can be called in real mode. 187 * ptes must be 8*sizeof(unsigned long) 188 */ 189static inline long plpar_pte_read_4_raw(unsigned long flags, unsigned long ptex, 190 unsigned long *ptes) 191 192{ 193 long rc; 194 unsigned long retbuf[PLPAR_HCALL9_BUFSIZE]; 195 196 rc = plpar_hcall9_raw(H_READ, retbuf, flags | H_READ_4, ptex); 197 198 memcpy(ptes, retbuf, 8*sizeof(unsigned long)); 199 200 return rc; 201} 202 203static inline long plpar_pte_protect(unsigned long flags, unsigned long ptex, 204 unsigned long avpn) 205{ 206 return plpar_hcall_norets(H_PROTECT, flags, ptex, avpn); 207} 208 209static inline long plpar_resize_hpt_prepare(unsigned long flags, 210 unsigned long shift) 211{ 212 return plpar_hcall_norets(H_RESIZE_HPT_PREPARE, flags, shift); 213} 214 215static inline long plpar_resize_hpt_commit(unsigned long flags, 216 unsigned long shift) 217{ 218 return plpar_hcall_norets(H_RESIZE_HPT_COMMIT, flags, shift); 219} 220 221static inline long plpar_tce_get(unsigned long liobn, unsigned long ioba, 222 unsigned long *tce_ret) 223{ 224 long rc; 225 unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; 226 227 rc = plpar_hcall(H_GET_TCE, retbuf, liobn, ioba); 228 229 *tce_ret = retbuf[0]; 230 231 return rc; 232} 233 234static inline long plpar_tce_put(unsigned long liobn, unsigned long ioba, 235 unsigned long tceval) 236{ 237 return plpar_hcall_norets(H_PUT_TCE, liobn, ioba, tceval); 238} 239 240static inline long plpar_tce_put_indirect(unsigned long liobn, 241 unsigned long ioba, unsigned long page, unsigned long count) 242{ 243 return plpar_hcall_norets(H_PUT_TCE_INDIRECT, liobn, ioba, page, count); 244} 245 246static inline long plpar_tce_stuff(unsigned long liobn, unsigned long ioba, 247 unsigned long tceval, unsigned long count) 248{ 249 return plpar_hcall_norets(H_STUFF_TCE, liobn, ioba, tceval, count); 250} 251 252/* Set various resource mode parameters */ 253static inline long plpar_set_mode(unsigned long mflags, unsigned long resource, 254 unsigned long value1, unsigned long value2) 255{ 256 return plpar_hcall_norets(H_SET_MODE, mflags, resource, value1, value2); 257} 258 259/* 260 * Enable relocation on exceptions on this partition 261 * 262 * Note: this call has a partition wide scope and can take a while to complete. 263 * If it returns H_LONG_BUSY_* it should be retried periodically until it 264 * returns H_SUCCESS. 265 */ 266static inline long enable_reloc_on_exceptions(void) 267{ 268 /* mflags = 3: Exceptions at 0xC000000000004000 */ 269 return plpar_set_mode(3, H_SET_MODE_RESOURCE_ADDR_TRANS_MODE, 0, 0); 270} 271 272/* 273 * Disable relocation on exceptions on this partition 274 * 275 * Note: this call has a partition wide scope and can take a while to complete. 276 * If it returns H_LONG_BUSY_* it should be retried periodically until it 277 * returns H_SUCCESS. 278 */ 279static inline long disable_reloc_on_exceptions(void) { 280 return plpar_set_mode(0, H_SET_MODE_RESOURCE_ADDR_TRANS_MODE, 0, 0); 281} 282 283/* 284 * Take exceptions in big endian mode on this partition 285 * 286 * Note: this call has a partition wide scope and can take a while to complete. 287 * If it returns H_LONG_BUSY_* it should be retried periodically until it 288 * returns H_SUCCESS. 289 */ 290static inline long enable_big_endian_exceptions(void) 291{ 292 /* mflags = 0: big endian exceptions */ 293 return plpar_set_mode(0, H_SET_MODE_RESOURCE_LE, 0, 0); 294} 295 296/* 297 * Take exceptions in little endian mode on this partition 298 * 299 * Note: this call has a partition wide scope and can take a while to complete. 300 * If it returns H_LONG_BUSY_* it should be retried periodically until it 301 * returns H_SUCCESS. 302 */ 303static inline long enable_little_endian_exceptions(void) 304{ 305 /* mflags = 1: little endian exceptions */ 306 return plpar_set_mode(1, H_SET_MODE_RESOURCE_LE, 0, 0); 307} 308 309static inline long plpar_set_ciabr(unsigned long ciabr) 310{ 311 return plpar_set_mode(0, H_SET_MODE_RESOURCE_SET_CIABR, ciabr, 0); 312} 313 314static inline long plpar_set_watchpoint0(unsigned long dawr0, unsigned long dawrx0) 315{ 316 return plpar_set_mode(0, H_SET_MODE_RESOURCE_SET_DAWR0, dawr0, dawrx0); 317} 318 319static inline long plpar_set_watchpoint1(unsigned long dawr1, unsigned long dawrx1) 320{ 321 return plpar_set_mode(0, H_SET_MODE_RESOURCE_SET_DAWR1, dawr1, dawrx1); 322} 323 324static inline long plpar_signal_sys_reset(long cpu) 325{ 326 return plpar_hcall_norets(H_SIGNAL_SYS_RESET, cpu); 327} 328 329static inline long plpar_get_cpu_characteristics(struct h_cpu_char_result *p) 330{ 331 unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; 332 long rc; 333 334 rc = plpar_hcall(H_GET_CPU_CHARACTERISTICS, retbuf); 335 if (rc == H_SUCCESS) { 336 p->character = retbuf[0]; 337 p->behaviour = retbuf[1]; 338 } 339 340 return rc; 341} 342 343/* 344 * Wrapper to H_RPT_INVALIDATE hcall that handles return values appropriately 345 * 346 * - Returns H_SUCCESS on success 347 * - For H_BUSY return value, we retry the hcall. 348 * - For any other hcall failures, attempt a full flush once before 349 * resorting to BUG(). 350 * 351 * Note: This hcall is expected to fail only very rarely. The correct 352 * error recovery of killing the process/guest will be eventually 353 * needed. 354 */ 355static inline long pseries_rpt_invalidate(u32 pid, u64 target, u64 type, 356 u64 page_sizes, u64 start, u64 end) 357{ 358 long rc; 359 unsigned long all; 360 361 while (true) { 362 rc = plpar_hcall_norets(H_RPT_INVALIDATE, pid, target, type, 363 page_sizes, start, end); 364 if (rc == H_BUSY) { 365 cpu_relax(); 366 continue; 367 } else if (rc == H_SUCCESS) 368 return rc; 369 370 /* Flush request failed, try with a full flush once */ 371 if (type & H_RPTI_TYPE_NESTED) 372 all = H_RPTI_TYPE_NESTED | H_RPTI_TYPE_NESTED_ALL; 373 else 374 all = H_RPTI_TYPE_ALL; 375retry: 376 rc = plpar_hcall_norets(H_RPT_INVALIDATE, pid, target, 377 all, page_sizes, 0, -1UL); 378 if (rc == H_BUSY) { 379 cpu_relax(); 380 goto retry; 381 } else if (rc == H_SUCCESS) 382 return rc; 383 384 BUG(); 385 } 386} 387 388#else /* !CONFIG_PPC_PSERIES */ 389 390static inline long plpar_set_ciabr(unsigned long ciabr) 391{ 392 return 0; 393} 394 395static inline long plpar_pte_read_4(unsigned long flags, unsigned long ptex, 396 unsigned long *ptes) 397{ 398 return 0; 399} 400 401static inline long pseries_rpt_invalidate(u32 pid, u64 target, u64 type, 402 u64 page_sizes, u64 start, u64 end) 403{ 404 return 0; 405} 406 407#endif /* CONFIG_PPC_PSERIES */ 408 409#endif /* _ASM_POWERPC_PLPAR_WRAPPERS_H */ 410