[Cbe-oss-dev] [PATCH] axonram: 1st version

Maxim Shchetynin maxim at de.ibm.com
Tue Feb 27 04:49:05 EST 2007


Hello,

Once more a whole patch with wishes from Christoph Hellwig applied.

========

Subject: cell: driver for DDR2 memory on AXON

From: Maxim Shchetynin <maxim.shchetynin at de.ibm.com>

Signed-off-by: Maxim Shchetynin <maxim.shchetynin at de.ibm.com>

diff -Nuar linux-2.6.20/arch/powerpc/Kconfig
linux-2.6.20-axonram/arch/powerpc/Kconfig
--- linux-2.6.20/arch/powerpc/Kconfig     2007-02-13 20:42:42.000000000
+0100
+++ linux-2.6.20-axonram/arch/powerpc/Kconfig   2007-02-16
01:24:38.000000000 +0100
@@ -727,6 +727,16 @@

        If in doubt, say N here.

+config AXON_RAM
+     tristate "Axon DDR2 memory device driver"
+     depends on PPC_IBM_CELL_BLADE
+     default y
+     help
+       It registers one block device per Axon's DDR2 memory bank found
+       on a system. Block devices are called axonram?, their major and
+       minor numbers are available in /proc/devices, /proc/partitions or
+       in /sys/block/axonram?/dev.
+
 endmenu

 source arch/powerpc/platforms/embedded6xx/Kconfig
diff -Nuar linux-2.6.20/arch/powerpc/sysdev/Makefile
linux-2.6.20-axonram/arch/powerpc/sysdev/Makefile
--- linux-2.6.20/arch/powerpc/sysdev/Makefile   2007-02-13
20:42:40.000000000 +0100
+++ linux-2.6.20-axonram/arch/powerpc/sysdev/Makefile 2007-02-13
20:54:40.000000000 +0100
@@ -13,6 +13,7 @@
 obj-$(CONFIG_FSL_SOC)        += fsl_soc.o
 obj-$(CONFIG_TSI108_BRIDGE)  += tsi108_pci.o tsi108_dev.o
 obj-$(CONFIG_QUICC_ENGINE)   += qe_lib/
+obj-$(CONFIG_AXON_RAM)       += axonram.o

 ifeq ($(CONFIG_PPC_MERGE),y)
 obj-$(CONFIG_PPC_I8259)            += i8259.o
diff -Nuar linux-2.6.20/arch/powerpc/sysdev/axonram.c
linux-2.6.20-axonram/arch/powerpc/sysdev/axonram.c
--- linux-2.6.20/arch/powerpc/sysdev/axonram.c  1970-01-01
01:00:00.000000000 +0100
+++ linux-2.6.20-axonram/arch/powerpc/sysdev/axonram.c      2007-02-16
01:59:59.000000000 +0100
@@ -0,0 +1,253 @@
+/*
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2006
+ *
+ * Author: Maxim Shchetynin <maxim at de.ibm.com>
+ *
+ * Axon DDR2 device driver.
+ * It registers one block device per Axon's DDR2 memory bank found on a
system.
+ * Block devices are called axonram?, their major and minor numbers are
+ * available in /proc/devices, /proc/partitions or in
/sys/block/axonram?/dev.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/bio.h>
+#include <linux/blkdev.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/of_device.h>
+#include <asm/of_platform.h>
+#include <asm/prom.h>
+#include <asm/string.h>
+
+#define AXON_RAM_MODULE_NAME             "axonram"
+#define AXON_RAM_DEVICE_NAME             "axonram"
+#define AXON_RAM_MINORS_PER_DISK         16
+#define AXON_RAM_BLOCK_SHIFT             12    /* block size 4KB */
+#define AXON_RAM_SECTOR_SHIFT                  9     /* sector size 512 */
+
+struct axon_ram_bank {
+     struct of_device  *device;
+     struct gendisk          *disk;
+     unsigned long           ph_addr;
+     unsigned long           io_addr;
+     unsigned long           size;
+};
+
+/**
+ * axon_ram_direct_access - direct_access() method for block device
+ * @device, @sector, @data: see block_device_operations method
+ */
+static int
+axon_ram_direct_access(struct block_device *device, sector_t sector,
+                  unsigned long *data)
+{
+     struct axon_ram_bank *bank = device->bd_disk->private_data;
+     loff_t offset;
+
+     BUG_ON(!bank);
+
+     offset = sector << AXON_RAM_SECTOR_SHIFT;
+     if (offset > bank->size) {
+           dev_err(&bank->device->dev, "Access outside of address
space\n");
+           return -ERANGE;
+     }
+
+     *data = bank->ph_addr + offset;
+
+     return 0;
+}
+
+/**
+ * axon_ram_make_request - make_request() method for block device
+ * @queue, @bio: see blk_queue_make_request()
+ */
+static int
+axon_ram_make_request(struct request_queue *queue, struct bio *bio)
+{
+     struct axon_ram_bank *bank = bio->bi_bdev->bd_disk->private_data;
+     unsigned long phys_mem, phys_end;
+     void *user_mem;
+     unsigned long transfered;
+     struct bio_vec *vec;
+     int i;
+
+     phys_mem = bank->io_addr + (bio->bi_sector << AXON_RAM_SECTOR_SHIFT);
+     phys_end = bank->io_addr + bank->size;
+     transfered = 0;
+     bio_for_each_segment(vec, bio, i) {
+           if (phys_mem + vec->bv_len > phys_end) {
+                 bio_io_error(bio, bio->bi_size);
+                 return -ERANGE;
+           }
+
+           user_mem = page_address(vec->bv_page) + vec->bv_offset;
+           if (bio_data_dir(bio) == READ)
+                 memcpy(user_mem, (void*) phys_mem, vec->bv_len);
+           else
+                 memcpy((void*) phys_mem, user_mem, vec->bv_len);
+
+           phys_mem += vec->bv_len;
+           transfered += vec->bv_len;
+     }
+     bio_endio(bio, transfered, 0);
+
+     return 0;
+}
+
+static struct block_device_operations axon_ram_devops = {
+     .owner            = THIS_MODULE,
+     .direct_access    = axon_ram_direct_access
+};
+
+/**
+ * axon_ram_probe - probe() method for platform driver
+ * @device, @device_id: see of_platform_driver method
+ */
+static int
+axon_ram_probe(struct of_device *device, const struct of_device_id
*device_id)
+{
+     static int axon_ram_bank_id = -1;
+     struct axon_ram_bank *bank;
+     struct resource resource;
+
+     /* There should be a better solution... */
+     axon_ram_bank_id++;
+
+     dev_info(&device->dev, "found %s%d on %s\n",
+                 AXON_RAM_DEVICE_NAME, axon_ram_bank_id,
+                 device->node->full_name);
+
+     bank = kzalloc(sizeof(struct axon_ram_bank), GFP_KERNEL);
+     if (bank == NULL) {
+           dev_err(&device->dev, "Out of memory\n");
+           return -ENOMEM;
+     }
+
+     device->dev.platform_data = (void*) bank;
+
+     if (of_address_to_resource(device->node, 0, &resource) != 0) {
+           dev_err(&device->dev, "Cannot access device tree\n");
+           kfree(bank);
+           return -EFAULT;
+     }
+
+     bank->device = device;
+     bank->size = resource.end - resource.start + 1;
+     bank->ph_addr = resource.start;
+     bank->io_addr = (unsigned long)
+                 __iomem ioremap_flags(bank->ph_addr, bank->size, 0);
+
+     bank->disk = alloc_disk(AXON_RAM_MINORS_PER_DISK);
+     if (bank->disk == NULL) {
+           dev_err(&device->dev, "Cannot register disk\n");
+           kfree(bank);
+           return -EFAULT;
+     }
+
+     sprintf(bank->disk->disk_name, "%s%d",
+                 AXON_RAM_DEVICE_NAME, axon_ram_bank_id);
+     bank->disk->major = register_blkdev(0, bank->disk->disk_name);
+     if (bank->disk->major < 0) {
+           dev_err(&device->dev, "Cannot register block device\n");
+           del_gendisk(bank->disk);
+           kfree(bank);
+           return -EFAULT;
+     }
+
+     bank->disk->first_minor = 0;
+     bank->disk->fops = &axon_ram_devops;
+     bank->disk->queue = blk_alloc_queue(GFP_KERNEL);
+     bank->disk->private_data = bank;
+     bank->disk->driverfs_dev = &device->dev;
+
+     set_capacity(bank->disk, bank->size >> AXON_RAM_SECTOR_SHIFT);
+     blk_queue_make_request(bank->disk->queue, axon_ram_make_request);
+     blk_queue_hardsect_size(bank->disk->queue, 1 <<
AXON_RAM_BLOCK_SHIFT);
+     add_disk(bank->disk);
+
+     return 0;
+}
+
+/**
+ * axon_ram_remove - remove() method for platform driver
+ * @device: see of_platform_driver method
+ */
+static int
+axon_ram_remove(struct of_device *device)
+{
+     struct axon_ram_bank *bank = device->dev.platform_data;
+     int rc;
+
+     BUG_ON(!bank || !bank->disk);
+
+     rc = unregister_blkdev(bank->disk->major, bank->disk->disk_name);
+     del_gendisk(bank->disk);
+
+     if (rc == 0)
+           kfree(bank);
+
+     return rc;
+}
+
+static struct of_device_id axon_ram_device_id[] = {
+     {
+           .type = "dma-memory"
+     },
+     {}
+};
+
+static struct of_platform_driver axon_ram_driver = {
+     .owner            = THIS_MODULE,
+     .name       = AXON_RAM_MODULE_NAME,
+     .match_table      = axon_ram_device_id,
+     .probe            = axon_ram_probe,
+     .remove           = axon_ram_remove
+};
+
+/**
+ * axon_ram_init
+ */
+static int __init
+axon_ram_init(void)
+{
+     return of_register_platform_driver(&axon_ram_driver);
+}
+
+/**
+ * axon_ram_exit
+ */
+static void __exit
+axon_ram_exit(void)
+{
+     of_unregister_platform_driver(&axon_ram_driver);
+}
+
+module_init(axon_ram_init);
+module_exit(axon_ram_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Maxim Shchetynin <maxim at de.ibm.com>");
+MODULE_DESCRIPTION("Axon DDR2 RAM device driver for IBM Cell BE");

Mit freundlichen Grüßen / met vriendelijke groeten / avec regards

Maxim V. Shchetynin
IBM Deutschland Entwicklung GmbH
Linux für Cell BE
Schönaicher Straße 220
71032 Böblingen, Deutschland

Fahr nur so schnell wie dein Schutzengel fliegen kann!




More information about the cbe-oss-dev mailing list