📄 scsi_dma.c
字号:
/* * scsi_dma.c Copyright (C) 2000 Eric Youngdale * * mid-level SCSI DMA bounce buffer allocator * */#define __NO_VERSION__#include <linux/config.h>#include <linux/module.h>#include <linux/blk.h>#include "scsi.h"#include "hosts.h"#include "constants.h"#ifdef CONFIG_KMOD#include <linux/kmod.h>#endif/* * PAGE_SIZE must be a multiple of the sector size (512). True * for all reasonably recent architectures (even the VAX...). */#define SECTOR_SIZE 512#define SECTORS_PER_PAGE (PAGE_SIZE/SECTOR_SIZE)#if SECTORS_PER_PAGE <= 8typedef unsigned char FreeSectorBitmap;#elif SECTORS_PER_PAGE <= 32typedef unsigned int FreeSectorBitmap;#elif SECTORS_PER_PAGE <= 64#if 0typedef unsigned long long FreeSectorBitmap;#elsetypedef struct { unsigned long l,h;} FreeSectorBitmap;#define LARGE_MALLOC#endif#else#error You lose.#endif/* * Used for access to internal allocator used for DMA safe buffers. */static spinlock_t allocator_request_lock = SPIN_LOCK_UNLOCKED;static FreeSectorBitmap *dma_malloc_freelist = NULL;static int need_isa_bounce_buffers;static unsigned int dma_sectors = 0;unsigned int scsi_dma_free_sectors = 0;unsigned int scsi_need_isa_buffer = 0;static unsigned char **dma_malloc_pages = NULL;/* * Function: scsi_malloc * * Purpose: Allocate memory from the DMA-safe pool. * * Arguments: len - amount of memory we need. * * Lock status: No locks assumed to be held. This function is SMP-safe. * * Returns: Pointer to memory block. * * Notes: Prior to the new queue code, this function was not SMP-safe. * This function can only allocate in units of sectors * (i.e. 512 bytes). * * We cannot use the normal system allocator becuase we need * to be able to guarantee that we can process a complete disk * I/O request without touching the system allocator. Think * about it - if the system were heavily swapping, and tried to * write out a block of memory to disk, and the SCSI code needed * to allocate more memory in order to be able to write the * data to disk, you would wedge the system. */#ifndef LARGE_MALLOCvoid *scsi_malloc(unsigned int len){ unsigned int nbits, mask; unsigned long flags; int i, j; if (len % SECTOR_SIZE != 0 || len > PAGE_SIZE) return NULL; nbits = len >> 9; mask = (1 << nbits) - 1; spin_lock_irqsave(&allocator_request_lock, flags); for (i = 0; i < dma_sectors / SECTORS_PER_PAGE; i++) for (j = 0; j <= SECTORS_PER_PAGE - nbits; j++) { if ((dma_malloc_freelist[i] & (mask << j)) == 0) { dma_malloc_freelist[i] |= (mask << j); scsi_dma_free_sectors -= nbits;#ifdef DEBUG SCSI_LOG_MLQUEUE(3, printk("SMalloc: %d %p [From:%p]\n", len, dma_malloc_pages[i] + (j << 9))); printk("SMalloc: %d %p [From:%p]\n", len, dma_malloc_pages[i] + (j << 9));#endif spin_unlock_irqrestore(&allocator_request_lock, flags); return (void *) ((unsigned long) dma_malloc_pages[i] + (j << 9)); } } spin_unlock_irqrestore(&allocator_request_lock, flags); return NULL; /* Nope. No more */}/* * Function: scsi_free * * Purpose: Free memory into the DMA-safe pool. * * Arguments: ptr - data block we are freeing. * len - size of block we are freeing. * * Lock status: No locks assumed to be held. This function is SMP-safe. * * Returns: Nothing * * Notes: This function *must* only be used to free memory * allocated from scsi_malloc(). * * Prior to the new queue code, this function was not SMP-safe. * This function can only allocate in units of sectors * (i.e. 512 bytes). */int scsi_free(void *obj, unsigned int len){ unsigned int page, sector, nbits, mask; unsigned long flags;#ifdef DEBUG unsigned long ret = 0;#ifdef __mips__ __asm__ __volatile__("move\t%0,$31":"=r"(ret));#else ret = __builtin_return_address(0);#endif printk("scsi_free %p %d\n", obj, len); SCSI_LOG_MLQUEUE(3, printk("SFree: %p %d\n", obj, len));#endif spin_lock_irqsave(&allocator_request_lock, flags); for (page = 0; page < dma_sectors / SECTORS_PER_PAGE; page++) { unsigned long page_addr = (unsigned long) dma_malloc_pages[page]; if ((unsigned long) obj >= page_addr && (unsigned long) obj < page_addr + PAGE_SIZE) { sector = (((unsigned long) obj) - page_addr) >> 9; nbits = len >> 9; mask = (1 << nbits) - 1; if (sector + nbits > SECTORS_PER_PAGE) panic("scsi_free:Bad memory alignment"); if ((dma_malloc_freelist[page] & (mask << sector)) != (mask << sector)) {#ifdef DEBUG printk("scsi_free(obj=%p, len=%d) called from %08lx\n", obj, len, ret);#endif panic("scsi_free:Trying to free unused memory"); } scsi_dma_free_sectors += nbits; dma_malloc_freelist[page] &= ~(mask << sector); spin_unlock_irqrestore(&allocator_request_lock, flags); return 0; } } panic("scsi_free:Bad offset");}#elsevoid *scsi_malloc(unsigned int len){ unsigned int nbits; unsigned long maskl, maskh, flags; FreeSectorBitmap *fsb; int i; if (len % SECTOR_SIZE != 0 || len > PAGE_SIZE) return NULL; save_flags_cli (flags); nbits = len >> 9; if (nbits < 32) { maskl = (1 << nbits) - 1; maskh = 0; } else { maskl = (unsigned long)-1; maskh = (1 << (nbits - 32)) - 1; } fsb = dma_malloc_freelist; for (i = 0; i < dma_sectors / SECTORS_PER_PAGE; i++) { unsigned long mml, mmh; int j; mml = maskl; mmh = maskh; j = 0; do { if ((fsb->l & mml) == 0 && (fsb->h & mmh) == 0) { fsb->h |= mmh; fsb->l |= mml; restore_flags (flags); scsi_dma_free_sectors -= nbits;#ifdef DEBUG printk("SMalloc: %d %p\n",len, dma_malloc_pages[i] + (j << 9));#endif return (void *) ((unsigned long) dma_malloc_pages[i] + (j << 9)); } mmh = (mmh << 1) | (mml >> 31); mml <<= 1; j++; } while (!(mmh & (1 << 31))); fsb ++; } return NULL; /* Nope. No more */}int scsi_free(void *obj, unsigned int len){ unsigned int page, sector, nbits; unsigned long maskl, maskh, flags;#ifdef DEBUG printk("scsi_free %p %d\n",obj, len);#endif for (page = 0; page < dma_sectors / SECTORS_PER_PAGE; page++) { unsigned long page_addr = (unsigned long) dma_malloc_pages[page]; if ((unsigned long) obj >= page_addr && (unsigned long) obj < page_addr + PAGE_SIZE) { sector = (((unsigned long) obj) - page_addr) >> 9; nbits = len >> 9; if (nbits < 32) { maskl = (1 << nbits) - 1; maskh = 0; } else { maskl = (unsigned long)-1; maskh = (1 << (nbits - 32)) - 1; } if ((sector + nbits) > SECTORS_PER_PAGE) panic ("scsi_free:Bad memory alignment"); maskh = (maskh << sector) | (maskl >> (32 - sector)); maskl = maskl << sector; save_flags_cli(flags); if (((dma_malloc_freelist[page].l & maskl) != maskl) || ((dma_malloc_freelist[page].h & maskh) != maskh)) panic("scsi_free:Trying to free unused memory"); scsi_dma_free_sectors += nbits; dma_malloc_freelist[page].l &= ~maskl; dma_malloc_freelist[page].h &= ~maskh; restore_flags(flags); return 0; } } panic("scsi_free:Bad offset");}#endif/* * Function: scsi_resize_dma_pool * * Purpose: Ensure that the DMA pool is sufficiently large to be * able to guarantee that we can always process I/O requests * without calling the system allocator.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -