On Sun, 2016-10-09 at 18:25 +0300, Yuval Mintz wrote: > From: Yuval Mintz <yuval.mi...@caviumnetworks.com> > > Whenever a ramrod is being sent for some device configuration, > the driver is going to sleep at least 5ms between each iteration > of polling on the completion of the ramrod. > > However, in almost every configuration scenario the firmware > would be able to comply and complete the ramrod in a manner of > several usecs. This is especially important in cases where there > might be a lot of sequential configurations applying to the hardware > [e.g., RoCE], in which case the existing scheme might cause some > visible user delays. > > This patch changes the completion scheme - instead of immediately > starting to sleep for a 'long' period, allow the device to quickly > poll on the first iteration after a couple of usecs. > > Signed-off-by: Yuval Mintz <yuval.mi...@caviumnetworks.com> > --- > drivers/net/ethernet/qlogic/qed/qed_spq.c | 85 > +++++++++++++++++++++---------- > 1 file changed, 59 insertions(+), 26 deletions(-) > > diff --git a/drivers/net/ethernet/qlogic/qed/qed_spq.c > b/drivers/net/ethernet/qlogic/qed/qed_spq.c > index caff415..259a615 100644 > --- a/drivers/net/ethernet/qlogic/qed/qed_spq.c > +++ b/drivers/net/ethernet/qlogic/qed/qed_spq.c > @@ -37,7 +37,11 @@ > ***************************************************************************/ > > #define SPQ_HIGH_PRI_RESERVE_DEFAULT (1) > -#define SPQ_BLOCK_SLEEP_LENGTH (1000) > + > +#define SPQ_BLOCK_DELAY_MAX_ITER (10) > +#define SPQ_BLOCK_DELAY_US (10) > +#define SPQ_BLOCK_SLEEP_MAX_ITER (1000) > +#define SPQ_BLOCK_SLEEP_MS (5) > > /*************************************************************************** > * Blocking Imp. (BLOCK/EBLOCK mode) > @@ -57,53 +61,81 @@ static void qed_spq_blocking_cb(struct qed_hwfn *p_hwfn, > smp_wmb(); > } > > -static int qed_spq_block(struct qed_hwfn *p_hwfn, > - struct qed_spq_entry *p_ent, > - u8 *p_fw_ret) > +static int __qed_spq_block(struct qed_hwfn *p_hwfn, > + struct qed_spq_entry *p_ent, > + u8 *p_fw_ret, bool sleep_between_iter) > { > - int sleep_count = SPQ_BLOCK_SLEEP_LENGTH; > struct qed_spq_comp_done *comp_done; > - int rc; > + u32 iter_cnt; > > comp_done = (struct qed_spq_comp_done *)p_ent->comp_cb.cookie; > - while (sleep_count) { > - /* validate we receive completion update */ > + iter_cnt = sleep_between_iter ? SPQ_BLOCK_SLEEP_MAX_ITER > + : SPQ_BLOCK_DELAY_MAX_ITER; > + > + while (iter_cnt--) { > + /* Validate we receive completion update */ > smp_rmb(); > if (comp_done->done == 1) { > if (p_fw_ret) > *p_fw_ret = comp_done->fw_return_code; > return 0; > }
Note that this smp_rmb() and accesses to ->done and ->fw_return_code are racy. fq_return_code needs to be written _before_ done. Something like the following patch would make sense... diff --git a/drivers/net/ethernet/qlogic/qed/qed_spq.c b/drivers/net/ethernet/qlogic/qed/qed_spq.c index caff41544898baed09f45a41829cb0ba9c719fb9..eefa45eab3728791f4d15a088c4550f318a1d1da 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_spq.c +++ b/drivers/net/ethernet/qlogic/qed/qed_spq.c @@ -50,11 +50,9 @@ static void qed_spq_blocking_cb(struct qed_hwfn *p_hwfn, comp_done = (struct qed_spq_comp_done *)cookie; - comp_done->done = 0x1; - comp_done->fw_return_code = fw_return_code; + comp_done->fw_return_code = fw_return_code; - /* make update visible to waiting thread */ - smp_wmb(); + smp_store_release(&comp_done->done, 0x1); } static int qed_spq_block(struct qed_hwfn *p_hwfn, @@ -68,8 +66,8 @@ static int qed_spq_block(struct qed_hwfn *p_hwfn, comp_done = (struct qed_spq_comp_done *)p_ent->comp_cb.cookie; while (sleep_count) { /* validate we receive completion update */ - smp_rmb(); - if (comp_done->done == 1) { + if (READ_ONCE(comp_done->done) == 1) { + smp_read_barrier_depends(); if (p_fw_ret) *p_fw_ret = comp_done->fw_return_code; return 0; @@ -87,8 +85,8 @@ static int qed_spq_block(struct qed_hwfn *p_hwfn, sleep_count = SPQ_BLOCK_SLEEP_LENGTH; while (sleep_count) { /* validate we receive completion update */ - smp_rmb(); - if (comp_done->done == 1) { + if (READ_ONCE(comp_done->done) == 1) { + smp_read_barrier_depends(); if (p_fw_ret) *p_fw_ret = comp_done->fw_return_code; return 0; @@ -97,7 +95,8 @@ static int qed_spq_block(struct qed_hwfn *p_hwfn, sleep_count--; } - if (comp_done->done == 1) { + if (READ_ONCE(comp_done->done) == 1) { + smp_read_barrier_depends(); if (p_fw_ret) *p_fw_ret = comp_done->fw_return_code; return 0;