Annotation of XNU/osfmk/i386/AT386/himem.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * The contents of this file constitute Original Code as defined in and
        !             7:  * are subject to the Apple Public Source License Version 1.1 (the
        !             8:  * "License").  You may not use this file except in compliance with the
        !             9:  * License.  Please obtain a copy of the License at
        !            10:  * http://www.apple.com/publicsource and read it before using this file.
        !            11:  * 
        !            12:  * This Original Code and all software distributed under the License are
        !            13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            17:  * License for the specific language governing rights and limitations
        !            18:  * under the License.
        !            19:  * 
        !            20:  * @APPLE_LICENSE_HEADER_END@
        !            21:  */
        !            22: /*
        !            23:  * @OSF_FREE_COPYRIGHT@
        !            24:  */
        !            25: /*
        !            26:  * HISTORY
        !            27:  * 
        !            28:  * Revision 1.1.1.1  1998/09/22 21:05:38  wsanchez
        !            29:  * Import of Mac OS X kernel (~semeria)
        !            30:  *
        !            31:  * Revision 1.1.1.1  1998/03/07 02:25:39  wsanchez
        !            32:  * Import of OSF Mach kernel (~mburg)
        !            33:  *
        !            34:  * Revision 1.3.17.7  1995/08/21  20:33:13  devrcs
        !            35:  *     ri-osc CR1547:  Fix himem buffer translation to cope with non
        !            36:  *     page-aligned addresses.
        !            37:  *     [1995/08/08  16:51:58  bolinger]
        !            38:  *
        !            39:  * Revision 1.3.17.6  1995/02/24  15:51:12  alanl
        !            40:  *     DIPC:  Merge from nmk17b2 to nmk18b8.
        !            41:  *     Notes:  lock package cleanup.
        !            42:  *     [95/01/23            alanl]
        !            43:  *     [95/02/24            alanl]
        !            44:  * 
        !            45:  * Revision 1.3.17.5  1995/01/26  22:14:52  ezf
        !            46:  *     removed extraneous CMU CR
        !            47:  *     [1995/01/26  20:24:45  ezf]
        !            48:  * 
        !            49:  * Revision 1.3.17.4  1995/01/10  04:51:04  devrcs
        !            50:  *     mk6 CR801 - merge up from nmk18b4 to nmk18b7
        !            51:  *     * Rev 1.3.17.3  1994/10/21  18:41:39  joe
        !            52:  *       Added ETAP support
        !            53:  *     [1994/12/09  20:37:48  dwm]
        !            54:  * 
        !            55:  *     mk6 CR764 - s/spinlock/simple_lock/ (name change only)
        !            56:  *     [1994/11/10  05:25:33  dwm]
        !            57:  * 
        !            58:  *     mk6 CR668 - 1.3b26 merge
        !            59:  *     * Revision 1.3.5.8  1994/05/06  18:44:06  tmt
        !            60:  *     Fix prototypes for new device signatures.
        !            61:  *     * Revision 1.3.5.6  1993/12/10  18:08:15  jeffc
        !            62:  *     CR10305 -- locking bug in himem_reserve(): change call to
        !            63:  *     vm_page_free to VM_PAGE_FREE.
        !            64:  *     * Revision 1.3.5.5  1993/11/19  17:56:58  jeffc
        !            65:  *     CR10125 -- Uninitialized lock in himem_convert. Add himem_init
        !            66:  *     CR9461 -- Locking bug in himem_convert - must retake lock after
        !            67:  *     thread_sleep.
        !            68:  *     * End1.3merge
        !            69:  *     [1994/11/04  09:07:39  dwm]
        !            70:  * 
        !            71:  * Revision 1.3.17.1  1994/06/14  03:04:20  toshi
        !            72:  *     Merge MK6 and NMK17
        !            73:  *     [1994/06/14  01:06:55  toshi]
        !            74:  * 
        !            75:  * Revision 1.3.15.2  1994/06/08  21:14:24  dswartz
        !            76:  *     Preemption merge.
        !            77:  *     [1994/06/08  21:12:29  dswartz]
        !            78:  * 
        !            79:  * Revision 1.3.15.1  1994/05/19  20:30:23  dwm
        !            80:  *     mk6 CR 74.  Locking bug in himem_reserve(): use VM_PAGE_FREE.
        !            81:  *     mk6 CR 9461.  Init hil_lock used by himem_convert();
        !            82:  *     retake lock after sleeping.
        !            83:  *     [1994/05/19  20:30:07  dwm]
        !            84:  * 
        !            85:  * Revision 1.3.11.1  1994/02/09  07:27:07  bernadat
        !            86:  *     Added himem_init() for module initialization.
        !            87:  *     [93/08/12            paire]
        !            88:  * 
        !            89:  *     Take back hil_lock lock on return from thread_sleep()
        !            90:  *     [93/07/16            bernadat]
        !            91:  * 
        !            92:  *     Add vm_page_gobble() calls where needed. (dwm bug #542)
        !            93:  *     Change from NORMA_MK14.6 [1993/02/09  22:24:00  dwm]
        !            94:  *     [93/07/16            bernadat]
        !            95:  *     [94/02/08            bernadat]
        !            96:  * 
        !            97:  * Revision 1.3.5.4  1993/08/09  19:37:19  dswartz
        !            98:  *     Add ANSI prototypes - CR#9523
        !            99:  *     [1993/08/06  17:50:02  dswartz]
        !           100:  * 
        !           101:  * Revision 1.3.5.3  1993/08/03  22:21:26  bernard
        !           102:  *     CR#9523 - ANSI prototype fixes.
        !           103:  *     [1993/08/03  15:34:10  bernard]
        !           104:  * 
        !           105:  * Revision 1.3.5.2  1993/06/09  02:25:18  gm
        !           106:  *     CR9157 - Find himem.h in the right place.
        !           107:  *     [1993/05/28  17:27:23  brezak]
        !           108:  * 
        !           109:  * Revision 1.3  1993/04/19  16:09:46  devrcs
        !           110:  *     make endif tags ansi compliant/include files
        !           111:  *     [1993/02/20  21:46:44  david]
        !           112:  * 
        !           113:  *     Print an appropriate message when going out of HIMEM pages.
        !           114:  *     [93/01/26            bernadat]
        !           115:  * 
        !           116:  * Revision 1.2  1992/11/25  01:07:08  robert
        !           117:  *     integrate changes below for norma_14
        !           118:  *     [1992/11/13  19:28:44  robert]
        !           119:  * 
        !           120:  * $EndLog$
        !           121:  */
        !           122: 
        !           123: /*
        !           124:  * support of memory above 16 Megs for DMA limited to memory
        !           125:  * below 16 Megs. Copies high memory lo low memory before DMA
        !           126:  * write operations and does the reverse at completion time for
        !           127:  * DMA read operations
        !           128:  */
        !           129: 
        !           130: #include <cpus.h>
        !           131: #include <platforms.h>
        !           132: #include <kern/lock.h>
        !           133: #include <mach/vm_param.h>
        !           134: #include <vm/vm_page.h>
        !           135: #include <i386/AT386/himem.h>
        !           136: #include <kern/kalloc.h>
        !           137: #include <kern/spl.h>
        !           138: #include <mach/boolean.h>
        !           139: #include <kern/misc_protos.h>
        !           140: #include <i386/AT386/misc_protos.h>
        !           141: 
        !           142: hil_t          hil_head;
        !           143: decl_simple_lock_data(,hil_lock)
        !           144: 
        !           145: #if    HIMEM_STATS
        !           146: int himem_request;     /* number of requests */
        !           147: int himem_used;                /* number of times used */
        !           148: #endif /* HIMEM_STATS */
        !           149: 
        !           150: void
        !           151: himem_init(
        !           152:        void)
        !           153: {
        !           154:        simple_lock_init(&hil_lock, ETAP_VM_HIMEM);
        !           155: }
        !           156: 
        !           157: /* 
        !           158:  * Called by drivers, this indicates himem that this driver might need
        !           159:  * to allocate as many as npages pages in a single I/O DMA transfer
        !           160:  */
        !           161: 
        !           162: void
        !           163: himem_reserve(
        !           164:        int             npages)
        !           165: {
        !           166:        register                i = 0;
        !           167:        vm_page_t               free_head = VM_PAGE_NULL;
        !           168:        vm_page_t               low;
        !           169:        hil_t                   hil;
        !           170:        spl_t                   ipl;
        !           171:        extern vm_offset_t      avail_end;
        !           172: 
        !           173:        if (avail_end <= HIGH_MEM)
        !           174:                return;
        !           175:        hil = (hil_t)kalloc(npages*sizeof(struct himem_link));
        !           176:        if (hil == (hil_t)0) 
        !           177:                panic("himem_reserve: kalloc failed\n");
        !           178: 
        !           179:        for (i=0; i < npages-1; i++)
        !           180:                (hil+i)->next = hil+i+1;
        !           181: 
        !           182:        /*
        !           183:         * This is the only way of getting low physical pages 
        !           184:         * wtithout changing VM internals
        !           185:         */
        !           186:        for (i=0; i != npages;) {
        !           187:                if ((low = vm_page_grab()) == VM_PAGE_NULL)
        !           188:                        panic("No low memory pages for himem\n");
        !           189:                vm_page_gobble(low); /* mark as consumed internally */
        !           190:                if (_high_mem_page(low->phys_addr)) {
        !           191:                        low->pageq.next = (queue_entry_t)free_head;
        !           192:                        free_head = low;
        !           193:                } else {
        !           194:                        (hil+i)->low_page = low->phys_addr;
        !           195:                        i++;
        !           196:                }
        !           197:        }
        !           198: 
        !           199:        for (low = free_head; low; low = free_head) {
        !           200:                free_head = (vm_page_t) low->pageq.next;
        !           201:                VM_PAGE_FREE(low);
        !           202:         }
        !           203: 
        !           204:        ipl = splhi();
        !           205:        simple_lock(&hil_lock);
        !           206:        (hil+npages-1)->next = hil_head;
        !           207:        hil_head = hil;
        !           208:        simple_unlock(&hil_lock);
        !           209:        splx(ipl);
        !           210: }
        !           211: 
        !           212: /*
        !           213:  * Called by driver at DMA initialization time. Converts a high memory
        !           214:  * physical page to a low memory one. If operation is a write, 
        !           215:  * [phys_addr, phys_addr+length-1] is copied to new page. Caller must
        !           216:  * provide a pointer to a pointer to a himem_list. This is used to store
        !           217:  * all the conversions and is use at completion time to revert the pages.
        !           218:  * This pointer must point to a null hil_t value for the call on the first
        !           219:  * page of a DMA transfer.
        !           220:  */
        !           221: 
        !           222: vm_offset_t
        !           223: himem_convert(
        !           224:        vm_offset_t     phys_addr,
        !           225:        vm_size_t       length,
        !           226:        int             io_op,
        !           227:        hil_t           *hil)
        !           228: {
        !           229:        hil_t           h;
        !           230:        spl_t           ipl;
        !           231:        vm_offset_t     offset = phys_addr & (I386_PGBYTES - 1);
        !           232: 
        !           233:        assert (offset + length <= I386_PGBYTES);
        !           234: 
        !           235:        ipl = splhi();
        !           236:        simple_lock(&hil_lock);
        !           237:        while (!(h = hil_head)) { 
        !           238:                printf("WARNING: out of HIMEM pages\n");
        !           239:                thread_sleep_simple_lock((event_t)&hil_head,
        !           240:                                        simple_lock_addr(hil_lock), FALSE);
        !           241:                simple_lock (&hil_lock);
        !           242:        }
        !           243:        hil_head = hil_head->next;
        !           244:        simple_unlock(&hil_lock);
        !           245:        splx(ipl);
        !           246:        
        !           247:        h->high_addr = phys_addr;
        !           248: 
        !           249:        if (io_op == D_WRITE) {
        !           250:          bcopy((char *)phystokv(phys_addr), (char *)phystokv(h->low_page + offset),
        !           251:                length);
        !           252:          h->length = 0;
        !           253:        } else {
        !           254:          h->length = length;
        !           255:        }
        !           256:        h->offset = offset;
        !           257: 
        !           258:        assert(!*hil || (*hil)->high_addr);
        !           259: 
        !           260:        h->next = *hil;
        !           261:        *hil = h;
        !           262:        return(h->low_page + offset);
        !           263: }
        !           264: 
        !           265: /*
        !           266:  * Called by driver at DMA completion time. Converts a list of low memory
        !           267:  * physical page to the original high memory one. If operation was read, 
        !           268:  * [phys_addr, phys_addr+lenght-1] is copied to original page
        !           269:  */
        !           270: 
        !           271: void
        !           272: himem_revert(
        !           273:        hil_t           hil)
        !           274: {
        !           275:        hil_t           next;
        !           276:        boolean_t       wakeup = FALSE;
        !           277:        spl_t           ipl;
        !           278: 
        !           279:        while(hil) {
        !           280:                if (hil->length) {
        !           281:                        bcopy((char *)phystokv(hil->low_page + hil->offset),
        !           282:                                (char *)phystokv(hil->high_addr),
        !           283:                              hil->length);
        !           284:                }
        !           285:                hil->high_addr = 0;
        !           286:                hil->length = 0;
        !           287:                hil->offset = 0;
        !           288:                next = hil->next;
        !           289:                ipl = splhi();
        !           290:                simple_lock(&hil_lock);
        !           291:                if (!(hil->next = hil_head))
        !           292:                        wakeup = TRUE;
        !           293:                hil_head = hil;
        !           294:                simple_unlock(&hil_lock);
        !           295:                splx(ipl);
        !           296:                hil = next;
        !           297:        }
        !           298:        if (wakeup)
        !           299:                thread_wakeup((event_t)&hil_head);
        !           300: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.