|
|
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.