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

📄 umem.c

📁 Linux块设备驱动源码
💻 C
📖 第 1 页 / 共 3 页
字号:
	desc = &p->desc[p->cnt];	p->cnt++;	if ((p->biotail) != &bio->bi_next) {		*(p->biotail) = bio;		p->biotail = &(bio->bi_next);		bio->bi_next = NULL;	}	desc->data_dma_handle = dma_handle;	desc->pci_addr = cpu_to_le64((u64)desc->data_dma_handle);	desc->local_addr= cpu_to_le64(bio->bi_sector << 9);	desc->transfer_size = cpu_to_le32(len);	offset = ( ((char*)&desc->sem_control_bits) - ((char*)p->desc));	desc->sem_addr = cpu_to_le64((u64)(p->page_dma+offset));	desc->zero1 = desc->zero2 = 0;	offset = ( ((char*)(desc+1)) - ((char*)p->desc));	desc->next_desc_addr = cpu_to_le64(p->page_dma+offset);	desc->control_bits = cpu_to_le32(DMASCR_GO|DMASCR_ERR_INT_EN|					 DMASCR_PARITY_INT_EN|					 DMASCR_CHAIN_EN |					 DMASCR_SEM_EN |					 pci_cmds);	if (rw == WRITE)		desc->control_bits |= cpu_to_le32(DMASCR_TRANSFER_READ);	desc->sem_control_bits = desc->control_bits;	bio->bi_sector += (len>>9);	bio->bi_size -= len;	bio->bi_idx++;	if (bio->bi_idx >= bio->bi_vcnt) 		card->currentbio = NULL;	return 1;}static void process_page(unsigned long data){	/* check if any of the requests in the page are DMA_COMPLETE,	 * and deal with them appropriately.	 * If we find a descriptor without DMA_COMPLETE in the semaphore, then	 * dma must have hit an error on that descriptor, so use dma_status instead	 * and assume that all following descriptors must be re-tried.	 */	struct mm_page *page;	struct bio *return_bio=NULL;	struct cardinfo *card = (struct cardinfo *)data;	unsigned int dma_status = card->dma_status;	spin_lock_bh(&card->lock);	if (card->Active < 0)		goto out_unlock;	page = &card->mm_pages[card->Active];		while (page->headcnt < page->cnt) {		struct bio *bio = page->bio;		struct mm_dma_desc *desc = &page->desc[page->headcnt];		int control = le32_to_cpu(desc->sem_control_bits);		int last=0;		int idx;		if (!(control & DMASCR_DMA_COMPLETE)) {			control = dma_status;			last=1; 		}		page->headcnt++;		idx = bio->bi_phys_segments;		bio->bi_phys_segments++;		if (bio->bi_phys_segments >= bio->bi_vcnt)			page->bio = bio->bi_next;		pci_unmap_page(card->dev, desc->data_dma_handle, 			       bio_iovec_idx(bio,idx)->bv_len,				 (control& DMASCR_TRANSFER_READ) ?				PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);		if (control & DMASCR_HARD_ERROR) {			/* error */			clear_bit(BIO_UPTODATE, &bio->bi_flags);			printk(KERN_WARNING "MM%d: I/O error on sector %d/%d\n",			       card->card_number, 			       le32_to_cpu(desc->local_addr)>>9,			       le32_to_cpu(desc->transfer_size));			dump_dmastat(card, control);		} else if (test_bit(BIO_RW, &bio->bi_rw) &&			   le32_to_cpu(desc->local_addr)>>9 == card->init_size) {			card->init_size += le32_to_cpu(desc->transfer_size)>>9;			if (card->init_size>>1 >= card->mm_size) {				printk(KERN_INFO "MM%d: memory now initialised\n",				       card->card_number);				set_userbit(card, MEMORY_INITIALIZED, 1);			}		}		if (bio != page->bio) {			bio->bi_next = return_bio;			return_bio = bio;		}		if (last) break;	}	if (debug & DEBUG_LED_ON_TRANSFER)		set_led(card, LED_REMOVE, LED_OFF);	if (card->check_batteries) {		card->check_batteries = 0;		check_batteries(card);	}	if (page->headcnt >= page->cnt) {		reset_page(page);		card->Active = -1;		activate(card);	} else {		/* haven't finished with this one yet */		pr_debug("do some more\n");		mm_start_io(card);	} out_unlock:	spin_unlock_bh(&card->lock);	while(return_bio) {		struct bio *bio = return_bio;		return_bio = bio->bi_next;		bio->bi_next = NULL;		bio_endio(bio, bio->bi_size, 0);	}}/*-------------------------------------------------------------------------------------                              mm_make_request-----------------------------------------------------------------------------------*/static int mm_make_request(request_queue_t *q, struct bio *bio){	struct cardinfo *card = q->queuedata;	pr_debug("mm_make_request %ld %d\n", bh->b_rsector, bh->b_size);	bio->bi_phys_segments = bio->bi_idx; /* count of completed segments*/	spin_lock_irq(&card->lock);	*card->biotail = bio;	bio->bi_next = NULL;	card->biotail = &bio->bi_next;	blk_plug_device(q);	spin_unlock_irq(&card->lock);	return 0;}/*-------------------------------------------------------------------------------------                              mm_interrupt-----------------------------------------------------------------------------------*/static irqreturn_t mm_interrupt(int irq, void *__card, struct pt_regs *regs){	struct cardinfo *card = (struct cardinfo *) __card;	unsigned int dma_status;	unsigned short cfg_status;HW_TRACE(0x30);	dma_status = le32_to_cpu(readl(card->csr_remap + DMA_STATUS_CTRL));	if (!(dma_status & (DMASCR_ERROR_MASK | DMASCR_CHAIN_COMPLETE))) {		/* interrupt wasn't for me ... */		return IRQ_NONE;        }	/* clear COMPLETION interrupts */	if (card->flags & UM_FLAG_NO_BYTE_STATUS)		writel(cpu_to_le32(DMASCR_DMA_COMPLETE|DMASCR_CHAIN_COMPLETE),		       card->csr_remap+ DMA_STATUS_CTRL);	else		writeb((DMASCR_DMA_COMPLETE|DMASCR_CHAIN_COMPLETE) >> 16,		       card->csr_remap+ DMA_STATUS_CTRL + 2);		/* log errors and clear interrupt status */	if (dma_status & DMASCR_ANY_ERR) {		unsigned int	data_log1, data_log2;		unsigned int	addr_log1, addr_log2;		unsigned char	stat, count, syndrome, check;		stat = readb(card->csr_remap + MEMCTRLCMD_ERRSTATUS);		data_log1 = le32_to_cpu(readl(card->csr_remap + ERROR_DATA_LOG));		data_log2 = le32_to_cpu(readl(card->csr_remap + ERROR_DATA_LOG + 4));		addr_log1 = le32_to_cpu(readl(card->csr_remap + ERROR_ADDR_LOG));		addr_log2 = readb(card->csr_remap + ERROR_ADDR_LOG + 4);		count = readb(card->csr_remap + ERROR_COUNT);		syndrome = readb(card->csr_remap + ERROR_SYNDROME);		check = readb(card->csr_remap + ERROR_CHECK);		dump_dmastat(card, dma_status);		if (stat & 0x01)			printk(KERN_ERR "MM%d*: Memory access error detected (err count %d)\n",				card->card_number, count);		if (stat & 0x02)			printk(KERN_ERR "MM%d*: Multi-bit EDC error\n",				card->card_number);		printk(KERN_ERR "MM%d*: Fault Address 0x%02x%08x, Fault Data 0x%08x%08x\n",			card->card_number, addr_log2, addr_log1, data_log2, data_log1);		printk(KERN_ERR "MM%d*: Fault Check 0x%02x, Fault Syndrome 0x%02x\n",			card->card_number, check, syndrome);		writeb(0, card->csr_remap + ERROR_COUNT);	}	if (dma_status & DMASCR_PARITY_ERR_REP) {		printk(KERN_ERR "MM%d*: PARITY ERROR REPORTED\n", card->card_number);		pci_read_config_word(card->dev, PCI_STATUS, &cfg_status);		pci_write_config_word(card->dev, PCI_STATUS, cfg_status);	}	if (dma_status & DMASCR_PARITY_ERR_DET) {		printk(KERN_ERR "MM%d*: PARITY ERROR DETECTED\n", card->card_number); 		pci_read_config_word(card->dev, PCI_STATUS, &cfg_status);		pci_write_config_word(card->dev, PCI_STATUS, cfg_status);	}	if (dma_status & DMASCR_SYSTEM_ERR_SIG) {		printk(KERN_ERR "MM%d*: SYSTEM ERROR\n", card->card_number); 		pci_read_config_word(card->dev, PCI_STATUS, &cfg_status);		pci_write_config_word(card->dev, PCI_STATUS, cfg_status);	}	if (dma_status & DMASCR_TARGET_ABT) {		printk(KERN_ERR "MM%d*: TARGET ABORT\n", card->card_number); 		pci_read_config_word(card->dev, PCI_STATUS, &cfg_status);		pci_write_config_word(card->dev, PCI_STATUS, cfg_status);	}	if (dma_status & DMASCR_MASTER_ABT) {		printk(KERN_ERR "MM%d*: MASTER ABORT\n", card->card_number); 		pci_read_config_word(card->dev, PCI_STATUS, &cfg_status);		pci_write_config_word(card->dev, PCI_STATUS, cfg_status);	}	/* and process the DMA descriptors */	card->dma_status = dma_status;	tasklet_schedule(&card->tasklet);HW_TRACE(0x36);	return IRQ_HANDLED; }/*-------------------------------------------------------------------------------------                         set_fault_to_battery_status-----------------------------------------------------------------------------------*//* * If both batteries are good, no LED * If either battery has been warned, solid LED * If both batteries are bad, flash the LED quickly * If either battery is bad, flash the LED semi quickly */static void set_fault_to_battery_status(struct cardinfo *card){	if (card->battery[0].good && card->battery[1].good)		set_led(card, LED_FAULT, LED_OFF);	else if (card->battery[0].warned || card->battery[1].warned)		set_led(card, LED_FAULT, LED_ON);	else if (!card->battery[0].good && !card->battery[1].good)		set_led(card, LED_FAULT, LED_FLASH_7_0);	else		set_led(card, LED_FAULT, LED_FLASH_3_5);}static void init_battery_timer(void);/*-------------------------------------------------------------------------------------                            check_battery-----------------------------------------------------------------------------------*/static int check_battery(struct cardinfo *card, int battery, int status){	if (status != card->battery[battery].good) {		card->battery[battery].good = !card->battery[battery].good;		card->battery[battery].last_change = jiffies;		if (card->battery[battery].good) {			printk(KERN_ERR "MM%d: Battery %d now good\n",				card->card_number, battery + 1);			card->battery[battery].warned = 0;		} else			printk(KERN_ERR "MM%d: Battery %d now FAILED\n",				card->card_number, battery + 1);		return 1;	} else if (!card->battery[battery].good &&		   !card->battery[battery].warned &&		   time_after_eq(jiffies, card->battery[battery].last_change +				 (HZ * 60 * 60 * 5))) {		printk(KERN_ERR "MM%d: Battery %d still FAILED after 5 hours\n",			card->card_number, battery + 1);		card->battery[battery].warned = 1;		return 1;	}	return 0;}/*-------------------------------------------------------------------------------------                              check_batteries-----------------------------------------------------------------------------------*/static void check_batteries(struct cardinfo *card){	/* NOTE: this must *never* be called while the card	 * is doing (bus-to-card) DMA, or you will need the	 * reset switch	 */	unsigned char status;	int ret1, ret2;	status = readb(card->csr_remap + MEMCTRLSTATUS_BATTERY);	if (debug & DEBUG_BATTERY_POLLING)		printk(KERN_DEBUG "MM%d: checking battery status, 1 = %s, 2 = %s\n",		       card->card_number,		       (status & BATTERY_1_FAILURE) ? "FAILURE" : "OK",		       (status & BATTERY_2_FAILURE) ? "FAILURE" : "OK");	ret1 = check_battery(card, 0, !(status & BATTERY_1_FAILURE));	ret2 = check_battery(card, 1, !(status & BATTERY_2_FAILURE));	if (ret1 || ret2)		set_fault_to_battery_status(card);}static void check_all_batteries(unsigned long ptr){	int i;	for (i = 0; i < num_cards; i++) 		if (!(cards[i].flags & UM_FLAG_NO_BATT)) {			struct cardinfo *card = &cards[i];			spin_lock_bh(&card->lock);			if (card->Active >= 0)				card->check_batteries = 1;			else				check_batteries(card);			spin_unlock_bh(&card->lock);		}	init_battery_timer();}/*-------------------------------------------------------------------------------------                            init_battery_timer-----------------------------------------------------------------------------------*/static void init_battery_timer(void){	init_timer(&battery_timer);	battery_timer.function = check_all_batteries;	battery_timer.expires = jiffies + (HZ * 60);	add_timer(&battery_timer);}/*-------------------------------------------------------------------------------------                              del_battery_timer-----------------------------------------------------------------------------------*/static void del_battery_timer(void){	del_timer(&battery_timer);}/*-------------------------------------------------------------------------------------                                mm_revalidate-----------------------------------------------------------------------------------*//* * Note no locks taken out here.  In a worst case scenario, we could drop * a chunk of system memory.  But that should never happen, since validation * happens at open or mount time, when locks are held. * *	That's crap, since doing that while some partitions are opened * or mounted will give you really nasty results. */static int mm_revalidate(struct gendisk *disk){	struct cardinfo *card = disk->private_data;	set_capacity(disk, card->mm_size << 1);	return 0;}/*-------------------------------------------------------------------------------------                            mm_ioctl-----------------------------------------------------------------------------------*/static int mm_ioctl(struct inode *i, struct file *f, unsigned int cmd, unsigned long arg){	if (cmd == HDIO_GETGEO) {		struct cardinfo *card = i->i_bdev->bd_disk->private_data;		int size = card->mm_size * (1024 / MM_HARDSECT);		struct hd_geometry geo;		/*		 * get geometry: we have to fake one...  trim the size to a		 * multiple of 2048 (1M): tell we have 32 sectors, 64 heads,		 * whatever cylinders.		 */		geo.heads     = 64;		geo.sectors   = 32;		geo.start     = get_start_sect(i->i_bdev);		geo.cylinders = size / (geo.heads * geo.sectors);		if (copy_to_user((void __user *) arg, &geo, sizeof(geo)))			return -EFAULT;		return 0;	}

⌨️ 快捷键说明

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