File Index
Files and directories
Sign in
FILE

irq.c

File preview with syntax highlighting.

linux-6.19.14/arch/um/kernel/irq.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright (C) 2017 - Cambridge Greys Ltd
  4 * Copyright (C) 2011 - 2014 Cisco Systems Inc
  5 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  6 * Derived (i.e. mostly copied) from arch/i386/kernel/irq.c:
  7 *	Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
  8 */
  9
 10#include <linux/cpumask.h>
 11#include <linux/hardirq.h>
 12#include <linux/interrupt.h>
 13#include <linux/kernel_stat.h>
 14#include <linux/module.h>
 15#include <linux/sched.h>
 16#include <linux/seq_file.h>
 17#include <linux/slab.h>
 18#include <as-layout.h>
 19#include <kern_util.h>
 20#include <os.h>
 21#include <irq_user.h>
 22#include <irq_kern.h>
 23#include <linux/time-internal.h>
 24
 25DEFINE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat);
 26
 27#define irq_stats(x)		(&per_cpu(irq_stat, x))
 28
 29/* When epoll triggers we do not know why it did so
 30 * we can also have different IRQs for read and write.
 31 * This is why we keep a small irq_reg array for each fd -
 32 * one entry per IRQ type
 33 */
 34struct irq_reg {
 35	void *id;
 36	int irq;
 37	/* it's cheaper to store this than to query it */
 38	int events;
 39	bool active;
 40	bool pending;
 41	bool wakeup;
 42#ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
 43	bool pending_event;
 44	void (*timetravel_handler)(int, int, void *,
 45				   struct time_travel_event *);
 46	struct time_travel_event event;
 47#endif
 48};
 49
 50struct irq_entry {
 51	struct list_head list;
 52	int fd;
 53	struct irq_reg reg[NUM_IRQ_TYPES];
 54	bool suspended;
 55	bool sigio_workaround;
 56};
 57
 58static DEFINE_RAW_SPINLOCK(irq_lock);
 59static LIST_HEAD(active_fds);
 60static DECLARE_BITMAP(irqs_allocated, UM_LAST_SIGNAL_IRQ);
 61static bool irqs_suspended;
 62#ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
 63static bool irqs_pending;
 64#endif
 65
 66static void irq_io_loop(struct irq_reg *irq, struct uml_pt_regs *regs)
 67{
 68/*
 69 * irq->active guards against reentry
 70 * irq->pending accumulates pending requests
 71 * if pending is raised the irq_handler is re-run
 72 * until pending is cleared
 73 */
 74	if (irq->active) {
 75		irq->active = false;
 76
 77		do {
 78			irq->pending = false;
 79			do_IRQ(irq->irq, regs);
 80		} while (irq->pending);
 81
 82		irq->active = true;
 83	} else {
 84		irq->pending = true;
 85	}
 86}
 87
 88#ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
 89static void irq_event_handler(struct time_travel_event *ev)
 90{
 91	struct irq_reg *reg = container_of(ev, struct irq_reg, event);
 92
 93	/* do nothing if suspended; just cause a wakeup and mark as pending */
 94	if (irqs_suspended) {
 95		irqs_pending = true;
 96		reg->pending_event = true;
 97		return;
 98	}
 99
100	generic_handle_irq(reg->irq);
101}
102
103static bool irq_do_timetravel_handler(struct irq_entry *entry,
104				      enum um_irq_type t)
105{
106	struct irq_reg *reg = &entry->reg[t];
107
108	if (!reg->timetravel_handler)
109		return false;
110
111	/*
112	 * Handle all messages - we might get multiple even while
113	 * interrupts are already suspended, due to suspend order
114	 * etc. Note that time_travel_add_irq_event() will not add
115	 * an event twice, if it's pending already "first wins".
116	 */
117	reg->timetravel_handler(reg->irq, entry->fd, reg->id, &reg->event);
118
119	if (!reg->event.pending)
120		return false;
121
122	return true;
123}
124
125static void irq_do_pending_events(bool timetravel_handlers_only)
126{
127	struct irq_entry *entry;
128
129	if (!irqs_pending || timetravel_handlers_only)
130		return;
131
132	irqs_pending = false;
133
134	list_for_each_entry(entry, &active_fds, list) {
135		enum um_irq_type t;
136
137		for (t = 0; t < NUM_IRQ_TYPES; t++) {
138			struct irq_reg *reg = &entry->reg[t];
139
140			/*
141			 * Any timetravel_handler was invoked already, just
142			 * directly run the IRQ.
143			 */
144			if (reg->pending_event) {
145				irq_enter();
146				generic_handle_irq(reg->irq);
147				irq_exit();
148				reg->pending_event = false;
149			}
150		}
151	}
152}
153#else
154static bool irq_do_timetravel_handler(struct irq_entry *entry,
155				      enum um_irq_type t)
156{
157	return false;
158}
159
160static void irq_do_pending_events(bool timetravel_handlers_only)
161{
162}
163#endif
164
165static void sigio_reg_handler(int idx, struct irq_entry *entry, enum um_irq_type t,
166			      struct uml_pt_regs *regs,
167			      bool timetravel_handlers_only)
168{
169	struct irq_reg *reg = &entry->reg[t];
170
171	if (!reg->events)
172		return;
173
174	if (os_epoll_triggered(idx, reg->events) <= 0)
175		return;
176
177	if (irq_do_timetravel_handler(entry, t))
178		return;
179
180	/*
181	 * If we're called to only run time-travel handlers then don't
182	 * actually proceed but mark sigio as pending (if applicable).
183	 * For suspend/resume, timetravel_handlers_only may be true
184	 * despite time-travel not being configured and used.
185	 */
186	if (timetravel_handlers_only) {
187#ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
188		reg->pending_event = true;
189		irqs_pending = true;
190		mark_sigio_pending();
191#endif
192		return;
193	}
194
195	irq_io_loop(reg, regs);
196}
197
198static void _sigio_handler(struct uml_pt_regs *regs,
199			   bool timetravel_handlers_only)
200{
201	struct irq_entry *irq_entry;
202	int n, i;
203
204	if (timetravel_handlers_only && !um_irq_timetravel_handler_used())
205		return;
206
207	/* Flush out pending events that were ignored due to time-travel. */
208	if (!irqs_suspended)
209		irq_do_pending_events(timetravel_handlers_only);
210
211	while (1) {
212		/* This is now lockless - epoll keeps back-referencesto the irqs
213		 * which have trigger it so there is no need to walk the irq
214		 * list and lock it every time. We avoid locking by turning off
215		 * IO for a specific fd by executing os_del_epoll_fd(fd) before
216		 * we do any changes to the actual data structures
217		 */
218		n = os_waiting_for_events_epoll();
219
220		if (n <= 0) {
221			if (n == -EINTR)
222				continue;
223			else
224				break;
225		}
226
227		for (i = 0; i < n ; i++) {
228			enum um_irq_type t;
229
230			irq_entry = os_epoll_get_data_pointer(i);
231
232			for (t = 0; t < NUM_IRQ_TYPES; t++)
233				sigio_reg_handler(i, irq_entry, t, regs,
234						  timetravel_handlers_only);
235		}
236	}
237
238	if (!timetravel_handlers_only)
239		free_irqs();
240}
241
242void sigio_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs,
243		   void *mc)
244{
245	preempt_disable();
246	_sigio_handler(regs, irqs_suspended);
247	preempt_enable();
248}
249
250static struct irq_entry *get_irq_entry_by_fd(int fd)
251{
252	struct irq_entry *walk;
253
254	lockdep_assert_held(&irq_lock);
255
256	list_for_each_entry(walk, &active_fds, list) {
257		if (walk->fd == fd)
258			return walk;
259	}
260
261	return NULL;
262}
263
264static void remove_irq_entry(struct irq_entry *to_free, bool remove)
265{
266	if (!to_free)
267		return;
268
269	if (remove)
270		os_del_epoll_fd(to_free->fd);
271	list_del(&to_free->list);
272}
273
274static bool update_irq_entry(struct irq_entry *entry)
275{
276	enum um_irq_type i;
277	int events = 0;
278
279	for (i = 0; i < NUM_IRQ_TYPES; i++)
280		events |= entry->reg[i].events;
281
282	if (events) {
283		/* will modify (instead of add) if needed */
284		os_add_epoll_fd(events, entry->fd, entry);
285		return true;
286	}
287
288	os_del_epoll_fd(entry->fd);
289	return false;
290}
291
292static struct irq_entry *update_or_remove_irq_entry(struct irq_entry *entry)
293{
294	if (update_irq_entry(entry))
295		return NULL;
296	remove_irq_entry(entry, false);
297	return entry;
298}
299
300static int activate_fd(int irq, int fd, enum um_irq_type type, void *dev_id,
301		       void (*timetravel_handler)(int, int, void *,
302						  struct time_travel_event *))
303{
304	struct irq_entry *irq_entry, *to_free = NULL;
305	int err, events = os_event_mask(type);
306	unsigned long flags;
307
308	err = os_set_fd_async(fd);
309	if (err < 0)
310		goto out;
311
312	raw_spin_lock_irqsave(&irq_lock, flags);
313	irq_entry = get_irq_entry_by_fd(fd);
314	if (irq_entry) {
315already:
316		/* cannot register the same FD twice with the same type */
317		if (WARN_ON(irq_entry->reg[type].events)) {
318			err = -EALREADY;
319			goto out_unlock;
320		}
321
322		/* temporarily disable to avoid IRQ-side locking */
323		os_del_epoll_fd(fd);
324	} else {
325		struct irq_entry *new;
326
327		/* don't restore interrupts */
328		raw_spin_unlock(&irq_lock);
329		new = kzalloc(sizeof(*irq_entry), GFP_ATOMIC);
330		if (!new) {
331			local_irq_restore(flags);
332			return -ENOMEM;
333		}
334		raw_spin_lock(&irq_lock);
335		irq_entry = get_irq_entry_by_fd(fd);
336		if (irq_entry) {
337			to_free = new;
338			goto already;
339		}
340		irq_entry = new;
341		irq_entry->fd = fd;
342		list_add_tail(&irq_entry->list, &active_fds);
343		maybe_sigio_broken(fd);
344	}
345
346	irq_entry->reg[type].id = dev_id;
347	irq_entry->reg[type].irq = irq;
348	irq_entry->reg[type].active = true;
349	irq_entry->reg[type].events = events;
350
351#ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
352	if (um_irq_timetravel_handler_used()) {
353		irq_entry->reg[type].timetravel_handler = timetravel_handler;
354		irq_entry->reg[type].event.fn = irq_event_handler;
355	}
356#endif
357
358	WARN_ON(!update_irq_entry(irq_entry));
359	err = 0;
360out_unlock:
361	raw_spin_unlock_irqrestore(&irq_lock, flags);
362out:
363	kfree(to_free);
364	return err;
365}
366
367/*
368 * Remove the entry or entries for a specific FD, if you
369 * don't want to remove all the possible entries then use
370 * um_free_irq() or deactivate_fd() instead.
371 */
372void free_irq_by_fd(int fd)
373{
374	struct irq_entry *to_free;
375	unsigned long flags;
376
377	raw_spin_lock_irqsave(&irq_lock, flags);
378	to_free = get_irq_entry_by_fd(fd);
379	remove_irq_entry(to_free, true);
380	raw_spin_unlock_irqrestore(&irq_lock, flags);
381	kfree(to_free);
382}
383EXPORT_SYMBOL(free_irq_by_fd);
384
385static void free_irq_by_irq_and_dev(unsigned int irq, void *dev)
386{
387	struct irq_entry *entry, *to_free = NULL;
388	unsigned long flags;
389
390	raw_spin_lock_irqsave(&irq_lock, flags);
391	list_for_each_entry(entry, &active_fds, list) {
392		enum um_irq_type i;
393
394		for (i = 0; i < NUM_IRQ_TYPES; i++) {
395			struct irq_reg *reg = &entry->reg[i];
396
397			if (!reg->events)
398				continue;
399			if (reg->irq != irq)
400				continue;
401			if (reg->id != dev)
402				continue;
403
404			os_del_epoll_fd(entry->fd);
405			reg->events = 0;
406			to_free = update_or_remove_irq_entry(entry);
407			goto out;
408		}
409	}
410out:
411	raw_spin_unlock_irqrestore(&irq_lock, flags);
412	kfree(to_free);
413}
414
415void deactivate_fd(int fd, int irqnum)
416{
417	struct irq_entry *entry;
418	unsigned long flags;
419	enum um_irq_type i;
420
421	os_del_epoll_fd(fd);
422
423	raw_spin_lock_irqsave(&irq_lock, flags);
424	entry = get_irq_entry_by_fd(fd);
425	if (!entry)
426		goto out;
427
428	for (i = 0; i < NUM_IRQ_TYPES; i++) {
429		if (!entry->reg[i].events)
430			continue;
431		if (entry->reg[i].irq == irqnum)
432			entry->reg[i].events = 0;
433	}
434
435	entry = update_or_remove_irq_entry(entry);
436out:
437	raw_spin_unlock_irqrestore(&irq_lock, flags);
438	kfree(entry);
439
440	ignore_sigio_fd(fd);
441}
442EXPORT_SYMBOL(deactivate_fd);
443
444/*
445 * Called just before shutdown in order to provide a clean exec
446 * environment in case the system is rebooting.  No locking because
447 * that would cause a pointless shutdown hang if something hadn't
448 * released the lock.
449 */
450int deactivate_all_fds(void)
451{
452	struct irq_entry *entry;
453
454	/* Stop IO. The IRQ loop has no lock so this is our
455	 * only way of making sure we are safe to dispose
456	 * of all IRQ handlers
457	 */
458	os_set_ioignore();
459
460	/* we can no longer call kfree() here so just deactivate */
461	list_for_each_entry(entry, &active_fds, list)
462		os_del_epoll_fd(entry->fd);
463	os_close_epoll_fd();
464	return 0;
465}
466
467/*
468 * do_IRQ handles all normal device IRQs (the special
469 * SMP cross-CPU interrupts have their own specific
470 * handlers).
471 */
472unsigned int do_IRQ(int irq, struct uml_pt_regs *regs)
473{
474	struct pt_regs *old_regs = set_irq_regs((struct pt_regs *)regs);
475	irq_enter();
476	generic_handle_irq(irq);
477	irq_exit();
478	set_irq_regs(old_regs);
479	return 1;
480}
481
482void um_free_irq(int irq, void *dev)
483{
484	if (WARN(irq < 0 || irq > UM_LAST_SIGNAL_IRQ,
485		 "freeing invalid irq %d", irq))
486		return;
487
488	free_irq_by_irq_and_dev(irq, dev);
489	free_irq(irq, dev);
490	clear_bit(irq, irqs_allocated);
491}
492EXPORT_SYMBOL(um_free_irq);
493
494static int
495_um_request_irq(int irq, int fd, enum um_irq_type type,
496		irq_handler_t handler, unsigned long irqflags,
497		const char *devname, void *dev_id,
498		void (*timetravel_handler)(int, int, void *,
499					   struct time_travel_event *))
500{
501	int err;
502
503	if (irq == UM_IRQ_ALLOC) {
504		int i;
505
506		for (i = UM_FIRST_DYN_IRQ; i < NR_IRQS; i++) {
507			if (!test_and_set_bit(i, irqs_allocated)) {
508				irq = i;
509				break;
510			}
511		}
512	}
513
514	if (irq < 0)
515		return -ENOSPC;
516
517	if (fd != -1) {
518		err = activate_fd(irq, fd, type, dev_id, timetravel_handler);
519		if (err)
520			goto error;
521	}
522
523	err = request_irq(irq, handler, irqflags, devname, dev_id);
524	if (err < 0)
525		goto error;
526
527	return irq;
528error:
529	clear_bit(irq, irqs_allocated);
530	return err;
531}
532
533int um_request_irq(int irq, int fd, enum um_irq_type type,
534		   irq_handler_t handler, unsigned long irqflags,
535		   const char *devname, void *dev_id)
536{
537	return _um_request_irq(irq, fd, type, handler, irqflags,
538			       devname, dev_id, NULL);
539}
540EXPORT_SYMBOL(um_request_irq);
541
542#ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
543int um_request_irq_tt(int irq, int fd, enum um_irq_type type,
544		      irq_handler_t handler, unsigned long irqflags,
545		      const char *devname, void *dev_id,
546		      void (*timetravel_handler)(int, int, void *,
547						 struct time_travel_event *))
548{
549	return _um_request_irq(irq, fd, type, handler, irqflags,
550			       devname, dev_id, timetravel_handler);
551}
552EXPORT_SYMBOL(um_request_irq_tt);
553
554void sigio_run_timetravel_handlers(void)
555{
556	_sigio_handler(NULL, true);
557}
558#endif
559
560#ifdef CONFIG_PM_SLEEP
561void um_irqs_suspend(void)
562{
563	struct irq_entry *entry;
564	unsigned long flags;
565
566	irqs_suspended = true;
567
568	raw_spin_lock_irqsave(&irq_lock, flags);
569	list_for_each_entry(entry, &active_fds, list) {
570		enum um_irq_type t;
571		bool clear = true;
572
573		for (t = 0; t < NUM_IRQ_TYPES; t++) {
574			if (!entry->reg[t].events)
575				continue;
576
577			/*
578			 * For the SIGIO_WRITE_IRQ, which is used to handle the
579			 * SIGIO workaround thread, we need special handling:
580			 * enable wake for it itself, but below we tell it about
581			 * any FDs that should be suspended.
582			 */
583			if (entry->reg[t].wakeup ||
584			    entry->reg[t].irq == SIGIO_WRITE_IRQ
585#ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
586			    || entry->reg[t].timetravel_handler
587#endif
588			    ) {
589				clear = false;
590				break;
591			}
592		}
593
594		if (clear) {
595			entry->suspended = true;
596			os_clear_fd_async(entry->fd);
597			entry->sigio_workaround =
598				!__ignore_sigio_fd(entry->fd);
599		}
600	}
601	raw_spin_unlock_irqrestore(&irq_lock, flags);
602}
603
604void um_irqs_resume(void)
605{
606	struct irq_entry *entry;
607	unsigned long flags;
608
609
610	raw_spin_lock_irqsave(&irq_lock, flags);
611	list_for_each_entry(entry, &active_fds, list) {
612		if (entry->suspended) {
613			int err = os_set_fd_async(entry->fd);
614
615			WARN(err < 0, "os_set_fd_async returned %d\n", err);
616			entry->suspended = false;
617
618			if (entry->sigio_workaround) {
619				err = __add_sigio_fd(entry->fd);
620				WARN(err < 0, "add_sigio_returned %d\n", err);
621			}
622		}
623	}
624	raw_spin_unlock_irqrestore(&irq_lock, flags);
625
626	irqs_suspended = false;
627	send_sigio_to_self();
628}
629
630static int normal_irq_set_wake(struct irq_data *d, unsigned int on)
631{
632	struct irq_entry *entry;
633	unsigned long flags;
634
635	raw_spin_lock_irqsave(&irq_lock, flags);
636	list_for_each_entry(entry, &active_fds, list) {
637		enum um_irq_type t;
638
639		for (t = 0; t < NUM_IRQ_TYPES; t++) {
640			if (!entry->reg[t].events)
641				continue;
642
643			if (entry->reg[t].irq != d->irq)
644				continue;
645			entry->reg[t].wakeup = on;
646			goto unlock;
647		}
648	}
649unlock:
650	raw_spin_unlock_irqrestore(&irq_lock, flags);
651	return 0;
652}
653#else
654#define normal_irq_set_wake NULL
655#endif
656
657/*
658 * irq_chip must define at least enable/disable and ack when
659 * the edge handler is used.
660 */
661static void dummy(struct irq_data *d)
662{
663}
664
665/* This is used for everything other than the timer. */
666static struct irq_chip normal_irq_type = {
667	.name = "SIGIO",
668	.irq_disable = dummy,
669	.irq_enable = dummy,
670	.irq_ack = dummy,
671	.irq_mask = dummy,
672	.irq_unmask = dummy,
673	.irq_set_wake = normal_irq_set_wake,
674};
675
676static struct irq_chip alarm_irq_type = {
677	.name = "SIGALRM",
678	.irq_disable = dummy,
679	.irq_enable = dummy,
680	.irq_ack = dummy,
681	.irq_mask = dummy,
682	.irq_unmask = dummy,
683};
684
685void __init init_IRQ(void)
686{
687	int i;
688
689	irq_set_chip_and_handler(TIMER_IRQ, &alarm_irq_type, handle_percpu_irq);
690
691	for (i = 1; i < UM_LAST_SIGNAL_IRQ; i++)
692		irq_set_chip_and_handler(i, &normal_irq_type, handle_edge_irq);
693	/* Initialize EPOLL Loop */
694	os_setup_epoll();
695}
696
697int __init arch_probe_nr_irqs(void)
698{
699	return NR_IRQS;
700}
701
702void sigchld_handler(int sig, struct siginfo *unused_si,
703		     struct uml_pt_regs *regs, void *mc)
704{
705	do_IRQ(SIGCHLD_IRQ, regs);
706}
707
708/*
709 * /proc/interrupts printing for arch specific interrupts
710 */
711int arch_show_interrupts(struct seq_file *p, int prec)
712{
713#if IS_ENABLED(CONFIG_SMP)
714	int cpu;
715
716	seq_printf(p, "%*s: ", prec, "RES");
717	for_each_online_cpu(cpu)
718		seq_printf(p, "%10u ", irq_stats(cpu)->irq_resched_count);
719	seq_puts(p, "  Rescheduling interrupts\n");
720
721	seq_printf(p, "%*s: ", prec, "CAL");
722	for_each_online_cpu(cpu)
723		seq_printf(p, "%10u ", irq_stats(cpu)->irq_call_count);
724	seq_puts(p, "  Function call interrupts\n");
725#endif
726
727	return 0;
728}
~/ Read-only file preview.