|
|
1.1 ! root 1: /* ! 2: * Linux initialization. ! 3: * ! 4: * Copyright (C) 1996 The University of Utah and the Computer Systems ! 5: * Laboratory at the University of Utah (CSL) ! 6: * ! 7: * This program is free software; you can redistribute it and/or modify ! 8: * it under the terms of the GNU General Public License as published by ! 9: * the Free Software Foundation; either version 2, or (at your option) ! 10: * any later version. ! 11: * ! 12: * This program is distributed in the hope that it will be useful, ! 13: * but WITHOUT ANY WARRANTY; without even the implied warranty of ! 14: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 15: * GNU General Public License for more details. ! 16: * ! 17: * You should have received a copy of the GNU General Public License ! 18: * along with this program; if not, write to the Free Software ! 19: * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ! 20: * ! 21: * Author: Shantanu Goel, University of Utah CSL ! 22: */ ! 23: ! 24: /* ! 25: * linux/init/main.c ! 26: * ! 27: * Copyright (C) 1991, 1992 Linus Torvalds ! 28: */ ! 29: ! 30: #include <sys/types.h> ! 31: ! 32: #include <mach/vm_param.h> ! 33: #include <mach/vm_prot.h> ! 34: #include <mach/machine.h> ! 35: ! 36: #include <vm/vm_page.h> ! 37: #include <kern/kalloc.h> ! 38: ! 39: #include <machine/spl.h> ! 40: #include <machine/pmap.h> ! 41: #include <machine/vm_param.h> ! 42: ! 43: #define MACH_INCLUDE ! 44: #include <linux/sched.h> ! 45: #include <linux/mm.h> ! 46: #include <linux/interrupt.h> ! 47: #include <linux/delay.h> ! 48: #include <linux/ioport.h> ! 49: #include <linux/string.h> ! 50: ! 51: #include <asm/system.h> ! 52: #include <asm/io.h> ! 53: ! 54: #include <device-drivers.h> ! 55: ! 56: /* ! 57: * Timing loop count. ! 58: */ ! 59: unsigned long loops_per_sec = 1; ! 60: ! 61: /* ! 62: * End of physical memory. ! 63: */ ! 64: unsigned long high_memory; ! 65: ! 66: /* ! 67: * Flag to indicate auto-configuration is in progress. ! 68: */ ! 69: int linux_auto_config = 1; ! 70: ! 71: /* ! 72: * Hard drive parameters obtained from the BIOS. ! 73: */ ! 74: struct drive_info_struct ! 75: { ! 76: char dummy[32]; ! 77: } drive_info; ! 78: ! 79: /* ! 80: * Forward declarations. ! 81: */ ! 82: static void calibrate_delay (void); ! 83: ! 84: extern int hz; ! 85: extern vm_offset_t phys_last_addr; ! 86: ! 87: extern void *alloc_contig_mem (unsigned, unsigned, unsigned, vm_page_t *); ! 88: extern void free_contig_mem (vm_page_t); ! 89: extern void init_IRQ (void); ! 90: extern void restore_IRQ (void); ! 91: extern void startrtclock (void); ! 92: extern void linux_version_init (void); ! 93: extern void linux_kmem_init (void); ! 94: extern unsigned long pci_init (unsigned long, unsigned long); ! 95: extern void linux_net_emulation_init (void); ! 96: extern void device_setup (void); ! 97: extern void linux_printk (char *,...); ! 98: extern int linux_timer_intr (void); ! 99: extern spl_t spl0 (void); ! 100: extern spl_t splhigh (void); ! 101: extern void form_pic_mask (void); ! 102: extern int linux_bad_intr (int); ! 103: extern int prtnull (); ! 104: extern int intnull (); ! 105: extern void linux_sched_init (void); ! 106: ! 107: ! 108: /* ! 109: * Amount of contiguous memory to allocate for initialization. ! 110: */ ! 111: #define CONTIG_ALLOC (512 * 1024) ! 112: ! 113: /* ! 114: * Initialize Linux drivers. ! 115: */ ! 116: void ! 117: linux_init (void) ! 118: { ! 119: int addr; ! 120: unsigned memory_start, memory_end; ! 121: vm_page_t pages; ! 122: ! 123: /* ! 124: * Initialize memory size. ! 125: */ ! 126: high_memory = phys_last_addr; ! 127: init_IRQ (); ! 128: linux_sched_init (); ! 129: ! 130: /* ! 131: * Set loop count. ! 132: */ ! 133: calibrate_delay (); ! 134: ! 135: /* ! 136: * Initialize drive info. ! 137: */ ! 138: addr = *((unsigned *) phystokv (0x104)); ! 139: memcpy (&drive_info, ! 140: (void *) ((addr & 0xffff) + ((addr >> 12) & 0xffff0)), 16); ! 141: addr = *((unsigned *) phystokv (0x118)); ! 142: memcpy ((char *) &drive_info + 16, ! 143: (void *) ((addr & 0xffff) + ((addr >> 12) & 0xffff0)), 16); ! 144: ! 145: /* ! 146: * Initialize Linux memory allocator. ! 147: */ ! 148: linux_kmem_init (); ! 149: ! 150: /* ! 151: * Allocate contiguous memory below 16 MB. ! 152: */ ! 153: memory_start = (unsigned long) alloc_contig_mem (CONTIG_ALLOC, ! 154: 16 * 1024 * 1024, ! 155: 0, &pages); ! 156: if (memory_start == 0) ! 157: panic ("linux_init: alloc_contig_mem failed"); ! 158: memory_end = memory_start + CONTIG_ALLOC; ! 159: ! 160: /* ! 161: * Initialize PCI bus. ! 162: */ ! 163: memory_start = pci_init (memory_start, memory_end); ! 164: ! 165: if (memory_start > memory_end) ! 166: panic ("linux_init: ran out memory"); ! 167: ! 168: /* ! 169: * Free unused memory. ! 170: */ ! 171: while (pages && pages->phys_addr < round_page (memory_start)) ! 172: pages = (vm_page_t) pages->pageq.next; ! 173: if (pages) ! 174: free_contig_mem (pages); ! 175: ! 176: /* ! 177: * Initialize devices. ! 178: */ ! 179: #ifdef CONFIG_INET ! 180: linux_net_emulation_init (); ! 181: #endif ! 182: cli (); ! 183: device_setup (); ! 184: ! 185: restore_IRQ (); ! 186: linux_auto_config = 0; ! 187: } ! 188: ! 189: #ifndef NBPW ! 190: #define NBPW 32 ! 191: #endif ! 192: ! 193: /* ! 194: * Allocate contiguous memory with the given constraints. ! 195: * This routine is horribly inefficient but it is presently ! 196: * only used during initialization so it's not that bad. ! 197: */ ! 198: void * ! 199: alloc_contig_mem (unsigned size, unsigned limit, ! 200: unsigned mask, vm_page_t * pages) ! 201: { ! 202: int i, j, bits_len; ! 203: unsigned *bits, len; ! 204: void *m; ! 205: vm_page_t p, page_list, tail, prev; ! 206: vm_offset_t addr, max_addr; ! 207: ! 208: if (size == 0) ! 209: return (NULL); ! 210: size = round_page (size); ! 211: if ((size >> PAGE_SHIFT) > vm_page_free_count) ! 212: return (NULL); ! 213: ! 214: /* Allocate bit array. */ ! 215: max_addr = phys_last_addr; ! 216: if (max_addr > limit) ! 217: max_addr = limit; ! 218: bits_len = ((((max_addr >> PAGE_SHIFT) + NBPW - 1) / NBPW) ! 219: * sizeof (unsigned)); ! 220: bits = (unsigned *) kalloc (bits_len); ! 221: if (!bits) ! 222: return (NULL); ! 223: memset (bits, 0, bits_len); ! 224: ! 225: /* ! 226: * Walk the page free list and set a bit for every usable page. ! 227: */ ! 228: simple_lock (&vm_page_queue_free_lock); ! 229: p = vm_page_queue_free; ! 230: while (p) ! 231: { ! 232: if (p->phys_addr < limit) ! 233: (bits[(p->phys_addr >> PAGE_SHIFT) / NBPW] ! 234: |= 1 << ((p->phys_addr >> PAGE_SHIFT) % NBPW)); ! 235: p = (vm_page_t) p->pageq.next; ! 236: } ! 237: ! 238: /* ! 239: * Scan bit array for contiguous pages. ! 240: */ ! 241: len = 0; ! 242: m = NULL; ! 243: for (i = 0; len < size && i < bits_len / sizeof (unsigned); i++) ! 244: for (j = 0; len < size && j < NBPW; j++) ! 245: if (!(bits[i] & (1 << j))) ! 246: { ! 247: len = 0; ! 248: m = NULL; ! 249: } ! 250: else ! 251: { ! 252: if (len == 0) ! 253: { ! 254: addr = ((vm_offset_t) (i * NBPW + j) ! 255: << PAGE_SHIFT); ! 256: if ((addr & mask) == 0) ! 257: { ! 258: len += PAGE_SIZE; ! 259: m = (void *) addr; ! 260: } ! 261: } ! 262: else ! 263: len += PAGE_SIZE; ! 264: } ! 265: ! 266: if (len != size) ! 267: { ! 268: simple_unlock (&vm_page_queue_free_lock); ! 269: kfree ((vm_offset_t) bits, bits_len); ! 270: return (NULL); ! 271: } ! 272: ! 273: /* ! 274: * Remove pages from free list ! 275: * and construct list to return to caller. ! 276: */ ! 277: page_list = NULL; ! 278: for (len = 0; len < size; len += PAGE_SIZE, addr += PAGE_SIZE) ! 279: { ! 280: prev = NULL; ! 281: for (p = vm_page_queue_free; p; p = (vm_page_t) p->pageq.next) ! 282: { ! 283: if (p->phys_addr == addr) ! 284: break; ! 285: prev = p; ! 286: } ! 287: if (!p) ! 288: panic ("alloc_contig_mem: page not on free list"); ! 289: if (prev) ! 290: prev->pageq.next = p->pageq.next; ! 291: else ! 292: vm_page_queue_free = (vm_page_t) p->pageq.next; ! 293: p->free = FALSE; ! 294: p->pageq.next = NULL; ! 295: if (!page_list) ! 296: page_list = tail = p; ! 297: else ! 298: { ! 299: tail->pageq.next = (queue_entry_t) p; ! 300: tail = p; ! 301: } ! 302: vm_page_free_count--; ! 303: } ! 304: ! 305: simple_unlock (&vm_page_queue_free_lock); ! 306: kfree ((vm_offset_t) bits, bits_len); ! 307: if (pages) ! 308: *pages = page_list; ! 309: return (m); ! 310: } ! 311: ! 312: /* ! 313: * Free memory allocated by alloc_contig_mem. ! 314: */ ! 315: void ! 316: free_contig_mem (vm_page_t pages) ! 317: { ! 318: int i; ! 319: vm_page_t p; ! 320: ! 321: for (p = pages, i = 0; p->pageq.next; p = (vm_page_t) p->pageq.next, i++) ! 322: p->free = TRUE; ! 323: p->free = TRUE; ! 324: simple_lock (&vm_page_queue_free_lock); ! 325: vm_page_free_count += i + 1; ! 326: p->pageq.next = (queue_entry_t) vm_page_queue_free; ! 327: vm_page_queue_free = pages; ! 328: simple_unlock (&vm_page_queue_free_lock); ! 329: } ! 330: ! 331: /* This is the number of bits of precision for the loops_per_second. Each ! 332: * bit takes on average 1.5/HZ seconds. This (like the original) is a little ! 333: * better than 1% ! 334: */ ! 335: #define LPS_PREC 8 ! 336: ! 337: static void ! 338: calibrate_delay (void) ! 339: { ! 340: int ticks; ! 341: int loopbit; ! 342: int lps_precision = LPS_PREC; ! 343: ! 344: loops_per_sec = (1 << 12); ! 345: ! 346: #ifndef MACH ! 347: printk ("Calibrating delay loop.. "); ! 348: #endif ! 349: while (loops_per_sec <<= 1) ! 350: { ! 351: /* wait for "start of" clock tick */ ! 352: ticks = jiffies; ! 353: while (ticks == jiffies) ! 354: /* nothing */ ; ! 355: /* Go .. */ ! 356: ticks = jiffies; ! 357: __delay (loops_per_sec); ! 358: ticks = jiffies - ticks; ! 359: if (ticks) ! 360: break; ! 361: } ! 362: ! 363: /* Do a binary approximation to get loops_per_second set to equal one clock ! 364: * (up to lps_precision bits) ! 365: */ ! 366: loops_per_sec >>= 1; ! 367: loopbit = loops_per_sec; ! 368: while (lps_precision-- && (loopbit >>= 1)) ! 369: { ! 370: loops_per_sec |= loopbit; ! 371: ticks = jiffies; ! 372: while (ticks == jiffies); ! 373: ticks = jiffies; ! 374: __delay (loops_per_sec); ! 375: if (jiffies != ticks) /* longer than 1 tick */ ! 376: loops_per_sec &= ~loopbit; ! 377: } ! 378: ! 379: /* finally, adjust loops per second in terms of seconds instead of clocks */ ! 380: loops_per_sec *= HZ; ! 381: /* Round the value and print it */ ! 382: #ifndef MACH ! 383: printk ("ok - %lu.%02lu BogoMIPS\n", ! 384: (loops_per_sec + 2500) / 500000, ! 385: ((loops_per_sec + 2500) / 5000) % 100); ! 386: #endif ! 387: ! 388: #if defined(__SMP__) && defined(__i386__) ! 389: smp_loops_per_tick = loops_per_sec / 400; ! 390: #endif ! 391: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.