mapping of PCI memory to user space not working with uio.c ?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




Hello,

I need some help.

I'm writing a user space driver for a PCI board.
The kernel part is working well ... all infos in sysfs are correct.

The mappings of the memories behind the BARs are "working" ... but the returned addresses are not valid.

Is it possible that the call remap_pfn_range used in uio.c are not working with PCI memory ??

I have attached the mapping procedure of the user space and the kernel part.

The mapping of BAR[2] (it's kernel memory) is valid ...


Best Regards

--Armin
/*
 * UIO can CAN L2 PCI
 *
 * (C) Armin Steinhoff <as@xxxxxxxxxxxxxxxxxxxxxxxx>
 * (C) 2007 Hans J. Koch <hjk@xxxxxxxxxxxxx>
 * Original code (C) 2005 Benedikt Spranger <b.spranger@xxxxxxxxxxxxx>
 *
 * Licensed under GPL version 2 only.
 *
 */

#include <linux/device.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/uio_driver.h>

#include <asm/io.h>

#define DEBUG 1

#define PCI_VENDORID 0x110A
#define PCI_DEVICEID 0x2104
#define INT_QUEUE_SIZE 64

static unsigned char IntIx, * IntQ;
static	void __iomem *ISR; 
static	void __iomem *ICR; 

static irqreturn_t CAN_handler(int irq, struct uio_info *dev_info)
{
	
    // check PITA ICR ...
	if(*((unsigned long *)ICR) & 0x02) // our interrupt ?
	{
		IntQ[IntIx] = *((unsigned char *)ISR);
		IntIx = (IntIx + 1) & 0xF ; // modulo 16

		*((unsigned long *)ICR) = 0x02; // confirm interrupt 
		return(IRQ_HANDLED);
	}
	else
		return(IRQ_NONE);

}

static int __devinit ems_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
	struct uio_info *info;
	int err;
	
	info = kzalloc(sizeof(struct uio_info), GFP_KERNEL);
	if (!info)
		return -ENOMEM;

	// if (pci_enable_device(dev)) goto out_free;
	err = pci_enable_device(dev);
	if (err) {
		dev_err(&dev->dev, "%s: pci_enable_device failed: %d\n", __func__, err);
		return err;
	}

	if (pci_request_regions(dev, "uio_ems"))
		goto out_disable;

	info->mem[0].addr = pci_resource_start(dev, 0);
	if (!info->mem[0].addr)
		goto out_release;	
	info->mem[0].size = pci_resource_len(dev, 0);
	info->mem[0].memtype = UIO_MEM_PHYS;
	
	info->mem[0].internal_addr = ioremap(info->mem[0].addr,info->mem[0].size);
	if (!info->mem[0].internal_addr)
		goto out_release;
	
	// disable interrupt at PITA level 
	*( (unsigned long *)( info->mem[0].internal_addr )) &= ~0x20000; // reset Bit 17

	info->mem[1].addr = pci_resource_start(dev, 1);
	if (!info->mem[1].addr)
		goto out_release;	
	info->mem[1].size = pci_resource_len(dev, 1);
	info->mem[1].memtype = UIO_MEM_PHYS;
	
	info->mem[1].internal_addr = ioremap(info->mem[1].addr,info->mem[1].size);
	if (!info->mem[1].internal_addr)
		goto out_release;
	
	// interrupt queue
	info->mem[2].addr = (unsigned long)kmalloc(64, GFP_KERNEL);
	IntQ = (unsigned char * )info->mem[2].addr;
	
	if (!info->mem[2].addr)
		goto out_unmap1;
	
	memset(IntQ, 0x00, 16);
	IntIx = 0;

	info->mem[2].memtype = UIO_MEM_LOGICAL;
	info->mem[2].size = 64;
	
	ISR = info->mem[1].internal_addr + 12 + 0x400;	// interrupt status channel 1
	ICR = info->mem[0].internal_addr;
	*((unsigned long *)ICR) = 0x02; // confirm interrupt 
	
	info->name = "uio_ems";	
	info->version = "0.0.1";
	info->irq = dev->irq;
	info->irq_flags |= IRQF_SHARED;
	info->handler = CAN_handler;

	if (uio_register_device(&dev->dev, info))
		goto out_kfree;

	pci_set_drvdata(dev, info);
	printk("can_pci_probe end\n");
	return 0;
	
out_kfree:	
	kfree((void *)info->mem[2].addr);
out_unmap1:	
	iounmap(info->mem[1].internal_addr);		
	iounmap(info->mem[0].internal_addr);
out_release:
	pci_release_regions(dev);
out_disable:
	pci_disable_device(dev);
	kfree (info);
	printk("CAN_PCI: -ENODEV\n");
	return -ENODEV;
}

static void ems_pci_remove(struct pci_dev *dev)
{
	struct uio_info *info = pci_get_drvdata(dev);

	uio_unregister_device(info);
	pci_release_regions(dev);
	pci_disable_device(dev);
	pci_set_drvdata(dev, NULL);
	iounmap(info->mem[0].internal_addr);
	iounmap(info->mem[1].internal_addr);
	kfree((void *)info->mem[2].addr);
	kfree (info);
}

static struct pci_device_id ems_pci_ids[] __devinitdata = {
	{
		PCI_VENDORID, PCI_DEVICEID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0
	},
	{ 0, }
};

static struct pci_driver ems_pci_driver = {
	.name = "uio_ems",
	.id_table = ems_pci_ids,
	.probe    = ems_pci_probe,
	.remove   = ems_pci_remove,
};

static int __init ems_init_module(void)
{
	int ret;

	ret = pci_register_driver(&ems_pci_driver);

	return ret;
}

static void __exit ems_exit_module(void)
{
	pci_unregister_driver(&ems_pci_driver);
}

module_init(ems_init_module);
module_exit(ems_exit_module);

MODULE_DEVICE_TABLE(pci, ems_pci_ids);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("A. Steinhoff");
int do_mappings(void)
{
	int  size_fd;
	int uio_size;
	
	size_fd = open( UIO_SIZE0, O_RDONLY );
	if( size_fd<0 || uio_fd<0 ) {
		fprintf(stderr,"Can't open UIO file 0...\n");
		return -1;
}
	read( size_fd, uio_size_buf, sizeof(uio_size_buf) );
	uio_size = (int)strtol( uio_size_buf, NULL, 0 );
	BAR[0] = (BYTE *)mmap(NULL, uio_size, PROT_READ | PROT_WRITE, MAP_SHARED, uio_fd, 0);
	if(BAR[0] == MAP_FAILED) perror("BAR0:\n");
	close(size_fd);
	
	size_fd = open( UIO_SIZE1, O_RDONLY );
	if( size_fd<0 ) {
		fprintf(stderr,"Can't open UIO file 1...\n");
		return -1;
}
	read( size_fd, uio_size_buf, sizeof(uio_size_buf) );
	uio_size = (int)strtol( uio_size_buf, NULL, 0 );
	BAR[1] = (BYTE *)mmap(NULL, uio_size, PROT_READ | PROT_WRITE, MAP_SHARED, uio_fd, getpagesize());
	close(size_fd);
	
	size_fd = open( UIO_SIZE2, O_RDONLY );
	if( size_fd<0 ) {
		fprintf(stderr,"Can't open UIO file 2...\n");
		return -1;
}
	read( size_fd, uio_size_buf, sizeof(uio_size_buf) );
	uio_size = (int)strtol( uio_size_buf, NULL, 0 );
	BAR[2] = (BYTE *)mmap(NULL, uio_size, PROT_READ | PROT_WRITE, MAP_SHARED, uio_fd, 2*getpagesize());
	close(size_fd);
	return(0);
}

[Index of Archives]     [RT Stable]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]

  Powered by Linux