Browse Source

Support emulation mode without real hardware

Suren A. Chilingaryan 8 years ago
parent
commit
631f0929c1
7 changed files with 116 additions and 15 deletions
  1. 8 1
      driver/Makefile
  2. 4 0
      driver/README
  3. 62 14
      driver/base.c
  4. 2 0
      driver/base.h
  5. 6 0
      driver/compat.h
  6. 20 0
      driver/ioctl.c
  7. 14 0
      driver/kmem.c

+ 8 - 1
driver/Makefile

@@ -1,3 +1,4 @@
+CONFIG_MODULE_SIG=n
 
 obj-m := pciDriver.o
 pciDriver-objs := base.o int.o umem.o kmem.o sysfs.o ioctl.o compat.o
@@ -8,6 +9,12 @@ PWD := $(shell pwd)
 
 EXTRA_CFLAGS += -I$(M)/..
 
+ifdef DUMMY_DEVICE
+ifneq ($(DUMMY_DEVICE), 0)
+    EXTRA_CFLAGS += -DPCIDRIVER_DUMMY_DEVICE
+endif
+endif
+
 default:
 	@KERNEL_GCC_VERSION=`cat /proc/version | head -n1 | cut -d " " -f 7` ;\
 	GCC_VERSION=`$(CC) --version | head -n 1 | tr ' ' '\n' | grep -e "[0-9]\+\.[0-9]" | tail -n 1` ;\
@@ -39,7 +46,7 @@ default:
 	build_date=`date "+%Y/%m/%d %H:%M:%S"` ;\
 	build="Built at $$build_date by $$build_user" ;\
 	revision="Revision $$build_revision from $$build_branch by $$build_author at $$build_path, last modification from $$build_lastmod" ;\
-	echo -e "#define PCIDRIVER_BUILD \"$$build\"\\n#define PCIDRIVER_REVISION \"$$revision\"\\n#define PCIDRIVER_CHANGES \"$$build_changes\"\\n" > build.h ;\
+	/bin/echo -e "#define PCIDRIVER_BUILD \"$$build\"\\n#define PCIDRIVER_REVISION \"$$revision\"\\n#define PCIDRIVER_CHANGES \"$$build_changes\"\\n" > build.h ;\
 	$(MAKE) $(CFLAGS) -C $(KERNELDIR) M=$(PWD) CC=$$CC modules
 
 install:

+ 4 - 0
driver/README

@@ -0,0 +1,4 @@
+make <OPTIONS>
+    V=1					verbose mode
+    RELAXED_GCC_CHECK=1			allow difference in micro version of gcc used to compile kernel and pcidriver module
+    DUMMY_DEVICE=1			build dummy device driver (does not require PCI device)

+ 62 - 14
driver/base.c

@@ -210,6 +210,10 @@ MODULE_LICENSE("GPL v2");
 /* Module class */
 static struct class_compat *pcidriver_class;
 
+#ifdef PCIDRIVER_DUMMY_DEVICE
+pcidriver_privdata_t *pcidriver_privdata = NULL;
+#endif /* PCIDRIVER_DUMMY_DEVICE */
+
 /**
  *
  * Called when loading the driver
@@ -217,7 +221,7 @@ static struct class_compat *pcidriver_class;
  */
 static int __init pcidriver_init(void)
 {
-	int err;
+	int err = 0;
 
 	/* Initialize the device count */
 	atomic_set(&pcidriver_deviceCount, 0);
@@ -239,7 +243,11 @@ static int __init pcidriver_init(void)
 
 	/* Register PCI driver. This function returns the number of devices on some
 	 * systems, therefore check for errors as < 0. */
+#ifdef PCIDRIVER_DUMMY_DEVICE
+	if ((err = pcidriver_probe(NULL, NULL)) < 0) {
+#else /* PCIDRIVER_DUMMY_DEVICE */
 	if ((err = pci_register_driver(&pcidriver_driver)) < 0) {
+#endif /* PCIDRIVER_DUMMY_DEVICE */
 		mod_info("Couldn't register PCI driver. Module not loaded.\n");
 		goto init_pcireg_fail;
 	}
@@ -268,7 +276,12 @@ init_alloc_fail:
  */
 static void pcidriver_exit(void)
 {
+#ifdef PCIDRIVER_DUMMY_DEVICE
+	pcidriver_remove(NULL);
+#else
 	pci_unregister_driver(&pcidriver_driver);
+#endif /* PCIDRIVER_DUMMY_DEVICE */
+
 	unregister_chrdev_region(pcidriver_devt, MAXDEVICES);
 
 	if (pcidriver_class != NULL)
@@ -286,12 +299,14 @@ static void pcidriver_exit(void)
  * Will be registered at module init.
  *
  */
+#ifndef PCIDRIVER_DUMMY_DEVICE
 static struct pci_driver pcidriver_driver = {
 	.name = MODNAME,
 	.id_table = pcidriver_ids,
 	.probe = pcidriver_probe,
 	.remove = pcidriver_remove,
 };
+#endif /* ! PCIDRIVER_DUMMY_DEVICE */
 
 /**
  *
@@ -301,7 +316,7 @@ static struct pci_driver pcidriver_driver = {
  */
 static int __devinit pcidriver_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
-	int err;
+	int err = 0;
 	int devno;
 	pcidriver_privdata_t *privdata;
 	int devid;
@@ -311,6 +326,9 @@ static int __devinit pcidriver_probe(struct pci_dev *pdev, const struct pci_devi
 	 *
 	 * However, there is some difference in the interrupt handling functions.
 	 */
+#ifdef PCIDRIVER_DUMMY_DEVICE
+	mod_info("Emulated device\n");
+#else /* PCIDRIVER_DUMMY_DEVICE */
 	if (id->vendor == PCIE_XILINX_VENDOR_ID) {
 	    if (id->device == PCIE_ML605_DEVICE_ID) {
 		mod_info("Found ML605 board at %s\n", dev_name(&pdev->dev));
@@ -323,7 +341,7 @@ static int __devinit pcidriver_probe(struct pci_dev *pdev, const struct pci_devi
 	    }
 	} else {
 	    /* It is something else */
-	    mod_info( "Found unknown board (%x:%x) at %s\n", id->vendor, id->device, dev_name(&pdev->dev));
+	    mod_info("Found unknown board (%x:%x) at %s\n", id->vendor, id->device, dev_name(&pdev->dev));
 	}
 
 	/* Enable the device */
@@ -343,7 +361,8 @@ static int __devinit pcidriver_probe(struct pci_dev *pdev, const struct pci_devi
 
 	/* Set Memory-Write-Invalidate support */
 	if ((err = pci_set_mwi(pdev)) != 0)
-		mod_info("MWI not supported. Continue without enabling MWI.\n");
+	    mod_info("MWI not supported. Continue without enabling MWI.\n");
+#endif /* PCIDRIVER_DUMMY_DEVICE */
 
 	/* Get / Increment the device id */
 	devid = atomic_inc_return(&pcidriver_deviceCount) - 1;
@@ -367,22 +386,31 @@ static int __devinit pcidriver_probe(struct pci_dev *pdev, const struct pci_devi
 	spin_lock_init(&(privdata->umemlist_lock));
 	atomic_set(&privdata->umem_count, 0);
 
-	pci_set_drvdata( pdev, privdata );
+#ifdef PCIDRIVER_DUMMY_DEVICE
+	pcidriver_privdata = privdata;
+#else /* PCIDRIVER_DUMMY_DEVICE */
+	pci_set_drvdata(pdev, privdata);
 	privdata->pdev = pdev;
+#endif /* PCIDRIVER_DUMMY_DEVICE */
 
 	/* Device add to sysfs */
 	devno = MKDEV(MAJOR(pcidriver_devt), MINOR(pcidriver_devt) + devid);
 	privdata->devno = devno;
-	if (pcidriver_class != NULL) {
-		/* FIXME: some error checking missing here */
-		privdata->class_dev = class_device_create(pcidriver_class, NULL, devno, &(pdev->dev), NODENAMEFMT, MINOR(pcidriver_devt) + devid, privdata);
-		class_set_devdata( privdata->class_dev, privdata );
-		mod_info("Device /dev/%s%d added\n",NODENAME,MINOR(pcidriver_devt) + devid);
-	}
 
+	/* FIXME: some error checking missing here */
+#ifdef PCIDRIVER_DUMMY_DEVICE
+	privdata->class_dev = class_device_create(pcidriver_class, NULL, devno, NULL, NODENAMEFMT, MINOR(pcidriver_devt) + devid, privdata);
+#else /* PCIDRIVER_DUMMY_DEVICE */
+	privdata->class_dev = class_device_create(pcidriver_class, NULL, devno, &(pdev->dev), NODENAMEFMT, MINOR(pcidriver_devt) + devid, privdata);
+#endif /* PCIDRIVER_DUMMY_DEVICE */
+	class_set_devdata( privdata->class_dev, privdata );
+	mod_info("Device /dev/%s%d added\n",NODENAME,MINOR(pcidriver_devt) + devid);
+
+#ifndef PCIDRIVER_DUMMY_DEVICE
 	/* Setup mmaped BARs into kernel space */
 	if ((err = pcidriver_probe_irq(privdata)) != 0)
 		goto probe_irq_probe_fail;
+#endif /* ! PCIDRIVER_DUMMY_DEVICE */
 
 	/* Populate sysfs attributes for the class device */
 	/* TODO: correct errorhandling. ewww. must remove the files in reversed order :-( */
@@ -419,15 +447,19 @@ static int __devinit pcidriver_probe(struct pci_dev *pdev, const struct pci_devi
 
 probe_device_create_fail:
 probe_cdevadd_fail:
+#ifndef PCIDRIVER_DUMMY_DEVICE
 probe_irq_probe_fail:
 	pcidriver_irq_unmap_bars(privdata);
+#endif /* ! PCIDRIVER_DUMMY_DEVICE */
 	kfree(privdata);
 probe_nomem:
 	atomic_dec(&pcidriver_deviceCount);
 probe_maxdevices_fail:
+#ifndef PCIDRIVER_DUMMY_DEVICE
 probe_dma_fail:
 	pci_disable_device(pdev);
 probe_pcien_fail:
+#endif /* ! PCIDRIVER_DUMMY_DEVICE */
  	return err;
 }
 
@@ -440,8 +472,13 @@ static void __devexit pcidriver_remove(struct pci_dev *pdev)
 {
 	pcidriver_privdata_t *privdata;
 
+#ifdef PCIDRIVER_DUMMY_DEVICE
+	privdata = pcidriver_privdata;
+	pcidriver_privdata = NULL;
+#else /* PCIDRIVER_DUMMY_DEVICE */
 	/* Get private data from the device */
 	privdata = pci_get_drvdata(pdev);
+#endif /* PCIDRIVER_DUMMY_DEVICE */
 
 	/* Removing sysfs attributes from class device */
 	#define sysfs_attr(name) do { \
@@ -465,9 +502,11 @@ static void __devexit pcidriver_remove(struct pci_dev *pdev)
 	/* Free all allocated kmem buffers before leaving */
 	pcidriver_kmem_free_all( privdata );
 
-#ifdef ENABLE_IRQ
+#ifndef PCIDRIVER_DUMMY_DEVICE
+# ifdef ENABLE_IRQ
 	pcidriver_remove_irq(privdata);
-#endif
+# endif
+#endif /* ! PCIDRIVER_DUMMY_DEVICE */
 
 	/* Removing Character device */
 	cdev_del(&(privdata->cdev));
@@ -478,10 +517,14 @@ static void __devexit pcidriver_remove(struct pci_dev *pdev)
 	/* Releasing privdata */
 	kfree(privdata);
 
+#ifdef PCIDRIVER_DUMMY_DEVICE
+	mod_info("Device at " NODENAMEFMT " removed\n", 0);
+#else /* PCIDRIVER_DUMMY_DEVICE */
 	/* Disabling PCI device */
 	pci_disable_device(pdev);
-
 	mod_info("Device at %s removed\n", dev_name(&pdev->dev));
+#endif /* PCIDRIVER_DUMMY_DEVICE */
+
 }
 
 /*************************************************************************/
@@ -613,6 +656,9 @@ int pcidriver_mmap(struct file *filp, struct vm_area_struct *vma)
 /* Internal driver functions */
 int pcidriver_mmap_pci(pcidriver_privdata_t *privdata, struct vm_area_struct *vmap, int bar)
 {
+#ifdef PCIDRIVER_DUMMY_DEVICE
+	return -ENXIO;
+#else /* PCIDRIVER_DUMMY_DEVICE */
 	int ret = 0;
 	unsigned long bar_addr;
 	unsigned long bar_length, vma_size;
@@ -620,6 +666,7 @@ int pcidriver_mmap_pci(pcidriver_privdata_t *privdata, struct vm_area_struct *vm
 
 	mod_info_dbg("Entering mmap_pci\n");
 
+
 	/* Get info of the BAR to be mapped */
 	bar_addr = pci_resource_start(privdata->pdev, bar);
 	bar_length = pci_resource_len(privdata->pdev, bar);
@@ -680,4 +727,5 @@ int pcidriver_mmap_pci(pcidriver_privdata_t *privdata, struct vm_area_struct *vm
 	}
 
 	return 0;	/* success */
+#endif /* PCIDRIVER_DUMMY_DEVICE */
 }

+ 2 - 0
driver/base.h

@@ -17,7 +17,9 @@ int pcidriver_open(struct inode *inode, struct file *filp );
 int pcidriver_release(struct inode *inode, struct file *filp);
 
 /* prototypes for device operations */
+#ifndef PCIDRIVER_DUMMY_DEVICE
 static struct pci_driver pcidriver_driver;
+#endif /* ! PCIDRIVER_DUMMY_DEVICE */
 static int __devinit pcidriver_probe(struct pci_dev *pdev, const struct pci_device_id *id);
 static void __devexit pcidriver_remove(struct pci_dev *pdev);
 

+ 6 - 0
driver/compat.h

@@ -10,6 +10,12 @@
 #ifndef _COMPAT_H
 #define _COMPAT_H
 
+/*
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)
+# error "Linux 3.0 and latter are supported"
+#endif
+*/
+
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)
 # define __devinit
 # define __devexit

+ 20 - 0
driver/ioctl.c

@@ -96,6 +96,9 @@ static int ioctl_mmap_area(pcidriver_privdata_t *privdata, unsigned long arg)
  */
 static int ioctl_pci_config_read_write(pcidriver_privdata_t *privdata, unsigned int cmd, unsigned long arg)
 {
+#ifdef PCIDRIVER_DUMMY_DEVICE
+	return -ENXIO;
+#else /* PCIDRIVER_DUMMY_DEVICE */
 	int ret;
 	READ_FROM_USER(pci_cfg_cmd, pci_cmd);
 
@@ -133,6 +136,7 @@ static int ioctl_pci_config_read_write(pcidriver_privdata_t *privdata, unsigned
 	WRITE_TO_USER(pci_cfg_cmd, pci_cmd);
 
 	return 0;
+#endif /* PCIDRIVER_DUMMY_DEVICE */
 }
 
 /**
@@ -145,7 +149,14 @@ static int ioctl_pci_config_read_write(pcidriver_privdata_t *privdata, unsigned
 static int ioctl_pci_info(pcidriver_privdata_t *privdata, unsigned long arg)
 {
 	int ret;
+
+#ifdef PCIDRIVER_DUMMY_DEVICE
+	READ_FROM_USER(pcilib_board_info_t, pci_info);
+	memset(&pci_info, 0, sizeof(pci_info));
+	WRITE_TO_USER(pcilib_board_info_t, pci_info);
+#else /* PCIDRIVER_DUMMY_DEVICE */
 	int bar;
+
 	READ_FROM_USER(pcilib_board_info_t, pci_info);
 
 	pci_info.vendor_id = privdata->pdev->vendor;
@@ -168,6 +179,7 @@ static int ioctl_pci_info(pcidriver_privdata_t *privdata, unsigned long arg)
 	}
 
 	WRITE_TO_USER(pcilib_board_info_t, pci_info);
+#endif /* PCIDRIVER_DUMMY_DEVICE */
 
 	return 0;
 }
@@ -443,12 +455,16 @@ static int ioctl_device_state(pcidriver_privdata_t *privdata, unsigned long arg)
 	int ret;
 	pcilib_device_state_t info;
 
+#ifdef PCIDRIVER_DUMMY_DEVICE
+	memset(&info, 0, sizeof(info));
+#else /* PCIDRIVER_DUMMY_DEVICE */
 	info = (pcilib_device_state_t) {
 	    .iommu = iommu_present(privdata->pdev->dev.bus),
 	    .mps = pcidriver_pcie_get_mps(privdata->pdev),
 	    .readrq = pcie_get_readrq(privdata->pdev),
 	    .dma_mask = privdata->pdev->dma_mask
 	};
+#endif /* PCIDRIVER_DUMMY_DEVICE */
 
 
 	WRITE_TO_USER(pcilib_device_state_t, info);
@@ -466,6 +482,7 @@ static int ioctl_device_state(pcidriver_privdata_t *privdata, unsigned long arg)
  */
 static int ioctl_set_dma_mask(pcidriver_privdata_t *privdata, unsigned long arg)
 {
+#ifndef PCIDRIVER_DUMMY_DEVICE
 	int err;
 
 	if ((arg < 24) || (arg > 64))
@@ -476,6 +493,7 @@ static int ioctl_set_dma_mask(pcidriver_privdata_t *privdata, unsigned long arg)
 	    printk(KERN_ERR "pci_set_dma_mask(%lu) failed\n", arg);
 	    return err;
 	}
+#endif /* ! PCIDRIVER_DUMMY_DEVICE */
 	
 	return 0;
 }
@@ -489,6 +507,7 @@ static int ioctl_set_dma_mask(pcidriver_privdata_t *privdata, unsigned long arg)
  */
 static int ioctl_set_mps(pcidriver_privdata_t *privdata, unsigned long arg)
 {
+#ifndef PCIDRIVER_DUMMY_DEVICE
 	int err;
 
 	if ((arg != 128) && (arg != 256) && (arg != 512))
@@ -499,6 +518,7 @@ static int ioctl_set_mps(pcidriver_privdata_t *privdata, unsigned long arg)
 	    printk(KERN_ERR "pcie_set_mps(%lu) failed\n", arg);
 	    return err;
 	}
+#endif /* ! PCIDRIVER_DUMMY_DEVICE */
 	
 	return 0;
 }

+ 14 - 0
driver/kmem.c

@@ -137,7 +137,11 @@ int pcidriver_kmem_alloc(pcidriver_privdata_t *privdata, kmem_handle_t *kmem_han
 	 */
 	switch (kmem_entry->type&PCILIB_KMEM_TYPE_MASK) {
 	 case PCILIB_KMEM_TYPE_CONSISTENT:
+#ifdef PCIDRIVER_DUMMY_DEVICE
+	    retptr = kmalloc( kmem_handle->size, GFP_KERNEL);
+#else /* PCIDRIVER_DUMMY_DEVICE */
 	    retptr = pci_alloc_consistent( privdata->pdev, kmem_handle->size, &(kmem_entry->dma_handle) );
+#endif /* PCIDRIVER_DUMMY_DEVICE */
 	    break;
 	 case PCILIB_KMEM_TYPE_REGION:
 	    retptr = ioremap(kmem_handle->pa,  kmem_handle->size);
@@ -162,6 +166,7 @@ int pcidriver_kmem_alloc(pcidriver_privdata_t *privdata, kmem_handle_t *kmem_han
 	    kmem_entry->dma_handle = 0;
 
 	    if (retptr) {
+#ifndef PCIDRIVER_DUMMY_DEVICE
 	        if (kmem_entry->type == PCILIB_KMEM_TYPE_DMA_S2C_PAGE) {
 		    kmem_entry->direction = PCI_DMA_TODEVICE;
     		    kmem_entry->dma_handle = pci_map_single(privdata->pdev, retptr, kmem_handle->size, PCI_DMA_TODEVICE);
@@ -178,6 +183,7 @@ int pcidriver_kmem_alloc(pcidriver_privdata_t *privdata, kmem_handle_t *kmem_han
 		    
 		    }
 		}
+#endif /* ! PCIDRIVER_DUMMY_DEVICE */
 	    }
 	    
 	    break;
@@ -361,6 +367,7 @@ int pcidriver_kmem_sync_entry( pcidriver_privdata_t *privdata, pcidriver_kmem_en
 	if (kmem_entry->direction == PCI_DMA_NONE)
 		return -EINVAL;
 
+#ifndef PCIDRIVER_DUMMY_DEVICE
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
 	switch (direction) {
 		case PCILIB_KMEM_SYNC_TODEVICE:
@@ -391,6 +398,7 @@ int pcidriver_kmem_sync_entry( pcidriver_privdata_t *privdata, pcidriver_kmem_en
 			return -EINVAL;				/* wrong direction parameter */
 	}
 #endif
+#endif /* ! PCIDRIVER_DUMMY_DEVICE */
 
 	return 0;	/* success */
 }
@@ -480,12 +488,17 @@ int pcidriver_kmem_free_entry(pcidriver_privdata_t *privdata, pcidriver_kmem_ent
 	/* Release DMA memory */
 	switch (kmem_entry->type&PCILIB_KMEM_TYPE_MASK) {
 	 case PCILIB_KMEM_TYPE_CONSISTENT:
+#ifdef PCIDRIVER_DUMMY_DEVICE
+	    kfree((void*)(kmem_entry->cpua));
+#else /* PCIDRIVER_DUMMY_DEVICE */
 	    pci_free_consistent( privdata->pdev, kmem_entry->size, (void *)(kmem_entry->cpua), kmem_entry->dma_handle );
+#endif /* PCIDRIVER_DUMMY_DEVICE */
 	    break;
 	 case PCILIB_KMEM_TYPE_REGION:
 	    iounmap((void *)(kmem_entry->cpua));
 	    break;
 	 case PCILIB_KMEM_TYPE_PAGE:
+#ifndef PCIDRIVER_DUMMY_DEVICE
 	    if (kmem_entry->dma_handle) {
 		if (kmem_entry->type == PCILIB_KMEM_TYPE_DMA_S2C_PAGE) {
 		    pci_unmap_single(privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, PCI_DMA_TODEVICE);
@@ -493,6 +506,7 @@ int pcidriver_kmem_free_entry(pcidriver_privdata_t *privdata, pcidriver_kmem_ent
 		    pci_unmap_single(privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, PCI_DMA_FROMDEVICE);
 		}
 	    }
+#endif /* ! PCIDRIVER_DUMMY_DEVICE */
 	    free_pages((unsigned long)kmem_entry->cpua, get_order(kmem_entry->size));
 	    break;
 	}