|
|
1.1 root 1: /*
2: * Copyright (c) 2000 University of Utah and the Flux Group.
3: * All rights reserved.
4: *
5: * This file is part of the Flux OSKit. The OSKit is free software, also known
6: * as "open source;" you can redistribute it and/or modify it under the terms
7: * of the GNU General Public License (GPL), version 2, as published by the Free
8: * Software Foundation (FSF). To explore alternate licensing terms, contact
9: * the University of Utah at [email protected] or +1-801-585-3271.
10: *
11: * The OSKit is distributed in the hope that it will be useful, but WITHOUT ANY
12: * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13: * FOR A PARTICULAR PURPOSE. See the GPL for more details. You should have
14: * received a copy of the GPL along with the OSKit; see the file COPYING. If
15: * not, write to the FSF, 59 Temple Place #330, Boston, MA 02111-1307, USA.
16: */
17:
18: /*
19: * oskit Software Interrupt management for Mach.
20: */
21:
22: #include <oskit/error.h>
23: #include <oskit/debug.h>
24: #include <oskit/dev/dev.h>
25: #include <oskit/dev/softirq.h>
26: #include <oskit/machine/base_irq.h>
27: #include <stdio.h>
28: #include <string.h> /* ffs */
29:
30: #include <machine/spl.h>
31: #include "ds_oskit.h"
32:
33:
34: /* Linked list of functions for a software interrupt. */
35: struct softint_handler {
36: void (*func)(void *);
37: void *data;
38: struct softint_handler *next;
39: int flags;
40: };
41:
42: /* Array of pointers to lists of interrupt handlers. */
43: static struct softint_handler *softint_handlers[SOFT_IRQ_COUNT];
44:
45: /* Mask of allocated vectors, for the benefit of osenv_softirq_request() */
46: static unsigned int softint_allocated = ((1 << OSENV_SOFT_IRQ_SOFTWARE)
47: | (1 << OSENV_SOFT_IRQ_PTHREAD));
48:
49: /* Pending softirqs that have been software scheduled. */
50: static volatile unsigned int softint_pending;
51:
52: static spl_t osenv_softintr_spl;
53: extern spl_t curr_ipl;
54:
55: /* This is called from softclock_oskit, at splsoftclock.
56: It's the hook to run any pending oskit software interrupt handlers.
57:
58: A software interrupt handler should obviously not allocate or deallocate
59: a software interrupt. It may schedule one of course. */
60: void
61: oskit_softint (void)
62: {
63: unsigned int pending;
64:
65: /* This must be an atomic instruction because hardware interrupts (splio)
66: are enabled, and one could come in and call osenv_softirq_schedule
67: while this frame is suspended by the interrupt. */
68:
69: asm ("xchgl %0,%1"
70: : "=&r" (pending), "=m" (softint_pending)
71: : "0" (0), "1" (softint_pending));
72:
73: while (pending)
74: {
75: int i;
76: struct softint_handler *current;
77:
78: i = ffs (pending) - 1;
79: pending &= ~(1 << i);
80:
81: current = softint_handlers[i];
82: while (current)
83: {
84: current->func (current->data);
85: current = current->next;
86: }
87: }
88: }
89:
90:
91: /* Allocate a (well-known) software interrupt handler. */
92: oskit_error_t
93: osenv_softirq_alloc (int irq, void (*handler)(void *), void *data, int flags)
94: {
95: struct softint_handler *temp, **p;
96:
97: if (irq < 0 || irq >= SOFT_IRQ_COUNT)
98: return OSKIT_EINVAL;
99:
100: /* Do this to ensure that the free vectors are explicitly allocated
101: before having a handler assigned. */
102: if ((irq >= SOFT_IRQ_FREEBASE) && !(softint_allocated & (1 << irq)))
103: return OSKIT_EINVAL;
104:
105: /* This is a blocking operation, so to avoid races we need to do it
106: before we start mucking with data structures. */
107: temp = osenv_mem_alloc (sizeof(struct softint_handler), 0, 1);
108: if (temp == NULL)
109: return OSKIT_ENOMEM;
110: temp->func = handler;
111: temp->data = data;
112: temp->next = NULL;
113: temp->flags = flags;
114:
115: /* Note that we only hook in the new handler after its structure has been
116: fully initialized; this way we don't have to disable interrupts, because
117: interrupt-level code only scans the list. */
118: for (p = &softint_handlers[irq]; *p != NULL; p = &(*p)->next)
119: ;
120: *p = temp;
121:
122: return 0;
123: }
124:
125: /* Request an unused software interrupt handler vector. This just reserves
126: and returns the vector number for use with osenv_softirq_alloc() above. */
127: oskit_error_t
128: osenv_softirq_alloc_vector (int *out_irq)
129: {
130: int i, enabled;
131:
132: /* Go ahead and block interrupts, cause its easy. */
133: enabled = osenv_softintr_enabled ();
134: if (enabled)
135: osenv_softintr_disable ();
136:
137: /* Search for an empty slot above the well-known vectors. */
138: for (i = SOFT_IRQ_FREEBASE; i < SOFT_IRQ_COUNT; i++)
139: {
140: if (! (softint_allocated & (1 << i)))
141: break;
142: }
143: if (i == SOFT_IRQ_COUNT)
144: {
145: if (enabled)
146: osenv_softintr_enable ();
147: return OSKIT_ERANGE;
148: }
149:
150: softint_allocated |= (1 << i);
151: *out_irq = i;
152:
153: if (enabled)
154: osenv_softintr_enable ();
155: return 0;
156: }
157:
158: /* Free up a vector. */
159: oskit_error_t
160: osenv_softirq_free_vector (int irq)
161: {
162: /* Must be allocated */
163: if (! (softint_allocated & (1 << irq)))
164: return OSKIT_EINVAL;
165:
166: /* Must no longer be in use */
167: if (softint_handlers[irq])
168: return OSKIT_EINVAL;
169:
170: softint_allocated &= ~(1 << irq);
171:
172: return 0;
173: }
174:
175: /* Deallocate a software interrupt. Need a handle so know WHICH
176: interrupt handler to remove. */
177: void
178: osenv_softirq_free (int irq, void (*handler)(void *), void *data)
179: {
180: struct softint_handler *temp, **p;
181:
182: osenv_assert (irq >= 0 && irq < SOFT_IRQ_COUNT);
183:
184: /* Find and unlink the handler from the list. */
185: p = &softint_handlers[irq];
186: while (((temp = *p) != NULL)
187: && (temp->func != handler || temp->data != data))
188: p = &temp->next;
189:
190: /* not found? */
191: if (temp == NULL)
192: {
193: osenv_log (OSENV_LOG_WARNING,
194: "osenv_softirq_free: handler not registered!\n");
195: return;
196: }
197:
198: /* remove it! */
199: *p = temp->next;
200: osenv_softintr_disable ();
201: osenv_mem_free (temp, 0, sizeof(struct softint_handler));
202: }
203:
204: /* Schedule a software interrupt to be delivered next time it's appropriate.
205: Note that this must be called with software interrupts disabled! */
206: void
207: osenv_softirq_schedule (int irq)
208: {
209: osenv_assert (softint_handlers[irq]);
210:
211: softint_pending |= (1 << irq);
212: setsoftclock ();
213: }
214:
215: void
216: osenv_softintr_enable (void)
217: {
218: spl_t s = osenv_softintr_spl;
219: osenv_softintr_spl = SPL1;
220: splx (s);
221: }
222:
223: void
224: osenv_softintr_disable (void)
225: {
226: /* We can be called with interrupts already disabled! */
227: if (curr_ipl > SPL1)
228: /* We are already at a higher priority, so return to it.
229: XXX This presumes _enable will be called at the same spl.
230: Perhaps we should instead just set a flag and have
231: the corresponding enable just do nothing. */
232: osenv_softintr_spl = curr_ipl;
233: else if (curr_ipl < SPL1)
234: /* We are at a level where software interrupts are enabled, so we must
235: go to spltsoftclock. osenv_softintr_enable we will return to the
236: current level. */
237: osenv_softintr_spl = splsoftclock ();
238: }
239:
240: int
241: osenv_softintr_enabled (void)
242: {
243: return curr_ipl < SPL1;
244: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.