X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=lib%2Feal%2Fx86%2Frte_power_intrinsics.c;h=f749da9b851ac84089be9839a7ea13168fee5def;hb=a1978aa23bf4a8dd34087173f7769250d050315e;hp=39ea9fdecdafe7ffe77391abb659c7a80691c637;hpb=99a2dd955fba6e4cc23b77d590a033650ced9c45;p=dpdk.git diff --git a/lib/eal/x86/rte_power_intrinsics.c b/lib/eal/x86/rte_power_intrinsics.c index 39ea9fdecd..f749da9b85 100644 --- a/lib/eal/x86/rte_power_intrinsics.c +++ b/lib/eal/x86/rte_power_intrinsics.c @@ -4,6 +4,7 @@ #include #include +#include #include #include "rte_power_intrinsics.h" @@ -28,6 +29,7 @@ __umwait_wakeup(volatile void *addr) } static bool wait_supported; +static bool wait_multi_supported; static inline uint64_t __get_umwait_val(const volatile void *p, const uint8_t sz) @@ -76,6 +78,7 @@ rte_power_monitor(const struct rte_power_monitor_cond *pmc, const uint32_t tsc_h = (uint32_t)(tsc_timestamp >> 32); const unsigned int lcore_id = rte_lcore_id(); struct power_wait_status *s; + uint64_t cur_value; /* prevent user from running this instruction if it's not supported */ if (!wait_supported) @@ -91,6 +94,9 @@ rte_power_monitor(const struct rte_power_monitor_cond *pmc, if (__check_val_size(pmc->size) < 0) return -EINVAL; + if (pmc->fn == NULL) + return -EINVAL; + s = &wait_status[lcore_id]; /* update sleep address */ @@ -110,16 +116,11 @@ rte_power_monitor(const struct rte_power_monitor_cond *pmc, /* now that we've put this address into monitor, we can unlock */ rte_spinlock_unlock(&s->lock); - /* if we have a comparison mask, we might not need to sleep at all */ - if (pmc->mask) { - const uint64_t cur_value = __get_umwait_val( - pmc->addr, pmc->size); - const uint64_t masked = cur_value & pmc->mask; + cur_value = __get_umwait_val(pmc->addr, pmc->size); - /* if the masked value is already matching, abort */ - if (masked == pmc->val) - goto end; - } + /* check if callback indicates we should abort */ + if (pmc->fn(cur_value, pmc->opaque) != 0) + goto end; /* execute UMWAIT */ asm volatile(".byte 0xf2, 0x0f, 0xae, 0xf7;" @@ -167,6 +168,8 @@ RTE_INIT(rte_power_intrinsics_init) { if (i.power_monitor && i.power_pause) wait_supported = 1; + if (i.power_monitor_multi) + wait_multi_supported = 1; } int @@ -205,6 +208,9 @@ rte_power_monitor_wakeup(const unsigned int lcore_id) * In this case, since we've already woken up, the "wakeup" was * unneeded, and since T1 is still waiting on T2 releasing the lock, the * wakeup address is still valid so it's perfectly safe to write it. + * + * For multi-monitor case, the act of locking will in itself trigger the + * wakeup, so no additional writes necessary. */ rte_spinlock_lock(&s->lock); if (s->monitor_addr != NULL) @@ -213,3 +219,69 @@ rte_power_monitor_wakeup(const unsigned int lcore_id) return 0; } + +int +rte_power_monitor_multi(const struct rte_power_monitor_cond pmc[], + const uint32_t num, const uint64_t tsc_timestamp) +{ + const unsigned int lcore_id = rte_lcore_id(); + struct power_wait_status *s = &wait_status[lcore_id]; + uint32_t i, rc; + + /* check if supported */ + if (!wait_multi_supported) + return -ENOTSUP; + + if (pmc == NULL || num == 0) + return -EINVAL; + + /* we are already inside transaction region, return */ + if (rte_xtest() != 0) + return 0; + + /* start new transaction region */ + rc = rte_xbegin(); + + /* transaction abort, possible write to one of wait addresses */ + if (rc != RTE_XBEGIN_STARTED) + return 0; + + /* + * the mere act of reading the lock status here adds the lock to + * the read set. This means that when we trigger a wakeup from another + * thread, even if we don't have a defined wakeup address and thus don't + * actually cause any writes, the act of locking our lock will itself + * trigger the wakeup and abort the transaction. + */ + rte_spinlock_is_locked(&s->lock); + + /* + * add all addresses to wait on into transaction read-set and check if + * any of wakeup conditions are already met. + */ + rc = 0; + for (i = 0; i < num; i++) { + const struct rte_power_monitor_cond *c = &pmc[i]; + + /* cannot be NULL */ + if (c->fn == NULL) { + rc = -EINVAL; + break; + } + + const uint64_t val = __get_umwait_val(c->addr, c->size); + + /* abort if callback indicates that we need to stop */ + if (c->fn(val, c->opaque) != 0) + break; + } + + /* none of the conditions were met, sleep until timeout */ + if (i == num) + rte_power_pause(tsc_timestamp); + + /* end transaction region */ + rte_xend(); + + return rc; +}