diff options
Diffstat (limited to 'drivers/block/umem.c')
-rw-r--r-- | drivers/block/umem.c | 1130 |
1 files changed, 0 insertions, 1130 deletions
diff --git a/drivers/block/umem.c b/drivers/block/umem.c deleted file mode 100644 index 664280f23bee..000000000000 --- a/drivers/block/umem.c +++ /dev/null @@ -1,1130 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * 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 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. - */ - -#undef DEBUG /* #define DEBUG if you want debugging info (pr_debug) */ -#include <linux/fs.h> -#include <linux/bio.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/mman.h> -#include <linux/gfp.h> -#include <linux/ioctl.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/timer.h> -#include <linux/pci.h> -#include <linux/dma-mapping.h> - -#include <linux/fcntl.h> /* O_ACCMODE */ -#include <linux/hdreg.h> /* HDIO_GETGEO */ - -#include "umem.h" - -#include <linux/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_NAME "umem" -#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 0x02 - -module_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 { - struct pci_dev *dev; - - unsigned char __iomem *csr_remap; - 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; - struct bvec_iter current_iter; - - struct request_queue *queue; - - struct mm_page { - dma_addr_t page_dma; - struct mm_dma_desc *desc; - int cnt, headcnt; - struct bio *bio, **biotail; - struct bvec_iter iter; - } 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 timer_list battery_timer; - -static int num_cards; - -static struct gendisk *mm_gendisk[MM_MAXCARDS]; - -static void check_batteries(struct cardinfo *card); - -static int get_userbit(struct cardinfo *card, int bit) -{ - unsigned char led; - - led = readb(card->csr_remap + MEMCTRLCMD_LEDCTRL); - return led & bit; -} - -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; -} - -/* - * 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 -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 - -static void dump_dmastat(struct cardinfo *card, unsigned int dmastat) -{ - dev_printk(KERN_DEBUG, &card->dev->dev, "DMAstat - "); - if (dmastat & DMASCR_ANY_ERR) - printk(KERN_CONT "ANY_ERR "); - if (dmastat & DMASCR_MBE_ERR) - printk(KERN_CONT "MBE_ERR "); - if (dmastat & DMASCR_PARITY_ERR_REP) - printk(KERN_CONT "PARITY_ERR_REP "); - if (dmastat & DMASCR_PARITY_ERR_DET) - printk(KERN_CONT "PARITY_ERR_DET "); - if (dmastat & DMASCR_SYSTEM_ERR_SIG) - printk(KERN_CONT "SYSTEM_ERR_SIG "); - if (dmastat & DMASCR_TARGET_ABT) - printk(KERN_CONT "TARGET_ABT "); - if (dmastat & DMASCR_MASTER_ABT) - printk(KERN_CONT "MASTER_ABT "); - if (dmastat & DMASCR_CHAIN_COMPLETE) - printk(KERN_CONT "CHAIN_COMPLETE "); - if (dmastat & DMASCR_DMA_COMPLETE) - printk(KERN_CONT "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. - * - * 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; -} - -/* - * 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; - struct bio_vec vec; - - bio = card->currentbio; - if (!bio && card->bio) { - card->currentbio = card->bio; - card->current_iter = card->bio->bi_iter; - 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; - - if (card->mm_pages[card->Ready].cnt >= DESC_PER_PAGE) - return 0; - - vec = bio_iter_iovec(bio, card->current_iter); - - dma_handle = dma_map_page(&card->dev->dev, - vec.bv_page, - vec.bv_offset, - vec.bv_len, - bio_op(bio) == REQ_OP_READ ? - DMA_FROM_DEVICE : DMA_TO_DEVICE); - - p = &card->mm_pages[card->Ready]; - desc = &p->desc[p->cnt]; - p->cnt++; - if (p->bio == NULL) - p->iter = card->current_iter; - 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(card->current_iter.bi_sector << 9); - desc->transfer_size = cpu_to_le32(vec.bv_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 (bio_op(bio) == REQ_OP_WRITE) - desc->control_bits |= cpu_to_le32(DMASCR_TRANSFER_READ); - desc->sem_control_bits = desc->control_bits; - - - bio_advance_iter(bio, &card->current_iter, vec.bv_len); - if (!card->current_iter.bi_size) - 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(&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; - struct bio_vec vec; - - if (!(control & DMASCR_DMA_COMPLETE)) { - control = dma_status; - last = 1; - } - - page->headcnt++; - vec = bio_iter_iovec(bio, page->iter); - bio_advance_iter(bio, &page->iter, vec.bv_len); - - if (!page->iter.bi_size) { - page->bio = bio->bi_next; - if (page->bio) - page->iter = page->bio->bi_iter; - } - - dma_unmap_page(&card->dev->dev, desc->data_dma_handle, - vec.bv_len, - (control & DMASCR_TRANSFER_READ) ? - DMA_TO_DEVICE : DMA_FROM_DEVICE); - if (control & DMASCR_HARD_ERROR) { - /* error */ - bio->bi_status = BLK_STS_IOERR; - dev_printk(KERN_WARNING, &card->dev->dev, - "I/O error on sector %d/%d\n", - le32_to_cpu(desc->local_addr)>>9, - le32_to_cpu(desc->transfer_size)); - dump_dmastat(card, control); - } else if (op_is_write(bio_op(bio)) && - 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) { - dev_printk(KERN_INFO, &card->dev->dev, - "memory now initialised\n"); - 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(&card->lock); - - while (return_bio) { - struct bio *bio = return_bio; - - return_bio = bio->bi_next; - bio->bi_next = NULL; - bio_endio(bio); - } -} - -static void mm_unplug(struct blk_plug_cb *cb, bool from_schedule) -{ - struct cardinfo *card = cb->data; - - spin_lock_irq(&card->lock); - activate(card); - spin_unlock_irq(&card->lock); - kfree(cb); -} - -static int mm_check_plugged(struct cardinfo *card) -{ - return !!blk_check_plugged(mm_unplug, card, sizeof(struct blk_plug_cb)); -} - -static blk_qc_t mm_submit_bio(struct bio *bio) -{ - struct cardinfo *card = bio->bi_bdev->bd_disk->private_data; - - pr_debug("mm_make_request %llu %u\n", - (unsigned long long)bio->bi_iter.bi_sector, - bio->bi_iter.bi_size); - - blk_queue_split(&bio); - - spin_lock_irq(&card->lock); - *card->biotail = bio; - bio->bi_next = NULL; - card->biotail = &bio->bi_next; - if (op_is_sync(bio->bi_opf) || !mm_check_plugged(card)) - activate(card); - spin_unlock_irq(&card->lock); - - return BLK_QC_T_NONE; -} - -static irqreturn_t mm_interrupt(int irq, void *__card) -{ - 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) - dev_printk(KERN_ERR, &card->dev->dev, - "Memory access error detected (err count %d)\n", - count); - if (stat & 0x02) - dev_printk(KERN_ERR, &card->dev->dev, - "Multi-bit EDC error\n"); - - dev_printk(KERN_ERR, &card->dev->dev, - "Fault Address 0x%02x%08x, Fault Data 0x%08x%08x\n", - addr_log2, addr_log1, data_log2, data_log1); - dev_printk(KERN_ERR, &card->dev->dev, - "Fault Check 0x%02x, Fault Syndrome 0x%02x\n", - check, syndrome); - - writeb(0, card->csr_remap + ERROR_COUNT); - } - - if (dma_status & DMASCR_PARITY_ERR_REP) { - dev_printk(KERN_ERR, &card->dev->dev, - "PARITY ERROR REPORTED\n"); - 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) { - dev_printk(KERN_ERR, &card->dev->dev, - "PARITY ERROR DETECTED\n"); - 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) { - dev_printk(KERN_ERR, &card->dev->dev, "SYSTEM ERROR\n"); - 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) { - dev_printk(KERN_ERR, &card->dev->dev, "TARGET ABORT\n"); - 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) { - dev_printk(KERN_ERR, &card->dev->dev, "MASTER ABORT\n"); - 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; -} - -/* - * 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); - -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) { - dev_printk(KERN_ERR, &card->dev->dev, - "Battery %d now good\n", battery + 1); - card->battery[battery].warned = 0; - } else - dev_printk(KERN_ERR, &card->dev->dev, - "Battery %d now FAILED\n", 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))) { - dev_printk(KERN_ERR, &card->dev->dev, - "Battery %d still FAILED after 5 hours\n", battery + 1); - card->battery[battery].warned = 1; - - return 1; - } - - return 0; -} - -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) - dev_printk(KERN_DEBUG, &card->dev->dev, - "checking battery status, 1 = %s, 2 = %s\n", - (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(struct timer_list *unused) -{ - 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(); -} - -static void init_battery_timer(void) -{ - timer_setup(&battery_timer, check_all_batteries, 0); - battery_timer.expires = jiffies + (HZ * 60); - add_timer(&battery_timer); -} - -static void del_battery_timer(void) -{ - del_timer(&battery_timer); -} - -/* - * 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; -} - -static int mm_getgeo(struct block_device *bdev, struct hd_geometry *geo) -{ - struct cardinfo *card = bdev->bd_disk->private_data; - int size = card->mm_size * (1024 / MM_HARDSECT); - - /* - * 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->cylinders = size / (geo->heads * geo->sectors); - return 0; -} - -static const struct block_device_operations mm_fops = { - .owner = THIS_MODULE, - .submit_bio = mm_submit_bio, - .getgeo = mm_getgeo, - .revalidate_disk = mm_revalidate, -}; - -static int mm_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) -{ - int ret; - struct cardinfo *card = &cards[num_cards]; - unsigned char mem_present; - unsigned char batt_status; - unsigned int saved_bar, data; - unsigned long csr_base; - unsigned long csr_len; - int magic_number; - static int printed_version; - - if (!printed_version++) - printk(KERN_INFO DRIVER_VERSION " : " DRIVER_DESC "\n"); - - ret = pci_enable_device(dev); - if (ret) - return ret; - - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF8); - pci_set_master(dev); - - card->dev = dev; - - csr_base = pci_resource_start(dev, 0); - csr_len = pci_resource_len(dev, 0); - if (!csr_base || !csr_len) - return -ENODEV; - - dev_printk(KERN_INFO, &dev->dev, - "Micro Memory(tm) controller found (PCI Mem Module (Battery Backup))\n"); - - if (dma_set_mask(&dev->dev, DMA_BIT_MASK(64)) && - dma_set_mask(&dev->dev, DMA_BIT_MASK(32))) { - dev_printk(KERN_WARNING, &dev->dev, "NO suitable DMA found\n"); - return -ENOMEM; - } - - ret = pci_request_regions(dev, DRIVER_NAME); - if (ret) { - dev_printk(KERN_ERR, &card->dev->dev, - "Unable to request memory region\n"); - goto failed_req_csr; - } - - card->csr_remap = ioremap(csr_base, csr_len); - if (!card->csr_remap) { - dev_printk(KERN_ERR, &card->dev->dev, - "Unable to remap memory region\n"); - ret = -ENOMEM; - - goto failed_remap_csr; - } - - dev_printk(KERN_INFO, &card->dev->dev, - "CSR 0x%08lx -> 0x%p (0x%lx)\n", - csr_base, card->csr_remap, csr_len); - - switch (card->dev->device) { - case 0x5415: - card->flags |= UM_FLAG_NO_BYTE_STATUS | UM_FLAG_NO_BATTREG; - magic_number = 0x59; - break; - - case 0x5425: - card->flags |= UM_FLAG_NO_BYTE_STATUS; - magic_number = 0x5C; - break; - - case 0x6155: - card->flags |= UM_FLAG_NO_BYTE_STATUS | - UM_FLAG_NO_BATTREG | UM_FLAG_NO_BATT; - magic_number = 0x99; - break; - - default: - magic_number = 0x100; - break; - } - - if (readb(card->csr_remap + MEMCTRLSTATUS_MAGIC) != magic_number) { - dev_printk(KERN_ERR, &card->dev->dev, "Magic number invalid\n"); - ret = -ENOMEM; - goto failed_magic; - } - - card->mm_pages[0].desc = dma_alloc_coherent(&card->dev->dev, - PAGE_SIZE * 2, &card->mm_pages[0].page_dma, GFP_KERNEL); - card->mm_pages[1].desc = dma_alloc_coherent(&card->dev->dev, - PAGE_SIZE * 2, &card->mm_pages[1].page_dma, GFP_KERNEL); - if (card->mm_pages[0].desc == NULL || - card->mm_pages[1].desc == NULL) { - dev_printk(KERN_ERR, &card->dev->dev, "alloc failed\n"); - ret = -ENOMEM; - goto failed_alloc; - } - reset_page(&card->mm_pages[0]); - reset_page(&card->mm_pages[1]); - card->Ready = 0; /* page 0 is ready */ - card->Active = -1; /* no page is active */ - card->bio = NULL; - card->biotail = &card->bio; - spin_lock_init(&card->lock); - - card->queue = blk_alloc_queue(NUMA_NO_NODE); - if (!card->queue) { - ret = -ENOMEM; - goto failed_alloc; - } - - tasklet_init(&card->tasklet, process_page, (unsigned long)card); - - card->check_batteries = 0; - - mem_present = readb(card->csr_remap + MEMCTRLSTATUS_MEMORY); - switch (mem_present) { - case MEM_128_MB: - card->mm_size = 1024 * 128; - break; - case MEM_256_MB: - card->mm_size = 1024 * 256; - break; - case MEM_512_MB: - card->mm_size = 1024 * 512; - break; - case MEM_1_GB: - card->mm_size = 1024 * 1024; - break; - case MEM_2_GB: - card->mm_size = 1024 * 2048; - break; - default: - card->mm_size = 0; - break; - } - - /* Clear the LED's we control */ - set_led(card, LED_REMOVE, LED_OFF); - set_led(card, LED_FAULT, LED_OFF); - - batt_status = readb(card->csr_remap + MEMCTRLSTATUS_BATTERY); - - card->battery[0].good = !(batt_status & BATTERY_1_FAILURE); - card->battery[1].good = !(batt_status & BATTERY_2_FAILURE); - card->battery[0].last_change = card->battery[1].last_change = jiffies; - - if (card->flags & UM_FLAG_NO_BATT) - dev_printk(KERN_INFO, &card->dev->dev, - "Size %d KB\n", card->mm_size); - else { - dev_printk(KERN_INFO, &card->dev->dev, - "Size %d KB, Battery 1 %s (%s), Battery 2 %s (%s)\n", - card->mm_size, - batt_status & BATTERY_1_DISABLED ? "Disabled" : "Enabled", - card->battery[0].good ? "OK" : "FAILURE", - batt_status & BATTERY_2_DISABLED ? "Disabled" : "Enabled", - card->battery[1].good ? "OK" : "FAILURE"); - - set_fault_to_battery_status(card); - } - - pci_read_config_dword(dev, PCI_BASE_ADDRESS_1, &saved_bar); - data = 0xffffffff; - pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, data); - pci_read_config_dword(dev, PCI_BASE_ADDRESS_1, &data); - pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, saved_bar); - data &= 0xfffffff0; - data = ~data; - data += 1; - - if (request_irq(dev->irq, mm_interrupt, IRQF_SHARED, DRIVER_NAME, - card)) { - dev_printk(KERN_ERR, &card->dev->dev, - "Unable to allocate IRQ\n"); - ret = -ENODEV; - goto failed_req_irq; - } - - dev_printk(KERN_INFO, &card->dev->dev, - "Window size %d bytes, IRQ %d\n", data, dev->irq); - - pci_set_drvdata(dev, card); - - if (pci_write_cmd != 0x0F) /* If not Memory Write & Invalidate */ - pci_write_cmd = 0x07; /* then Memory Write command */ - - if (pci_write_cmd & 0x08) { /* use Memory Write and Invalidate */ - unsigned short cfg_command; - pci_read_config_word(dev, PCI_COMMAND, &cfg_command); - cfg_command |= 0x10; /* Memory Write & Invalidate Enable */ - pci_write_config_word(dev, PCI_COMMAND, cfg_command); - } - pci_cmds = (pci_read_cmd << 28) | (pci_write_cmd << 24); - - num_cards++; - - if (!get_userbit(card, MEMORY_INITIALIZED)) { - dev_printk(KERN_INFO, &card->dev->dev, - "memory NOT initialized. Consider over-writing whole device.\n"); - card->init_size = 0; - } else { - dev_printk(KERN_INFO, &card->dev->dev, - "memory already initialized\n"); - card->init_size = card->mm_size; - } - - /* Enable ECC */ - writeb(EDC_STORE_CORRECT, card->csr_remap + MEMCTRLCMD_ERRCTRL); - - return 0; - - failed_req_irq: - failed_alloc: - if (card->mm_pages[0].desc) - dma_free_coherent(&card->dev->dev, PAGE_SIZE * 2, - card->mm_pages[0].desc, - card->mm_pages[0].page_dma); - if (card->mm_pages[1].desc) - dma_free_coherent(&card->dev->dev, PAGE_SIZE * 2, - card->mm_pages[1].desc, - card->mm_pages[1].page_dma); - failed_magic: - iounmap(card->csr_remap); - failed_remap_csr: - pci_release_regions(dev); - failed_req_csr: - - return ret; -} - -static void mm_pci_remove(struct pci_dev *dev) -{ - struct cardinfo *card = pci_get_drvdata(dev); - - tasklet_kill(&card->tasklet); - free_irq(dev->irq, card); - iounmap(card->csr_remap); - - if (card->mm_pages[0].desc) - dma_free_coherent(&card->dev->dev, PAGE_SIZE * 2, - card->mm_pages[0].desc, - card->mm_pages[0].page_dma); - if (card->mm_pages[1].desc) - dma_free_coherent(&card->dev->dev, PAGE_SIZE * 2, - card->mm_pages[1].desc, - card->mm_pages[1].page_dma); - blk_cleanup_queue(card->queue); - - pci_release_regions(dev); - pci_disable_device(dev); -} - -static const struct pci_device_id mm_pci_ids[] = { - {PCI_DEVICE(PCI_VENDOR_ID_MICRO_MEMORY, PCI_DEVICE_ID_MICRO_MEMORY_5415CN)}, - {PCI_DEVICE(PCI_VENDOR_ID_MICRO_MEMORY, PCI_DEVICE_ID_MICRO_MEMORY_5425CN)}, - {PCI_DEVICE(PCI_VENDOR_ID_MICRO_MEMORY, PCI_DEVICE_ID_MICRO_MEMORY_6155)}, - { - .vendor = 0x8086, - .device = 0xB555, - .subvendor = 0x1332, - .subdevice = 0x5460, - .class = 0x050000, - .class_mask = 0, - }, { /* end: all zeroes */ } -}; - -MODULE_DEVICE_TABLE(pci, mm_pci_ids); - -static struct pci_driver mm_pci_driver = { - .name = DRIVER_NAME, - .id_table = mm_pci_ids, - .probe = mm_pci_probe, - .remove = mm_pci_remove, -}; - -static int __init mm_init(void) -{ - int retval, i; - int err; - - retval = pci_register_driver(&mm_pci_driver); - if (retval) - return -ENOMEM; - - err = major_nr = register_blkdev(0, DRIVER_NAME); - if (err < 0) { - pci_unregister_driver(&mm_pci_driver); - return -EIO; - } - - for (i = 0; i < num_cards; i++) { - mm_gendisk[i] = alloc_disk(1 << MM_SHIFT); - if (!mm_gendisk[i]) - goto out; - } - - for (i = 0; i < num_cards; i++) { - struct gendisk *disk = mm_gendisk[i]; - sprintf(disk->disk_name, "umem%c", 'a'+i); - spin_lock_init(&cards[i].lock); - disk->major = major_nr; - disk->first_minor = i << MM_SHIFT; - disk->fops = &mm_fops; - disk->private_data = &cards[i]; - disk->queue = cards[i].queue; - set_capacity(disk, cards[i].mm_size << 1); - add_disk(disk); - } - - init_battery_timer(); - printk(KERN_INFO "MM: desc_per_page = %ld\n", DESC_PER_PAGE); -/* printk("mm_init: Done. 10-19-01 9:00\n"); */ - return 0; - -out: - pci_unregister_driver(&mm_pci_driver); - unregister_blkdev(major_nr, DRIVER_NAME); - while (i--) - put_disk(mm_gendisk[i]); - return -ENOMEM; -} - -static void __exit mm_cleanup(void) -{ - int i; - - del_battery_timer(); - - for (i = 0; i < num_cards ; i++) { - del_gendisk(mm_gendisk[i]); - put_disk(mm_gendisk[i]); - } - - pci_unregister_driver(&mm_pci_driver); - - unregister_blkdev(major_nr, DRIVER_NAME); -} - -module_init(mm_init); -module_exit(mm_cleanup); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); |