Skip to contentSkip to conversation

Power-optimized RX for Ethernet devices

RFC In review Anatoly Burakov 20 participants 421 messages May 27, 2020 – Jan 29, 2021 Page 3 of 4

Subsystems (3)
lore
Share & tools
lore
#242 lore raw

Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics

In reply to Burakov, Anatoly
Quoted 197 lines · Anatoly
Quoted 196 lines · Konstantin
Quoted 82 lines
Quoted 82 lines
Quoted 81 lines
Quoted 67 lines
Quoted 54 lines
Quoted 54 lines
Quoted 53 lines
Quoted 25 lines
Quoted 19 lines
Quoted 9 lines

Add two new power management intrinsics, and provide an implementation
in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread
compiler support for these instructions.

Quoted 9 lines

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or
optionally wait until either a TSC timestamp is reached or a memory
location is written to. The monitor function also provides an optional
comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

Quoted 5 lines

I think what this API is missing - a function to wakeup sleeping core.
If user can/should use some system call to achieve that, then at least
it has to be clearly documented, even better some wrapper provided.

Quoted 7 lines

I don't think it's possible to do that without severely overcomplicating
the intrinsic and its usage, because AFAIK the only way to wake up a sleeping core would be to send some kind of interrupt to the core, or
trigger a write to the cache-line in question.

Yes, I think we either need a syscall that would do an IPI for us (on top of my head - membarrier() does that, might be there are some other syscalls too),
or something hand-made. For hand-made, I wonder would something like that
be safe and sufficient:
uint64_t val = atomic_load(addr);
CAS(addr, val, &val);
?
Anyway, one way or another - I think ability to wakeup core we put to sleep
have to be an essential part of this feature.
As I understand linux kernel will limit max amount of sleep time for these instructions:
https://lwn.net/Articles/790920/
But relying just on that, seems too vague for me:
- user can adjust that value
- wouldn't apply to older kernels and non-linux cases Konstantin

Quoted 5 lines
Quoted 1 line

This implies knowing the value the core is sleeping on.

You don't the value to wait for, you just need an address. And you can make wakeup function to accept address as a parameter, same as monitor() does.

Sorry, i meant the address. We don't know the address we're sleeping on.

Quoted 5 lines
Quoted 4 lines

That's not
always the case - with this particular PMD power management scheme, we get the address from the PMD and it stays inside the callback.

Quoted 7 lines
Quoted 3 lines

That's fine - you can store address inside you callback metadata and do wakeup as part of _disable_ function.

The address may be different, and by the time we access the address it may become stale, so i don't see how that would help unless you're suggesting to have some kind of synchronization mechanism there.

Yes, we'll need something to sync here for sure.
Sorry, I should say it straightway, to avoid further misunderstanding. Let say, associate a spin_lock with monitor(), by analogy with pthread_cond_wait().
Konstantin

Quoted 7 lines
Quoted 7 lines

The idea was to provide an intrinsic-like function - as in, raw instruction call, without anything extra. We even added the masks/values etc. only because there's no race-less way to combine UMONITOR/UMWAIT without those.

Perhaps we can provide a synchronize-able wrapper around it to avoid adding overhead to calls that function but doesn't need the sync mechanism?

Yes, might be two flavours, something like
rte_power_monitor() and rte_power_monitor_sync()
or whatever would be a better name.

Quoted 5 lines
Quoted 1 line

Also, how would having a spinlock help to synchronize? Are you suggesting we do UMWAIT on a spinlock address, or something to that effect?

I thought about something very similar to cond_wait() working model:

/*
  * Caller has to obtain lock before calling that function.
  */
static inline int rte_power_monitor_sync(const volatile void *p,
                 const uint64_t expected_value, const uint64_t value_mask, const uint32_t state, const uint64_t tsc_timestamp, rte_spinlock_t *lck) {
/* do whatever preparations are needed */
                ....
umonitor(p);

if (value_mask != 0 && *((const uint64_t *)p) & value_mask == expected_value) { return 0;
  }

/* release lock and go to sleep */
rte_spinlock_unlock(lck);
rflags = umwait();

/* grab lock back after wakeup */
rte_spinlock_lock(lck);

/* do rest of processing */
....
}

/* similar go cond_signal */
static inline void rte_power_monitor_wakeup(volatile void *p) {
uint64_t v;

v = __atomic_load_n(p, __ATOMIC_RELAXED); __atomic_compare_exchange_n(p, v, &v, 1, __ATOMIC_RELAXED, __ATOMIC_RELAXED); }

Now in librte_power:

struct pmd_queue_cfg {
        /* to protect state and wait_addr */
        rte_spinlock_t lck;
        enum pmd_mgmt_state pwr_mgmt_state;
        void *wait_addr;
        /* rest fields */
       ....
} __rte_cache_aligned;

static uint16_t
rte_power_mgmt_umwait(uint16_t port_id, uint16_t qidx, struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx, uint16_t max_pkts __rte_unused, void *_  __rte_unused) {

         struct pmd_queue_cfg *q_conf;
         q_conf = &port_cfg[port_id].queue_cfg[qidx];

         if (unlikely(nb_rx == 0)) { q_conf->empty_poll_stats++;
                 if (unlikely(q_conf->empty_poll_stats > EMPTYPOLL_MAX)) { volatile void *target_addr;
                         uint64_t expected, mask;
                         uint16_t ret;

          /* grab the lock and check the state */ rte_spinlock_lock(&q_conf->lck);
          If (q-conf->state == ENABLED) {
                         ret = rte_eth_get_wake_addr(port_id, qidx, &target_addr, &expected, &mask); If (ret == 0) {
q_conf->wait_addr = target_addr;
rte_power_monitor(target_addr, ..., &q_conf->lck);
          }
           /* reset the wait_addr */
           q_conf->wait_addr = NULL;
          }
          rte_spinlock_unlock(&q_conf->lck);
          ....
}

nt
rte_power_pmd_mgmt_queue_disable(unsigned int lcore_id, uint16_t port_id, uint16_t queue_id) {
...
/* grab the lock and change the state */ rte_spinlock_lock(&q_conf->lck); queue_cfg->state = DISABLED;

/* wakeup if necessary */
If (queue_cfg->wakeup_addr != NULL)
rte_power_monitor_wakeup(queue_cfg->wakeup_addr);

Quoted 7 lines
Quoted 4 lines

rte_spinlock_unlock(&q_conf->lck);
...
}

Yeah, seems that i understood you correctly the first time then. I'm not completely convinced that this overhead and complexity is worth the trouble, to be honest. I mean, it's not like we're going to sleep indefinitely, this isn't like pthread wait - the biggest sleep time i've seen was around half a second and i'm not sure there is a use case for enabling/disabling this functionality willy nilly ever 5 seconds.

Back story: we've had a little internal chat and basically agreed to Konstantin's proposal, with slight modifications. That is, we need to be able to wake up the core because otherwise we have no deterministic way of stopping the sleeping RX path, however there is no need to expose this mechanism in a public API and it can be kept inside the power library instead.

Signature · 2 lines
Thanks,
Anatoly
#243 lore raw

PATCH v4 3/10 ethdev: add simple power management API

In reply to Liang Ma

Add a simple API allow ethdev get wake up address from PMD. Also include internal structure update.

---
 lib/librte_ethdev/rte_ethdev.c           | 19 ++++++++++++++++
 lib/librte_ethdev/rte_ethdev.h           | 24 ++++++++++++++++++++
 lib/librte_ethdev/rte_ethdev_driver.h    | 28 ++++++++++++++++++++++++
 lib/librte_ethdev/rte_ethdev_version.map |  1 +
 4 files changed, 72 insertions(+)
lib/librte_ethdev/rte_ethdev.c +19 -0
index d7668114ca..88253d95f9 100644
@@ -4804,6 +4804,25 @@ rte_eth_tx_burst_mode_get(uint16_t port_id, uint16_t queue_id,
 		       dev->dev_ops->tx_burst_mode_get(dev, queue_id, mode));
 }
 
+int
+rte_eth_get_wake_addr(uint16_t port_id, uint16_t queue_id,
+		      volatile void **wake_addr,
+		      uint64_t *expected, uint64_t *mask)
+{
+	struct rte_eth_dev *dev;
+	uint16_t ret;
+
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+
+	ret = (*dev->dev_ops->get_wake_addr)
+				(dev->data->rx_queues[queue_id],
+				 wake_addr, expected, mask);
+
+	return ret;
+}
+
 int
 rte_eth_dev_set_mc_addr_list(uint16_t port_id,
 			     struct rte_ether_addr *mc_addr_set,
lib/librte_ethdev/rte_ethdev.h +24 -0
index d2bf74f128..a6cfe3cd57 100644
@@ -4014,6 +4014,30 @@ __rte_experimental
 int rte_eth_tx_burst_mode_get(uint16_t port_id, uint16_t queue_id,
 	struct rte_eth_burst_mode *mode);
 
+/**
+ * Retrieve the wake up address from specific queue
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param queue_id
+ *   The Tx queue on the Ethernet device for which information
+ *   will be retrieved.
+ * @param wake_addr
+ *   The pointer point to the address which is used for monitoring.
+ * @param expected
+ *   The pointer point to value to be expected when descriptor is set.
+ * @param mask
+ *   The pointer point to comparison bitmask for the expected value.
+ *
+ * @return
+ *   - 0: Success.
+ *   -EINVAL: Failed to get wake address.
+ */
+__rte_experimental
+int rte_eth_get_wake_addr(uint16_t port_id, uint16_t queue_id,
+			  volatile void **wake_addr,
+			  uint64_t *expected, uint64_t *mask);
+
 /**
  * Retrieve device registers and register attributes (number of registers and
  * register size)
lib/librte_ethdev/rte_ethdev_driver.h +28 -0
index c3062c246c..935d46f25c 100644
@@ -574,6 +574,31 @@ typedef int (*eth_tx_hairpin_queue_setup_t)
 	 uint16_t nb_tx_desc,
 	 const struct rte_eth_hairpin_conf *hairpin_conf);
 
+/**
+ * @internal
+ * Get the Wake up address.
+ *
+ * @param rxq
+ *   Ethdev queue pointer.
+ * @param tail_desc_addr
+ *   The pointer point to descriptor address var.
+ * @param expected
+ *   The pointer point to value to be expected when descriptor is set.
+ * @param mask
+ *   The pointer point to comparison bitmask for the expected value.
+ * @return
+ *   Negative errno value on error, 0 on success.
+ *
+ * @retval 0
+ *   Success.
+ * @retval -EINVAL
+ *   Failed to get descriptor address.
+ */
+typedef int (*eth_get_wake_addr_t)
+	(void *rxq, volatile void **tail_desc_addr,
+	 uint64_t *expected, uint64_t *mask);
+
+
 /**
  * @internal A structure containing the functions exported by an Ethernet driver.
  */
@@ -713,6 +738,9 @@ struct eth_dev_ops {
 	/**< Set up device RX hairpin queue. */
 	eth_tx_hairpin_queue_setup_t tx_hairpin_queue_setup;
 	/**< Set up device TX hairpin queue. */
+	eth_get_wake_addr_t get_wake_addr;
+	/**< Get wake up address. */
+
 };
 
 /**
lib/librte_ethdev/rte_ethdev_version.map +1 -0
index c95ef5157a..3cb2093980 100644
@@ -229,6 +229,7 @@ EXPERIMENTAL {
 	# added in 20.11
 	rte_eth_link_speed_to_str;
 	rte_eth_link_to_str;
+	rte_eth_get_wake_addr;
 };
 
 INTERNAL {
Signature · 1 line
2.17.1
#244 lore raw

Re: [dpdk-dev] [PATCH v4 03/10] ethdev: add simple power management API

Quoted 13 lines
lib/librte_ethdev/rte_ethdev.h +13 -0
+/**
+ * Retrieve the wake up address from specific queue
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param queue_id
+ *   The Tx queue on the Ethernet device for which information
+ *   will be retrieved.
+ * @param wake_addr
+ *   The pointer point to the address which is used for monitoring.
+ * @param expected
+ *   The pointer point to value to be expected when descriptor is set.
+ * @param mask

lib/librte_ethdev/rte_ethdev.h __rte_experimental · line 4039

Quoted 10 lines
lib/librte_ethdev/rte_ethdev.h +10 -0
+ *   The pointer point to comparison bitmask for the expected value.
+ *
+ * @return
+ *   - 0: Success.
+ *   -EINVAL: Failed to get wake address.
+ */
+__rte_experimental
+int rte_eth_get_wake_addr(uint16_t port_id, uint16_t queue_id,
+                         volatile void **wake_addr,
+                         uint64_t *expected, uint64_t *mask);

It looks to be a very low-level API.
Can't we do something more "ready-to-use" at ethdev level?

Cc'in the relevant maintainers...
Note: sorry this comment come late but ethdev maintainers were not Cc.
Reminder: having no feedback is not a good sign, you should request comments.

#245 lore raw

Re: [dpdk-dev] [PATCH v4 03/10] ethdev: add simple power management API

Quoted 20 lines
Quoted 20 lines

+/**
+ * Retrieve the wake up address from specific queue
+ *
+ * @param port_id
+ * The port identifier of the Ethernet device.
+ * @param queue_id
+ * The Tx queue on the Ethernet device for which information
+ * will be retrieved.
+ * @param wake_addr
+ * The pointer point to the address which is used for monitoring.
+ * @param expected
+ * The pointer point to value to be expected when descriptor is set.
+ * @param mask
+ * The pointer point to comparison bitmask for the expected value.
+ *
+ * @return
+ * - 0: Success.
+ * -EINVAL: Failed to get wake address.

Quoted 8 lines

lib/librte_ethdev/rte_ethdev.h __rte_experimental · line 4039

Quoted 5 lines

+ */

lib/librte_ethdev/rte_ethdev.h +4 -0
+__rte_experimental
+int rte_eth_get_wake_addr(uint16_t port_id, uint16_t queue_id,
+                         volatile void **wake_addr,
+                         uint64_t *expected, uint64_t *mask);

It looks to be a very low-level API.
Can't we do something more "ready-to-use" at ethdev level?

I think that series provides both:
There is a low-level API at ethdev/eal to retrieve information to wait for and actual function to put core to sleep.
Plus there is a high-level API at rte_power lib:
rte_power_pmd_mgmt_queue_enable()/rte_power_pmd_mgmt_queue_disable() that uses these low-level ones and puts some high-level logic around it. From my perspective it is a good design choice,
as it keeps all power-related burden inside rte_power library and provides user a lot of flexibility in terms of API usage. Konstantin

Quoted 5 lines

Cc'in the relevant maintainers...
Note: sorry this comment come late but ethdev maintainers were not Cc.
Reminder: having no feedback is not a good sign, you should request comments.

#246 lore raw

Re: [dpdk-dev] [PATCH v4 03/10] ethdev: add simple power management API

In reply to Liang Ma
Quoted 26 lines

Add a simple API allow ethdev get wake up address from PMD. Also include internal structure update.

---
 lib/librte_ethdev/rte_ethdev.c           | 19 ++++++++++++++++
 lib/librte_ethdev/rte_ethdev.h           | 24 ++++++++++++++++++++
 lib/librte_ethdev/rte_ethdev_driver.h    | 28 ++++++++++++++++++++++++
 lib/librte_ethdev/rte_ethdev_version.map |  1 +
 4 files changed, 72 insertions(+)
lib/librte_ethdev/rte_ethdev.c +5 -0
index d7668114ca..88253d95f9 100644
@@ -4804,6 +4804,25 @@ rte_eth_tx_burst_mode_get(uint16_t port_id, uint16_t queue_id,
 		       dev->dev_ops->tx_burst_mode_get(dev, queue_id, mode));
 }
 
+int
+rte_eth_get_wake_addr(uint16_t port_id, uint16_t queue_id,
+		      volatile void **wake_addr,
+		      uint64_t *expected, uint64_t *mask)
+{

lib/librte_ethdev/rte_ethdev.c rte_eth_tx_burst_mode_get(uint16_t port_id, uint16_t queue_id, · line 4821

Quoted 10 lines
lib/librte_ethdev/rte_ethdev.c +10 -0
+	struct rte_eth_dev *dev;
+	uint16_t ret;
+
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+
+	ret = (*dev->dev_ops->get_wake_addr)
+				(dev->data->rx_queues[queue_id],
+				 wake_addr, expected, mask);

This is an optional dev_ops, so I think you need to check that get_wake_addr() is defined for that PMD.
Plus you need to check that queue_id is valid.

Quoted 102 lines
lib/librte_ethdev/rte_ethdev.c +4 -0
+
+	return ret;
+}
+
 int
 rte_eth_dev_set_mc_addr_list(uint16_t port_id,
 			     struct rte_ether_addr *mc_addr_set,
lib/librte_ethdev/rte_ethdev.h +24 -0
index d2bf74f128..a6cfe3cd57 100644
@@ -4014,6 +4014,30 @@ __rte_experimental
 int rte_eth_tx_burst_mode_get(uint16_t port_id, uint16_t queue_id,
 	struct rte_eth_burst_mode *mode);
 
+/**
+ * Retrieve the wake up address from specific queue
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param queue_id
+ *   The Tx queue on the Ethernet device for which information
+ *   will be retrieved.
+ * @param wake_addr
+ *   The pointer point to the address which is used for monitoring.
+ * @param expected
+ *   The pointer point to value to be expected when descriptor is set.
+ * @param mask
+ *   The pointer point to comparison bitmask for the expected value.
+ *
+ * @return
+ *   - 0: Success.
+ *   -EINVAL: Failed to get wake address.
+ */
+__rte_experimental
+int rte_eth_get_wake_addr(uint16_t port_id, uint16_t queue_id,
+			  volatile void **wake_addr,
+			  uint64_t *expected, uint64_t *mask);
+
 /**
  * Retrieve device registers and register attributes (number of registers and
  * register size)
lib/librte_ethdev/rte_ethdev_driver.h +28 -0
index c3062c246c..935d46f25c 100644
@@ -574,6 +574,31 @@ typedef int (*eth_tx_hairpin_queue_setup_t)
 	 uint16_t nb_tx_desc,
 	 const struct rte_eth_hairpin_conf *hairpin_conf);
 
+/**
+ * @internal
+ * Get the Wake up address.
+ *
+ * @param rxq
+ *   Ethdev queue pointer.
+ * @param tail_desc_addr
+ *   The pointer point to descriptor address var.
+ * @param expected
+ *   The pointer point to value to be expected when descriptor is set.
+ * @param mask
+ *   The pointer point to comparison bitmask for the expected value.
+ * @return
+ *   Negative errno value on error, 0 on success.
+ *
+ * @retval 0
+ *   Success.
+ * @retval -EINVAL
+ *   Failed to get descriptor address.
+ */
+typedef int (*eth_get_wake_addr_t)
+	(void *rxq, volatile void **tail_desc_addr,
+	 uint64_t *expected, uint64_t *mask);
+
+
 /**
  * @internal A structure containing the functions exported by an Ethernet driver.
  */
@@ -713,6 +738,9 @@ struct eth_dev_ops {
 	/**< Set up device RX hairpin queue. */
 	eth_tx_hairpin_queue_setup_t tx_hairpin_queue_setup;
 	/**< Set up device TX hairpin queue. */
+	eth_get_wake_addr_t get_wake_addr;
+	/**< Get wake up address. */
+
 };
 
 /**
lib/librte_ethdev/rte_ethdev_version.map +1 -1
index c95ef5157a..3cb2093980 100644
@@ -229,6 +229,7 @@ EXPERIMENTAL {
 	# added in 20.11
 	rte_eth_link_speed_to_str;
 	rte_eth_link_to_str;
+	rte_eth_get_wake_addr;
 };
 
 INTERNAL {
--

2.17.1

#247 lore raw

Re: [dpdk-dev] [PATCH v4 03/10] ethdev: add simple power management API

Quoted 33 lines · Konstantin
Quoted 33 lines

Add a simple API allow ethdev get wake up address from PMD. Also include internal structure update.

---
  lib/librte_ethdev/rte_ethdev.c           | 19 ++++++++++++++++
  lib/librte_ethdev/rte_ethdev.h           | 24 ++++++++++++++++++++
  lib/librte_ethdev/rte_ethdev_driver.h    | 28 ++++++++++++++++++++++++
  lib/librte_ethdev/rte_ethdev_version.map |  1 +
  4 files changed, 72 insertions(+)
lib/librte_ethdev/rte_ethdev.c +12 -0
index d7668114ca..88253d95f9 100644
@@ -4804,6 +4804,25 @@ rte_eth_tx_burst_mode_get(uint16_t port_id, uint16_t queue_id,
         dev->dev_ops->tx_burst_mode_get(dev, queue_id, mode));
  }
 
+int
+rte_eth_get_wake_addr(uint16_t port_id, uint16_t queue_id,
+      volatile void **wake_addr,
+      uint64_t *expected, uint64_t *mask)
+{
+struct rte_eth_dev *dev;
+uint16_t ret;
+
+RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+dev = &rte_eth_devices[port_id];
+
Quoted 9 lines

lib/librte_ethdev/rte_ethdev.c rte_eth_tx_burst_mode_get(uint16_t port_id, uint16_t queue_id, · line 4821

Quoted 3 lines
lib/librte_ethdev/rte_ethdev.c +3 -0
+ret = (*dev->dev_ops->get_wake_addr)
+(dev->data->rx_queues[queue_id],
+ wake_addr, expected, mask);

This is an optional dev_ops, so I think you need to check that get_wake_addr() is defined for that PMD.
Plus you need to check that queue_id is valid.

Sorry, added dev_ops check but left out the queue id part :( Will fix in v6.

Signature · 2 lines
Thanks,
Anatoly
#248 lore raw

PATCH v4 4/10 power: add simple power management API and callback

In reply to Liang Ma

Add a simple on/off switch that will enable saving power when no packets are arriving. It is based on counting the number of empty polls and, when the number reaches a certain threshold, entering an architecture-defined optimized power state that will either wait until a TSC timestamp expires, or when packets arrive.

This API support 1 port to multiple core use case.

This design leverage RX Callback mechnaism which allow three different power management methodology co exist.

1. umwait/umonitor:

The TSC timestamp is automatically calculated using current link speed and RX descriptor ring size, such that the sleep time is not longer than it would take for a NIC to fill its entire RX descriptor ring.

2. Pause instruction

Instead of move the core into deeper C state, this lightweight method use Pause instruction to relief the processor from busy polling.

3. Frequency Scaling
Reuse exist rte power library to scale up/down core frequency depend on traffic volume.

---
 lib/librte_power/meson.build           |   5 +-
 lib/librte_power/pmd_mgmt.h            |  49 ++++++
 lib/librte_power/rte_power_pmd_mgmt.c  | 208 +++++++++++++++++++++++++
 lib/librte_power/rte_power_pmd_mgmt.h  |  88 +++++++++++
 lib/librte_power/rte_power_version.map |   4 +
 5 files changed, 352 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_power/pmd_mgmt.h
 create mode 100644 lib/librte_power/rte_power_pmd_mgmt.c
 create mode 100644 lib/librte_power/rte_power_pmd_mgmt.h
lib/librte_power/meson.build +3 -2
index 78c031c943..cc3c7a8646 100644
@@ -9,6 +9,7 @@ sources = files('rte_power.c', 'power_acpi_cpufreq.c',
 		'power_kvm_vm.c', 'guest_channel.c',
 		'rte_power_empty_poll.c',
 		'power_pstate_cpufreq.c',
+		'rte_power_pmd_mgmt.c',
 		'power_common.c')
-headers = files('rte_power.h','rte_power_empty_poll.h')
-deps += ['timer']
+headers = files('rte_power.h','rte_power_empty_poll.h','rte_power_pmd_mgmt.h')
+deps += ['timer' ,'ethdev']
lib/librte_power/pmd_mgmt.h new file +49 -0

49 lines not on this page · raw message

lib/librte_power/rte_power_pmd_mgmt.c new file +208 -0

208 lines not on this page · raw message

lib/librte_power/rte_power_pmd_mgmt.h new file +88 -0

88 lines not on this page · raw message

lib/librte_power/rte_power_version.map +4 -0
index 69ca9af616..3f2f6cd6f6 100644
@@ -34,4 +34,8 @@ EXPERIMENTAL {
 	rte_power_guest_channel_receive_msg;
 	rte_power_poll_stat_fetch;
 	rte_power_poll_stat_update;
+	# added in 20.11
+	rte_power_pmd_mgmt_queue_enable;
+	rte_power_pmd_mgmt_queue_disable;
+
 };
Signature · 1 line
2.17.1
#249 lore raw

Re: [dpdk-dev] [PATCH v4 04/10] power: add simple power management API and callback

Quoted 137 lines

Add a simple on/off switch that will enable saving power when no packets are arriving. It is based on counting the number of empty polls and, when the number reaches a certain threshold, entering an architecture-defined optimized power state that will either wait until a TSC timestamp expires, or when packets arrive.

This API support 1 port to multiple core use case.

This design leverage RX Callback mechnaism which allow three different power management methodology co exist.

1. umwait/umonitor:

The TSC timestamp is automatically calculated using current link speed and RX descriptor ring size, such that the sleep time is not longer than it would take for a NIC to fill its entire RX descriptor ring.

2. Pause instruction

Instead of move the core into deeper C state, this lightweight method use Pause instruction to relief the processor from busy polling.

3. Frequency Scaling
Reuse exist rte power library to scale up/down core frequency depend on traffic volume.

---
 lib/librte_power/meson.build           |   5 +-
 lib/librte_power/pmd_mgmt.h            |  49 ++++++
 lib/librte_power/rte_power_pmd_mgmt.c  | 208 +++++++++++++++++++++++++
 lib/librte_power/rte_power_pmd_mgmt.h  |  88 +++++++++++
 lib/librte_power/rte_power_version.map |   4 +
 5 files changed, 352 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_power/pmd_mgmt.h
 create mode 100644 lib/librte_power/rte_power_pmd_mgmt.c
 create mode 100644 lib/librte_power/rte_power_pmd_mgmt.h
lib/librte_power/meson.build +3 -2
index 78c031c943..cc3c7a8646 100644
@@ -9,6 +9,7 @@ sources = files('rte_power.c', 'power_acpi_cpufreq.c',
 		'power_kvm_vm.c', 'guest_channel.c',
 		'rte_power_empty_poll.c',
 		'power_pstate_cpufreq.c',
+		'rte_power_pmd_mgmt.c',
 		'power_common.c')
-headers = files('rte_power.h','rte_power_empty_poll.h')
-deps += ['timer']
+headers = files('rte_power.h','rte_power_empty_poll.h','rte_power_pmd_mgmt.h')
+deps += ['timer' ,'ethdev']
lib/librte_power/pmd_mgmt.h new file +49 -0
new file mode 100644
index 0000000000..756fbe20f7
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2020 Intel Corporation
+ */
+
+#ifndef _PMD_MGMT_H
+#define _PMD_MGMT_H
+
+/**
+ * @file
+ * Power Management
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Possible power management states of an ethdev port.
+ */
+enum pmd_mgmt_state {
+	/** Device power management is disabled. */
+	PMD_MGMT_DISABLED = 0,
+	/** Device power management is enabled. */
+	PMD_MGMT_ENABLED,
+};
+
+struct pmd_queue_cfg {
+	enum pmd_mgmt_state pwr_mgmt_state;
+	/**< Power mgmt Callback mode */
+	enum rte_power_pmd_mgmt_type cb_mode;
+	/**< Empty poll number */
+	uint16_t empty_poll_stats;
+	/**< Callback instance  */
+	const struct rte_eth_rxtx_callback *cur_cb;
+} __rte_cache_aligned;
+
+struct pmd_port_cfg {
+	int  ref_cnt;
+	struct pmd_queue_cfg *queue_cfg;
+} __rte_cache_aligned;
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
lib/librte_power/rte_power_pmd_mgmt.c new file +21 -0
new file mode 100644
index 0000000000..35d2af46a4
@@ -0,0 +1,208 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2020 Intel Corporation
+ */
+
+#include <rte_lcore.h>
+#include <rte_cycles.h>
+#include <rte_malloc.h>
+#include <rte_ethdev.h>
+#include <rte_power_intrinsics.h>
+
+#include "rte_power_pmd_mgmt.h"
+#include "pmd_mgmt.h"
+
+
+#define EMPTYPOLL_MAX  512
+#define PAUSE_NUM  64
+
+static struct pmd_port_cfg port_cfg[RTE_MAX_ETHPORTS];
+
+static uint16_t
+rte_power_mgmt_umwait(uint16_t port_id, uint16_t qidx,

lib/librte_power/rte_power_pmd_mgmt.c line 31

Quoted 10 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +10 -0
+		struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx,
+		uint16_t max_pkts __rte_unused, void *_  __rte_unused)
+{
+
+	struct pmd_queue_cfg *q_conf;
+	q_conf = &port_cfg[port_id].queue_cfg[qidx];
+
+	if (unlikely(nb_rx == 0)) {
+		q_conf->empty_poll_stats++;
+		if (unlikely(q_conf->empty_poll_stats > EMPTYPOLL_MAX)) {

Here and in other places - wouldn't it be better to empty_poll_max as configurable parameter, instead of constant value?

Quoted 7 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +7 -0
+			volatile void *target_addr;
+			uint64_t expected, mask;
+			uint16_t ret;
+
+			/*
+			 * get address of next descriptor in the RX
+			 * ring for this queue, as well as expected

lib/librte_power/rte_power_pmd_mgmt.c line 48

Quoted 10 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +10 -0
+			 * value and a mask.
+			 */
+			ret = rte_eth_get_wake_addr(port_id, qidx,
+						    &target_addr, &expected,
+						    &mask);
+			if (ret == 0)
+				/* -1ULL is maximum value for TSC */
+				rte_power_monitor(target_addr,
+						  expected, mask,
+						  0, -1ULL);

Why not make timeout a user specified parameter?

Quoted 11 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +11 -0
+		}
+	} else
+		q_conf->empty_poll_stats = 0;
+
+	return nb_rx;
+}
+
+static uint16_t
+rte_power_mgmt_pause(uint16_t port_id, uint16_t qidx,
+		struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx,
+		uint16_t max_pkts __rte_unused, void *_  __rte_unused)

lib/librte_power/rte_power_pmd_mgmt.c line 69

Quoted 10 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +10 -0
+{
+	struct pmd_queue_cfg *q_conf;
+	int i;
+	q_conf = &port_cfg[port_id].queue_cfg[qidx];
+
+	if (unlikely(nb_rx == 0)) {
+		q_conf->empty_poll_stats++;
+		if (unlikely(q_conf->empty_poll_stats > EMPTYPOLL_MAX)) {
+			for (i = 0; i < PAUSE_NUM; i++)
+				rte_pause();

Just rte_delay_us(timeout) instead of this loop?

Quoted 21 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +21 -0
+		}
+	} else
+		q_conf->empty_poll_stats = 0;
+
+	return nb_rx;
+}
+
+static uint16_t
+rte_power_mgmt_scalefreq(uint16_t port_id, uint16_t qidx,
+		struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx,
+		uint16_t max_pkts __rte_unused, void *_  __rte_unused)
+{
+	struct pmd_queue_cfg *q_conf;
+	q_conf = &port_cfg[port_id].queue_cfg[qidx];
+
+	if (unlikely(nb_rx == 0)) {
+		q_conf->empty_poll_stats++;
+		if (unlikely(q_conf->empty_poll_stats > EMPTYPOLL_MAX)) {
+			/*scale down freq */
+			rte_power_freq_min(rte_lcore_id());
+

lib/librte_power/rte_power_pmd_mgmt.c line 100

Quoted 10 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +10 -0
+		}
+	} else {
+		q_conf->empty_poll_stats = 0;
+		/* scal up freq */
+		rte_power_freq_max(rte_lcore_id());
+	}
+
+	return nb_rx;
+}
+

Probably worth to mention in comments that these functions enable/disable are not MT safe.

Quoted 43 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +43 -0
+int
+rte_power_pmd_mgmt_queue_enable(unsigned int lcore_id,
+				uint16_t port_id,
+				uint16_t queue_id,
+				enum rte_power_pmd_mgmt_type mode)
+{
+	struct rte_eth_dev *dev;
+	struct pmd_queue_cfg *queue_cfg;
+	int ret = 0;
+
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
+	dev = &rte_eth_devices[port_id];
+
+	if (port_cfg[port_id].queue_cfg == NULL) {
+		port_cfg[port_id].ref_cnt = 0;
+		/* allocate memory for empty poll stats */
+		port_cfg[port_id].queue_cfg  = rte_malloc_socket(NULL,
+					sizeof(struct pmd_queue_cfg)
+					* RTE_MAX_QUEUES_PER_PORT,
+					0, dev->data->numa_node);
+		if (port_cfg[port_id].queue_cfg == NULL)
+			return -ENOMEM;
+	}
+
+	queue_cfg = &port_cfg[port_id].queue_cfg[queue_id];
+
+	if (queue_cfg->pwr_mgmt_state == PMD_MGMT_ENABLED) {
+		ret = -EINVAL;
+		goto failure_handler;
+	}
+
+	switch (mode) {
+	case RTE_POWER_MGMT_TYPE_WAIT:
+		if (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_WAITPKG)) {
+			ret = -ENOTSUP;
+			goto failure_handler;
+		}
+		queue_cfg->cur_cb = rte_eth_add_rx_callback(port_id, queue_id,
+						rte_power_mgmt_umwait, NULL);
+		break;
+	case RTE_POWER_MGMT_TYPE_SCALE:
+		/* init scale freq */
+		if (rte_power_init(lcore_id)) {

lib/librte_power/rte_power_pmd_mgmt.c line 153

Quoted 10 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +10 -0
+			ret = -EINVAL;
+			goto failure_handler;
+		}
+		queue_cfg->cur_cb = rte_eth_add_rx_callback(port_id, queue_id,
+					rte_power_mgmt_scalefreq, NULL);
+		break;
+	case RTE_POWER_MGMT_TYPE_PAUSE:
+		queue_cfg->cur_cb = rte_eth_add_rx_callback(port_id, queue_id,
+						rte_power_mgmt_pause, NULL);
+		break;
	default:
		....
Quoted 21 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +21 -0
+	}
+	queue_cfg->cb_mode = mode;
+	port_cfg[port_id].ref_cnt++;
+	queue_cfg->pwr_mgmt_state = PMD_MGMT_ENABLED;
+	return ret;
+
+failure_handler:
+	if (port_cfg[port_id].ref_cnt == 0) {
+		rte_free(port_cfg[port_id].queue_cfg);
+		port_cfg[port_id].queue_cfg = NULL;
+	}
+	return ret;
+}
+
+int
+rte_power_pmd_mgmt_queue_disable(unsigned int lcore_id,
+				uint16_t port_id,
+				uint16_t queue_id)
+{
+	struct pmd_queue_cfg *queue_cfg;
+

lib/librte_power/rte_power_pmd_mgmt.c line 184

Quoted 10 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +10 -0
+	if (port_cfg[port_id].ref_cnt <= 0)
+		return -EINVAL;
+
+	queue_cfg = &port_cfg[port_id].queue_cfg[queue_id];
+
+	if (queue_cfg->pwr_mgmt_state == PMD_MGMT_DISABLED)
+		return -EINVAL;
+
+	switch (queue_cfg->cb_mode) {
+	case RTE_POWER_MGMT_TYPE_WAIT:

Think we need wakeup(lcore_id) here.

Quoted 10 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +10 -0
+	case RTE_POWER_MGMT_TYPE_PAUSE:
+		rte_eth_remove_rx_callback(port_id, queue_id,
+					   queue_cfg->cur_cb);
+		break;
+	case RTE_POWER_MGMT_TYPE_SCALE:
+		rte_power_freq_max(lcore_id);
+		rte_eth_remove_rx_callback(port_id, queue_id,
+					   queue_cfg->cur_cb);
+		rte_power_exit(lcore_id);
+		break;

lib/librte_power/rte_power_pmd_mgmt.c line 204

Quoted 10 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +10 -0
+	}
+	/* it's not recommend to free callback instance here.
+	 * it cause memory leak which is a known issue.
+	 */
+	queue_cfg->cur_cb = NULL;
+	queue_cfg->pwr_mgmt_state = PMD_MGMT_DISABLED;
+	port_cfg[port_id].ref_cnt--;
+
+	if (port_cfg[port_id].ref_cnt == 0) {
+		rte_free(port_cfg[port_id].queue_cfg);

It is not safe to do so, unless device is already stopped.
Otherwise you need some sync mechanism here (hand-made as bpf lib, or rcu online/offline, or...)

Quoted 4 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +4 -0
+		port_cfg[port_id].queue_cfg = NULL;
+	}
+	return 0;
+}
#250 lore raw

Re: [dpdk-dev] [PATCH v4 04/10] power: add simple power management API and callback

Quoted 143 lines · Konstantin
Quoted 143 lines

Add a simple on/off switch that will enable saving power when no packets are arriving. It is based on counting the number of empty polls and, when the number reaches a certain threshold, entering an architecture-defined optimized power state that will either wait until a TSC timestamp expires, or when packets arrive.

This API support 1 port to multiple core use case.

This design leverage RX Callback mechnaism which allow three different power management methodology co exist.

1. umwait/umonitor:

The TSC timestamp is automatically calculated using current link speed and RX descriptor ring size, such that the sleep time is not longer than it would take for a NIC to fill its entire RX descriptor ring.

2. Pause instruction

Instead of move the core into deeper C state, this lightweight method use Pause instruction to relief the processor from busy polling.

3. Frequency Scaling
Reuse exist rte power library to scale up/down core frequency depend on traffic volume.

---
  lib/librte_power/meson.build           |   5 +-
  lib/librte_power/pmd_mgmt.h            |  49 ++++++
  lib/librte_power/rte_power_pmd_mgmt.c  | 208 +++++++++++++++++++++++++
  lib/librte_power/rte_power_pmd_mgmt.h  |  88 +++++++++++
  lib/librte_power/rte_power_version.map |   4 +
  5 files changed, 352 insertions(+), 2 deletions(-)

create mode 100644 lib/librte_power/pmd_mgmt.h create mode 100644 lib/librte_power/rte_power_pmd_mgmt.c create mode 100644 lib/librte_power/rte_power_pmd_mgmt.h

lib/librte_power/meson.build +3 -2
index 78c031c943..cc3c7a8646 100644
@@ -9,6 +9,7 @@ sources = files('rte_power.c', 'power_acpi_cpufreq.c',
  'power_kvm_vm.c', 'guest_channel.c',
  'rte_power_empty_poll.c',
  'power_pstate_cpufreq.c',
+'rte_power_pmd_mgmt.c',
  'power_common.c')
-headers = files('rte_power.h','rte_power_empty_poll.h')
-deps += ['timer']
+headers = files('rte_power.h','rte_power_empty_poll.h','rte_power_pmd_mgmt.h')
+deps += ['timer' ,'ethdev']
lib/librte_power/pmd_mgmt.h new file +49 -0
new file mode 100644
index 0000000000..756fbe20f7
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2020 Intel Corporation
+ */
+
+#ifndef _PMD_MGMT_H
+#define _PMD_MGMT_H
+
+/**
+ * @file
+ * Power Management
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Possible power management states of an ethdev port.
+ */
+enum pmd_mgmt_state {
+/** Device power management is disabled. */
+PMD_MGMT_DISABLED = 0,
+/** Device power management is enabled. */
+PMD_MGMT_ENABLED,
+};
+
+struct pmd_queue_cfg {
+enum pmd_mgmt_state pwr_mgmt_state;
+/**< Power mgmt Callback mode */
+enum rte_power_pmd_mgmt_type cb_mode;
+/**< Empty poll number */
+uint16_t empty_poll_stats;
+/**< Callback instance  */
+const struct rte_eth_rxtx_callback *cur_cb;
+} __rte_cache_aligned;
+
+struct pmd_port_cfg {
+int  ref_cnt;
+struct pmd_queue_cfg *queue_cfg;
+} __rte_cache_aligned;
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
lib/librte_power/rte_power_pmd_mgmt.c new file +27 -0
new file mode 100644
index 0000000000..35d2af46a4
@@ -0,0 +1,208 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2020 Intel Corporation
+ */
+
+#include <rte_lcore.h>
+#include <rte_cycles.h>
+#include <rte_malloc.h>
+#include <rte_ethdev.h>
+#include <rte_power_intrinsics.h>
+
+#include "rte_power_pmd_mgmt.h"
+#include "pmd_mgmt.h"
+
+
+#define EMPTYPOLL_MAX  512
+#define PAUSE_NUM  64
+
+static struct pmd_port_cfg port_cfg[RTE_MAX_ETHPORTS];
+
+static uint16_t
+rte_power_mgmt_umwait(uint16_t port_id, uint16_t qidx,
+struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx,
+uint16_t max_pkts __rte_unused, void *_  __rte_unused)
+{
+
+struct pmd_queue_cfg *q_conf;
+q_conf = &port_cfg[port_id].queue_cfg[qidx];
Quoted 8 lines

lib/librte_power/rte_power_pmd_mgmt.c line 31

Quoted 4 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +4 -0
+
+if (unlikely(nb_rx == 0)) {
+q_conf->empty_poll_stats++;
+if (unlikely(q_conf->empty_poll_stats > EMPTYPOLL_MAX)) {

Here and in other places - wouldn't it be better to empty_poll_max as configurable parameter, instead of constant value?

It would be more flexible, but i don't think it's "better" in the sense that providing additional options will only make using this (already under-utilized!) API harder than it needs to be.

Quoted 13 lines
Quoted 13 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +12 -0
+volatile void *target_addr;
+uint64_t expected, mask;
+uint16_t ret;
+
+/*
+ * get address of next descriptor in the RX
+ * ring for this queue, as well as expected
+ * value and a mask.
+ */
+ret = rte_eth_get_wake_addr(port_id, qidx,
+    &target_addr, &expected,
+    &mask);
Quoted 8 lines

lib/librte_power/rte_power_pmd_mgmt.c line 48

Quoted 5 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +5 -0
+if (ret == 0)
+/* -1ULL is maximum value for TSC */
+rte_power_monitor(target_addr,
+  expected, mask,
+  0, -1ULL);

Why not make timeout a user specified parameter?

This is meant to be an "easy to use" API, we were trying to keep the amount of configuration to an absolute minimum. If the user wants to use custom timeouts, they can do so with using rte_power_monitor API explicitly.

Quoted 16 lines
Quoted 16 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +15 -0
+}
+} else
+q_conf->empty_poll_stats = 0;
+
+return nb_rx;
+}
+
+static uint16_t
+rte_power_mgmt_pause(uint16_t port_id, uint16_t qidx,
+struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx,
+uint16_t max_pkts __rte_unused, void *_  __rte_unused)
+{
+struct pmd_queue_cfg *q_conf;
+int i;
+q_conf = &port_cfg[port_id].queue_cfg[qidx];
Quoted 8 lines

lib/librte_power/rte_power_pmd_mgmt.c line 69

Quoted 6 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +6 -0
+
+if (unlikely(nb_rx == 0)) {
+q_conf->empty_poll_stats++;
+if (unlikely(q_conf->empty_poll_stats > EMPTYPOLL_MAX)) {
+for (i = 0; i < PAUSE_NUM; i++)
+rte_pause();

Just rte_delay_us(timeout) instead of this loop?

Yes, seems better, thanks.

Quoted 27 lines
Quoted 27 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +26 -0
+}
+} else
+q_conf->empty_poll_stats = 0;
+
+return nb_rx;
+}
+
+static uint16_t
+rte_power_mgmt_scalefreq(uint16_t port_id, uint16_t qidx,
+struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx,
+uint16_t max_pkts __rte_unused, void *_  __rte_unused)
+{
+struct pmd_queue_cfg *q_conf;
+q_conf = &port_cfg[port_id].queue_cfg[qidx];
+
+if (unlikely(nb_rx == 0)) {
+q_conf->empty_poll_stats++;
+if (unlikely(q_conf->empty_poll_stats > EMPTYPOLL_MAX)) {
+/*scale down freq */
+rte_power_freq_min(rte_lcore_id());
+
+}
+} else {
+q_conf->empty_poll_stats = 0;
+/* scal up freq */
+rte_power_freq_max(rte_lcore_id());
Quoted 8 lines

lib/librte_power/rte_power_pmd_mgmt.c line 55

Quoted 5 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +5 -0
+}
+
+return nb_rx;
+}
+

Probably worth to mention in comments that these functions enable/disable are not MT safe.

Will do in v6.

Quoted 49 lines
Quoted 49 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +48 -0
+int
+rte_power_pmd_mgmt_queue_enable(unsigned int lcore_id,
+uint16_t port_id,
+uint16_t queue_id,
+enum rte_power_pmd_mgmt_type mode)
+{
+struct rte_eth_dev *dev;
+struct pmd_queue_cfg *queue_cfg;
+int ret = 0;
+
+RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
+dev = &rte_eth_devices[port_id];
+
+if (port_cfg[port_id].queue_cfg == NULL) {
+port_cfg[port_id].ref_cnt = 0;
+/* allocate memory for empty poll stats */
+port_cfg[port_id].queue_cfg  = rte_malloc_socket(NULL,
+sizeof(struct pmd_queue_cfg)
+* RTE_MAX_QUEUES_PER_PORT,
+0, dev->data->numa_node);
+if (port_cfg[port_id].queue_cfg == NULL)
+return -ENOMEM;
+}
+
+queue_cfg = &port_cfg[port_id].queue_cfg[queue_id];
+
+if (queue_cfg->pwr_mgmt_state == PMD_MGMT_ENABLED) {
+ret = -EINVAL;
+goto failure_handler;
+}
+
+switch (mode) {
+case RTE_POWER_MGMT_TYPE_WAIT:
+if (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_WAITPKG)) {
+ret = -ENOTSUP;
+goto failure_handler;
+}
+queue_cfg->cur_cb = rte_eth_add_rx_callback(port_id, queue_id,
+rte_power_mgmt_umwait, NULL);
+break;
+case RTE_POWER_MGMT_TYPE_SCALE:
+/* init scale freq */
+if (rte_power_init(lcore_id)) {
+ret = -EINVAL;
+goto failure_handler;
+}
+queue_cfg->cur_cb = rte_eth_add_rx_callback(port_id, queue_id,
+rte_power_mgmt_scalefreq, NULL);
Quoted 8 lines

lib/librte_power/rte_power_pmd_mgmt.c line 153

Quoted 5 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +5 -0
+break;
+case RTE_POWER_MGMT_TYPE_PAUSE:
+queue_cfg->cur_cb = rte_eth_add_rx_callback(port_id, queue_id,
+rte_power_mgmt_pause, NULL);
+break;

default:
....

Will add in v6.

Quoted 26 lines
Quoted 26 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +25 -0
+}
+queue_cfg->cb_mode = mode;
+port_cfg[port_id].ref_cnt++;
+queue_cfg->pwr_mgmt_state = PMD_MGMT_ENABLED;
+return ret;
+
+failure_handler:
+if (port_cfg[port_id].ref_cnt == 0) {
+rte_free(port_cfg[port_id].queue_cfg);
+port_cfg[port_id].queue_cfg = NULL;
+}
+return ret;
+}
+
+int
+rte_power_pmd_mgmt_queue_disable(unsigned int lcore_id,
+uint16_t port_id,
+uint16_t queue_id)
+{
+struct pmd_queue_cfg *queue_cfg;
+
+if (port_cfg[port_id].ref_cnt <= 0)
+return -EINVAL;
+
+queue_cfg = &port_cfg[port_id].queue_cfg[queue_id];
Quoted 8 lines

lib/librte_power/rte_power_pmd_mgmt.c line 184

Quoted 6 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +6 -0
+
+if (queue_cfg->pwr_mgmt_state == PMD_MGMT_DISABLED)
+return -EINVAL;
+
+switch (queue_cfg->cb_mode) {
+case RTE_POWER_MGMT_TYPE_WAIT:

Think we need wakeup(lcore_id) here.

Not sure what you mean? Could you please elaborate?

Quoted 16 lines
Quoted 16 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +15 -0
+case RTE_POWER_MGMT_TYPE_PAUSE:
+rte_eth_remove_rx_callback(port_id, queue_id,
+   queue_cfg->cur_cb);
+break;
+case RTE_POWER_MGMT_TYPE_SCALE:
+rte_power_freq_max(lcore_id);
+rte_eth_remove_rx_callback(port_id, queue_id,
+   queue_cfg->cur_cb);
+rte_power_exit(lcore_id);
+break;
+}
+/* it's not recommend to free callback instance here.
+ * it cause memory leak which is a known issue.
+ */
+queue_cfg->cur_cb = NULL;
Quoted 8 lines

lib/librte_power/rte_power_pmd_mgmt.c line 204

Quoted 5 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +5 -0
+queue_cfg->pwr_mgmt_state = PMD_MGMT_DISABLED;
+port_cfg[port_id].ref_cnt--;
+
+if (port_cfg[port_id].ref_cnt == 0) {
+rte_free(port_cfg[port_id].queue_cfg);

It is not safe to do so, unless device is already stopped.
Otherwise you need some sync mechanism here (hand-made as bpf lib, or rcu online/offline, or...)

Not sure what you mean. We're not freeing the callback structure, we're freeing the local data structure holding the per-port status.

Quoted 5 lines
Quoted 5 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +4 -0
+port_cfg[port_id].queue_cfg = NULL;
+}
+return 0;
+}
Signature · 2 lines
Thanks,
Anatoly
#251 lore raw

Re: [dpdk-dev] [PATCH v4 04/10] power: add simple power management API and callback

Quoted 370 lines · Konstantin
Quoted 143 lines
Quoted 143 lines

Add a simple on/off switch that will enable saving power when no packets are arriving. It is based on counting the number of empty polls and, when the number reaches a certain threshold, entering an architecture-defined optimized power state that will either wait until a TSC timestamp expires, or when packets arrive.

This API support 1 port to multiple core use case.

This design leverage RX Callback mechnaism which allow three different power management methodology co exist.

1. umwait/umonitor:

The TSC timestamp is automatically calculated using current link speed and RX descriptor ring size, such that the sleep time is not longer than it would take for a NIC to fill its entire RX descriptor ring.

2. Pause instruction

Instead of move the core into deeper C state, this lightweight method use Pause instruction to relief the processor from busy polling.

3. Frequency Scaling
Reuse exist rte power library to scale up/down core frequency depend on traffic volume.

---
  lib/librte_power/meson.build           |   5 +-
  lib/librte_power/pmd_mgmt.h            |  49 ++++++
  lib/librte_power/rte_power_pmd_mgmt.c  | 208 +++++++++++++++++++++++++
  lib/librte_power/rte_power_pmd_mgmt.h  |  88 +++++++++++
  lib/librte_power/rte_power_version.map |   4 +
  5 files changed, 352 insertions(+), 2 deletions(-)

create mode 100644 lib/librte_power/pmd_mgmt.h create mode 100644 lib/librte_power/rte_power_pmd_mgmt.c create mode 100644 lib/librte_power/rte_power_pmd_mgmt.h

lib/librte_power/meson.build +3 -2
index 78c031c943..cc3c7a8646 100644
@@ -9,6 +9,7 @@ sources = files('rte_power.c', 'power_acpi_cpufreq.c',
  'power_kvm_vm.c', 'guest_channel.c',
  'rte_power_empty_poll.c',
  'power_pstate_cpufreq.c',
+'rte_power_pmd_mgmt.c',
  'power_common.c')
-headers = files('rte_power.h','rte_power_empty_poll.h')
-deps += ['timer']
+headers = files('rte_power.h','rte_power_empty_poll.h','rte_power_pmd_mgmt.h')
+deps += ['timer' ,'ethdev']
lib/librte_power/pmd_mgmt.h new file +49 -0
new file mode 100644
index 0000000000..756fbe20f7
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2020 Intel Corporation
+ */
+
+#ifndef _PMD_MGMT_H
+#define _PMD_MGMT_H
+
+/**
+ * @file
+ * Power Management
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Possible power management states of an ethdev port.
+ */
+enum pmd_mgmt_state {
+/** Device power management is disabled. */
+PMD_MGMT_DISABLED = 0,
+/** Device power management is enabled. */
+PMD_MGMT_ENABLED,
+};
+
+struct pmd_queue_cfg {
+enum pmd_mgmt_state pwr_mgmt_state;
+/**< Power mgmt Callback mode */
+enum rte_power_pmd_mgmt_type cb_mode;
+/**< Empty poll number */
+uint16_t empty_poll_stats;
+/**< Callback instance  */
+const struct rte_eth_rxtx_callback *cur_cb;
+} __rte_cache_aligned;
+
+struct pmd_port_cfg {
+int  ref_cnt;
+struct pmd_queue_cfg *queue_cfg;
+} __rte_cache_aligned;
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
lib/librte_power/rte_power_pmd_mgmt.c new file +27 -0
new file mode 100644
index 0000000000..35d2af46a4
@@ -0,0 +1,208 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2020 Intel Corporation
+ */
+
+#include <rte_lcore.h>
+#include <rte_cycles.h>
+#include <rte_malloc.h>
+#include <rte_ethdev.h>
+#include <rte_power_intrinsics.h>
+
+#include "rte_power_pmd_mgmt.h"
+#include "pmd_mgmt.h"
+
+
+#define EMPTYPOLL_MAX  512
+#define PAUSE_NUM  64
+
+static struct pmd_port_cfg port_cfg[RTE_MAX_ETHPORTS];
+
+static uint16_t
+rte_power_mgmt_umwait(uint16_t port_id, uint16_t qidx,
+struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx,
+uint16_t max_pkts __rte_unused, void *_  __rte_unused)
+{
+
+struct pmd_queue_cfg *q_conf;
+q_conf = &port_cfg[port_id].queue_cfg[qidx];
Quoted 8 lines

lib/librte_power/rte_power_pmd_mgmt.c line 31

Quoted 4 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +4 -0
+
+if (unlikely(nb_rx == 0)) {
+q_conf->empty_poll_stats++;
+if (unlikely(q_conf->empty_poll_stats > EMPTYPOLL_MAX)) {

Here and in other places - wouldn't it be better to empty_poll_max as configurable parameter, instead of constant value?

It would be more flexible, but i don't think it's "better" in the sense that providing additional options will only make using this (already under-utilized!) API harder than it needs to be.

Quoted 13 lines
Quoted 13 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +12 -0
+volatile void *target_addr;
+uint64_t expected, mask;
+uint16_t ret;
+
+/*
+ * get address of next descriptor in the RX
+ * ring for this queue, as well as expected
+ * value and a mask.
+ */
+ret = rte_eth_get_wake_addr(port_id, qidx,
+    &target_addr, &expected,
+    &mask);
Quoted 8 lines

lib/librte_power/rte_power_pmd_mgmt.c line 48

Quoted 5 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +5 -0
+if (ret == 0)
+/* -1ULL is maximum value for TSC */
+rte_power_monitor(target_addr,
+  expected, mask,
+  0, -1ULL);

Why not make timeout a user specified parameter?

This is meant to be an "easy to use" API, we were trying to keep the amount of configuration to an absolute minimum. If the user wants to use custom timeouts, they can do so with using rte_power_monitor API explicitly.

Quoted 16 lines
Quoted 16 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +15 -0
+}
+} else
+q_conf->empty_poll_stats = 0;
+
+return nb_rx;
+}
+
+static uint16_t
+rte_power_mgmt_pause(uint16_t port_id, uint16_t qidx,
+struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx,
+uint16_t max_pkts __rte_unused, void *_  __rte_unused)
+{
+struct pmd_queue_cfg *q_conf;
+int i;
+q_conf = &port_cfg[port_id].queue_cfg[qidx];
Quoted 8 lines

lib/librte_power/rte_power_pmd_mgmt.c line 69

Quoted 6 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +6 -0
+
+if (unlikely(nb_rx == 0)) {
+q_conf->empty_poll_stats++;
+if (unlikely(q_conf->empty_poll_stats > EMPTYPOLL_MAX)) {
+for (i = 0; i < PAUSE_NUM; i++)
+rte_pause();

Just rte_delay_us(timeout) instead of this loop?

Yes, seems better, thanks.

Quoted 27 lines
Quoted 27 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +26 -0
+}
+} else
+q_conf->empty_poll_stats = 0;
+
+return nb_rx;
+}
+
+static uint16_t
+rte_power_mgmt_scalefreq(uint16_t port_id, uint16_t qidx,
+struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx,
+uint16_t max_pkts __rte_unused, void *_  __rte_unused)
+{
+struct pmd_queue_cfg *q_conf;
+q_conf = &port_cfg[port_id].queue_cfg[qidx];
+
+if (unlikely(nb_rx == 0)) {
+q_conf->empty_poll_stats++;
+if (unlikely(q_conf->empty_poll_stats > EMPTYPOLL_MAX)) {
+/*scale down freq */
+rte_power_freq_min(rte_lcore_id());
+
+}
+} else {
+q_conf->empty_poll_stats = 0;
+/* scal up freq */
+rte_power_freq_max(rte_lcore_id());
Quoted 8 lines

lib/librte_power/rte_power_pmd_mgmt.c line 55

Quoted 5 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +5 -0
+}
+
+return nb_rx;
+}
+

Probably worth to mention in comments that these functions enable/disable are not MT safe.

Will do in v6.

Quoted 49 lines
Quoted 49 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +48 -0
+int
+rte_power_pmd_mgmt_queue_enable(unsigned int lcore_id,
+uint16_t port_id,
+uint16_t queue_id,
+enum rte_power_pmd_mgmt_type mode)
+{
+struct rte_eth_dev *dev;
+struct pmd_queue_cfg *queue_cfg;
+int ret = 0;
+
+RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
+dev = &rte_eth_devices[port_id];
+
+if (port_cfg[port_id].queue_cfg == NULL) {
+port_cfg[port_id].ref_cnt = 0;
+/* allocate memory for empty poll stats */
+port_cfg[port_id].queue_cfg  = rte_malloc_socket(NULL,
+sizeof(struct pmd_queue_cfg)
+* RTE_MAX_QUEUES_PER_PORT,
+0, dev->data->numa_node);
+if (port_cfg[port_id].queue_cfg == NULL)
+return -ENOMEM;
+}
+
+queue_cfg = &port_cfg[port_id].queue_cfg[queue_id];
+
+if (queue_cfg->pwr_mgmt_state == PMD_MGMT_ENABLED) {
+ret = -EINVAL;
+goto failure_handler;
+}
+
+switch (mode) {
+case RTE_POWER_MGMT_TYPE_WAIT:
+if (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_WAITPKG)) {
+ret = -ENOTSUP;
+goto failure_handler;
+}
+queue_cfg->cur_cb = rte_eth_add_rx_callback(port_id, queue_id,
+rte_power_mgmt_umwait, NULL);
+break;
+case RTE_POWER_MGMT_TYPE_SCALE:
+/* init scale freq */
+if (rte_power_init(lcore_id)) {
+ret = -EINVAL;
+goto failure_handler;
+}
+queue_cfg->cur_cb = rte_eth_add_rx_callback(port_id, queue_id,
+rte_power_mgmt_scalefreq, NULL);
Quoted 8 lines

lib/librte_power/rte_power_pmd_mgmt.c line 153

Quoted 5 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +5 -0
+break;
+case RTE_POWER_MGMT_TYPE_PAUSE:
+queue_cfg->cur_cb = rte_eth_add_rx_callback(port_id, queue_id,
+rte_power_mgmt_pause, NULL);
+break;

default:
....

Will add in v6.

Quoted 26 lines
Quoted 26 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +25 -0
+}
+queue_cfg->cb_mode = mode;
+port_cfg[port_id].ref_cnt++;
+queue_cfg->pwr_mgmt_state = PMD_MGMT_ENABLED;
+return ret;
+
+failure_handler:
+if (port_cfg[port_id].ref_cnt == 0) {
+rte_free(port_cfg[port_id].queue_cfg);
+port_cfg[port_id].queue_cfg = NULL;
+}
+return ret;
+}
+
+int
+rte_power_pmd_mgmt_queue_disable(unsigned int lcore_id,
+uint16_t port_id,
+uint16_t queue_id)
+{
+struct pmd_queue_cfg *queue_cfg;
+
+if (port_cfg[port_id].ref_cnt <= 0)
+return -EINVAL;
+
+queue_cfg = &port_cfg[port_id].queue_cfg[queue_id];
Quoted 8 lines

lib/librte_power/rte_power_pmd_mgmt.c line 184

Quoted 6 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +6 -0
+
+if (queue_cfg->pwr_mgmt_state == PMD_MGMT_DISABLED)
+return -EINVAL;
+
+switch (queue_cfg->cb_mode) {
+case RTE_POWER_MGMT_TYPE_WAIT:

Think we need wakeup(lcore_id) here.

Not sure what you mean? Could you please elaborate?

Quoted 16 lines
Quoted 16 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +15 -0
+case RTE_POWER_MGMT_TYPE_PAUSE:
+rte_eth_remove_rx_callback(port_id, queue_id,
+   queue_cfg->cur_cb);
+break;
+case RTE_POWER_MGMT_TYPE_SCALE:
+rte_power_freq_max(lcore_id);
+rte_eth_remove_rx_callback(port_id, queue_id,
+   queue_cfg->cur_cb);
+rte_power_exit(lcore_id);
+break;
+}
+/* it's not recommend to free callback instance here.
+ * it cause memory leak which is a known issue.
+ */
+queue_cfg->cur_cb = NULL;
Quoted 8 lines

lib/librte_power/rte_power_pmd_mgmt.c line 204

Quoted 5 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +5 -0
+queue_cfg->pwr_mgmt_state = PMD_MGMT_DISABLED;
+port_cfg[port_id].ref_cnt--;
+
+if (port_cfg[port_id].ref_cnt == 0) {
+rte_free(port_cfg[port_id].queue_cfg);

It is not safe to do so, unless device is already stopped.
Otherwise you need some sync mechanism here (hand-made as bpf lib, or rcu online/offline, or...)

Quoted 2 lines

Not sure what you mean. We're not freeing the callback structure, we're freeing the local data structure holding the per-port status.

What is the difference?
You still trying to free memory that might be used by your DP thread that still executes the callback.

Quoted 11 lines
Quoted 6 lines

lib/librte_power/rte_power_pmd_mgmt.c line 208

Quoted 6 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +4 -0
+port_cfg[port_id].queue_cfg = NULL;
+}
+return 0;
+}

--
Thanks,
Anatoly

#252 lore raw

Re: [dpdk-dev] [PATCH v4 04/10] power: add simple power management API and callback

Quoted 25 lines · Konstantin
Quoted 25 lines
Quoted 24 lines
Quoted 11 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +10 -0
+case RTE_POWER_MGMT_TYPE_PAUSE:
+rte_eth_remove_rx_callback(port_id, queue_id,
+   queue_cfg->cur_cb);
+break;
+case RTE_POWER_MGMT_TYPE_SCALE:
+rte_power_freq_max(lcore_id);
+rte_eth_remove_rx_callback(port_id, queue_id,
+   queue_cfg->cur_cb);
+rte_power_exit(lcore_id);
+break;

lib/librte_power/rte_power_pmd_mgmt.c line 204

Quoted 10 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +10 -0
+}
+/* it's not recommend to free callback instance here.
+ * it cause memory leak which is a known issue.
+ */
+queue_cfg->cur_cb = NULL;
+queue_cfg->pwr_mgmt_state = PMD_MGMT_DISABLED;
+port_cfg[port_id].ref_cnt--;
+
+if (port_cfg[port_id].ref_cnt == 0) {
+rte_free(port_cfg[port_id].queue_cfg);

It is not safe to do so, unless device is already stopped.
Otherwise you need some sync mechanism here (hand-made as bpf lib, or rcu online/offline, or...)

Quoted 6 lines
Quoted 2 lines

Not sure what you mean. We're not freeing the callback structure, we're freeing the local data structure holding the per-port status.

What is the difference?
You still trying to free memory that might be used by your DP thread that still executes the callback.

Welp, you're right :/ I'll see what i can do to fix it.

Signature · 2 lines
Thanks,
Anatoly
#253 lore raw

PATCH v4 5/10 net/ixgbe: implement power management API

In reply to Liang Ma

Implement support for the power management API by implementing a get_wake_addr function that will return an address of an RX ring's status bit.

---
 drivers/net/ixgbe/ixgbe_ethdev.c |  1 +
 drivers/net/ixgbe/ixgbe_rxtx.c   | 22 ++++++++++++++++++++++
 drivers/net/ixgbe/ixgbe_rxtx.h   |  2 ++
 3 files changed, 25 insertions(+)
drivers/net/ixgbe/ixgbe_ethdev.c +1 -0
index 0b98e210e7..30b3f416d4 100644
@@ -588,6 +588,7 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.udp_tunnel_port_del  = ixgbe_dev_udp_tunnel_port_del,
 	.tm_ops_get           = ixgbe_tm_ops_get,
 	.tx_done_cleanup      = ixgbe_dev_tx_done_cleanup,
+	.get_wake_addr        = ixgbe_get_wake_addr,
 };
 
 /*
drivers/net/ixgbe/ixgbe_rxtx.c +22 -0
index 977ecf5137..7a9fd2aec6 100644
@@ -1366,6 +1366,28 @@ const uint32_t
 		RTE_PTYPE_INNER_L3_IPV4_EXT | RTE_PTYPE_INNER_L4_UDP,
 };
 
+int ixgbe_get_wake_addr(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask)
+{
+	volatile union ixgbe_adv_rx_desc *rxdp;
+	struct ixgbe_rx_queue *rxq = rx_queue;
+	uint16_t desc;
+
+	desc = rxq->rx_tail;
+	rxdp = &rxq->rx_ring[desc];
+	/* watch for changes in status bit */
+	*tail_desc_addr = &rxdp->wb.upper.status_error;
+
+	/*
+	 * we expect the DD bit to be set to 1 if this descriptor was already
+	 * written to.
+	 */
+	*expected = rte_cpu_to_le_32(IXGBE_RXDADV_STAT_DD);
+	*mask = rte_cpu_to_le_32(IXGBE_RXDADV_STAT_DD);
+
+	return 0;
+}
+
 /* @note: fix ixgbe_dev_supported_ptypes_get() if any change here. */
 static inline uint32_t
 ixgbe_rxd_pkt_info_to_pkt_type(uint32_t pkt_info, uint16_t ptype_mask)
drivers/net/ixgbe/ixgbe_rxtx.h +2 -0
index 7e09291b22..75020fa2fc 100644
@@ -299,5 +299,7 @@ uint64_t ixgbe_get_tx_port_offloads(struct rte_eth_dev *dev);
 uint64_t ixgbe_get_rx_queue_offloads(struct rte_eth_dev *dev);
 uint64_t ixgbe_get_rx_port_offloads(struct rte_eth_dev *dev);
 uint64_t ixgbe_get_tx_queue_offloads(struct rte_eth_dev *dev);
+int ixgbe_get_wake_addr(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask);
 
 #endif /* _IXGBE_RXTX_H_ */
Signature · 1 line
2.17.1
#255 lore raw

PATCH v4 6/10 net/i40e: implement power management API

In reply to Liang Ma

Implement support for the power management API by implementing a get_wake_addr function that will return an address of an RX ring's status bit.

---
 drivers/net/i40e/i40e_ethdev.c |  1 +
 drivers/net/i40e/i40e_rxtx.c   | 23 +++++++++++++++++++++++
 drivers/net/i40e/i40e_rxtx.h   |  2 ++
 3 files changed, 26 insertions(+)
drivers/net/i40e/i40e_ethdev.c +1 -0
index 943cfe71dc..cab86f8ec9 100644
@@ -513,6 +513,7 @@ static const struct eth_dev_ops i40e_eth_dev_ops = {
 	.mtu_set                      = i40e_dev_mtu_set,
 	.tm_ops_get                   = i40e_tm_ops_get,
 	.tx_done_cleanup              = i40e_tx_done_cleanup,
+	.get_wake_addr	              = i40e_get_wake_addr,
 };
 
 /* store statistics names and its offset in stats structure */
drivers/net/i40e/i40e_rxtx.c +23 -0
index 322fc1ed75..c17f27292f 100644
@@ -71,6 +71,29 @@
 #define I40E_TX_OFFLOAD_NOTSUP_MASK \
 		(PKT_TX_OFFLOAD_MASK ^ I40E_TX_OFFLOAD_MASK)
 
+int
+i40e_get_wake_addr(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask)
+{
+	struct i40e_rx_queue *rxq = rx_queue;
+	volatile union i40e_rx_desc *rxdp;
+	uint16_t desc;
+
+	desc = rxq->rx_tail;
+	rxdp = &rxq->rx_ring[desc];
+	/* watch for changes in status bit */
+	*tail_desc_addr = &rxdp->wb.qword1.status_error_len;
+
+	/*
+	 * we expect the DD bit to be set to 1 if this descriptor was already
+	 * written to.
+	 */
+	*expected = rte_cpu_to_le_64(1 << I40E_RX_DESC_STATUS_DD_SHIFT);
+	*mask = rte_cpu_to_le_64(1 << I40E_RX_DESC_STATUS_DD_SHIFT);
+
+	return 0;
+}
+
 static inline void
 i40e_rxd_to_vlan_tci(struct rte_mbuf *mb, volatile union i40e_rx_desc *rxdp)
 {
drivers/net/i40e/i40e_rxtx.h +2 -0
index 57d7b4160b..f23a2073e3 100644
@@ -248,6 +248,8 @@ uint16_t i40e_recv_scattered_pkts_vec_avx2(void *rx_queue,
 	struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
 uint16_t i40e_xmit_pkts_vec_avx2(void *tx_queue, struct rte_mbuf **tx_pkts,
 	uint16_t nb_pkts);
+int i40e_get_wake_addr(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *value);
 
 /* For each value it means, datasheet of hardware can tell more details
  *
Signature · 1 line
2.17.1
#257 lore raw

PATCH v4 7/10 net/ice: implement power management API

In reply to Liang Ma

Implement support for the power management API by implementing a get_wake_addr function that will return an address of an RX ring's status bit.

---
 drivers/net/ice/ice_ethdev.c |  1 +
 drivers/net/ice/ice_rxtx.c   | 23 +++++++++++++++++++++++
 drivers/net/ice/ice_rxtx.h   |  2 ++
 3 files changed, 26 insertions(+)
drivers/net/ice/ice_ethdev.c +1 -0
index d8ce09d28f..260de5dfd7 100644
@@ -216,6 +216,7 @@ static const struct eth_dev_ops ice_eth_dev_ops = {
 	.udp_tunnel_port_add          = ice_dev_udp_tunnel_port_add,
 	.udp_tunnel_port_del          = ice_dev_udp_tunnel_port_del,
 	.tx_done_cleanup              = ice_tx_done_cleanup,
+	.get_wake_addr	              = ice_get_wake_addr,
 };
 
 /* store statistics names and its offset in stats structure */
drivers/net/ice/ice_rxtx.c +23 -0
index 93a0ac6918..9e55eca942 100644
@@ -25,6 +25,29 @@ uint64_t rte_net_ice_dynflag_proto_xtr_ipv6_flow_mask;
 uint64_t rte_net_ice_dynflag_proto_xtr_tcp_mask;
 uint64_t rte_net_ice_dynflag_proto_xtr_ip_offset_mask;
 
+int ice_get_wake_addr(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask)
+{
+	volatile union ice_rx_flex_desc *rxdp;
+	struct ice_rx_queue *rxq = rx_queue;
+	uint16_t desc;
+
+	desc = rxq->rx_tail;
+	rxdp = &rxq->rx_ring[desc];
+	/* watch for changes in status bit */
+	*tail_desc_addr = &rxdp->wb.status_error0;
+
+	/*
+	 * we expect the DD bit to be set to 1 if this descriptor was already
+	 * written to.
+	 */
+	*expected = rte_cpu_to_le_16(1 << ICE_RX_FLEX_DESC_STATUS0_DD_S);
+	*mask = rte_cpu_to_le_16(1 << ICE_RX_FLEX_DESC_STATUS0_DD_S);
+
+	return 0;
+}
+
+
 static inline uint8_t
 ice_proto_xtr_type_to_rxdid(uint8_t xtr_type)
 {
drivers/net/ice/ice_rxtx.h +2 -0
index 1c23c7541e..c729e474c9 100644
@@ -250,6 +250,8 @@ uint16_t ice_xmit_pkts_vec_avx2(void *tx_queue, struct rte_mbuf **tx_pkts,
 				uint16_t nb_pkts);
 int ice_fdir_programming(struct ice_pf *pf, struct ice_fltr_desc *fdir_desc);
 int ice_tx_done_cleanup(void *txq, uint32_t free_cnt);
+int ice_get_wake_addr(void *rx_queue, volatile void **tail_desc_addr,
+		      uint64_t *expected, uint64_t *mask);
 
 #define FDIR_PARSING_ENABLE_PER_QUEUE(ad, on) do { \
 	int i; \
Signature · 1 line
2.17.1
#258 lore raw

PATCH v4 8/10 examples/l3fwd-power: enable PMD power mgmt

In reply to Liang Ma

Add pmd power mgmt feature support.

---
 examples/l3fwd-power/main.c | 44 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 43 insertions(+), 1 deletion(-)
examples/l3fwd-power/main.c +43 -1
index d0e6c9bd77..b1b139129a 100644
@@ -47,6 +47,8 @@
 #include <rte_power_empty_poll.h>
 #include <rte_metrics.h>
 #include <rte_telemetry.h>
+#include <rte_power_pmd_mgmt.h>
+
 
 #include "perf_core.h"
 #include "main.h"
@@ -199,7 +201,8 @@ enum appmode {
 	APP_MODE_LEGACY,
 	APP_MODE_EMPTY_POLL,
 	APP_MODE_TELEMETRY,
-	APP_MODE_INTERRUPT
+	APP_MODE_INTERRUPT,
+	APP_MODE_PMD_MGMT
 };
 
 enum appmode app_mode;
@@ -1750,6 +1753,7 @@ parse_ep_config(const char *q_arg)
 #define CMD_LINE_OPT_EMPTY_POLL "empty-poll"
 #define CMD_LINE_OPT_INTERRUPT_ONLY "interrupt-only"
 #define CMD_LINE_OPT_TELEMETRY "telemetry"
+#define CMD_LINE_OPT_PMD_MGMT "pmd-mgmt"
 
 /* Parse the argument given in the command line of the application */
 static int
@@ -1771,6 +1775,7 @@ parse_args(int argc, char **argv)
 		{CMD_LINE_OPT_LEGACY, 0, 0, 0},
 		{CMD_LINE_OPT_TELEMETRY, 0, 0, 0},
 		{CMD_LINE_OPT_INTERRUPT_ONLY, 0, 0, 0},
+		{CMD_LINE_OPT_PMD_MGMT, 0, 0, 0},
 		{NULL, 0, 0, 0}
 	};
 
@@ -1881,6 +1886,16 @@ parse_args(int argc, char **argv)
 				printf("telemetry mode is enabled\n");
 			}
 
+			if (!strncmp(lgopts[option_index].name,
+					CMD_LINE_OPT_PMD_MGMT,
+					sizeof(CMD_LINE_OPT_PMD_MGMT))) {
+				if (app_mode != APP_MODE_DEFAULT) {
+					printf(" power mgmt mode is mutually exclusive with other modes\n");
+					return -1;
+				}
+				app_mode = APP_MODE_PMD_MGMT;
+				printf("PMD power mgmt  mode is enabled\n");
+			}
 			if (!strncmp(lgopts[option_index].name,
 					CMD_LINE_OPT_INTERRUPT_ONLY,
 					sizeof(CMD_LINE_OPT_INTERRUPT_ONLY))) {
@@ -2437,6 +2452,9 @@ mode_to_str(enum appmode mode)
 		return "telemetry";
 	case APP_MODE_INTERRUPT:
 		return "interrupt-only";
+	case APP_MODE_PMD_MGMT:
+		return "pmd mgmt";
+
 	default:
 		return "invalid";
 	}
@@ -2705,6 +2723,12 @@ main(int argc, char **argv)
 			} else if (!check_ptype(portid))
 				rte_exit(EXIT_FAILURE,
 					 "PMD can not provide needed ptypes\n");
+			if (app_mode == APP_MODE_PMD_MGMT) {
+				rte_power_pmd_mgmt_queue_enable(lcore_id,
+							portid, queueid,
+						RTE_POWER_MGMT_TYPE_SCALE);
+
+			}
 		}
 	}
 
@@ -2790,8 +2814,12 @@ main(int argc, char **argv)
 						SKIP_MASTER);
 	} else if (app_mode == APP_MODE_INTERRUPT) {
 		rte_eal_mp_remote_launch(main_intr_loop, NULL, CALL_MASTER);
+	} else if (app_mode == APP_MODE_PMD_MGMT) {
+		rte_eal_mp_remote_launch(main_telemetry_loop, NULL,
+					 CALL_MASTER);
 	}
 
+
 	if (app_mode == APP_MODE_EMPTY_POLL || app_mode == APP_MODE_TELEMETRY)
 		launch_timer(rte_lcore_id());
 
@@ -2812,6 +2840,20 @@ main(int argc, char **argv)
 	if (app_mode == APP_MODE_EMPTY_POLL)
 		rte_power_empty_poll_stat_free();
 
+	if (app_mode == APP_MODE_PMD_MGMT) {
+		for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
+			if (rte_lcore_is_enabled(lcore_id) == 0)
+				continue;
+			qconf = &lcore_conf[lcore_id];
+			for (queue = 0; queue < qconf->n_rx_queue; ++queue) {
+				portid = qconf->rx_queue_list[queue].port_id;
+				queueid = qconf->rx_queue_list[queue].queue_id;
+				rte_power_pmd_mgmt_queue_disable(lcore_id,
+							portid, queueid);
+			}
+		}
+	}
+
 	if ((app_mode == APP_MODE_LEGACY || app_mode == APP_MODE_EMPTY_POLL) &&
 			deinit_power_library())
 		rte_exit(EXIT_FAILURE, "deinit_power_library failed\n");
Signature · 1 line
2.17.1
#259 lore raw

PATCH v4 9/10 doc: update release notes for PMD power management

In reply to Liang Ma

Add release notes for PMD power management

---
 doc/guides/rel_notes/release_20_11.rst | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
doc/guides/rel_notes/release_20_11.rst +16 -0
index c2175f37f3..57ac73722a 100644
@@ -55,6 +55,11 @@ New Features
      Also, make sure to start the actual text at the margin.
      =======================================================
 
+* **ethdev: add 1 new EXPERIMENTAL API for PMD power management.**
+
+  * ``rte_eth_get_wake_addr()``
+  * add new eth_dev_ops ``get_wake_addr``
+
 * **Updated Broadcom bnxt driver.**
 
   Updated the Broadcom bnxt driver with new features and improvements, including:
@@ -107,6 +112,17 @@ New Features
   * Extern objects and functions can be plugged into the pipeline.
   * Transaction-oriented table updates.
 
+* **Add PMD power management mechanism**
+
+  3 new PMD power managmeent mechanism is added through existing
+  RX_ETH_CALLBACK infrastructure.
+
+  * Add umwait power saving scheme
+  * Add pause power saving scheme
+  * Add frequency scaling power saving scheme
+  * Add new EXPERIMENTAL API ``rte_power_pmd_mgmt_queue_enable()``
+  * Add new EXPERIMENTAL API ``rte_power_pmd_mgmt_queue_disable()``
+
 
 Removed Items
 -------------
Signature · 1 line
2.17.1
#260 lore raw

PATCH v4 10/10 doc: update the programming guide for PMD power management

In reply to Liang Ma

Update programming guide and sample application l3fwd-power document for PMD power management

---
 doc/guides/prog_guide/power_man.rst           | 40 +++++++++++++++++++
 .../sample_app_ug/l3_forward_power_man.rst    | 15 ++++++-
 2 files changed, 54 insertions(+), 1 deletion(-)
doc/guides/prog_guide/power_man.rst +40 -0
index 0a3755a901..c95b948874 100644
@@ -188,6 +188,43 @@ API Overview for Empty Poll Power Management
 
 * **Detect empty poll state change**: empty poll state change detection algorithm then take action.
 
+PMD Power Management API
+------------------------
+
+Abstract
+~~~~~~~~
+Given existing power management mechanism, developer need change application design or code to use it.
+In order to solve the problem, it's very helpful to make the design transparent to application.
+The proposed solution is to leverage RX_CALLBACK mechanism which allow three different power management
+methodology co exist. The trigger condition is empty poll number beyond defined threshold.
+
+  * umwait/umonitor
+
+   The new umwait/umonitor instruction monitoring the wake address then transfer processor to sub-state.
+   Once the content of address is changed, the processor will be wake up from the sub-state. Timeout is
+   setup as well, in case, there is no wake event happen, processor still will wake up after timeout
+   timer expired.
+
+  * Pause instruction
+
+   Instead of move the core into deeper C state, this lightweight method use Pause instruction
+   to relief the processor from busy polling.
+
+  * Frequency Scaling
+
+   Reuse exist rte power library to scale up/down core frequency
+   depend on traffic volume.
+
+The proposed solution support multiple port and each port can map to multiple core. But 1 core only can map
+1 queue(regardless which port). In theory, each queue belongs to same port can apply different power scheme.
+It's strongly recommend to use same power scheme for all queues belong to same port.
+
+API Overview for PMD Power Management
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* **Queue Enable**: Enable specific power scheme for certain queue/port/core
+
+* **Queue Disable**: Disable power scheme for certain queue/port/core
+
 User Cases
 ----------
 The mechanism can applied to any device which is based on polling. e.g. NIC, FPGA.
@@ -200,3 +237,6 @@ References
 
 *   The :doc:`../sample_app_ug/vm_power_management`
     chapter in the :doc:`../sample_app_ug/index` section.
+
+*   The :doc:`../sample_app_ug/rxtx_callbacks`
+    chapter in the :doc:`../sample_app_ug/index` section.
doc/guides/sample_app_ug/l3_forward_power_man.rst +14 -1
index 0cc6f2e62e..82f9ac849c 100644
@@ -107,7 +107,9 @@ where,
 
 *   --empty-poll: Traffic Aware power management. See below for details
 
-*   --telemetry:  Telemetry mode.
+*   --telemetry: Telemetry mode.
+
+*   --pmd-mgmt: PMD power management mode.
 
 See :doc:`l3_forward` for details.
 The L3fwd-power example reuses the L3fwd command line options.
@@ -459,3 +461,14 @@ reference cycles and accordingly busy rate is set  to either 0% or
 
 The new stats ``empty_poll`` , ``full_poll`` and ``busy_percent`` can be viewed by running the script
 ``/usertools/dpdk-telemetry-client.py`` and selecting the menu option ``Send for global Metrics``.
+
+PMD power management Mode
+-------------------------
+
+The PMD power management  mode support for ``l3fwd-power`` is a standalone mode, in this mode
+``l3fwd-power`` does simple l3fwding along with enable the power saving scheme on specific
+port/queue/lcore. Main purpose for this mode is to demonstrate how to use the PMD power management API.
+
+.. code-block:: console
+
+        ./examples/l3fwd-power/build/l3fwd-power --pmd-mgmt -l 1-3 -- -p 0x0f --config="(0,0,2),(0,1,3)"
Signature · 1 line
2.17.1
#261 lore raw

Re: [dpdk-dev] [PATCH v4 01/10] eal: add new x86 cpuid support for WAITPKG

In reply to Liang Ma
Quoted 16 lines · Liang Ma

Add new x86 cpuid support for WAITPKG.
This flag indicate processor support umwait/umonitor/tpause instruction.

---
 lib/librte_eal/x86/include/rte_cpuflags.h | 2 ++
 lib/librte_eal/x86/rte_cpuflags.c         | 2 ++
 2 files changed, 4 insertions(+)
lib/librte_eal/x86/include/rte_cpuflags.h +0 -0
index c1d20364d1..5041a830a7 100644

lib/librte_eal/x86/include/rte_cpuflags.h enum rte_cpu_flag_t { · line 136

Quoted 5 lines
lib/librte_eal/x86/include/rte_cpuflags.h +2 -0
@@ -132,6 +132,8 @@ enum rte_cpu_flag_t {
 	RTE_CPUFLAG_MOVDIR64B,              /**< Direct Store Instructions 64B */
 	RTE_CPUFLAG_AVX512VP2INTERSECT,     /**< AVX512 Two Register Intersection */
 
+	/**< UMWAIT/TPAUSE Instructions */
+	RTE_CPUFLAG_WAITPKG,                /**< UMINITOR/UMWAIT/TPAUSE */

Typo: UMINITOR

Quoted 19 lines
lib/librte_eal/x86/include/rte_cpuflags.h +0 -0
 	/* The last item */
 	RTE_CPUFLAG_NUMFLAGS,               /**< This should always be the last! */
 };
lib/librte_eal/x86/rte_cpuflags.c +2 -0
index 30439e7951..0325c4b93b 100644
@@ -110,6 +110,8 @@ const struct feature_entry rte_cpu_feature_table[] = {
 	FEAT_DEF(AVX512F, 0x00000007, 0, RTE_REG_EBX, 16)
 	FEAT_DEF(RDSEED, 0x00000007, 0, RTE_REG_EBX, 18)
 
+	FEAT_DEF(WAITPKG, 0x00000007, 0, RTE_REG_ECX, 5)
+
 	FEAT_DEF(LAHF_SAHF, 0x80000001, 0, RTE_REG_ECX,  0)
 	FEAT_DEF(LZCNT, 0x80000001, 0, RTE_REG_ECX,  4)
 
Signature · 1 line
2.17.1
Acked-by on v4 1/10
#262 lore raw

Re: [dpdk-dev] [PATCH v4 01/10] eal: add new x86 cpuid support for WAITPKG

In reply to Liang Ma
Quoted 30 lines

Add new x86 cpuid support for WAITPKG.
This flag indicate processor support umwait/umonitor/tpause instruction.

---
 lib/librte_eal/x86/include/rte_cpuflags.h | 2 ++
 lib/librte_eal/x86/rte_cpuflags.c         | 2 ++
 2 files changed, 4 insertions(+)
lib/librte_eal/x86/include/rte_cpuflags.h +2 -0
index c1d20364d1..5041a830a7 100644
@@ -132,6 +132,8 @@ enum rte_cpu_flag_t {
 	RTE_CPUFLAG_MOVDIR64B,              /**< Direct Store Instructions 64B */
 	RTE_CPUFLAG_AVX512VP2INTERSECT,     /**< AVX512 Two Register Intersection */
 
+	/**< UMWAIT/TPAUSE Instructions */
+	RTE_CPUFLAG_WAITPKG,                /**< UMINITOR/UMWAIT/TPAUSE */
 	/* The last item */
 	RTE_CPUFLAG_NUMFLAGS,               /**< This should always be the last! */
 };
lib/librte_eal/x86/rte_cpuflags.c +0 -0
index 30439e7951..0325c4b93b 100644

lib/librte_eal/x86/rte_cpuflags.c const struct feature_entry rte_cpu_feature_table[] = {

Quoted 9 lines
lib/librte_eal/x86/rte_cpuflags.c +2 -1
@@ -110,6 +110,8 @@ const struct feature_entry rte_cpu_feature_table[] = {
 	FEAT_DEF(AVX512F, 0x00000007, 0, RTE_REG_EBX, 16)
 	FEAT_DEF(RDSEED, 0x00000007, 0, RTE_REG_EBX, 18)
 
+	FEAT_DEF(WAITPKG, 0x00000007, 0, RTE_REG_ECX, 5)
+
 	FEAT_DEF(LAHF_SAHF, 0x80000001, 0, RTE_REG_ECX,  0)
 	FEAT_DEF(LZCNT, 0x80000001, 0, RTE_REG_ECX,  4)
 
--
Quoted 1 line

2.17.1

#263 lore raw

PATCH v5 1/10 eal: add new x86 cpuid support for WAITPKG

In reply to Liang Ma

From: Liang Ma <[email protected]>

Add new x86 cpuid support for WAITPKG.
This flag indicate processor support umwait/umonitor/tpause instruction.

---
 lib/librte_eal/x86/include/rte_cpuflags.h | 2 ++
 lib/librte_eal/x86/rte_cpuflags.c         | 2 ++
 2 files changed, 4 insertions(+)
lib/librte_eal/x86/include/rte_cpuflags.h +2 -0
index c1d20364d1..5041a830a7 100644
@@ -132,6 +132,8 @@ enum rte_cpu_flag_t {
 	RTE_CPUFLAG_MOVDIR64B,              /**< Direct Store Instructions 64B */
 	RTE_CPUFLAG_AVX512VP2INTERSECT,     /**< AVX512 Two Register Intersection */
 
+	/**< UMWAIT/TPAUSE Instructions */
+	RTE_CPUFLAG_WAITPKG,                /**< UMINITOR/UMWAIT/TPAUSE */
 	/* The last item */
 	RTE_CPUFLAG_NUMFLAGS,               /**< This should always be the last! */
 };
lib/librte_eal/x86/rte_cpuflags.c +2 -0
index 30439e7951..0325c4b93b 100644
@@ -110,6 +110,8 @@ const struct feature_entry rte_cpu_feature_table[] = {
 	FEAT_DEF(AVX512F, 0x00000007, 0, RTE_REG_EBX, 16)
 	FEAT_DEF(RDSEED, 0x00000007, 0, RTE_REG_EBX, 18)
 
+	FEAT_DEF(WAITPKG, 0x00000007, 0, RTE_REG_ECX, 5)
+
 	FEAT_DEF(LAHF_SAHF, 0x80000001, 0, RTE_REG_ECX,  0)
 	FEAT_DEF(LZCNT, 0x80000001, 0, RTE_REG_ECX,  4)
 
Signature · 1 line
2.17.1
#264 lore raw

PATCH v5 2/10 eal: add power management intrinsics

From: Liang Ma <[email protected]>

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

For more details, please refer to Intel(R) 64 and IA-32 Architectures Software Developer's Manual, Volume 2.

---

Notes:
v5:
- Removed return values
- Simplified intrinsics and hardcoded C0.2 state
- Added other arch stubs

 lib/librte_eal/arm/include/meson.build        |   1 +
 .../arm/include/rte_power_intrinsics.h        |  62 ++++++++++
 .../include/generic/rte_power_intrinsics.h    |  61 ++++++++++
 lib/librte_eal/include/meson.build            |   1 +
 lib/librte_eal/ppc/include/meson.build        |   1 +
 .../ppc/include/rte_power_intrinsics.h        |  62 ++++++++++
 lib/librte_eal/x86/include/meson.build        |   1 +
 .../x86/include/rte_power_intrinsics.h        | 106 ++++++++++++++++++
 8 files changed, 295 insertions(+)
 create mode 100644 lib/librte_eal/arm/include/rte_power_intrinsics.h
 create mode 100644 lib/librte_eal/include/generic/rte_power_intrinsics.h
 create mode 100644 lib/librte_eal/ppc/include/rte_power_intrinsics.h
 create mode 100644 lib/librte_eal/x86/include/rte_power_intrinsics.h
lib/librte_eal/arm/include/meson.build +1 -0
index 73b750a18f..c6a9f70d73 100644
@@ -20,6 +20,7 @@ arch_headers = files(
 	'rte_pause_32.h',
 	'rte_pause_64.h',
 	'rte_pause.h',
+	'rte_power_intrinsics.h',
 	'rte_prefetch_32.h',
 	'rte_prefetch_64.h',
 	'rte_prefetch.h',
lib/librte_eal/arm/include/rte_power_intrinsics.h new file +62 -0

62 lines not on this page · raw message

lib/librte_eal/include/generic/rte_power_intrinsics.h new file +61 -0

61 lines not on this page · raw message

lib/librte_eal/include/meson.build +1 -0
index cd09027958..3a12e87e19 100644
@@ -60,6 +60,7 @@ generic_headers = files(
 	'generic/rte_memcpy.h',
 	'generic/rte_pause.h',
 	'generic/rte_prefetch.h',
+	'generic/rte_power_intrinsics.h',
 	'generic/rte_rwlock.h',
 	'generic/rte_spinlock.h',
 	'generic/rte_ticketlock.h',
lib/librte_eal/ppc/include/meson.build +1 -0
index ab4bd28092..0873b2aecb 100644
@@ -10,6 +10,7 @@ arch_headers = files(
 	'rte_io.h',
 	'rte_memcpy.h',
 	'rte_pause.h',
+	'rte_power_intrinsics.h',
 	'rte_prefetch.h',
 	'rte_rwlock.h',
 	'rte_spinlock.h',
lib/librte_eal/ppc/include/rte_power_intrinsics.h new file +62 -0

62 lines not on this page · raw message

lib/librte_eal/x86/include/meson.build +1 -0
index f0e998c2fe..494a8142a2 100644
@@ -13,6 +13,7 @@ arch_headers = files(
 	'rte_io.h',
 	'rte_memcpy.h',
 	'rte_prefetch.h',
+	'rte_power_intrinsics.h',
 	'rte_pause.h',
 	'rte_rtm.h',
 	'rte_rwlock.h',
lib/librte_eal/x86/include/rte_power_intrinsics.h new file +106 -0

106 lines not on this page · raw message

Signature · 1 line
2.17.1
#265 lore raw

Re: [dpdk-dev] [PATCH v5 02/10] eal: add power management intrinsics

Quoted 81 lines · Anatoly Burakov

From: Liang Ma <[email protected]>

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

For more details, please refer to Intel(R) 64 and IA-32 Architectures Software Developer's Manual, Volume 2.

---

Notes:
v5:
- Removed return values
- Simplified intrinsics and hardcoded C0.2 state
- Added other arch stubs

 lib/librte_eal/arm/include/meson.build        |   1 +
 .../arm/include/rte_power_intrinsics.h        |  62 ++++++++++
 .../include/generic/rte_power_intrinsics.h    |  61 ++++++++++
 lib/librte_eal/include/meson.build            |   1 +
 lib/librte_eal/ppc/include/meson.build        |   1 +
 .../ppc/include/rte_power_intrinsics.h        |  62 ++++++++++
 lib/librte_eal/x86/include/meson.build        |   1 +
 .../x86/include/rte_power_intrinsics.h        | 106 ++++++++++++++++++
 8 files changed, 295 insertions(+)
 create mode 100644 lib/librte_eal/arm/include/rte_power_intrinsics.h
 create mode 100644 lib/librte_eal/include/generic/rte_power_intrinsics.h
 create mode 100644 lib/librte_eal/ppc/include/rte_power_intrinsics.h
 create mode 100644 lib/librte_eal/x86/include/rte_power_intrinsics.h
lib/librte_eal/arm/include/meson.build +1 -0
index 73b750a18f..c6a9f70d73 100644
@@ -20,6 +20,7 @@ arch_headers = files(
        'rte_pause_32.h',
        'rte_pause_64.h',
        'rte_pause.h',
+       'rte_power_intrinsics.h',
        'rte_prefetch_32.h',
        'rte_prefetch_64.h',
        'rte_prefetch.h',
lib/librte_eal/arm/include/rte_power_intrinsics.h new file +21 -0
new file mode 100644
index 0000000000..4aad44a0b9
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _RTE_POWER_INTRINSIC_ARM_H_
+#define _RTE_POWER_INTRINSIC_ARM_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_atomic.h>
+#include <rte_common.h>
+
+#include "generic/rte_power_intrinsics.h"
+
+/**
+ * This function is not supported on ARM.
+ *
+ * @param p
+ *   Address to monitor for changes. Must be aligned on an 64-byte boundary.

lib/librte_eal/arm/include/rte_power_intrinsics.h line 31

Quoted 10 lines
lib/librte_eal/arm/include/rte_power_intrinsics.h new file +10 -0
+ * @param expected_value
+ *   Before attempting the monitoring, the `p` address may be read and compared
+ *   against this value. If `value_mask` is zero, this step will be skipped.
+ * @param value_mask
+ *   The 64-bit mask to use to extract current value from `p`.
+ * @param tsc_timestamp
+ *   Maximum TSC timestamp to wait for.
+ *
+ * @return
+ *   - 0 on success

remove return as it is a void function

Quoted 316 lines
lib/librte_eal/arm/include/rte_power_intrinsics.h new file +31 -0
+ */
+static inline void rte_power_monitor(const volatile void *p,
+               const uint64_t expected_value, const uint64_t value_mask,
+               const uint64_t tsc_timestamp)
+{
+       RTE_SET_USED(p);
+       RTE_SET_USED(expected_value);
+       RTE_SET_USED(value_mask);
+       RTE_SET_USED(tsc_timestamp);
+}
+
+/**
+ * This function is not supported on ARM.
+ *
+ * @param tsc_timestamp
+ *   Maximum TSC timestamp to wait for.
+ *
+ * @return
+ *   - 1 if wakeup was due to TSC timeout expiration.
+ *   - 0 if wakeup was due to other reasons.
+ */
+static inline void rte_power_pause(const uint64_t tsc_timestamp)
+{
+       RTE_SET_USED(tsc_timestamp);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_POWER_INTRINSIC_ARM_H_ */
lib/librte_eal/include/generic/rte_power_intrinsics.h new file +61 -0
new file mode 100644
index 0000000000..e36c1f8976
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _RTE_POWER_INTRINSIC_H_
+#define _RTE_POWER_INTRINSIC_H_
+
+#include <inttypes.h>
+
+/**
+ * @file
+ * Advanced power management operations.
+ *
+ * This file define APIs for advanced power management,
+ * which are architecture-dependent.
+ */
+
+/**
+ * Monitor specific address for changes. This will cause the CPU to enter an
+ * architecture-defined optimized power state until either the specified
+ * memory address is written to, a certain TSC timestamp is reached, or other
+ * reasons cause the CPU to wake up.
+ *
+ * Additionally, an `expected` 64-bit value and 64-bit mask are provided. If
+ * mask is non-zero, the current value pointed to by the `p` pointer will be
+ * checked against the expected value, and if they match, the entering of
+ * optimized power state may be aborted.
+ *
+ * @param p
+ *   Address to monitor for changes. Must be aligned on an 64-byte boundary.
+ * @param expected_value
+ *   Before attempting the monitoring, the `p` address may be read and compared
+ *   against this value. If `value_mask` is zero, this step will be skipped.
+ * @param value_mask
+ *   The 64-bit mask to use to extract current value from `p`.
+ * @param tsc_timestamp
+ *   Maximum TSC timestamp to wait for. Note that the wait behavior is
+ *   architecture-dependent.
+ *
+ * @return
+ *   - 0 on success
+ *   - -ENOTSUP if not supported
+ */
+static inline void rte_power_monitor(const volatile void *p,
+               const uint64_t expected_value, const uint64_t value_mask,
+               const uint64_t tsc_timestamp);
+
+/**
+ * Enter an architecture-defined optimized power state until a certain TSC
+ * timestamp is reached.
+ *
+ * @param tsc_timestamp
+ *   Maximum TSC timestamp to wait for. Note that the wait behavior is
+ *   architecture-dependent.
+ *
+ * @return
+ *   Architecture-dependent return value.
+ */
+static inline void rte_power_pause(const uint64_t tsc_timestamp);
+
+#endif /* _RTE_POWER_INTRINSIC_H_ */
lib/librte_eal/include/meson.build +1 -0
index cd09027958..3a12e87e19 100644
@@ -60,6 +60,7 @@ generic_headers = files(
        'generic/rte_memcpy.h',
        'generic/rte_pause.h',
        'generic/rte_prefetch.h',
+       'generic/rte_power_intrinsics.h',
        'generic/rte_rwlock.h',
        'generic/rte_spinlock.h',
        'generic/rte_ticketlock.h',
lib/librte_eal/ppc/include/meson.build +1 -0
index ab4bd28092..0873b2aecb 100644
@@ -10,6 +10,7 @@ arch_headers = files(
        'rte_io.h',
        'rte_memcpy.h',
        'rte_pause.h',
+       'rte_power_intrinsics.h',
        'rte_prefetch.h',
        'rte_rwlock.h',
        'rte_spinlock.h',
lib/librte_eal/ppc/include/rte_power_intrinsics.h new file +62 -0
new file mode 100644
index 0000000000..70fd7b094f
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _RTE_POWER_INTRINSIC_PPC_H_
+#define _RTE_POWER_INTRINSIC_PPC_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_atomic.h>
+#include <rte_common.h>
+
+#include "generic/rte_power_intrinsics.h"
+
+/**
+ * This function is not supported on PPC64.
+ *
+ * @param p
+ *   Address to monitor for changes. Must be aligned on an 64-byte boundary.
+ * @param expected_value
+ *   Before attempting the monitoring, the `p` address may be read and compared
+ *   against this value. If `value_mask` is zero, this step will be skipped.
+ * @param value_mask
+ *   The 64-bit mask to use to extract current value from `p`.
+ * @param tsc_timestamp
+ *   Maximum TSC timestamp to wait for.
+ *
+ * @return
+ *   - 0 on success
+ */
+static inline void rte_power_monitor(const volatile void *p,
+               const uint64_t expected_value, const uint64_t value_mask,
+               const uint64_t tsc_timestamp)
+{
+       RTE_SET_USED(p);
+       RTE_SET_USED(expected_value);
+       RTE_SET_USED(value_mask);
+       RTE_SET_USED(tsc_timestamp);
+}
+
+/**
+ * This function is not supported on PPC64.
+ *
+ * @param tsc_timestamp
+ *   Maximum TSC timestamp to wait for.
+ *
+ * @return
+ *   - 1 if wakeup was due to TSC timeout expiration.
+ *   - 0 if wakeup was due to other reasons.
+ */
+static inline void rte_power_pause(const uint64_t tsc_timestamp)
+{
+       RTE_SET_USED(tsc_timestamp);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_POWER_INTRINSIC_PPC_H_ */
lib/librte_eal/x86/include/meson.build +1 -0
index f0e998c2fe..494a8142a2 100644
@@ -13,6 +13,7 @@ arch_headers = files(
        'rte_io.h',
        'rte_memcpy.h',
        'rte_prefetch.h',
+       'rte_power_intrinsics.h',
        'rte_pause.h',
        'rte_rtm.h',
        'rte_rwlock.h',
lib/librte_eal/x86/include/rte_power_intrinsics.h new file +106 -1
new file mode 100644
index 0000000000..8d579eaf64
@@ -0,0 +1,106 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _RTE_POWER_INTRINSIC_X86_64_H_
+#define _RTE_POWER_INTRINSIC_X86_64_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_atomic.h>
+#include <rte_common.h>
+
+#include "generic/rte_power_intrinsics.h"
+
+/**
+ * Monitor specific address for changes. This will cause the CPU to enter an
+ * architecture-defined optimized power state until either the specified
+ * memory address is written to, a certain TSC timestamp is reached, or other
+ * reasons cause the CPU to wake up.
+ *
+ * Additionally, an `expected` 64-bit value and 64-bit mask are provided. If
+ * mask is non-zero, the current value pointed to by the `p` pointer will be
+ * checked against the expected value, and if they match, the entering of
+ * optimized power state may be aborted.
+ *
+ * This function uses UMONITOR/UMWAIT instructions and will enter C0.2 state.
+ * For more information about usage of these instructions, please refer to
+ * Intel(R) 64 and IA-32 Architectures Software Developer's Manual.
+ *
+ * @param p
+ *   Address to monitor for changes. Must be aligned on an 64-byte boundary.
+ * @param expected_value
+ *   Before attempting the monitoring, the `p` address may be read and compared
+ *   against this value. If `value_mask` is zero, this step will be skipped.
+ * @param value_mask
+ *   The 64-bit mask to use to extract current value from `p`.
+ * @param tsc_timestamp
+ *   Maximum TSC timestamp to wait for.
+ *
+ * @return
+ *   - 0 on success
+ */
+static inline void rte_power_monitor(const volatile void *p,
+               const uint64_t expected_value, const uint64_t value_mask,
+               const uint64_t tsc_timestamp)
+{
+       const uint32_t tsc_l = (uint32_t)tsc_timestamp;
+       const uint32_t tsc_h = (uint32_t)(tsc_timestamp >> 32);
+       /*
+        * we're using raw byte codes for now as only the newest compiler
+        * versions support this instruction natively.
+        */
+
+       /* set address for UMONITOR */
+       asm volatile(".byte 0xf3, 0x0f, 0xae, 0xf7;"
+                       :
+                       : "D"(p));
+
+       if (value_mask) {
+               const uint64_t cur_value = *(const volatile uint64_t *)p;
+               const uint64_t masked = cur_value & value_mask;
+               /* if the masked value is already matching, abort */
+               if (masked == expected_value)
+                       return;
+       }
+       /* execute UMWAIT */
+       asm volatile(".byte 0xf2, 0x0f, 0xae, 0xf7;"
+               : /* ignore rflags */
+               : "D"(0), /* enter C0.2 */
+                 "a"(tsc_l), "d"(tsc_h));
+}
+
+/**
+ * Enter an architecture-defined optimized power state until a certain TSC
+ * timestamp is reached.
+ *
+ * This function uses TPAUSE instruction  and will enter C0.2 state. For more
+ * information about usage of this instruction, please refer to Intel(R) 64 and
+ * IA-32 Architectures Software Developer's Manual.
+ *
+ * @param tsc_timestamp
+ *   Maximum TSC timestamp to wait for.
+ *
+ * @return
+ *   - 1 if wakeup was due to TSC timeout expiration.
+ *   - 0 if wakeup was due to other reasons.
+ */
+static inline void rte_power_pause(const uint64_t tsc_timestamp)
+{
+       const uint32_t tsc_l = (uint32_t)tsc_timestamp;
+       const uint32_t tsc_h = (uint32_t)(tsc_timestamp >> 32);
+
+       /* execute TPAUSE */
+       asm volatile(".byte 0x66, 0x0f, 0xae, 0xf7;"
+                    : /* ignore rflags */
+                    : "D"(0), /* enter C0.2 */
+                      "a"(tsc_l), "d"(tsc_h));
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_POWER_INTRINSIC_X86_64_H_ */
--

2.17.1

#266 lore raw

Re: [dpdk-dev] [PATCH v5 02/10] eal: add power management intrinsics

Quoted 29 lines · Jerin Jacob
Quoted 27 lines · Anatoly Burakov

From: Liang Ma <[email protected]>

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

For more details, please refer to Intel(R) 64 and IA-32 Architectures Software Developer's Manual, Volume 2.

---

Notes:
v5:
- Removed return values
- Simplified intrinsics and hardcoded C0.2 state
- Added other arch stubs

<snip>

Quoted 11 lines
Quoted 11 lines
lib/librte_eal/arm/include/rte_power_intrinsics.h new file +11 -0
+
+/**
+ * This function is not supported on ARM.
+ *
+ * @param p
+ *   Address to monitor for changes. Must be aligned on an 64-byte boundary.
+ * @param expected_value
+ *   Before attempting the monitoring, the `p` address may be read and compared
+ *   against this value. If `value_mask` is zero, this step will be skipped.
+ * @param value_mask
+ *   The 64-bit mask to use to extract current value from `p`.
Quoted 8 lines
Quoted 5 lines

+ * @param tsc_timestamp
+ * Maximum TSC timestamp to wait for.
+ *
+ * @return
+ * - 0 on success

remove return as it is a void function

Oops, will fix in v6. Thanks!

Signature · 2 lines
Thanks,
Anatoly
Acked-by on v5 2/10
#267 lore raw

Re: [dpdk-dev] [PATCH v5 02/10] eal: add power management intrinsics

In reply to Anatoly Burakov
Quoted 27 lines · Anatoly Burakov

From: Liang Ma <[email protected]>

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

For more details, please refer to Intel(R) 64 and IA-32 Architectures Software Developer's Manual, Volume 2.

---

Notes:
v5:
- Removed return values
- Simplified intrinsics and hardcoded C0.2 state
- Added other arch stubs

... snip ...

Quoted 54 lines

+++ b/lib/librte_eal/ppc/include/rte_power_intrinsics.h

lib/librte_eal/ppc/include/rte_power_intrinsics.h new file +52 -0
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _RTE_POWER_INTRINSIC_PPC_H_
+#define _RTE_POWER_INTRINSIC_PPC_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_atomic.h>
+#include <rte_common.h>
+
+#include "generic/rte_power_intrinsics.h"
+
+/**
+ * This function is not supported on PPC64.
+ *
+ * @param p
+ *   Address to monitor for changes. Must be aligned on an 64-byte boundary.
+ * @param expected_value
+ *   Before attempting the monitoring, the `p` address may be read and compared
+ *   against this value. If `value_mask` is zero, this step will be skipped.
+ * @param value_mask
+ *   The 64-bit mask to use to extract current value from `p`.
+ * @param tsc_timestamp
+ *   Maximum TSC timestamp to wait for.
+ *
+ * @return
+ *   - 0 on success
+ */
+static inline void rte_power_monitor(const volatile void *p,
+		const uint64_t expected_value, const uint64_t value_mask,
+		const uint64_t tsc_timestamp)
+{
+	RTE_SET_USED(p);
+	RTE_SET_USED(expected_value);
+	RTE_SET_USED(value_mask);
+	RTE_SET_USED(tsc_timestamp);
+}
+
+/**
+ * This function is not supported on PPC64.
+ *
+ * @param tsc_timestamp
+ *   Maximum TSC timestamp to wait for.
+ *
+ * @return
+ *   - 1 if wakeup was due to TSC timeout expiration.
+ *   - 0 if wakeup was due to other reasons.
+ */

lib/librte_eal/ppc/include/rte_power_intrinsics.h line 62

Quoted 10 lines
lib/librte_eal/ppc/include/rte_power_intrinsics.h new file +10 -0
+static inline void rte_power_pause(const uint64_t tsc_timestamp)
+{
+	RTE_SET_USED(tsc_timestamp);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_POWER_INTRINSIC_PPC_H_ */

I didn't find an equivalent instruction in the current 3.1 ISA, so not supported is correct for POWER.

#268 lore raw

PATCH v5 3/10 eal: add intrinsics support check infrastructure

In reply to Anatoly Burakov

Currently, it is not possible to check support for intrinsics that are platform-specific, cannot be abstracted in a generic way, or do not have support on all architectures. The CPUID flags can be used to some extent, but they are only defined for their platform, while intrinsics will be available to all code as they are in generic headers.

This patch introduces infrastructure to check support for certain platform-specific intrinsics, and adds support for checking support for IA power management-related intrinsics for UMWAIT/UMONITOR and TPAUSE.

---
 .../arm/include/rte_power_intrinsics.h        |  8 ++++++
 lib/librte_eal/arm/rte_cpuflags.c             |  6 +++++
 lib/librte_eal/include/generic/rte_cpuflags.h | 26 +++++++++++++++++++
 .../include/generic/rte_power_intrinsics.h    |  8 ++++++
 .../ppc/include/rte_power_intrinsics.h        |  8 ++++++
 lib/librte_eal/ppc/rte_cpuflags.c             |  6 +++++
 lib/librte_eal/rte_eal_version.map            |  1 +
 .../x86/include/rte_power_intrinsics.h        |  8 ++++++
 lib/librte_eal/x86/rte_cpuflags.c             | 12 +++++++++
 9 files changed, 83 insertions(+)
lib/librte_eal/arm/include/rte_power_intrinsics.h +8 -0
index 4aad44a0b9..055ec5877a 100644
@@ -17,6 +17,10 @@ extern "C" {
 /**
  * This function is not supported on ARM.
  *
+ * @warning It is responsibility of the user to check if this function is
+ *   supported at runtime using `rte_cpu_get_features()` API call. Failing to do
+ *   so may result in an illegal CPU instruction error.
+ *
  * @param p
  *   Address to monitor for changes. Must be aligned on an 64-byte boundary.
  * @param expected_value
@@ -43,6 +47,10 @@ static inline void rte_power_monitor(const volatile void *p,
 /**
  * This function is not supported on ARM.
  *
+ * @warning It is responsibility of the user to check if this function is
+ *   supported at runtime using `rte_cpu_get_features()` API call. Failing to do
+ *   so may result in an illegal CPU instruction error.
+ *
  * @param tsc_timestamp
  *   Maximum TSC timestamp to wait for.
  *
lib/librte_eal/arm/rte_cpuflags.c +6 -0
index caf3dc83a5..7eef11fa02 100644
@@ -138,3 +138,9 @@ rte_cpu_get_flag_name(enum rte_cpu_flag_t feature)
 		return NULL;
 	return rte_cpu_feature_table[feature].name;
 }
+
+void
+rte_cpu_get_intrinsics_support(struct rte_cpu_intrinsics *intrinsics)
+{
+	memset(intrinsics, 0, sizeof(*intrinsics));
+}
lib/librte_eal/include/generic/rte_cpuflags.h +26 -0
index 872f0ebe3e..28a5aecde8 100644
@@ -13,6 +13,32 @@
 #include "rte_common.h"
 #include <errno.h>
 
+#include <rte_compat.h>
+
+/**
+ * Structure used to describe platform-specific intrinsics that may or may not
+ * be supported at runtime.
+ */
+struct rte_cpu_intrinsics {
+	uint32_t power_monitor : 1;
+	/**< indicates support for rte_power_monitor function */
+	uint32_t power_pause : 1;
+	/**< indicates support for rte_power_pause function */
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Check CPU support for various intrinsics at runtime.
+ *
+ * @param intrinsics
+ *     Pointer to a structure to be filled.
+ */
+__rte_experimental
+void
+rte_cpu_get_intrinsics_support(struct rte_cpu_intrinsics *intrinsics);
+
 /**
  * Enumeration of all CPU features supported
  */
lib/librte_eal/include/generic/rte_power_intrinsics.h +8 -0
index e36c1f8976..218eda7e86 100644
@@ -26,6 +26,10 @@
  * checked against the expected value, and if they match, the entering of
  * optimized power state may be aborted.
  *
+ * @warning It is responsibility of the user to check if this function is
+ *   supported at runtime using `rte_cpu_get_features()` API call. Failing to do
+ *   so may result in an illegal CPU instruction error.
+ *
  * @param p
  *   Address to monitor for changes. Must be aligned on an 64-byte boundary.
  * @param expected_value
@@ -49,6 +53,10 @@ static inline void rte_power_monitor(const volatile void *p,
  * Enter an architecture-defined optimized power state until a certain TSC
  * timestamp is reached.
  *
+ * @warning It is responsibility of the user to check if this function is
+ *   supported at runtime using `rte_cpu_get_features()` API call. Failing to do
+ *   so may result in an illegal CPU instruction error.
+ *
  * @param tsc_timestamp
  *   Maximum TSC timestamp to wait for. Note that the wait behavior is
  *   architecture-dependent.
lib/librte_eal/ppc/include/rte_power_intrinsics.h +8 -0
index 70fd7b094f..d63ad86849 100644
@@ -17,6 +17,10 @@ extern "C" {
 /**
  * This function is not supported on PPC64.
  *
+ * @warning It is responsibility of the user to check if this function is
+ *   supported at runtime using `rte_cpu_get_features()` API call. Failing to do
+ *   so may result in an illegal CPU instruction error.
+ *
  * @param p
  *   Address to monitor for changes. Must be aligned on an 64-byte boundary.
  * @param expected_value
@@ -43,6 +47,10 @@ static inline void rte_power_monitor(const volatile void *p,
 /**
  * This function is not supported on PPC64.
  *
+ * @warning It is responsibility of the user to check if this function is
+ *   supported at runtime using `rte_cpu_get_features()` API call. Failing to do
+ *   so may result in an illegal CPU instruction error.
+ *
  * @param tsc_timestamp
  *   Maximum TSC timestamp to wait for.
  *
lib/librte_eal/ppc/rte_cpuflags.c +6 -0
index 3bb7563ce9..eee8234384 100644
@@ -108,3 +108,9 @@ rte_cpu_get_flag_name(enum rte_cpu_flag_t feature)
 		return NULL;
 	return rte_cpu_feature_table[feature].name;
 }
+
+void
+rte_cpu_get_intrinsics_support(struct rte_cpu_intrinsics *intrinsics)
+{
+	memset(intrinsics, 0, sizeof(*intrinsics));
+}
lib/librte_eal/rte_eal_version.map +1 -0
index a93dea9fe6..ed944f2bd4 100644
@@ -400,6 +400,7 @@ EXPERIMENTAL {
 	# added in 20.11
 	__rte_eal_trace_generic_size_t;
 	rte_service_lcore_may_be_active;
+	rte_cpu_get_intrinsics_support;
 };
 
 INTERNAL {
lib/librte_eal/x86/include/rte_power_intrinsics.h +8 -0
index 8d579eaf64..3afc165a1f 100644
@@ -29,6 +29,10 @@ extern "C" {
  * For more information about usage of these instructions, please refer to
  * Intel(R) 64 and IA-32 Architectures Software Developer's Manual.
  *
+ * @warning It is responsibility of the user to check if this function is
+ *   supported at runtime using `rte_cpu_get_features()` API call. Failing to do
+ *   so may result in an illegal CPU instruction error.
+ *
  * @param p
  *   Address to monitor for changes. Must be aligned on an 64-byte boundary.
  * @param expected_value
@@ -80,6 +84,10 @@ static inline void rte_power_monitor(const volatile void *p,
  * information about usage of this instruction, please refer to Intel(R) 64 and
  * IA-32 Architectures Software Developer's Manual.
  *
+ * @warning It is responsibility of the user to check if this function is
+ *   supported at runtime using `rte_cpu_get_features()` API call. Failing to do
+ *   so may result in an illegal CPU instruction error.
+ *
  * @param tsc_timestamp
  *   Maximum TSC timestamp to wait for.
  *
lib/librte_eal/x86/rte_cpuflags.c +12 -0
index 0325c4b93b..a96312ff7f 100644
@@ -7,6 +7,7 @@
 #include <stdio.h>
 #include <errno.h>
 #include <stdint.h>
+#include <string.h>
 
 #include "rte_cpuid.h"
 
@@ -179,3 +180,14 @@ rte_cpu_get_flag_name(enum rte_cpu_flag_t feature)
 		return NULL;
 	return rte_cpu_feature_table[feature].name;
 }
+
+void
+rte_cpu_get_intrinsics_support(struct rte_cpu_intrinsics *intrinsics)
+{
+	memset(intrinsics, 0, sizeof(*intrinsics));
+
+	if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_WAITPKG)) {
+		intrinsics->power_monitor = 1;
+		intrinsics->power_pause = 1;
+	}
+}
Signature · 1 line
2.17.1
#269 lore raw

Re: [dpdk-dev] [PATCH v5 03/10] eal: add intrinsics support check infrastructure

Quoted 29 lines · Anatoly Burakov

Currently, it is not possible to check support for intrinsics that are platform-specific, cannot be abstracted in a generic way, or do not have support on all architectures. The CPUID flags can be used to some extent, but they are only defined for their platform, while intrinsics will be available to all code as they are in generic headers.

This patch introduces infrastructure to check support for certain platform-specific intrinsics, and adds support for checking support for IA power management-related intrinsics for UMWAIT/UMONITOR and TPAUSE.

---
 .../arm/include/rte_power_intrinsics.h        |  8 ++++++
 lib/librte_eal/arm/rte_cpuflags.c             |  6 +++++
 lib/librte_eal/include/generic/rte_cpuflags.h | 26 +++++++++++++++++++
 .../include/generic/rte_power_intrinsics.h    |  8 ++++++
 .../ppc/include/rte_power_intrinsics.h        |  8 ++++++
 lib/librte_eal/ppc/rte_cpuflags.c             |  6 +++++
 lib/librte_eal/rte_eal_version.map            |  1 +
 .../x86/include/rte_power_intrinsics.h        |  8 ++++++
 lib/librte_eal/x86/rte_cpuflags.c             | 12 +++++++++
 9 files changed, 83 insertions(+)
lib/librte_eal/arm/include/rte_power_intrinsics.h +0 -0
index 4aad44a0b9..055ec5877a 100644

lib/librte_eal/arm/include/rte_power_intrinsics.h extern "C" { · line 22

Quoted 6 lines
lib/librte_eal/arm/include/rte_power_intrinsics.h +3 -0
@@ -17,6 +17,10 @@ extern "C" {
 /**
  * This function is not supported on ARM.
  *
+ * @warning It is responsibility of the user to check if this function is
+ *   supported at runtime using `rte_cpu_get_features()` API call. Failing to do
+ *   so may result in an illegal CPU instruction error.

See below

lib/librte_eal/arm/include/rte_power_intrinsics.h static inline void rte_power_monitor(const volatile void *p, · line 53

Quoted 12 lines
lib/librte_eal/arm/include/rte_power_intrinsics.h +5 -0
+ *
  * @param p
  *   Address to monitor for changes. Must be aligned on an 64-byte boundary.
  * @param expected_value
@@ -43,6 +47,10 @@ static inline void rte_power_monitor(const volatile void *p,
 /**
  * This function is not supported on ARM.
  *
+ * @warning It is responsibility of the user to check if this function is
+ *   supported at runtime using `rte_cpu_get_features()` API call. Failing to do
+ *   so may result in an illegal CPU instruction error.
+ *

See below

This patch looks to me.

Since rte_power_monitor() API is public API, I think, only in the generic header file, you need to have
these warnings and API documentation rather than repeating everywhere.

Quoted 59 lines
lib/librte_eal/arm/include/rte_power_intrinsics.h +0 -0
  * @param tsc_timestamp
  *   Maximum TSC timestamp to wait for.
  *
lib/librte_eal/arm/rte_cpuflags.c +6 -0
index caf3dc83a5..7eef11fa02 100644
@@ -138,3 +138,9 @@ rte_cpu_get_flag_name(enum rte_cpu_flag_t feature)
                return NULL;
        return rte_cpu_feature_table[feature].name;
 }
+
+void
+rte_cpu_get_intrinsics_support(struct rte_cpu_intrinsics *intrinsics)
+{
+       memset(intrinsics, 0, sizeof(*intrinsics));
+}
lib/librte_eal/include/generic/rte_cpuflags.h +26 -0
index 872f0ebe3e..28a5aecde8 100644
@@ -13,6 +13,32 @@
 #include "rte_common.h"
 #include <errno.h>
 
+#include <rte_compat.h>
+
+/**
+ * Structure used to describe platform-specific intrinsics that may or may not
+ * be supported at runtime.
+ */
+struct rte_cpu_intrinsics {
+       uint32_t power_monitor : 1;
+       /**< indicates support for rte_power_monitor function */
+       uint32_t power_pause : 1;
+       /**< indicates support for rte_power_pause function */
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Check CPU support for various intrinsics at runtime.
+ *
+ * @param intrinsics
+ *     Pointer to a structure to be filled.
+ */
+__rte_experimental
+void
+rte_cpu_get_intrinsics_support(struct rte_cpu_intrinsics *intrinsics);
+
 /**
  * Enumeration of all CPU features supported
  */
lib/librte_eal/include/generic/rte_power_intrinsics.h +0 -0
index e36c1f8976..218eda7e86 100644

lib/librte_eal/include/generic/rte_power_intrinsics.h line 31

Quoted 6 lines
lib/librte_eal/include/generic/rte_power_intrinsics.h +3 -0
@@ -26,6 +26,10 @@
  * checked against the expected value, and if they match, the entering of
  * optimized power state may be aborted.
  *
+ * @warning It is responsibility of the user to check if this function is
+ *   supported at runtime using `rte_cpu_get_features()` API call. Failing to do
+ *   so may result in an illegal CPU instruction error.

See above

Quoted 122 lines
lib/librte_eal/include/generic/rte_power_intrinsics.h +5 -0
+ *
  * @param p
  *   Address to monitor for changes. Must be aligned on an 64-byte boundary.
  * @param expected_value
@@ -49,6 +53,10 @@ static inline void rte_power_monitor(const volatile void *p,
  * Enter an architecture-defined optimized power state until a certain TSC
  * timestamp is reached.
  *
+ * @warning It is responsibility of the user to check if this function is
+ *   supported at runtime using `rte_cpu_get_features()` API call. Failing to do
+ *   so may result in an illegal CPU instruction error.
+ *
  * @param tsc_timestamp
  *   Maximum TSC timestamp to wait for. Note that the wait behavior is
  *   architecture-dependent.
lib/librte_eal/ppc/include/rte_power_intrinsics.h +8 -0
index 70fd7b094f..d63ad86849 100644
@@ -17,6 +17,10 @@ extern "C" {
 /**
  * This function is not supported on PPC64.
  *
+ * @warning It is responsibility of the user to check if this function is
+ *   supported at runtime using `rte_cpu_get_features()` API call. Failing to do
+ *   so may result in an illegal CPU instruction error.
+ *
  * @param p
  *   Address to monitor for changes. Must be aligned on an 64-byte boundary.
  * @param expected_value
@@ -43,6 +47,10 @@ static inline void rte_power_monitor(const volatile void *p,
 /**
  * This function is not supported on PPC64.
  *
+ * @warning It is responsibility of the user to check if this function is
+ *   supported at runtime using `rte_cpu_get_features()` API call. Failing to do
+ *   so may result in an illegal CPU instruction error.
+ *
  * @param tsc_timestamp
  *   Maximum TSC timestamp to wait for.
  *
lib/librte_eal/ppc/rte_cpuflags.c +6 -0
index 3bb7563ce9..eee8234384 100644
@@ -108,3 +108,9 @@ rte_cpu_get_flag_name(enum rte_cpu_flag_t feature)
                return NULL;
        return rte_cpu_feature_table[feature].name;
 }
+
+void
+rte_cpu_get_intrinsics_support(struct rte_cpu_intrinsics *intrinsics)
+{
+       memset(intrinsics, 0, sizeof(*intrinsics));
+}
lib/librte_eal/rte_eal_version.map +1 -0
index a93dea9fe6..ed944f2bd4 100644
@@ -400,6 +400,7 @@ EXPERIMENTAL {
        # added in 20.11
        __rte_eal_trace_generic_size_t;
        rte_service_lcore_may_be_active;
+       rte_cpu_get_intrinsics_support;
 };
 
 INTERNAL {
lib/librte_eal/x86/include/rte_power_intrinsics.h +8 -0
index 8d579eaf64..3afc165a1f 100644
@@ -29,6 +29,10 @@ extern "C" {
  * For more information about usage of these instructions, please refer to
  * Intel(R) 64 and IA-32 Architectures Software Developer's Manual.
  *
+ * @warning It is responsibility of the user to check if this function is
+ *   supported at runtime using `rte_cpu_get_features()` API call. Failing to do
+ *   so may result in an illegal CPU instruction error.
+ *
  * @param p
  *   Address to monitor for changes. Must be aligned on an 64-byte boundary.
  * @param expected_value
@@ -80,6 +84,10 @@ static inline void rte_power_monitor(const volatile void *p,
  * information about usage of this instruction, please refer to Intel(R) 64 and
  * IA-32 Architectures Software Developer's Manual.
  *
+ * @warning It is responsibility of the user to check if this function is
+ *   supported at runtime using `rte_cpu_get_features()` API call. Failing to do
+ *   so may result in an illegal CPU instruction error.
+ *
  * @param tsc_timestamp
  *   Maximum TSC timestamp to wait for.
  *
lib/librte_eal/x86/rte_cpuflags.c +12 -1
index 0325c4b93b..a96312ff7f 100644
@@ -7,6 +7,7 @@
 #include <stdio.h>
 #include <errno.h>
 #include <stdint.h>
+#include <string.h>
 
 #include "rte_cpuid.h"
 
@@ -179,3 +180,14 @@ rte_cpu_get_flag_name(enum rte_cpu_flag_t feature)
                return NULL;
        return rte_cpu_feature_table[feature].name;
 }
+
+void
+rte_cpu_get_intrinsics_support(struct rte_cpu_intrinsics *intrinsics)
+{
+       memset(intrinsics, 0, sizeof(*intrinsics));
+
+       if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_WAITPKG)) {
+               intrinsics->power_monitor = 1;
+               intrinsics->power_pause = 1;
+       }
+}
--

2.17.1

#270 lore raw

Re: [dpdk-dev] [PATCH v5 03/10] eal: add intrinsics support check infrastructure

Quoted 54 lines · Jerin Jacob
Quoted 29 lines · Anatoly Burakov

Currently, it is not possible to check support for intrinsics that are platform-specific, cannot be abstracted in a generic way, or do not have support on all architectures. The CPUID flags can be used to some extent, but they are only defined for their platform, while intrinsics will be available to all code as they are in generic headers.

This patch introduces infrastructure to check support for certain platform-specific intrinsics, and adds support for checking support for IA power management-related intrinsics for UMWAIT/UMONITOR and TPAUSE.

---
  .../arm/include/rte_power_intrinsics.h        |  8 ++++++
  lib/librte_eal/arm/rte_cpuflags.c             |  6 +++++
  lib/librte_eal/include/generic/rte_cpuflags.h | 26 +++++++++++++++++++
  .../include/generic/rte_power_intrinsics.h    |  8 ++++++
  .../ppc/include/rte_power_intrinsics.h        |  8 ++++++
  lib/librte_eal/ppc/rte_cpuflags.c             |  6 +++++
  lib/librte_eal/rte_eal_version.map            |  1 +
  .../x86/include/rte_power_intrinsics.h        |  8 ++++++
  lib/librte_eal/x86/rte_cpuflags.c             | 12 +++++++++
  9 files changed, 83 insertions(+)
lib/librte_eal/arm/include/rte_power_intrinsics.h +0 -0
index 4aad44a0b9..055ec5877a 100644

lib/librte_eal/arm/include/rte_power_intrinsics.h extern "C" { · line 22

Quoted 6 lines
lib/librte_eal/arm/include/rte_power_intrinsics.h +3 -0
@@ -17,6 +17,10 @@ extern "C" {
  /**
   * This function is not supported on ARM.
   *
+ * @warning It is responsibility of the user to check if this function is
+ *   supported at runtime using `rte_cpu_get_features()` API call. Failing to do
+ *   so may result in an illegal CPU instruction error.

See below

lib/librte_eal/arm/include/rte_power_intrinsics.h static inline void rte_power_monitor(const volatile void *p, · line 53

Quoted 12 lines
lib/librte_eal/arm/include/rte_power_intrinsics.h +5 -0
+ *
   * @param p
   *   Address to monitor for changes. Must be aligned on an 64-byte boundary.
   * @param expected_value
@@ -43,6 +47,10 @@ static inline void rte_power_monitor(const volatile void *p,
  /**
   * This function is not supported on ARM.
   *
+ * @warning It is responsibility of the user to check if this function is
+ *   supported at runtime using `rte_cpu_get_features()` API call. Failing to do
+ *   so may result in an illegal CPU instruction error.
+ *

See below

Quoted 6 lines

This patch looks to me.

Since rte_power_monitor() API is public API, I think, only in the generic header file, you need to have
these warnings and API documentation rather than repeating everywhere.

Great, will fix in v6 so. Thanks!

Signature · 2 lines
Thanks,
Anatoly
Acked-by on v5 3/10
#271 lore raw

Re: [dpdk-dev] [PATCH v5 03/10] eal: add intrinsics support check infrastructure

In reply to Anatoly Burakov
Quoted 12 lines · Anatoly Burakov

Currently, it is not possible to check support for intrinsics that are platform-specific, cannot be abstracted in a generic way, or do not have support on all architectures. The CPUID flags can be used to some extent, but they are only defined for their platform, while intrinsics will be available to all code as they are in generic headers.

This patch introduces infrastructure to check support for certain platform-specific intrinsics, and adds support for checking support for IA power management-related intrinsics for UMWAIT/UMONITOR and TPAUSE.

---

... snip ...

Quoted 45 lines
lib/librte_eal/ppc/include/rte_power_intrinsics.h +8 -0
index 70fd7b094f..d63ad86849 100644
@@ -17,6 +17,10 @@ extern "C" {
  /**
   * This function is not supported on PPC64.
   *
+ * @warning It is responsibility of the user to check if this function is
+ *   supported at runtime using `rte_cpu_get_features()` API call. Failing to do
+ *   so may result in an illegal CPU instruction error.
+ *
   * @param p
   *   Address to monitor for changes. Must be aligned on an 64-byte boundary.
   * @param expected_value
@@ -43,6 +47,10 @@ static inline void rte_power_monitor(const volatile void *p,
  /**
   * This function is not supported on PPC64.
   *
+ * @warning It is responsibility of the user to check if this function is
+ *   supported at runtime using `rte_cpu_get_features()` API call. Failing to do
+ *   so may result in an illegal CPU instruction error.
+ *
   * @param tsc_timestamp
   *   Maximum TSC timestamp to wait for.
   *
lib/librte_eal/ppc/rte_cpuflags.c +6 -0
index 3bb7563ce9..eee8234384 100644
@@ -108,3 +108,9 @@ rte_cpu_get_flag_name(enum rte_cpu_flag_t feature)
  		return NULL;
  	return rte_cpu_feature_table[feature].name;
  }
+
+void
+rte_cpu_get_intrinsics_support(struct rte_cpu_intrinsics *intrinsics)
+{
+	memset(intrinsics, 0, sizeof(*intrinsics));
+}
lib/librte_eal/rte_eal_version.map +0 -0
index a93dea9fe6..ed944f2bd4 100644

lib/librte_eal/rte_eal_version.map EXPERIMENTAL { · line 406

Quoted 7 lines
lib/librte_eal/rte_eal_version.map +1 -0
@@ -400,6 +400,7 @@ EXPERIMENTAL {
  	# added in 20.11
  	__rte_eal_trace_generic_size_t;
  	rte_service_lcore_may_be_active;
+	rte_cpu_get_intrinsics_support;
  };
 
  INTERNAL {
#272 lore raw

PATCH v5 4/10 ethdev: add simple power management API

In reply to Anatoly Burakov

From: Liang Ma <[email protected]>

Add a simple API to allow getting address of next RX descriptor from the PMD, as well as release notes information.

---

Notes:
v5:
- Bring function format in line with other functions in the file
- Ensure the API is supported by the driver before calling it (Konstantin)

 doc/guides/rel_notes/release_20_11.rst   | 16 ++++++++++++++
 lib/librte_ethdev/rte_ethdev.c           | 17 ++++++++++++++
 lib/librte_ethdev/rte_ethdev.h           | 24 ++++++++++++++++++++
 lib/librte_ethdev/rte_ethdev_driver.h    | 28 ++++++++++++++++++++++++
 lib/librte_ethdev/rte_ethdev_version.map |  1 +
 5 files changed, 86 insertions(+)
doc/guides/rel_notes/release_20_11.rst +16 -0
index 808bdc4e54..e85af5d3e9 100644
@@ -55,6 +55,11 @@ New Features
      Also, make sure to start the actual text at the margin.
      =======================================================
 
+* **ethdev: add 1 new EXPERIMENTAL API for PMD power management.**
+
+  * ``rte_eth_get_wake_addr()``
+  * add new eth_dev_ops ``get_wake_addr``
+
 * **Updated Broadcom bnxt driver.**
 
   Updated the Broadcom bnxt driver with new features and improvements, including:
@@ -136,6 +141,17 @@ New Features
   * Extern objects and functions can be plugged into the pipeline.
   * Transaction-oriented table updates.
 
+* **Add PMD power management mechanism**
+
+  3 new Ethernet PMD power management mechanism is added through existing
+  RX callback infrastructure.
+
+  * Add power saving scheme based on UMWAIT instruction (x86 only)
+  * Add power saving scheme based on ``rte_pause()``
+  * Add power saving scheme based on frequency scaling through the power library
+  * Add new EXPERIMENTAL API ``rte_power_pmd_mgmt_queue_enable()``
+  * Add new EXPERIMENTAL API ``rte_power_pmd_mgmt_queue_disable()``
+
 
 Removed Items
 -------------
lib/librte_ethdev/rte_ethdev.c +17 -0
index 48d1333b17..352108f43c 100644
@@ -4804,6 +4804,23 @@ rte_eth_tx_burst_mode_get(uint16_t port_id, uint16_t queue_id,
 		       dev->dev_ops->tx_burst_mode_get(dev, queue_id, mode));
 }
 
+int
+rte_eth_get_wake_addr(uint16_t port_id, uint16_t queue_id,
+		volatile void **wake_addr, uint64_t *expected, uint64_t *mask)
+{
+	struct rte_eth_dev *dev;
+
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_wake_addr, -ENOTSUP);
+
+	return eth_err(port_id,
+		dev->dev_ops->get_wake_addr(dev->data->rx_queues[queue_id],
+			wake_addr, expected, mask));
+}
+
 int
 rte_eth_dev_set_mc_addr_list(uint16_t port_id,
 			     struct rte_ether_addr *mc_addr_set,
lib/librte_ethdev/rte_ethdev.h +24 -0
index d2bf74f128..a6cfe3cd57 100644
@@ -4014,6 +4014,30 @@ __rte_experimental
 int rte_eth_tx_burst_mode_get(uint16_t port_id, uint16_t queue_id,
 	struct rte_eth_burst_mode *mode);
 
+/**
+ * Retrieve the wake up address from specific queue
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param queue_id
+ *   The Tx queue on the Ethernet device for which information
+ *   will be retrieved.
+ * @param wake_addr
+ *   The pointer point to the address which is used for monitoring.
+ * @param expected
+ *   The pointer point to value to be expected when descriptor is set.
+ * @param mask
+ *   The pointer point to comparison bitmask for the expected value.
+ *
+ * @return
+ *   - 0: Success.
+ *   -EINVAL: Failed to get wake address.
+ */
+__rte_experimental
+int rte_eth_get_wake_addr(uint16_t port_id, uint16_t queue_id,
+			  volatile void **wake_addr,
+			  uint64_t *expected, uint64_t *mask);
+
 /**
  * Retrieve device registers and register attributes (number of registers and
  * register size)
lib/librte_ethdev/rte_ethdev_driver.h +28 -0
index c3062c246c..935d46f25c 100644
@@ -574,6 +574,31 @@ typedef int (*eth_tx_hairpin_queue_setup_t)
 	 uint16_t nb_tx_desc,
 	 const struct rte_eth_hairpin_conf *hairpin_conf);
 
+/**
+ * @internal
+ * Get the Wake up address.
+ *
+ * @param rxq
+ *   Ethdev queue pointer.
+ * @param tail_desc_addr
+ *   The pointer point to descriptor address var.
+ * @param expected
+ *   The pointer point to value to be expected when descriptor is set.
+ * @param mask
+ *   The pointer point to comparison bitmask for the expected value.
+ * @return
+ *   Negative errno value on error, 0 on success.
+ *
+ * @retval 0
+ *   Success.
+ * @retval -EINVAL
+ *   Failed to get descriptor address.
+ */
+typedef int (*eth_get_wake_addr_t)
+	(void *rxq, volatile void **tail_desc_addr,
+	 uint64_t *expected, uint64_t *mask);
+
+
 /**
  * @internal A structure containing the functions exported by an Ethernet driver.
  */
@@ -713,6 +738,9 @@ struct eth_dev_ops {
 	/**< Set up device RX hairpin queue. */
 	eth_tx_hairpin_queue_setup_t tx_hairpin_queue_setup;
 	/**< Set up device TX hairpin queue. */
+	eth_get_wake_addr_t get_wake_addr;
+	/**< Get wake up address. */
+
 };
 
 /**
lib/librte_ethdev/rte_ethdev_version.map +1 -0
index c95ef5157a..3cb2093980 100644
@@ -229,6 +229,7 @@ EXPERIMENTAL {
 	# added in 20.11
 	rte_eth_link_speed_to_str;
 	rte_eth_link_to_str;
+	rte_eth_get_wake_addr;
 };
 
 INTERNAL {
Signature · 1 line
2.17.1
#273 lore raw

Re: [dpdk-dev] [PATCH v5 04/10] ethdev: add simple power management API

Quoted 58 lines

-----Original Message-----
From: dev <[email protected]> On Behalf Of Anatoly Burakov
Sent: Saturday, October 10, 2020 12:02 AM
To: [email protected]
Cc: Ma, Liang J <[email protected]>; Thomas Monjalon <[email protected]>; Yigit, Ferruh <[email protected]>; Andrew Rybchenko <[email protected]>; Ray Kinsella <[email protected]>; Neil Horman <[email protected]>; Hunt, David <[email protected]>; Ananyev, Konstantin <[email protected]>; [email protected]; Richardson, Bruce <[email protected]>; McDaniel, Timothy <[email protected]>; Eads, Gage <[email protected]>; Macnamara, Chris <[email protected]>
Subject: [dpdk-dev] [PATCH v5 04/10] ethdev: add simple power management API

From: Liang Ma <[email protected]>

Add a simple API to allow getting address of next RX descriptor from the PMD, as well as release notes information.

---

Notes:
v5:
- Bring function format in line with other functions in the file
- Ensure the API is supported by the driver before calling it (Konstantin)

 doc/guides/rel_notes/release_20_11.rst   | 16 ++++++++++++++
 lib/librte_ethdev/rte_ethdev.c           | 17 ++++++++++++++
 lib/librte_ethdev/rte_ethdev.h           | 24 ++++++++++++++++++++
 lib/librte_ethdev/rte_ethdev_driver.h    | 28 ++++++++++++++++++++++++
 lib/librte_ethdev/rte_ethdev_version.map |  1 +
 5 files changed, 86 insertions(+)
doc/guides/rel_notes/release_20_11.rst +1 -0
index 808bdc4e54..e85af5d3e9 100644
@@ -55,6 +55,11 @@ New Features
      Also, make sure to start the actual text at the margin.
      =======================================================
 
+* **ethdev: add 1 new EXPERIMENTAL API for PMD power

management.**

doc/guides/rel_notes/release_20_11.rst +4 -0
+
+  * ``rte_eth_get_wake_addr()``
+  * add new eth_dev_ops ``get_wake_addr``
+
 * **Updated Broadcom bnxt driver.**
 
   Updated the Broadcom bnxt driver with new features and improvements,

including:

doc/guides/rel_notes/release_20_11.rst New Features · line 146

Quoted 6 lines
doc/guides/rel_notes/release_20_11.rst +3 -0
@@ -136,6 +141,17 @@ New Features
   * Extern objects and functions can be plugged into the pipeline.
   * Transaction-oriented table updates.
 
+* **Add PMD power management mechanism**
+
+  3 new Ethernet PMD power management mechanism is added through

" mechanisms are " please.

Quoted 11 lines
doc/guides/rel_notes/release_20_11.rst +7 -0
+ existing  RX callback infrastructure.
+
+  * Add power saving scheme based on UMWAIT instruction (x86 only)
+  * Add power saving scheme based on ``rte_pause()``
+  * Add power saving scheme based on frequency scaling through the
+ power library
+  * Add new EXPERIMENTAL API

``rte_power_pmd_mgmt_queue_enable()``
+ * Add new EXPERIMENTAL API
``rte_power_pmd_mgmt_queue_disable()``
+

Could this doc be separate to other specific patch if it is not related with this patch?

Quoted 51 lines

Removed Items
-------------

lib/librte_ethdev/rte_ethdev.c +13 -0
index 48d1333b17..352108f43c 100644
@@ -4804,6 +4804,23 @@ rte_eth_tx_burst_mode_get(uint16_t port_id,
 uint16_t queue_id,
 		       dev->dev_ops->tx_burst_mode_get(dev, queue_id,
 mode));  }
 
+int
+rte_eth_get_wake_addr(uint16_t port_id, uint16_t queue_id,
+		volatile void **wake_addr, uint64_t *expected, uint64_t
 *mask) {
+	struct rte_eth_dev *dev;
+
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_wake_addr, -
 ENOTSUP);
+
+	return eth_err(port_id,
+		dev->dev_ops->get_wake_addr(dev->data-
Quoted 1 line

rx_queues[queue_id],

lib/librte_ethdev/rte_ethdev.c +3 -0
+			wake_addr, expected, mask));
+}
+
 int
 rte_eth_dev_set_mc_addr_list(uint16_t port_id,
 			     struct rte_ether_addr *mc_addr_set, diff --git

a/lib/librte_ethdev/rte_ethdev.h b/lib/librte_ethdev/rte_ethdev.h index d2bf74f128..a6cfe3cd57 100644

lib/librte_ethdev/rte_ethdev.h +9 -0
@@ -4014,6 +4014,30 @@ __rte_experimental  int
 rte_eth_tx_burst_mode_get(uint16_t port_id, uint16_t queue_id,
 	struct rte_eth_burst_mode *mode);
 
+/**
+ * Retrieve the wake up address from specific queue
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param queue_id
+ *   The Tx queue on the Ethernet device for which information
+ *   will be retrieved.
+ * @param wake_addr

lib/librte_ethdev/rte_ethdev.h __rte_experimental int · line 4035

Quoted 10 lines
lib/librte_ethdev/rte_ethdev.h +10 -0
+ *   The pointer point to the address which is used for monitoring.
+ * @param expected
+ *   The pointer point to value to be expected when descriptor is set.
+ * @param mask
+ *   The pointer point to comparison bitmask for the expected value.
+ *
+ * @return
+ *   - 0: Success.
+ *   -EINVAL: Failed to get wake address.
+ */

Is that "-EINVAL " is the only error value which will be return?

Quoted 27 lines
lib/librte_ethdev/rte_ethdev.h +5 -0
+__rte_experimental
+int rte_eth_get_wake_addr(uint16_t port_id, uint16_t queue_id,
+			  volatile void **wake_addr,
+			  uint64_t *expected, uint64_t *mask);
+
 /**
  * Retrieve device registers and register attributes (number of registers and
  * register size)
lib/librte_ethdev/rte_ethdev_driver.h +10 -0
index c3062c246c..935d46f25c 100644
@@ -574,6 +574,31 @@ typedef int (*eth_tx_hairpin_queue_setup_t)
 	 uint16_t nb_tx_desc,
 	 const struct rte_eth_hairpin_conf *hairpin_conf);
 
+/**
+ * @internal
+ * Get the Wake up address.
+ *
+ * @param rxq
+ *   Ethdev queue pointer.
+ * @param tail_desc_addr
+ *   The pointer point to descriptor address var.
+ * @param expected
+ *   The pointer point to value to be expected when descriptor is set.

lib/librte_ethdev/rte_ethdev_driver.h typedef int (*eth_tx_hairpin_queue_setup_t) · line 596

Quoted 10 lines
lib/librte_ethdev/rte_ethdev_driver.h +10 -0
+ * @param mask
+ *   The pointer point to comparison bitmask for the expected value.
+ * @return
+ *   Negative errno value on error, 0 on success.
+ *
+ * @retval 0
+ *   Success.
+ * @retval -EINVAL
+ *   Failed to get descriptor address.
+ */

The question is the same as above.

Quoted 34 lines
lib/librte_ethdev/rte_ethdev_driver.h +5 -0
+typedef int (*eth_get_wake_addr_t)
+	(void *rxq, volatile void **tail_desc_addr,
+	 uint64_t *expected, uint64_t *mask);
+
+
 /**
  * @internal A structure containing the functions exported by an Ethernet

driver.
*/

lib/librte_ethdev/rte_ethdev_driver.h +3 -0
@@ -713,6 +738,9 @@ struct eth_dev_ops {
 	/**< Set up device RX hairpin queue. */
 	eth_tx_hairpin_queue_setup_t tx_hairpin_queue_setup;
 	/**< Set up device TX hairpin queue. */
+	eth_get_wake_addr_t get_wake_addr;
+	/**< Get wake up address. */
+
 };
 
 /**
lib/librte_ethdev/rte_ethdev_version.map +1 -1
index c95ef5157a..3cb2093980 100644
@@ -229,6 +229,7 @@ EXPERIMENTAL {
 	# added in 20.11
 	rte_eth_link_speed_to_str;
 	rte_eth_link_to_str;
+	rte_eth_get_wake_addr;
 };
 
 INTERNAL {
--

2.17.1

#274 lore raw

Re: [dpdk-dev] [PATCH v5 04/10] ethdev: add simple power management API

Quoted 17 lines · Jia
Quoted 17 lines

-----Original Message-----
From: dev <[email protected]> On Behalf Of Anatoly Burakov
Sent: Saturday, October 10, 2020 12:02 AM
To: [email protected]
Cc: Ma, Liang J <[email protected]>; Thomas Monjalon <[email protected]>; Yigit, Ferruh <[email protected]>; Andrew Rybchenko <[email protected]>; Ray Kinsella <[email protected]>; Neil Horman <[email protected]>; Hunt, David <[email protected]>; Ananyev, Konstantin <[email protected]>; [email protected]; Richardson, Bruce <[email protected]>; McDaniel, Timothy <[email protected]>; Eads, Gage <[email protected]>; Macnamara, Chris <[email protected]>
Subject: [dpdk-dev] [PATCH v5 04/10] ethdev: add simple power management API

Quoted 8 lines
Quoted 8 lines

From: Liang Ma <[email protected]>

Add a simple API to allow getting address of next RX descriptor from the PMD, as well as release notes information.

---

Hi Jia,

Thanks for your review. Responses below.

Quoted 42 lines
Quoted 33 lines

Notes:
v5:
- Bring function format in line with other functions in the file
- Ensure the API is supported by the driver before calling it (Konstantin)

  doc/guides/rel_notes/release_20_11.rst   | 16 ++++++++++++++
  lib/librte_ethdev/rte_ethdev.c           | 17 ++++++++++++++
  lib/librte_ethdev/rte_ethdev.h           | 24 ++++++++++++++++++++
  lib/librte_ethdev/rte_ethdev_driver.h    | 28 ++++++++++++++++++++++++
  lib/librte_ethdev/rte_ethdev_version.map |  1 +
  5 files changed, 86 insertions(+)
doc/guides/rel_notes/release_20_11.rst +1 -0
index 808bdc4e54..e85af5d3e9 100644
@@ -55,6 +55,11 @@ New Features
       Also, make sure to start the actual text at the margin.
       =======================================================
 
+* **ethdev: add 1 new EXPERIMENTAL API for PMD power

management.**

doc/guides/rel_notes/release_20_11.rst +4 -0
+
+  * ``rte_eth_get_wake_addr()``
+  * add new eth_dev_ops ``get_wake_addr``
+
  * **Updated Broadcom bnxt driver.**
 
    Updated the Broadcom bnxt driver with new features and improvements,

including:

doc/guides/rel_notes/release_20_11.rst New Features · line 146

Quoted 6 lines
doc/guides/rel_notes/release_20_11.rst +3 -0
@@ -136,6 +141,17 @@ New Features
    * Extern objects and functions can be plugged into the pipeline.
    * Transaction-oriented table updates.
 
+* **Add PMD power management mechanism**
+
+  3 new Ethernet PMD power management mechanism is added through

" mechanisms are " please.

Quoted 13 lines
Quoted 11 lines
doc/guides/rel_notes/release_20_11.rst +7 -0
+ existing  RX callback infrastructure.
+
+  * Add power saving scheme based on UMWAIT instruction (x86 only)
+  * Add power saving scheme based on ``rte_pause()``
+  * Add power saving scheme based on frequency scaling through the
+ power library
+  * Add new EXPERIMENTAL API

``rte_power_pmd_mgmt_queue_enable()``
+ * Add new EXPERIMENTAL API
``rte_power_pmd_mgmt_queue_disable()``
+

Could this doc be separate to other specific patch if it is not related with this patch?

It is related - it's the doc changes that add mention of this API. I was under the impression current policy was having doc updates in the same patch as the changes made?

Quoted 56 lines
Quoted 56 lines

Removed Items
-------------

lib/librte_ethdev/rte_ethdev.c +13 -0
index 48d1333b17..352108f43c 100644
@@ -4804,6 +4804,23 @@ rte_eth_tx_burst_mode_get(uint16_t port_id,
 uint16_t queue_id,
  		       dev->dev_ops->tx_burst_mode_get(dev, queue_id,
 mode));  }
 
+int
+rte_eth_get_wake_addr(uint16_t port_id, uint16_t queue_id,
+		volatile void **wake_addr, uint64_t *expected, uint64_t
 *mask) {
+	struct rte_eth_dev *dev;
+
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_wake_addr, -
 ENOTSUP);
+
+	return eth_err(port_id,
+		dev->dev_ops->get_wake_addr(dev->data-
Quoted 1 line

rx_queues[queue_id],

lib/librte_ethdev/rte_ethdev.c +3 -0
+			wake_addr, expected, mask));
+}
+
  int
  rte_eth_dev_set_mc_addr_list(uint16_t port_id,
  			     struct rte_ether_addr *mc_addr_set, diff --git

a/lib/librte_ethdev/rte_ethdev.h b/lib/librte_ethdev/rte_ethdev.h index d2bf74f128..a6cfe3cd57 100644

lib/librte_ethdev/rte_ethdev.h +13 -0
@@ -4014,6 +4014,30 @@ __rte_experimental  int
 rte_eth_tx_burst_mode_get(uint16_t port_id, uint16_t queue_id,
  	struct rte_eth_burst_mode *mode);
 
+/**
+ * Retrieve the wake up address from specific queue
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param queue_id
+ *   The Tx queue on the Ethernet device for which information
+ *   will be retrieved.
+ * @param wake_addr
+ *   The pointer point to the address which is used for monitoring.
+ * @param expected
+ *   The pointer point to value to be expected when descriptor is set.
+ * @param mask
Quoted 8 lines

lib/librte_ethdev/rte_ethdev.h __rte_experimental · line 4035

Quoted 6 lines
lib/librte_ethdev/rte_ethdev.h +6 -0
+ *   The pointer point to comparison bitmask for the expected value.
+ *
+ * @return
+ *   - 0: Success.
+ *   -EINVAL: Failed to get wake address.
+ */

Is that "-EINVAL " is the only error value which will be return?

Also -ENOTSUP, i'll add this, thanks.

Quoted 32 lines
Quoted 32 lines
lib/librte_ethdev/rte_ethdev.h +5 -0
+__rte_experimental
+int rte_eth_get_wake_addr(uint16_t port_id, uint16_t queue_id,
+			  volatile void **wake_addr,
+			  uint64_t *expected, uint64_t *mask);
+
  /**
   * Retrieve device registers and register attributes (number of registers and
   * register size)
lib/librte_ethdev/rte_ethdev_driver.h +14 -0
index c3062c246c..935d46f25c 100644
@@ -574,6 +574,31 @@ typedef int (*eth_tx_hairpin_queue_setup_t)
  	 uint16_t nb_tx_desc,
  	 const struct rte_eth_hairpin_conf *hairpin_conf);
 
+/**
+ * @internal
+ * Get the Wake up address.
+ *
+ * @param rxq
+ *   Ethdev queue pointer.
+ * @param tail_desc_addr
+ *   The pointer point to descriptor address var.
+ * @param expected
+ *   The pointer point to value to be expected when descriptor is set.
+ * @param mask
+ *   The pointer point to comparison bitmask for the expected value.
+ * @return
+ *   Negative errno value on error, 0 on success.
Quoted 8 lines

lib/librte_ethdev/rte_ethdev_driver.h typedef int (*eth_tx_hairpin_queue_setup_t) · line 596

Quoted 6 lines
lib/librte_ethdev/rte_ethdev_driver.h +6 -0
+ *
+ * @retval 0
+ *   Success.
+ * @retval -EINVAL
+ *   Failed to get descriptor address.
+ */

The question is the same as above.

This is a driver function pointer, so return value will depend on driver implementation. So far we only see 0 or -EINVAL values from the driver itself, while -ENOTSUP will be returned by ethdev in case there is no driver implementation of this function. So, in this case this is correct.

Quoted 35 lines
Quoted 35 lines
lib/librte_ethdev/rte_ethdev_driver.h +5 -0
+typedef int (*eth_get_wake_addr_t)
+	(void *rxq, volatile void **tail_desc_addr,
+	 uint64_t *expected, uint64_t *mask);
+
+
  /**
   * @internal A structure containing the functions exported by an Ethernet

driver.
*/

lib/librte_ethdev/rte_ethdev_driver.h +3 -0
@@ -713,6 +738,9 @@ struct eth_dev_ops {
  	/**< Set up device RX hairpin queue. */
  	eth_tx_hairpin_queue_setup_t tx_hairpin_queue_setup;
  	/**< Set up device TX hairpin queue. */
+	eth_get_wake_addr_t get_wake_addr;
+	/**< Get wake up address. */
+
  };
 
  /**
lib/librte_ethdev/rte_ethdev_version.map +1 -1
index c95ef5157a..3cb2093980 100644
@@ -229,6 +229,7 @@ EXPERIMENTAL {
  	# added in 20.11
  	rte_eth_link_speed_to_str;
  	rte_eth_link_to_str;
+	rte_eth_get_wake_addr;
  };
 
  INTERNAL {
--

2.17.1

Signature · 2 lines
Thanks,
Anatoly
#275 lore raw

Re: [dpdk-dev] [PATCH v5 04/10] ethdev: add simple power management API

Quoted 107 lines

-----Original Message-----
From: Burakov, Anatoly <[email protected]>
Sent: Wednesday, October 14, 2020 5:07 PM
To: Guo, Jia <[email protected]>; [email protected]
Cc: Ma, Liang J <[email protected]>; Thomas Monjalon <[email protected]>; Yigit, Ferruh <[email protected]>; Andrew Rybchenko <[email protected]>; Ray Kinsella <[email protected]>; Neil Horman <[email protected]>; Hunt, David <[email protected]>; Ananyev, Konstantin <[email protected]>; [email protected]; Richardson, Bruce <[email protected]>; McDaniel, Timothy <[email protected]>; Eads, Gage <[email protected]>; Macnamara, Chris <[email protected]>
Subject: Re: [dpdk-dev] [PATCH v5 04/10] ethdev: add simple power management API

Quoted 17 lines · Jia
Quoted 17 lines

-----Original Message-----
From: dev <[email protected]> On Behalf Of Anatoly Burakov
Sent: Saturday, October 10, 2020 12:02 AM
To: [email protected]
Cc: Ma, Liang J <[email protected]>; Thomas Monjalon <[email protected]>; Yigit, Ferruh <[email protected]>; Andrew Rybchenko <[email protected]>; Ray Kinsella <[email protected]>; Neil Horman <[email protected]>; Hunt, David <[email protected]>; Ananyev, Konstantin <[email protected]>; [email protected]; Richardson, Bruce <[email protected]>; McDaniel, Timothy <[email protected]>; Eads, Gage <[email protected]>; Macnamara, Chris <[email protected]>
Subject: [dpdk-dev] [PATCH v5 04/10] ethdev: add simple power management API

Quoted 8 lines
Quoted 8 lines

From: Liang Ma <[email protected]>

Add a simple API to allow getting address of next RX descriptor from the PMD, as well as release notes information.

---

Hi Jia,

Thanks for your review. Responses below.

Quoted 11 lines
Quoted 11 lines

Notes:
v5:
- Bring function format in line with other functions in the file
- Ensure the API is supported by the driver before calling it
(Konstantin)

  doc/guides/rel_notes/release_20_11.rst   | 16 ++++++++++++++
  lib/librte_ethdev/rte_ethdev.c           | 17 ++++++++++++++
  lib/librte_ethdev/rte_ethdev.h           | 24 ++++++++++++++++++++
  lib/librte_ethdev/rte_ethdev_driver.h    | 28

++++++++++++++++++++++++

Quoted 11 lines

doc/guides/rel_notes/release_20_11.rst New Features · line 56

Quoted 11 lines
  lib/librte_ethdev/rte_ethdev_version.map |  1 +
  5 files changed, 86 insertions(+)
doc/guides/rel_notes/release_20_11.rst +0 -0
index 808bdc4e54..e85af5d3e9 100644
@@ -55,6 +55,11 @@ New Features
       Also, make sure to start the actual text at the margin.
 

=======================================================

Quoted 22 lines
Quoted 13 lines
doc/guides/rel_notes/release_20_11.rst +1 -0
+* **ethdev: add 1 new EXPERIMENTAL API for PMD power

management.**

doc/guides/rel_notes/release_20_11.rst +4 -0
+
+  * ``rte_eth_get_wake_addr()``
+  * add new eth_dev_ops ``get_wake_addr``
+
  * **Updated Broadcom bnxt driver.**
 
    Updated the Broadcom bnxt driver with new features and

improvements,
including:

doc/guides/rel_notes/release_20_11.rst New Features · line 146

Quoted 6 lines
doc/guides/rel_notes/release_20_11.rst +3 -0
@@ -136,6 +141,17 @@ New Features
    * Extern objects and functions can be plugged into the pipeline.
    * Transaction-oriented table updates.
 
+* **Add PMD power management mechanism**
+
+  3 new Ethernet PMD power management mechanism is added through

" mechanisms are " please.

Quoted 13 lines
Quoted 11 lines
doc/guides/rel_notes/release_20_11.rst +7 -0
+ existing  RX callback infrastructure.
+
+  * Add power saving scheme based on UMWAIT instruction (x86 only)
+  * Add power saving scheme based on ``rte_pause()``
+  * Add power saving scheme based on frequency scaling through the
+ power library
+  * Add new EXPERIMENTAL API

``rte_power_pmd_mgmt_queue_enable()``
+ * Add new EXPERIMENTAL API
``rte_power_pmd_mgmt_queue_disable()``
+

Could this doc be separate to other specific patch if it is not related with this

Quoted 6 lines

patch?

It is related - it's the doc changes that add mention of this API. I was under the impression current policy was having doc updates in the same patch as the changes made?

Do you think this part would be better separate into [PATCH v5 05/10]?

Quoted 110 lines
Quoted 11 lines

lib/librte_ethdev/rte_ethdev.c rte_eth_tx_burst_mode_get(uint16_t port_id, · line 4805

Quoted 11 lines

Removed Items
-------------

(quoted diff) +0 -0

b/lib/librte_ethdev/rte_ethdev.c index 48d1333b17..352108f43c 100644

lib/librte_ethdev/rte_ethdev.c +0 -0
@@ -4804,6 +4804,23 @@ rte_eth_tx_burst_mode_get(uint16_t port_id,
 uint16_t queue_id,
  		       dev->dev_ops->tx_burst_mode_get(dev, queue_id,

mode)); }

Quoted 45 lines
Quoted 45 lines
lib/librte_ethdev/rte_ethdev.c +16 -0
+int
+rte_eth_get_wake_addr(uint16_t port_id, uint16_t queue_id,
+		volatile void **wake_addr, uint64_t *expected, uint64_t
 *mask) {
+	struct rte_eth_dev *dev;
+
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_wake_addr, -
 ENOTSUP);
+
+	return eth_err(port_id,
+		dev->dev_ops->get_wake_addr(dev->data-
 > rx_queues[queue_id],
+			wake_addr, expected, mask));
+}
+
  int
  rte_eth_dev_set_mc_addr_list(uint16_t port_id,
  			     struct rte_ether_addr *mc_addr_set, diff --git

a/lib/librte_ethdev/rte_ethdev.h b/lib/librte_ethdev/rte_ethdev.h index
d2bf74f128..a6cfe3cd57 100644

lib/librte_ethdev/rte_ethdev.h +13 -0
@@ -4014,6 +4014,30 @@ __rte_experimental  int
 rte_eth_tx_burst_mode_get(uint16_t port_id, uint16_t queue_id,
  	struct rte_eth_burst_mode *mode);
 
+/**
+ * Retrieve the wake up address from specific queue
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param queue_id
+ *   The Tx queue on the Ethernet device for which information
+ *   will be retrieved.
+ * @param wake_addr
+ *   The pointer point to the address which is used for monitoring.
+ * @param expected
+ *   The pointer point to value to be expected when descriptor is set.
+ * @param mask
Quoted 8 lines

lib/librte_ethdev/rte_ethdev.h __rte_experimental · line 4035

Quoted 6 lines
lib/librte_ethdev/rte_ethdev.h +6 -0
+ *   The pointer point to comparison bitmask for the expected value.
+ *
+ * @return
+ *   - 0: Success.
+ *   -EINVAL: Failed to get wake address.
+ */

Is that "-EINVAL " is the only error value which will be return?

Also -ENOTSUP, i'll add this, thanks.

Quoted 8 lines

lib/librte_ethdev/rte_ethdev.h __rte_experimental

Quoted 8 lines
lib/librte_ethdev/rte_ethdev.h +5 -0
+__rte_experimental
+int rte_eth_get_wake_addr(uint16_t port_id, uint16_t queue_id,
+			  volatile void **wake_addr,
+			  uint64_t *expected, uint64_t *mask);
+
  /**
   * Retrieve device registers and register attributes (number of registers

and

Quoted 24 lines
Quoted 24 lines
lib/librte_ethdev/rte_ethdev.h +0 -0
   * register size)
lib/librte_ethdev/rte_ethdev_driver.h +14 -0
index c3062c246c..935d46f25c 100644
@@ -574,6 +574,31 @@ typedef int (*eth_tx_hairpin_queue_setup_t)
  	 uint16_t nb_tx_desc,
  	 const struct rte_eth_hairpin_conf *hairpin_conf);
 
+/**
+ * @internal
+ * Get the Wake up address.
+ *
+ * @param rxq
+ *   Ethdev queue pointer.
+ * @param tail_desc_addr
+ *   The pointer point to descriptor address var.
+ * @param expected
+ *   The pointer point to value to be expected when descriptor is set.
+ * @param mask
+ *   The pointer point to comparison bitmask for the expected value.
+ * @return
+ *   Negative errno value on error, 0 on success.
Quoted 8 lines

lib/librte_ethdev/rte_ethdev_driver.h typedef int (*eth_tx_hairpin_queue_setup_t) · line 596

Quoted 6 lines
lib/librte_ethdev/rte_ethdev_driver.h +6 -0
+ *
+ * @retval 0
+ *   Success.
+ * @retval -EINVAL
+ *   Failed to get descriptor address.
+ */

The question is the same as above.

Quoted 5 lines

This is a driver function pointer, so return value will depend on driver implementation. So far we only see 0 or -EINVAL values from the driver itself, while -ENOTSUP will be returned by ethdev in case there is no driver implementation of this function. So, in this case this is correct.

Ok.

Quoted 41 lines
Quoted 8 lines

lib/librte_ethdev/rte_ethdev_driver.h typedef int (*eth_tx_hairpin_queue_setup_t)

Quoted 8 lines
lib/librte_ethdev/rte_ethdev_driver.h +5 -0
+typedef int (*eth_get_wake_addr_t)
+	(void *rxq, volatile void **tail_desc_addr,
+	 uint64_t *expected, uint64_t *mask);
+
+
  /**
   * @internal A structure containing the functions exported by an

Ethernet

Quoted 24 lines
Quoted 24 lines

driver.
*/

lib/librte_ethdev/rte_ethdev_driver.h +3 -0
@@ -713,6 +738,9 @@ struct eth_dev_ops {
  	/**< Set up device RX hairpin queue. */
  	eth_tx_hairpin_queue_setup_t tx_hairpin_queue_setup;
  	/**< Set up device TX hairpin queue. */
+	eth_get_wake_addr_t get_wake_addr;
+	/**< Get wake up address. */
+
  };
 
  /**
lib/librte_ethdev/rte_ethdev_version.map +1 -0
index c95ef5157a..3cb2093980 100644
@@ -229,6 +229,7 @@ EXPERIMENTAL {
  	# added in 20.11
  	rte_eth_link_speed_to_str;
  	rte_eth_link_to_str;
+	rte_eth_get_wake_addr;
  };
 
Quoted 3 lines
Quoted 3 lines
lib/librte_ethdev/rte_ethdev_version.map +0 -1
  INTERNAL {
--

2.17.1

--
Thanks,
Anatoly

#276 lore raw

Re: [dpdk-dev] [PATCH v5 04/10] ethdev: add simple power management API

Quoted 107 lines · Jia
Quoted 107 lines

-----Original Message-----
From: Burakov, Anatoly <[email protected]>
Sent: Wednesday, October 14, 2020 5:07 PM
To: Guo, Jia <[email protected]>; [email protected]
Cc: Ma, Liang J <[email protected]>; Thomas Monjalon <[email protected]>; Yigit, Ferruh <[email protected]>; Andrew Rybchenko <[email protected]>; Ray Kinsella <[email protected]>; Neil Horman <[email protected]>; Hunt, David <[email protected]>; Ananyev, Konstantin <[email protected]>; [email protected]; Richardson, Bruce <[email protected]>; McDaniel, Timothy <[email protected]>; Eads, Gage <[email protected]>; Macnamara, Chris <[email protected]>
Subject: Re: [dpdk-dev] [PATCH v5 04/10] ethdev: add simple power management API

Quoted 17 lines · Jia
Quoted 17 lines

-----Original Message-----
From: dev <[email protected]> On Behalf Of Anatoly Burakov
Sent: Saturday, October 10, 2020 12:02 AM
To: [email protected]
Cc: Ma, Liang J <[email protected]>; Thomas Monjalon <[email protected]>; Yigit, Ferruh <[email protected]>; Andrew Rybchenko <[email protected]>; Ray Kinsella <[email protected]>; Neil Horman <[email protected]>; Hunt, David <[email protected]>; Ananyev, Konstantin <[email protected]>; [email protected]; Richardson, Bruce <[email protected]>; McDaniel, Timothy <[email protected]>; Eads, Gage <[email protected]>; Macnamara, Chris <[email protected]>
Subject: [dpdk-dev] [PATCH v5 04/10] ethdev: add simple power management API

Quoted 8 lines
Quoted 8 lines

From: Liang Ma <[email protected]>

Add a simple API to allow getting address of next RX descriptor from the PMD, as well as release notes information.

---

Hi Jia,

Thanks for your review. Responses below.

Quoted 11 lines
Quoted 11 lines

Notes:
v5:
- Bring function format in line with other functions in the file
- Ensure the API is supported by the driver before calling it
(Konstantin)

   doc/guides/rel_notes/release_20_11.rst   | 16 ++++++++++++++
   lib/librte_ethdev/rte_ethdev.c           | 17 ++++++++++++++
   lib/librte_ethdev/rte_ethdev.h           | 24 ++++++++++++++++++++
   lib/librte_ethdev/rte_ethdev_driver.h    | 28

++++++++++++++++++++++++

Quoted 11 lines

doc/guides/rel_notes/release_20_11.rst New Features · line 56

Quoted 11 lines
   lib/librte_ethdev/rte_ethdev_version.map |  1 +
   5 files changed, 86 insertions(+)
doc/guides/rel_notes/release_20_11.rst +0 -0
index 808bdc4e54..e85af5d3e9 100644
@@ -55,6 +55,11 @@ New Features
        Also, make sure to start the actual text at the margin.
 

=======================================================

Quoted 35 lines
Quoted 13 lines
doc/guides/rel_notes/release_20_11.rst +1 -0
+* **ethdev: add 1 new EXPERIMENTAL API for PMD power

management.**

doc/guides/rel_notes/release_20_11.rst +4 -0
+
+  * ``rte_eth_get_wake_addr()``
+  * add new eth_dev_ops ``get_wake_addr``
+
   * **Updated Broadcom bnxt driver.**
 
     Updated the Broadcom bnxt driver with new features and

improvements,
including:

doc/guides/rel_notes/release_20_11.rst New Features · line 146

Quoted 6 lines
doc/guides/rel_notes/release_20_11.rst +3 -0
@@ -136,6 +141,17 @@ New Features
     * Extern objects and functions can be plugged into the pipeline.
     * Transaction-oriented table updates.
 
+* **Add PMD power management mechanism**
+
+  3 new Ethernet PMD power management mechanism is added through

" mechanisms are " please.

Quoted 11 lines
doc/guides/rel_notes/release_20_11.rst +7 -0
+ existing  RX callback infrastructure.
+
+  * Add power saving scheme based on UMWAIT instruction (x86 only)
+  * Add power saving scheme based on ``rte_pause()``
+  * Add power saving scheme based on frequency scaling through the
+ power library
+  * Add new EXPERIMENTAL API

``rte_power_pmd_mgmt_queue_enable()``
+ * Add new EXPERIMENTAL API
``rte_power_pmd_mgmt_queue_disable()``
+

Could this doc be separate to other specific patch if it is not related with this

Quoted 8 lines
Quoted 6 lines

patch?

It is related - it's the doc changes that add mention of this API. I was under the impression current policy was having doc updates in the same patch as the changes made?

Do you think this part would be better separate into [PATCH v5 05/10]?

Oh, sorry, you're right, these aren't related, as this functionality isn't in this patch yet. Will fix.

Quoted 160 lines
Quoted 111 lines
Quoted 12 lines

lib/librte_ethdev/rte_ethdev.c rte_eth_tx_burst_mode_get(uint16_t port_id, · line 4805

Quoted 12 lines


   Removed Items
   -------------
(quoted diff) +0 -0

b/lib/librte_ethdev/rte_ethdev.c index 48d1333b17..352108f43c 100644

lib/librte_ethdev/rte_ethdev.c +0 -0
@@ -4804,6 +4804,23 @@ rte_eth_tx_burst_mode_get(uint16_t port_id,
 uint16_t queue_id,
   		       dev->dev_ops->tx_burst_mode_get(dev, queue_id,

mode)); }

Quoted 45 lines
Quoted 45 lines
lib/librte_ethdev/rte_ethdev.c +16 -0
+int
+rte_eth_get_wake_addr(uint16_t port_id, uint16_t queue_id,
+		volatile void **wake_addr, uint64_t *expected, uint64_t
 *mask) {
+	struct rte_eth_dev *dev;
+
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_wake_addr, -
 ENOTSUP);
+
+	return eth_err(port_id,
+		dev->dev_ops->get_wake_addr(dev->data-
 > rx_queues[queue_id],
+			wake_addr, expected, mask));
+}
+
   int
   rte_eth_dev_set_mc_addr_list(uint16_t port_id,
   			     struct rte_ether_addr *mc_addr_set, diff --git

a/lib/librte_ethdev/rte_ethdev.h b/lib/librte_ethdev/rte_ethdev.h index
d2bf74f128..a6cfe3cd57 100644

lib/librte_ethdev/rte_ethdev.h +13 -0
@@ -4014,6 +4014,30 @@ __rte_experimental  int
 rte_eth_tx_burst_mode_get(uint16_t port_id, uint16_t queue_id,
   	struct rte_eth_burst_mode *mode);
 
+/**
+ * Retrieve the wake up address from specific queue
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param queue_id
+ *   The Tx queue on the Ethernet device for which information
+ *   will be retrieved.
+ * @param wake_addr
+ *   The pointer point to the address which is used for monitoring.
+ * @param expected
+ *   The pointer point to value to be expected when descriptor is set.
+ * @param mask
Quoted 8 lines

lib/librte_ethdev/rte_ethdev.h __rte_experimental · line 4035

Quoted 6 lines
lib/librte_ethdev/rte_ethdev.h +6 -0
+ *   The pointer point to comparison bitmask for the expected value.
+ *
+ * @return
+ *   - 0: Success.
+ *   -EINVAL: Failed to get wake address.
+ */

Is that "-EINVAL " is the only error value which will be return?

Also -ENOTSUP, i'll add this, thanks.

Quoted 8 lines

lib/librte_ethdev/rte_ethdev.h __rte_experimental

Quoted 8 lines
lib/librte_ethdev/rte_ethdev.h +5 -0
+__rte_experimental
+int rte_eth_get_wake_addr(uint16_t port_id, uint16_t queue_id,
+			  volatile void **wake_addr,
+			  uint64_t *expected, uint64_t *mask);
+
   /**
    * Retrieve device registers and register attributes (number of registers

and

Quoted 24 lines
Quoted 24 lines
lib/librte_ethdev/rte_ethdev.h +0 -0
    * register size)
lib/librte_ethdev/rte_ethdev_driver.h +14 -0
index c3062c246c..935d46f25c 100644
@@ -574,6 +574,31 @@ typedef int (*eth_tx_hairpin_queue_setup_t)
   	 uint16_t nb_tx_desc,
   	 const struct rte_eth_hairpin_conf *hairpin_conf);
 
+/**
+ * @internal
+ * Get the Wake up address.
+ *
+ * @param rxq
+ *   Ethdev queue pointer.
+ * @param tail_desc_addr
+ *   The pointer point to descriptor address var.
+ * @param expected
+ *   The pointer point to value to be expected when descriptor is set.
+ * @param mask
+ *   The pointer point to comparison bitmask for the expected value.
+ * @return
+ *   Negative errno value on error, 0 on success.
Quoted 8 lines

lib/librte_ethdev/rte_ethdev_driver.h typedef int (*eth_tx_hairpin_queue_setup_t) · line 596

Quoted 6 lines
lib/librte_ethdev/rte_ethdev_driver.h +6 -0
+ *
+ * @retval 0
+ *   Success.
+ * @retval -EINVAL
+ *   Failed to get descriptor address.
+ */

The question is the same as above.

Quoted 5 lines

This is a driver function pointer, so return value will depend on driver implementation. So far we only see 0 or -EINVAL values from the driver itself, while -ENOTSUP will be returned by ethdev in case there is no driver implementation of this function. So, in this case this is correct.

Ok.

Quoted 41 lines
Quoted 8 lines

lib/librte_ethdev/rte_ethdev_driver.h typedef int (*eth_tx_hairpin_queue_setup_t)

Quoted 8 lines
lib/librte_ethdev/rte_ethdev_driver.h +5 -0
+typedef int (*eth_get_wake_addr_t)
+	(void *rxq, volatile void **tail_desc_addr,
+	 uint64_t *expected, uint64_t *mask);
+
+
   /**
    * @internal A structure containing the functions exported by an

Ethernet

Quoted 24 lines
Quoted 24 lines

driver.

    */
lib/librte_ethdev/rte_ethdev_driver.h +3 -0
@@ -713,6 +738,9 @@ struct eth_dev_ops {
   	/**< Set up device RX hairpin queue. */
   	eth_tx_hairpin_queue_setup_t tx_hairpin_queue_setup;
   	/**< Set up device TX hairpin queue. */
+	eth_get_wake_addr_t get_wake_addr;
+	/**< Get wake up address. */
+
   };
 
   /**
lib/librte_ethdev/rte_ethdev_version.map +1 -0
index c95ef5157a..3cb2093980 100644
@@ -229,6 +229,7 @@ EXPERIMENTAL {
   	# added in 20.11
   	rte_eth_link_speed_to_str;
   	rte_eth_link_to_str;
+	rte_eth_get_wake_addr;
   };
 
Quoted 3 lines
Quoted 3 lines
lib/librte_ethdev/rte_ethdev_version.map +0 -1
   INTERNAL {
--

2.17.1

--
Thanks,
Anatoly

Signature · 2 lines
Thanks,
Anatoly
#277 lore raw

Re: [dpdk-dev] [PATCH v5 04/10] ethdev: add simple power management API

In reply to Burakov, Anatoly
Quoted 87 lines · Anatoly
Quoted 17 lines · Jia
Quoted 17 lines

-----Original Message-----
From: dev <[email protected]> On Behalf Of Anatoly Burakov
Sent: Saturday, October 10, 2020 12:02 AM
To: [email protected]
Cc: Ma, Liang J <[email protected]>; Thomas Monjalon <[email protected]>; Yigit, Ferruh <[email protected]>; Andrew Rybchenko <[email protected]>; Ray Kinsella <[email protected]>; Neil Horman <[email protected]>; Hunt, David <[email protected]>; Ananyev, Konstantin <[email protected]>; [email protected]; Richardson, Bruce <[email protected]>; McDaniel, Timothy <[email protected]>; Eads, Gage <[email protected]>; Macnamara, Chris <[email protected]>
Subject: [dpdk-dev] [PATCH v5 04/10] ethdev: add simple power management API

Quoted 8 lines
Quoted 8 lines

From: Liang Ma <[email protected]>

Add a simple API to allow getting address of next RX descriptor from the PMD, as well as release notes information.

---

Hi Jia,

Thanks for your review. Responses below.

Quoted 42 lines
Quoted 33 lines

Notes:
v5:
- Bring function format in line with other functions in the file
- Ensure the API is supported by the driver before calling it (Konstantin)

  doc/guides/rel_notes/release_20_11.rst   | 16 ++++++++++++++
  lib/librte_ethdev/rte_ethdev.c           | 17 ++++++++++++++
  lib/librte_ethdev/rte_ethdev.h           | 24 ++++++++++++++++++++
  lib/librte_ethdev/rte_ethdev_driver.h    | 28 ++++++++++++++++++++++++
  lib/librte_ethdev/rte_ethdev_version.map |  1 +
  5 files changed, 86 insertions(+)
doc/guides/rel_notes/release_20_11.rst +1 -0
index 808bdc4e54..e85af5d3e9 100644
@@ -55,6 +55,11 @@ New Features
       Also, make sure to start the actual text at the margin.
       =======================================================
 
+* **ethdev: add 1 new EXPERIMENTAL API for PMD power

management.**

doc/guides/rel_notes/release_20_11.rst +4 -0
+
+  * ``rte_eth_get_wake_addr()``
+  * add new eth_dev_ops ``get_wake_addr``
+
  * **Updated Broadcom bnxt driver.**
 
    Updated the Broadcom bnxt driver with new features and improvements,

including:

doc/guides/rel_notes/release_20_11.rst New Features · line 146

Quoted 6 lines
doc/guides/rel_notes/release_20_11.rst +3 -0
@@ -136,6 +141,17 @@ New Features
    * Extern objects and functions can be plugged into the pipeline.
    * Transaction-oriented table updates.
 
+* **Add PMD power management mechanism**
+
+  3 new Ethernet PMD power management mechanism is added through

" mechanisms are " please.

Quoted 13 lines
Quoted 11 lines
doc/guides/rel_notes/release_20_11.rst +7 -0
+ existing  RX callback infrastructure.
+
+  * Add power saving scheme based on UMWAIT instruction (x86 only)
+  * Add power saving scheme based on ``rte_pause()``
+  * Add power saving scheme based on frequency scaling through the
+ power library
+  * Add new EXPERIMENTAL API

``rte_power_pmd_mgmt_queue_enable()``
+ * Add new EXPERIMENTAL API
``rte_power_pmd_mgmt_queue_disable()``
+

Could this doc be separate to other specific patch if it is not related with this patch?

Quoted 4 lines

It is related - it's the doc changes that add mention of this API. I was under the impression current policy was having doc updates in the same patch as the changes made?

Yes, that is the case. Doc changes should be made alongside the relevant code changes.

#278 lore raw

PATCH v5 5/10 power: add PMD power management API and callback

In reply to Anatoly Burakov

From: Liang Ma <[email protected]>

Add a simple on/off switch that will enable saving power when no packets are arriving. It is based on counting the number of empty polls and, when the number reaches a certain threshold, entering an architecture-defined optimized power state that will either wait until a TSC timestamp expires, or when packets arrive.

This API mandates a core-to-single-queue mapping (that is, multiple queued per device are supported, but they have to be polled on different cores).

This design is using PMD RX callbacks.

1. UMWAIT/UMONITOR:

When a certain threshold of empty polls is reached, the core will go into a power optimized sleep while waiting on an address of next RX descriptor to be written to.

2. Pause instruction

Instead of move the core into deeper C state, this method uses the pause instruction to avoid busy polling.

3. Frequency scaling
Reuse existing DPDK power library to scale up/down core frequency depending on traffic volume.

---

Notes:
v5:
- Make error checking more robust
- Prevent initializing scaling if ACPI or PSTATE env wasn't set
- Prevent initializing UMWAIT path if PMD doesn't support get_wake_addr
- Add some debug logging
- Replace x86-specific code path to generic path using the intrinsic check

 lib/librte_power/meson.build           |   5 +-
 lib/librte_power/pmd_mgmt.h            |  38 ++++
 lib/librte_power/rte_power_pmd_mgmt.c  | 244 +++++++++++++++++++++++++
 lib/librte_power/rte_power_pmd_mgmt.h  |  88 +++++++++
 lib/librte_power/rte_power_version.map |   4 +
 5 files changed, 377 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_power/pmd_mgmt.h
 create mode 100644 lib/librte_power/rte_power_pmd_mgmt.c
 create mode 100644 lib/librte_power/rte_power_pmd_mgmt.h
lib/librte_power/meson.build +3 -2
index 78c031c943..cc3c7a8646 100644
@@ -9,6 +9,7 @@ sources = files('rte_power.c', 'power_acpi_cpufreq.c',
 		'power_kvm_vm.c', 'guest_channel.c',
 		'rte_power_empty_poll.c',
 		'power_pstate_cpufreq.c',
+		'rte_power_pmd_mgmt.c',
 		'power_common.c')
-headers = files('rte_power.h','rte_power_empty_poll.h')
-deps += ['timer']
+headers = files('rte_power.h','rte_power_empty_poll.h','rte_power_pmd_mgmt.h')
+deps += ['timer' ,'ethdev']
lib/librte_power/pmd_mgmt.h new file +38 -0
new file mode 100644
index 0000000000..20be53bacf
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2020 Intel Corporation
+ */
+
+#ifndef _PMD_MGMT_H
+#define _PMD_MGMT_H
+
+/**
+ * @file
+ * Power Management
+ */
+
+/**
+ * Possible power management states of an ethdev port.
+ */
+enum pmd_mgmt_state {
+	/** Device power management is disabled. */
+	PMD_MGMT_DISABLED = 0,
+	/** Device power management is enabled. */
+	PMD_MGMT_ENABLED,
+};
+
+struct pmd_queue_cfg {
+	enum pmd_mgmt_state pwr_mgmt_state;
+	/**< Power mgmt Callback mode */
+	enum rte_power_pmd_mgmt_type cb_mode;
+	/**< Empty poll number */
+	uint16_t empty_poll_stats;
+	/**< Callback instance  */
+	const struct rte_eth_rxtx_callback *cur_cb;
+} __rte_cache_aligned;
+
+struct pmd_port_cfg {
+	int  ref_cnt;
+	struct pmd_queue_cfg *queue_cfg;
+} __rte_cache_aligned;
+
+#endif
lib/librte_power/rte_power_pmd_mgmt.c new file +244 -0

244 lines not on this page · raw message

lib/librte_power/rte_power_pmd_mgmt.h new file +88 -0

88 lines not on this page · raw message

lib/librte_power/rte_power_version.map +4 -0
index 69ca9af616..3f2f6cd6f6 100644
@@ -34,4 +34,8 @@ EXPERIMENTAL {
 	rte_power_guest_channel_receive_msg;
 	rte_power_poll_stat_fetch;
 	rte_power_poll_stat_update;
+	# added in 20.11
+	rte_power_pmd_mgmt_queue_enable;
+	rte_power_pmd_mgmt_queue_disable;
+
 };
Signature · 1 line
2.17.1
#279 lore raw

PATCH v5 6/10 net/ixgbe: implement power management API

In reply to Anatoly Burakov

From: Liang Ma <[email protected]>

Implement support for the power management API by implementing a get_wake_addr function that will return an address of an RX ring's status bit.

---
 drivers/net/ixgbe/ixgbe_ethdev.c |  1 +
 drivers/net/ixgbe/ixgbe_rxtx.c   | 22 ++++++++++++++++++++++
 drivers/net/ixgbe/ixgbe_rxtx.h   |  2 ++
 3 files changed, 25 insertions(+)
drivers/net/ixgbe/ixgbe_ethdev.c +1 -0
index 0b98e210e7..30b3f416d4 100644
@@ -588,6 +588,7 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.udp_tunnel_port_del  = ixgbe_dev_udp_tunnel_port_del,
 	.tm_ops_get           = ixgbe_tm_ops_get,
 	.tx_done_cleanup      = ixgbe_dev_tx_done_cleanup,
+	.get_wake_addr        = ixgbe_get_wake_addr,
 };
 
 /*
drivers/net/ixgbe/ixgbe_rxtx.c +22 -0
index 977ecf5137..7a9fd2aec6 100644
@@ -1366,6 +1366,28 @@ const uint32_t
 		RTE_PTYPE_INNER_L3_IPV4_EXT | RTE_PTYPE_INNER_L4_UDP,
 };
 
+int ixgbe_get_wake_addr(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask)
+{
+	volatile union ixgbe_adv_rx_desc *rxdp;
+	struct ixgbe_rx_queue *rxq = rx_queue;
+	uint16_t desc;
+
+	desc = rxq->rx_tail;
+	rxdp = &rxq->rx_ring[desc];
+	/* watch for changes in status bit */
+	*tail_desc_addr = &rxdp->wb.upper.status_error;
+
+	/*
+	 * we expect the DD bit to be set to 1 if this descriptor was already
+	 * written to.
+	 */
+	*expected = rte_cpu_to_le_32(IXGBE_RXDADV_STAT_DD);
+	*mask = rte_cpu_to_le_32(IXGBE_RXDADV_STAT_DD);
+
+	return 0;
+}
+
 /* @note: fix ixgbe_dev_supported_ptypes_get() if any change here. */
 static inline uint32_t
 ixgbe_rxd_pkt_info_to_pkt_type(uint32_t pkt_info, uint16_t ptype_mask)
drivers/net/ixgbe/ixgbe_rxtx.h +2 -0
index 7e09291b22..75020fa2fc 100644
@@ -299,5 +299,7 @@ uint64_t ixgbe_get_tx_port_offloads(struct rte_eth_dev *dev);
 uint64_t ixgbe_get_rx_queue_offloads(struct rte_eth_dev *dev);
 uint64_t ixgbe_get_rx_port_offloads(struct rte_eth_dev *dev);
 uint64_t ixgbe_get_tx_queue_offloads(struct rte_eth_dev *dev);
+int ixgbe_get_wake_addr(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask);
 
 #endif /* _IXGBE_RXTX_H_ */
Signature · 1 line
2.17.1
Acked-by on v5 6/10
#280 lore raw

Re: [dpdk-dev] [PATCH v5 06/10] net/ixgbe: implement power management API

Hi Liang,

Quoted 57 lines

-----Original Message-----
From: Burakov, Anatoly <[email protected]>
Sent: Saturday, October 10, 2020 00:02
To: [email protected]
Cc: Ma, Liang J <[email protected]>; Guo, Jia <[email protected]>; Wang, Haiyue <[email protected]>; Hunt, David <[email protected]>; Ananyev, Konstantin <[email protected]>; [email protected]; Richardson, Bruce <[email protected]>; [email protected]; McDaniel, Timothy <[email protected]>; Eads, Gage <[email protected]>; Macnamara, Chris <[email protected]>
Subject: [PATCH v5 06/10] net/ixgbe: implement power management API

From: Liang Ma <[email protected]>

Implement support for the power management API by implementing a get_wake_addr function that will return an address of an RX ring's status bit.

---
 drivers/net/ixgbe/ixgbe_ethdev.c |  1 +
 drivers/net/ixgbe/ixgbe_rxtx.c   | 22 ++++++++++++++++++++++
 drivers/net/ixgbe/ixgbe_rxtx.h   |  2 ++
 3 files changed, 25 insertions(+)
drivers/net/ixgbe/ixgbe_ethdev.c +1 -0
index 0b98e210e7..30b3f416d4 100644
@@ -588,6 +588,7 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.udp_tunnel_port_del  = ixgbe_dev_udp_tunnel_port_del,
 	.tm_ops_get           = ixgbe_tm_ops_get,
 	.tx_done_cleanup      = ixgbe_dev_tx_done_cleanup,
+	.get_wake_addr        = ixgbe_get_wake_addr,
 };
 
 /*
drivers/net/ixgbe/ixgbe_rxtx.c +12 -0
index 977ecf5137..7a9fd2aec6 100644
@@ -1366,6 +1366,28 @@ const uint32_t
 		RTE_PTYPE_INNER_L3_IPV4_EXT | RTE_PTYPE_INNER_L4_UDP,
 };
 
+int ixgbe_get_wake_addr(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask)
+{
+	volatile union ixgbe_adv_rx_desc *rxdp;
+	struct ixgbe_rx_queue *rxq = rx_queue;
+	uint16_t desc;
+
+	desc = rxq->rx_tail;
+	rxdp = &rxq->rx_ring[desc];
+	/* watch for changes in status bit */
+	*tail_desc_addr = &rxdp->wb.upper.status_error;
+

drivers/net/ixgbe/ixgbe_rxtx.c const uint32_t · line 1390

Quoted 10 lines
drivers/net/ixgbe/ixgbe_rxtx.c +10 -0
+	/*
+	 * we expect the DD bit to be set to 1 if this descriptor was already
+	 * written to.
+	 */
+	*expected = rte_cpu_to_le_32(IXGBE_RXDADV_STAT_DD);
+	*mask = rte_cpu_to_le_32(IXGBE_RXDADV_STAT_DD);
+
+	return 0;
+}
+

I'm wondering that whether the '.get_wake_addr' can be specific to like 'rxq_tailq_addr_get' ? So that one day this wake up mechanism can be applied to 'txq_tailq_addr_get' ? :-)

Also, "volatile void **tail_desc_addr, uint64_t *expected, uint64_t *mask" can be merged into 'struct xxx' ? So that you can expand the API easily.

Just my thoughts.

Anyway, LGTM

Quoted 2 lines
drivers/net/ixgbe/ixgbe_rxtx.c +0 -1
--

2.17.1

#281 lore raw

Re: [dpdk-dev] [PATCH v5 06/10] net/ixgbe: implement power management API

Quoted 74 lines · Haiyue

Hi Liang,

Quoted 57 lines

-----Original Message-----
From: Burakov, Anatoly <[email protected]>
Sent: Saturday, October 10, 2020 00:02
To: [email protected]
Cc: Ma, Liang J <[email protected]>; Guo, Jia <[email protected]>; Wang, Haiyue <[email protected]>; Hunt, David <[email protected]>; Ananyev, Konstantin <[email protected]>; [email protected]; Richardson, Bruce <[email protected]>; [email protected]; McDaniel, Timothy <[email protected]>; Eads, Gage <[email protected]>; Macnamara, Chris <[email protected]>
Subject: [PATCH v5 06/10] net/ixgbe: implement power management API

From: Liang Ma <[email protected]>

Implement support for the power management API by implementing a get_wake_addr function that will return an address of an RX ring's status bit.

---
  drivers/net/ixgbe/ixgbe_ethdev.c |  1 +
  drivers/net/ixgbe/ixgbe_rxtx.c   | 22 ++++++++++++++++++++++
  drivers/net/ixgbe/ixgbe_rxtx.h   |  2 ++
  3 files changed, 25 insertions(+)
drivers/net/ixgbe/ixgbe_ethdev.c +1 -0
index 0b98e210e7..30b3f416d4 100644
@@ -588,6 +588,7 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
  .udp_tunnel_port_del  = ixgbe_dev_udp_tunnel_port_del,
  .tm_ops_get           = ixgbe_tm_ops_get,
  .tx_done_cleanup      = ixgbe_dev_tx_done_cleanup,
+.get_wake_addr        = ixgbe_get_wake_addr,
  };
 
  /*
drivers/net/ixgbe/ixgbe_rxtx.c +12 -0
index 977ecf5137..7a9fd2aec6 100644
@@ -1366,6 +1366,28 @@ const uint32_t
  RTE_PTYPE_INNER_L3_IPV4_EXT | RTE_PTYPE_INNER_L4_UDP,
  };
 
+int ixgbe_get_wake_addr(void *rx_queue, volatile void **tail_desc_addr,
+uint64_t *expected, uint64_t *mask)
+{
+volatile union ixgbe_adv_rx_desc *rxdp;
+struct ixgbe_rx_queue *rxq = rx_queue;
+uint16_t desc;
+
+desc = rxq->rx_tail;
+rxdp = &rxq->rx_ring[desc];
+/* watch for changes in status bit */
+*tail_desc_addr = &rxdp->wb.upper.status_error;
+

drivers/net/ixgbe/ixgbe_rxtx.c const uint32_t · line 1390

Quoted 10 lines
drivers/net/ixgbe/ixgbe_rxtx.c +10 -0
+/*
+ * we expect the DD bit to be set to 1 if this descriptor was already
+ * written to.
+ */
+*expected = rte_cpu_to_le_32(IXGBE_RXDADV_STAT_DD);
+*mask = rte_cpu_to_le_32(IXGBE_RXDADV_STAT_DD);
+
+return 0;
+}
+

I'm wondering that whether the '.get_wake_addr' can be specific to like 'rxq_tailq_addr_get' ? So that one day this wake up mechanism can be applied to 'txq_tailq_addr_get' ? :-)

Quoted 8 lines

Also, "volatile void **tail_desc_addr, uint64_t *expected, uint64_t *mask" can be merged into 'struct xxx' ? So that you can expand the API easily.

Just my thoughts.

Anyway, LGTM

Great point, will think of how to address it.

Quoted 3 lines
Quoted 3 lines
drivers/net/ixgbe/ixgbe_rxtx.c +0 -1
--

2.17.1

Signature · 2 lines
Thanks,
Anatoly
#282 lore raw

Re: [dpdk-dev] [PATCH v5 06/10] net/ixgbe: implement power management API

In reply to Wang, Haiyue
Quoted 65 lines · Haiyue

Hi Liang,

Quoted 63 lines

-----Original Message-----
From: Burakov, Anatoly <[email protected]>
Sent: Saturday, October 10, 2020 00:02
To: [email protected]
Cc: Ma, Liang J <[email protected]>; Guo, Jia <[email protected]>; Wang, Haiyue <[email protected]>; Hunt, David <[email protected]>; Ananyev, Konstantin <[email protected]>; [email protected]; Richardson, Bruce <[email protected]>; [email protected]; McDaniel, Timothy <[email protected]>; Eads, Gage <[email protected]>; Macnamara, Chris <[email protected]>
Subject: [PATCH v5 06/10] net/ixgbe: implement power management API

From: Liang Ma <[email protected]>

Implement support for the power management API by implementing a get_wake_addr function that will return an address of an RX ring's status bit.

---
  drivers/net/ixgbe/ixgbe_ethdev.c |  1 +
  drivers/net/ixgbe/ixgbe_rxtx.c   | 22 ++++++++++++++++++++++
  drivers/net/ixgbe/ixgbe_rxtx.h   |  2 ++
  3 files changed, 25 insertions(+)
drivers/net/ixgbe/ixgbe_ethdev.c +1 -0
index 0b98e210e7..30b3f416d4 100644
@@ -588,6 +588,7 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
  .udp_tunnel_port_del  = ixgbe_dev_udp_tunnel_port_del,
  .tm_ops_get           = ixgbe_tm_ops_get,
  .tx_done_cleanup      = ixgbe_dev_tx_done_cleanup,
+.get_wake_addr        = ixgbe_get_wake_addr,
  };
 
  /*
drivers/net/ixgbe/ixgbe_rxtx.c +18 -0
index 977ecf5137..7a9fd2aec6 100644
@@ -1366,6 +1366,28 @@ const uint32_t
  RTE_PTYPE_INNER_L3_IPV4_EXT | RTE_PTYPE_INNER_L4_UDP,
  };
 
+int ixgbe_get_wake_addr(void *rx_queue, volatile void **tail_desc_addr,
+uint64_t *expected, uint64_t *mask)
+{
+volatile union ixgbe_adv_rx_desc *rxdp;
+struct ixgbe_rx_queue *rxq = rx_queue;
+uint16_t desc;
+
+desc = rxq->rx_tail;
+rxdp = &rxq->rx_ring[desc];
+/* watch for changes in status bit */
+*tail_desc_addr = &rxdp->wb.upper.status_error;
+
+/*
+ * we expect the DD bit to be set to 1 if this descriptor was already
+ * written to.
+ */
+*expected = rte_cpu_to_le_32(IXGBE_RXDADV_STAT_DD);
+*mask = rte_cpu_to_le_32(IXGBE_RXDADV_STAT_DD);
Quoted 8 lines

drivers/net/ixgbe/ixgbe_rxtx.c const uint32_t · line 1390

Quoted 4 lines
drivers/net/ixgbe/ixgbe_rxtx.c +4 -0
+
+return 0;
+}
+

I'm wondering that whether the '.get_wake_addr' can be specific to like 'rxq_tailq_addr_get' ? So that one day this wake up mechanism can be applied to 'txq_tailq_addr_get' ? :-)

What would be the point of sleeping on TX queue though?

Quoted 3 lines

Also, "volatile void **tail_desc_addr, uint64_t *expected, uint64_t *mask" can be merged into 'struct xxx' ? So that you can expand the API easily.

Actually, i don't think we can do that. Well, we can, but we'll have to either define a new struct for ethdev, or define it in the power library and make ethdev dependent on the power library. The latter is a no-go, and the former i don't think is a good idea because adding a new struct to ethdev is big deal and i'd like to avoid that if i can.

Quoted 9 lines

Just my thoughts.

Anyway, LGTM

Quoted 2 lines
drivers/net/ixgbe/ixgbe_rxtx.c +0 -1
--

2.17.1

Signature · 2 lines
Thanks,
Anatoly
#283 lore raw

Re: [dpdk-dev] [PATCH v5 06/10] net/ixgbe: implement power management API

Quoted 88 lines

-----Original Message-----
From: Burakov, Anatoly <[email protected]>
Sent: Monday, October 12, 2020 17:45
To: Wang, Haiyue <[email protected]>; [email protected]
Cc: Ma, Liang J <[email protected]>; Guo, Jia <[email protected]>; Hunt, David <[email protected]>; Ananyev, Konstantin <[email protected]>; [email protected]; Richardson, Bruce <[email protected]>; [email protected]; McDaniel, Timothy <[email protected]>; Eads, Gage <[email protected]>; Macnamara, Chris <[email protected]>
Subject: Re: [PATCH v5 06/10] net/ixgbe: implement power management API

Quoted 9 lines · Haiyue

Hi Liang,

Quoted 7 lines

-----Original Message-----
From: Burakov, Anatoly <[email protected]>
Sent: Saturday, October 10, 2020 00:02
To: [email protected]
Cc: Ma, Liang J <[email protected]>; Guo, Jia <[email protected]>; Wang, Haiyue <[email protected]>; Hunt, David <[email protected]>; Ananyev, Konstantin <[email protected]>; [email protected]; Richardson, Bruce

<[email protected]>;

Quoted 1 line
Quoted 1 line

[email protected]; McDaniel, Timothy <[email protected]>; Eads, Gage

<[email protected]>;

Quoted 55 lines
Quoted 55 lines

Macnamara, Chris <[email protected]>
Subject: [PATCH v5 06/10] net/ixgbe: implement power management API

From: Liang Ma <[email protected]>

Implement support for the power management API by implementing a get_wake_addr function that will return an address of an RX ring's status bit.

---
  drivers/net/ixgbe/ixgbe_ethdev.c |  1 +
  drivers/net/ixgbe/ixgbe_rxtx.c   | 22 ++++++++++++++++++++++
  drivers/net/ixgbe/ixgbe_rxtx.h   |  2 ++
  3 files changed, 25 insertions(+)
drivers/net/ixgbe/ixgbe_ethdev.c +1 -0
index 0b98e210e7..30b3f416d4 100644
@@ -588,6 +588,7 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
  .udp_tunnel_port_del  = ixgbe_dev_udp_tunnel_port_del,
  .tm_ops_get           = ixgbe_tm_ops_get,
  .tx_done_cleanup      = ixgbe_dev_tx_done_cleanup,
+.get_wake_addr        = ixgbe_get_wake_addr,
  };
 
  /*
drivers/net/ixgbe/ixgbe_rxtx.c +18 -0
index 977ecf5137..7a9fd2aec6 100644
@@ -1366,6 +1366,28 @@ const uint32_t
  RTE_PTYPE_INNER_L3_IPV4_EXT | RTE_PTYPE_INNER_L4_UDP,
  };
 
+int ixgbe_get_wake_addr(void *rx_queue, volatile void **tail_desc_addr,
+uint64_t *expected, uint64_t *mask)
+{
+volatile union ixgbe_adv_rx_desc *rxdp;
+struct ixgbe_rx_queue *rxq = rx_queue;
+uint16_t desc;
+
+desc = rxq->rx_tail;
+rxdp = &rxq->rx_ring[desc];
+/* watch for changes in status bit */
+*tail_desc_addr = &rxdp->wb.upper.status_error;
+
+/*
+ * we expect the DD bit to be set to 1 if this descriptor was already
+ * written to.
+ */
+*expected = rte_cpu_to_le_32(IXGBE_RXDADV_STAT_DD);
+*mask = rte_cpu_to_le_32(IXGBE_RXDADV_STAT_DD);
Quoted 8 lines

drivers/net/ixgbe/ixgbe_rxtx.c const uint32_t · line 1390

Quoted 4 lines
drivers/net/ixgbe/ixgbe_rxtx.c +4 -0
+
+return 0;
+}
+

I'm wondering that whether the '.get_wake_addr' can be specific to like 'rxq_tailq_addr_get' ? So that one day this wake up mechanism can be applied to 'txq_tailq_addr_get' ? :-)

Quoted 1 line

What would be the point of sleeping on TX queue though?

I checked, seems that the PMD uses internal index, no address, please ignore this bad idea. ;-)

Quoted 10 lines
Quoted 4 lines

Also, "volatile void **tail_desc_addr, uint64_t *expected, uint64_t *mask" can be merged into 'struct xxx' ? So that you can expand the API easily.

Actually, i don't think we can do that. Well, we can, but we'll have to either define a new struct for ethdev, or define it in the power library and make ethdev dependent on the power library. The latter is a no-go, and the former i don't think is a good idea because adding a new struct to ethdev is big deal and i'd like to avoid that if i can.

Understood the design now, thanks!

Quoted 15 lines
Quoted 10 lines

Just my thoughts.

Anyway, LGTM

Quoted 2 lines
drivers/net/ixgbe/ixgbe_rxtx.c +0 -1
--

2.17.1

--
Thanks,
Anatoly

#284 lore raw

Re: [dpdk-dev] [PATCH v5 06/10] net/ixgbe: implement power management API

In reply to Anatoly Burakov

Hi Liang,

Quoted 37 lines

-----Original Message-----
From: Burakov, Anatoly <[email protected]>
Sent: Saturday, October 10, 2020 00:02
To: [email protected]
Cc: Ma, Liang J <[email protected]>; Guo, Jia <[email protected]>; Wang, Haiyue <[email protected]>; Hunt, David <[email protected]>; Ananyev, Konstantin <[email protected]>; [email protected]; Richardson, Bruce <[email protected]>; [email protected]; McDaniel, Timothy <[email protected]>; Eads, Gage <[email protected]>; Macnamara, Chris <[email protected]>
Subject: [PATCH v5 06/10] net/ixgbe: implement power management API

From: Liang Ma <[email protected]>

Implement support for the power management API by implementing a get_wake_addr function that will return an address of an RX ring's status bit.

---
 drivers/net/ixgbe/ixgbe_ethdev.c |  1 +
 drivers/net/ixgbe/ixgbe_rxtx.c   | 22 ++++++++++++++++++++++
 drivers/net/ixgbe/ixgbe_rxtx.h   |  2 ++
 3 files changed, 25 insertions(+)
drivers/net/ixgbe/ixgbe_rxtx.c +9 -0
+int ixgbe_get_wake_addr(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask)
+{
+	volatile union ixgbe_adv_rx_desc *rxdp;
+	struct ixgbe_rx_queue *rxq = rx_queue;
+	uint16_t desc;
+
+	desc = rxq->rx_tail;
+	rxdp = &rxq->rx_ring[desc];

drivers/net/ixgbe/ixgbe_rxtx.c const uint32_t · line 1387

Quoted 10 lines
drivers/net/ixgbe/ixgbe_rxtx.c +10 -0
+	/* watch for changes in status bit */
+	*tail_desc_addr = &rxdp->wb.upper.status_error;
+
+	/*
+	 * we expect the DD bit to be set to 1 if this descriptor was already
+	 * written to.
+	 */
+	*expected = rte_cpu_to_le_32(IXGBE_RXDADV_STAT_DD);
+	*mask = rte_cpu_to_le_32(IXGBE_RXDADV_STAT_DD);
+

Seems have one issue about the byte endian:
Like for BIG endian:
*expected = rte_bswap32(IXGBE_RXDADV_STAT_DD)
!=
*expected = rte_bswap64(IXGBE_RXDADV_STAT_DD)

And in API 'rte_power_monitor', use uint64_t type to access the wake up data:

static inline void rte_power_monitor(const volatile void *p,
const uint64_t expected_value, const uint64_t value_mask, const uint64_t tsc_timestamp)

{
	if (value_mask) {
			const uint64_t cur_value = *(const volatile uint64_t *)p;
			const uint64_t masked = cur_value & value_mask;
			/* if the masked value is already matching, abort */
			if (masked == expected_value)
				return;
		}

So that we need the wake up address type like 16/32/64b ?

Quoted 2 lines

--
2.17.1

#285 lore raw

Re: [dpdk-dev] [PATCH v5 06/10] net/ixgbe: implement power management API

Quoted 72 lines · Haiyue

Hi Liang,

Quoted 37 lines

-----Original Message-----
From: Burakov, Anatoly <[email protected]>
Sent: Saturday, October 10, 2020 00:02
To: [email protected]
Cc: Ma, Liang J <[email protected]>; Guo, Jia <[email protected]>; Wang, Haiyue <[email protected]>; Hunt, David <[email protected]>; Ananyev, Konstantin <[email protected]>; [email protected]; Richardson, Bruce <[email protected]>; [email protected]; McDaniel, Timothy <[email protected]>; Eads, Gage <[email protected]>; Macnamara, Chris <[email protected]>
Subject: [PATCH v5 06/10] net/ixgbe: implement power management API

From: Liang Ma <[email protected]>

Implement support for the power management API by implementing a get_wake_addr function that will return an address of an RX ring's status bit.

---
  drivers/net/ixgbe/ixgbe_ethdev.c |  1 +
  drivers/net/ixgbe/ixgbe_rxtx.c   | 22 ++++++++++++++++++++++
  drivers/net/ixgbe/ixgbe_rxtx.h   |  2 ++
  3 files changed, 25 insertions(+)
drivers/net/ixgbe/ixgbe_rxtx.c +9 -0
+int ixgbe_get_wake_addr(void *rx_queue, volatile void **tail_desc_addr,
+uint64_t *expected, uint64_t *mask)
+{
+volatile union ixgbe_adv_rx_desc *rxdp;
+struct ixgbe_rx_queue *rxq = rx_queue;
+uint16_t desc;
+
+desc = rxq->rx_tail;
+rxdp = &rxq->rx_ring[desc];

drivers/net/ixgbe/ixgbe_rxtx.c const uint32_t · line 1387

Quoted 10 lines
drivers/net/ixgbe/ixgbe_rxtx.c +10 -0
+/* watch for changes in status bit */
+*tail_desc_addr = &rxdp->wb.upper.status_error;
+
+/*
+ * we expect the DD bit to be set to 1 if this descriptor was already
+ * written to.
+ */
+*expected = rte_cpu_to_le_32(IXGBE_RXDADV_STAT_DD);
+*mask = rte_cpu_to_le_32(IXGBE_RXDADV_STAT_DD);
+

Seems have one issue about the byte endian:
Like for BIG endian:
*expected = rte_bswap32(IXGBE_RXDADV_STAT_DD)
!=
*expected = rte_bswap64(IXGBE_RXDADV_STAT_DD)

And in API 'rte_power_monitor', use uint64_t type to access the wake up data:

static inline void rte_power_monitor(const volatile void *p, const uint64_t expected_value, const uint64_t value_mask, const uint64_t tsc_timestamp)
{
if (value_mask) {
const uint64_t cur_value = *(const volatile uint64_t *)p; const uint64_t masked = cur_value & value_mask;
/* if the masked value is already matching, abort */ if (masked == expected_value)
return;
}

Quoted 1 line

So that we need the wake up address type like 16/32/64b ?

Endian differences strike again! You're right of course.

I suspect casting everything to CPU endinanness would fix it, would it not?

Quoted 3 lines
Quoted 3 lines

--
2.17.1

Signature · 2 lines
Thanks,
Anatoly
#286 lore raw

Re: [dpdk-dev] [PATCH v5 06/10] net/ixgbe: implement power management API

Quoted 86 lines

-----Original Message-----
From: Burakov, Anatoly <[email protected]>
Sent: Monday, October 12, 2020 17:29
To: Wang, Haiyue <[email protected]>; [email protected]
Cc: Ma, Liang J <[email protected]>; Guo, Jia <[email protected]>; Hunt, David <[email protected]>; Ananyev, Konstantin <[email protected]>; [email protected]; Richardson, Bruce <[email protected]>; [email protected]; McDaniel, Timothy <[email protected]>; Eads, Gage <[email protected]>; Macnamara, Chris <[email protected]>
Subject: Re: [PATCH v5 06/10] net/ixgbe: implement power management API

Quoted 9 lines · Haiyue

Hi Liang,

Quoted 7 lines

-----Original Message-----
From: Burakov, Anatoly <[email protected]>
Sent: Saturday, October 10, 2020 00:02
To: [email protected]
Cc: Ma, Liang J <[email protected]>; Guo, Jia <[email protected]>; Wang, Haiyue <[email protected]>; Hunt, David <[email protected]>; Ananyev, Konstantin <[email protected]>; [email protected]; Richardson, Bruce

<[email protected]>;

Quoted 1 line
Quoted 1 line

[email protected]; McDaniel, Timothy <[email protected]>; Eads, Gage

<[email protected]>;

Quoted 62 lines
Quoted 29 lines

Macnamara, Chris <[email protected]>
Subject: [PATCH v5 06/10] net/ixgbe: implement power management API

From: Liang Ma <[email protected]>

Implement support for the power management API by implementing a get_wake_addr function that will return an address of an RX ring's status bit.

---
  drivers/net/ixgbe/ixgbe_ethdev.c |  1 +
  drivers/net/ixgbe/ixgbe_rxtx.c   | 22 ++++++++++++++++++++++
  drivers/net/ixgbe/ixgbe_rxtx.h   |  2 ++
  3 files changed, 25 insertions(+)
drivers/net/ixgbe/ixgbe_rxtx.c +9 -0
+int ixgbe_get_wake_addr(void *rx_queue, volatile void **tail_desc_addr,
+uint64_t *expected, uint64_t *mask)
+{
+volatile union ixgbe_adv_rx_desc *rxdp;
+struct ixgbe_rx_queue *rxq = rx_queue;
+uint16_t desc;
+
+desc = rxq->rx_tail;
+rxdp = &rxq->rx_ring[desc];

drivers/net/ixgbe/ixgbe_rxtx.c const uint32_t · line 1387

Quoted 10 lines
drivers/net/ixgbe/ixgbe_rxtx.c +10 -0
+/* watch for changes in status bit */
+*tail_desc_addr = &rxdp->wb.upper.status_error;
+
+/*
+ * we expect the DD bit to be set to 1 if this descriptor was already
+ * written to.
+ */
+*expected = rte_cpu_to_le_32(IXGBE_RXDADV_STAT_DD);
+*mask = rte_cpu_to_le_32(IXGBE_RXDADV_STAT_DD);
+

Seems have one issue about the byte endian:
Like for BIG endian:
*expected = rte_bswap32(IXGBE_RXDADV_STAT_DD)
!=
*expected = rte_bswap64(IXGBE_RXDADV_STAT_DD)

And in API 'rte_power_monitor', use uint64_t type to access the wake up data:

static inline void rte_power_monitor(const volatile void *p, const uint64_t expected_value, const uint64_t value_mask, const uint64_t tsc_timestamp)
{
if (value_mask) {
const uint64_t cur_value = *(const volatile uint64_t *)p; const uint64_t masked = cur_value & value_mask;
/* if the masked value is already matching, abort */ if (masked == expected_value)
return;
}

Quoted 5 lines
Quoted 1 line

So that we need the wake up address type like 16/32/64b ?

Endian differences strike again! You're right of course.

I suspect casting everything to CPU endinanness would fix it, would it not?

But need the same date type, if swap is needed for casting, then (u64 a = rte_bswap32(1)) != (u64 b = rte_bswap64(1))

Quoted 9 lines
Quoted 4 lines
Quoted 4 lines

--
2.17.1

--
Thanks,
Anatoly

#287 lore raw

PATCH v5 7/10 net/i40e: implement power management API

In reply to Anatoly Burakov

From: Liang Ma <[email protected]>

Implement support for the power management API by implementing a get_wake_addr function that will return an address of an RX ring's status bit.

---
 drivers/net/i40e/i40e_ethdev.c |  1 +
 drivers/net/i40e/i40e_rxtx.c   | 23 +++++++++++++++++++++++
 drivers/net/i40e/i40e_rxtx.h   |  2 ++
 3 files changed, 26 insertions(+)
drivers/net/i40e/i40e_ethdev.c +1 -0
index 943cfe71dc..cab86f8ec9 100644
@@ -513,6 +513,7 @@ static const struct eth_dev_ops i40e_eth_dev_ops = {
 	.mtu_set                      = i40e_dev_mtu_set,
 	.tm_ops_get                   = i40e_tm_ops_get,
 	.tx_done_cleanup              = i40e_tx_done_cleanup,
+	.get_wake_addr	              = i40e_get_wake_addr,
 };
 
 /* store statistics names and its offset in stats structure */
drivers/net/i40e/i40e_rxtx.c +23 -0
index 322fc1ed75..c17f27292f 100644
@@ -71,6 +71,29 @@
 #define I40E_TX_OFFLOAD_NOTSUP_MASK \
 		(PKT_TX_OFFLOAD_MASK ^ I40E_TX_OFFLOAD_MASK)
 
+int
+i40e_get_wake_addr(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask)
+{
+	struct i40e_rx_queue *rxq = rx_queue;
+	volatile union i40e_rx_desc *rxdp;
+	uint16_t desc;
+
+	desc = rxq->rx_tail;
+	rxdp = &rxq->rx_ring[desc];
+	/* watch for changes in status bit */
+	*tail_desc_addr = &rxdp->wb.qword1.status_error_len;
+
+	/*
+	 * we expect the DD bit to be set to 1 if this descriptor was already
+	 * written to.
+	 */
+	*expected = rte_cpu_to_le_64(1 << I40E_RX_DESC_STATUS_DD_SHIFT);
+	*mask = rte_cpu_to_le_64(1 << I40E_RX_DESC_STATUS_DD_SHIFT);
+
+	return 0;
+}
+
 static inline void
 i40e_rxd_to_vlan_tci(struct rte_mbuf *mb, volatile union i40e_rx_desc *rxdp)
 {
drivers/net/i40e/i40e_rxtx.h +2 -0
index 57d7b4160b..f23a2073e3 100644
@@ -248,6 +248,8 @@ uint16_t i40e_recv_scattered_pkts_vec_avx2(void *rx_queue,
 	struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
 uint16_t i40e_xmit_pkts_vec_avx2(void *tx_queue, struct rte_mbuf **tx_pkts,
 	uint16_t nb_pkts);
+int i40e_get_wake_addr(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *value);
 
 /* For each value it means, datasheet of hardware can tell more details
  *
Signature · 1 line
2.17.1
#288 lore raw

Re: [dpdk-dev] [PATCH v5 07/10] net/i40e: implement power management API

Quoted 59 lines

-----Original Message-----
From: Burakov, Anatoly <[email protected]>
Sent: Saturday, October 10, 2020 12:02 AM
To: [email protected]
Cc: Ma, Liang J <[email protected]>; Xing, Beilei <[email protected]>; Guo, Jia <[email protected]>; Hunt, David <[email protected]>; Ananyev, Konstantin <[email protected]>; [email protected]; Richardson, Bruce <[email protected]>; [email protected]; McDaniel, Timothy <[email protected]>; Eads, Gage <[email protected]>; Macnamara, Chris <[email protected]>
Subject: [PATCH v5 07/10] net/i40e: implement power management API

From: Liang Ma <[email protected]>

Implement support for the power management API by implementing a get_wake_addr function that will return an address of an RX ring's status bit.

---
 drivers/net/i40e/i40e_ethdev.c |  1 +
 drivers/net/i40e/i40e_rxtx.c   | 23 +++++++++++++++++++++++
 drivers/net/i40e/i40e_rxtx.h   |  2 ++
 3 files changed, 26 insertions(+)
drivers/net/i40e/i40e_ethdev.c +1 -0
index 943cfe71dc..cab86f8ec9 100644
@@ -513,6 +513,7 @@ static const struct eth_dev_ops i40e_eth_dev_ops = {
 	.mtu_set                      = i40e_dev_mtu_set,
 	.tm_ops_get                   = i40e_tm_ops_get,
 	.tx_done_cleanup              = i40e_tx_done_cleanup,
+	.get_wake_addr	              = i40e_get_wake_addr,
 };
 
 /* store statistics names and its offset in stats structure */ diff --git

a/drivers/net/i40e/i40e_rxtx.c b/drivers/net/i40e/i40e_rxtx.c index 322fc1ed75..c17f27292f 100644

drivers/net/i40e/i40e_rxtx.c +12 -0
@@ -71,6 +71,29 @@
 #define I40E_TX_OFFLOAD_NOTSUP_MASK \
 		(PKT_TX_OFFLOAD_MASK ^ I40E_TX_OFFLOAD_MASK)
 
+int
+i40e_get_wake_addr(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask)
+{
+	struct i40e_rx_queue *rxq = rx_queue;
+	volatile union i40e_rx_desc *rxdp;
+	uint16_t desc;
+
+	desc = rxq->rx_tail;
+	rxdp = &rxq->rx_ring[desc];
+	/* watch for changes in status bit */
+	*tail_desc_addr = &rxdp->wb.qword1.status_error_len;

drivers/net/i40e/i40e_rxtx.c line 95

Quoted 10 lines
drivers/net/i40e/i40e_rxtx.c +9 -0
+
+	/*
+	 * we expect the DD bit to be set to 1 if this descriptor was already
+	 * written to.
+	 */
+	*expected = rte_cpu_to_le_64(1 <<
 I40E_RX_DESC_STATUS_DD_SHIFT);
+	*mask = rte_cpu_to_le_64(1 << I40E_RX_DESC_STATUS_DD_SHIFT);
+
+	return 0;

Suppose that it will always success to get wake addr in i40e, right?

Quoted 20 lines
drivers/net/i40e/i40e_rxtx.c +2 -0
+}
+
 static inline void
 i40e_rxd_to_vlan_tci(struct rte_mbuf *mb, volatile union i40e_rx_desc

*rxdp) { diff --git a/drivers/net/i40e/i40e_rxtx.h b/drivers/net/i40e/i40e_rxtx.h index 57d7b4160b..f23a2073e3 100644

drivers/net/i40e/i40e_rxtx.h +2 -0
@@ -248,6 +248,8 @@ uint16_t i40e_recv_scattered_pkts_vec_avx2(void
 *rx_queue,
 	struct rte_mbuf **rx_pkts, uint16_t nb_pkts);  uint16_t
 i40e_xmit_pkts_vec_avx2(void *tx_queue, struct rte_mbuf **tx_pkts,
 	uint16_t nb_pkts);
+int i40e_get_wake_addr(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *value);
 
 /* For each value it means, datasheet of hardware can tell more details

*
--
2.17.1

#289 lore raw

Re: [dpdk-dev] [PATCH v5 07/10] net/i40e: implement power management API

Quoted 63 lines · Jia
Quoted 63 lines

-----Original Message-----
From: Burakov, Anatoly <[email protected]>
Sent: Saturday, October 10, 2020 12:02 AM
To: [email protected]
Cc: Ma, Liang J <[email protected]>; Xing, Beilei <[email protected]>; Guo, Jia <[email protected]>; Hunt, David <[email protected]>; Ananyev, Konstantin <[email protected]>; [email protected]; Richardson, Bruce <[email protected]>; [email protected]; McDaniel, Timothy <[email protected]>; Eads, Gage <[email protected]>; Macnamara, Chris <[email protected]>
Subject: [PATCH v5 07/10] net/i40e: implement power management API

From: Liang Ma <[email protected]>

Implement support for the power management API by implementing a get_wake_addr function that will return an address of an RX ring's status bit.

---
  drivers/net/i40e/i40e_ethdev.c |  1 +
  drivers/net/i40e/i40e_rxtx.c   | 23 +++++++++++++++++++++++
  drivers/net/i40e/i40e_rxtx.h   |  2 ++
  3 files changed, 26 insertions(+)
drivers/net/i40e/i40e_ethdev.c +1 -0
index 943cfe71dc..cab86f8ec9 100644
@@ -513,6 +513,7 @@ static const struct eth_dev_ops i40e_eth_dev_ops = {
  	.mtu_set                      = i40e_dev_mtu_set,
  	.tm_ops_get                   = i40e_tm_ops_get,
  	.tx_done_cleanup              = i40e_tx_done_cleanup,
+	.get_wake_addr	              = i40e_get_wake_addr,
  };
 
  /* store statistics names and its offset in stats structure */ diff --git

a/drivers/net/i40e/i40e_rxtx.c b/drivers/net/i40e/i40e_rxtx.c index 322fc1ed75..c17f27292f 100644

drivers/net/i40e/i40e_rxtx.c +16 -0
@@ -71,6 +71,29 @@
  #define I40E_TX_OFFLOAD_NOTSUP_MASK \
  		(PKT_TX_OFFLOAD_MASK ^ I40E_TX_OFFLOAD_MASK)
 
+int
+i40e_get_wake_addr(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask)
+{
+	struct i40e_rx_queue *rxq = rx_queue;
+	volatile union i40e_rx_desc *rxdp;
+	uint16_t desc;
+
+	desc = rxq->rx_tail;
+	rxdp = &rxq->rx_ring[desc];
+	/* watch for changes in status bit */
+	*tail_desc_addr = &rxdp->wb.qword1.status_error_len;
+
+	/*
+	 * we expect the DD bit to be set to 1 if this descriptor was already
+	 * written to.
Quoted 8 lines

drivers/net/i40e/i40e_rxtx.c line 94

Quoted 6 lines
drivers/net/i40e/i40e_rxtx.c +5 -0
+	 */
+	*expected = rte_cpu_to_le_64(1 <<
 I40E_RX_DESC_STATUS_DD_SHIFT);
+	*mask = rte_cpu_to_le_64(1 << I40E_RX_DESC_STATUS_DD_SHIFT);
+
+	return 0;

Suppose that it will always success to get wake addr in i40e, right?

Yes. We've already checked all the parameters (queue etc.) in ethdev, so once we're here, that means there's no way this could fail as far as i can tell.

Quoted 21 lines
Quoted 21 lines
drivers/net/i40e/i40e_rxtx.c +2 -0
+}
+
  static inline void
  i40e_rxd_to_vlan_tci(struct rte_mbuf *mb, volatile union i40e_rx_desc

*rxdp) { diff --git a/drivers/net/i40e/i40e_rxtx.h b/drivers/net/i40e/i40e_rxtx.h index 57d7b4160b..f23a2073e3 100644

drivers/net/i40e/i40e_rxtx.h +2 -0
@@ -248,6 +248,8 @@ uint16_t i40e_recv_scattered_pkts_vec_avx2(void
 *rx_queue,
  	struct rte_mbuf **rx_pkts, uint16_t nb_pkts);  uint16_t
 i40e_xmit_pkts_vec_avx2(void *tx_queue, struct rte_mbuf **tx_pkts,
  	uint16_t nb_pkts);
+int i40e_get_wake_addr(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *value);
 
  /* For each value it means, datasheet of hardware can tell more details
   *

--
2.17.1

Signature · 2 lines
Thanks,
Anatoly
Acked-by
#290 lore raw

Re: [dpdk-dev] [PATCH v5 07/10] net/i40e: implement power management API

Quoted 87 lines

-----Original Message-----
From: Burakov, Anatoly <[email protected]>
Sent: Wednesday, October 14, 2020 5:08 PM
To: Guo, Jia <[email protected]>; [email protected]
Cc: Ma, Liang J <[email protected]>; Xing, Beilei <[email protected]>; Hunt, David <[email protected]>; Ananyev, Konstantin <[email protected]>; [email protected]; Richardson, Bruce <[email protected]>; [email protected]; McDaniel, Timothy <[email protected]>; Eads, Gage <[email protected]>; Macnamara, Chris <[email protected]>
Subject: Re: [PATCH v5 07/10] net/i40e: implement power management API

Quoted 14 lines · Jia
Quoted 14 lines

-----Original Message-----
From: Burakov, Anatoly <[email protected]>
Sent: Saturday, October 10, 2020 12:02 AM
To: [email protected]
Cc: Ma, Liang J <[email protected]>; Xing, Beilei <[email protected]>; Guo, Jia <[email protected]>; Hunt, David <[email protected]>; Ananyev, Konstantin <[email protected]>; [email protected]; Richardson, Bruce <[email protected]>; [email protected]; McDaniel, Timothy <[email protected]>; Eads, Gage <[email protected]>; Macnamara, Chris <[email protected]>
Subject: [PATCH v5 07/10] net/i40e: implement power management API

Quoted 4 lines
Quoted 4 lines

From: Liang Ma <[email protected]>

Implement support for the power management API by implementing a get_wake_addr function that will return an address of an RX ring's status

bit.

Quoted 9 lines
Quoted 9 lines
---
  drivers/net/i40e/i40e_ethdev.c |  1 +
  drivers/net/i40e/i40e_rxtx.c   | 23 +++++++++++++++++++++++
  drivers/net/i40e/i40e_rxtx.h   |  2 ++
  3 files changed, 26 insertions(+)
Quoted 5 lines

drivers/net/i40e/i40e_ethdev.c static const struct eth_dev_ops i40e_eth_dev_ops

Quoted 5 lines
(quoted diff) +0 -0

b/drivers/net/i40e/i40e_ethdev.c index 943cfe71dc..cab86f8ec9 100644

drivers/net/i40e/i40e_ethdev.c +0 -0
@@ -513,6 +513,7 @@ static const struct eth_dev_ops i40e_eth_dev_ops

= {

Quoted 30 lines
Quoted 30 lines
drivers/net/i40e/i40e_ethdev.c +1 -1
  	.mtu_set                      = i40e_dev_mtu_set,
  	.tm_ops_get                   = i40e_tm_ops_get,
  	.tx_done_cleanup              = i40e_tx_done_cleanup,
+	.get_wake_addr	              = i40e_get_wake_addr,
  };
 
  /* store statistics names and its offset in stats structure */ diff
--git a/drivers/net/i40e/i40e_rxtx.c b/drivers/net/i40e/i40e_rxtx.c

index 322fc1ed75..c17f27292f 100644

drivers/net/i40e/i40e_rxtx.c +15 -0
@@ -71,6 +71,29 @@
  #define I40E_TX_OFFLOAD_NOTSUP_MASK \
  		(PKT_TX_OFFLOAD_MASK ^ I40E_TX_OFFLOAD_MASK)
 
+int
+i40e_get_wake_addr(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask) {
+	struct i40e_rx_queue *rxq = rx_queue;
+	volatile union i40e_rx_desc *rxdp;
+	uint16_t desc;
+
+	desc = rxq->rx_tail;
+	rxdp = &rxq->rx_ring[desc];
+	/* watch for changes in status bit */
+	*tail_desc_addr = &rxdp->wb.qword1.status_error_len;
+
+	/*
+	 * we expect the DD bit to be set to 1 if this descriptor was already
+	 * written to.
Quoted 8 lines

drivers/net/i40e/i40e_rxtx.c line 94

Quoted 6 lines
drivers/net/i40e/i40e_rxtx.c +5 -0
+	 */
+	*expected = rte_cpu_to_le_64(1 <<
 I40E_RX_DESC_STATUS_DD_SHIFT);
+	*mask = rte_cpu_to_le_64(1 << I40E_RX_DESC_STATUS_DD_SHIFT);
+
+	return 0;

Suppose that it will always success to get wake addr in i40e, right?

Quoted 3 lines

Yes. We've already checked all the parameters (queue etc.) in ethdev, so once we're here, that means there's no way this could fail as far as i can tell.

Ok.

Quoted 27 lines
Quoted 18 lines
Quoted 18 lines
drivers/net/i40e/i40e_rxtx.c +2 -0
+}
+
  static inline void
  i40e_rxd_to_vlan_tci(struct rte_mbuf *mb, volatile union

i40e_rx_desc
*rxdp) { diff --git a/drivers/net/i40e/i40e_rxtx.h b/drivers/net/i40e/i40e_rxtx.h index 57d7b4160b..f23a2073e3 100644

drivers/net/i40e/i40e_rxtx.h +2 -0
@@ -248,6 +248,8 @@ uint16_t i40e_recv_scattered_pkts_vec_avx2(void
 *rx_queue,
  	struct rte_mbuf **rx_pkts, uint16_t nb_pkts);  uint16_t
 i40e_xmit_pkts_vec_avx2(void *tx_queue, struct rte_mbuf **tx_pkts,
  	uint16_t nb_pkts);
+int i40e_get_wake_addr(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *value);
 
Quoted 4 lines
Quoted 4 lines
drivers/net/i40e/i40e_rxtx.h +0 -0
  /* For each value it means, datasheet of hardware can tell more details
   *

--
2.17.1

--
Thanks,
Anatoly

#291 lore raw

PATCH v5 8/10 net/ice: implement power management API

In reply to Anatoly Burakov

From: Liang Ma <[email protected]>

Implement support for the power management API by implementing a get_wake_addr function that will return an address of an RX ring's status bit.

---
 drivers/net/ice/ice_ethdev.c |  1 +
 drivers/net/ice/ice_rxtx.c   | 23 +++++++++++++++++++++++
 drivers/net/ice/ice_rxtx.h   |  2 ++
 3 files changed, 26 insertions(+)
drivers/net/ice/ice_ethdev.c +1 -0
index d8ce09d28f..260de5dfd7 100644
@@ -216,6 +216,7 @@ static const struct eth_dev_ops ice_eth_dev_ops = {
 	.udp_tunnel_port_add          = ice_dev_udp_tunnel_port_add,
 	.udp_tunnel_port_del          = ice_dev_udp_tunnel_port_del,
 	.tx_done_cleanup              = ice_tx_done_cleanup,
+	.get_wake_addr	              = ice_get_wake_addr,
 };
 
 /* store statistics names and its offset in stats structure */
drivers/net/ice/ice_rxtx.c +23 -0
index 93a0ac6918..9e55eca942 100644
@@ -25,6 +25,29 @@ uint64_t rte_net_ice_dynflag_proto_xtr_ipv6_flow_mask;
 uint64_t rte_net_ice_dynflag_proto_xtr_tcp_mask;
 uint64_t rte_net_ice_dynflag_proto_xtr_ip_offset_mask;
 
+int ice_get_wake_addr(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask)
+{
+	volatile union ice_rx_flex_desc *rxdp;
+	struct ice_rx_queue *rxq = rx_queue;
+	uint16_t desc;
+
+	desc = rxq->rx_tail;
+	rxdp = &rxq->rx_ring[desc];
+	/* watch for changes in status bit */
+	*tail_desc_addr = &rxdp->wb.status_error0;
+
+	/*
+	 * we expect the DD bit to be set to 1 if this descriptor was already
+	 * written to.
+	 */
+	*expected = rte_cpu_to_le_16(1 << ICE_RX_FLEX_DESC_STATUS0_DD_S);
+	*mask = rte_cpu_to_le_16(1 << ICE_RX_FLEX_DESC_STATUS0_DD_S);
+
+	return 0;
+}
+
+
 static inline uint8_t
 ice_proto_xtr_type_to_rxdid(uint8_t xtr_type)
 {
drivers/net/ice/ice_rxtx.h +2 -0
index 1c23c7541e..c729e474c9 100644
@@ -250,6 +250,8 @@ uint16_t ice_xmit_pkts_vec_avx2(void *tx_queue, struct rte_mbuf **tx_pkts,
 				uint16_t nb_pkts);
 int ice_fdir_programming(struct ice_pf *pf, struct ice_fltr_desc *fdir_desc);
 int ice_tx_done_cleanup(void *txq, uint32_t free_cnt);
+int ice_get_wake_addr(void *rx_queue, volatile void **tail_desc_addr,
+		      uint64_t *expected, uint64_t *mask);
 
 #define FDIR_PARSING_ENABLE_PER_QUEUE(ad, on) do { \
 	int i; \
Signature · 1 line
2.17.1
#292 lore raw

PATCH v5 9/10 examples/l3fwd-power: enable PMD power mgmt

In reply to Anatoly Burakov

From: Liang Ma <[email protected]>

Add PMD power management feature support to l3fwd-power sample app.

---

Notes:
v5:
- Moved doc update here
- Some minor formatting fixes

 .../sample_app_ug/l3_forward_power_man.rst    | 13 ++++++
 examples/l3fwd-power/main.c                   | 41 ++++++++++++++++++-
 2 files changed, 53 insertions(+), 1 deletion(-)
doc/guides/sample_app_ug/l3_forward_power_man.rst +13 -0
index 0cc6f2e62e..8722fbaeaa 100644
@@ -109,6 +109,8 @@ where,
 
 *   --telemetry:  Telemetry mode.
 
+*   --pmd-mgmt: PMD power management mode.
+
 See :doc:`l3_forward` for details.
 The L3fwd-power example reuses the L3fwd command line options.
 
@@ -459,3 +461,14 @@ reference cycles and accordingly busy rate is set  to either 0% or
 
 The new stats ``empty_poll`` , ``full_poll`` and ``busy_percent`` can be viewed by running the script
 ``/usertools/dpdk-telemetry-client.py`` and selecting the menu option ``Send for global Metrics``.
+
+PMD power management Mode
+-------------------------
+
+The PMD power management  mode support for ``l3fwd-power`` is a standalone mode, in this mode
+``l3fwd-power`` does simple l3fwding along with enable the power saving scheme on specific
+port/queue/lcore. Main purpose for this mode is to demonstrate how to use the PMD power management API.
+
+.. code-block:: console
+
+        ./examples/l3fwd-power/build/l3fwd-power --pmd-mgmt -l 1-3 -- -p 0x0f --config="(0,0,2),(0,1,3)"
examples/l3fwd-power/main.c +40 -1

95 lines not on this page · raw message

Signature · 1 line
2.17.1
#293 lore raw

PATCH v5 10/10 doc: update programmer's guide for power library

In reply to Anatoly Burakov

From: Liang Ma <[email protected]>

Update programmer's guide to document PMD power management usage.

---

Notes:
v5:
- Moved l3fwd-power update to the l3fwd-power-related commit
- Some rewordings and clarifications

 doc/guides/prog_guide/power_man.rst | 42 +++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)
doc/guides/prog_guide/power_man.rst +42 -0
index 0a3755a901..38c64d31e4 100644
@@ -192,6 +192,45 @@ User Cases
 ----------
 The mechanism can applied to any device which is based on polling. e.g. NIC, FPGA.
 
+PMD Power Management API
+------------------------
+
+Abstract
+~~~~~~~~
+Existing power management mechanisms require developers to change application
+design or change code to make use of it. The PMD power management API provides a
+convenient alternative by utilizing Ethernet PMD RX callbacks, and triggering
+power saving whenever empty poll count reaches a certain number.
+
+  * UMWAIT/UMONITOR
+
+   This power saving scheme will put the CPU into optimized power state and use
+   the UMWAIT/UMONITOR instructions to monitor the Ethernet PMD RX descriptor
+   address, and wake the CPU up whenever there's new traffic.
+
+  * Pause
+
+   This power saving scheme will use the `rte_pause` function to avoid busy
+   polling.
+
+  * Frequency scaling
+
+   This power saving scheme will use existing power library functionality to
+   scale the core frequency up/down depending on traffic volume.
+
+
+.. note::
+
+   Currently, this power management API is limited to mandatory mapping of 1
+   queue to 1 core (multiple queues are supported, but they must be polled from
+   different cores).
+
+API Overview for PMD Power Management
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* **Queue Enable**: Enable specific power scheme for certain queue/port/core
+
+* **Queue Disable**: Disable power scheme for certain queue/port/core
+
 References
 ----------
 
@@ -200,3 +239,6 @@ References
 
 *   The :doc:`../sample_app_ug/vm_power_management`
     chapter in the :doc:`../sample_app_ug/index` section.
+
+*   The :doc:`../sample_app_ug/rxtx_callbacks`
+    chapter in the :doc:`../sample_app_ug/index` section.
Signature · 1 line
2.17.1
#294 lore raw

Re: [dpdk-dev] [PATCH v5 01/10] eal: add new x86 cpuid support for WAITPKG

In reply to Anatoly Burakov
Quoted 9 lines · Anatoly Burakov

From: Liang Ma <[email protected]>

Add new x86 cpuid support for WAITPKG.
This flag indicate processor support umwait/umonitor/tpause instruction.

The work on this patchset is clearly going to take a few more days, but this particular patch is high priority as there are other dependencies on this patch for DLB drivers. Would it be possible to accept this particular patch now...

Quoted 10 lines
---
  lib/librte_eal/x86/include/rte_cpuflags.h | 2 ++
  lib/librte_eal/x86/rte_cpuflags.c         | 2 ++
  2 files changed, 4 insertions(+)
lib/librte_eal/x86/include/rte_cpuflags.h +0 -0
index c1d20364d1..5041a830a7 100644

lib/librte_eal/x86/include/rte_cpuflags.h enum rte_cpu_flag_t { · line 136

Quoted 5 lines
lib/librte_eal/x86/include/rte_cpuflags.h +2 -0
@@ -132,6 +132,8 @@ enum rte_cpu_flag_t {
  	RTE_CPUFLAG_MOVDIR64B,              /**< Direct Store Instructions 64B */
  	RTE_CPUFLAG_AVX512VP2INTERSECT,     /**< AVX512 Two Register Intersection */
 
+	/**< UMWAIT/TPAUSE Instructions */
+	RTE_CPUFLAG_WAITPKG,                /**< UMINITOR/UMWAIT/TPAUSE */

...with typo fix (UMONITOR rather than UMINITOR)?

Signature · 2 lines
Thanks,
Anatoly
#295 lore raw

PATCH v6 1/10 eal: add new x86 cpuid support for WAITPKG

In reply to Anatoly Burakov

From: Liang Ma <[email protected]>

Add a new CPUID flag indicating processor support for UMONITOR/UMWAIT and TPAUSE instructions instruction.

---

Notes:
v6:
- Fix typos
- Better commit message

 lib/librte_eal/x86/include/rte_cpuflags.h | 1 +
 lib/librte_eal/x86/rte_cpuflags.c         | 2 ++
 2 files changed, 3 insertions(+)
lib/librte_eal/x86/include/rte_cpuflags.h +1 -0
index c1d20364d1..848ba9cbfb 100644
@@ -132,6 +132,7 @@ enum rte_cpu_flag_t {
 	RTE_CPUFLAG_MOVDIR64B,              /**< Direct Store Instructions 64B */
 	RTE_CPUFLAG_AVX512VP2INTERSECT,     /**< AVX512 Two Register Intersection */
 
+	RTE_CPUFLAG_WAITPKG,                /**< UMONITOR/UMWAIT/TPAUSE */
 	/* The last item */
 	RTE_CPUFLAG_NUMFLAGS,               /**< This should always be the last! */
 };
lib/librte_eal/x86/rte_cpuflags.c +2 -0
index 30439e7951..0325c4b93b 100644
@@ -110,6 +110,8 @@ const struct feature_entry rte_cpu_feature_table[] = {
 	FEAT_DEF(AVX512F, 0x00000007, 0, RTE_REG_EBX, 16)
 	FEAT_DEF(RDSEED, 0x00000007, 0, RTE_REG_EBX, 18)
 
+	FEAT_DEF(WAITPKG, 0x00000007, 0, RTE_REG_ECX, 5)
+
 	FEAT_DEF(LAHF_SAHF, 0x80000001, 0, RTE_REG_ECX,  0)
 	FEAT_DEF(LZCNT, 0x80000001, 0, RTE_REG_ECX,  4)
 
Signature · 1 line
2.17.1
#296 lore raw

PATCH v6 2/10 eal: add power management intrinsics

From: Liang Ma <[email protected]>

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

For more details, please refer to Intel(R) 64 and IA-32 Architectures Software Developer's Manual, Volume 2.

---

Notes:
v6:
- Add spinlock-enabled version to allow pthread-wait-like constructs with umwait
- Clarify comments
- Added experimental tags to intrinsics
- Added endianness support
v5:
- Removed return values
- Simplified intrinsics and hardcoded C0.2 state
- Added other arch stubs

 lib/librte_eal/arm/include/meson.build        |   1 +
 .../arm/include/rte_power_intrinsics.h        |  58 ++++++++
 .../include/generic/rte_power_intrinsics.h    | 111 +++++++++++++++
 lib/librte_eal/include/meson.build            |   1 +
 lib/librte_eal/ppc/include/meson.build        |   1 +
 .../ppc/include/rte_power_intrinsics.h        |  58 ++++++++
 lib/librte_eal/x86/include/meson.build        |   1 +
 .../x86/include/rte_power_intrinsics.h        | 132 ++++++++++++++++++
 8 files changed, 363 insertions(+)
 create mode 100644 lib/librte_eal/arm/include/rte_power_intrinsics.h
 create mode 100644 lib/librte_eal/include/generic/rte_power_intrinsics.h
 create mode 100644 lib/librte_eal/ppc/include/rte_power_intrinsics.h
 create mode 100644 lib/librte_eal/x86/include/rte_power_intrinsics.h
lib/librte_eal/arm/include/meson.build +1 -0
index 73b750a18f..c6a9f70d73 100644
@@ -20,6 +20,7 @@ arch_headers = files(
 	'rte_pause_32.h',
 	'rte_pause_64.h',
 	'rte_pause.h',
+	'rte_power_intrinsics.h',
 	'rte_prefetch_32.h',
 	'rte_prefetch_64.h',
 	'rte_prefetch.h',
lib/librte_eal/arm/include/rte_power_intrinsics.h new file +58 -0

58 lines not on this page · raw message

lib/librte_eal/include/generic/rte_power_intrinsics.h new file +111 -0

111 lines not on this page · raw message

lib/librte_eal/include/meson.build +1 -0
index cd09027958..3a12e87e19 100644
@@ -60,6 +60,7 @@ generic_headers = files(
 	'generic/rte_memcpy.h',
 	'generic/rte_pause.h',
 	'generic/rte_prefetch.h',
+	'generic/rte_power_intrinsics.h',
 	'generic/rte_rwlock.h',
 	'generic/rte_spinlock.h',
 	'generic/rte_ticketlock.h',
lib/librte_eal/ppc/include/meson.build +1 -0
index ab4bd28092..0873b2aecb 100644
@@ -10,6 +10,7 @@ arch_headers = files(
 	'rte_io.h',
 	'rte_memcpy.h',
 	'rte_pause.h',
+	'rte_power_intrinsics.h',
 	'rte_prefetch.h',
 	'rte_rwlock.h',
 	'rte_spinlock.h',
lib/librte_eal/ppc/include/rte_power_intrinsics.h new file +58 -0

58 lines not on this page · raw message

lib/librte_eal/x86/include/meson.build +1 -0
index f0e998c2fe..494a8142a2 100644
@@ -13,6 +13,7 @@ arch_headers = files(
 	'rte_io.h',
 	'rte_memcpy.h',
 	'rte_prefetch.h',
+	'rte_power_intrinsics.h',
 	'rte_pause.h',
 	'rte_rtm.h',
 	'rte_rwlock.h',
lib/librte_eal/x86/include/rte_power_intrinsics.h new file +132 -0

132 lines not on this page · raw message

Signature · 1 line
2.17.1
#297 lore raw

Re: [dpdk-dev] [PATCH v6 02/10] eal: add power management intrinsics

Quoted 77 lines

From: Liang Ma <[email protected]>

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

For more details, please refer to Intel(R) 64 and IA-32 Architectures Software Developer's Manual, Volume 2.

---

Notes:
v6:
- Add spinlock-enabled version to allow pthread-wait-like constructs with umwait
- Clarify comments
- Added experimental tags to intrinsics
- Added endianness support
v5:
- Removed return values
- Simplified intrinsics and hardcoded C0.2 state
- Added other arch stubs

 lib/librte_eal/arm/include/meson.build        |   1 +
 .../arm/include/rte_power_intrinsics.h        |  58 ++++++++
 .../include/generic/rte_power_intrinsics.h    | 111 +++++++++++++++
 lib/librte_eal/include/meson.build            |   1 +
 lib/librte_eal/ppc/include/meson.build        |   1 +
 .../ppc/include/rte_power_intrinsics.h        |  58 ++++++++
 lib/librte_eal/x86/include/meson.build        |   1 +
 .../x86/include/rte_power_intrinsics.h        | 132 ++++++++++++++++++
 8 files changed, 363 insertions(+)
 create mode 100644 lib/librte_eal/arm/include/rte_power_intrinsics.h
 create mode 100644 lib/librte_eal/include/generic/rte_power_intrinsics.h
 create mode 100644 lib/librte_eal/ppc/include/rte_power_intrinsics.h
 create mode 100644 lib/librte_eal/x86/include/rte_power_intrinsics.h
lib/librte_eal/arm/include/meson.build +1 -0
index 73b750a18f..c6a9f70d73 100644
@@ -20,6 +20,7 @@ arch_headers = files(
 	'rte_pause_32.h',
 	'rte_pause_64.h',
 	'rte_pause.h',
+	'rte_power_intrinsics.h',
 	'rte_prefetch_32.h',
 	'rte_prefetch_64.h',
 	'rte_prefetch.h',
lib/librte_eal/arm/include/rte_power_intrinsics.h new file +8 -0
new file mode 100644
index 0000000000..b04ba10c76
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _RTE_POWER_INTRINSIC_ARM_H_
+#define _RTE_POWER_INTRINSIC_ARM_H_
+
+#ifdef __cplusplus

lib/librte_eal/arm/include/rte_power_intrinsics.h line 18

Quoted 10 lines
lib/librte_eal/arm/include/rte_power_intrinsics.h new file +10 -0
+extern "C" {
+#endif
+
+#include <rte_common.h>
+
+#include "generic/rte_power_intrinsics.h"
+
+/**
+ * This function is not supported on ARM.
+ */

Here and in other places - please follow dpdk coding convention for function definitions, i.e:
static inline void
rte_power_monitor(...

lib/librte_eal/arm/include/rte_power_intrinsics.h line 28

Quoted 10 lines
lib/librte_eal/arm/include/rte_power_intrinsics.h new file +10 -0
+static inline void rte_power_monitor(const volatile void *p,
+		const uint64_t expected_value, const uint64_t value_mask,
+		const uint64_t tsc_timestamp, const uint8_t data_sz)
+{
+	RTE_SET_USED(p);
+	RTE_SET_USED(expected_value);
+	RTE_SET_USED(value_mask);
+	RTE_SET_USED(tsc_timestamp);
+	RTE_SET_USED(data_sz);
+}

You can probably put NOP implementations of these rte_powe_* functions into generic/rte_power_intrinsics.h.
So, wouldn't need to duplicate them for every non-supported arch. Same as it was done for rte_wait_until_equal_*().

Quoted 62 lines
lib/librte_eal/arm/include/rte_power_intrinsics.h new file +30 -0
+
+/**
+ * This function is not supported on ARM.
+ */
+static inline void rte_power_monitor_sync(const volatile void *p,
+		const uint64_t expected_value, const uint64_t value_mask,
+		const uint64_t tsc_timestamp, const uint8_t data_sz,
+		rte_spinlock_t *lck)
+{
+	RTE_SET_USED(p);
+	RTE_SET_USED(expected_value);
+	RTE_SET_USED(value_mask);
+	RTE_SET_USED(tsc_timestamp);
+	RTE_SET_USED(lck);
+	RTE_SET_USED(data_sz);
+}
+
+/**
+ * This function is not supported on ARM.
+ */
+static inline void rte_power_pause(const uint64_t tsc_timestamp)
+{
+	RTE_SET_USED(tsc_timestamp);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_POWER_INTRINSIC_ARM_H_ */
lib/librte_eal/include/generic/rte_power_intrinsics.h new file +26 -0
new file mode 100644
index 0000000000..f9522f2776
@@ -0,0 +1,111 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _RTE_POWER_INTRINSIC_H_
+#define _RTE_POWER_INTRINSIC_H_
+
+#include <inttypes.h>
+
+#include <rte_compat.h>
+#include <rte_spinlock.h>
+
+/**
+ * @file
+ * Advanced power management operations.
+ *
+ * This file define APIs for advanced power management,
+ * which are architecture-dependent.
+ */
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Monitor specific address for changes. This will cause the CPU to enter an
+ * architecture-defined optimized power state until either the specified

lib/librte_eal/include/generic/rte_power_intrinsics.h line 36

Quoted 10 lines
lib/librte_eal/include/generic/rte_power_intrinsics.h new file +10 -0
+ * memory address is written to, a certain TSC timestamp is reached, or other
+ * reasons cause the CPU to wake up.
+ *
+ * Additionally, an `expected` 64-bit value and 64-bit mask are provided. If
+ * mask is non-zero, the current value pointed to by the `p` pointer will be
+ * checked against the expected value, and if they match, the entering of
+ * optimized power state may be aborted.
+ *
+ * @param p
+ *   Address to monitor for changes. Must be aligned on an 64-byte boundary.

Is 64B alignment really needed?

Quoted 181 lines
lib/librte_eal/include/generic/rte_power_intrinsics.h new file +75 -0
+ * @param expected_value
+ *   Before attempting the monitoring, the `p` address may be read and compared
+ *   against this value. If `value_mask` is zero, this step will be skipped.
+ * @param value_mask
+ *   The 64-bit mask to use to extract current value from `p`.
+ * @param tsc_timestamp
+ *   Maximum TSC timestamp to wait for. Note that the wait behavior is
+ *   architecture-dependent.
+ * @param data_sz
+ *   Data size (in bytes) that will be used to compare expected value with the
+ *   memory address. Can be 1, 2, 4 or 8. Supplying any other value will lead
+ *   to undefined result.
+ */
+__rte_experimental
+static inline void rte_power_monitor(const volatile void *p,
+		const uint64_t expected_value, const uint64_t value_mask,
+		const uint64_t tsc_timestamp, const uint8_t data_sz);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Monitor specific address for changes. This will cause the CPU to enter an
+ * architecture-defined optimized power state until either the specified
+ * memory address is written to, a certain TSC timestamp is reached, or other
+ * reasons cause the CPU to wake up.
+ *
+ * Additionally, an `expected` 64-bit value and 64-bit mask are provided. If
+ * mask is non-zero, the current value pointed to by the `p` pointer will be
+ * checked against the expected value, and if they match, the entering of
+ * optimized power state may be aborted.
+ *
+ * This call will also lock a spinlock on entering sleep, and release it on
+ * waking up the CPU.
+ *
+ * @param p
+ *   Address to monitor for changes. Must be aligned on an 64-byte boundary.
+ * @param expected_value
+ *   Before attempting the monitoring, the `p` address may be read and compared
+ *   against this value. If `value_mask` is zero, this step will be skipped.
+ * @param value_mask
+ *   The 64-bit mask to use to extract current value from `p`.
+ * @param tsc_timestamp
+ *   Maximum TSC timestamp to wait for. Note that the wait behavior is
+ *   architecture-dependent.
+ * @param data_sz
+ *   Data size (in bytes) that will be used to compare expected value with the
+ *   memory address. Can be 1, 2, 4 or 8. Supplying any other value will lead
+ *   to undefined result.
+ * @param lck
+ *   A spinlock that must be locked before entering the function, will be
+ *   unlocked while the CPU is sleeping, and will be locked again once the CPU
+ *   wakes up.
+ */
+__rte_experimental
+static inline void rte_power_monitor_sync(const volatile void *p,
+		const uint64_t expected_value, const uint64_t value_mask,
+		const uint64_t tsc_timestamp, const uint8_t data_sz,
+		rte_spinlock_t *lck);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Enter an architecture-defined optimized power state until a certain TSC
+ * timestamp is reached.
+ *
+ * @param tsc_timestamp
+ *   Maximum TSC timestamp to wait for. Note that the wait behavior is
+ *   architecture-dependent.
+ */
+__rte_experimental
+static inline void rte_power_pause(const uint64_t tsc_timestamp);
+
+#endif /* _RTE_POWER_INTRINSIC_H_ */
lib/librte_eal/include/meson.build +1 -0
index cd09027958..3a12e87e19 100644
@@ -60,6 +60,7 @@ generic_headers = files(
 	'generic/rte_memcpy.h',
 	'generic/rte_pause.h',
 	'generic/rte_prefetch.h',
+	'generic/rte_power_intrinsics.h',
 	'generic/rte_rwlock.h',
 	'generic/rte_spinlock.h',
 	'generic/rte_ticketlock.h',
lib/librte_eal/ppc/include/meson.build +1 -0
index ab4bd28092..0873b2aecb 100644
@@ -10,6 +10,7 @@ arch_headers = files(
 	'rte_io.h',
 	'rte_memcpy.h',
 	'rte_pause.h',
+	'rte_power_intrinsics.h',
 	'rte_prefetch.h',
 	'rte_rwlock.h',
 	'rte_spinlock.h',
lib/librte_eal/ppc/include/rte_power_intrinsics.h new file +58 -0
new file mode 100644
index 0000000000..3bceefdc3f
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _RTE_POWER_INTRINSIC_PPC_H_
+#define _RTE_POWER_INTRINSIC_PPC_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_common.h>
+
+#include "generic/rte_power_intrinsics.h"
+
+/**
+ * This function is not supported on PPC64.
+ */
+static inline void rte_power_monitor(const volatile void *p,
+		const uint64_t expected_value, const uint64_t value_mask,
+		const uint64_t tsc_timestamp, const uint8_t data_sz)
+{
+	RTE_SET_USED(p);
+	RTE_SET_USED(expected_value);
+	RTE_SET_USED(value_mask);
+	RTE_SET_USED(tsc_timestamp);
+	RTE_SET_USED(data_sz);
+}
+
+/**
+ * This function is not supported on PPC64.
+ */
+static inline void rte_power_monitor_sync(const volatile void *p,
+		const uint64_t expected_value, const uint64_t value_mask,
+		const uint64_t tsc_timestamp, const uint8_t data_sz,
+		rte_spinlock_t *lck)
+{
+	RTE_SET_USED(p);
+	RTE_SET_USED(expected_value);
+	RTE_SET_USED(value_mask);
+	RTE_SET_USED(tsc_timestamp);
+	RTE_SET_USED(lck);
+	RTE_SET_USED(data_sz);
+}
+
+/**
+ * This function is not supported on PPC64.
+ */
+static inline void rte_power_pause(const uint64_t tsc_timestamp)
+{
+	RTE_SET_USED(tsc_timestamp);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_POWER_INTRINSIC_PPC_H_ */
lib/librte_eal/x86/include/meson.build +1 -0
index f0e998c2fe..494a8142a2 100644
@@ -13,6 +13,7 @@ arch_headers = files(
 	'rte_io.h',
 	'rte_memcpy.h',
 	'rte_prefetch.h',
+	'rte_power_intrinsics.h',
 	'rte_pause.h',
 	'rte_rtm.h',
 	'rte_rwlock.h',
lib/librte_eal/x86/include/rte_power_intrinsics.h new file +0 -0
new file mode 100644
index 0000000000..9ac8e6eef6

lib/librte_eal/x86/include/rte_power_intrinsics.h line 6

Quoted 6 lines
lib/librte_eal/x86/include/rte_power_intrinsics.h new file +6 -0
@@ -0,0 +1,132 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _RTE_POWER_INTRINSIC_X86_64_H_
+#define _RTE_POWER_INTRINSIC_X86_64_H_

Why '_64_H'?
My understanding was these ops are supported 32-bit mode too.

Quoted 4 lines
lib/librte_eal/x86/include/rte_power_intrinsics.h new file +4 -0
+
+#ifdef __cplusplus
+extern "C" {
+#endif

lib/librte_eal/x86/include/rte_power_intrinsics.h line 20

Quoted 10 lines
lib/librte_eal/x86/include/rte_power_intrinsics.h new file +10 -0
+
+#include <rte_common.h>
+
+#include "generic/rte_power_intrinsics.h"
+
+static inline uint64_t __get_umwait_val(const volatile void *p,
+		const uint8_t sz)
+{
+	switch (sz) {
+	case 1:

Just as a nit:
case sizeof(type_x):

	return *(const volatile type_x *)p;

lib/librte_eal/x86/include/rte_power_intrinsics.h line 29

Quoted 9 lines
lib/librte_eal/x86/include/rte_power_intrinsics.h new file +9 -0
+		return *(const volatile uint8_t *)p;
+	case 2:
+		return *(const volatile uint16_t *)p;
+	case 4:
+		return *(const volatile uint32_t *)p;
+	case 8:
+		return *(const volatile uint64_t *)p;
+	default:
+		/* this is an intrinsic, so we can't have any error handling */

RTE_ASSERT(0); ?

Quoted 105 lines
lib/librte_eal/x86/include/rte_power_intrinsics.h new file +103 -1
+		return 0;
+	}
+}
+
+/**
+ * This function uses UMONITOR/UMWAIT instructions and will enter C0.2 state.
+ * For more information about usage of these instructions, please refer to
+ * Intel(R) 64 and IA-32 Architectures Software Developer's Manual.
+ */
+static inline void rte_power_monitor(const volatile void *p,
+		const uint64_t expected_value, const uint64_t value_mask,
+		const uint64_t tsc_timestamp, const uint8_t data_sz)
+{
+	const uint32_t tsc_l = (uint32_t)tsc_timestamp;
+	const uint32_t tsc_h = (uint32_t)(tsc_timestamp >> 32);
+	/*
+	 * we're using raw byte codes for now as only the newest compiler
+	 * versions support this instruction natively.
+	 */
+
+	/* set address for UMONITOR */
+	asm volatile(".byte 0xf3, 0x0f, 0xae, 0xf7;"
+			:
+			: "D"(p));
+
+	if (value_mask) {
+		const uint64_t cur_value = __get_umwait_val(p, data_sz);
+		const uint64_t masked = cur_value & value_mask;
+
+		/* if the masked value is already matching, abort */
+		if (masked == expected_value)
+			return;
+	}
+	/* execute UMWAIT */
+	asm volatile(".byte 0xf2, 0x0f, 0xae, 0xf7;"
+			: /* ignore rflags */
+			: "D"(0), /* enter C0.2 */
+			  "a"(tsc_l), "d"(tsc_h));
+}
+
+/**
+ * This function uses UMONITOR/UMWAIT instructions and will enter C0.2 state.
+ * For more information about usage of these instructions, please refer to
+ * Intel(R) 64 and IA-32 Architectures Software Developer's Manual.
+ */
+static inline void rte_power_monitor_sync(const volatile void *p,
+		const uint64_t expected_value, const uint64_t value_mask,
+		const uint64_t tsc_timestamp, const uint8_t data_sz,
+		rte_spinlock_t *lck)
+{
+	const uint32_t tsc_l = (uint32_t)tsc_timestamp;
+	const uint32_t tsc_h = (uint32_t)(tsc_timestamp >> 32);
+	/*
+	 * we're using raw byte codes for now as only the newest compiler
+	 * versions support this instruction natively.
+	 */
+
+	/* set address for UMONITOR */
+	asm volatile(".byte 0xf3, 0x0f, 0xae, 0xf7;"
+			:
+			: "D"(p));
+
+	if (value_mask) {
+		const uint64_t cur_value = __get_umwait_val(p, data_sz);
+		const uint64_t masked = cur_value & value_mask;
+
+		/* if the masked value is already matching, abort */
+		if (masked == expected_value)
+			return;
+	}
+	rte_spinlock_unlock(lck);
+
+	/* execute UMWAIT */
+	asm volatile(".byte 0xf2, 0x0f, 0xae, 0xf7;"
+			: /* ignore rflags */
+			: "D"(0), /* enter C0.2 */
+			  "a"(tsc_l), "d"(tsc_h));
+
+	rte_spinlock_lock(lck);
+}
+
+/**
+ * This function uses TPAUSE instruction  and will enter C0.2 state. For more
+ * information about usage of this instruction, please refer to Intel(R) 64 and
+ * IA-32 Architectures Software Developer's Manual.
+ */
+static inline void rte_power_pause(const uint64_t tsc_timestamp)
+{
+	const uint32_t tsc_l = (uint32_t)tsc_timestamp;
+	const uint32_t tsc_h = (uint32_t)(tsc_timestamp >> 32);
+
+	/* execute TPAUSE */
+	asm volatile(".byte 0x66, 0x0f, 0xae, 0xf7;"
+		: /* ignore rflags */
+		: "D"(0), /* enter C0.2 */
+		  "a"(tsc_l), "d"(tsc_h));
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_POWER_INTRINSIC_X86_64_H_ */
--

2.17.1

#298 lore raw

Re: [dpdk-dev] [PATCH v6 02/10] eal: add power management intrinsics

Quoted 84 lines · Konstantin
Quoted 84 lines

From: Liang Ma <[email protected]>

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

For more details, please refer to Intel(R) 64 and IA-32 Architectures Software Developer's Manual, Volume 2.

---

Notes:
v6:
- Add spinlock-enabled version to allow pthread-wait-like constructs with umwait
- Clarify comments
- Added experimental tags to intrinsics
- Added endianness support
v5:
- Removed return values
- Simplified intrinsics and hardcoded C0.2 state
- Added other arch stubs

  lib/librte_eal/arm/include/meson.build        |   1 +
  .../arm/include/rte_power_intrinsics.h        |  58 ++++++++
  .../include/generic/rte_power_intrinsics.h    | 111 +++++++++++++++
  lib/librte_eal/include/meson.build            |   1 +
  lib/librte_eal/ppc/include/meson.build        |   1 +
  .../ppc/include/rte_power_intrinsics.h        |  58 ++++++++
  lib/librte_eal/x86/include/meson.build        |   1 +
  .../x86/include/rte_power_intrinsics.h        | 132 ++++++++++++++++++
  8 files changed, 363 insertions(+)

create mode 100644 lib/librte_eal/arm/include/rte_power_intrinsics.h create mode 100644 lib/librte_eal/include/generic/rte_power_intrinsics.h create mode 100644 lib/librte_eal/ppc/include/rte_power_intrinsics.h create mode 100644 lib/librte_eal/x86/include/rte_power_intrinsics.h

lib/librte_eal/arm/include/meson.build +1 -0
index 73b750a18f..c6a9f70d73 100644
@@ -20,6 +20,7 @@ arch_headers = files(
  'rte_pause_32.h',
  'rte_pause_64.h',
  'rte_pause.h',
+'rte_power_intrinsics.h',
  'rte_prefetch_32.h',
  'rte_prefetch_64.h',
  'rte_prefetch.h',
lib/librte_eal/arm/include/rte_power_intrinsics.h new file +15 -0
new file mode 100644
index 0000000000..b04ba10c76
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _RTE_POWER_INTRINSIC_ARM_H_
+#define _RTE_POWER_INTRINSIC_ARM_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_common.h>
+
+#include "generic/rte_power_intrinsics.h"
+
Quoted 9 lines

lib/librte_eal/arm/include/rte_power_intrinsics.h line 18

Quoted 3 lines
lib/librte_eal/arm/include/rte_power_intrinsics.h new file +3 -0
+/**
+ * This function is not supported on ARM.
+ */

Here and in other places - please follow dpdk coding convention for function definitions, i.e:
static inline void
rte_power_monitor(...

Yep, will do.

Quoted 7 lines
Quoted 7 lines
lib/librte_eal/arm/include/rte_power_intrinsics.h new file +7 -0
+static inline void rte_power_monitor(const volatile void *p,
+const uint64_t expected_value, const uint64_t value_mask,
+const uint64_t tsc_timestamp, const uint8_t data_sz)
+{
+RTE_SET_USED(p);
+RTE_SET_USED(expected_value);
+RTE_SET_USED(value_mask);
Quoted 9 lines

lib/librte_eal/arm/include/rte_power_intrinsics.h line 28

Quoted 3 lines
lib/librte_eal/arm/include/rte_power_intrinsics.h new file +3 -0
+RTE_SET_USED(tsc_timestamp);
+RTE_SET_USED(data_sz);
+}

You can probably put NOP implementations of these rte_powe_* functions into generic/rte_power_intrinsics.h.
So, wouldn't need to duplicate them for every non-supported arch. Same as it was done for rte_wait_until_equal_*().

Will look into it.

Quoted 15 lines
Quoted 15 lines
lib/librte_eal/arm/include/rte_power_intrinsics.h new file +15 -0
+ *
+ * This file define APIs for advanced power management,
+ * which are architecture-dependent.
+ */
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Monitor specific address for changes. This will cause the CPU to enter an
+ * architecture-defined optimized power state until either the specified
+ * memory address is written to, a certain TSC timestamp is reached, or other
+ * reasons cause the CPU to wake up.
+ *
+ * Additionally, an `expected` 64-bit value and 64-bit mask are provided. If
Quoted 8 lines

lib/librte_eal/arm/include/rte_power_intrinsics.h line 49

Quoted 6 lines
lib/librte_eal/arm/include/rte_power_intrinsics.h new file +6 -0
+ * mask is non-zero, the current value pointed to by the `p` pointer will be
+ * checked against the expected value, and if they match, the entering of
+ * optimized power state may be aborted.
+ *
+ * @param p
+ *   Address to monitor for changes. Must be aligned on an 64-byte boundary.

Is 64B alignment really needed?

I'm not 100% sure to be honest, but it's there just in case. I can remove it.

Quoted 12 lines
Quoted 12 lines
lib/librte_eal/arm/include/rte_power_intrinsics.h new file +1 -0
  'rte_prefetch.h',
+'rte_power_intrinsics.h',
  'rte_pause.h',
  'rte_rtm.h',
  'rte_rwlock.h',
lib/librte_eal/x86/include/rte_power_intrinsics.h new file +1 -0
new file mode 100644
index 0000000000..9ac8e6eef6
@@ -0,0 +1,132 @@
+/* SPDX-License-Identifier: BSD-3-Clause
Quoted 8 lines

lib/librte_eal/x86/include/rte_power_intrinsics.h line 6

Quoted 5 lines
lib/librte_eal/x86/include/rte_power_intrinsics.h new file +5 -0
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _RTE_POWER_INTRINSIC_X86_64_H_
+#define _RTE_POWER_INTRINSIC_X86_64_H_

Why '_64_H'?
My understanding was these ops are supported 32-bit mode too.

Yeah, artifact of early implementation. Will fix.

Quoted 11 lines
Quoted 11 lines
lib/librte_eal/x86/include/rte_power_intrinsics.h new file +10 -0
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_common.h>
+
+#include "generic/rte_power_intrinsics.h"
+
+static inline uint64_t __get_umwait_val(const volatile void *p,
Quoted 8 lines

lib/librte_eal/x86/include/rte_power_intrinsics.h line 20

Quoted 4 lines
lib/librte_eal/x86/include/rte_power_intrinsics.h new file +4 -0
+const uint8_t sz)
+{
+switch (sz) {
+case 1:

Just as a nit:
case sizeof(type_x):
return *(const volatile type_x *)p;

Thanks, will fix.

Quoted 12 lines

lib/librte_eal/x86/include/rte_power_intrinsics.h line 29

Quoted 10 lines
lib/librte_eal/x86/include/rte_power_intrinsics.h new file +9 -0
+return *(const volatile uint8_t *)p;
+case 2:
+return *(const volatile uint16_t *)p;
+case 4:
+return *(const volatile uint32_t *)p;
+case 8:
+return *(const volatile uint64_t *)p;
+default:
+/* this is an intrinsic, so we can't have any error handling */

RTE_ASSERT(0); ?

Great idea, will add.

Signature · 2 lines
Thanks,
Anatoly
#299 lore raw

Re: [dpdk-dev] [PATCH v6 02/10] eal: add power management intrinsics

Quoted 17 lines
Quoted 7 lines
Quoted 7 lines
lib/librte_eal/arm/include/rte_power_intrinsics.h new file +7 -0
+static inline void rte_power_monitor(const volatile void *p,
+const uint64_t expected_value, const uint64_t value_mask,
+const uint64_t tsc_timestamp, const uint8_t data_sz)
+{
+RTE_SET_USED(p);
+RTE_SET_USED(expected_value);
+RTE_SET_USED(value_mask);
Quoted 9 lines

lib/librte_eal/arm/include/rte_power_intrinsics.h line 28

Quoted 3 lines
lib/librte_eal/arm/include/rte_power_intrinsics.h new file +3 -0
+RTE_SET_USED(tsc_timestamp);
+RTE_SET_USED(data_sz);
+}

You can probably put NOP implementations of these rte_powe_* functions into generic/rte_power_intrinsics.h.
So, wouldn't need to duplicate them for every non-supported arch. Same as it was done for rte_wait_until_equal_*().

Quoted 2 lines

Will look into it.

To be completely honest, i don't like that approach. The ifdefery in generic headers looks ugly and out of place, i'd rather leave everything in arch specific header files and provide stubs there.

Signature · 2 lines
Thanks,
Anatoly
#300 lore raw

PATCH v6 3/10 eal: add intrinsics support check infrastructure

In reply to Anatoly Burakov

Currently, it is not possible to check support for intrinsics that are platform-specific, cannot be abstracted in a generic way, or do not have support on all architectures. The CPUID flags can be used to some extent, but they are only defined for their platform, while intrinsics will be available to all code as they are in generic headers.

This patch introduces infrastructure to check support for certain platform-specific intrinsics, and adds support for checking support for IA power management-related intrinsics for UMWAIT/UMONITOR and TPAUSE.

---

Notes:
v6:
- Fix the comments

 lib/librte_eal/arm/rte_cpuflags.c             |  6 +++++
 lib/librte_eal/include/generic/rte_cpuflags.h | 26 +++++++++++++++++++
 .../include/generic/rte_power_intrinsics.h    | 12 +++++++++
 lib/librte_eal/ppc/rte_cpuflags.c             |  7 +++++
 lib/librte_eal/rte_eal_version.map            |  1 +
 lib/librte_eal/x86/rte_cpuflags.c             | 12 +++++++++
 6 files changed, 64 insertions(+)
lib/librte_eal/arm/rte_cpuflags.c +6 -0
index 7b257b7873..e3a53bcece 100644
@@ -151,3 +151,9 @@ rte_cpu_get_flag_name(enum rte_cpu_flag_t feature)
 		return NULL;
 	return rte_cpu_feature_table[feature].name;
 }
+
+void
+rte_cpu_get_intrinsics_support(struct rte_cpu_intrinsics *intrinsics)
+{
+	memset(intrinsics, 0, sizeof(*intrinsics));
+}
lib/librte_eal/include/generic/rte_cpuflags.h +26 -0
index 872f0ebe3e..28a5aecde8 100644
@@ -13,6 +13,32 @@
 #include "rte_common.h"
 #include <errno.h>
 
+#include <rte_compat.h>
+
+/**
+ * Structure used to describe platform-specific intrinsics that may or may not
+ * be supported at runtime.
+ */
+struct rte_cpu_intrinsics {
+	uint32_t power_monitor : 1;
+	/**< indicates support for rte_power_monitor function */
+	uint32_t power_pause : 1;
+	/**< indicates support for rte_power_pause function */
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Check CPU support for various intrinsics at runtime.
+ *
+ * @param intrinsics
+ *     Pointer to a structure to be filled.
+ */
+__rte_experimental
+void
+rte_cpu_get_intrinsics_support(struct rte_cpu_intrinsics *intrinsics);
+
 /**
  * Enumeration of all CPU features supported
  */
lib/librte_eal/include/generic/rte_power_intrinsics.h +12 -0
index f9522f2776..1c176e4ef5 100644
@@ -32,6 +32,10 @@
  * checked against the expected value, and if they match, the entering of
  * optimized power state may be aborted.
  *
+ * @warning It is responsibility of the user to check if this function is
+ *   supported at runtime using `rte_cpu_get_features()` API call. Failing to do
+ *   so may result in an illegal CPU instruction error.
+ *
  * @param p
  *   Address to monitor for changes. Must be aligned on an 64-byte boundary.
  * @param expected_value
@@ -69,6 +73,10 @@ static inline void rte_power_monitor(const volatile void *p,
  * This call will also lock a spinlock on entering sleep, and release it on
  * waking up the CPU.
  *
+ * @warning It is responsibility of the user to check if this function is
+ *   supported at runtime using `rte_cpu_get_features()` API call. Failing to do
+ *   so may result in an illegal CPU instruction error.
+ *
  * @param p
  *   Address to monitor for changes. Must be aligned on an 64-byte boundary.
  * @param expected_value
@@ -101,6 +109,10 @@ static inline void rte_power_monitor_sync(const volatile void *p,
  * Enter an architecture-defined optimized power state until a certain TSC
  * timestamp is reached.
  *
+ * @warning It is responsibility of the user to check if this function is
+ *   supported at runtime using `rte_cpu_get_features()` API call. Failing to do
+ *   so may result in an illegal CPU instruction error.
+ *
  * @param tsc_timestamp
  *   Maximum TSC timestamp to wait for. Note that the wait behavior is
  *   architecture-dependent.
lib/librte_eal/ppc/rte_cpuflags.c +7 -0
index 3bb7563ce9..61db5c216d 100644
@@ -8,6 +8,7 @@
 #include <elf.h>
 #include <fcntl.h>
 #include <assert.h>
+#include <string.h>
 #include <unistd.h>
 
 /* Symbolic values for the entries in the auxiliary table */
@@ -108,3 +109,9 @@ rte_cpu_get_flag_name(enum rte_cpu_flag_t feature)
 		return NULL;
 	return rte_cpu_feature_table[feature].name;
 }
+
+void
+rte_cpu_get_intrinsics_support(struct rte_cpu_intrinsics *intrinsics)
+{
+	memset(intrinsics, 0, sizeof(*intrinsics));
+}
lib/librte_eal/rte_eal_version.map +1 -0
index a93dea9fe6..ed944f2bd4 100644
@@ -400,6 +400,7 @@ EXPERIMENTAL {
 	# added in 20.11
 	__rte_eal_trace_generic_size_t;
 	rte_service_lcore_may_be_active;
+	rte_cpu_get_intrinsics_support;
 };
 
 INTERNAL {
lib/librte_eal/x86/rte_cpuflags.c +12 -0
index 0325c4b93b..a96312ff7f 100644
@@ -7,6 +7,7 @@
 #include <stdio.h>
 #include <errno.h>
 #include <stdint.h>
+#include <string.h>
 
 #include "rte_cpuid.h"
 
@@ -179,3 +180,14 @@ rte_cpu_get_flag_name(enum rte_cpu_flag_t feature)
 		return NULL;
 	return rte_cpu_feature_table[feature].name;
 }
+
+void
+rte_cpu_get_intrinsics_support(struct rte_cpu_intrinsics *intrinsics)
+{
+	memset(intrinsics, 0, sizeof(*intrinsics));
+
+	if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_WAITPKG)) {
+		intrinsics->power_monitor = 1;
+		intrinsics->power_pause = 1;
+	}
+}
Signature · 1 line
2.17.1
Acked-by on v6 3/10
#301 lore raw

Re: [dpdk-dev] [PATCH v6 03/10] eal: add intrinsics support check infrastructure

Quoted 9 lines

Currently, it is not possible to check support for intrinsics that are platform-specific, cannot be abstracted in a generic way, or do not have support on all architectures. The CPUID flags can be used to some extent, but they are only defined for their platform, while intrinsics will be available to all code as they are in generic headers.

Quoted 7 lines

This patch introduces infrastructure to check support for certain platform-specific intrinsics, and adds support for checking support for IA power management-related intrinsics for UMWAIT/UMONITOR and TPAUSE.

---

Quoted 2 lines

--
2.17.1

Acked-by on v6 3/10
#302 lore raw

Re: [dpdk-dev] [PATCH v6 03/10] eal: add intrinsics support check infrastructure

In reply to Anatoly Burakov
Quoted 7 lines · Anatoly Burakov

Currently, it is not possible to check support for intrinsics that are platform-specific, cannot be abstracted in a generic way, or do not have support on all architectures. The CPUID flags can be used to some extent, but they are only defined for their platform, while intrinsics will be available to all code as they are in generic headers.

Quoted 6 lines

This patch introduces infrastructure to check support for certain platform-specific intrinsics, and adds support for checking support for IA power management-related intrinsics for UMWAIT/UMONITOR and TPAUSE.

Quoted 165 lines

---

Notes:
v6:
- Fix the comments

 lib/librte_eal/arm/rte_cpuflags.c             |  6 +++++
 lib/librte_eal/include/generic/rte_cpuflags.h | 26 +++++++++++++++++++
 .../include/generic/rte_power_intrinsics.h    | 12 +++++++++
 lib/librte_eal/ppc/rte_cpuflags.c             |  7 +++++
 lib/librte_eal/rte_eal_version.map            |  1 +
 lib/librte_eal/x86/rte_cpuflags.c             | 12 +++++++++
 6 files changed, 64 insertions(+)
lib/librte_eal/arm/rte_cpuflags.c +6 -0
index 7b257b7873..e3a53bcece 100644
@@ -151,3 +151,9 @@ rte_cpu_get_flag_name(enum rte_cpu_flag_t feature)
                return NULL;
        return rte_cpu_feature_table[feature].name;
 }
+
+void
+rte_cpu_get_intrinsics_support(struct rte_cpu_intrinsics *intrinsics)
+{
+       memset(intrinsics, 0, sizeof(*intrinsics));
+}
lib/librte_eal/include/generic/rte_cpuflags.h +26 -0
index 872f0ebe3e..28a5aecde8 100644
@@ -13,6 +13,32 @@
 #include "rte_common.h"
 #include <errno.h>
 
+#include <rte_compat.h>
+
+/**
+ * Structure used to describe platform-specific intrinsics that may or may not
+ * be supported at runtime.
+ */
+struct rte_cpu_intrinsics {
+       uint32_t power_monitor : 1;
+       /**< indicates support for rte_power_monitor function */
+       uint32_t power_pause : 1;
+       /**< indicates support for rte_power_pause function */
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Check CPU support for various intrinsics at runtime.
+ *
+ * @param intrinsics
+ *     Pointer to a structure to be filled.
+ */
+__rte_experimental
+void
+rte_cpu_get_intrinsics_support(struct rte_cpu_intrinsics *intrinsics);
+
 /**
  * Enumeration of all CPU features supported
  */
lib/librte_eal/include/generic/rte_power_intrinsics.h +12 -0
index f9522f2776..1c176e4ef5 100644
@@ -32,6 +32,10 @@
  * checked against the expected value, and if they match, the entering of
  * optimized power state may be aborted.
  *
+ * @warning It is responsibility of the user to check if this function is
+ *   supported at runtime using `rte_cpu_get_features()` API call. Failing to do
+ *   so may result in an illegal CPU instruction error.
+ *
  * @param p
  *   Address to monitor for changes. Must be aligned on an 64-byte boundary.
  * @param expected_value
@@ -69,6 +73,10 @@ static inline void rte_power_monitor(const volatile void *p,
  * This call will also lock a spinlock on entering sleep, and release it on
  * waking up the CPU.
  *
+ * @warning It is responsibility of the user to check if this function is
+ *   supported at runtime using `rte_cpu_get_features()` API call. Failing to do
+ *   so may result in an illegal CPU instruction error.
+ *
  * @param p
  *   Address to monitor for changes. Must be aligned on an 64-byte boundary.
  * @param expected_value
@@ -101,6 +109,10 @@ static inline void rte_power_monitor_sync(const volatile void *p,
  * Enter an architecture-defined optimized power state until a certain TSC
  * timestamp is reached.
  *
+ * @warning It is responsibility of the user to check if this function is
+ *   supported at runtime using `rte_cpu_get_features()` API call. Failing to do
+ *   so may result in an illegal CPU instruction error.
+ *
  * @param tsc_timestamp
  *   Maximum TSC timestamp to wait for. Note that the wait behavior is
  *   architecture-dependent.
lib/librte_eal/ppc/rte_cpuflags.c +7 -0
index 3bb7563ce9..61db5c216d 100644
@@ -8,6 +8,7 @@
 #include <elf.h>
 #include <fcntl.h>
 #include <assert.h>
+#include <string.h>
 #include <unistd.h>
 
 /* Symbolic values for the entries in the auxiliary table */
@@ -108,3 +109,9 @@ rte_cpu_get_flag_name(enum rte_cpu_flag_t feature)
                return NULL;
        return rte_cpu_feature_table[feature].name;
 }
+
+void
+rte_cpu_get_intrinsics_support(struct rte_cpu_intrinsics *intrinsics)
+{
+       memset(intrinsics, 0, sizeof(*intrinsics));
+}
lib/librte_eal/rte_eal_version.map +1 -0
index a93dea9fe6..ed944f2bd4 100644
@@ -400,6 +400,7 @@ EXPERIMENTAL {
        # added in 20.11
        __rte_eal_trace_generic_size_t;
        rte_service_lcore_may_be_active;
+       rte_cpu_get_intrinsics_support;
 };
 
 INTERNAL {
lib/librte_eal/x86/rte_cpuflags.c +12 -1
index 0325c4b93b..a96312ff7f 100644
@@ -7,6 +7,7 @@
 #include <stdio.h>
 #include <errno.h>
 #include <stdint.h>
+#include <string.h>
 
 #include "rte_cpuid.h"
 
@@ -179,3 +180,14 @@ rte_cpu_get_flag_name(enum rte_cpu_flag_t feature)
                return NULL;
        return rte_cpu_feature_table[feature].name;
 }
+
+void
+rte_cpu_get_intrinsics_support(struct rte_cpu_intrinsics *intrinsics)
+{
+       memset(intrinsics, 0, sizeof(*intrinsics));
+
+       if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_WAITPKG)) {
+               intrinsics->power_monitor = 1;
+               intrinsics->power_pause = 1;
+       }
+}
--

2.17.1

#303 lore raw

PATCH v6 4/10 ethdev: add simple power management API

In reply to Anatoly Burakov

From: Liang Ma <[email protected]>

Add a simple API to allow getting address of next RX descriptor from the PMD, as well as release notes information.

---

Notes:
v6:
- Rebase on top of latest main
- Ensure the API checks queue ID (Konstantin)
- Removed accidental inclusion of unrelated release notes
v5:
- Bring function format in line with other functions in the file
- Ensure the API is supported by the driver before calling it (Konstantin)

 doc/guides/rel_notes/release_20_11.rst   |  8 ++++++-
 lib/librte_ethdev/rte_ethdev.c           | 23 +++++++++++++++++++
 lib/librte_ethdev/rte_ethdev.h           | 26 ++++++++++++++++++++++
 lib/librte_ethdev/rte_ethdev_driver.h    | 28 ++++++++++++++++++++++++
 lib/librte_ethdev/rte_ethdev_version.map |  1 +
 5 files changed, 85 insertions(+), 1 deletion(-)
doc/guides/rel_notes/release_20_11.rst +7 -1
index 0925123e9c..ca4f43f7f9 100644
@@ -71,7 +71,13 @@ New Features
 * **Added the FEC API, for a generic FEC query and config.**
 
   Added the FEC API which provides functions for query FEC capabilities and
-  current FEC mode from device. Also, API for configuring FEC mode is also provided.
+  current FEC mode from device. Also, API for configuring FEC mode is also
+  provided.
+
+* **ethdev: add 1 new EXPERIMENTAL API for PMD power management.**
+
+  * ``rte_eth_get_wake_addr()``
+  * add new eth_dev_ops ``get_wake_addr``
 
 * **Updated Broadcom bnxt driver.**
 
lib/librte_ethdev/rte_ethdev.c +23 -0
index 59beb8aec2..5d19c97a3e 100644
@@ -4844,6 +4844,29 @@ rte_eth_tx_burst_mode_get(uint16_t port_id, uint16_t queue_id,
 		       dev->dev_ops->tx_burst_mode_get(dev, queue_id, mode));
 }
 
+int
+rte_eth_get_wake_addr(uint16_t port_id, uint16_t queue_id,
+		volatile void **wake_addr, uint64_t *expected, uint64_t *mask,
+		uint8_t *data_sz)
+{
+	struct rte_eth_dev *dev;
+
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_wake_addr, -ENOTSUP);
+
+	if (queue_id >= dev->data->nb_tx_queues) {
+		RTE_ETHDEV_LOG(ERR, "Invalid TX queue_id=%u\n", queue_id);
+		return -EINVAL;
+	}
+
+	return eth_err(port_id,
+		dev->dev_ops->get_wake_addr(dev->data->rx_queues[queue_id],
+			wake_addr, expected, mask, data_sz));
+}
+
 int
 rte_eth_dev_set_mc_addr_list(uint16_t port_id,
 			     struct rte_ether_addr *mc_addr_set,
lib/librte_ethdev/rte_ethdev.h +26 -0
index 3a31f94367..005faba455 100644
@@ -4119,6 +4119,32 @@ __rte_experimental
 int rte_eth_tx_burst_mode_get(uint16_t port_id, uint16_t queue_id,
 	struct rte_eth_burst_mode *mode);
 
+/**
+ * Retrieve the wake up address for the receive queue.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param queue_id
+ *   The Rx queue on the Ethernet device for which information
+ *   will be retrieved.
+ * @param wake_addr
+ *   The pointer point to the address which is used for monitoring.
+ * @param expected
+ *   The pointer point to value to be expected when descriptor is set.
+ * @param mask
+ *   The pointer point to comparison bitmask for the expected value.
+ *
+ * @return
+ *   - 0: Success.
+ *   -ENOTSUP: Operation not supported.
+ *   -EINVAL: Invalid parameters.
+ *   -ENODEV: Invalid port ID.
+ */
+__rte_experimental
+int rte_eth_get_wake_addr(uint16_t port_id, uint16_t queue_id,
+		volatile void **wake_addr, uint64_t *expected, uint64_t *mask,
+		uint8_t *data_sz);
+
 /**
  * Retrieve device registers and register attributes (number of registers and
  * register size)
lib/librte_ethdev/rte_ethdev_driver.h +28 -0
index 35cc4fb186..76b179de42 100644
@@ -655,6 +655,32 @@ typedef int (*eth_fec_get_t)(struct rte_eth_dev *dev,
  */
 typedef int (*eth_fec_set_t)(struct rte_eth_dev *dev, uint32_t fec_capa);
 
+/**
+ * @internal
+ * Get address of memory location whose contents will change whenever there is
+ * new data to be received on an RX queue.
+ *
+ * @param rxq
+ *   Ethdev queue pointer.
+ * @param tail_desc_addr
+ *   The pointer point to where the address will be stored.
+ * @param expected
+ *   The pointer point to value to be expected when descriptor is set.
+ * @param mask
+ *   The pointer point to comparison bitmask for the expected value.
+ * @param data_sz
+ *   Data size for the expected value (can be 1, 2, 4, or 8 bytes)
+ * @return
+ *   Negative errno value on error, 0 on success.
+ *
+ * @retval 0
+ *   Success
+ * @retval -EINVAL
+ *   Invalid parameters
+ */
+typedef int (*eth_get_wake_addr_t)(void *rxq, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask, uint8_t *data_sz);
+
 /**
  * @internal A structure containing the functions exported by an Ethernet driver.
  */
@@ -801,6 +827,8 @@ struct eth_dev_ops {
 	/**< Get Forward Error Correction(FEC) mode. */
 	eth_fec_set_t fec_set;
 	/**< Set Forward Error Correction(FEC) mode. */
+	eth_get_wake_addr_t get_wake_addr;
+	/**< Get next RX queue ring entry address. */
 };
 
 /**
lib/librte_ethdev/rte_ethdev_version.map +1 -0
index f8a0945812..6c2ea5996d 100644
@@ -232,6 +232,7 @@ EXPERIMENTAL {
 	rte_eth_fec_get_capability;
 	rte_eth_fec_get;
 	rte_eth_fec_set;
+	rte_eth_get_wake_addr;
 };
 
 INTERNAL {
Signature · 1 line
2.17.1
#304 lore raw

Re: [dpdk-dev] [PATCH v6 04/10] ethdev: add simple power management API

Quoted 59 lines

From: Liang Ma <[email protected]>

Add a simple API to allow getting address of next RX descriptor from the PMD, as well as release notes information.

---

Notes:
v6:
- Rebase on top of latest main
- Ensure the API checks queue ID (Konstantin)
- Removed accidental inclusion of unrelated release notes
v5:
- Bring function format in line with other functions in the file
- Ensure the API is supported by the driver before calling it (Konstantin)

 doc/guides/rel_notes/release_20_11.rst   |  8 ++++++-
 lib/librte_ethdev/rte_ethdev.c           | 23 +++++++++++++++++++
 lib/librte_ethdev/rte_ethdev.h           | 26 ++++++++++++++++++++++
 lib/librte_ethdev/rte_ethdev_driver.h    | 28 ++++++++++++++++++++++++
 lib/librte_ethdev/rte_ethdev_version.map |  1 +
 5 files changed, 85 insertions(+), 1 deletion(-)
doc/guides/rel_notes/release_20_11.rst +7 -1
index 0925123e9c..ca4f43f7f9 100644
@@ -71,7 +71,13 @@ New Features
 * **Added the FEC API, for a generic FEC query and config.**
 
   Added the FEC API which provides functions for query FEC capabilities and
-  current FEC mode from device. Also, API for configuring FEC mode is also provided.
+  current FEC mode from device. Also, API for configuring FEC mode is also
+  provided.
+
+* **ethdev: add 1 new EXPERIMENTAL API for PMD power management.**
+
+  * ``rte_eth_get_wake_addr()``
+  * add new eth_dev_ops ``get_wake_addr``
 
 * **Updated Broadcom bnxt driver.**
 
lib/librte_ethdev/rte_ethdev.c +4 -0
index 59beb8aec2..5d19c97a3e 100644
@@ -4844,6 +4844,29 @@ rte_eth_tx_burst_mode_get(uint16_t port_id, uint16_t queue_id,
 		       dev->dev_ops->tx_burst_mode_get(dev, queue_id, mode));
 }
 
+int
+rte_eth_get_wake_addr(uint16_t port_id, uint16_t queue_id,
+		volatile void **wake_addr, uint64_t *expected, uint64_t *mask,
+		uint8_t *data_sz)

lib/librte_ethdev/rte_ethdev.c rte_eth_tx_burst_mode_get(uint16_t port_id, uint16_t queue_id, · line 4860

Quoted 10 lines
lib/librte_ethdev/rte_ethdev.c +10 -0
+{
+	struct rte_eth_dev *dev;
+
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_wake_addr, -ENOTSUP);
+
+	if (queue_id >= dev->data->nb_tx_queues) {

nb_rx_queues

lib/librte_ethdev/rte_ethdev.c rte_eth_tx_burst_mode_get(uint16_t port_id, uint16_t queue_id, · line 4861

Quoted 1 line
lib/librte_ethdev/rte_ethdev.c +1 -0
+		RTE_ETHDEV_LOG(ERR, "Invalid TX queue_id=%u\n", queue_id);

RX not TX

Quoted 108 lines
lib/librte_ethdev/rte_ethdev.c +8 -0
+		return -EINVAL;
+	}
+
+	return eth_err(port_id,
+		dev->dev_ops->get_wake_addr(dev->data->rx_queues[queue_id],
+			wake_addr, expected, mask, data_sz));
+}
+
 int
 rte_eth_dev_set_mc_addr_list(uint16_t port_id,
 			     struct rte_ether_addr *mc_addr_set,
lib/librte_ethdev/rte_ethdev.h +26 -0
index 3a31f94367..005faba455 100644
@@ -4119,6 +4119,32 @@ __rte_experimental
 int rte_eth_tx_burst_mode_get(uint16_t port_id, uint16_t queue_id,
 	struct rte_eth_burst_mode *mode);
 
+/**
+ * Retrieve the wake up address for the receive queue.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param queue_id
+ *   The Rx queue on the Ethernet device for which information
+ *   will be retrieved.
+ * @param wake_addr
+ *   The pointer point to the address which is used for monitoring.
+ * @param expected
+ *   The pointer point to value to be expected when descriptor is set.
+ * @param mask
+ *   The pointer point to comparison bitmask for the expected value.
+ *
+ * @return
+ *   - 0: Success.
+ *   -ENOTSUP: Operation not supported.
+ *   -EINVAL: Invalid parameters.
+ *   -ENODEV: Invalid port ID.
+ */
+__rte_experimental
+int rte_eth_get_wake_addr(uint16_t port_id, uint16_t queue_id,
+		volatile void **wake_addr, uint64_t *expected, uint64_t *mask,
+		uint8_t *data_sz);
+
 /**
  * Retrieve device registers and register attributes (number of registers and
  * register size)
lib/librte_ethdev/rte_ethdev_driver.h +28 -0
index 35cc4fb186..76b179de42 100644
@@ -655,6 +655,32 @@ typedef int (*eth_fec_get_t)(struct rte_eth_dev *dev,
  */
 typedef int (*eth_fec_set_t)(struct rte_eth_dev *dev, uint32_t fec_capa);
 
+/**
+ * @internal
+ * Get address of memory location whose contents will change whenever there is
+ * new data to be received on an RX queue.
+ *
+ * @param rxq
+ *   Ethdev queue pointer.
+ * @param tail_desc_addr
+ *   The pointer point to where the address will be stored.
+ * @param expected
+ *   The pointer point to value to be expected when descriptor is set.
+ * @param mask
+ *   The pointer point to comparison bitmask for the expected value.
+ * @param data_sz
+ *   Data size for the expected value (can be 1, 2, 4, or 8 bytes)
+ * @return
+ *   Negative errno value on error, 0 on success.
+ *
+ * @retval 0
+ *   Success
+ * @retval -EINVAL
+ *   Invalid parameters
+ */
+typedef int (*eth_get_wake_addr_t)(void *rxq, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask, uint8_t *data_sz);
+
 /**
  * @internal A structure containing the functions exported by an Ethernet driver.
  */
@@ -801,6 +827,8 @@ struct eth_dev_ops {
 	/**< Get Forward Error Correction(FEC) mode. */
 	eth_fec_set_t fec_set;
 	/**< Set Forward Error Correction(FEC) mode. */
+	eth_get_wake_addr_t get_wake_addr;
+	/**< Get next RX queue ring entry address. */
 };
 
 /**
lib/librte_ethdev/rte_ethdev_version.map +1 -1
index f8a0945812..6c2ea5996d 100644
@@ -232,6 +232,7 @@ EXPERIMENTAL {
 	rte_eth_fec_get_capability;
 	rte_eth_fec_get;
 	rte_eth_fec_set;
+	rte_eth_get_wake_addr;
 };
 
 INTERNAL {
--

2.17.1

#305 lore raw

Re: [dpdk-dev] [PATCH v6 04/10] ethdev: add simple power management API

In reply to Anatoly Burakov
Quoted 8 lines · Anatoly Burakov

From: Liang Ma <[email protected]>

Add a simple API to allow getting address of next RX descriptor from the PMD, as well as release notes information.

<snip>

Quoted 13 lines
lib/librte_ethdev/rte_ethdev.h +5 -0
index 3a31f94367..005faba455 100644
@@ -4119,6 +4119,32 @@ __rte_experimental
 int rte_eth_tx_burst_mode_get(uint16_t port_id, uint16_t queue_id,
 	struct rte_eth_burst_mode *mode);
 
+/**
+ * Retrieve the wake up address for the receive queue.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.

lib/librte_ethdev/rte_ethdev.h __rte_experimental · line 4136

Quoted 10 lines
lib/librte_ethdev/rte_ethdev.h +10 -0
+ * @param queue_id
+ *   The Rx queue on the Ethernet device for which information
+ *   will be retrieved.
+ * @param wake_addr
+ *   The pointer point to the address which is used for monitoring.
+ * @param expected
+ *   The pointer point to value to be expected when descriptor is set.
+ * @param mask
+ *   The pointer point to comparison bitmask for the expected value.
+ *

need add the comment of data_sz.

Quoted 74 lines
lib/librte_ethdev/rte_ethdev.h +11 -0
+ * @return
+ *   - 0: Success.
+ *   -ENOTSUP: Operation not supported.
+ *   -EINVAL: Invalid parameters.
+ *   -ENODEV: Invalid port ID.
+ */
+__rte_experimental
+int rte_eth_get_wake_addr(uint16_t port_id, uint16_t queue_id,
+		volatile void **wake_addr, uint64_t *expected, uint64_t *mask,
+		uint8_t *data_sz);
+
 /**
  * Retrieve device registers and register attributes (number of registers and
  * register size)
lib/librte_ethdev/rte_ethdev_driver.h +28 -0
index 35cc4fb186..76b179de42 100644
@@ -655,6 +655,32 @@ typedef int (*eth_fec_get_t)(struct rte_eth_dev *dev,
  */
 typedef int (*eth_fec_set_t)(struct rte_eth_dev *dev, uint32_t fec_capa);
 
+/**
+ * @internal
+ * Get address of memory location whose contents will change whenever there is
+ * new data to be received on an RX queue.
+ *
+ * @param rxq
+ *   Ethdev queue pointer.
+ * @param tail_desc_addr
+ *   The pointer point to where the address will be stored.
+ * @param expected
+ *   The pointer point to value to be expected when descriptor is set.
+ * @param mask
+ *   The pointer point to comparison bitmask for the expected value.
+ * @param data_sz
+ *   Data size for the expected value (can be 1, 2, 4, or 8 bytes)
+ * @return
+ *   Negative errno value on error, 0 on success.
+ *
+ * @retval 0
+ *   Success
+ * @retval -EINVAL
+ *   Invalid parameters
+ */
+typedef int (*eth_get_wake_addr_t)(void *rxq, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask, uint8_t *data_sz);
+
 /**
  * @internal A structure containing the functions exported by an Ethernet driver.
  */
@@ -801,6 +827,8 @@ struct eth_dev_ops {
 	/**< Get Forward Error Correction(FEC) mode. */
 	eth_fec_set_t fec_set;
 	/**< Set Forward Error Correction(FEC) mode. */
+	eth_get_wake_addr_t get_wake_addr;
+	/**< Get next RX queue ring entry address. */
 };
 
 /**
lib/librte_ethdev/rte_ethdev_version.map +1 -0
index f8a0945812..6c2ea5996d 100644
@@ -232,6 +232,7 @@ EXPERIMENTAL {
 	rte_eth_fec_get_capability;
 	rte_eth_fec_get;
 	rte_eth_fec_set;
+	rte_eth_get_wake_addr;
 };
 
 INTERNAL {
Signature · 1 line
2.17.1
#306 lore raw

PATCH v6 5/10 power: add PMD power management API and callback

In reply to Anatoly Burakov

From: Liang Ma <[email protected]>

Add a simple on/off switch that will enable saving power when no packets are arriving. It is based on counting the number of empty polls and, when the number reaches a certain threshold, entering an architecture-defined optimized power state that will either wait until a TSC timestamp expires, or when packets arrive.

This API mandates a core-to-single-queue mapping (that is, multiple queued per device are supported, but they have to be polled on different cores).

This design is using PMD RX callbacks.

1. UMWAIT/UMONITOR:

When a certain threshold of empty polls is reached, the core will go into a power optimized sleep while waiting on an address of next RX descriptor to be written to.

2. Pause instruction

Instead of move the core into deeper C state, this method uses the pause instruction to avoid busy polling.

3. Frequency scaling
Reuse existing DPDK power library to scale up/down core frequency depending on traffic volume.

---

Notes:
v6:
- Added wakeup mechanism for UMWAIT
- Removed memory allocation (everything is now allocated statically)
- Fixed various typos and comments
- Check for invalid queue ID
- Moved release notes to this patch

v5:
- Make error checking more robust
- Prevent initializing scaling if ACPI or PSTATE env wasn't set
- Prevent initializing UMWAIT path if PMD doesn't support get_wake_addr
- Add some debug logging
- Replace x86-specific code path to generic path using the intrinsic check

 doc/guides/rel_notes/release_20_11.rst |  11 +
 lib/librte_power/meson.build           |   5 +-
 lib/librte_power/rte_power_pmd_mgmt.c  | 300 +++++++++++++++++++++++++
 lib/librte_power/rte_power_pmd_mgmt.h  |  92 ++++++++
 lib/librte_power/rte_power_version.map |   4 +
 5 files changed, 410 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_power/rte_power_pmd_mgmt.c
 create mode 100644 lib/librte_power/rte_power_pmd_mgmt.h
doc/guides/rel_notes/release_20_11.rst +11 -0
index ca4f43f7f9..06b822aa36 100644
@@ -197,6 +197,17 @@ New Features
   * Added new ``RTE_ACL_CLASSIFY_AVX512X32`` vector implementation,
     which can process up to 32 flows in parallel. Requires AVX512 support.
 
+* **Add PMD power management mechanism**
+
+  3 new Ethernet PMD power management mechanism is added through existing
+  RX callback infrastructure.
+
+  * Add power saving scheme based on UMWAIT instruction (x86 only)
+  * Add power saving scheme based on ``rte_pause()``
+  * Add power saving scheme based on frequency scaling through the power library
+  * Add new EXPERIMENTAL API ``rte_power_pmd_mgmt_queue_enable()``
+  * Add new EXPERIMENTAL API ``rte_power_pmd_mgmt_queue_disable()``
+
 
 Removed Items
 -------------
lib/librte_power/meson.build +3 -2
index 78c031c943..cc3c7a8646 100644
@@ -9,6 +9,7 @@ sources = files('rte_power.c', 'power_acpi_cpufreq.c',
 		'power_kvm_vm.c', 'guest_channel.c',
 		'rte_power_empty_poll.c',
 		'power_pstate_cpufreq.c',
+		'rte_power_pmd_mgmt.c',
 		'power_common.c')
-headers = files('rte_power.h','rte_power_empty_poll.h')
-deps += ['timer']
+headers = files('rte_power.h','rte_power_empty_poll.h','rte_power_pmd_mgmt.h')
+deps += ['timer' ,'ethdev']
lib/librte_power/rte_power_pmd_mgmt.c new file +300 -0

300 lines not on this page · raw message

lib/librte_power/rte_power_pmd_mgmt.h new file +92 -0

92 lines not on this page · raw message

lib/librte_power/rte_power_version.map +4 -0
index 69ca9af616..3f2f6cd6f6 100644
@@ -34,4 +34,8 @@ EXPERIMENTAL {
 	rte_power_guest_channel_receive_msg;
 	rte_power_poll_stat_fetch;
 	rte_power_poll_stat_update;
+	# added in 20.11
+	rte_power_pmd_mgmt_queue_enable;
+	rte_power_pmd_mgmt_queue_disable;
+
 };
Signature · 1 line
2.17.1
Acked-by on v6 5/10
#307 lore raw

Re: [dpdk-dev] [PATCH v6 05/10] power: add PMD power management API and callback

Quoted 25 lines · Anatoly Burakov

From: Liang Ma <[email protected]>

Add a simple on/off switch that will enable saving power when no packets are arriving. It is based on counting the number of empty polls and, when the number reaches a certain threshold, entering an architecture-defined optimized power state that will either wait until a TSC timestamp expires, or when packets arrive.

This API mandates a core-to-single-queue mapping (that is, multiple queued per device are supported, but they have to be polled on different cores).

This design is using PMD RX callbacks.

1. UMWAIT/UMONITOR:

When a certain threshold of empty polls is reached, the core will go into a power optimized sleep while waiting on an address of next RX descriptor to be written to.

2. Pause instruction

Instead of move the core into deeper C state, this method uses the pause instruction to avoid busy polling.

Quoted 7 lines

3. Frequency scaling
Reuse existing DPDK power library to scale up/down core frequency depending on traffic volume.

---

Hi Liang, Anatoly, great work on the patch set.

#308 lore raw

Re: [dpdk-dev] [PATCH v6 05/10] power: add PMD power management API and callback

In reply to Anatoly Burakov
Quoted 174 lines

From: Liang Ma <[email protected]>

Add a simple on/off switch that will enable saving power when no packets are arriving. It is based on counting the number of empty polls and, when the number reaches a certain threshold, entering an architecture-defined optimized power state that will either wait until a TSC timestamp expires, or when packets arrive.

This API mandates a core-to-single-queue mapping (that is, multiple queued per device are supported, but they have to be polled on different cores).

This design is using PMD RX callbacks.

1. UMWAIT/UMONITOR:

When a certain threshold of empty polls is reached, the core will go into a power optimized sleep while waiting on an address of next RX descriptor to be written to.

2. Pause instruction

Instead of move the core into deeper C state, this method uses the pause instruction to avoid busy polling.

3. Frequency scaling
Reuse existing DPDK power library to scale up/down core frequency depending on traffic volume.

---

Notes:
v6:
- Added wakeup mechanism for UMWAIT
- Removed memory allocation (everything is now allocated statically)
- Fixed various typos and comments
- Check for invalid queue ID
- Moved release notes to this patch

v5:
- Make error checking more robust
- Prevent initializing scaling if ACPI or PSTATE env wasn't set
- Prevent initializing UMWAIT path if PMD doesn't support get_wake_addr
- Add some debug logging
- Replace x86-specific code path to generic path using the intrinsic check

 doc/guides/rel_notes/release_20_11.rst |  11 +
 lib/librte_power/meson.build           |   5 +-
 lib/librte_power/rte_power_pmd_mgmt.c  | 300 +++++++++++++++++++++++++
 lib/librte_power/rte_power_pmd_mgmt.h  |  92 ++++++++
 lib/librte_power/rte_power_version.map |   4 +
 5 files changed, 410 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_power/rte_power_pmd_mgmt.c
 create mode 100644 lib/librte_power/rte_power_pmd_mgmt.h
doc/guides/rel_notes/release_20_11.rst +11 -0
index ca4f43f7f9..06b822aa36 100644
@@ -197,6 +197,17 @@ New Features
   * Added new ``RTE_ACL_CLASSIFY_AVX512X32`` vector implementation,
     which can process up to 32 flows in parallel. Requires AVX512 support.
 
+* **Add PMD power management mechanism**
+
+  3 new Ethernet PMD power management mechanism is added through existing
+  RX callback infrastructure.
+
+  * Add power saving scheme based on UMWAIT instruction (x86 only)
+  * Add power saving scheme based on ``rte_pause()``
+  * Add power saving scheme based on frequency scaling through the power library
+  * Add new EXPERIMENTAL API ``rte_power_pmd_mgmt_queue_enable()``
+  * Add new EXPERIMENTAL API ``rte_power_pmd_mgmt_queue_disable()``
+
 
 Removed Items
 -------------
lib/librte_power/meson.build +3 -2
index 78c031c943..cc3c7a8646 100644
@@ -9,6 +9,7 @@ sources = files('rte_power.c', 'power_acpi_cpufreq.c',
 		'power_kvm_vm.c', 'guest_channel.c',
 		'rte_power_empty_poll.c',
 		'power_pstate_cpufreq.c',
+		'rte_power_pmd_mgmt.c',
 		'power_common.c')
-headers = files('rte_power.h','rte_power_empty_poll.h')
-deps += ['timer']
+headers = files('rte_power.h','rte_power_empty_poll.h','rte_power_pmd_mgmt.h')
+deps += ['timer' ,'ethdev']
lib/librte_power/rte_power_pmd_mgmt.c new file +75 -0
new file mode 100644
index 0000000000..2b7d2a1a46
@@ -0,0 +1,300 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2020 Intel Corporation
+ */
+
+#include <rte_lcore.h>
+#include <rte_cycles.h>
+#include <rte_cpuflags.h>
+#include <rte_malloc.h>
+#include <rte_ethdev.h>
+#include <rte_power_intrinsics.h>
+
+#include "rte_power_pmd_mgmt.h"
+
+#define EMPTYPOLL_MAX  512
+
+/**
+ * Possible power management states of an ethdev port.
+ */
+enum pmd_mgmt_state {
+	/** Device power management is disabled. */
+	PMD_MGMT_DISABLED = 0,
+	/** Device power management is enabled. */
+	PMD_MGMT_ENABLED,
+};
+
+struct pmd_queue_cfg {
+	enum pmd_mgmt_state pwr_mgmt_state;
+	/**< State of power management for this queue */
+	enum rte_power_pmd_mgmt_type cb_mode;
+	/**< Callback mode for this queue */
+	const struct rte_eth_rxtx_callback *cur_cb;
+	/**< Callback instance */
+	rte_spinlock_t umwait_lock;
+	/**< Per-queue status lock - used only for UMWAIT mode */
+	volatile void *wait_addr;
+	/**< UMWAIT wakeup address */
+	uint64_t empty_poll_stats;
+	/**< Number of empty polls */
+} __rte_cache_aligned;
+
+static struct pmd_queue_cfg port_cfg[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT];
+
+/* trigger a write to the cache line we're waiting on */
+static void umwait_wakeup(volatile void *addr)
+{
+	uint64_t val;
+
+	val = __atomic_load_n((volatile uint64_t *)addr, __ATOMIC_RELAXED);
+	__atomic_compare_exchange_n((volatile uint64_t *)addr, &val, val, 0,
+			__ATOMIC_RELAXED, __ATOMIC_RELAXED);
+}
+
+static uint16_t
+clb_umwait(uint16_t port_id, uint16_t qidx,
+		struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx,
+		uint16_t max_pkts __rte_unused, void *addr __rte_unused)
+{
+
+	struct pmd_queue_cfg *q_conf;
+
+	q_conf = &port_cfg[port_id][qidx];
+
+	if (unlikely(nb_rx == 0)) {
+		q_conf->empty_poll_stats++;
+		if (unlikely(q_conf->empty_poll_stats > EMPTYPOLL_MAX)) {
+			volatile void *target_addr;
+			uint64_t expected, mask;
+			uint16_t ret;
+			uint8_t data_sz;
+
+			/*
+			 * get address of next descriptor in the RX
+			 * ring for this queue, as well as expected
+			 * value and a mask.
+			 */

lib/librte_power/rte_power_pmd_mgmt.c line 85

Quoted 10 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +10 -0
+			ret = rte_eth_get_wake_addr(port_id, qidx,
+					&target_addr, &expected, &mask,
+					&data_sz);
+			if (ret == 0) {
+				/*
+				 * we need to ensure we can wake up by another
+				 * thread triggering a write, so we need the
+				 * address to always be up to date.
+				 */
+				rte_spinlock_lock(&q_conf->umwait_lock);

I think you need to check state here, and _disable() have to set state with lock grabbed. Otherwise this lock wouldn't protect you from race conditions.
As an example:

CP@T0:

	rte_spinlock_lock(&queue_cfg->umwait_lock);
	if (queue_cfg->wait_addr != NULL) //wait_addr == NULL, fallthrough
	rte_spinlock_unlock(&queue_cfg->umwait_lock);

DP@T1:

	rte_spinlock_lock(&queue_cfg->umwait_lock);
	queue_cfg->wait_addr = target_addr;
	monitor_sync(...);  // DP was put to sleep

CP@T2:

	queue_cfg->cur_cb = NULL;
	queue_cfg->pwr_mgmt_state = PMD_MGMT_DISABLED;
	ret = 0;

rte_power_pmd_mgmt_queue_disable() finished with success, but DP core wasn't wokenup.

To be more specific:

clb_umwait(...) {
	...
	lock(&qcfg->lck);
	if (qcfg->state == ENABLED)  {
		qcfg->wake_addr = addr;
		monitor_sync(addr, ...,&qcfg->lck);
	}
	unlock(&qcfg->lck); 
	...
}
_disable(...) {
	...
	lock(&qcfg->lck);
	qcfg->state = DISABLED;
	if (qcfg->wake_addr != NULL)
		monitor_wakeup(qcfg->wake_addr);
	unlock(&qcfg->lock);
	...
}
Quoted 101 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +101 -0
+				q_conf->wait_addr = target_addr;
+				/* -1ULL is maximum value for TSC */
+				rte_power_monitor_sync(target_addr, expected,
+						mask, -1ULL, data_sz,
+						&q_conf->umwait_lock);
+				/* erase the address */
+				q_conf->wait_addr = NULL;
+				rte_spinlock_unlock(&q_conf->umwait_lock);
+			}
+		}
+	} else
+		q_conf->empty_poll_stats = 0;
+
+	return nb_rx;
+}
+
+static uint16_t
+clb_pause(uint16_t port_id, uint16_t qidx,
+		struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx,
+		uint16_t max_pkts __rte_unused, void *addr __rte_unused)
+{
+	struct pmd_queue_cfg *q_conf;
+
+	q_conf = &port_cfg[port_id][qidx];
+
+	if (unlikely(nb_rx == 0)) {
+		q_conf->empty_poll_stats++;
+		/* sleep for 1 microsecond */
+		if (unlikely(q_conf->empty_poll_stats > EMPTYPOLL_MAX))
+			rte_delay_us(1);
+	} else
+		q_conf->empty_poll_stats = 0;
+
+	return nb_rx;
+}
+
+static uint16_t
+clb_scale_freq(uint16_t port_id, uint16_t qidx,
+		struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx,
+		uint16_t max_pkts __rte_unused, void *_  __rte_unused)
+{
+	struct pmd_queue_cfg *q_conf;
+
+	q_conf = &port_cfg[port_id][qidx];
+
+	if (unlikely(nb_rx == 0)) {
+		q_conf->empty_poll_stats++;
+		if (unlikely(q_conf->empty_poll_stats > EMPTYPOLL_MAX))
+			/* scale down freq */
+			rte_power_freq_min(rte_lcore_id());
+	} else {
+		q_conf->empty_poll_stats = 0;
+		/* scale up freq */
+		rte_power_freq_max(rte_lcore_id());
+	}
+
+	return nb_rx;
+}
+
+int
+rte_power_pmd_mgmt_queue_enable(unsigned int lcore_id,
+		uint16_t port_id, uint16_t queue_id,
+		enum rte_power_pmd_mgmt_type mode)
+{
+	struct rte_eth_dev *dev;
+	struct pmd_queue_cfg *queue_cfg;
+	int ret;
+
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
+	dev = &rte_eth_devices[port_id];
+
+	/* check if queue id is valid */
+	if (queue_id >= dev->data->nb_rx_queues ||
+			queue_id >= RTE_MAX_QUEUES_PER_PORT) {
+		return -EINVAL;
+	}
+
+	queue_cfg = &port_cfg[port_id][queue_id];
+
+	if (queue_cfg->pwr_mgmt_state == PMD_MGMT_ENABLED) {
+		ret = -EINVAL;
+		goto end;
+	}
+
+	switch (mode) {
+	case RTE_POWER_MGMT_TYPE_WAIT:
+	{
+		/* check if rte_power_monitor is supported */
+		uint64_t dummy_expected, dummy_mask;
+		struct rte_cpu_intrinsics i;
+		volatile void *dummy_addr;
+		uint8_t dummy_sz;
+
+		rte_cpu_get_intrinsics_support(&i);
+
+		if (!i.power_monitor) {
+			RTE_LOG(DEBUG, POWER, "Monitoring intrinsics are not supported\n");
+			ret = -ENOTSUP;
+			goto end;
+		}
+

lib/librte_power/rte_power_pmd_mgmt.c line 196

Quoted 10 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +10 -0
+		/* check if the device supports the necessary PMD API */
+		if (rte_eth_get_wake_addr(port_id, queue_id,
+				&dummy_addr, &dummy_expected,
+				&dummy_mask, &dummy_sz) == -ENOTSUP) {
+			RTE_LOG(DEBUG, POWER, "The device does not support rte_eth_rxq_ring_addr_get\n");
+			ret = -ENOTSUP;
+			goto end;
+		}
+		/* initialize UMWAIT spinlock */
+		rte_spinlock_init(&queue_cfg->umwait_lock);

I think don't need to do that.
It supposed to be in valid state (otherwise you are probably in trouble anyway).

lib/librte_power/rte_power_pmd_mgmt.c line 204

Quoted 8 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +8 -0
+
+		/* initialize data before enabling the callback */
+		queue_cfg->empty_poll_stats = 0;
+		queue_cfg->cb_mode = mode;
+		queue_cfg->pwr_mgmt_state = PMD_MGMT_ENABLED;
+
+		queue_cfg->cur_cb = rte_eth_add_rx_callback(port_id, queue_id,
+				clb_umwait, NULL);

Would be a bit cleaner/nicer to move add_rx_callback out of switch() {} As you have to do it always anyway.
Same thought for disable() and remove_rx_callback().

Quoted 209 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +96 -0
+		break;
+	}
+	case RTE_POWER_MGMT_TYPE_SCALE:
+	{
+		enum power_management_env env;
+		/* only PSTATE and ACPI modes are supported */
+		if (!rte_power_check_env_supported(PM_ENV_ACPI_CPUFREQ) &&
+				!rte_power_check_env_supported(
+					PM_ENV_PSTATE_CPUFREQ)) {
+			RTE_LOG(DEBUG, POWER, "Neither ACPI nor PSTATE modes are supported\n");
+			ret = -ENOTSUP;
+			goto end;
+		}
+		/* ensure we could initialize the power library */
+		if (rte_power_init(lcore_id)) {
+			ret = -EINVAL;
+			goto end;
+		}
+		/* ensure we initialized the correct env */
+		env = rte_power_get_env();
+		if (env != PM_ENV_ACPI_CPUFREQ &&
+				env != PM_ENV_PSTATE_CPUFREQ) {
+			RTE_LOG(DEBUG, POWER, "Neither ACPI nor PSTATE modes were initialized\n");
+			ret = -ENOTSUP;
+			goto end;
+		}
+		/* initialize data before enabling the callback */
+		queue_cfg->empty_poll_stats = 0;
+		queue_cfg->cb_mode = mode;
+		queue_cfg->pwr_mgmt_state = PMD_MGMT_ENABLED;
+
+		queue_cfg->cur_cb = rte_eth_add_rx_callback(port_id,
+				queue_id, clb_scale_freq, NULL);
+		break;
+	}
+	case RTE_POWER_MGMT_TYPE_PAUSE:
+		/* initialize data before enabling the callback */
+		queue_cfg->empty_poll_stats = 0;
+		queue_cfg->cb_mode = mode;
+		queue_cfg->pwr_mgmt_state = PMD_MGMT_ENABLED;
+
+		queue_cfg->cur_cb = rte_eth_add_rx_callback(port_id, queue_id,
+				clb_pause, NULL);
+		break;
+	}
+	ret = 0;
+
+end:
+	return ret;
+}
+
+int
+rte_power_pmd_mgmt_queue_disable(unsigned int lcore_id,
+		uint16_t port_id, uint16_t queue_id)
+{
+	struct pmd_queue_cfg *queue_cfg;
+	int ret;
+
+	queue_cfg = &port_cfg[port_id][queue_id];
+
+	if (queue_cfg->pwr_mgmt_state == PMD_MGMT_DISABLED) {
+		ret = -EINVAL;
+		goto end;
+	}
+
+	switch (queue_cfg->cb_mode) {
+	case RTE_POWER_MGMT_TYPE_WAIT:
+		rte_spinlock_lock(&queue_cfg->umwait_lock);
+
+		/* wake up the core from UMWAIT sleep, if any */
+		if (queue_cfg->wait_addr != NULL)
+			umwait_wakeup(queue_cfg->wait_addr);
+
+		rte_spinlock_unlock(&queue_cfg->umwait_lock);
+		/* fall-through */
+	case RTE_POWER_MGMT_TYPE_PAUSE:
+		rte_eth_remove_rx_callback(port_id, queue_id,
+				queue_cfg->cur_cb);
+		break;
+	case RTE_POWER_MGMT_TYPE_SCALE:
+		rte_power_freq_max(lcore_id);
+		rte_eth_remove_rx_callback(port_id, queue_id,
+				queue_cfg->cur_cb);
+		rte_power_exit(lcore_id);
+		break;
+	}
+	/*
+	 * we don't free the RX callback here because it is unsafe to do so
+	 * unless we know for a fact that all data plane threads have stopped.
+	 */
+	queue_cfg->cur_cb = NULL;
+	queue_cfg->pwr_mgmt_state = PMD_MGMT_DISABLED;
+	ret = 0;
+end:
+	return ret;
+}
lib/librte_power/rte_power_pmd_mgmt.h new file +92 -0
new file mode 100644
index 0000000000..a7a3f98268
@@ -0,0 +1,92 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2020 Intel Corporation
+ */
+
+#ifndef _RTE_POWER_PMD_MGMT_H
+#define _RTE_POWER_PMD_MGMT_H
+
+/**
+ * @file
+ * RTE PMD Power Management
+ */
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <rte_common.h>
+#include <rte_byteorder.h>
+#include <rte_log.h>
+#include <rte_power.h>
+#include <rte_atomic.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * PMD Power Management Type
+ */
+enum rte_power_pmd_mgmt_type {
+	/** WAIT callback mode. */
+	RTE_POWER_MGMT_TYPE_WAIT = 1,
+	/** PAUSE callback mode. */
+	RTE_POWER_MGMT_TYPE_PAUSE,
+	/** Freq Scaling callback mode. */
+	RTE_POWER_MGMT_TYPE_SCALE,
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Setup per-queue power management callback.
+ *
+ * @note This function is not thread-safe.
+ *
+ * @param lcore_id
+ *   lcore_id.
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param queue_id
+ *   The queue identifier of the Ethernet device.
+ * @param mode
+ *   The power management callback function type.
+
+ * @return
+ *   0 on success
+ *   <0 on error
+ */
+__rte_experimental
+int
+rte_power_pmd_mgmt_queue_enable(unsigned int lcore_id,
+				uint16_t port_id,
+				uint16_t queue_id,
+				enum rte_power_pmd_mgmt_type mode);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Remove per-queue power management callback.
+ *
+ * @note This function is not thread-safe.
+ *
+ * @param lcore_id
+ *   lcore_id.
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param queue_id
+ *   The queue identifier of the Ethernet device.
+ * @return
+ *   0 on success
+ *   <0 on error
+ */
+__rte_experimental
+int
+rte_power_pmd_mgmt_queue_disable(unsigned int lcore_id,
+				uint16_t port_id,
+				uint16_t queue_id);
+#ifdef __cplusplus
+}
+#endif
+
+#endif
lib/librte_power/rte_power_version.map +4 -1
index 69ca9af616..3f2f6cd6f6 100644
@@ -34,4 +34,8 @@ EXPERIMENTAL {
 	rte_power_guest_channel_receive_msg;
 	rte_power_poll_stat_fetch;
 	rte_power_poll_stat_update;
+	# added in 20.11
+	rte_power_pmd_mgmt_queue_enable;
+	rte_power_pmd_mgmt_queue_disable;
+
 };
--

2.17.1

#309 lore raw

Re: [dpdk-dev] [PATCH v6 05/10] power: add PMD power management API and callback

Quoted 48 lines · Konstantin
Quoted 48 lines

From: Liang Ma <[email protected]>

Add a simple on/off switch that will enable saving power when no packets are arriving. It is based on counting the number of empty polls and, when the number reaches a certain threshold, entering an architecture-defined optimized power state that will either wait until a TSC timestamp expires, or when packets arrive.

This API mandates a core-to-single-queue mapping (that is, multiple queued per device are supported, but they have to be polled on different cores).

This design is using PMD RX callbacks.

1. UMWAIT/UMONITOR:

When a certain threshold of empty polls is reached, the core will go into a power optimized sleep while waiting on an address of next RX descriptor to be written to.

2. Pause instruction

Instead of move the core into deeper C state, this method uses the pause instruction to avoid busy polling.

3. Frequency scaling
Reuse existing DPDK power library to scale up/down core frequency depending on traffic volume.

---

Notes:
v6:
- Added wakeup mechanism for UMWAIT
- Removed memory allocation (everything is now allocated statically)
- Fixed various typos and comments
- Check for invalid queue ID
- Moved release notes to this patch

v5:
- Make error checking more robust
- Prevent initializing scaling if ACPI or PSTATE env wasn't set
- Prevent initializing UMWAIT path if PMD doesn't support get_wake_addr
- Add some debug logging
- Replace x86-specific code path to generic path using the intrinsic check

<snip>

Quoted 36 lines

I think you need to check state here, and _disable() have to set state with lock grabbed. Otherwise this lock wouldn't protect you from race conditions.
As an example:

CP@T0:
rte_spinlock_lock(&queue_cfg->umwait_lock);
if (queue_cfg->wait_addr != NULL) //wait_addr == NULL, fallthrough rte_spinlock_unlock(&queue_cfg->umwait_lock);

DP@T1:
rte_spinlock_lock(&queue_cfg->umwait_lock);
queue_cfg->wait_addr = target_addr;
monitor_sync(...); // DP was put to sleep

CP@T2:
queue_cfg->cur_cb = NULL;
queue_cfg->pwr_mgmt_state = PMD_MGMT_DISABLED;
ret = 0;

rte_power_pmd_mgmt_queue_disable() finished with success, but DP core wasn't wokenup.

To be more specific:
clb_umwait(...) {
...
lock(&qcfg->lck);
if (qcfg->state == ENABLED) {
qcfg->wake_addr = addr;
monitor_sync(addr, ...,&qcfg->lck);
}
unlock(&qcfg->lck);
...
}

Quoted 9 lines

_disable(...) {
...
lock(&qcfg->lck);
qcfg->state = DISABLED;
if (qcfg->wake_addr != NULL)
monitor_wakeup(qcfg->wake_addr);
unlock(&qcfg->lock);
...
}

True, didn't think of that. Will fix.

Quoted 12 lines
Quoted 12 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +12 -0
+
+if (!i.power_monitor) {
+RTE_LOG(DEBUG, POWER, "Monitoring intrinsics are not supported\n");
+ret = -ENOTSUP;
+goto end;
+}
+
+/* check if the device supports the necessary PMD API */
+if (rte_eth_get_wake_addr(port_id, queue_id,
+&dummy_addr, &dummy_expected,
+&dummy_mask, &dummy_sz) == -ENOTSUP) {
+RTE_LOG(DEBUG, POWER, "The device does not support rte_eth_rxq_ring_addr_get\n");
Quoted 8 lines

lib/librte_power/rte_power_pmd_mgmt.c line 196

Quoted 5 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +5 -0
+ret = -ENOTSUP;
+goto end;
+}
+/* initialize UMWAIT spinlock */
+rte_spinlock_init(&queue_cfg->umwait_lock);

I think don't need to do that.
It supposed to be in valid state (otherwise you are probably in trouble anyway).

This is mostly for initialization, for when we first run the callback. I suppose we could do it in an RTE_INIT() function or just leave it be since the spinlocks are part of a statically allocated structure and will default to 0 anyway (although it wouldn't be proper usage of the API as that would be relying on implementation detail).

Quoted 13 lines

lib/librte_power/rte_power_pmd_mgmt.c line 204

Quoted 9 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +8 -0
+
+/* initialize data before enabling the callback */
+queue_cfg->empty_poll_stats = 0;
+queue_cfg->cb_mode = mode;
+queue_cfg->pwr_mgmt_state = PMD_MGMT_ENABLED;
+
+queue_cfg->cur_cb = rte_eth_add_rx_callback(port_id, queue_id,
+clb_umwait, NULL);

Would be a bit cleaner/nicer to move add_rx_callback out of switch() {} As you have to do it always anyway.
Same thought for disable() and remove_rx_callback().

The functions are different for each, so we can't move them out of switch (unless you're suggesting to unify the callback to handle all three modes?).

Signature · 2 lines
Thanks,
Anatoly
#310 lore raw

Re: [dpdk-dev] [PATCH v6 05/10] power: add PMD power management API and callback

Quoted 122 lines · Konstantin
Quoted 48 lines
Quoted 48 lines

From: Liang Ma <[email protected]>

Add a simple on/off switch that will enable saving power when no packets are arriving. It is based on counting the number of empty polls and, when the number reaches a certain threshold, entering an architecture-defined optimized power state that will either wait until a TSC timestamp expires, or when packets arrive.

This API mandates a core-to-single-queue mapping (that is, multiple queued per device are supported, but they have to be polled on different cores).

This design is using PMD RX callbacks.

1. UMWAIT/UMONITOR:

When a certain threshold of empty polls is reached, the core will go into a power optimized sleep while waiting on an address of next RX descriptor to be written to.

2. Pause instruction

Instead of move the core into deeper C state, this method uses the pause instruction to avoid busy polling.

3. Frequency scaling
Reuse existing DPDK power library to scale up/down core frequency depending on traffic volume.

---

Notes:
v6:
- Added wakeup mechanism for UMWAIT
- Removed memory allocation (everything is now allocated statically)
- Fixed various typos and comments
- Check for invalid queue ID
- Moved release notes to this patch

v5:
- Make error checking more robust
- Prevent initializing scaling if ACPI or PSTATE env wasn't set
- Prevent initializing UMWAIT path if PMD doesn't support get_wake_addr
- Add some debug logging
- Replace x86-specific code path to generic path using the intrinsic check

<snip>

Quoted 36 lines

I think you need to check state here, and _disable() have to set state with lock grabbed. Otherwise this lock wouldn't protect you from race conditions.
As an example:

CP@T0:
rte_spinlock_lock(&queue_cfg->umwait_lock);
if (queue_cfg->wait_addr != NULL) //wait_addr == NULL, fallthrough rte_spinlock_unlock(&queue_cfg->umwait_lock);

DP@T1:
rte_spinlock_lock(&queue_cfg->umwait_lock);
queue_cfg->wait_addr = target_addr;
monitor_sync(...); // DP was put to sleep

CP@T2:
queue_cfg->cur_cb = NULL;
queue_cfg->pwr_mgmt_state = PMD_MGMT_DISABLED;
ret = 0;

rte_power_pmd_mgmt_queue_disable() finished with success, but DP core wasn't wokenup.

To be more specific:
clb_umwait(...) {
...
lock(&qcfg->lck);
if (qcfg->state == ENABLED) {
qcfg->wake_addr = addr;
monitor_sync(addr, ...,&qcfg->lck);
}
unlock(&qcfg->lck);
...
}

Quoted 9 lines

_disable(...) {
...
lock(&qcfg->lck);
qcfg->state = DISABLED;
if (qcfg->wake_addr != NULL)
monitor_wakeup(qcfg->wake_addr);
unlock(&qcfg->lock);
...
}

True, didn't think of that. Will fix.

Quoted 12 lines
Quoted 12 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +12 -0
+
+if (!i.power_monitor) {
+RTE_LOG(DEBUG, POWER, "Monitoring intrinsics are not supported\n");
+ret = -ENOTSUP;
+goto end;
+}
+
+/* check if the device supports the necessary PMD API */
+if (rte_eth_get_wake_addr(port_id, queue_id,
+&dummy_addr, &dummy_expected,
+&dummy_mask, &dummy_sz) == -ENOTSUP) {
+RTE_LOG(DEBUG, POWER, "The device does not support rte_eth_rxq_ring_addr_get\n");
Quoted 8 lines

lib/librte_power/rte_power_pmd_mgmt.c line 196

Quoted 5 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +5 -0
+ret = -ENOTSUP;
+goto end;
+}
+/* initialize UMWAIT spinlock */
+rte_spinlock_init(&queue_cfg->umwait_lock);

I think don't need to do that.
It supposed to be in valid state (otherwise you are probably in trouble anyway).

Quoted 4 lines

This is mostly for initialization, for when we first run the callback. I suppose we could do it in an RTE_INIT() function or just leave it be since the spinlocks are part of a statically allocated structure and will default to 0 anyway

Yes static initialization should be sufficient here.

(although it wouldn't be proper usage of the

Quoted 1 line

API as that would be relying on implementation detail).

What I am trying to say - at that moment spinlock value should be zero. If it is not, then your DP callback is still running and holding the lock. I understand that it should be *very* rare situation, but it seems strange to me to silently over-write the locked value from other thread. It shouldn't cause any major trouble, but still...

Quoted 22 lines
Quoted 14 lines

lib/librte_power/rte_power_pmd_mgmt.c line 204

Quoted 10 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +8 -0
+
+/* initialize data before enabling the callback */
+queue_cfg->empty_poll_stats = 0;
+queue_cfg->cb_mode = mode;
+queue_cfg->pwr_mgmt_state = PMD_MGMT_ENABLED;
+
+queue_cfg->cur_cb = rte_eth_add_rx_callback(port_id, queue_id,
+clb_umwait, NULL);

Would be a bit cleaner/nicer to move add_rx_callback out of switch() {} As you have to do it always anyway.
Same thought for disable() and remove_rx_callback().

The functions are different for each, so we can't move them out of switch (unless you're suggesting to unify the callback to handle all three modes?).

--
Thanks,
Anatoly

#311 lore raw

PATCH v6 6/10 net/ixgbe: implement power management API

In reply to Anatoly Burakov

From: Liang Ma <[email protected]>

Implement support for the power management API by implementing a get_wake_addr function that will return an address of an RX ring's status bit.

---
 drivers/net/ixgbe/ixgbe_ethdev.c |  1 +
 drivers/net/ixgbe/ixgbe_rxtx.c   | 25 +++++++++++++++++++++++++
 drivers/net/ixgbe/ixgbe_rxtx.h   |  2 ++
 3 files changed, 28 insertions(+)
drivers/net/ixgbe/ixgbe_ethdev.c +1 -0
index 0b98e210e7..30b3f416d4 100644
@@ -588,6 +588,7 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.udp_tunnel_port_del  = ixgbe_dev_udp_tunnel_port_del,
 	.tm_ops_get           = ixgbe_tm_ops_get,
 	.tx_done_cleanup      = ixgbe_dev_tx_done_cleanup,
+	.get_wake_addr        = ixgbe_get_wake_addr,
 };
 
 /*
drivers/net/ixgbe/ixgbe_rxtx.c +25 -0
index 29d385c062..b1d656d270 100644
@@ -1366,6 +1366,31 @@ const uint32_t
 		RTE_PTYPE_INNER_L3_IPV4_EXT | RTE_PTYPE_INNER_L4_UDP,
 };
 
+int ixgbe_get_wake_addr(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask, uint8_t *data_sz)
+{
+	volatile union ixgbe_adv_rx_desc *rxdp;
+	struct ixgbe_rx_queue *rxq = rx_queue;
+	uint16_t desc;
+
+	desc = rxq->rx_tail;
+	rxdp = &rxq->rx_ring[desc];
+	/* watch for changes in status bit */
+	*tail_desc_addr = &rxdp->wb.upper.status_error;
+
+	/*
+	 * we expect the DD bit to be set to 1 if this descriptor was already
+	 * written to.
+	 */
+	*expected = rte_cpu_to_le_32(IXGBE_RXDADV_STAT_DD);
+	*mask = rte_cpu_to_le_32(IXGBE_RXDADV_STAT_DD);
+
+	/* the registers are 32-bit */
+	*data_sz = 4;
+
+	return 0;
+}
+
 /* @note: fix ixgbe_dev_supported_ptypes_get() if any change here. */
 static inline uint32_t
 ixgbe_rxd_pkt_info_to_pkt_type(uint32_t pkt_info, uint16_t ptype_mask)
drivers/net/ixgbe/ixgbe_rxtx.h +2 -0
index 0b5589ef4d..6b9afec655 100644
@@ -299,5 +299,7 @@ uint64_t ixgbe_get_tx_port_offloads(struct rte_eth_dev *dev);
 uint64_t ixgbe_get_rx_queue_offloads(struct rte_eth_dev *dev);
 uint64_t ixgbe_get_rx_port_offloads(struct rte_eth_dev *dev);
 uint64_t ixgbe_get_tx_queue_offloads(struct rte_eth_dev *dev);
+int ixgbe_get_wake_addr(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask, uint8_t *data_sz);
 
 #endif /* _IXGBE_RXTX_H_ */
Signature · 1 line
2.17.1
Reviewed-by on v6 6/10
#312 lore raw

Re: [dpdk-dev] [PATCH v6 06/10] net/ixgbe: implement power management API

Quoted 17 lines

-----Original Message-----
From: Burakov, Anatoly <[email protected]>
Sent: Wednesday, October 14, 2020 21:30
To: [email protected]
Cc: Ma, Liang J <[email protected]>; Guo, Jia <[email protected]>; Wang, Haiyue <[email protected]>; Hunt, David <[email protected]>; Ananyev, Konstantin <[email protected]>; [email protected]; Richardson, Bruce <[email protected]>; [email protected]; McDaniel, Timothy <[email protected]>; Eads, Gage <[email protected]>; Macnamara, Chris <[email protected]>
Subject: [PATCH v6 06/10] net/ixgbe: implement power management API

From: Liang Ma <[email protected]>

Implement support for the power management API by implementing a get_wake_addr function that will return an address of an RX ring's status bit.

Quoted 8 lines
---
 drivers/net/ixgbe/ixgbe_ethdev.c |  1 +
 drivers/net/ixgbe/ixgbe_rxtx.c   | 25 +++++++++++++++++++++++++
 drivers/net/ixgbe/ixgbe_rxtx.h   |  2 ++
 3 files changed, 28 insertions(+)
Quoted 2 lines

--
2.17.1

#313 lore raw

PATCH v6 7/10 net/i40e: implement power management API

In reply to Anatoly Burakov

From: Liang Ma <[email protected]>

Implement support for the power management API by implementing a get_wake_addr function that will return an address of an RX ring's status bit.

---
 drivers/net/i40e/i40e_ethdev.c |  1 +
 drivers/net/i40e/i40e_rxtx.c   | 26 ++++++++++++++++++++++++++
 drivers/net/i40e/i40e_rxtx.h   |  2 ++
 3 files changed, 29 insertions(+)
drivers/net/i40e/i40e_ethdev.c +1 -0
index 943cfe71dc..cab86f8ec9 100644
@@ -513,6 +513,7 @@ static const struct eth_dev_ops i40e_eth_dev_ops = {
 	.mtu_set                      = i40e_dev_mtu_set,
 	.tm_ops_get                   = i40e_tm_ops_get,
 	.tx_done_cleanup              = i40e_tx_done_cleanup,
+	.get_wake_addr	              = i40e_get_wake_addr,
 };
 
 /* store statistics names and its offset in stats structure */
drivers/net/i40e/i40e_rxtx.c +26 -0
index f2844d3f74..cdb1cd494b 100644
@@ -71,6 +71,32 @@
 #define I40E_TX_OFFLOAD_NOTSUP_MASK \
 		(PKT_TX_OFFLOAD_MASK ^ I40E_TX_OFFLOAD_MASK)
 
+int
+i40e_get_wake_addr(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask, uint8_t *data_sz)
+{
+	struct i40e_rx_queue *rxq = rx_queue;
+	volatile union i40e_rx_desc *rxdp;
+	uint16_t desc;
+
+	desc = rxq->rx_tail;
+	rxdp = &rxq->rx_ring[desc];
+	/* watch for changes in status bit */
+	*tail_desc_addr = &rxdp->wb.qword1.status_error_len;
+
+	/*
+	 * we expect the DD bit to be set to 1 if this descriptor was already
+	 * written to.
+	 */
+	*expected = rte_cpu_to_le_64(1 << I40E_RX_DESC_STATUS_DD_SHIFT);
+	*mask = rte_cpu_to_le_64(1 << I40E_RX_DESC_STATUS_DD_SHIFT);
+
+	/* registers are 64-bit */
+	*data_sz = 8;
+
+	return 0;
+}
+
 static inline void
 i40e_rxd_to_vlan_tci(struct rte_mbuf *mb, volatile union i40e_rx_desc *rxdp)
 {
drivers/net/i40e/i40e_rxtx.h +2 -0
index 57d7b4160b..5826cf1099 100644
@@ -248,6 +248,8 @@ uint16_t i40e_recv_scattered_pkts_vec_avx2(void *rx_queue,
 	struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
 uint16_t i40e_xmit_pkts_vec_avx2(void *tx_queue, struct rte_mbuf **tx_pkts,
 	uint16_t nb_pkts);
+int i40e_get_wake_addr(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *value, uint8_t *data_sz);
 
 /* For each value it means, datasheet of hardware can tell more details
  *
Signature · 1 line
2.17.1
#314 lore raw

PATCH v6 8/10 net/ice: implement power management API

In reply to Anatoly Burakov

From: Liang Ma <[email protected]>

Implement support for the power management API by implementing a get_wake_addr function that will return an address of an RX ring's status bit.

---
 drivers/net/ice/ice_ethdev.c |  1 +
 drivers/net/ice/ice_rxtx.c   | 26 ++++++++++++++++++++++++++
 drivers/net/ice/ice_rxtx.h   |  2 ++
 3 files changed, 29 insertions(+)
drivers/net/ice/ice_ethdev.c +1 -0
index d8ce09d28f..260de5dfd7 100644
@@ -216,6 +216,7 @@ static const struct eth_dev_ops ice_eth_dev_ops = {
 	.udp_tunnel_port_add          = ice_dev_udp_tunnel_port_add,
 	.udp_tunnel_port_del          = ice_dev_udp_tunnel_port_del,
 	.tx_done_cleanup              = ice_tx_done_cleanup,
+	.get_wake_addr	              = ice_get_wake_addr,
 };
 
 /* store statistics names and its offset in stats structure */
drivers/net/ice/ice_rxtx.c +26 -0
index 79e6df11f4..7c0f963d96 100644
@@ -25,6 +25,32 @@ uint64_t rte_net_ice_dynflag_proto_xtr_ipv6_flow_mask;
 uint64_t rte_net_ice_dynflag_proto_xtr_tcp_mask;
 uint64_t rte_net_ice_dynflag_proto_xtr_ip_offset_mask;
 
+int ice_get_wake_addr(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask, uint8_t *data_sz)
+{
+	volatile union ice_rx_flex_desc *rxdp;
+	struct ice_rx_queue *rxq = rx_queue;
+	uint16_t desc;
+
+	desc = rxq->rx_tail;
+	rxdp = &rxq->rx_ring[desc];
+	/* watch for changes in status bit */
+	*tail_desc_addr = &rxdp->wb.status_error0;
+
+	/*
+	 * we expect the DD bit to be set to 1 if this descriptor was already
+	 * written to.
+	 */
+	*expected = rte_cpu_to_le_16(1 << ICE_RX_FLEX_DESC_STATUS0_DD_S);
+	*mask = rte_cpu_to_le_16(1 << ICE_RX_FLEX_DESC_STATUS0_DD_S);
+
+	/* register is 16-bit */
+	*data_sz = 2;
+
+	return 0;
+}
+
+
 static inline uint8_t
 ice_proto_xtr_type_to_rxdid(uint8_t xtr_type)
 {
drivers/net/ice/ice_rxtx.h +2 -0
index 1c23c7541e..7eeb8d467e 100644
@@ -250,6 +250,8 @@ uint16_t ice_xmit_pkts_vec_avx2(void *tx_queue, struct rte_mbuf **tx_pkts,
 				uint16_t nb_pkts);
 int ice_fdir_programming(struct ice_pf *pf, struct ice_fltr_desc *fdir_desc);
 int ice_tx_done_cleanup(void *txq, uint32_t free_cnt);
+int ice_get_wake_addr(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask, uint8_t *data_sz);
 
 #define FDIR_PARSING_ENABLE_PER_QUEUE(ad, on) do { \
 	int i; \
Signature · 1 line
2.17.1
#315 lore raw

PATCH v6 9/10 examples/l3fwd-power: enable PMD power mgmt

In reply to Anatoly Burakov

From: Liang Ma <[email protected]>

Add PMD power management feature support to l3fwd-power sample app.

---

Notes:
v6:
- Fixed typos in documentation

 .../sample_app_ug/l3_forward_power_man.rst    | 13 ++++++
 examples/l3fwd-power/main.c                   | 41 ++++++++++++++++++-
 2 files changed, 53 insertions(+), 1 deletion(-)
doc/guides/sample_app_ug/l3_forward_power_man.rst +13 -0
index 0cc6f2e62e..2767fb91aa 100644
@@ -109,6 +109,8 @@ where,
 
 *   --telemetry:  Telemetry mode.
 
+*   --pmd-mgmt: PMD power management mode.
+
 See :doc:`l3_forward` for details.
 The L3fwd-power example reuses the L3fwd command line options.
 
@@ -459,3 +461,14 @@ reference cycles and accordingly busy rate is set  to either 0% or
 
 The new stats ``empty_poll`` , ``full_poll`` and ``busy_percent`` can be viewed by running the script
 ``/usertools/dpdk-telemetry-client.py`` and selecting the menu option ``Send for global Metrics``.
+
+PMD power management Mode
+-------------------------
+
+The PMD power management  mode support for ``l3fwd-power`` is a standalone mode, in this mode
+``l3fwd-power`` does simple l3fwding along with enable the power saving scheme on specific
+port/queue/lcore. Main purpose for this mode is to demonstrate how to use the PMD power management API.
+
+.. code-block:: console
+
+        ./build/examples/dpdk-l3fwd-power -l 1-3 --  --pmd-mgmt -p 0x0f --config="(0,0,2),(0,1,3)"
examples/l3fwd-power/main.c +40 -1

95 lines not on this page · raw message

Signature · 1 line
2.17.1
Acked-by on v6 9/10
#316 lore raw

Re: [dpdk-dev] [PATCH v6 09/10] examples/l3fwd-power: enable PMD power mgmt

Quoted 8 lines · Anatoly Burakov

From: Liang Ma <[email protected]>

Add PMD power management feature support to l3fwd-power sample app.

---

Quoted 8 lines

Notes:
v6:
- Fixed typos in documentation

  .../sample_app_ug/l3_forward_power_man.rst    | 13 ++++++
  examples/l3fwd-power/main.c                   | 41 ++++++++++++++++++-
  2 files changed, 53 insertions(+), 1 deletion(-)
#317 lore raw

PATCH v6 10/10 doc: update programmer's guide for power library

In reply to Anatoly Burakov

From: Liang Ma <[email protected]>

Update programmer's guide to document PMD power management usage.

---

Notes:
v5:
- Moved l3fwd-power update to the l3fwd-power-related commit
- Some rewordings and clarifications

 doc/guides/prog_guide/power_man.rst | 42 +++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)
doc/guides/prog_guide/power_man.rst +42 -0
index 0a3755a901..38c64d31e4 100644
@@ -192,6 +192,45 @@ User Cases
 ----------
 The mechanism can applied to any device which is based on polling. e.g. NIC, FPGA.
 
+PMD Power Management API
+------------------------
+
+Abstract
+~~~~~~~~
+Existing power management mechanisms require developers to change application
+design or change code to make use of it. The PMD power management API provides a
+convenient alternative by utilizing Ethernet PMD RX callbacks, and triggering
+power saving whenever empty poll count reaches a certain number.
+
+  * UMWAIT/UMONITOR
+
+   This power saving scheme will put the CPU into optimized power state and use
+   the UMWAIT/UMONITOR instructions to monitor the Ethernet PMD RX descriptor
+   address, and wake the CPU up whenever there's new traffic.
+
+  * Pause
+
+   This power saving scheme will use the `rte_pause` function to avoid busy
+   polling.
+
+  * Frequency scaling
+
+   This power saving scheme will use existing power library functionality to
+   scale the core frequency up/down depending on traffic volume.
+
+
+.. note::
+
+   Currently, this power management API is limited to mandatory mapping of 1
+   queue to 1 core (multiple queues are supported, but they must be polled from
+   different cores).
+
+API Overview for PMD Power Management
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* **Queue Enable**: Enable specific power scheme for certain queue/port/core
+
+* **Queue Disable**: Disable power scheme for certain queue/port/core
+
 References
 ----------
 
@@ -200,3 +239,6 @@ References
 
 *   The :doc:`../sample_app_ug/vm_power_management`
     chapter in the :doc:`../sample_app_ug/index` section.
+
+*   The :doc:`../sample_app_ug/rxtx_callbacks`
+    chapter in the :doc:`../sample_app_ug/index` section.
Signature · 1 line
2.17.1
Acked-by on v6 10/10
#318 lore raw

Re: [dpdk-dev] [PATCH v6 10/10] doc: update programmer's guide for power library

Quoted 8 lines · Anatoly Burakov

From: Liang Ma <[email protected]>

Update programmer's guide to document PMD power management usage.

---

Quoted 8 lines

Notes:
v5:
- Moved l3fwd-power update to the l3fwd-power-related commit
- Some rewordings and clarifications

  doc/guides/prog_guide/power_man.rst | 42 +++++++++++++++++++++++++++++
  1 file changed, 42 insertions(+)
#319 lore raw

PATCH v7 1/10 eal: add new x86 cpuid support for WAITPKG

In reply to Anatoly Burakov

From: Liang Ma <[email protected]>

Add a new CPUID flag indicating processor support for UMONITOR/UMWAIT and TPAUSE instructions instruction.

---

Notes:
v6:
- Fix typos
- Better commit message

 lib/librte_eal/x86/include/rte_cpuflags.h | 1 +
 lib/librte_eal/x86/rte_cpuflags.c         | 2 ++
 2 files changed, 3 insertions(+)
lib/librte_eal/x86/include/rte_cpuflags.h +1 -0
index c1d20364d1..848ba9cbfb 100644
@@ -132,6 +132,7 @@ enum rte_cpu_flag_t {
 	RTE_CPUFLAG_MOVDIR64B,              /**< Direct Store Instructions 64B */
 	RTE_CPUFLAG_AVX512VP2INTERSECT,     /**< AVX512 Two Register Intersection */
 
+	RTE_CPUFLAG_WAITPKG,                /**< UMONITOR/UMWAIT/TPAUSE */
 	/* The last item */
 	RTE_CPUFLAG_NUMFLAGS,               /**< This should always be the last! */
 };
lib/librte_eal/x86/rte_cpuflags.c +2 -0
index 30439e7951..0325c4b93b 100644
@@ -110,6 +110,8 @@ const struct feature_entry rte_cpu_feature_table[] = {
 	FEAT_DEF(AVX512F, 0x00000007, 0, RTE_REG_EBX, 16)
 	FEAT_DEF(RDSEED, 0x00000007, 0, RTE_REG_EBX, 18)
 
+	FEAT_DEF(WAITPKG, 0x00000007, 0, RTE_REG_ECX, 5)
+
 	FEAT_DEF(LAHF_SAHF, 0x80000001, 0, RTE_REG_ECX,  0)
 	FEAT_DEF(LZCNT, 0x80000001, 0, RTE_REG_ECX,  4)
 
Signature · 1 line
2.17.1
#320 lore raw

PATCH v7 2/10 eal: add power management intrinsics

From: Liang Ma <[email protected]>

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

For more details, please refer to Intel(R) 64 and IA-32 Architectures Software Developer's Manual, Volume 2.

---

Notes:
v7:
- Fix code style and other nitpicks (Konstantin) v6:
- Add spinlock-enabled version to allow pthread-wait-like constructs with umwait
- Clarify comments
- Added experimental tags to intrinsics
- Added endianness support
v5:
- Removed return values
- Simplified intrinsics and hardcoded C0.2 state
- Added other arch stubs

 lib/librte_eal/arm/include/meson.build        |   1 +
 .../arm/include/rte_power_intrinsics.h        |  60 ++++++++
 .../include/generic/rte_power_intrinsics.h    | 111 ++++++++++++++
 lib/librte_eal/include/meson.build            |   1 +
 lib/librte_eal/ppc/include/meson.build        |   1 +
 .../ppc/include/rte_power_intrinsics.h        |  60 ++++++++
 lib/librte_eal/x86/include/meson.build        |   1 +
 .../x86/include/rte_power_intrinsics.h        | 135 ++++++++++++++++++
 8 files changed, 370 insertions(+)
 create mode 100644 lib/librte_eal/arm/include/rte_power_intrinsics.h
 create mode 100644 lib/librte_eal/include/generic/rte_power_intrinsics.h
 create mode 100644 lib/librte_eal/ppc/include/rte_power_intrinsics.h
 create mode 100644 lib/librte_eal/x86/include/rte_power_intrinsics.h
lib/librte_eal/arm/include/meson.build +1 -0
index 73b750a18f..c6a9f70d73 100644
@@ -20,6 +20,7 @@ arch_headers = files(
 	'rte_pause_32.h',
 	'rte_pause_64.h',
 	'rte_pause.h',
+	'rte_power_intrinsics.h',
 	'rte_prefetch_32.h',
 	'rte_prefetch_64.h',
 	'rte_prefetch.h',
lib/librte_eal/arm/include/rte_power_intrinsics.h new file +60 -0

60 lines not on this page · raw message

lib/librte_eal/include/generic/rte_power_intrinsics.h new file +111 -0

111 lines not on this page · raw message

lib/librte_eal/include/meson.build +1 -0
index cd09027958..3a12e87e19 100644
@@ -60,6 +60,7 @@ generic_headers = files(
 	'generic/rte_memcpy.h',
 	'generic/rte_pause.h',
 	'generic/rte_prefetch.h',
+	'generic/rte_power_intrinsics.h',
 	'generic/rte_rwlock.h',
 	'generic/rte_spinlock.h',
 	'generic/rte_ticketlock.h',
lib/librte_eal/ppc/include/meson.build +1 -0
index ab4bd28092..0873b2aecb 100644
@@ -10,6 +10,7 @@ arch_headers = files(
 	'rte_io.h',
 	'rte_memcpy.h',
 	'rte_pause.h',
+	'rte_power_intrinsics.h',
 	'rte_prefetch.h',
 	'rte_rwlock.h',
 	'rte_spinlock.h',
lib/librte_eal/ppc/include/rte_power_intrinsics.h new file +60 -0

60 lines not on this page · raw message

lib/librte_eal/x86/include/meson.build +1 -0
index f0e998c2fe..494a8142a2 100644
@@ -13,6 +13,7 @@ arch_headers = files(
 	'rte_io.h',
 	'rte_memcpy.h',
 	'rte_prefetch.h',
+	'rte_power_intrinsics.h',
 	'rte_pause.h',
 	'rte_rtm.h',
 	'rte_rwlock.h',
lib/librte_eal/x86/include/rte_power_intrinsics.h new file +135 -0

135 lines not on this page · raw message

Signature · 1 line
2.17.1
Acked-by on v7 2/10
#321 lore raw

Re: [dpdk-dev] [PATCH v7 02/10] eal: add power management intrinsics

Quoted 15 lines · Anatoly Burakov

From: Liang Ma <[email protected]>

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

Quoted 6 lines

For more details, please refer to Intel(R) 64 and IA-32 Architectures Software Developer's Manual, Volume 2.

Quoted 470 lines

---

Notes:
v7:
- Fix code style and other nitpicks (Konstantin) v6:
- Add spinlock-enabled version to allow pthread-wait-like constructs with umwait
- Clarify comments
- Added experimental tags to intrinsics
- Added endianness support
v5:
- Removed return values
- Simplified intrinsics and hardcoded C0.2 state
- Added other arch stubs

 lib/librte_eal/arm/include/meson.build        |   1 +
 .../arm/include/rte_power_intrinsics.h        |  60 ++++++++
 .../include/generic/rte_power_intrinsics.h    | 111 ++++++++++++++
 lib/librte_eal/include/meson.build            |   1 +
 lib/librte_eal/ppc/include/meson.build        |   1 +
 .../ppc/include/rte_power_intrinsics.h        |  60 ++++++++
 lib/librte_eal/x86/include/meson.build        |   1 +
 .../x86/include/rte_power_intrinsics.h        | 135 ++++++++++++++++++
 8 files changed, 370 insertions(+)
 create mode 100644 lib/librte_eal/arm/include/rte_power_intrinsics.h
 create mode 100644 lib/librte_eal/include/generic/rte_power_intrinsics.h
 create mode 100644 lib/librte_eal/ppc/include/rte_power_intrinsics.h
 create mode 100644 lib/librte_eal/x86/include/rte_power_intrinsics.h
lib/librte_eal/arm/include/meson.build +1 -0
index 73b750a18f..c6a9f70d73 100644
@@ -20,6 +20,7 @@ arch_headers = files(
        'rte_pause_32.h',
        'rte_pause_64.h',
        'rte_pause.h',
+       'rte_power_intrinsics.h',
        'rte_prefetch_32.h',
        'rte_prefetch_64.h',
        'rte_prefetch.h',
lib/librte_eal/arm/include/rte_power_intrinsics.h new file +60 -0
new file mode 100644
index 0000000000..a4a1bc1159
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _RTE_POWER_INTRINSIC_ARM_H_
+#define _RTE_POWER_INTRINSIC_ARM_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_common.h>
+
+#include "generic/rte_power_intrinsics.h"
+
+/**
+ * This function is not supported on ARM.
+ */
+static inline void
+rte_power_monitor(const volatile void *p, const uint64_t expected_value,
+               const uint64_t value_mask, const uint64_t tsc_timestamp,
+               const uint8_t data_sz)
+{
+       RTE_SET_USED(p);
+       RTE_SET_USED(expected_value);
+       RTE_SET_USED(value_mask);
+       RTE_SET_USED(tsc_timestamp);
+       RTE_SET_USED(data_sz);
+}
+
+/**
+ * This function is not supported on ARM.
+ */
+static inline void
+rte_power_monitor_sync(const volatile void *p, const uint64_t expected_value,
+               const uint64_t value_mask, const uint64_t tsc_timestamp,
+               const uint8_t data_sz, rte_spinlock_t *lck)
+{
+       RTE_SET_USED(p);
+       RTE_SET_USED(expected_value);
+       RTE_SET_USED(value_mask);
+       RTE_SET_USED(tsc_timestamp);
+       RTE_SET_USED(lck);
+       RTE_SET_USED(data_sz);
+}
+
+/**
+ * This function is not supported on ARM.
+ */
+static inline void
+rte_power_pause(const uint64_t tsc_timestamp)
+{
+       RTE_SET_USED(tsc_timestamp);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_POWER_INTRINSIC_ARM_H_ */
lib/librte_eal/include/generic/rte_power_intrinsics.h new file +111 -0
new file mode 100644
index 0000000000..fb897d9060
@@ -0,0 +1,111 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _RTE_POWER_INTRINSIC_H_
+#define _RTE_POWER_INTRINSIC_H_
+
+#include <inttypes.h>
+
+#include <rte_compat.h>
+#include <rte_spinlock.h>
+
+/**
+ * @file
+ * Advanced power management operations.
+ *
+ * This file define APIs for advanced power management,
+ * which are architecture-dependent.
+ */
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Monitor specific address for changes. This will cause the CPU to enter an
+ * architecture-defined optimized power state until either the specified
+ * memory address is written to, a certain TSC timestamp is reached, or other
+ * reasons cause the CPU to wake up.
+ *
+ * Additionally, an `expected` 64-bit value and 64-bit mask are provided. If
+ * mask is non-zero, the current value pointed to by the `p` pointer will be
+ * checked against the expected value, and if they match, the entering of
+ * optimized power state may be aborted.
+ *
+ * @param p
+ *   Address to monitor for changes.
+ * @param expected_value
+ *   Before attempting the monitoring, the `p` address may be read and compared
+ *   against this value. If `value_mask` is zero, this step will be skipped.
+ * @param value_mask
+ *   The 64-bit mask to use to extract current value from `p`.
+ * @param tsc_timestamp
+ *   Maximum TSC timestamp to wait for. Note that the wait behavior is
+ *   architecture-dependent.
+ * @param data_sz
+ *   Data size (in bytes) that will be used to compare expected value with the
+ *   memory address. Can be 1, 2, 4 or 8. Supplying any other value will lead
+ *   to undefined result.
+ */
+__rte_experimental
+static inline void rte_power_monitor(const volatile void *p,
+               const uint64_t expected_value, const uint64_t value_mask,
+               const uint64_t tsc_timestamp, const uint8_t data_sz);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Monitor specific address for changes. This will cause the CPU to enter an
+ * architecture-defined optimized power state until either the specified
+ * memory address is written to, a certain TSC timestamp is reached, or other
+ * reasons cause the CPU to wake up.
+ *
+ * Additionally, an `expected` 64-bit value and 64-bit mask are provided. If
+ * mask is non-zero, the current value pointed to by the `p` pointer will be
+ * checked against the expected value, and if they match, the entering of
+ * optimized power state may be aborted.
+ *
+ * This call will also lock a spinlock on entering sleep, and release it on
+ * waking up the CPU.
+ *
+ * @param p
+ *   Address to monitor for changes.
+ * @param expected_value
+ *   Before attempting the monitoring, the `p` address may be read and compared
+ *   against this value. If `value_mask` is zero, this step will be skipped.
+ * @param value_mask
+ *   The 64-bit mask to use to extract current value from `p`.
+ * @param tsc_timestamp
+ *   Maximum TSC timestamp to wait for. Note that the wait behavior is
+ *   architecture-dependent.
+ * @param data_sz
+ *   Data size (in bytes) that will be used to compare expected value with the
+ *   memory address. Can be 1, 2, 4 or 8. Supplying any other value will lead
+ *   to undefined result.
+ * @param lck
+ *   A spinlock that must be locked before entering the function, will be
+ *   unlocked while the CPU is sleeping, and will be locked again once the CPU
+ *   wakes up.
+ */
+__rte_experimental
+static inline void rte_power_monitor_sync(const volatile void *p,
+               const uint64_t expected_value, const uint64_t value_mask,
+               const uint64_t tsc_timestamp, const uint8_t data_sz,
+               rte_spinlock_t *lck);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Enter an architecture-defined optimized power state until a certain TSC
+ * timestamp is reached.
+ *
+ * @param tsc_timestamp
+ *   Maximum TSC timestamp to wait for. Note that the wait behavior is
+ *   architecture-dependent.
+ */
+__rte_experimental
+static inline void rte_power_pause(const uint64_t tsc_timestamp);
+
+#endif /* _RTE_POWER_INTRINSIC_H_ */
lib/librte_eal/include/meson.build +1 -0
index cd09027958..3a12e87e19 100644
@@ -60,6 +60,7 @@ generic_headers = files(
        'generic/rte_memcpy.h',
        'generic/rte_pause.h',
        'generic/rte_prefetch.h',
+       'generic/rte_power_intrinsics.h',
        'generic/rte_rwlock.h',
        'generic/rte_spinlock.h',
        'generic/rte_ticketlock.h',
lib/librte_eal/ppc/include/meson.build +1 -0
index ab4bd28092..0873b2aecb 100644
@@ -10,6 +10,7 @@ arch_headers = files(
        'rte_io.h',
        'rte_memcpy.h',
        'rte_pause.h',
+       'rte_power_intrinsics.h',
        'rte_prefetch.h',
        'rte_rwlock.h',
        'rte_spinlock.h',
lib/librte_eal/ppc/include/rte_power_intrinsics.h new file +60 -0
new file mode 100644
index 0000000000..4ed03d521f
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _RTE_POWER_INTRINSIC_PPC_H_
+#define _RTE_POWER_INTRINSIC_PPC_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_common.h>
+
+#include "generic/rte_power_intrinsics.h"
+
+/**
+ * This function is not supported on PPC64.
+ */
+static inline void
+rte_power_monitor(const volatile void *p, const uint64_t expected_value,
+               const uint64_t value_mask, const uint64_t tsc_timestamp,
+               const uint8_t data_sz)
+{
+       RTE_SET_USED(p);
+       RTE_SET_USED(expected_value);
+       RTE_SET_USED(value_mask);
+       RTE_SET_USED(tsc_timestamp);
+       RTE_SET_USED(data_sz);
+}
+
+/**
+ * This function is not supported on PPC64.
+ */
+static inline void
+rte_power_monitor_sync(const volatile void *p, const uint64_t expected_value,
+               const uint64_t value_mask, const uint64_t tsc_timestamp,
+               const uint8_t data_sz, rte_spinlock_t *lck)
+{
+       RTE_SET_USED(p);
+       RTE_SET_USED(expected_value);
+       RTE_SET_USED(value_mask);
+       RTE_SET_USED(tsc_timestamp);
+       RTE_SET_USED(lck);
+       RTE_SET_USED(data_sz);
+}
+
+/**
+ * This function is not supported on PPC64.
+ */
+static inline void
+rte_power_pause(const uint64_t tsc_timestamp)
+{
+       RTE_SET_USED(tsc_timestamp);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_POWER_INTRINSIC_PPC_H_ */
lib/librte_eal/x86/include/meson.build +1 -0
index f0e998c2fe..494a8142a2 100644
@@ -13,6 +13,7 @@ arch_headers = files(
        'rte_io.h',
        'rte_memcpy.h',
        'rte_prefetch.h',
+       'rte_power_intrinsics.h',
        'rte_pause.h',
        'rte_rtm.h',
        'rte_rwlock.h',
lib/librte_eal/x86/include/rte_power_intrinsics.h new file +135 -1
new file mode 100644
index 0000000000..f9b761d796
@@ -0,0 +1,135 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _RTE_POWER_INTRINSIC_X86_H_
+#define _RTE_POWER_INTRINSIC_X86_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_common.h>
+
+#include "generic/rte_power_intrinsics.h"
+
+static inline uint64_t
+__get_umwait_val(const volatile void *p, const uint8_t sz)
+{
+       switch (sz) {
+       case sizeof(uint8_t):
+               return *(const volatile uint8_t *)p;
+       case sizeof(uint16_t):
+               return *(const volatile uint16_t *)p;
+       case sizeof(uint32_t):
+               return *(const volatile uint32_t *)p;
+       case sizeof(uint64_t):
+               return *(const volatile uint64_t *)p;
+       default:
+               /* this is an intrinsic, so we can't have any error handling */
+               RTE_ASSERT(0);
+               return 0;
+       }
+}
+
+/**
+ * This function uses UMONITOR/UMWAIT instructions and will enter C0.2 state.
+ * For more information about usage of these instructions, please refer to
+ * Intel(R) 64 and IA-32 Architectures Software Developer's Manual.
+ */
+static inline void
+rte_power_monitor(const volatile void *p, const uint64_t expected_value,
+               const uint64_t value_mask, const uint64_t tsc_timestamp,
+               const uint8_t data_sz)
+{
+       const uint32_t tsc_l = (uint32_t)tsc_timestamp;
+       const uint32_t tsc_h = (uint32_t)(tsc_timestamp >> 32);
+       /*
+        * we're using raw byte codes for now as only the newest compiler
+        * versions support this instruction natively.
+        */
+
+       /* set address for UMONITOR */
+       asm volatile(".byte 0xf3, 0x0f, 0xae, 0xf7;"
+                       :
+                       : "D"(p));
+
+       if (value_mask) {
+               const uint64_t cur_value = __get_umwait_val(p, data_sz);
+               const uint64_t masked = cur_value & value_mask;
+
+               /* if the masked value is already matching, abort */
+               if (masked == expected_value)
+                       return;
+       }
+       /* execute UMWAIT */
+       asm volatile(".byte 0xf2, 0x0f, 0xae, 0xf7;"
+                       : /* ignore rflags */
+                       : "D"(0), /* enter C0.2 */
+                         "a"(tsc_l), "d"(tsc_h));
+}
+
+/**
+ * This function uses UMONITOR/UMWAIT instructions and will enter C0.2 state.
+ * For more information about usage of these instructions, please refer to
+ * Intel(R) 64 and IA-32 Architectures Software Developer's Manual.
+ */
+static inline void
+rte_power_monitor_sync(const volatile void *p, const uint64_t expected_value,
+               const uint64_t value_mask, const uint64_t tsc_timestamp,
+               const uint8_t data_sz, rte_spinlock_t *lck)
+{
+       const uint32_t tsc_l = (uint32_t)tsc_timestamp;
+       const uint32_t tsc_h = (uint32_t)(tsc_timestamp >> 32);
+       /*
+        * we're using raw byte codes for now as only the newest compiler
+        * versions support this instruction natively.
+        */
+
+       /* set address for UMONITOR */
+       asm volatile(".byte 0xf3, 0x0f, 0xae, 0xf7;"
+                       :
+                       : "D"(p));
+
+       if (value_mask) {
+               const uint64_t cur_value = __get_umwait_val(p, data_sz);
+               const uint64_t masked = cur_value & value_mask;
+
+               /* if the masked value is already matching, abort */
+               if (masked == expected_value)
+                       return;
+       }
+       rte_spinlock_unlock(lck);
+
+       /* execute UMWAIT */
+       asm volatile(".byte 0xf2, 0x0f, 0xae, 0xf7;"
+                       : /* ignore rflags */
+                       : "D"(0), /* enter C0.2 */
+                         "a"(tsc_l), "d"(tsc_h));
+
+       rte_spinlock_lock(lck);
+}
+
+/**
+ * This function uses TPAUSE instruction  and will enter C0.2 state. For more
+ * information about usage of this instruction, please refer to Intel(R) 64 and
+ * IA-32 Architectures Software Developer's Manual.
+ */
+static inline void
+rte_power_pause(const uint64_t tsc_timestamp)
+{
+       const uint32_t tsc_l = (uint32_t)tsc_timestamp;
+       const uint32_t tsc_h = (uint32_t)(tsc_timestamp >> 32);
+
+       /* execute TPAUSE */
+       asm volatile(".byte 0x66, 0x0f, 0xae, 0xf7;"
+               : /* ignore rflags */
+               : "D"(0), /* enter C0.2 */
+                 "a"(tsc_l), "d"(tsc_h));
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_POWER_INTRINSIC_X86_H_ */
--

2.17.1

#322 lore raw

Re: [dpdk-dev] [PATCH v7 02/10] eal: add power management intrinsics

In reply to Anatoly Burakov
Quoted 22 lines · Anatoly Burakov

From: Liang Ma <[email protected]>

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

For more details, please refer to Intel(R) 64 and IA-32 Architectures Software Developer's Manual, Volume 2.

---

Quoted 14 lines

Notes:
v7:
- Fix code style and other nitpicks (Konstantin) v6:
- Add spinlock-enabled version to allow pthread-wait-like constructs with umwait
- Clarify comments
- Added experimental tags to intrinsics
- Added endianness support
v5:
- Removed return values
- Simplified intrinsics and hardcoded C0.2 state
- Added other arch stubs

Hi Ruifeng,

This is the patch we have talked in today's release status meeting, can you please check the patch from Arm perspective? Since the instructions are not supported by Arm I expect it should be OK but it would be good to get your ack to proceed.

Thanks,
ferruh

Acked-by
#323 lore raw

Re: [dpdk-dev] [PATCH v7 02/10] eal: add power management intrinsics

Quoted 55 lines

-----Original Message-----
From: Ferruh Yigit <[email protected]>
Sent: Thursday, October 15, 2020 9:17 PM
To: Anatoly Burakov <[email protected]>; [email protected]; Ruifeng Wang <[email protected]>
Cc: Liang Ma <[email protected]>; Jan Viktorin <[email protected]>; David Christensen <[email protected]>; Bruce Richardson <[email protected]>; Konstantin Ananyev <[email protected]>; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]
Subject: Re: [dpdk-dev] [PATCH v7 02/10] eal: add power management intrinsics

Quoted 3 lines · Anatoly Burakov

From: Liang Ma <[email protected]>

Add two new power management intrinsics, and provide an

implementation

Quoted 19 lines

in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

For more details, please refer to Intel(R) 64 and IA-32 Architectures Software Developer's Manual, Volume 2.

---

Quoted 14 lines

Notes:
v7:
- Fix code style and other nitpicks (Konstantin) v6:
- Add spinlock-enabled version to allow pthread-wait-like constructs with umwait
- Clarify comments
- Added experimental tags to intrinsics
- Added endianness support
v5:
- Removed return values
- Simplified intrinsics and hardcoded C0.2 state
- Added other arch stubs

Quoted 7 lines

Hi Ruifeng,

This is the patch we have talked in today's release status meeting, can you please check the patch from Arm perspective?
Since the instructions are not supported by Arm I expect it should be OK but it would be good to get your ack to proceed.

Thanks for pointing me to this.
Generally looks good to me.

Quoted 2 lines

Thanks,
ferruh

Acked-by on v7 2/10
#324 lore raw

Re: [dpdk-dev] [PATCH v7 02/10] eal: add power management intrinsics

In reply to Anatoly Burakov
Quoted 13 lines

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

Quoted 8 lines

For more details, please refer to Intel(R) 64 and IA-32 Architectures Software Developer's Manual, Volume 2.

---

Quoted 1 line

2.17.1

#325 lore raw

Re: [dpdk-dev] [PATCH v7 02/10] eal: add power management intrinsics

In reply to Anatoly Burakov

15/10/2020 14:04, Anatoly Burakov:

Quoted 4 lines
lib/librte_eal/arm/include/rte_power_intrinsics.h new file +4 -0
+/**
+ * This function is not supported on ARM.
+ */
+static inline void

lib/librte_eal/arm/include/rte_power_intrinsics.h line 29

Quoted 10 lines
lib/librte_eal/arm/include/rte_power_intrinsics.h new file +10 -0
+rte_power_monitor(const volatile void *p, const uint64_t expected_value,
+               const uint64_t value_mask, const uint64_t tsc_timestamp,
+               const uint8_t data_sz)
+{
+       RTE_SET_USED(p);
+       RTE_SET_USED(expected_value);
+       RTE_SET_USED(value_mask);
+       RTE_SET_USED(tsc_timestamp);
+       RTE_SET_USED(data_sz);
+}

Are you sure it cannot be partially supported with WFE instruction?

#326 lore raw

Re: [dpdk-dev] [PATCH v7 02/10] eal: add power management intrinsics

Quoted 32 lines

-----Original Message-----
From: Thomas Monjalon <[email protected]>
Sent: Tuesday, October 20, 2020 5:13 AM
To: Ruifeng Wang <[email protected]>; Honnappa Nagarahalli <[email protected]>
Cc: [email protected]; Liang Ma <[email protected]>; Jan Viktorin <[email protected]>; David Christensen <[email protected]>; Bruce Richardson <[email protected]>; Konstantin Ananyev <[email protected]>; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; Anatoly Burakov <[email protected]>; [email protected]
Subject: Re: [dpdk-dev] [PATCH v7 02/10] eal: add power management intrinsics

15/10/2020 14:04, Anatoly Burakov:

lib/librte_eal/arm/include/rte_power_intrinsics.h

Quoted 5 lines
lib/librte_eal/arm/include/rte_power_intrinsics.h new file +5 -0
+/**
+ * This function is not supported on ARM.
+ */
+static inline void
+rte_power_monitor(const volatile void *p, const uint64_t

expected_value,

lib/librte_eal/arm/include/rte_power_intrinsics.h line 29

Quoted 8 lines
lib/librte_eal/arm/include/rte_power_intrinsics.h new file +8 -0
+               const uint64_t value_mask, const uint64_t tsc_timestamp,
+               const uint8_t data_sz) {
+       RTE_SET_USED(p);
+       RTE_SET_USED(expected_value);
+       RTE_SET_USED(value_mask);
+       RTE_SET_USED(tsc_timestamp);
+       RTE_SET_USED(data_sz);
+}
Quoted 2 lines

Are you sure it cannot be partially supported with WFE instruction?

Armv8 WFE instruction can support monitoring of specific address for changes, but not monitoring of TSC timestamp.

#327 lore raw

Re: [dpdk-dev] [PATCH v7 02/10] eal: add power management intrinsics

20/10/2020 04:49, Ruifeng Wang:

Quoted 17 lines

From: Thomas Monjalon <[email protected]>

Quoted 16 lines

15/10/2020 14:04, Anatoly Burakov:

lib/librte_eal/arm/include/rte_power_intrinsics.h

Quoted 5 lines
lib/librte_eal/arm/include/rte_power_intrinsics.h new file +5 -0
+/**
+ * This function is not supported on ARM.
+ */
+static inline void
+rte_power_monitor(const volatile void *p, const uint64_t

expected_value,

Quoted 8 lines
lib/librte_eal/arm/include/rte_power_intrinsics.h new file +8 -0
+               const uint64_t value_mask, const uint64_t tsc_timestamp,
+               const uint8_t data_sz) {
+       RTE_SET_USED(p);
+       RTE_SET_USED(expected_value);
+       RTE_SET_USED(value_mask);
+       RTE_SET_USED(tsc_timestamp);
+       RTE_SET_USED(data_sz);
+}
Quoted 4 lines
Quoted 2 lines

Are you sure it cannot be partially supported with WFE instruction?

Armv8 WFE instruction can support monitoring of specific address for changes, but not monitoring of TSC timestamp.

So it is a partial support.

We must try hard to unify architectures support
to avoid #ifdef everywhere.

I don't agree with how are managed new instructions recently. Please look further.

#328 lore raw

Re: [dpdk-dev] [PATCH v7 02/10] eal: add power management intrinsics

Quoted 21 lines · Thomas Monjalon

20/10/2020 04:49, Ruifeng Wang:

Quoted 16 lines

From: Thomas Monjalon <[email protected]>

Quoted 15 lines

15/10/2020 14:04, Anatoly Burakov:

lib/librte_eal/arm/include/rte_power_intrinsics.h

Quoted 5 lines
lib/librte_eal/arm/include/rte_power_intrinsics.h new file +5 -0
+/**
+ * This function is not supported on ARM.
+ */
+static inline void
+rte_power_monitor(const volatile void *p, const uint64_t

expected_value,

Quoted 8 lines
lib/librte_eal/arm/include/rte_power_intrinsics.h new file +8 -0
+               const uint64_t value_mask, const uint64_t tsc_timestamp,
+               const uint8_t data_sz) {
+       RTE_SET_USED(p);
+       RTE_SET_USED(expected_value);
+       RTE_SET_USED(value_mask);
+       RTE_SET_USED(tsc_timestamp);
+       RTE_SET_USED(data_sz);
+}
Quoted 4 lines
Quoted 2 lines

Are you sure it cannot be partially supported with WFE instruction?

Armv8 WFE instruction can support monitoring of specific address for changes, but not monitoring of TSC timestamp.

Quoted 8 lines

So it is a partial support.

We must try hard to unify architectures support
to avoid #ifdef everywhere.

I don't agree with how are managed new instructions recently. Please look further.

Hi Thomas,

We believe this is ready for -rc1, can we discuss this with the technical board before the RC1 tag is applied?

Regards,
Dave.

#329 lore raw

Re: [dpdk-dev] [PATCH v7 02/10] eal: add power management intrinsics

Quoted 29 lines · David Hunt
Quoted 27 lines · Thomas Monjalon

20/10/2020 04:49, Ruifeng Wang:

Quoted 17 lines

From: Thomas Monjalon <[email protected]>

Quoted 16 lines

15/10/2020 14:04, Anatoly Burakov:

lib/librte_eal/arm/include/rte_power_intrinsics.h

Quoted 5 lines
lib/librte_eal/arm/include/rte_power_intrinsics.h new file +5 -0
+/**
+ * This function is not supported on ARM.
+ */
+static inline void
+rte_power_monitor(const volatile void *p, const uint64_t

expected_value,

Quoted 9 lines

+               const uint64_t value_mask, const uint64_t tsc_timestamp,
+               const uint8_t data_sz) {
+       RTE_SET_USED(p);
+       RTE_SET_USED(expected_value);
+       RTE_SET_USED(value_mask);
+       RTE_SET_USED(tsc_timestamp);
+       RTE_SET_USED(data_sz);
+}

Quoted 4 lines
Quoted 2 lines

Are you sure it cannot be partially supported with WFE instruction?

Armv8 WFE instruction can support monitoring of specific address for changes, but not monitoring of TSC timestamp.

So it is a partial support.

We must try hard to unify architectures support
to avoid #ifdef everywhere.

Quoted 8 lines
Quoted 3 lines

I don't agree with how are managed new instructions recently. Please look further.

Hi Thomas,

We believe this is ready for -rc1, can we discuss this with the technical board before the RC1 tag is applied?

Hi Thomas,
    By way of further follow-up, here are the reasons why we believe it's ready for merge.

There are 18 Acks for the 10 patches, with the two critical patches getting 4 acks each. These acks are from ARM, Marvell, IBM and Intel.
There have been 7 revisions, with quite a lot of discussion, and all comments have been addressed and Ack'd. From what I can see, the community are in agreement that this patch should be merged.

Rgds,
Dave.

#330 lore raw

Re: [dpdk-dev] [PATCH v7 02/10] eal: add power management intrinsics

20/10/2020 16:17, David Hunt:

Quoted 44 lines · David Hunt
Quoted 29 lines · Thomas Monjalon
Quoted 28 lines

20/10/2020 04:49, Ruifeng Wang:

Quoted 17 lines

From: Thomas Monjalon <[email protected]>

Quoted 16 lines

15/10/2020 14:04, Anatoly Burakov:

lib/librte_eal/arm/include/rte_power_intrinsics.h

Quoted 5 lines
lib/librte_eal/arm/include/rte_power_intrinsics.h new file +5 -0
+/**
+ * This function is not supported on ARM.
+ */
+static inline void
+rte_power_monitor(const volatile void *p, const uint64_t

expected_value,

Quoted 9 lines

+ const uint64_t value_mask, const uint64_t
tsc_timestamp,

lib/librte_eal/arm/include/rte_power_intrinsics.h new file +7 -0
+               const uint8_t data_sz) {
+       RTE_SET_USED(p);
+       RTE_SET_USED(expected_value);
+       RTE_SET_USED(value_mask);
+       RTE_SET_USED(tsc_timestamp);
+       RTE_SET_USED(data_sz);
+}
Quoted 5 lines
Quoted 2 lines

Are you sure it cannot be partially supported with WFE instruction?

Armv8 WFE instruction can support monitoring of specific address for changes,
but not monitoring of TSC timestamp.

So it is a partial support.

We must try hard to unify architectures support
to avoid #ifdef everywhere.

Quoted 9 lines
Quoted 3 lines

I don't agree with how are managed new instructions recently. Please look further.

Hi Thomas,

We believe this is ready for -rc1, can we discuss this with the technical board before the RC1 tag is applied?

Hi Thomas,
By way of further follow-up, here are the reasons why we believe
it's ready for merge.

Quoted 7 lines

There are 18 Acks for the 10 patches, with the two critical patches getting 4 acks each.
These acks are from ARM, Marvell, IBM and Intel.
There have been 7 revisions, with quite a lot of discussion, and all comments have been addressed and Ack'd.
From what I can see, the community are in agreement that this patch
should be merged.

The problem is that I don't agree,
and I feel you tried to avoid comments from others at the beginning.

Now I don't want to spend more time on it before tagging -rc1.

Next time, you'll make sure to Cc and reply everybody.

#331 lore raw

Re: [dpdk-dev] [PATCH v7 02/10] eal: add power management intrinsics

Quoted 55 lines

20/10/2020 16:17, David Hunt:

Quoted 44 lines · David Hunt
Quoted 29 lines · Thomas Monjalon
Quoted 28 lines

20/10/2020 04:49, Ruifeng Wang:

Quoted 17 lines

From: Thomas Monjalon <[email protected]>

Quoted 16 lines

15/10/2020 14:04, Anatoly Burakov:

Review

Quoted 5 lines
(quoted diff) +5 -0
+/**
+ * This function is not supported on ARM.
+ */
+static inline void
+rte_power_monitor(const volatile void *p, const uint64_t

expected_value,

Quoted 9 lines

+ const uint64_t value_mask, const uint64_t
tsc_timestamp,

(quoted diff) +7 -0
+               const uint8_t data_sz) {
+       RTE_SET_USED(p);
+       RTE_SET_USED(expected_value);
+       RTE_SET_USED(value_mask);
+       RTE_SET_USED(tsc_timestamp);
+       RTE_SET_USED(data_sz);
+}
Quoted 5 lines
Quoted 2 lines

Are you sure it cannot be partially supported with WFE instruction?

Armv8 WFE instruction can support monitoring of specific address for changes,
but not monitoring of TSC timestamp.

So it is a partial support.

We must try hard to unify architectures support
to avoid #ifdef everywhere.

Quoted 9 lines
Quoted 3 lines

I don't agree with how are managed new instructions recently. Please look further.

Hi Thomas,

We believe this is ready for -rc1, can we discuss this with the technical board before the RC1 tag is applied?

Hi Thomas,
By way of further follow-up, here are the reasons why we believe
it's ready for merge.

Quoted 7 lines

There are 18 Acks for the 10 patches, with the two critical patches getting 4 acks each.
These acks are from ARM, Marvell, IBM and Intel.
There have been 7 revisions, with quite a lot of discussion, and all comments have been addressed and Ack'd.
From what I can see, the community are in agreement that this patch
should be merged.

Quoted 1 line

The problem is that I don't agree,

Thomas, could you explain about what exactly you don't agree with? Is it about WFE? Something else?
Konstantin

Quoted 6 lines

and I feel you tried to avoid comments from others at the beginning.

Now I don't want to spend more time on it before tagging -rc1.

Next time, you'll make sure to Cc and reply everybody.

#332 lore raw

Re: [dpdk-dev] [PATCH v7 02/10] eal: add power management intrinsics

20/10/2020 19:26, Ananyev, Konstantin:

Quoted 53 lines
Quoted 53 lines

20/10/2020 16:17, David Hunt:

Quoted 51 lines · David Hunt
Quoted 29 lines · Thomas Monjalon
Quoted 28 lines

20/10/2020 04:49, Ruifeng Wang:

Quoted 17 lines

From: Thomas Monjalon <[email protected]>

Quoted 16 lines

15/10/2020 14:04, Anatoly Burakov:

Review

Quoted 5 lines
(quoted diff) +5 -0
+/**
+ * This function is not supported on ARM.
+ */
+static inline void
+rte_power_monitor(const volatile void *p, const uint64_t

expected_value,

Quoted 9 lines

+ const uint64_t value_mask, const uint64_t
tsc_timestamp,

(quoted diff) +7 -0
+               const uint8_t data_sz) {
+       RTE_SET_USED(p);
+       RTE_SET_USED(expected_value);
+       RTE_SET_USED(value_mask);
+       RTE_SET_USED(tsc_timestamp);
+       RTE_SET_USED(data_sz);
+}
Quoted 5 lines
Quoted 2 lines

Are you sure it cannot be partially supported with WFE instruction?

Armv8 WFE instruction can support monitoring of specific address for changes,
but not monitoring of TSC timestamp.

So it is a partial support.

We must try hard to unify architectures support
to avoid #ifdef everywhere.

Quoted 9 lines
Quoted 3 lines

I don't agree with how are managed new instructions recently. Please look further.

Hi Thomas,

We believe this is ready for -rc1, can we discuss this with the technical board before the RC1 tag is applied?

Hi Thomas,
By way of further follow-up, here are the reasons why we believe
it's ready for merge.

There are 18 Acks for the 10 patches, with the two critical patches getting 4 acks each.
These acks are from ARM, Marvell, IBM and Intel.
There have been 7 revisions, with quite a lot of discussion, and all comments have been addressed and Ack'd.
From what I can see, the community are in agreement that this patch
should be merged.

Quoted 4 lines
Quoted 1 line

The problem is that I don't agree,

Thomas, could you explain about what exactly you don't agree with? Is it about WFE? Something else?

It's about -rc1. I will look at this patchset for -rc2.

Quoted 5 lines
Quoted 5 lines

and I feel you tried to avoid comments from others at the beginning.

Now I don't want to spend more time on it before tagging -rc1.

Next time, you'll make sure to Cc and reply everybody.

#333 lore raw

PATCH v7 3/10 eal: add intrinsics support check infrastructure

In reply to Anatoly Burakov

Currently, it is not possible to check support for intrinsics that are platform-specific, cannot be abstracted in a generic way, or do not have support on all architectures. The CPUID flags can be used to some extent, but they are only defined for their platform, while intrinsics will be available to all code as they are in generic headers.

This patch introduces infrastructure to check support for certain platform-specific intrinsics, and adds support for checking support for IA power management-related intrinsics for UMWAIT/UMONITOR and TPAUSE.

---

Notes:
v6:
- Fix the comments

 lib/librte_eal/arm/rte_cpuflags.c             |  6 +++++
 lib/librte_eal/include/generic/rte_cpuflags.h | 26 +++++++++++++++++++
 .../include/generic/rte_power_intrinsics.h    | 12 +++++++++
 lib/librte_eal/ppc/rte_cpuflags.c             |  7 +++++
 lib/librte_eal/rte_eal_version.map            |  1 +
 lib/librte_eal/x86/rte_cpuflags.c             | 12 +++++++++
 6 files changed, 64 insertions(+)
lib/librte_eal/arm/rte_cpuflags.c +6 -0
index 7b257b7873..e3a53bcece 100644
@@ -151,3 +151,9 @@ rte_cpu_get_flag_name(enum rte_cpu_flag_t feature)
 		return NULL;
 	return rte_cpu_feature_table[feature].name;
 }
+
+void
+rte_cpu_get_intrinsics_support(struct rte_cpu_intrinsics *intrinsics)
+{
+	memset(intrinsics, 0, sizeof(*intrinsics));
+}
lib/librte_eal/include/generic/rte_cpuflags.h +26 -0
index 872f0ebe3e..28a5aecde8 100644
@@ -13,6 +13,32 @@
 #include "rte_common.h"
 #include <errno.h>
 
+#include <rte_compat.h>
+
+/**
+ * Structure used to describe platform-specific intrinsics that may or may not
+ * be supported at runtime.
+ */
+struct rte_cpu_intrinsics {
+	uint32_t power_monitor : 1;
+	/**< indicates support for rte_power_monitor function */
+	uint32_t power_pause : 1;
+	/**< indicates support for rte_power_pause function */
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Check CPU support for various intrinsics at runtime.
+ *
+ * @param intrinsics
+ *     Pointer to a structure to be filled.
+ */
+__rte_experimental
+void
+rte_cpu_get_intrinsics_support(struct rte_cpu_intrinsics *intrinsics);
+
 /**
  * Enumeration of all CPU features supported
  */
lib/librte_eal/include/generic/rte_power_intrinsics.h +12 -0
index fb897d9060..03a326f076 100644
@@ -32,6 +32,10 @@
  * checked against the expected value, and if they match, the entering of
  * optimized power state may be aborted.
  *
+ * @warning It is responsibility of the user to check if this function is
+ *   supported at runtime using `rte_cpu_get_features()` API call. Failing to do
+ *   so may result in an illegal CPU instruction error.
+ *
  * @param p
  *   Address to monitor for changes.
  * @param expected_value
@@ -69,6 +73,10 @@ static inline void rte_power_monitor(const volatile void *p,
  * This call will also lock a spinlock on entering sleep, and release it on
  * waking up the CPU.
  *
+ * @warning It is responsibility of the user to check if this function is
+ *   supported at runtime using `rte_cpu_get_features()` API call. Failing to do
+ *   so may result in an illegal CPU instruction error.
+ *
  * @param p
  *   Address to monitor for changes.
  * @param expected_value
@@ -101,6 +109,10 @@ static inline void rte_power_monitor_sync(const volatile void *p,
  * Enter an architecture-defined optimized power state until a certain TSC
  * timestamp is reached.
  *
+ * @warning It is responsibility of the user to check if this function is
+ *   supported at runtime using `rte_cpu_get_features()` API call. Failing to do
+ *   so may result in an illegal CPU instruction error.
+ *
  * @param tsc_timestamp
  *   Maximum TSC timestamp to wait for. Note that the wait behavior is
  *   architecture-dependent.
lib/librte_eal/ppc/rte_cpuflags.c +7 -0
index 3bb7563ce9..61db5c216d 100644
@@ -8,6 +8,7 @@
 #include <elf.h>
 #include <fcntl.h>
 #include <assert.h>
+#include <string.h>
 #include <unistd.h>
 
 /* Symbolic values for the entries in the auxiliary table */
@@ -108,3 +109,9 @@ rte_cpu_get_flag_name(enum rte_cpu_flag_t feature)
 		return NULL;
 	return rte_cpu_feature_table[feature].name;
 }
+
+void
+rte_cpu_get_intrinsics_support(struct rte_cpu_intrinsics *intrinsics)
+{
+	memset(intrinsics, 0, sizeof(*intrinsics));
+}
lib/librte_eal/rte_eal_version.map +1 -0
index a93dea9fe6..ed944f2bd4 100644
@@ -400,6 +400,7 @@ EXPERIMENTAL {
 	# added in 20.11
 	__rte_eal_trace_generic_size_t;
 	rte_service_lcore_may_be_active;
+	rte_cpu_get_intrinsics_support;
 };
 
 INTERNAL {
lib/librte_eal/x86/rte_cpuflags.c +12 -0
index 0325c4b93b..a96312ff7f 100644
@@ -7,6 +7,7 @@
 #include <stdio.h>
 #include <errno.h>
 #include <stdint.h>
+#include <string.h>
 
 #include "rte_cpuid.h"
 
@@ -179,3 +180,14 @@ rte_cpu_get_flag_name(enum rte_cpu_flag_t feature)
 		return NULL;
 	return rte_cpu_feature_table[feature].name;
 }
+
+void
+rte_cpu_get_intrinsics_support(struct rte_cpu_intrinsics *intrinsics)
+{
+	memset(intrinsics, 0, sizeof(*intrinsics));
+
+	if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_WAITPKG)) {
+		intrinsics->power_monitor = 1;
+		intrinsics->power_pause = 1;
+	}
+}
Signature · 1 line
2.17.1
Acked-by on v7 3/10
#334 lore raw

Re: [dpdk-dev] [PATCH v7 03/10] eal: add intrinsics support check infrastructure

Quoted 34 lines

-----Original Message-----
From: Anatoly Burakov <[email protected]>
Sent: Thursday, October 15, 2020 8:04 PM
To: [email protected]
Cc: Jan Viktorin <[email protected]>; Ruifeng Wang <[email protected]>; David Christensen <[email protected]>; Ray Kinsella <[email protected]>; Neil Horman <[email protected]>; Bruce Richardson <[email protected]>; Konstantin Ananyev <[email protected]>; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]
Subject: [PATCH v7 03/10] eal: add intrinsics support check infrastructure

Currently, it is not possible to check support for intrinsics that are platform- specific, cannot be abstracted in a generic way, or do not have support on all architectures. The CPUID flags can be used to some extent, but they are only defined for their platform, while intrinsics will be available to all code as they are in generic headers.

This patch introduces infrastructure to check support for certain platform- specific intrinsics, and adds support for checking support for IA power management-related intrinsics for UMWAIT/UMONITOR and TPAUSE.

---

Notes:
v6:
- Fix the comments

Quoted 8 lines
 lib/librte_eal/arm/rte_cpuflags.c             |  6 +++++
 lib/librte_eal/include/generic/rte_cpuflags.h | 26 +++++++++++++++++++
 .../include/generic/rte_power_intrinsics.h    | 12 +++++++++
 lib/librte_eal/ppc/rte_cpuflags.c             |  7 +++++
 lib/librte_eal/rte_eal_version.map            |  1 +
 lib/librte_eal/x86/rte_cpuflags.c             | 12 +++++++++
 6 files changed, 64 insertions(+)
Acked-by on v7 3/10
#335 lore raw

Re: [dpdk-dev] [PATCH v7 03/10] eal: add intrinsics support check infrastructure

In reply to Anatoly Burakov
Quoted 19 lines · Anatoly Burakov

Currently, it is not possible to check support for intrinsics that are platform-specific, cannot be abstracted in a generic way, or do not have support on all architectures. The CPUID flags can be used to some extent, but they are only defined for their platform, while intrinsics will be available to all code as they are in generic headers.

This patch introduces infrastructure to check support for certain platform-specific intrinsics, and adds support for checking support for IA power management-related intrinsics for UMWAIT/UMONITOR and TPAUSE.

---

Notes:
v6:
- Fix the comments

Quoted 7 lines
 lib/librte_eal/arm/rte_cpuflags.c             |  6 +++++
 lib/librte_eal/include/generic/rte_cpuflags.h | 26 +++++++++++++++++++
 .../include/generic/rte_power_intrinsics.h    | 12 +++++++++
 lib/librte_eal/ppc/rte_cpuflags.c             |  7 +++++
 lib/librte_eal/rte_eal_version.map            |  1 +
 lib/librte_eal/x86/rte_cpuflags.c             | 12 +++++++++
 6 files changed, 64 insertions(+)
Quoted 150 lines
lib/librte_eal/arm/rte_cpuflags.c +6 -0
index 7b257b7873..e3a53bcece 100644
@@ -151,3 +151,9 @@ rte_cpu_get_flag_name(enum rte_cpu_flag_t feature)
 		return NULL;
 	return rte_cpu_feature_table[feature].name;
 }
+
+void
+rte_cpu_get_intrinsics_support(struct rte_cpu_intrinsics *intrinsics)
+{
+	memset(intrinsics, 0, sizeof(*intrinsics));
+}
lib/librte_eal/include/generic/rte_cpuflags.h +26 -0
index 872f0ebe3e..28a5aecde8 100644
@@ -13,6 +13,32 @@
 #include "rte_common.h"
 #include <errno.h>
 
+#include <rte_compat.h>
+
+/**
+ * Structure used to describe platform-specific intrinsics that may or may not
+ * be supported at runtime.
+ */
+struct rte_cpu_intrinsics {
+	uint32_t power_monitor : 1;
+	/**< indicates support for rte_power_monitor function */
+	uint32_t power_pause : 1;
+	/**< indicates support for rte_power_pause function */
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Check CPU support for various intrinsics at runtime.
+ *
+ * @param intrinsics
+ *     Pointer to a structure to be filled.
+ */
+__rte_experimental
+void
+rte_cpu_get_intrinsics_support(struct rte_cpu_intrinsics *intrinsics);
+
 /**
  * Enumeration of all CPU features supported
  */
lib/librte_eal/include/generic/rte_power_intrinsics.h +12 -0
index fb897d9060..03a326f076 100644
@@ -32,6 +32,10 @@
  * checked against the expected value, and if they match, the entering of
  * optimized power state may be aborted.
  *
+ * @warning It is responsibility of the user to check if this function is
+ *   supported at runtime using `rte_cpu_get_features()` API call. Failing to do
+ *   so may result in an illegal CPU instruction error.
+ *
  * @param p
  *   Address to monitor for changes.
  * @param expected_value
@@ -69,6 +73,10 @@ static inline void rte_power_monitor(const volatile void *p,
  * This call will also lock a spinlock on entering sleep, and release it on
  * waking up the CPU.
  *
+ * @warning It is responsibility of the user to check if this function is
+ *   supported at runtime using `rte_cpu_get_features()` API call. Failing to do
+ *   so may result in an illegal CPU instruction error.
+ *
  * @param p
  *   Address to monitor for changes.
  * @param expected_value
@@ -101,6 +109,10 @@ static inline void rte_power_monitor_sync(const volatile void *p,
  * Enter an architecture-defined optimized power state until a certain TSC
  * timestamp is reached.
  *
+ * @warning It is responsibility of the user to check if this function is
+ *   supported at runtime using `rte_cpu_get_features()` API call. Failing to do
+ *   so may result in an illegal CPU instruction error.
+ *
  * @param tsc_timestamp
  *   Maximum TSC timestamp to wait for. Note that the wait behavior is
  *   architecture-dependent.
lib/librte_eal/ppc/rte_cpuflags.c +7 -0
index 3bb7563ce9..61db5c216d 100644
@@ -8,6 +8,7 @@
 #include <elf.h>
 #include <fcntl.h>
 #include <assert.h>
+#include <string.h>
 #include <unistd.h>
 
 /* Symbolic values for the entries in the auxiliary table */
@@ -108,3 +109,9 @@ rte_cpu_get_flag_name(enum rte_cpu_flag_t feature)
 		return NULL;
 	return rte_cpu_feature_table[feature].name;
 }
+
+void
+rte_cpu_get_intrinsics_support(struct rte_cpu_intrinsics *intrinsics)
+{
+	memset(intrinsics, 0, sizeof(*intrinsics));
+}
lib/librte_eal/rte_eal_version.map +1 -0
index a93dea9fe6..ed944f2bd4 100644
@@ -400,6 +400,7 @@ EXPERIMENTAL {
 	# added in 20.11
 	__rte_eal_trace_generic_size_t;
 	rte_service_lcore_may_be_active;
+	rte_cpu_get_intrinsics_support;
 };
 
 INTERNAL {
lib/librte_eal/x86/rte_cpuflags.c +12 -0
index 0325c4b93b..a96312ff7f 100644
@@ -7,6 +7,7 @@
 #include <stdio.h>
 #include <errno.h>
 #include <stdint.h>
+#include <string.h>
 
 #include "rte_cpuid.h"
 
@@ -179,3 +180,14 @@ rte_cpu_get_flag_name(enum rte_cpu_flag_t feature)
 		return NULL;
 	return rte_cpu_feature_table[feature].name;
 }
+
+void
+rte_cpu_get_intrinsics_support(struct rte_cpu_intrinsics *intrinsics)
+{
+	memset(intrinsics, 0, sizeof(*intrinsics));
+
+	if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_WAITPKG)) {
+		intrinsics->power_monitor = 1;
+		intrinsics->power_pause = 1;
+	}
+}
#336 lore raw

PATCH v7 4/10 ethdev: add simple power management API

In reply to Anatoly Burakov

From: Liang Ma <[email protected]>

Add a simple API to allow getting address of next RX descriptor from the PMD, as well as release notes information.

---

Notes:
v7:
- Fixed queue ID validation
- Fixed documentation

v6:
- Rebase on top of latest main
- Ensure the API checks queue ID (Konstantin)
- Removed accidental inclusion of unrelated release notes
v5:
- Bring function format in line with other functions in the file
- Ensure the API is supported by the driver before calling it (Konstantin)

 doc/guides/rel_notes/release_20_11.rst   |  8 ++++++-
 lib/librte_ethdev/rte_ethdev.c           | 23 +++++++++++++++++++
 lib/librte_ethdev/rte_ethdev.h           | 28 ++++++++++++++++++++++++
 lib/librte_ethdev/rte_ethdev_driver.h    | 28 ++++++++++++++++++++++++
 lib/librte_ethdev/rte_ethdev_version.map |  1 +
 5 files changed, 87 insertions(+), 1 deletion(-)
doc/guides/rel_notes/release_20_11.rst +7 -1
index c61d7fcf67..4c6a615ce9 100644
@@ -71,7 +71,13 @@ New Features
 * **Added the FEC API, for a generic FEC query and config.**
 
   Added the FEC API which provides functions for query FEC capabilities and
-  current FEC mode from device. Also, API for configuring FEC mode is also provided.
+  current FEC mode from device. Also, API for configuring FEC mode is also
+  provided.
+
+* **ethdev: add 1 new EXPERIMENTAL API for PMD power management.**
+
+  * ``rte_eth_get_wake_addr()``
+  * add new eth_dev_ops ``get_wake_addr``
 
 * **Updated Broadcom bnxt driver.**
 
lib/librte_ethdev/rte_ethdev.c +23 -0
index 59beb8aec2..d972a3a656 100644
@@ -4844,6 +4844,29 @@ rte_eth_tx_burst_mode_get(uint16_t port_id, uint16_t queue_id,
 		       dev->dev_ops->tx_burst_mode_get(dev, queue_id, mode));
 }
 
+int
+rte_eth_get_wake_addr(uint16_t port_id, uint16_t queue_id,
+		volatile void **wake_addr, uint64_t *expected, uint64_t *mask,
+		uint8_t *data_sz)
+{
+	struct rte_eth_dev *dev;
+
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_wake_addr, -ENOTSUP);
+
+	if (queue_id >= dev->data->nb_rx_queues) {
+		RTE_ETHDEV_LOG(ERR, "Invalid RX queue_id=%u\n", queue_id);
+		return -EINVAL;
+	}
+
+	return eth_err(port_id,
+		dev->dev_ops->get_wake_addr(dev->data->rx_queues[queue_id],
+			wake_addr, expected, mask, data_sz));
+}
+
 int
 rte_eth_dev_set_mc_addr_list(uint16_t port_id,
 			     struct rte_ether_addr *mc_addr_set,
lib/librte_ethdev/rte_ethdev.h +28 -0
index 3a31f94367..008bc3cce0 100644
@@ -4119,6 +4119,34 @@ __rte_experimental
 int rte_eth_tx_burst_mode_get(uint16_t port_id, uint16_t queue_id,
 	struct rte_eth_burst_mode *mode);
 
+/**
+ * Retrieve the wake up address for the receive queue.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param queue_id
+ *   The Rx queue on the Ethernet device for which information will be
+ *   retrieved.
+ * @param wake_addr
+ *   The pointer to the address which will be monitored.
+ * @param expected
+ *   The pointer to value to be expected when descriptor is set.
+ * @param mask
+ *   The pointer to comparison bitmask for the expected value.
+ * @param data_sz
+ *   The pointer to data size for the expected value and comparison bitmask.
+ *
+ * @return
+ *   - 0: Success.
+ *   -ENOTSUP: Operation not supported.
+ *   -EINVAL: Invalid parameters.
+ *   -ENODEV: Invalid port ID.
+ */
+__rte_experimental
+int rte_eth_get_wake_addr(uint16_t port_id, uint16_t queue_id,
+		volatile void **wake_addr, uint64_t *expected, uint64_t *mask,
+		uint8_t *data_sz);
+
 /**
  * Retrieve device registers and register attributes (number of registers and
  * register size)
lib/librte_ethdev/rte_ethdev_driver.h +28 -0
index 35cc4fb186..76b179de42 100644
@@ -655,6 +655,32 @@ typedef int (*eth_fec_get_t)(struct rte_eth_dev *dev,
  */
 typedef int (*eth_fec_set_t)(struct rte_eth_dev *dev, uint32_t fec_capa);
 
+/**
+ * @internal
+ * Get address of memory location whose contents will change whenever there is
+ * new data to be received on an RX queue.
+ *
+ * @param rxq
+ *   Ethdev queue pointer.
+ * @param tail_desc_addr
+ *   The pointer point to where the address will be stored.
+ * @param expected
+ *   The pointer point to value to be expected when descriptor is set.
+ * @param mask
+ *   The pointer point to comparison bitmask for the expected value.
+ * @param data_sz
+ *   Data size for the expected value (can be 1, 2, 4, or 8 bytes)
+ * @return
+ *   Negative errno value on error, 0 on success.
+ *
+ * @retval 0
+ *   Success
+ * @retval -EINVAL
+ *   Invalid parameters
+ */
+typedef int (*eth_get_wake_addr_t)(void *rxq, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask, uint8_t *data_sz);
+
 /**
  * @internal A structure containing the functions exported by an Ethernet driver.
  */
@@ -801,6 +827,8 @@ struct eth_dev_ops {
 	/**< Get Forward Error Correction(FEC) mode. */
 	eth_fec_set_t fec_set;
 	/**< Set Forward Error Correction(FEC) mode. */
+	eth_get_wake_addr_t get_wake_addr;
+	/**< Get next RX queue ring entry address. */
 };
 
 /**
lib/librte_ethdev/rte_ethdev_version.map +1 -0
index f8a0945812..6c2ea5996d 100644
@@ -232,6 +232,7 @@ EXPERIMENTAL {
 	rte_eth_fec_get_capability;
 	rte_eth_fec_get;
 	rte_eth_fec_set;
+	rte_eth_get_wake_addr;
 };
 
 INTERNAL {
Signature · 1 line
2.17.1
#337 lore raw

PATCH v7 5/10 power: add PMD power management API and callback

In reply to Anatoly Burakov

From: Liang Ma <[email protected]>

Add a simple on/off switch that will enable saving power when no packets are arriving. It is based on counting the number of empty polls and, when the number reaches a certain threshold, entering an architecture-defined optimized power state that will either wait until a TSC timestamp expires, or when packets arrive.

This API mandates a core-to-single-queue mapping (that is, multiple queued per device are supported, but they have to be polled on different cores).

This design is using PMD RX callbacks.

1. UMWAIT/UMONITOR:

When a certain threshold of empty polls is reached, the core will go into a power optimized sleep while waiting on an address of next RX descriptor to be written to.

2. Pause instruction

Instead of move the core into deeper C state, this method uses the pause instruction to avoid busy polling.

3. Frequency scaling
Reuse existing DPDK power library to scale up/down core frequency depending on traffic volume.

---

Notes:
v7:
- Fixed race condition (Konstantin)
- Slight rework of the structure of monitor code
- Added missing inline for wakeup

v6:
- Added wakeup mechanism for UMWAIT
- Removed memory allocation (everything is now allocated statically)
- Fixed various typos and comments
- Check for invalid queue ID
- Moved release notes to this patch

v5:
- Make error checking more robust
- Prevent initializing scaling if ACPI or PSTATE env wasn't set
- Prevent initializing UMWAIT path if PMD doesn't support get_wake_addr
- Add some debug logging
- Replace x86-specific code path to generic path using the intrinsic check

 doc/guides/rel_notes/release_20_11.rst |  11 +
 lib/librte_power/meson.build           |   5 +-
 lib/librte_power/rte_power_pmd_mgmt.c  | 320 +++++++++++++++++++++++++
 lib/librte_power/rte_power_pmd_mgmt.h  |  92 +++++++
 lib/librte_power/rte_power_version.map |   4 +
 5 files changed, 430 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_power/rte_power_pmd_mgmt.c
 create mode 100644 lib/librte_power/rte_power_pmd_mgmt.h
doc/guides/rel_notes/release_20_11.rst +11 -0
index 4c6a615ce9..a814c67d54 100644
@@ -204,6 +204,17 @@ New Features
 
    * Added support to update subport rate dynamically.
 
+* **Add PMD power management mechanism**
+
+  3 new Ethernet PMD power management mechanism is added through existing
+  RX callback infrastructure.
+
+  * Add power saving scheme based on UMWAIT instruction (x86 only)
+  * Add power saving scheme based on ``rte_pause()``
+  * Add power saving scheme based on frequency scaling through the power library
+  * Add new EXPERIMENTAL API ``rte_power_pmd_mgmt_queue_enable()``
+  * Add new EXPERIMENTAL API ``rte_power_pmd_mgmt_queue_disable()``
+
 
 Removed Items
 -------------
lib/librte_power/meson.build +3 -2
index 78c031c943..cc3c7a8646 100644
@@ -9,6 +9,7 @@ sources = files('rte_power.c', 'power_acpi_cpufreq.c',
 		'power_kvm_vm.c', 'guest_channel.c',
 		'rte_power_empty_poll.c',
 		'power_pstate_cpufreq.c',
+		'rte_power_pmd_mgmt.c',
 		'power_common.c')
-headers = files('rte_power.h','rte_power_empty_poll.h')
-deps += ['timer']
+headers = files('rte_power.h','rte_power_empty_poll.h','rte_power_pmd_mgmt.h')
+deps += ['timer' ,'ethdev']
lib/librte_power/rte_power_pmd_mgmt.c new file +320 -0

320 lines not on this page · raw message

lib/librte_power/rte_power_pmd_mgmt.h new file +92 -0

92 lines not on this page · raw message

lib/librte_power/rte_power_version.map +4 -0
index 69ca9af616..3f2f6cd6f6 100644
@@ -34,4 +34,8 @@ EXPERIMENTAL {
 	rte_power_guest_channel_receive_msg;
 	rte_power_poll_stat_fetch;
 	rte_power_poll_stat_update;
+	# added in 20.11
+	rte_power_pmd_mgmt_queue_enable;
+	rte_power_pmd_mgmt_queue_disable;
+
 };
Signature · 1 line
2.17.1
Acked-by on v7 5/10
#338 lore raw

Re: [dpdk-dev] [PATCH v7 05/10] power: add PMD power management API and callback

Quoted 85 lines

Add a simple on/off switch that will enable saving power when no packets are arriving. It is based on counting the number of empty polls and, when the number reaches a certain threshold, entering an architecture-defined optimized power state that will either wait until a TSC timestamp expires, or when packets arrive.

This API mandates a core-to-single-queue mapping (that is, multiple queued per device are supported, but they have to be polled on different cores).

This design is using PMD RX callbacks.

1. UMWAIT/UMONITOR:

When a certain threshold of empty polls is reached, the core will go into a power optimized sleep while waiting on an address of next RX descriptor to be written to.

2. Pause instruction

Instead of move the core into deeper C state, this method uses the pause instruction to avoid busy polling.

3. Frequency scaling
Reuse existing DPDK power library to scale up/down core frequency depending on traffic volume.

---

Notes:
v7:
- Fixed race condition (Konstantin)
- Slight rework of the structure of monitor code
- Added missing inline for wakeup

v6:
- Added wakeup mechanism for UMWAIT
- Removed memory allocation (everything is now allocated statically)
- Fixed various typos and comments
- Check for invalid queue ID
- Moved release notes to this patch

v5:
- Make error checking more robust
- Prevent initializing scaling if ACPI or PSTATE env wasn't set
- Prevent initializing UMWAIT path if PMD doesn't support get_wake_addr
- Add some debug logging
- Replace x86-specific code path to generic path using the intrinsic check

 doc/guides/rel_notes/release_20_11.rst |  11 +
 lib/librte_power/meson.build           |   5 +-
 lib/librte_power/rte_power_pmd_mgmt.c  | 320 +++++++++++++++++++++++++
 lib/librte_power/rte_power_pmd_mgmt.h  |  92 +++++++
 lib/librte_power/rte_power_version.map |   4 +
 5 files changed, 430 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_power/rte_power_pmd_mgmt.c
 create mode 100644 lib/librte_power/rte_power_pmd_mgmt.h
doc/guides/rel_notes/release_20_11.rst +11 -0
index 4c6a615ce9..a814c67d54 100644
@@ -204,6 +204,17 @@ New Features
 
    * Added support to update subport rate dynamically.
 
+* **Add PMD power management mechanism**
+
+  3 new Ethernet PMD power management mechanism is added through existing
+  RX callback infrastructure.
+
+  * Add power saving scheme based on UMWAIT instruction (x86 only)
+  * Add power saving scheme based on ``rte_pause()``
+  * Add power saving scheme based on frequency scaling through the power library
+  * Add new EXPERIMENTAL API ``rte_power_pmd_mgmt_queue_enable()``
+  * Add new EXPERIMENTAL API ``rte_power_pmd_mgmt_queue_disable()``
+
 
 Removed Items
 -------------

....

Quoted 43 lines
doc/guides/rel_notes/release_20_11.rst +43 -0
+
+int
+rte_power_pmd_mgmt_queue_enable(unsigned int lcore_id,
+		uint16_t port_id, uint16_t queue_id,
+		enum rte_power_pmd_mgmt_type mode)
+{
+	struct rte_eth_dev *dev;
+	struct pmd_queue_cfg *queue_cfg;
+	int ret;
+
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
+	dev = &rte_eth_devices[port_id];
+
+	/* check if queue id is valid */
+	if (queue_id >= dev->data->nb_rx_queues ||
+			queue_id >= RTE_MAX_QUEUES_PER_PORT) {
+		return -EINVAL;
+	}
+
+	queue_cfg = &port_cfg[port_id][queue_id];
+
+	if (queue_cfg->pwr_mgmt_state == PMD_MGMT_ENABLED) {
+		ret = -EINVAL;
+		goto end;
+	}
+
+	switch (mode) {
+	case RTE_POWER_MGMT_TYPE_WAIT:
+	{
+		/* check if rte_power_monitor is supported */
+		uint64_t dummy_expected, dummy_mask;
+		struct rte_cpu_intrinsics i;
+		volatile void *dummy_addr;
+		uint8_t dummy_sz;
+
+		rte_cpu_get_intrinsics_support(&i);
+
+		if (!i.power_monitor) {
+			RTE_LOG(DEBUG, POWER, "Monitoring intrinsics are not supported\n");
+			ret = -ENOTSUP;
+			goto end;
+		}
+

doc/guides/rel_notes/release_20_11.rst

Quoted 10 lines
doc/guides/rel_notes/release_20_11.rst +10 -0
+		/* check if the device supports the necessary PMD API */
+		if (rte_eth_get_wake_addr(port_id, queue_id,
+				&dummy_addr, &dummy_expected,
+				&dummy_mask, &dummy_sz) == -ENOTSUP) {
+			RTE_LOG(DEBUG, POWER, "The device does not support rte_eth_rxq_ring_addr_get\n");
+			ret = -ENOTSUP;
+			goto end;
+		}
+		/* initialize UMWAIT spinlock */
+		rte_spinlock_init(&queue_cfg->umwait_lock);

Still looks excessive and possibly error prone to me. Apart from that:

Quoted 59 lines
doc/guides/rel_notes/release_20_11.rst +59 -0
+
+		/* initialize data before enabling the callback */
+		queue_cfg->empty_poll_stats = 0;
+		queue_cfg->cb_mode = mode;
+		queue_cfg->pwr_mgmt_state = PMD_MGMT_ENABLED;
+
+		queue_cfg->cur_cb = rte_eth_add_rx_callback(port_id, queue_id,
+				clb_umwait, NULL);
+		break;
+	}
+	case RTE_POWER_MGMT_TYPE_SCALE:
+	{
+		enum power_management_env env;
+		/* only PSTATE and ACPI modes are supported */
+		if (!rte_power_check_env_supported(PM_ENV_ACPI_CPUFREQ) &&
+				!rte_power_check_env_supported(
+					PM_ENV_PSTATE_CPUFREQ)) {
+			RTE_LOG(DEBUG, POWER, "Neither ACPI nor PSTATE modes are supported\n");
+			ret = -ENOTSUP;
+			goto end;
+		}
+		/* ensure we could initialize the power library */
+		if (rte_power_init(lcore_id)) {
+			ret = -EINVAL;
+			goto end;
+		}
+		/* ensure we initialized the correct env */
+		env = rte_power_get_env();
+		if (env != PM_ENV_ACPI_CPUFREQ &&
+				env != PM_ENV_PSTATE_CPUFREQ) {
+			RTE_LOG(DEBUG, POWER, "Neither ACPI nor PSTATE modes were initialized\n");
+			ret = -ENOTSUP;
+			goto end;
+		}
+		/* initialize data before enabling the callback */
+		queue_cfg->empty_poll_stats = 0;
+		queue_cfg->cb_mode = mode;
+		queue_cfg->pwr_mgmt_state = PMD_MGMT_ENABLED;
+
+		queue_cfg->cur_cb = rte_eth_add_rx_callback(port_id,
+				queue_id, clb_scale_freq, NULL);
+		break;
+	}
+	case RTE_POWER_MGMT_TYPE_PAUSE:
+		/* initialize data before enabling the callback */
+		queue_cfg->empty_poll_stats = 0;
+		queue_cfg->cb_mode = mode;
+		queue_cfg->pwr_mgmt_state = PMD_MGMT_ENABLED;
+
+		queue_cfg->cur_cb = rte_eth_add_rx_callback(port_id, queue_id,
+				clb_pause, NULL);
+		break;
+	}
+	ret = 0;
+
+end:
+	return ret;
+}
+
#339 lore raw

PATCH v7 6/10 net/ixgbe: implement power management API

In reply to Anatoly Burakov

From: Liang Ma <[email protected]>

Implement support for the power management API by implementing a get_wake_addr function that will return an address of an RX ring's status bit.

---
 drivers/net/ixgbe/ixgbe_ethdev.c |  1 +
 drivers/net/ixgbe/ixgbe_rxtx.c   | 25 +++++++++++++++++++++++++
 drivers/net/ixgbe/ixgbe_rxtx.h   |  2 ++
 3 files changed, 28 insertions(+)
drivers/net/ixgbe/ixgbe_ethdev.c +1 -0
index 0b98e210e7..30b3f416d4 100644
@@ -588,6 +588,7 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.udp_tunnel_port_del  = ixgbe_dev_udp_tunnel_port_del,
 	.tm_ops_get           = ixgbe_tm_ops_get,
 	.tx_done_cleanup      = ixgbe_dev_tx_done_cleanup,
+	.get_wake_addr        = ixgbe_get_wake_addr,
 };
 
 /*
drivers/net/ixgbe/ixgbe_rxtx.c +25 -0
index 29d385c062..b1d656d270 100644
@@ -1366,6 +1366,31 @@ const uint32_t
 		RTE_PTYPE_INNER_L3_IPV4_EXT | RTE_PTYPE_INNER_L4_UDP,
 };
 
+int ixgbe_get_wake_addr(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask, uint8_t *data_sz)
+{
+	volatile union ixgbe_adv_rx_desc *rxdp;
+	struct ixgbe_rx_queue *rxq = rx_queue;
+	uint16_t desc;
+
+	desc = rxq->rx_tail;
+	rxdp = &rxq->rx_ring[desc];
+	/* watch for changes in status bit */
+	*tail_desc_addr = &rxdp->wb.upper.status_error;
+
+	/*
+	 * we expect the DD bit to be set to 1 if this descriptor was already
+	 * written to.
+	 */
+	*expected = rte_cpu_to_le_32(IXGBE_RXDADV_STAT_DD);
+	*mask = rte_cpu_to_le_32(IXGBE_RXDADV_STAT_DD);
+
+	/* the registers are 32-bit */
+	*data_sz = 4;
+
+	return 0;
+}
+
 /* @note: fix ixgbe_dev_supported_ptypes_get() if any change here. */
 static inline uint32_t
 ixgbe_rxd_pkt_info_to_pkt_type(uint32_t pkt_info, uint16_t ptype_mask)
drivers/net/ixgbe/ixgbe_rxtx.h +2 -0
index 0b5589ef4d..6b9afec655 100644
@@ -299,5 +299,7 @@ uint64_t ixgbe_get_tx_port_offloads(struct rte_eth_dev *dev);
 uint64_t ixgbe_get_rx_queue_offloads(struct rte_eth_dev *dev);
 uint64_t ixgbe_get_rx_port_offloads(struct rte_eth_dev *dev);
 uint64_t ixgbe_get_tx_queue_offloads(struct rte_eth_dev *dev);
+int ixgbe_get_wake_addr(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask, uint8_t *data_sz);
 
 #endif /* _IXGBE_RXTX_H_ */
Signature · 1 line
2.17.1
#340 lore raw

PATCH v7 7/10 net/i40e: implement power management API

In reply to Anatoly Burakov

From: Liang Ma <[email protected]>

Implement support for the power management API by implementing a get_wake_addr function that will return an address of an RX ring's status bit.

---
 drivers/net/i40e/i40e_ethdev.c |  1 +
 drivers/net/i40e/i40e_rxtx.c   | 26 ++++++++++++++++++++++++++
 drivers/net/i40e/i40e_rxtx.h   |  2 ++
 3 files changed, 29 insertions(+)
drivers/net/i40e/i40e_ethdev.c +1 -0
index 943cfe71dc..cab86f8ec9 100644
@@ -513,6 +513,7 @@ static const struct eth_dev_ops i40e_eth_dev_ops = {
 	.mtu_set                      = i40e_dev_mtu_set,
 	.tm_ops_get                   = i40e_tm_ops_get,
 	.tx_done_cleanup              = i40e_tx_done_cleanup,
+	.get_wake_addr	              = i40e_get_wake_addr,
 };
 
 /* store statistics names and its offset in stats structure */
drivers/net/i40e/i40e_rxtx.c +26 -0
index f2844d3f74..cdb1cd494b 100644
@@ -71,6 +71,32 @@
 #define I40E_TX_OFFLOAD_NOTSUP_MASK \
 		(PKT_TX_OFFLOAD_MASK ^ I40E_TX_OFFLOAD_MASK)
 
+int
+i40e_get_wake_addr(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask, uint8_t *data_sz)
+{
+	struct i40e_rx_queue *rxq = rx_queue;
+	volatile union i40e_rx_desc *rxdp;
+	uint16_t desc;
+
+	desc = rxq->rx_tail;
+	rxdp = &rxq->rx_ring[desc];
+	/* watch for changes in status bit */
+	*tail_desc_addr = &rxdp->wb.qword1.status_error_len;
+
+	/*
+	 * we expect the DD bit to be set to 1 if this descriptor was already
+	 * written to.
+	 */
+	*expected = rte_cpu_to_le_64(1 << I40E_RX_DESC_STATUS_DD_SHIFT);
+	*mask = rte_cpu_to_le_64(1 << I40E_RX_DESC_STATUS_DD_SHIFT);
+
+	/* registers are 64-bit */
+	*data_sz = 8;
+
+	return 0;
+}
+
 static inline void
 i40e_rxd_to_vlan_tci(struct rte_mbuf *mb, volatile union i40e_rx_desc *rxdp)
 {
drivers/net/i40e/i40e_rxtx.h +2 -0
index 57d7b4160b..5826cf1099 100644
@@ -248,6 +248,8 @@ uint16_t i40e_recv_scattered_pkts_vec_avx2(void *rx_queue,
 	struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
 uint16_t i40e_xmit_pkts_vec_avx2(void *tx_queue, struct rte_mbuf **tx_pkts,
 	uint16_t nb_pkts);
+int i40e_get_wake_addr(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *value, uint8_t *data_sz);
 
 /* For each value it means, datasheet of hardware can tell more details
  *
Signature · 1 line
2.17.1
#341 lore raw

PATCH v7 8/10 net/ice: implement power management API

In reply to Anatoly Burakov

From: Liang Ma <[email protected]>

Implement support for the power management API by implementing a get_wake_addr function that will return an address of an RX ring's status bit.

---
 drivers/net/ice/ice_ethdev.c |  1 +
 drivers/net/ice/ice_rxtx.c   | 26 ++++++++++++++++++++++++++
 drivers/net/ice/ice_rxtx.h   |  2 ++
 3 files changed, 29 insertions(+)
drivers/net/ice/ice_ethdev.c +1 -0
index d8ce09d28f..260de5dfd7 100644
@@ -216,6 +216,7 @@ static const struct eth_dev_ops ice_eth_dev_ops = {
 	.udp_tunnel_port_add          = ice_dev_udp_tunnel_port_add,
 	.udp_tunnel_port_del          = ice_dev_udp_tunnel_port_del,
 	.tx_done_cleanup              = ice_tx_done_cleanup,
+	.get_wake_addr	              = ice_get_wake_addr,
 };
 
 /* store statistics names and its offset in stats structure */
drivers/net/ice/ice_rxtx.c +26 -0
index 79e6df11f4..7c0f963d96 100644
@@ -25,6 +25,32 @@ uint64_t rte_net_ice_dynflag_proto_xtr_ipv6_flow_mask;
 uint64_t rte_net_ice_dynflag_proto_xtr_tcp_mask;
 uint64_t rte_net_ice_dynflag_proto_xtr_ip_offset_mask;
 
+int ice_get_wake_addr(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask, uint8_t *data_sz)
+{
+	volatile union ice_rx_flex_desc *rxdp;
+	struct ice_rx_queue *rxq = rx_queue;
+	uint16_t desc;
+
+	desc = rxq->rx_tail;
+	rxdp = &rxq->rx_ring[desc];
+	/* watch for changes in status bit */
+	*tail_desc_addr = &rxdp->wb.status_error0;
+
+	/*
+	 * we expect the DD bit to be set to 1 if this descriptor was already
+	 * written to.
+	 */
+	*expected = rte_cpu_to_le_16(1 << ICE_RX_FLEX_DESC_STATUS0_DD_S);
+	*mask = rte_cpu_to_le_16(1 << ICE_RX_FLEX_DESC_STATUS0_DD_S);
+
+	/* register is 16-bit */
+	*data_sz = 2;
+
+	return 0;
+}
+
+
 static inline uint8_t
 ice_proto_xtr_type_to_rxdid(uint8_t xtr_type)
 {
drivers/net/ice/ice_rxtx.h +2 -0
index 1c23c7541e..7eeb8d467e 100644
@@ -250,6 +250,8 @@ uint16_t ice_xmit_pkts_vec_avx2(void *tx_queue, struct rte_mbuf **tx_pkts,
 				uint16_t nb_pkts);
 int ice_fdir_programming(struct ice_pf *pf, struct ice_fltr_desc *fdir_desc);
 int ice_tx_done_cleanup(void *txq, uint32_t free_cnt);
+int ice_get_wake_addr(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask, uint8_t *data_sz);
 
 #define FDIR_PARSING_ENABLE_PER_QUEUE(ad, on) do { \
 	int i; \
Signature · 1 line
2.17.1
#342 lore raw

PATCH v7 9/10 examples/l3fwd-power: enable PMD power mgmt

In reply to Anatoly Burakov

From: Liang Ma <[email protected]>

Add PMD power management feature support to l3fwd-power sample app.

---

Notes:
v6:
- Fixed typos in documentation

 .../sample_app_ug/l3_forward_power_man.rst    | 13 ++++++
 examples/l3fwd-power/main.c                   | 41 ++++++++++++++++++-
 2 files changed, 53 insertions(+), 1 deletion(-)
doc/guides/sample_app_ug/l3_forward_power_man.rst +13 -0
index 0cc6f2e62e..2767fb91aa 100644
@@ -109,6 +109,8 @@ where,
 
 *   --telemetry:  Telemetry mode.
 
+*   --pmd-mgmt: PMD power management mode.
+
 See :doc:`l3_forward` for details.
 The L3fwd-power example reuses the L3fwd command line options.
 
@@ -459,3 +461,14 @@ reference cycles and accordingly busy rate is set  to either 0% or
 
 The new stats ``empty_poll`` , ``full_poll`` and ``busy_percent`` can be viewed by running the script
 ``/usertools/dpdk-telemetry-client.py`` and selecting the menu option ``Send for global Metrics``.
+
+PMD power management Mode
+-------------------------
+
+The PMD power management  mode support for ``l3fwd-power`` is a standalone mode, in this mode
+``l3fwd-power`` does simple l3fwding along with enable the power saving scheme on specific
+port/queue/lcore. Main purpose for this mode is to demonstrate how to use the PMD power management API.
+
+.. code-block:: console
+
+        ./build/examples/dpdk-l3fwd-power -l 1-3 --  --pmd-mgmt -p 0x0f --config="(0,0,2),(0,1,3)"
examples/l3fwd-power/main.c +40 -1

95 lines not on this page · raw message

Signature · 1 line
2.17.1
#343 lore raw

PATCH v7 10/10 doc: update programmer's guide for power library

In reply to Anatoly Burakov

From: Liang Ma <[email protected]>

Update programmer's guide to document PMD power management usage.

---

Notes:
v5:
- Moved l3fwd-power update to the l3fwd-power-related commit
- Some rewordings and clarifications

 doc/guides/prog_guide/power_man.rst | 42 +++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)
doc/guides/prog_guide/power_man.rst +42 -0
index 0a3755a901..38c64d31e4 100644
@@ -192,6 +192,45 @@ User Cases
 ----------
 The mechanism can applied to any device which is based on polling. e.g. NIC, FPGA.
 
+PMD Power Management API
+------------------------
+
+Abstract
+~~~~~~~~
+Existing power management mechanisms require developers to change application
+design or change code to make use of it. The PMD power management API provides a
+convenient alternative by utilizing Ethernet PMD RX callbacks, and triggering
+power saving whenever empty poll count reaches a certain number.
+
+  * UMWAIT/UMONITOR
+
+   This power saving scheme will put the CPU into optimized power state and use
+   the UMWAIT/UMONITOR instructions to monitor the Ethernet PMD RX descriptor
+   address, and wake the CPU up whenever there's new traffic.
+
+  * Pause
+
+   This power saving scheme will use the `rte_pause` function to avoid busy
+   polling.
+
+  * Frequency scaling
+
+   This power saving scheme will use existing power library functionality to
+   scale the core frequency up/down depending on traffic volume.
+
+
+.. note::
+
+   Currently, this power management API is limited to mandatory mapping of 1
+   queue to 1 core (multiple queues are supported, but they must be polled from
+   different cores).
+
+API Overview for PMD Power Management
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* **Queue Enable**: Enable specific power scheme for certain queue/port/core
+
+* **Queue Disable**: Disable power scheme for certain queue/port/core
+
 References
 ----------
 
@@ -200,3 +239,6 @@ References
 
 *   The :doc:`../sample_app_ug/vm_power_management`
     chapter in the :doc:`../sample_app_ug/index` section.
+
+*   The :doc:`../sample_app_ug/rxtx_callbacks`
+    chapter in the :doc:`../sample_app_ug/index` section.
Signature · 1 line
2.17.1
#344 lore raw

PATCH v8 1/10 eal: add new x86 cpuid support for WAITPKG

In reply to Anatoly Burakov

Add a new CPUID flag indicating processor support for UMONITOR/UMWAIT and TPAUSE instructions instruction.

---
 lib/librte_eal/x86/include/rte_cpuflags.h | 1 +
 lib/librte_eal/x86/rte_cpuflags.c         | 2 ++
 2 files changed, 3 insertions(+)
lib/librte_eal/x86/include/rte_cpuflags.h +1 -0
index c1d20364d1..848ba9cbfb 100644
@@ -132,6 +132,7 @@ enum rte_cpu_flag_t {
 	RTE_CPUFLAG_MOVDIR64B,              /**< Direct Store Instructions 64B */
 	RTE_CPUFLAG_AVX512VP2INTERSECT,     /**< AVX512 Two Register Intersection */
 
+	RTE_CPUFLAG_WAITPKG,                /**< UMONITOR/UMWAIT/TPAUSE */
 	/* The last item */
 	RTE_CPUFLAG_NUMFLAGS,               /**< This should always be the last! */
 };
lib/librte_eal/x86/rte_cpuflags.c +2 -0
index 30439e7951..0325c4b93b 100644
@@ -110,6 +110,8 @@ const struct feature_entry rte_cpu_feature_table[] = {
 	FEAT_DEF(AVX512F, 0x00000007, 0, RTE_REG_EBX, 16)
 	FEAT_DEF(RDSEED, 0x00000007, 0, RTE_REG_EBX, 18)
 
+	FEAT_DEF(WAITPKG, 0x00000007, 0, RTE_REG_ECX, 5)
+
 	FEAT_DEF(LAHF_SAHF, 0x80000001, 0, RTE_REG_ECX,  0)
 	FEAT_DEF(LZCNT, 0x80000001, 0, RTE_REG_ECX,  4)
 
Signature · 1 line
2.17.1
#345 lore raw

v9 cover Add PMD power mgmt

This patchset proposes a simple API for Ethernet drivers to cause the CPU to enter a power-optimized state while waiting for packets to arrive, along with a set of generic intrinsics that facilitate that. This is achieved through cooperation with the NIC driver that will allow us to know address of wake up event, and wait for writes on it.

On IA, this is achieved through using UMONITOR/UMWAIT instructions. They are used in their raw opcode form because there is no widespread compiler support for them yet. Still, the API is made generic enough to hopefully support other architectures, if they happen to implement similar instructions.

To achieve power savings, there is a very simple mechanism
used: we're counting empty polls, and if a certain threshold is reached, we get the address of next RX ring descriptor from the NIC driver, arm the monitoring hardware, and enter a power-optimized state. We will then wake up when either a timeout happens, or a write happens (or generally whenever CPU feels like waking up - this is platform- specific), and proceed as normal. The empty poll counter is reset whenever we actually get packets, so we only go to sleep when we know nothing is going on. The mechanism is generic which can be used for any write back descriptor.

Why are we putting it into ethdev as opposed to leaving this up to the application? Our customers specifically requested a way to do it wit minimal changes to the application code. The current approach allows to just flip a switch and automatically have power savings.

- Only 1:1 core to queue mapping is supported, meaning that each lcore must at most handle RX on a single queue
- Support 3 type policies. UMWAIT/PAUSE/Frequency_Scale
- Power management is enabled per-queue
- The API doesn't extend to other device types

Liang Ma (10):
eal: add new x86 cpuid support for WAITPKG
eal: add power management intrinsics
eal: add intrinsics support check infrastructure
ethdev: add simple power management API
power: add PMD power management API and callback net/ixgbe: implement power management API net/i40e: implement power management API net/ice: implement power management API examples/l3fwd-power: enable PMD power mgmt
doc: update programmer's guide for power library

 doc/guides/prog_guide/power_man.rst           |  42 +++
 doc/guides/rel_notes/release_20_11.rst        |  16 +
 .../sample_app_ug/l3_forward_power_man.rst    |  13 +
 drivers/net/i40e/i40e_ethdev.c                |   1 +
 drivers/net/i40e/i40e_rxtx.c                  |  26 ++
 drivers/net/i40e/i40e_rxtx.h                  |   2 +
 drivers/net/ice/ice_ethdev.c                  |   1 +
 drivers/net/ice/ice_rxtx.c                    |  26 ++
 drivers/net/ice/ice_rxtx.h                    |   2 +
 drivers/net/ixgbe/ixgbe_ethdev.c              |   1 +
 drivers/net/ixgbe/ixgbe_rxtx.c                |  25 ++
 drivers/net/ixgbe/ixgbe_rxtx.h                |   2 +
 examples/l3fwd-power/main.c                   |  46 ++-
 lib/librte_eal/arm/include/meson.build        |   1 +
 .../arm/include/rte_power_intrinsics.h        |  60 ++++
 lib/librte_eal/arm/rte_cpuflags.c             |   6 +
 lib/librte_eal/include/generic/rte_cpuflags.h |  26 ++
 .../include/generic/rte_power_intrinsics.h    | 123 +++++++
 lib/librte_eal/include/meson.build            |   1 +
 lib/librte_eal/ppc/include/meson.build        |   1 +
 .../ppc/include/rte_power_intrinsics.h        |  60 ++++
 lib/librte_eal/ppc/rte_cpuflags.c             |   7 +
 lib/librte_eal/version.map                    |   1 +
 lib/librte_eal/x86/include/meson.build        |   1 +
 lib/librte_eal/x86/include/rte_cpuflags.h     |   1 +
 .../x86/include/rte_power_intrinsics.h        | 135 ++++++++
 lib/librte_eal/x86/rte_cpuflags.c             |  14 +
 lib/librte_ethdev/rte_ethdev.c                |  23 ++
 lib/librte_ethdev/rte_ethdev.h                |  28 ++
 lib/librte_ethdev/rte_ethdev_driver.h         |  28 ++
 lib/librte_ethdev/version.map                 |   1 +
 lib/librte_power/meson.build                  |   5 +-
 lib/librte_power/rte_power_pmd_mgmt.c         | 320 ++++++++++++++++++
 lib/librte_power/rte_power_pmd_mgmt.h         |  92 +++++
 lib/librte_power/version.map                  |   4 +
 35 files changed, 1138 insertions(+), 3 deletions(-)
 create mode 100644 lib/librte_eal/arm/include/rte_power_intrinsics.h
 create mode 100644 lib/librte_eal/include/generic/rte_power_intrinsics.h
 create mode 100644 lib/librte_eal/ppc/include/rte_power_intrinsics.h
 create mode 100644 lib/librte_eal/x86/include/rte_power_intrinsics.h
 create mode 100644 lib/librte_power/rte_power_pmd_mgmt.c
 create mode 100644 lib/librte_power/rte_power_pmd_mgmt.h
Signature · 1 line
2.17.1
#346 lore raw

PATCH v9 1/10 eal: add new x86 cpuid support for WAITPKG

Add a new CPUID flag indicating processor support for UMONITOR/UMWAIT and TPAUSE instructions instruction.

---
 lib/librte_eal/x86/include/rte_cpuflags.h | 1 +
 lib/librte_eal/x86/rte_cpuflags.c         | 2 ++
 2 files changed, 3 insertions(+)
lib/librte_eal/x86/include/rte_cpuflags.h +1 -0
index c1d20364d1..848ba9cbfb 100644
@@ -132,6 +132,7 @@ enum rte_cpu_flag_t {
 	RTE_CPUFLAG_MOVDIR64B,              /**< Direct Store Instructions 64B */
 	RTE_CPUFLAG_AVX512VP2INTERSECT,     /**< AVX512 Two Register Intersection */
 
+	RTE_CPUFLAG_WAITPKG,                /**< UMONITOR/UMWAIT/TPAUSE */
 	/* The last item */
 	RTE_CPUFLAG_NUMFLAGS,               /**< This should always be the last! */
 };
lib/librte_eal/x86/rte_cpuflags.c +2 -0
index 30439e7951..0325c4b93b 100644
@@ -110,6 +110,8 @@ const struct feature_entry rte_cpu_feature_table[] = {
 	FEAT_DEF(AVX512F, 0x00000007, 0, RTE_REG_EBX, 16)
 	FEAT_DEF(RDSEED, 0x00000007, 0, RTE_REG_EBX, 18)
 
+	FEAT_DEF(WAITPKG, 0x00000007, 0, RTE_REG_ECX, 5)
+
 	FEAT_DEF(LAHF_SAHF, 0x80000001, 0, RTE_REG_ECX,  0)
 	FEAT_DEF(LZCNT, 0x80000001, 0, RTE_REG_ECX,  4)
 
Signature · 1 line
2.17.1
#347 lore raw

PATCH v9 2/10 eal: add power management intrinsics

In reply to Liang Ma

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

For more details, please refer to Intel(R) 64 and IA-32 Architectures Software Developer's Manual, Volume 2.

---
 lib/librte_eal/arm/include/meson.build        |   1 +
 .../arm/include/rte_power_intrinsics.h        |  60 ++++++++
 .../include/generic/rte_power_intrinsics.h    | 111 ++++++++++++++
 lib/librte_eal/include/meson.build            |   1 +
 lib/librte_eal/ppc/include/meson.build        |   1 +
 .../ppc/include/rte_power_intrinsics.h        |  60 ++++++++
 lib/librte_eal/x86/include/meson.build        |   1 +
 .../x86/include/rte_power_intrinsics.h        | 135 ++++++++++++++++++
 8 files changed, 370 insertions(+)
 create mode 100644 lib/librte_eal/arm/include/rte_power_intrinsics.h
 create mode 100644 lib/librte_eal/include/generic/rte_power_intrinsics.h
 create mode 100644 lib/librte_eal/ppc/include/rte_power_intrinsics.h
 create mode 100644 lib/librte_eal/x86/include/rte_power_intrinsics.h
lib/librte_eal/arm/include/meson.build +1 -0
index 73b750a18f..c6a9f70d73 100644
@@ -20,6 +20,7 @@ arch_headers = files(
 	'rte_pause_32.h',
 	'rte_pause_64.h',
 	'rte_pause.h',
+	'rte_power_intrinsics.h',
 	'rte_prefetch_32.h',
 	'rte_prefetch_64.h',
 	'rte_prefetch.h',
lib/librte_eal/arm/include/rte_power_intrinsics.h new file +60 -0

60 lines not on this page · raw message

lib/librte_eal/include/generic/rte_power_intrinsics.h new file +111 -0

111 lines not on this page · raw message

lib/librte_eal/include/meson.build +1 -0
index cd09027958..3a12e87e19 100644
@@ -60,6 +60,7 @@ generic_headers = files(
 	'generic/rte_memcpy.h',
 	'generic/rte_pause.h',
 	'generic/rte_prefetch.h',
+	'generic/rte_power_intrinsics.h',
 	'generic/rte_rwlock.h',
 	'generic/rte_spinlock.h',
 	'generic/rte_ticketlock.h',
lib/librte_eal/ppc/include/meson.build +1 -0
index ab4bd28092..0873b2aecb 100644
@@ -10,6 +10,7 @@ arch_headers = files(
 	'rte_io.h',
 	'rte_memcpy.h',
 	'rte_pause.h',
+	'rte_power_intrinsics.h',
 	'rte_prefetch.h',
 	'rte_rwlock.h',
 	'rte_spinlock.h',
lib/librte_eal/ppc/include/rte_power_intrinsics.h new file +60 -0

60 lines not on this page · raw message

lib/librte_eal/x86/include/meson.build +1 -0
index f0e998c2fe..494a8142a2 100644
@@ -13,6 +13,7 @@ arch_headers = files(
 	'rte_io.h',
 	'rte_memcpy.h',
 	'rte_prefetch.h',
+	'rte_power_intrinsics.h',
 	'rte_pause.h',
 	'rte_rtm.h',
 	'rte_rwlock.h',
lib/librte_eal/x86/include/rte_power_intrinsics.h new file +135 -0

135 lines not on this page · raw message

Signature · 1 line
2.17.1
#348 lore raw

PATCH v9 3/10 eal: add intrinsics support check infrastructure

In reply to Liang Ma

Currently, it is not possible to check support for intrinsics that are platform-specific, cannot be abstracted in a generic way, or do not have support on all architectures. The CPUID flags can be used to some extent, but they are only defined for their platform, while intrinsics will be available to all code as they are in generic headers.

This patch introduces infrastructure to check support for certain platform-specific intrinsics, and adds support for checking support for IA power management-related intrinsics for UMWAIT/UMONITOR and TPAUSE.

---

Notes:
v6:
- Fix the comments
v8:
- Rename eal version.map

---
 lib/librte_eal/arm/rte_cpuflags.c             |  6 +++++
 lib/librte_eal/include/generic/rte_cpuflags.h | 26 +++++++++++++++++++
 .../include/generic/rte_power_intrinsics.h    | 12 +++++++++
 lib/librte_eal/ppc/rte_cpuflags.c             |  7 +++++
 lib/librte_eal/version.map                    |  1 +
 lib/librte_eal/x86/rte_cpuflags.c             | 12 +++++++++
 6 files changed, 64 insertions(+)
lib/librte_eal/arm/rte_cpuflags.c +6 -0
index 7b257b7873..e3a53bcece 100644
@@ -151,3 +151,9 @@ rte_cpu_get_flag_name(enum rte_cpu_flag_t feature)
 		return NULL;
 	return rte_cpu_feature_table[feature].name;
 }
+
+void
+rte_cpu_get_intrinsics_support(struct rte_cpu_intrinsics *intrinsics)
+{
+	memset(intrinsics, 0, sizeof(*intrinsics));
+}
lib/librte_eal/include/generic/rte_cpuflags.h +26 -0
index 872f0ebe3e..28a5aecde8 100644
@@ -13,6 +13,32 @@
 #include "rte_common.h"
 #include <errno.h>
 
+#include <rte_compat.h>
+
+/**
+ * Structure used to describe platform-specific intrinsics that may or may not
+ * be supported at runtime.
+ */
+struct rte_cpu_intrinsics {
+	uint32_t power_monitor : 1;
+	/**< indicates support for rte_power_monitor function */
+	uint32_t power_pause : 1;
+	/**< indicates support for rte_power_pause function */
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Check CPU support for various intrinsics at runtime.
+ *
+ * @param intrinsics
+ *     Pointer to a structure to be filled.
+ */
+__rte_experimental
+void
+rte_cpu_get_intrinsics_support(struct rte_cpu_intrinsics *intrinsics);
+
 /**
  * Enumeration of all CPU features supported
  */
lib/librte_eal/include/generic/rte_power_intrinsics.h +12 -0
index fb897d9060..03a326f076 100644
@@ -32,6 +32,10 @@
  * checked against the expected value, and if they match, the entering of
  * optimized power state may be aborted.
  *
+ * @warning It is responsibility of the user to check if this function is
+ *   supported at runtime using `rte_cpu_get_features()` API call. Failing to do
+ *   so may result in an illegal CPU instruction error.
+ *
  * @param p
  *   Address to monitor for changes.
  * @param expected_value
@@ -69,6 +73,10 @@ static inline void rte_power_monitor(const volatile void *p,
  * This call will also lock a spinlock on entering sleep, and release it on
  * waking up the CPU.
  *
+ * @warning It is responsibility of the user to check if this function is
+ *   supported at runtime using `rte_cpu_get_features()` API call. Failing to do
+ *   so may result in an illegal CPU instruction error.
+ *
  * @param p
  *   Address to monitor for changes.
  * @param expected_value
@@ -101,6 +109,10 @@ static inline void rte_power_monitor_sync(const volatile void *p,
  * Enter an architecture-defined optimized power state until a certain TSC
  * timestamp is reached.
  *
+ * @warning It is responsibility of the user to check if this function is
+ *   supported at runtime using `rte_cpu_get_features()` API call. Failing to do
+ *   so may result in an illegal CPU instruction error.
+ *
  * @param tsc_timestamp
  *   Maximum TSC timestamp to wait for. Note that the wait behavior is
  *   architecture-dependent.
lib/librte_eal/ppc/rte_cpuflags.c +7 -0
index 3bb7563ce9..61db5c216d 100644
@@ -8,6 +8,7 @@
 #include <elf.h>
 #include <fcntl.h>
 #include <assert.h>
+#include <string.h>
 #include <unistd.h>
 
 /* Symbolic values for the entries in the auxiliary table */
@@ -108,3 +109,9 @@ rte_cpu_get_flag_name(enum rte_cpu_flag_t feature)
 		return NULL;
 	return rte_cpu_feature_table[feature].name;
 }
+
+void
+rte_cpu_get_intrinsics_support(struct rte_cpu_intrinsics *intrinsics)
+{
+	memset(intrinsics, 0, sizeof(*intrinsics));
+}
lib/librte_eal/version.map +1 -0
index c23ff57ce6..269cdccfd3 100644
@@ -402,6 +402,7 @@ EXPERIMENTAL {
 	rte_service_lcore_may_be_active;
 	rte_vect_get_max_simd_bitwidth;
 	rte_vect_set_max_simd_bitwidth;
+	rte_cpu_get_intrinsics_support;
 };
 
 INTERNAL {
lib/librte_eal/x86/rte_cpuflags.c +12 -0
index 0325c4b93b..a96312ff7f 100644
@@ -7,6 +7,7 @@
 #include <stdio.h>
 #include <errno.h>
 #include <stdint.h>
+#include <string.h>
 
 #include "rte_cpuid.h"
 
@@ -179,3 +180,14 @@ rte_cpu_get_flag_name(enum rte_cpu_flag_t feature)
 		return NULL;
 	return rte_cpu_feature_table[feature].name;
 }
+
+void
+rte_cpu_get_intrinsics_support(struct rte_cpu_intrinsics *intrinsics)
+{
+	memset(intrinsics, 0, sizeof(*intrinsics));
+
+	if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_WAITPKG)) {
+		intrinsics->power_monitor = 1;
+		intrinsics->power_pause = 1;
+	}
+}
Signature · 1 line
2.17.1