162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Functions related to interrupt-poll handling in the block layer. This
462306a36Sopenharmony_ci * is similar to NAPI for network devices.
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci#include <linux/kernel.h>
762306a36Sopenharmony_ci#include <linux/module.h>
862306a36Sopenharmony_ci#include <linux/init.h>
962306a36Sopenharmony_ci#include <linux/bio.h>
1062306a36Sopenharmony_ci#include <linux/interrupt.h>
1162306a36Sopenharmony_ci#include <linux/cpu.h>
1262306a36Sopenharmony_ci#include <linux/irq_poll.h>
1362306a36Sopenharmony_ci#include <linux/delay.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistatic unsigned int irq_poll_budget __read_mostly = 256;
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_cistatic DEFINE_PER_CPU(struct list_head, blk_cpu_iopoll);
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/**
2062306a36Sopenharmony_ci * irq_poll_sched - Schedule a run of the iopoll handler
2162306a36Sopenharmony_ci * @iop:      The parent iopoll structure
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci * Description:
2462306a36Sopenharmony_ci *     Add this irq_poll structure to the pending poll list and trigger the
2562306a36Sopenharmony_ci *     raise of the blk iopoll softirq.
2662306a36Sopenharmony_ci **/
2762306a36Sopenharmony_civoid irq_poll_sched(struct irq_poll *iop)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	unsigned long flags;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	if (test_bit(IRQ_POLL_F_DISABLE, &iop->state))
3262306a36Sopenharmony_ci		return;
3362306a36Sopenharmony_ci	if (test_and_set_bit(IRQ_POLL_F_SCHED, &iop->state))
3462306a36Sopenharmony_ci		return;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	local_irq_save(flags);
3762306a36Sopenharmony_ci	list_add_tail(&iop->list, this_cpu_ptr(&blk_cpu_iopoll));
3862306a36Sopenharmony_ci	raise_softirq_irqoff(IRQ_POLL_SOFTIRQ);
3962306a36Sopenharmony_ci	local_irq_restore(flags);
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ciEXPORT_SYMBOL(irq_poll_sched);
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci/**
4462306a36Sopenharmony_ci * __irq_poll_complete - Mark this @iop as un-polled again
4562306a36Sopenharmony_ci * @iop:      The parent iopoll structure
4662306a36Sopenharmony_ci *
4762306a36Sopenharmony_ci * Description:
4862306a36Sopenharmony_ci *     See irq_poll_complete(). This function must be called with interrupts
4962306a36Sopenharmony_ci *     disabled.
5062306a36Sopenharmony_ci **/
5162306a36Sopenharmony_cistatic void __irq_poll_complete(struct irq_poll *iop)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	list_del(&iop->list);
5462306a36Sopenharmony_ci	smp_mb__before_atomic();
5562306a36Sopenharmony_ci	clear_bit_unlock(IRQ_POLL_F_SCHED, &iop->state);
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci/**
5962306a36Sopenharmony_ci * irq_poll_complete - Mark this @iop as un-polled again
6062306a36Sopenharmony_ci * @iop:      The parent iopoll structure
6162306a36Sopenharmony_ci *
6262306a36Sopenharmony_ci * Description:
6362306a36Sopenharmony_ci *     If a driver consumes less than the assigned budget in its run of the
6462306a36Sopenharmony_ci *     iopoll handler, it'll end the polled mode by calling this function. The
6562306a36Sopenharmony_ci *     iopoll handler will not be invoked again before irq_poll_sched()
6662306a36Sopenharmony_ci *     is called.
6762306a36Sopenharmony_ci **/
6862306a36Sopenharmony_civoid irq_poll_complete(struct irq_poll *iop)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	unsigned long flags;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	local_irq_save(flags);
7362306a36Sopenharmony_ci	__irq_poll_complete(iop);
7462306a36Sopenharmony_ci	local_irq_restore(flags);
7562306a36Sopenharmony_ci}
7662306a36Sopenharmony_ciEXPORT_SYMBOL(irq_poll_complete);
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic void __latent_entropy irq_poll_softirq(struct softirq_action *h)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	struct list_head *list = this_cpu_ptr(&blk_cpu_iopoll);
8162306a36Sopenharmony_ci	int rearm = 0, budget = irq_poll_budget;
8262306a36Sopenharmony_ci	unsigned long start_time = jiffies;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	local_irq_disable();
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	while (!list_empty(list)) {
8762306a36Sopenharmony_ci		struct irq_poll *iop;
8862306a36Sopenharmony_ci		int work, weight;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci		/*
9162306a36Sopenharmony_ci		 * If softirq window is exhausted then punt.
9262306a36Sopenharmony_ci		 */
9362306a36Sopenharmony_ci		if (budget <= 0 || time_after(jiffies, start_time)) {
9462306a36Sopenharmony_ci			rearm = 1;
9562306a36Sopenharmony_ci			break;
9662306a36Sopenharmony_ci		}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci		local_irq_enable();
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci		/* Even though interrupts have been re-enabled, this
10162306a36Sopenharmony_ci		 * access is safe because interrupts can only add new
10262306a36Sopenharmony_ci		 * entries to the tail of this list, and only ->poll()
10362306a36Sopenharmony_ci		 * calls can remove this head entry from the list.
10462306a36Sopenharmony_ci		 */
10562306a36Sopenharmony_ci		iop = list_entry(list->next, struct irq_poll, list);
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci		weight = iop->weight;
10862306a36Sopenharmony_ci		work = 0;
10962306a36Sopenharmony_ci		if (test_bit(IRQ_POLL_F_SCHED, &iop->state))
11062306a36Sopenharmony_ci			work = iop->poll(iop, weight);
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci		budget -= work;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci		local_irq_disable();
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci		/*
11762306a36Sopenharmony_ci		 * Drivers must not modify the iopoll state, if they
11862306a36Sopenharmony_ci		 * consume their assigned weight (or more, some drivers can't
11962306a36Sopenharmony_ci		 * easily just stop processing, they have to complete an
12062306a36Sopenharmony_ci		 * entire mask of commands).In such cases this code
12162306a36Sopenharmony_ci		 * still "owns" the iopoll instance and therefore can
12262306a36Sopenharmony_ci		 * move the instance around on the list at-will.
12362306a36Sopenharmony_ci		 */
12462306a36Sopenharmony_ci		if (work >= weight) {
12562306a36Sopenharmony_ci			if (test_bit(IRQ_POLL_F_DISABLE, &iop->state))
12662306a36Sopenharmony_ci				__irq_poll_complete(iop);
12762306a36Sopenharmony_ci			else
12862306a36Sopenharmony_ci				list_move_tail(&iop->list, list);
12962306a36Sopenharmony_ci		}
13062306a36Sopenharmony_ci	}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	if (rearm)
13362306a36Sopenharmony_ci		__raise_softirq_irqoff(IRQ_POLL_SOFTIRQ);
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	local_irq_enable();
13662306a36Sopenharmony_ci}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci/**
13962306a36Sopenharmony_ci * irq_poll_disable - Disable iopoll on this @iop
14062306a36Sopenharmony_ci * @iop:      The parent iopoll structure
14162306a36Sopenharmony_ci *
14262306a36Sopenharmony_ci * Description:
14362306a36Sopenharmony_ci *     Disable io polling and wait for any pending callbacks to have completed.
14462306a36Sopenharmony_ci **/
14562306a36Sopenharmony_civoid irq_poll_disable(struct irq_poll *iop)
14662306a36Sopenharmony_ci{
14762306a36Sopenharmony_ci	set_bit(IRQ_POLL_F_DISABLE, &iop->state);
14862306a36Sopenharmony_ci	while (test_and_set_bit(IRQ_POLL_F_SCHED, &iop->state))
14962306a36Sopenharmony_ci		msleep(1);
15062306a36Sopenharmony_ci	clear_bit(IRQ_POLL_F_DISABLE, &iop->state);
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ciEXPORT_SYMBOL(irq_poll_disable);
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci/**
15562306a36Sopenharmony_ci * irq_poll_enable - Enable iopoll on this @iop
15662306a36Sopenharmony_ci * @iop:      The parent iopoll structure
15762306a36Sopenharmony_ci *
15862306a36Sopenharmony_ci * Description:
15962306a36Sopenharmony_ci *     Enable iopoll on this @iop. Note that the handler run will not be
16062306a36Sopenharmony_ci *     scheduled, it will only mark it as active.
16162306a36Sopenharmony_ci **/
16262306a36Sopenharmony_civoid irq_poll_enable(struct irq_poll *iop)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	BUG_ON(!test_bit(IRQ_POLL_F_SCHED, &iop->state));
16562306a36Sopenharmony_ci	smp_mb__before_atomic();
16662306a36Sopenharmony_ci	clear_bit_unlock(IRQ_POLL_F_SCHED, &iop->state);
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ciEXPORT_SYMBOL(irq_poll_enable);
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci/**
17162306a36Sopenharmony_ci * irq_poll_init - Initialize this @iop
17262306a36Sopenharmony_ci * @iop:      The parent iopoll structure
17362306a36Sopenharmony_ci * @weight:   The default weight (or command completion budget)
17462306a36Sopenharmony_ci * @poll_fn:  The handler to invoke
17562306a36Sopenharmony_ci *
17662306a36Sopenharmony_ci * Description:
17762306a36Sopenharmony_ci *     Initialize and enable this irq_poll structure.
17862306a36Sopenharmony_ci **/
17962306a36Sopenharmony_civoid irq_poll_init(struct irq_poll *iop, int weight, irq_poll_fn *poll_fn)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	memset(iop, 0, sizeof(*iop));
18262306a36Sopenharmony_ci	INIT_LIST_HEAD(&iop->list);
18362306a36Sopenharmony_ci	iop->weight = weight;
18462306a36Sopenharmony_ci	iop->poll = poll_fn;
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ciEXPORT_SYMBOL(irq_poll_init);
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_cistatic int irq_poll_cpu_dead(unsigned int cpu)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	/*
19162306a36Sopenharmony_ci	 * If a CPU goes away, splice its entries to the current CPU and
19262306a36Sopenharmony_ci	 * set the POLL softirq bit. The local_bh_disable()/enable() pair
19362306a36Sopenharmony_ci	 * ensures that it is handled. Otherwise the current CPU could
19462306a36Sopenharmony_ci	 * reach idle with the POLL softirq pending.
19562306a36Sopenharmony_ci	 */
19662306a36Sopenharmony_ci	local_bh_disable();
19762306a36Sopenharmony_ci	local_irq_disable();
19862306a36Sopenharmony_ci	list_splice_init(&per_cpu(blk_cpu_iopoll, cpu),
19962306a36Sopenharmony_ci			 this_cpu_ptr(&blk_cpu_iopoll));
20062306a36Sopenharmony_ci	__raise_softirq_irqoff(IRQ_POLL_SOFTIRQ);
20162306a36Sopenharmony_ci	local_irq_enable();
20262306a36Sopenharmony_ci	local_bh_enable();
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	return 0;
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_cistatic __init int irq_poll_setup(void)
20862306a36Sopenharmony_ci{
20962306a36Sopenharmony_ci	int i;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	for_each_possible_cpu(i)
21262306a36Sopenharmony_ci		INIT_LIST_HEAD(&per_cpu(blk_cpu_iopoll, i));
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	open_softirq(IRQ_POLL_SOFTIRQ, irq_poll_softirq);
21562306a36Sopenharmony_ci	cpuhp_setup_state_nocalls(CPUHP_IRQ_POLL_DEAD, "irq_poll:dead", NULL,
21662306a36Sopenharmony_ci				  irq_poll_cpu_dead);
21762306a36Sopenharmony_ci	return 0;
21862306a36Sopenharmony_ci}
21962306a36Sopenharmony_cisubsys_initcall(irq_poll_setup);
220