⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 umem.c

📁 Linux块设备驱动源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * mm.c - Micro Memory(tm) PCI memory board block device driver - v2.3 * * (C) 2001 San Mehat <nettwerk@valinux.com> * (C) 2001 Johannes Erdfelt <jerdfelt@valinux.com> * (C) 2001 NeilBrown <neilb@cse.unsw.edu.au> * * This driver for the Micro Memory PCI Memory Module with Battery Backup * is Copyright Micro Memory Inc 2001-2002.  All rights reserved. * * This driver is released to the public under the terms of the *  GNU GENERAL PUBLIC LICENSE version 2 * See the file COPYING for details. * * This driver provides a standard block device interface for Micro Memory(tm) * PCI based RAM boards. * 10/05/01: Phap Nguyen - Rebuilt the driver * 10/22/01: Phap Nguyen - v2.1 Added disk partitioning * 29oct2001:NeilBrown   - Use make_request_fn instead of request_fn *                       - use stand disk partitioning (so fdisk works). * 08nov2001:NeilBrown	 - change driver name from "mm" to "umem" *			 - incorporate into main kernel * 08apr2002:NeilBrown   - Move some of interrupt handle to tasklet *			 - use spin_lock_bh instead of _irq *			 - Never block on make_request.  queue *			   bh's instead. *			 - unregister umem from devfs at mod unload *			 - Change version to 2.3 * 07Nov2001:Phap Nguyen - Select pci read command: 06, 12, 15 (Decimal) * 07Jan2002: P. Nguyen  - Used PCI Memory Write & Invalidate for DMA * 15May2002:NeilBrown   - convert to bio for 2.5 * 17May2002:NeilBrown   - remove init_mem initialisation.  Instead detect *			 - a sequence of writes that cover the card, and *			 - set initialised bit then. *///#define DEBUG /* uncomment if you want debugging info (pr_debug) */#include <linux/config.h>#include <linux/sched.h>#include <linux/fs.h>#include <linux/bio.h>#include <linux/kernel.h>#include <linux/mm.h>#include <linux/mman.h>#include <linux/ioctl.h>#include <linux/module.h>#include <linux/init.h>#include <linux/interrupt.h>#include <linux/smp_lock.h>#include <linux/timer.h>#include <linux/pci.h>#include <linux/slab.h>#include <linux/fcntl.h>        /* O_ACCMODE */#include <linux/hdreg.h>  /* HDIO_GETGEO */#include <linux/umem.h>#include <asm/uaccess.h>#include <asm/io.h>#define MM_MAXCARDS 4#define MM_RAHEAD 2      /* two sectors */#define MM_BLKSIZE 1024  /* 1k blocks */#define MM_HARDSECT 512  /* 512-byte hardware sectors */#define MM_SHIFT 6       /* max 64 partitions on 4 cards  *//* * Version Information */#define DRIVER_VERSION "v2.3"#define DRIVER_AUTHOR "San Mehat, Johannes Erdfelt, NeilBrown"#define DRIVER_DESC "Micro Memory(tm) PCI memory board block driver"static int debug;/* #define HW_TRACE(x)     writeb(x,cards[0].csr_remap + MEMCTRLSTATUS_MAGIC) */#define HW_TRACE(x)#define DEBUG_LED_ON_TRANSFER	0x01#define DEBUG_BATTERY_POLLING	0x02module_param(debug, int, 0644);MODULE_PARM_DESC(debug, "Debug bitmask");static int pci_read_cmd = 0x0C;		/* Read Multiple */module_param(pci_read_cmd, int, 0);MODULE_PARM_DESC(pci_read_cmd, "PCI read command");static int pci_write_cmd = 0x0F;	/* Write and Invalidate */module_param(pci_write_cmd, int, 0);MODULE_PARM_DESC(pci_write_cmd, "PCI write command");static int pci_cmds;static int major_nr;#include <linux/blkdev.h>#include <linux/blkpg.h>struct cardinfo {	int		card_number;	struct pci_dev	*dev;	int		irq;	unsigned long	csr_base;	unsigned char	__iomem *csr_remap;	unsigned long	csr_len;#ifdef CONFIG_MM_MAP_MEMORY	unsigned long	mem_base;	unsigned char	__iomem *mem_remap;	unsigned long	mem_len;#endif	unsigned int	win_size; /* PCI window size */	unsigned int	mm_size;  /* size in kbytes */	unsigned int	init_size; /* initial segment, in sectors,				    * that we know to				    * have been written				    */	struct bio	*bio, *currentbio, **biotail;	request_queue_t *queue;	struct mm_page {		dma_addr_t		page_dma;		struct mm_dma_desc	*desc;		int	 		cnt, headcnt;		struct bio		*bio, **biotail;	} mm_pages[2];#define DESC_PER_PAGE ((PAGE_SIZE*2)/sizeof(struct mm_dma_desc))	int  Active, Ready;	struct tasklet_struct	tasklet;	unsigned int dma_status;	struct {		int		good;		int		warned;		unsigned long	last_change;	} battery[2];	spinlock_t 	lock;	int		check_batteries;	int		flags;};static struct cardinfo cards[MM_MAXCARDS];static struct block_device_operations mm_fops;static struct timer_list battery_timer;static int num_cards = 0;static struct gendisk *mm_gendisk[MM_MAXCARDS];static void check_batteries(struct cardinfo *card);/*-------------------------------------------------------------------------------------                           get_userbit-----------------------------------------------------------------------------------*/static int get_userbit(struct cardinfo *card, int bit){	unsigned char led;	led = readb(card->csr_remap + MEMCTRLCMD_LEDCTRL);	return led & bit;}/*-------------------------------------------------------------------------------------                            set_userbit-----------------------------------------------------------------------------------*/static int set_userbit(struct cardinfo *card, int bit, unsigned char state){	unsigned char led;	led = readb(card->csr_remap + MEMCTRLCMD_LEDCTRL);	if (state)		led |= bit;	else		led &= ~bit;	writeb(led, card->csr_remap + MEMCTRLCMD_LEDCTRL);	return 0;}/*-------------------------------------------------------------------------------------                             set_led-----------------------------------------------------------------------------------*//* * NOTE: For the power LED, use the LED_POWER_* macros since they differ */static void set_led(struct cardinfo *card, int shift, unsigned char state){	unsigned char led;	led = readb(card->csr_remap + MEMCTRLCMD_LEDCTRL);	if (state == LED_FLIP)		led ^= (1<<shift);	else {		led &= ~(0x03 << shift);		led |= (state << shift);	}	writeb(led, card->csr_remap + MEMCTRLCMD_LEDCTRL);}#ifdef MM_DIAG/*-------------------------------------------------------------------------------------                              dump_regs-----------------------------------------------------------------------------------*/static void dump_regs(struct cardinfo *card){	unsigned char *p;	int i, i1;	p = card->csr_remap;	for (i = 0; i < 8; i++) {		printk(KERN_DEBUG "%p   ", p);		for (i1 = 0; i1 < 16; i1++)			printk("%02x ", *p++);		printk("\n");	}}#endif/*-------------------------------------------------------------------------------------                            dump_dmastat-----------------------------------------------------------------------------------*/static void dump_dmastat(struct cardinfo *card, unsigned int dmastat){	printk(KERN_DEBUG "MM%d*: DMAstat - ", card->card_number);	if (dmastat & DMASCR_ANY_ERR)		printk("ANY_ERR ");	if (dmastat & DMASCR_MBE_ERR)		printk("MBE_ERR ");	if (dmastat & DMASCR_PARITY_ERR_REP)		printk("PARITY_ERR_REP ");	if (dmastat & DMASCR_PARITY_ERR_DET)		printk("PARITY_ERR_DET ");	if (dmastat & DMASCR_SYSTEM_ERR_SIG)		printk("SYSTEM_ERR_SIG ");	if (dmastat & DMASCR_TARGET_ABT)		printk("TARGET_ABT ");	if (dmastat & DMASCR_MASTER_ABT)		printk("MASTER_ABT ");	if (dmastat & DMASCR_CHAIN_COMPLETE)		printk("CHAIN_COMPLETE ");	if (dmastat & DMASCR_DMA_COMPLETE)		printk("DMA_COMPLETE ");	printk("\n");}/* * Theory of request handling * * Each bio is assigned to one mm_dma_desc - which may not be enough FIXME * We have two pages of mm_dma_desc, holding about 64 descriptors * each.  These are allocated at init time. * One page is "Ready" and is either full, or can have request added. * The other page might be "Active", which DMA is happening on it. * * Whenever IO on the active page completes, the Ready page is activated * and the ex-Active page is clean out and made Ready. * Otherwise the Ready page is only activated when it becomes full, or * when mm_unplug_device is called via the unplug_io_fn. * * If a request arrives while both pages a full, it is queued, and b_rdev is * overloaded to record whether it was a read or a write. * * The interrupt handler only polls the device to clear the interrupt. * The processing of the result is done in a tasklet. */static void mm_start_io(struct cardinfo *card){	/* we have the lock, we know there is	 * no IO active, and we know that card->Active	 * is set	 */	struct mm_dma_desc *desc;	struct mm_page *page;	int offset;	/* make the last descriptor end the chain */	page = &card->mm_pages[card->Active];	pr_debug("start_io: %d %d->%d\n", card->Active, page->headcnt, page->cnt-1);	desc = &page->desc[page->cnt-1];	desc->control_bits |= cpu_to_le32(DMASCR_CHAIN_COMP_EN);	desc->control_bits &= ~cpu_to_le32(DMASCR_CHAIN_EN);	desc->sem_control_bits = desc->control_bits;			       	if (debug & DEBUG_LED_ON_TRANSFER)		set_led(card, LED_REMOVE, LED_ON);	desc = &page->desc[page->headcnt];	writel(0, card->csr_remap + DMA_PCI_ADDR);	writel(0, card->csr_remap + DMA_PCI_ADDR + 4);	writel(0, card->csr_remap + DMA_LOCAL_ADDR);	writel(0, card->csr_remap + DMA_LOCAL_ADDR + 4);	writel(0, card->csr_remap + DMA_TRANSFER_SIZE);	writel(0, card->csr_remap + DMA_TRANSFER_SIZE + 4);	writel(0, card->csr_remap + DMA_SEMAPHORE_ADDR);	writel(0, card->csr_remap + DMA_SEMAPHORE_ADDR + 4);	offset = ((char*)desc) - ((char*)page->desc);	writel(cpu_to_le32((page->page_dma+offset)&0xffffffff),	       card->csr_remap + DMA_DESCRIPTOR_ADDR);	/* Force the value to u64 before shifting otherwise >> 32 is undefined C	 * and on some ports will do nothing ! */	writel(cpu_to_le32(((u64)page->page_dma)>>32),	       card->csr_remap + DMA_DESCRIPTOR_ADDR + 4);	/* Go, go, go */	writel(cpu_to_le32(DMASCR_GO | DMASCR_CHAIN_EN | pci_cmds),	       card->csr_remap + DMA_STATUS_CTRL);}static int add_bio(struct cardinfo *card);static void activate(struct cardinfo *card){	/* if No page is Active, and Ready is 	 * not empty, then switch Ready page	 * to active and start IO.	 * Then add any bh's that are available to Ready	 */	do {		while (add_bio(card))			;		if (card->Active == -1 &&		    card->mm_pages[card->Ready].cnt > 0) {			card->Active = card->Ready;			card->Ready = 1-card->Ready;			mm_start_io(card);		}	} while (card->Active == -1 && add_bio(card));}static inline void reset_page(struct mm_page *page){	page->cnt = 0;	page->headcnt = 0;	page->bio = NULL;	page->biotail = & page->bio;}static void mm_unplug_device(request_queue_t *q){	struct cardinfo *card = q->queuedata;	unsigned long flags;	spin_lock_irqsave(&card->lock, flags);	if (blk_remove_plug(q))		activate(card);	spin_unlock_irqrestore(&card->lock, flags);}/*  * If there is room on Ready page, take * one bh off list and add it. * return 1 if there was room, else 0. */static int add_bio(struct cardinfo *card){	struct mm_page *p;	struct mm_dma_desc *desc;	dma_addr_t dma_handle;	int offset;	struct bio *bio;	int rw;	int len;	bio = card->currentbio;	if (!bio && card->bio) {		card->currentbio = card->bio;		card->bio = card->bio->bi_next;		if (card->bio == NULL)			card->biotail = &card->bio;		card->currentbio->bi_next = NULL;		return 1;	}	if (!bio)		return 0;	rw = bio_rw(bio);	if (card->mm_pages[card->Ready].cnt >= DESC_PER_PAGE)		return 0;	len = bio_iovec(bio)->bv_len;	dma_handle = pci_map_page(card->dev, 				  bio_page(bio),				  bio_offset(bio),				  len,				  (rw==READ) ?				  PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);	p = &card->mm_pages[card->Ready];

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -