1*b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 2511cbce2SChristoph Hellwig /* 3511cbce2SChristoph Hellwig * Functions related to interrupt-poll handling in the block layer. This 4511cbce2SChristoph Hellwig * is similar to NAPI for network devices. 5511cbce2SChristoph Hellwig */ 6511cbce2SChristoph Hellwig #include <linux/kernel.h> 7511cbce2SChristoph Hellwig #include <linux/module.h> 8511cbce2SChristoph Hellwig #include <linux/init.h> 9511cbce2SChristoph Hellwig #include <linux/bio.h> 10511cbce2SChristoph Hellwig #include <linux/interrupt.h> 11511cbce2SChristoph Hellwig #include <linux/cpu.h> 12511cbce2SChristoph Hellwig #include <linux/irq_poll.h> 13511cbce2SChristoph Hellwig #include <linux/delay.h> 14511cbce2SChristoph Hellwig 15511cbce2SChristoph Hellwig static unsigned int irq_poll_budget __read_mostly = 256; 16511cbce2SChristoph Hellwig 17511cbce2SChristoph Hellwig static DEFINE_PER_CPU(struct list_head, blk_cpu_iopoll); 18511cbce2SChristoph Hellwig 19511cbce2SChristoph Hellwig /** 20511cbce2SChristoph Hellwig * irq_poll_sched - Schedule a run of the iopoll handler 21511cbce2SChristoph Hellwig * @iop: The parent iopoll structure 22511cbce2SChristoph Hellwig * 23511cbce2SChristoph Hellwig * Description: 24511cbce2SChristoph Hellwig * Add this irq_poll structure to the pending poll list and trigger the 25ea51190cSChristoph Hellwig * raise of the blk iopoll softirq. 26511cbce2SChristoph Hellwig **/ 27511cbce2SChristoph Hellwig void irq_poll_sched(struct irq_poll *iop) 28511cbce2SChristoph Hellwig { 29511cbce2SChristoph Hellwig unsigned long flags; 30511cbce2SChristoph Hellwig 31ea51190cSChristoph Hellwig if (test_bit(IRQ_POLL_F_DISABLE, &iop->state)) 32ea51190cSChristoph Hellwig return; 332ee177e9SBart Van Assche if (test_and_set_bit(IRQ_POLL_F_SCHED, &iop->state)) 34ea51190cSChristoph Hellwig return; 35ea51190cSChristoph Hellwig 36511cbce2SChristoph Hellwig local_irq_save(flags); 37511cbce2SChristoph Hellwig list_add_tail(&iop->list, this_cpu_ptr(&blk_cpu_iopoll)); 38511cbce2SChristoph Hellwig __raise_softirq_irqoff(IRQ_POLL_SOFTIRQ); 39511cbce2SChristoph Hellwig local_irq_restore(flags); 40511cbce2SChristoph Hellwig } 41511cbce2SChristoph Hellwig EXPORT_SYMBOL(irq_poll_sched); 42511cbce2SChristoph Hellwig 43511cbce2SChristoph Hellwig /** 44511cbce2SChristoph Hellwig * __irq_poll_complete - Mark this @iop as un-polled again 45511cbce2SChristoph Hellwig * @iop: The parent iopoll structure 46511cbce2SChristoph Hellwig * 47511cbce2SChristoph Hellwig * Description: 48511cbce2SChristoph Hellwig * See irq_poll_complete(). This function must be called with interrupts 49511cbce2SChristoph Hellwig * disabled. 50511cbce2SChristoph Hellwig **/ 5183af187dSChristoph Hellwig static void __irq_poll_complete(struct irq_poll *iop) 52511cbce2SChristoph Hellwig { 53511cbce2SChristoph Hellwig list_del(&iop->list); 54511cbce2SChristoph Hellwig smp_mb__before_atomic(); 55511cbce2SChristoph Hellwig clear_bit_unlock(IRQ_POLL_F_SCHED, &iop->state); 56511cbce2SChristoph Hellwig } 57511cbce2SChristoph Hellwig 58511cbce2SChristoph Hellwig /** 59511cbce2SChristoph Hellwig * irq_poll_complete - Mark this @iop as un-polled again 60511cbce2SChristoph Hellwig * @iop: The parent iopoll structure 61511cbce2SChristoph Hellwig * 62511cbce2SChristoph Hellwig * Description: 63511cbce2SChristoph Hellwig * If a driver consumes less than the assigned budget in its run of the 64511cbce2SChristoph Hellwig * iopoll handler, it'll end the polled mode by calling this function. The 65ea51190cSChristoph Hellwig * iopoll handler will not be invoked again before irq_poll_sched() 66511cbce2SChristoph Hellwig * is called. 67511cbce2SChristoph Hellwig **/ 68511cbce2SChristoph Hellwig void irq_poll_complete(struct irq_poll *iop) 69511cbce2SChristoph Hellwig { 70511cbce2SChristoph Hellwig unsigned long flags; 71511cbce2SChristoph Hellwig 72511cbce2SChristoph Hellwig local_irq_save(flags); 73511cbce2SChristoph Hellwig __irq_poll_complete(iop); 74511cbce2SChristoph Hellwig local_irq_restore(flags); 75511cbce2SChristoph Hellwig } 76511cbce2SChristoph Hellwig EXPORT_SYMBOL(irq_poll_complete); 77511cbce2SChristoph Hellwig 780766f788SEmese Revfy static void __latent_entropy irq_poll_softirq(struct softirq_action *h) 79511cbce2SChristoph Hellwig { 80511cbce2SChristoph Hellwig struct list_head *list = this_cpu_ptr(&blk_cpu_iopoll); 81511cbce2SChristoph Hellwig int rearm = 0, budget = irq_poll_budget; 82511cbce2SChristoph Hellwig unsigned long start_time = jiffies; 83511cbce2SChristoph Hellwig 84511cbce2SChristoph Hellwig local_irq_disable(); 85511cbce2SChristoph Hellwig 86511cbce2SChristoph Hellwig while (!list_empty(list)) { 87511cbce2SChristoph Hellwig struct irq_poll *iop; 88511cbce2SChristoph Hellwig int work, weight; 89511cbce2SChristoph Hellwig 90511cbce2SChristoph Hellwig /* 91511cbce2SChristoph Hellwig * If softirq window is exhausted then punt. 92511cbce2SChristoph Hellwig */ 93511cbce2SChristoph Hellwig if (budget <= 0 || time_after(jiffies, start_time)) { 94511cbce2SChristoph Hellwig rearm = 1; 95511cbce2SChristoph Hellwig break; 96511cbce2SChristoph Hellwig } 97511cbce2SChristoph Hellwig 98511cbce2SChristoph Hellwig local_irq_enable(); 99511cbce2SChristoph Hellwig 100511cbce2SChristoph Hellwig /* Even though interrupts have been re-enabled, this 101511cbce2SChristoph Hellwig * access is safe because interrupts can only add new 102511cbce2SChristoph Hellwig * entries to the tail of this list, and only ->poll() 103511cbce2SChristoph Hellwig * calls can remove this head entry from the list. 104511cbce2SChristoph Hellwig */ 105511cbce2SChristoph Hellwig iop = list_entry(list->next, struct irq_poll, list); 106511cbce2SChristoph Hellwig 107511cbce2SChristoph Hellwig weight = iop->weight; 108511cbce2SChristoph Hellwig work = 0; 109511cbce2SChristoph Hellwig if (test_bit(IRQ_POLL_F_SCHED, &iop->state)) 110511cbce2SChristoph Hellwig work = iop->poll(iop, weight); 111511cbce2SChristoph Hellwig 112511cbce2SChristoph Hellwig budget -= work; 113511cbce2SChristoph Hellwig 114511cbce2SChristoph Hellwig local_irq_disable(); 115511cbce2SChristoph Hellwig 116511cbce2SChristoph Hellwig /* 117511cbce2SChristoph Hellwig * Drivers must not modify the iopoll state, if they 118511cbce2SChristoph Hellwig * consume their assigned weight (or more, some drivers can't 119511cbce2SChristoph Hellwig * easily just stop processing, they have to complete an 120511cbce2SChristoph Hellwig * entire mask of commands).In such cases this code 121511cbce2SChristoph Hellwig * still "owns" the iopoll instance and therefore can 122511cbce2SChristoph Hellwig * move the instance around on the list at-will. 123511cbce2SChristoph Hellwig */ 124511cbce2SChristoph Hellwig if (work >= weight) { 1250bc92aceSChristoph Hellwig if (test_bit(IRQ_POLL_F_DISABLE, &iop->state)) 126511cbce2SChristoph Hellwig __irq_poll_complete(iop); 127511cbce2SChristoph Hellwig else 128511cbce2SChristoph Hellwig list_move_tail(&iop->list, list); 129511cbce2SChristoph Hellwig } 130511cbce2SChristoph Hellwig } 131511cbce2SChristoph Hellwig 132511cbce2SChristoph Hellwig if (rearm) 133511cbce2SChristoph Hellwig __raise_softirq_irqoff(IRQ_POLL_SOFTIRQ); 134511cbce2SChristoph Hellwig 135511cbce2SChristoph Hellwig local_irq_enable(); 136511cbce2SChristoph Hellwig } 137511cbce2SChristoph Hellwig 138511cbce2SChristoph Hellwig /** 139511cbce2SChristoph Hellwig * irq_poll_disable - Disable iopoll on this @iop 140511cbce2SChristoph Hellwig * @iop: The parent iopoll structure 141511cbce2SChristoph Hellwig * 142511cbce2SChristoph Hellwig * Description: 143511cbce2SChristoph Hellwig * Disable io polling and wait for any pending callbacks to have completed. 144511cbce2SChristoph Hellwig **/ 145511cbce2SChristoph Hellwig void irq_poll_disable(struct irq_poll *iop) 146511cbce2SChristoph Hellwig { 147511cbce2SChristoph Hellwig set_bit(IRQ_POLL_F_DISABLE, &iop->state); 148511cbce2SChristoph Hellwig while (test_and_set_bit(IRQ_POLL_F_SCHED, &iop->state)) 149511cbce2SChristoph Hellwig msleep(1); 150511cbce2SChristoph Hellwig clear_bit(IRQ_POLL_F_DISABLE, &iop->state); 151511cbce2SChristoph Hellwig } 152511cbce2SChristoph Hellwig EXPORT_SYMBOL(irq_poll_disable); 153511cbce2SChristoph Hellwig 154511cbce2SChristoph Hellwig /** 155511cbce2SChristoph Hellwig * irq_poll_enable - Enable iopoll on this @iop 156511cbce2SChristoph Hellwig * @iop: The parent iopoll structure 157511cbce2SChristoph Hellwig * 158511cbce2SChristoph Hellwig * Description: 159511cbce2SChristoph Hellwig * Enable iopoll on this @iop. Note that the handler run will not be 160511cbce2SChristoph Hellwig * scheduled, it will only mark it as active. 161511cbce2SChristoph Hellwig **/ 162511cbce2SChristoph Hellwig void irq_poll_enable(struct irq_poll *iop) 163511cbce2SChristoph Hellwig { 164511cbce2SChristoph Hellwig BUG_ON(!test_bit(IRQ_POLL_F_SCHED, &iop->state)); 165511cbce2SChristoph Hellwig smp_mb__before_atomic(); 166511cbce2SChristoph Hellwig clear_bit_unlock(IRQ_POLL_F_SCHED, &iop->state); 167511cbce2SChristoph Hellwig } 168511cbce2SChristoph Hellwig EXPORT_SYMBOL(irq_poll_enable); 169511cbce2SChristoph Hellwig 170511cbce2SChristoph Hellwig /** 171511cbce2SChristoph Hellwig * irq_poll_init - Initialize this @iop 172511cbce2SChristoph Hellwig * @iop: The parent iopoll structure 173511cbce2SChristoph Hellwig * @weight: The default weight (or command completion budget) 174511cbce2SChristoph Hellwig * @poll_fn: The handler to invoke 175511cbce2SChristoph Hellwig * 176511cbce2SChristoph Hellwig * Description: 17778d0264eSChristoph Hellwig * Initialize and enable this irq_poll structure. 178511cbce2SChristoph Hellwig **/ 179511cbce2SChristoph Hellwig void irq_poll_init(struct irq_poll *iop, int weight, irq_poll_fn *poll_fn) 180511cbce2SChristoph Hellwig { 181511cbce2SChristoph Hellwig memset(iop, 0, sizeof(*iop)); 182511cbce2SChristoph Hellwig INIT_LIST_HEAD(&iop->list); 183511cbce2SChristoph Hellwig iop->weight = weight; 184511cbce2SChristoph Hellwig iop->poll = poll_fn; 185511cbce2SChristoph Hellwig } 186511cbce2SChristoph Hellwig EXPORT_SYMBOL(irq_poll_init); 187511cbce2SChristoph Hellwig 18875e12ed6SSebastian Andrzej Siewior static int irq_poll_cpu_dead(unsigned int cpu) 189511cbce2SChristoph Hellwig { 190511cbce2SChristoph Hellwig /* 191511cbce2SChristoph Hellwig * If a CPU goes away, splice its entries to the current CPU 192511cbce2SChristoph Hellwig * and trigger a run of the softirq 193511cbce2SChristoph Hellwig */ 194511cbce2SChristoph Hellwig local_irq_disable(); 195511cbce2SChristoph Hellwig list_splice_init(&per_cpu(blk_cpu_iopoll, cpu), 196511cbce2SChristoph Hellwig this_cpu_ptr(&blk_cpu_iopoll)); 197511cbce2SChristoph Hellwig __raise_softirq_irqoff(IRQ_POLL_SOFTIRQ); 198511cbce2SChristoph Hellwig local_irq_enable(); 199511cbce2SChristoph Hellwig 20075e12ed6SSebastian Andrzej Siewior return 0; 201511cbce2SChristoph Hellwig } 202511cbce2SChristoph Hellwig 203511cbce2SChristoph Hellwig static __init int irq_poll_setup(void) 204511cbce2SChristoph Hellwig { 205511cbce2SChristoph Hellwig int i; 206511cbce2SChristoph Hellwig 207511cbce2SChristoph Hellwig for_each_possible_cpu(i) 208511cbce2SChristoph Hellwig INIT_LIST_HEAD(&per_cpu(blk_cpu_iopoll, i)); 209511cbce2SChristoph Hellwig 210511cbce2SChristoph Hellwig open_softirq(IRQ_POLL_SOFTIRQ, irq_poll_softirq); 21175e12ed6SSebastian Andrzej Siewior cpuhp_setup_state_nocalls(CPUHP_IRQ_POLL_DEAD, "irq_poll:dead", NULL, 21275e12ed6SSebastian Andrzej Siewior irq_poll_cpu_dead); 213511cbce2SChristoph Hellwig return 0; 214511cbce2SChristoph Hellwig } 215511cbce2SChristoph Hellwig subsys_initcall(irq_poll_setup); 216