ice: reduce initial wait for control queue messages
authorJacob Keller <jacob.e.keller@intel.com>
Tue, 13 Jun 2023 20:40:53 +0000 (13:40 -0700)
committerTony Nguyen <anthony.l.nguyen@intel.com>
Thu, 22 Jun 2023 17:23:44 +0000 (10:23 -0700)
The ice_sq_send_cmd() function is used to send messages to the control
queues used to communicate with firmware, virtual functions, and even some
hardware.

When sending a control queue message, the driver is designed to
synchronously wait for a response from the queue. Currently it waits
between checks for 100 to 150 microseconds.

Commit f86d6f9c49f6 ("ice: sleep, don't busy-wait, for
ICE_CTL_Q_SQ_CMD_TIMEOUT") did recently change the behavior from an
unnecessary delay into a sleep which is a significant improvement over the
old behavior of polling using udelay.

Because of the nature of PCIe transactions, the hardware won't be informed
about a new message until the write to the tail register posts. This is
only guaranteed to occur at the next register read. In ice_sq_send_cmd(),
this happens at the ice_sq_done() call. Because of this, the driver
essentially forces a minimum of one full wait time regardless of how fast
the response is.

For the hardware-based sideband queue, this is especially slow. It is
expected that the hardware will respond within 2 or 3 microseconds, an
order of magnitude faster than the 100-150 microsecond sleep.

Allow such fast completions to occur without delay by introducing a small 5
microsecond delay first before entering the sleeping timeout loop. Ensure
the tail write has been posted by using ice_flush(hw) first.

While at it, lets also remove the ICE_CTL_Q_SQ_CMD_USEC macro as it
obscures the sleep time in the inner loop. It was likely introduced to
avoid "magic numbers", but in practice sleep and delay values are easier to
read and understand when using actual numbers instead of a named constant.

This change should allow the fast hardware based control queue messages to
complete quickly without delay, while slower firmware queue response times
will sleep while waiting for the response.

Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
Reviewed-by: Michal Schmidt <mschmidt@redhat.com>
Tested-by: Pucha Himasekhar Reddy <himasekharx.reddy.pucha@intel.com> (A Contingent worker at Intel)
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
drivers/net/ethernet/intel/ice/ice_controlq.c
drivers/net/ethernet/intel/ice/ice_controlq.h

index d2faf1baad2f9d14b4d01a30fff2d8fc11a09775..385fd88831dbdb7f778c9b8e3f4b200be0314666 100644 (file)
@@ -1056,14 +1056,19 @@ ice_sq_send_cmd(struct ice_hw *hw, struct ice_ctl_q_info *cq,
        if (cq->sq.next_to_use == cq->sq.count)
                cq->sq.next_to_use = 0;
        wr32(hw, cq->sq.tail, cq->sq.next_to_use);
+       ice_flush(hw);
+
+       /* Wait a short time before initial ice_sq_done() check, to allow
+        * hardware time for completion.
+        */
+       udelay(5);
 
        timeout = jiffies + ICE_CTL_Q_SQ_CMD_TIMEOUT;
        do {
                if (ice_sq_done(hw, cq))
                        break;
 
-               usleep_range(ICE_CTL_Q_SQ_CMD_USEC,
-                            ICE_CTL_Q_SQ_CMD_USEC * 3 / 2);
+               usleep_range(100, 150);
        } while (time_before(jiffies, timeout));
 
        /* if ready, copy the desc back to temp */
index 950b7f4a7a053df7f6a098efd8c8790bb3625c28..8f2fd1613a952d22e1bf488cd455febcf0621292 100644 (file)
@@ -35,7 +35,6 @@ enum ice_ctl_q {
 
 /* Control Queue timeout settings - max delay 1s */
 #define ICE_CTL_Q_SQ_CMD_TIMEOUT       HZ    /* Wait max 1s */
-#define ICE_CTL_Q_SQ_CMD_USEC          100   /* Check every 100usec */
 #define ICE_CTL_Q_ADMIN_INIT_TIMEOUT   10    /* Count 10 times */
 #define ICE_CTL_Q_ADMIN_INIT_MSEC      100   /* Check every 100msec */