📄 umem.c
字号:
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 + -