Update of /cvsroot/gc-linux/linux/drivers/block
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv18564/linux-cvs-2.6.9/drivers/block
Modified Files:
gcn-aram.c
Log Message:
Finished massive changes to ARAM driver. Now uses IRQ for improved I/O
Index: gcn-aram.c
===================================================================
RCS file: /cvsroot/gc-linux/linux/drivers/block/gcn-aram.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- gcn-aram.c 19 Oct 2004 23:47:09 -0000 1.1
+++ gcn-aram.c 9 Jan 2005 23:56:21 -0000 1.2
@@ -23,7 +23,7 @@
#include <linux/module.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
-
+#include <linux/wait.h>
#include <asm/setup.h>
#include <asm/bitops.h>
#include <asm/pgtable.h>
@@ -33,187 +33,201 @@
#include <linux/fcntl.h> /* O_ACCMODE */
#include <linux/hdreg.h> /* HDIO_GETGEO */
+#include <asm/io.h>
+
#define ARAM_MAJOR Z2RAM_MAJOR
-#define TRUE (1)
-#define FALSE (0)
+#define HARD_SECTOR_SIZE 512
//#define ARAM_DBG printk
#define ARAM_DBG(format, arg...); { }
-//#define RAMDISK
-#undef RAMDISK
+#define ARAM_SOUNDMEMORYOFFSET 0
+#define ARAM_BUFFERSIZE (16*1024*1024 - ARAM_SOUNDMEMORYOFFSET)
-#ifdef RAMDISK
-unsigned char *RAMDISKBuffer;
-#define ARAM_BUFFERSIZE 10*1024
-#else
-#define ARAM_BUFFERSIZE 14*1024*1024
-#define ARAM_SOUNDMEMORYOFFSET 1024*1024
- //#define ARAM_BLOCKSIZE 1024
-#endif
+#define AI_DSP_CSR (void* __iomem)0xCC00500A
+#define AI_CSR_PIINT (1<<1)
+#define AI_CSR_ARINT (1<<5)
+#define AI_CSR_ARINTMASK (1<<6)
+#define AI_CSR_DSPINT (1<<7)
+#define AI_CSR_DSPINTMASK (1<<8)
+#define AI_CSR_DMA_STATUS (1<<9)
-static int current_device = -1;
-static spinlock_t aram_lock = SPIN_LOCK_UNLOCKED;
+#define AR_DMA_MMADDR (void* __iomem)0xCC005020
+#define AR_DMA_ARADDR (void* __iomem)0xCC005024
+#define AR_DMA_CNT (void* __iomem)0xCC005028
-extern void flush_cache(void *start, unsigned int len);
+#define ARAM_READ (1 << 31)
+#define ARAM_WRITE 0
+
+#define ARAM_DMA_ALIGNMENT_MASK 0x1F
+
+#define ARAM_IRQ 6
+#define IRQ_PARAM (void*)0xFFFFFFFA
+static spinlock_t aram_lock = SPIN_LOCK_UNLOCKED;
static struct block_device_operations aram_fops;
static struct gendisk *aram_gendisk;
+static struct request_queue *aram_queue;
+static struct request * volatile irq_request;
+static u32 refCount;
-#define AR_DMA_MMADDR_H *(unsigned short*)0xCC005020
-#define AR_DMA_MMADDR_L *(unsigned short*)0xCC005022
-#define AR_DMA_ARADDR_H *(unsigned short*)0xCC005024
-#define AR_DMA_ARADDR_L *(unsigned short*)0xCC005026
-#define AR_DMA_CNT_H *(unsigned short*)0xCC005028
-#define AR_DMA_CNT_L *(unsigned short*)0xCC00502A
-#define AI_DSP_STATUS *(volatile unsigned short*)0xCC00500A
-
-#define ARAM_READ 1
-#define ARAM_WRITE 0
+static inline void ARAM_StartDMA(unsigned long mmAddr, unsigned long arAddr,
+ unsigned long length, unsigned long type)
+{
+ writel(mmAddr,AR_DMA_MMADDR);
+ writel(arAddr,AR_DMA_ARADDR);
+ writel(type | length,AR_DMA_CNT);
+}
-void ARAM_StartDMA(unsigned long mmAddr, unsigned long arAddr,
- unsigned long length, unsigned long type)
+static irqreturn_t aram_irq(int irq,void *dev_id,struct pt_regs *regs)
{
+ unsigned long flags;
+ unsigned long len;
+ struct request *req;
- //printk("ARAM DMA copy -> %08x - %08x - %d %d\n",mmAddr,arAddr,length,type);
- AR_DMA_MMADDR_H = mmAddr >> 16;
- AR_DMA_MMADDR_L = mmAddr & 0xFFFF;
- AR_DMA_ARADDR_H = arAddr >> 16;
- AR_DMA_ARADDR_L = arAddr & 0xFFFF;
- AR_DMA_CNT_H = (type << 15) | (length >> 16);
- AR_DMA_CNT_L = length & 0xFFFF;
+ if (readw(AI_DSP_CSR) & AI_CSR_ARINT) {
+ /* ack the int */
+ local_irq_save(flags);
+ writew(readw(AI_DSP_CSR) | AI_CSR_ARINT,AI_DSP_CSR);
+ local_irq_restore(flags);
+
+ /* now process */
+ spin_lock_irqsave(&aram_lock,flags);
+ if ((req = irq_request)) {
+ len = req->current_nr_sectors << 9;
+ /* invalidate cache on read */
+ if (rq_data_dir(req) == READ) {
+ invalidate_dcache_range(
+ (u32)req->buffer,
+ (u32)req->buffer + len);
+ }
+ /* complete request */
+ if (!end_that_request_first(req,1,
+ req->current_nr_sectors)) {
+ add_disk_randomness(req->rq_disk);
+ end_that_request_last(req);
+ }
+ else {
+ printk(KERN_ERR DEVICE_NAME " device still thinks there are requests but DMA has finished\n");
+ }
+ irq_request = NULL;
+ /* start queue back up */
+ blk_start_queue(aram_queue);
+ }
+ else {
+ printk(KERN_ERR DEVICE_NAME " received an interrupt but no irq_request set\n");
+ }
+ spin_unlock_irqrestore(&aram_lock,flags);
+ /* return handled */
+ return IRQ_HANDLED;
+ }
- // We wait, until DMA finished
- while (AI_DSP_STATUS & 0x200) ;
+ return IRQ_NONE;
}
-/*
- echo YUHUUhello1234567890hello12345678901234567890CCC > /dev/aram
- dd if=/dev/aram
- cat /dev/aram | wc -c
-*/
+
static void do_aram_request(request_queue_t * q)
{
struct request *req;
- blk_stop_queue(q);
- spin_lock(&aram_lock);
-
- while ((req = elv_next_request(q)) != NULL) {
- unsigned long start = req->sector << 9;
- unsigned long len = req->current_nr_sectors << 9;
-
- if (start + len > ARAM_BUFFERSIZE) {
+ unsigned long start;
+ unsigned long len;
+
+ /*unsigned long flags; */
+
+ while ((req = elv_next_request(q))) {
+ /* get length */
+ start = req->sector << 9;
+ len = req->current_nr_sectors << 9;
+
+ if ((start + len) > ARAM_BUFFERSIZE) {
printk(KERN_ERR DEVICE_NAME
- ": bad access: block=%lu, count=%u\n",
- (unsigned long)req->sector,
- req->current_nr_sectors);
+ ": bad access: block=%lu, count=%lu\n",
+ (unsigned long)req->sector,len);
end_request(req, 0);
continue;
}
-#ifdef RAMDISK
- if (rq_data_dir(req) == READ) {
- memcpy(req->buffer, (char *)&RAMDISKBuffer[start], len);
- } else {
- memcpy((char *)&RAMDISKBuffer[start], req->buffer, len);
+ else if (irq_request) { /* already scheduled? */
+ blk_stop_queue(q);
+ return;
}
-#else
+ /* dequeue */
+ blkdev_dequeue_request(req);
+ blk_stop_queue(q);
+ irq_request = req;
+ /* schedule DMA */
if (rq_data_dir(req) == READ) {
- //memset(req->buffer,0,len);
- //flush_dcache_range((unsigned long)req->buffer,(unsigned long)req->buffer + len);
ARAM_StartDMA((unsigned long)req->buffer,
start + ARAM_SOUNDMEMORYOFFSET, len,
ARAM_READ);
- //flush_dcache_range((unsigned long)req->buffer,(unsigned long)req->buffer + len);
- invalidate_dcache_range((unsigned long)req->buffer,
- (unsigned long)req->buffer +
- len);
- } else {
+ }
+ else {
flush_dcache_range((unsigned long)req->buffer,
(unsigned long)req->buffer + len);
ARAM_StartDMA((unsigned long)req->buffer,
start + ARAM_SOUNDMEMORYOFFSET, len,
ARAM_WRITE);
}
-#endif
-
- end_request(req, 1);
+ return;
}
-
- spin_unlock(&aram_lock);
- blk_start_queue(q);
-
}
static int aram_open(struct inode *inode, struct file *filp)
{
+ unsigned long flags;
+
ARAM_DBG("A-RAM Open device\n");
-
- int device;
- int rc = -ENOMEM;
-
- device = iminor(inode);
-
- if (current_device != -1 && current_device != device) {
- rc = -EBUSY;
- goto err_out;
- }
-#ifdef RAMDISK
- if (current_device == -1) {
- current_device = device;
- set_capacity(aram_gendisk, ARAM_BUFFERSIZE >> 9);
- }
-#endif
+ /* only allow a minor of 0 to be opened */
+ if (iminor(inode))
+ return -ENODEV;
+ /* allow multiple people to open this file */
+ spin_lock_irqsave(&aram_lock,flags);
+ ++refCount;
+ spin_unlock_irqrestore(&aram_lock,flags);
return 0;
-
- err_out:
- ARAM_DBG("A-RAM Open device Error %d\n", rc);
-
- return rc;
-
}
-/*
- mkfs.minix /dev/aram
- mount -t minix /dev/aram /mnt/
-
- dd if=/dev/urandom bs=1M count=10 > /mnt/test.bin
- dd if=/dev/urandom bs=1M count=1 > /mnt/test1.bin
+static int aram_release(struct inode *inode, struct file *filp)
+{
+ unsigned long flags;
+ ARAM_DBG("A-RAM Close device\n");
+ /* lower ref count */
+ spin_lock_irqsave(&aram_lock,flags);
+ --refCount;
+ spin_unlock_irqrestore(&aram_lock,flags);
+ return 0;
+}
-
-*/
static int aram_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
+ struct hd_geometry geo;
+
ARAM_DBG("A-RAM IOCTL\n");
-
- if (cmd == HDIO_GETGEO) {
- 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;
+
+ switch (cmd) {
+ case BLKRAGET:
+ case BLKFRAGET:
+ case BLKROGET:
+ case BLKBSZGET:
+ case BLKSSZGET:
+ case BLKSECTGET:
+ case BLKGETSIZE:
+ case BLKGETSIZE64:
+ case BLKFLSBUF:
+ return ioctl_by_bdev(inode->i_bdev,cmd,arg);
+ case HDIO_GETGEO:
+ /* fake the entries */
+ geo.heads = 32;
geo.sectors = 32;
geo.start = 0;
geo.cylinders = ARAM_BUFFERSIZE / (geo.heads * geo.sectors);
-
- if (copy_to_user((void *)arg, &geo, sizeof(geo)))
+ if (copy_to_user((void __user*)arg,&geo,sizeof(geo)))
return -EFAULT;
return 0;
+ default:
+ return -ENOTTY;
}
-
- return -EINVAL;
-}
-
-static int aram_release(struct inode *inode, struct file *filp)
-{
- ARAM_DBG("A-RAM Close device\n");
- if (current_device == -1)
- return 0;
-
- return 0;
}
static int aram_revalidate(struct gendisk *disk)
@@ -230,31 +244,27 @@
.ioctl = aram_ioctl,
};
-static struct request_queue *aram_queue;
-#if 0
-static irqreturn_t aram_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- printk("interrupt received\n");
- return 0;
-}
-#endif
int __init aram_init(void)
{
int ret;
+ unsigned long flags;
- printk("A-Ram Block Device Driver Init\n");
-
- ret = -EBUSY;
- if (register_blkdev(ARAM_MAJOR, DEVICE_NAME))
- goto err;
-
+ /* get the irq */
+ if ((ret=request_irq(ARAM_IRQ,aram_irq,SA_SHIRQ,"ARAM",IRQ_PARAM)))
+ goto out_irq;
+
+ if ((ret=register_blkdev(ARAM_MAJOR, DEVICE_NAME)))
+ goto out_blkdev;
+
ret = -ENOMEM;
aram_gendisk = alloc_disk(1);
if (!aram_gendisk)
goto out_disk;
-
+
+ spin_lock_init(&aram_lock);
+
aram_queue = blk_init_queue(do_aram_request, &aram_lock);
if (!aram_queue)
goto out_queue;
@@ -262,61 +272,60 @@
aram_gendisk->major = ARAM_MAJOR;
aram_gendisk->first_minor = 0;
aram_gendisk->fops = &aram_fops;
- sprintf(aram_gendisk->disk_name, "aram");
+ strcpy(aram_gendisk->disk_name, "aram");
strcpy(aram_gendisk->devfs_name, aram_gendisk->disk_name);
aram_gendisk->queue = aram_queue;
- set_capacity(aram_gendisk, ARAM_BUFFERSIZE >> 9);
+ /* we can only have one segment at a time */
+ blk_queue_max_phys_segments(aram_queue,1);
+ blk_queue_max_hw_segments(aram_queue,1);
+ /* make sectors equal to the pagesize */
+ blk_queue_hardsect_size(aram_queue,HARD_SECTOR_SIZE);
+ /* set the DMA alignment */
+ blk_queue_dma_alignment(aram_queue,ARAM_DMA_ALIGNMENT_MASK);
+
+ set_capacity(aram_gendisk, ARAM_BUFFERSIZE >> 9);
add_disk(aram_gendisk);
- spin_lock_init(&aram_lock);
-
-#if 0
- ret =
- request_irq(5, aram_interrupt, 0, aram_gendisk->disk_name,
- aram_gendisk);
- if (ret) {
- //BBA_DBG(KERN_ERR "%s: unable to get IRQ %d\n", dev->name, dev->irq);
- return ret;
- }
-#endif
-#define AUDIO_DSP_CONTROL *(volatile u_int16_t *)(0xCC00500a)
-#define AI_CSR_ARINTMASK (1<<6)
- AUDIO_DSP_CONTROL &= ~AI_CSR_ARINTMASK;
+ /* lock this since audio driver might be using it */
+ local_irq_save(flags);
+ writew(readw(AI_DSP_CSR) | AI_CSR_ARINTMASK,AI_DSP_CSR);
+ local_irq_restore(flags);
-#ifdef RAMDISK
- RAMDISKBuffer = kmalloc(ARAM_BUFFERSIZE, GFP_KERNEL);
-#endif
+ refCount = 0;
return 0;
- out_queue:
+ out_queue:
+ del_gendisk(aram_gendisk);
put_disk(aram_gendisk);
- out_disk:
+ out_disk:
unregister_blkdev(ARAM_MAJOR, DEVICE_NAME);
- err:
+ out_blkdev:
+ free_irq(ARAM_IRQ,IRQ_PARAM);
+ out_irq:
return ret;
}
void __exit aram_cleanup(void)
{
+ free_irq(ARAM_IRQ,IRQ_PARAM);
blk_unregister_region(MKDEV(ARAM_MAJOR, 0), 256);
+
if (unregister_blkdev(ARAM_MAJOR, DEVICE_NAME) != 0)
printk(KERN_ERR DEVICE_NAME ": unregister of device failed\n");
-
+
del_gendisk(aram_gendisk);
put_disk(aram_gendisk);
blk_cleanup_queue(aram_queue);
-
-#ifdef RAMDISK
- kfree(RAMDISKBuffer);
-#endif
-
+
return;
}
+MODULE_AUTHOR("Todd Jeffreys <todd@...>");
+MODULE_DESCRIPTION("Gamecube ARAM block driver");
MODULE_LICENSE("GPL");
module_init(aram_init);
module_exit(aram_cleanup);
|