On 19/11/22 01:37, Bart Van Assche wrote: > Fix the following issues in ufshcd_poll(): > - If polling succeeds, return a positive value. > - Do not complete polling requests from interrupt context because the > block layer expects these requests to be completed from thread > context. From block/bio.c: > > If REQ_ALLOC_CACHE is set, the final put of the bio MUST be done > from process context, not hard/soft IRQ. > > Fixes: eaab9b573054 ("scsi: ufs: Implement polling support") > Signed-off-by: Bart Van Assche <bvanassche@xxxxxxx> Reviewed-by: Adrian Hunter <adrian.hunter@xxxxxxxxx> > --- > > Changes compared to v1: > - Made sure that polled requests are not completed from interrupt context. > > drivers/ufs/core/ufshcd.c | 28 ++++++++++++++++++++++++++-- > 1 file changed, 26 insertions(+), 2 deletions(-) > > diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c > index 768cb49d269c..b4bf3c3bef0c 100644 > --- a/drivers/ufs/core/ufshcd.c > +++ b/drivers/ufs/core/ufshcd.c > @@ -5344,6 +5344,26 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, > } > } > > +/* Any value that is not an existing queue number is fine for this constant. */ > +enum { > + UFSHCD_POLL_FROM_INTERRUPT_CONTEXT = -1 > +}; > + > +static void ufshcd_clear_polled(struct ufs_hba *hba, > + unsigned long *completed_reqs) > +{ > + int tag; > + > + for_each_set_bit(tag, completed_reqs, hba->nutrs) { > + struct scsi_cmnd *cmd = hba->lrb[tag].cmd; > + > + if (!cmd) > + continue; > + if (scsi_cmd_to_rq(cmd)->cmd_flags & REQ_POLLED) > + __clear_bit(tag, completed_reqs); > + } > +} > + > /* > * Returns > 0 if one or more commands have been completed or 0 if no > * requests have been completed. > @@ -5360,13 +5380,17 @@ static int ufshcd_poll(struct Scsi_Host *shost, unsigned int queue_num) > WARN_ONCE(completed_reqs & ~hba->outstanding_reqs, > "completed: %#lx; outstanding: %#lx\n", completed_reqs, > hba->outstanding_reqs); > + if (queue_num == UFSHCD_POLL_FROM_INTERRUPT_CONTEXT) { > + /* Do not complete polled requests from interrupt context. */ > + ufshcd_clear_polled(hba, &completed_reqs); > + } > hba->outstanding_reqs &= ~completed_reqs; > spin_unlock_irqrestore(&hba->outstanding_lock, flags); > > if (completed_reqs) > __ufshcd_transfer_req_compl(hba, completed_reqs); > > - return completed_reqs; > + return completed_reqs != 0; > } > > /** > @@ -5397,7 +5421,7 @@ static irqreturn_t ufshcd_transfer_req_compl(struct ufs_hba *hba) > * Ignore the ufshcd_poll() return value and return IRQ_HANDLED since we > * do not want polling to trigger spurious interrupt complaints. > */ > - ufshcd_poll(hba->host, 0); > + ufshcd_poll(hba->host, UFSHCD_POLL_FROM_INTERRUPT_CONTEXT); > > return IRQ_HANDLED; > }