This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

AM572x virtual address access error by ioremap

Expert 1385 points
Other Parts Discussed in Thread: AM5728

Hi,

I write a driver to plan to access any  memory  address on AM5728 , and the driver as follow:

/*
 * Copyright(C),2014-2015, All rights reserved.
 * Developed using:  gcc version 4.7.3 20130226 
 * Author: Chang.Qing<chang.qing@advantech.com.cn>
 * Description:
 *  Write value to any physical address of any device.
 * Version: 1.00
 * Last Change: 2016/07/30
 * -------------------------------------------------------------------------------
 * Version history:
 * 1.00  16/07/30  Qing   the first version.
 *
 */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/notifier.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/jiffies.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/sysfs.h>
#include <asm/io.h>

#define PHY_SIZE_LEN	(4)

static struct class *phy2virt_class;
static struct cdev phy2virt_cdev;
static struct device *pdev;
static dev_t dev;
static struct {
u32  value;
u32  phy_addr;
u32 __iomem * virt_addr; 
} Phy2virt_Obj;

static DEFINE_MUTEX(sysfs_lock);

/* string to hex */
static inline unsigned char str2hexnum(unsigned char c)
{
	if (c >= '0' && c <= '9')
		return c - '0';
	if (c >= 'a' && c <= 'f')
		return c - 'a' + 10;
	if (c >= 'A' && c <= 'F')
		return c - 'A' + 10;

	return 0; /* foo */
}
static inline unsigned long str2hex(const unsigned char *str)
{
	unsigned long value = 0;

	while (*str) {
		value = value << 4;
		value |= str2hexnum(*str++);
	}

	return value;
}

/* hex to string */
static inline  char hex2char(unsigned char ch)
{
	if(ch >= 0 && ch <= 9)
		return ch + '0';
	if(ch > 9 && ch < 16)
		return ch + 'A' - 10;

	return 0;
}

static inline void hex2str(unsigned long value , char * str)
{
	int i = 0; 
	unsigned char ch;

	while(i++ <= sizeof(value)){
		ch = value & 0xF;
		*str++ = hex2char(ch);
		value = value >> 4;
	}	
}

/******************* The implement for access these  attributes ******************/
static ssize_t phy2virt_addr_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	ssize_t			status;

	mutex_lock(&sysfs_lock);
	status = sprintf(buf, "0x%x\n", Phy2virt_Obj.phy_addr);
	mutex_unlock(&sysfs_lock);
	return status;
}

static ssize_t phy2virt_addr_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t size)
{
	ssize_t			status;

	mutex_lock(&sysfs_lock);
	printk("########%s size =%d\r\n", buf, size);
	Phy2virt_Obj.phy_addr = str2hex(buf) >> 4;
	Phy2virt_Obj.virt_addr = ioremap(Phy2virt_Obj.phy_addr, PHY_SIZE_LEN);

	printk(" Phy2virt_Obj.phy_addr = %x, Phy2virt_Obj.virt_addr = %x\r\n ",Phy2virt_Obj.phy_addr , Phy2virt_Obj.virt_addr );
	status = size;
	mutex_unlock(&sysfs_lock);
	
	return status;
}
static DEVICE_ATTR(addr, 0644,
		phy2virt_addr_show, phy2virt_addr_store);


static ssize_t phy2virt_value_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	ssize_t			status;
	u32				tmp;

	mutex_lock(&sysfs_lock);
	if(!Phy2virt_Obj.virt_addr){
		status = sprintf(buf, "invalid phy address!\n");
		goto out;
	}			
	
	printk("#####!\r\n"); 
	Phy2virt_Obj.virt_addr = ioremap(Phy2virt_Obj.phy_addr, PHY_SIZE_LEN);
	Phy2virt_Obj.value =*(const volatile u32 *)(Phy2virt_Obj.virt_addr); //readl(Phy2virt_Obj.virt_addr);
	printk("#####12121!\r\n");
	tmp = Phy2virt_Obj.value;

	hex2str(tmp, buf);
	status = sprintf(buf, "0x%s\n", buf);	

out:
	mutex_unlock(&sysfs_lock);
	return status;
}

static ssize_t phy2virt_value_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t size)
{
	ssize_t			status = 1;

	mutex_lock(&sysfs_lock);
	Phy2virt_Obj.value = str2hex(buf);
	printk("#######Phy2virt_Obj.value = %x \r\n", Phy2virt_Obj.value);
	if(!Phy2virt_Obj.virt_addr)
		goto out;

	writel(Phy2virt_Obj.value, Phy2virt_Obj.virt_addr);

	status =  (ssize_t)Phy2virt_Obj.value;
out:
	mutex_unlock(&sysfs_lock);
	return status;
}
static DEVICE_ATTR(value, 0644,
		phy2virt_value_show, phy2virt_value_store);

static struct attribute *phy2virt_attrs[] = {
	&dev_attr_addr.attr,
	&dev_attr_value.attr,
	NULL,
};


static const struct attribute_group phy2virt_group = {
	.attrs = phy2virt_attrs,
	//.is_visible = phy2virt_is_visible,   		/* No  need .*/
};

/* Phy2virt group */
static const struct attribute_group *phy2virt_groups[] = {
	&phy2virt_group,
	NULL
};

static const struct file_operations phy2virt_fops = {
	.owner		= THIS_MODULE,
};

static int __init phy2virt_init(void)
{
	int res;
	
	printk(KERN_INFO "phy2virt driver\n");

	/* dymaic alloc & register a devid */
	res = alloc_chrdev_region(&dev, 0, 1, "phy2virt");
	if (res){
		printk(KERN_ERR "phy2virt: unable to get major %d\n", MAJOR(dev));
		goto out;
	}

	/* Init the cdev. */
	cdev_init(&phy2virt_cdev, &phy2virt_fops);

	/* Add a char device driver */
	if ((res = cdev_add(&phy2virt_cdev, dev, 1)) != 0) {
		printk(KERN_ERR "phy2virt: unable register character device\n");
		goto out_unregister_region;
	}

	/* Create a class */
	phy2virt_class = class_create(THIS_MODULE, "phy2virt");
	if (IS_ERR(phy2virt_class)) {
		res = PTR_ERR(phy2virt_class);
		goto out_unreg_chrdev;
	}

	/* Create a device to sysfs */	
	pdev = device_create_with_groups(phy2virt_class, NULL,
					dev, NULL , phy2virt_groups,
					"phy2virt");
	if (IS_ERR(pdev)) {
		res = PTR_ERR(pdev);
		goto out_unregister_calss;
	}

	Phy2virt_Obj.value = 0;
	Phy2virt_Obj.virt_addr = NULL;
	Phy2virt_Obj.phy_addr = 0;
	return 0;

out_unregister_calss:
	class_destroy(phy2virt_class);
out_unreg_chrdev:
	cdev_del(&phy2virt_cdev);
out_unregister_region:
	unregister_chrdev_region(dev, 1);
out:
	return res;
}
module_init(phy2virt_init);

static void __exit phy2virt_exit(void)
{
	if (pdev) {
		device_unregister(pdev);
		put_device(pdev);
		pdev = NULL;
	}
	class_destroy(phy2virt_class);
	cdev_del(&phy2virt_cdev);
	unregister_chrdev_region(dev, 1);	
}
module_exit(phy2virt_exit);

MODULE_AUTHOR("Qing(chang.qing@advantech.com.cn) ");
MODULE_DESCRIPTION("phy2virt-address test");
MODULE_VERSION("1.0.0");
MODULE_LICENSE("GPL");

But,  When I complete the building,  and insmod the module,

I try to write a value to address  0x88880000(can be any address), but have some kernel print info as follow:

[   79.130899] omap_l3_noc 44000000.ocp: L3 application error: target 5 mod:1 (unclearable)
[   79.142931] omap_l3_noc 44000000.ocp: L3 debug error: target 5 mod:1 (unclearable)

And system is blocked.

When read a value from 0x88880000(can be any address), the system is blocked.

I don't know why? can you give me some suggestion for my driver code?

Thank you very much!

Best Regards

Qing