static int __init shm_driver_init(void)
{
	int res, i;
	struct device_node *np;
	struct resource r;
	struct proc_dir_entry *pent = NULL;
	struct proc_dir_entry *pstat = NULL;

	np = of_find_compatible_node(NULL, NULL, "mrvl,berlin-shm");
	if (!np)
		goto err_node;
	res = of_address_to_resource(np, 0, &r);
	if (res)
		goto err_reg_device;
	shm_base_cache = r.start;
	shm_size_cache = resource_size(&r);
	res = of_address_to_resource(np, 1, &r);
	if (res)
		goto err_reg_device;
	shm_base_noncache = r.start;
	shm_size_noncache = resource_size(&r);
	of_node_put(np);
	/* Figure out our device number. */
	res =
	    register_chrdev_region(MKDEV(GALOIS_SHM_MAJOR, 0),
				   GALOIS_SHM_MINORS, SHM_DEVICE_NAME);
	if (res < 0) {
		shm_error("unable to get shm device major [%d]\n",
			  GALOIS_SHM_MAJOR);
		goto err_reg_device;
	}
	shm_debug("register cdev device major [%d]\n", GALOIS_SHM_MAJOR);

	/* Now setup cdevs. */
	for (i = 0; i < ARRAY_SIZE(shm_driver_dev_list); i++) {
		res = shm_driver_setup_cdev(shm_driver_dev_list[i].cdev,
					    GALOIS_SHM_MAJOR,
					    shm_driver_dev_list[i].minor,
					    shm_driver_dev_list[i].fops);
		if (res) {
			shm_error("shm_driver_setup_cdev failed in [%d].\n", i);
			goto err_add_device;
		}
		shm_debug("setup cdevs device minor [%d]\n",
			  shm_driver_dev_list[i].minor);
	}

	/* add shm devices to sysfs */
	shm_dev_class = class_create(THIS_MODULE, SHM_DEVICE_NAME);
	if (IS_ERR(shm_dev_class)) {
		shm_error("class_create failed.\n");
		res = -ENODEV;
		goto err_add_device;
	}

	for (i = 0; i < ARRAY_SIZE(shm_driver_dev_list); i++) {
		device_create(shm_dev_class, NULL,
			      MKDEV(GALOIS_SHM_MAJOR,
				    shm_driver_dev_list[i].minor), NULL,
			      shm_driver_dev_list[i].name);
		shm_debug("create device sysfs [%s]\n",
			  shm_driver_dev_list[i].name);
	}

	/* create shm cache device */
	res =
	    shm_device_create(&shm_device, shm_base_cache, shm_size_cache,
			      SHM_DEVICE_THRESHOLD);
	if (res != 0) {
		shm_error("shm_device_create failed.\n");
		goto err_add_device;
	}
	/* init shrinker */
	shm_device->m_shrinker = shm_lowmem_shrink_killer;
	/* create shm cache device */
	res = shm_device_create(&shm_device_noncache, shm_base_noncache,
			      shm_size_noncache, SHM_DEVICE_THRESHOLD);
	if (res != 0) {
		shm_error("shm_device_create failed.\n");
		goto err_add_device;
	}
	/* init shrinker */
	shm_device_noncache->m_shrinker = NULL;
	/* create shm kernel API, need map for noncache and cache device!!! */
	res = MV_SHM_Init(shm_device_noncache, shm_device);
	if (res != 0) {
		shm_error("MV_SHM_Init failed !!!\n");
		goto err_SHM_Init;
	}

	/* create shm device proc file */
	shm_driver_procdir = proc_mkdir(SHM_DEVICE_NAME, NULL);
	if (!shm_driver_procdir) {
		shm_error(KERN_WARNING "Failed to mkdir /proc/%s\n", SHM_DEVICE_NAME);
		return 0;
	}
	proc_create("meminfo", 0, shm_driver_procdir, &meminfo_proc_fops);
	proc_create("baseinfo", 0, shm_driver_procdir, &baseinfo_proc_fops);

	pent = create_proc_entry("detail", 0, shm_driver_procdir);
	if (pent)
		pent->proc_fops = &detail_proc_ops;

	pstat = create_proc_entry("stat", 0, shm_driver_procdir);
	if (pstat)
		pstat->proc_fops = &shm_stat_file_ops;

	task_free_register(&shm_task_nb);
	shm_trace("shm_driver_init OK\n");

	return 0;

 err_SHM_Init:

	shm_trace("shm_driver_init Undo ...\n");

	shm_device_destroy(&shm_device);
	shm_device_destroy(&shm_device_noncache);

	/* del sysfs entries */
	for (i = 0; i < ARRAY_SIZE(shm_driver_dev_list); i++) {
		device_destroy(shm_dev_class,
			       MKDEV(GALOIS_SHM_MAJOR,
				     shm_driver_dev_list[i].minor));
		shm_debug("delete device sysfs [%s]\n",
			  shm_driver_dev_list[i].name);
	}
	class_destroy(shm_dev_class);

 err_add_device:

	for (i = 0; i < ARRAY_SIZE(shm_driver_dev_list); i++) {
		cdev_del(shm_driver_dev_list[i].cdev);
	}
	unregister_chrdev_region(MKDEV(GALOIS_SHM_MAJOR, 0), GALOIS_SHM_MINORS);

err_reg_device:
	 of_node_put(np);
err_node:
	shm_trace("shm_driver_init failed !!! (%d)\n", res);

	return res;
}
static int __init shm_driver_init(void)
{
    int res, i;

	/* Figure out our device number. */
	res = register_chrdev_region(MKDEV(GALOIS_SHM_MAJOR, 0), GALOIS_SHM_MINORS, SHM_DEVICE_NAME);
	if (res < 0) {
		shm_error("unable to get shm device major [%d]\n", GALOIS_SHM_MAJOR);
		goto err_reg_device;
	}
	shm_debug("register cdev device major [%d]\n", GALOIS_SHM_MAJOR);

	/* Now setup cdevs. */
	for (i = 0; i < ARRAY_SIZE(shm_driver_dev_list); i++) {
		res = shm_driver_setup_cdev(shm_driver_dev_list[i].cdev, 
				GALOIS_SHM_MAJOR, shm_driver_dev_list[i].minor, shm_driver_dev_list[i].fops);
		if (res) {
			shm_error("shm_driver_setup_cdev failed in [%d].\n", i);
			goto err_add_device;
		}
		shm_debug("setup cdevs device minor [%d]\n", shm_driver_dev_list[i].minor);
	}

	/* add shm devices to sysfs */
	shm_dev_class = class_create(THIS_MODULE, SHM_DEVICE_NAME);
	if (IS_ERR(shm_dev_class)) {
		shm_error("class_create failed.\n");
		res = -ENODEV;
		goto err_add_device;
	}
	
	for (i = 0; i < ARRAY_SIZE(shm_driver_dev_list); i++) {
		device_create(shm_dev_class, NULL, 
				MKDEV(GALOIS_SHM_MAJOR, shm_driver_dev_list[i].minor), 
				NULL, shm_driver_dev_list[i].name);
	    shm_debug("create device sysfs [%s]\n", shm_driver_dev_list[i].name);
	}

	/* create shm device*/
    res = shm_device_create(&shm_device, shm_base, shm_size, SHM_DEVICE_THRESHOLD);
    if (res != 0) {
        shm_error("shm_device_create failed.\n");
        goto err_add_device;
    }

    /* create shm kernel API */
    res = MV_SHM_Init(shm_device);
    if (res != 0) {
        shm_error("MV_SHM_Init failed !!!\n");
        goto err_SHM_Init;
    }
    
	/* create shm device proc file*/
	shm_driver_procdir = proc_mkdir(SHM_DEVICE_NAME, NULL);
	shm_driver_procdir->owner = THIS_MODULE;
    create_proc_read_entry(SHM_DEVICE_PROCFILE_MEMINFO, 0, shm_driver_procdir, read_proc_meminfo, NULL);
    create_proc_read_entry(SHM_DEVICE_PROCFILE_BASEINFO, 0, shm_driver_procdir, read_proc_baseinfo, NULL);
    create_proc_read_entry(SHM_DEVICE_PROCFILE_DETAIL, 0, shm_driver_procdir, read_proc_detail, NULL);

	shm_trace("shm_driver_init OK\n");
    
	return 0;

err_SHM_Init:
    
    shm_trace("shm_driver_init Undo ...\n");
       
    shm_device_destroy(&shm_device);

	/* del sysfs entries */	
	for (i = 0; i < ARRAY_SIZE(shm_driver_dev_list); i++) {
		device_destroy(shm_dev_class, MKDEV(GALOIS_SHM_MAJOR, shm_driver_dev_list[i].minor));
		shm_debug("delete device sysfs [%s]\n", shm_driver_dev_list[i].name);
	}
	class_destroy(shm_dev_class);
	
err_add_device:
    
	for (i = 0; i < ARRAY_SIZE(shm_driver_dev_list); i++) {
		cdev_del(shm_driver_dev_list[i].cdev);
	}
	unregister_chrdev_region(MKDEV(GALOIS_SHM_MAJOR, 0), GALOIS_SHM_MINORS);

err_reg_device:
    
	shm_trace("shm_driver_init failed !!! (%d)\n", res);

	return res;
}