Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  paravirt.h   Sprache: C

 
/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef _ASM_POWERPC_PARAVIRT_H
#define _ASM_POWERPC_PARAVIRT_H

#include <linux/jump_label.h>
#include <asm/smp.h>
#ifdef CONFIG_PPC64
#include <asm/paca.h>
#include <asm/lppaca.h>
#include <asm/hvcall.h>
#endif

#ifdef CONFIG_PPC_SPLPAR
#include <linux/smp.h>
#include <asm/kvm_guest.h>
#include <asm/cputhreads.h>

DECLARE_STATIC_KEY_FALSE(shared_processor);

static inline bool is_shared_processor(void)
{
 return static_branch_unlikely(&shared_processor);
}

#ifdef CONFIG_PARAVIRT_TIME_ACCOUNTING
extern struct static_key paravirt_steal_enabled;
extern struct static_key paravirt_steal_rq_enabled;

u64 pseries_paravirt_steal_clock(int cpu);

static inline u64 paravirt_steal_clock(int cpu)
{
 return pseries_paravirt_steal_clock(cpu);
}
#endif

/* If bit 0 is set, the cpu has been ceded, conferred, or preempted */
static inline u32 yield_count_of(int cpu)
{
 __be32 yield_count = READ_ONCE(lppaca_of(cpu).yield_count);
 return be32_to_cpu(yield_count);
}

/*
 * Spinlock code confers and prods, so don't trace the hcalls because the
 * tracing code takes spinlocks which can cause recursion deadlocks.
 *
 * These calls are made while the lock is not held: the lock slowpath yields if
 * it can not acquire the lock, and unlock slow path might prod if a waiter has
 * yielded). So this may not be a problem for simple spin locks because the
 * tracing does not technically recurse on the lock, but we avoid it anyway.
 *
 * However the queued spin lock contended path is more strictly ordered: the
 * H_CONFER hcall is made after the task has queued itself on the lock, so then
 * recursing on that lock will cause the task to then queue up again behind the
 * first instance (or worse: queued spinlocks use tricks that assume a context
 * never waits on more than one spinlock, so such recursion may cause random
 * corruption in the lock code).
 */

static inline void yield_to_preempted(int cpu, u32 yield_count)
{
 plpar_hcall_norets_notrace(H_CONFER, get_hard_smp_processor_id(cpu), yield_count);
}

static inline void prod_cpu(int cpu)
{
 plpar_hcall_norets_notrace(H_PROD, get_hard_smp_processor_id(cpu));
}

static inline void yield_to_any(void)
{
 plpar_hcall_norets_notrace(H_CONFER, -1, 0);
}

static inline bool is_vcpu_idle(int vcpu)
{
 return lppaca_of(vcpu).idle;
}

static inline bool vcpu_is_dispatched(int vcpu)
{
 /*
 * This is the yield_count.  An "odd" value (low bit on) means that
 * the processor is yielded (either because of an OS yield or a
 * hypervisor preempt).  An even value implies that the processor is
 * currently executing.
 */

 return (!(yield_count_of(vcpu) & 1));
}
#else
static inline bool is_shared_processor(void)
{
 return false;
}

static inline u32 yield_count_of(int cpu)
{
 return 0;
}

extern void ___bad_yield_to_preempted(void);
static inline void yield_to_preempted(int cpu, u32 yield_count)
{
 ___bad_yield_to_preempted(); /* This would be a bug */
}

extern void ___bad_yield_to_any(void);
static inline void yield_to_any(void)
{
 ___bad_yield_to_any(); /* This would be a bug */
}

extern void ___bad_prod_cpu(void);
static inline void prod_cpu(int cpu)
{
 ___bad_prod_cpu(); /* This would be a bug */
}

static inline bool is_vcpu_idle(int vcpu)
{
 return false;
}
static inline bool vcpu_is_dispatched(int vcpu)
{
 return true;
}
#endif

#define vcpu_is_preempted vcpu_is_preempted
static inline bool vcpu_is_preempted(int cpu)
{
 /*
 * The dispatch/yield bit alone is an imperfect indicator of
 * whether the hypervisor has dispatched @cpu to run on a physical
 * processor. When it is clear, @cpu is definitely not preempted.
 * But when it is set, it means only that it *might* be, subject to
 * other conditions. So we check other properties of the VM and
 * @cpu first, resorting to the yield count last.
 */


 /*
 * Hypervisor preemption isn't possible in dedicated processor
 * mode by definition.
 */

 if (!is_shared_processor())
  return false;

 /*
 * If the hypervisor has dispatched the target CPU on a physical
 * processor, then the target CPU is definitely not preempted.
 */

 if (vcpu_is_dispatched(cpu))
  return false;

 /*
 * if the target CPU is not dispatched and the guest OS
 * has not marked the CPU idle, then it is hypervisor preempted.
 */

 if (!is_vcpu_idle(cpu))
  return true;

#ifdef CONFIG_PPC_SPLPAR
 if (!is_kvm_guest()) {
  int first_cpu, i;

  /*
 * The result of vcpu_is_preempted() is used in a
 * speculative way, and is always subject to invalidation
 * by events internal and external to Linux. While we can
 * be called in preemptable context (in the Linux sense),
 * we're not accessing per-cpu resources in a way that can
 * race destructively with Linux scheduler preemption and
 * migration, and callers can tolerate the potential for
 * error introduced by sampling the CPU index without
 * pinning the task to it. So it is permissible to use
 * raw_smp_processor_id() here to defeat the preempt debug
 * warnings that can arise from using smp_processor_id()
 * in arbitrary contexts.
 */

  first_cpu = cpu_first_thread_sibling(raw_smp_processor_id());

  /*
 * The PowerVM hypervisor dispatches VMs on a whole core
 * basis. So we know that a thread sibling of the executing CPU
 * cannot have been preempted by the hypervisor, even if it
 * has called H_CONFER, which will set the yield bit.
 */

  if (cpu_first_thread_sibling(cpu) == first_cpu)
   return false;

  /*
 * The specific target CPU was marked by guest OS as idle, but
 * then also check all other cpus in the core for PowerVM
 * because it does core scheduling and one of the vcpu
 * of the core getting preempted by hypervisor implies
 * other vcpus can also be considered preempted.
 */

  first_cpu = cpu_first_thread_sibling(cpu);
  for (i = first_cpu; i < first_cpu + threads_per_core; i++) {
   if (i == cpu)
    continue;
   if (vcpu_is_dispatched(i))
    return false;
   if (!is_vcpu_idle(i))
    return true;
  }
 }
#endif

 /*
 * None of the threads in target CPU's core are running but none of
 * them were preempted too. Hence assume the target CPU to be
 * non-preempted.
 */

 return false;
}

static inline bool pv_is_native_spin_unlock(void)
{
 return !is_shared_processor();
}

#endif /* _ASM_POWERPC_PARAVIRT_H */

Messung V0.5
C=93 H=92 G=92

¤ Dauer der Verarbeitung: 0.9 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge