All of lore.kernel.org
 help / color / mirror / Atom feed
* [Xenomai]  Hilscher driver for cifX boards
@ 2013-02-26  9:29 Jerome Poncin
  2013-02-26 11:37 ` Jan Kiszka
  0 siblings, 1 reply; 57+ messages in thread
From: Jerome Poncin @ 2013-02-26  9:29 UTC (permalink / raw)
  To: xenomai

Hello,

I have a problem with driver for Hilscher cifx with IRQ.

All driver run good (I verified in polling mode) but in case I activate 
IRQ the system freeze.

I checked parameters of "rtdm_irq_request" function without success (all 
seems good) ! I tried to see on internet to get some information about 
the use of "rtdm_irq_request", or compare my code with other driver but 
it's not easy...
I give you in attached file my code because I have no idea about my 
problem, and it's really difficult to have some information or trace 
after system freeze...
Do you have an idea about my problem ?

Thank you very much for you help,
-- 

Hilscher France
12, rue du 35ème Régiment d'Aviation
Miniparc du Chêne
69500 BRON
France
Tél. : +33 (0) 4 72 37 98 40
Fax  : +33 (0) 4 78 26 83 27
http://www.hilscher.fr
HILSCHER FRANCE 	Jérôme Poncin
jponcin@hilscher.com
Ingénieur Développement Logiciel
Tél. : +33 (0) 4 72 37 98 44





-------------- next part --------------
/***************************************************************************
 *   Copyright (C) 2013 		                                   		   *
 *   Hilscher France (JP)                                                  *
 *   http://www.hilscher.fr/ 						   					   *
 *                                                                         *
 *   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 of the License, 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.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

/***************************************************************************/

/* Includes */

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

#include <sys/mman.h>

#include <rtdm/rtdm_driver.h>

/***************************************************************************/

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("RTDM board driver for CifX cards");
MODULE_AUTHOR("Hilscher France (JP) <www.hilscher.fr>");

/***************************************************************************/
/*!
*   \addtogroup cifx_pci_Core
*   @{
*/
/***************************************************************************/

/* #define */

#ifndef TRUE
#define TRUE						1		
#endif /* TRUE */

#ifndef FALSE
#define FALSE						0		
#endif /* TRUE */

#ifndef PCI_VENDOR_ID_HILSCHER
	#define PCI_VENDOR_ID_HILSCHER   			0x15CF
#endif

#ifndef PCI_DEVICE_ID_HILSCHER_NETX
	#define PCI_DEVICE_ID_HILSCHER_NETX  		0x0000
#endif

#ifndef PCI_DEVICE_ID_HILSCHER_NETPLC
	#define PCI_DEVICE_ID_HILSCHER_NETPLC  		0x0010
#endif

#ifndef PCI_DEVICE_ID_HILSCHER_NETJACK
	#define PCI_DEVICE_ID_HILSCHER_NETJACK  	0x0020
#endif

#ifndef PCI_SUBDEVICE_ID_NXSB_PCA
	#define PCI_SUBDEVICE_ID_NXSB_PCA  			0x3235
#endif

#ifndef PCI_SUBDEVICE_ID_NXPCA
	#define PCI_SUBDEVICE_ID_NXPCA   			0x3335
#endif

#ifndef PCI_SUBDEVICE_ID_NETPLC_RAM
	#define PCI_SUBDEVICE_ID_NETPLC_RAM  		0x0000
#endif

#ifndef PCI_SUBDEVICE_ID_NETPLC_FLASH
	#define PCI_SUBDEVICE_ID_NETPLC_FLASH   	0x0001
#endif

#ifndef PCI_SUBDEVICE_ID_NETJACK_RAM
	#define PCI_SUBDEVICE_ID_NETJACK_RAM   		0x0000
#endif

#ifndef PCI_SUBDEVICE_ID_NETJACK_FLASH
	#define PCI_SUBDEVICE_ID_NETJACK_FLASH   	0x0001
#endif

#define DPM_HOST_INT_EN0						0xfff0
#define DPM_HOST_INT_STAT0						0xffe0
#define PLX_GPIO_OFFSET        					0x15
#define PLX_TIMING_OFFSET       				0x0a

#define DPM_HOST_INT_MASK						0xe600ffff
#define DPM_HOST_INT_GLOBAL_EN					0x80000000
#define PLX_GPIO_DATA0_MASK     				0x00000004
#define PLX_GPIO_DATA1_MASK     				0x00000020

#define NX_PCA_PCI_8_BIT_DPM_MODE  				0x5431F962
#define NX_PCA_PCI_16_BIT_DPM_MODE 				0x4073F8E2
#define NX_PCA_PCI_32_BIT_DPM_MODE 				0x40824122

/* number of bar */
#define DPM_BAR    								0			/* points to the DPM -> netX, netPLC, netJACK */
#define EXT_MEM_BAR 							1 			/* points to the optional extended memory     */
#define PLX_DPM_BAR 							2 			/* points to the DPM -> netXPLX               */ 
#define PXA_PLX_BAR 							0 			/* timing config register                     */

/* index of io_info structure's memory array */
#define DPM_INDEX     							0 			/* first mapping describes DPM              */
#define EXT_MEM_INDEX 							1			/* second mapping describes extended memory */

#define MAX_MAPS    							2

/* defines for memtype */
#define MEM_PHYS    							1

#define DRIVER_NAME								"rtdm_cifx"
#define PERIPHERAL_NAME							"cifx"
#define PROVIDER_NAME							"Hilscher"

#define CIFX_RTDM_PLX_CARD_NAME     			"netx_plx"  /* name of a NXSB-PCA or NXPCA-PCI card */
#define CIFX_RTDM_CARD_NAME         			"netx"      /* name of a cifX PCI card              */
#define CIFX_RTDM_NETPLC_CARD_NAME  			"netplc"    /* name of a netPLC PCI card            */
#define CIFX_RTDM_NETJACK_CARD_NAME 			"netjack"   /* name of a netJACK PCI card           */

typedef struct {
	uint32_t __iomem 	*plx;
	uint8_t 			dpm_mode;
	uint32_t  			plx_timing;
} pxa_dev_info;

typedef struct {
	uint32_t			addr;
	uint32_t 			size;
	int32_t 			memtype;
	void __iomem 		*internal_addr;
} io_mem;  

typedef struct {
	io_mem				mem[MAX_MAPS];
	int32_t				irq;
	uint8_t 			irq_enable;
	uint8_t 			irq_registered;
	rtdm_irq_t  		irq_handle;
	void				*priv;
} io_info_t;

typedef struct {
	uint32_t			phys_addr;
	void **				virt_addr;
	uint32_t			length;
} io_map_mem;

/***************************************************************************/

/* Prototypes */

static int 	cifx_handler(rtdm_irq_t *irq);
static int 	cifx_pxa_set_plx_timing(struct rtdm_device *info);
static int 	cifx_pxa_get_plx_timing(struct rtdm_device *info);
static int 	cifx_pxa_get_dpm_mode(struct rtdm_device *info);

static int 	cifx_pci_open(struct rtdm_dev_context *context, rtdm_user_info_t * user_info, int oflags);
static int 	cifx_pci_close(struct rtdm_dev_context *context, rtdm_user_info_t * user_info);
static ssize_t  cifx_pci_read(struct rtdm_dev_context *context, rtdm_user_info_t *user_info, void *buf, size_t nbyte);
static ssize_t  cifx_pci_write(struct rtdm_dev_context *context, rtdm_user_info_t * user_info, const void *buf, size_t nbyte);

static int 	cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id);
static void cifx_pci_remove(struct pci_dev *dev);

/***************************************************************************/

/* Local variables */

static 	int32_t 	cifx_num	=	0;


static const struct rtdm_device __initdata cifx_device_tmpl = {
	.struct_version		= RTDM_DEVICE_STRUCT_VER,
	
	.device_flags		= RTDM_NAMED_DEVICE,
	.context_size   	= 0,
	.device_name		= "",

	.open_nrt		= cifx_pci_open,

	.ops = {
		.close_nrt	= cifx_pci_close,

		.read_nrt   = cifx_pci_read,
		.write_nrt  = cifx_pci_write,
		
		.ioctl_rt	= NULL,
		.ioctl_nrt	= NULL,

		.read_rt	= NULL,
		.write_rt	= NULL,
	},

	.device_class		= RTDM_CLASS_EXPERIMENTAL,
	.device_sub_class	= RTDM_SUBCLASS_GENERIC,
	.profile_version	= 1,
	.driver_name		= DRIVER_NAME,
	.driver_version		= RTDM_DRIVER_VER(1, 0, 0),
	.provider_name		= PROVIDER_NAME,
};

static struct pci_device_id cifx_pci_tbl[] = {
	{
		.vendor =	PCI_VENDOR_ID_HILSCHER,
		.device =	PCI_DEVICE_ID_HILSCHER_NETX,
		.subvendor =	0,
		.subdevice =	0,
	},
	{
		.vendor =	PCI_VENDOR_ID_PLX,
		.device =	PCI_DEVICE_ID_PLX_9030,
		.subvendor =	PCI_VENDOR_ID_PLX,
		.subdevice =	PCI_SUBDEVICE_ID_NXSB_PCA,
	},
	{
		.vendor =	PCI_VENDOR_ID_PLX,
		.device =	PCI_DEVICE_ID_PLX_9030,
		.subvendor =	PCI_VENDOR_ID_PLX,
		.subdevice =	PCI_SUBDEVICE_ID_NXPCA,
	},
	{
		.vendor =	PCI_VENDOR_ID_HILSCHER,
		.device =	PCI_DEVICE_ID_HILSCHER_NETPLC,
		.subvendor =	PCI_VENDOR_ID_HILSCHER,
		.subdevice =	PCI_SUBDEVICE_ID_NETPLC_RAM,
	},
	{
		.vendor =	PCI_VENDOR_ID_HILSCHER,
		.device =	PCI_DEVICE_ID_HILSCHER_NETPLC,
		.subvendor =	PCI_VENDOR_ID_HILSCHER,
		.subdevice =	PCI_SUBDEVICE_ID_NETPLC_FLASH,
	},
	{
		.vendor = PCI_VENDOR_ID_HILSCHER,
		.device = PCI_DEVICE_ID_HILSCHER_NETJACK,
		.subvendor =  PCI_VENDOR_ID_HILSCHER,
		.subdevice =  PCI_SUBDEVICE_ID_NETJACK_RAM,
	},
	{
		.vendor = PCI_VENDOR_ID_HILSCHER,
		.device = PCI_DEVICE_ID_HILSCHER_NETJACK,
		.subvendor =  PCI_VENDOR_ID_HILSCHER,
		.subdevice =  PCI_SUBDEVICE_ID_NETJACK_FLASH,
	},
	{ 0, }
};

/* This structure describe the RTDM cifX Driver */
static struct pci_driver cifx_pci_driver = {
	.name		= "cifx",
	.id_table	= cifx_pci_tbl,
	.probe		= cifx_pci_probe,
	.remove		= cifx_pci_remove,
};

/***************************************************************************/

/*****************************************************************************/
/*!
*   \brief  cifx_handler
*
*   \param  [in]	irq  	Resource task pointer
*
*   \return RTDM_IRQ_NONE or RTDM_IRQ_HANDLED
*
*   \note   cifx interrupt handler
*/
/*****************************************************************************/
static inline int cifx_handler(rtdm_irq_t *irq)
{
	struct rtdm_device	*info 			= (struct rtdm_device *)rtdm_irq_get_arg(irq, void);
	io_info_t 			*device_data 	= (io_info_t *) info->device_data;
	
	if (device_data->priv != NULL)
	{
		/* This is a PLX device and cannot produce an IRQ */
		return RTDM_IRQ_NONE;
	} 
	else
	{	
		void __iomem *int_enable_reg = device_data->mem[DPM_INDEX].internal_addr + DPM_HOST_INT_EN0;
		void __iomem *int_status_reg = device_data->mem[DPM_INDEX].internal_addr + DPM_HOST_INT_STAT0;
	
		/* Is one of our interrupts enabled and active ? */
		if (!(ioread32(int_enable_reg) & ioread32(int_status_reg) & DPM_HOST_INT_MASK))
			return IRQ_NONE;
	
		/* Disable interrupt */
		iowrite32(ioread32(int_enable_reg) & ~DPM_HOST_INT_GLOBAL_EN, int_enable_reg);

		return RTDM_IRQ_HANDLED;
	}
}

/*****************************************************************************/
/*!
*   \brief  cifx_pxa_set_plx_timing
*
*   \param  [in]	info  	cifx rtdm device information
*
*   \return 0 (OK) or Error
*
*   \note   Set plx timing
*/
/*****************************************************************************/
static int cifx_pxa_set_plx_timing(struct rtdm_device *info)
{
	pxa_dev_info 	 *pxa_info 	= (pxa_dev_info *) ((io_info_t *)info->device_data)->priv;
	uint32_t __iomem *plx_timing;
	
	if (!pxa_info)
		return -ENODEV;
		
	plx_timing = pxa_info->plx + PLX_TIMING_OFFSET;
	*plx_timing = pxa_info->plx_timing;
	
	return 0;
}

/*****************************************************************************/
/*!
*   \brief  cifx_pxa_get_plx_timing
*
*   \param  [in]	info  	cifx rtdm device information
*
*   \return 0 (OK) or Error
*
*   \note   Get plx timing
*/
/*****************************************************************************/
static int cifx_pxa_get_plx_timing(struct rtdm_device *info)
{
	pxa_dev_info *pxa_info = (pxa_dev_info *) ((io_info_t *)info->device_data)->priv;
	
	if (!pxa_info)
		return -ENODEV;
		
	switch (pxa_info->dpm_mode) 
	{
		case 8:
			pxa_info->plx_timing = NX_PCA_PCI_8_BIT_DPM_MODE;
			break;
		case 16:
			pxa_info->plx_timing = NX_PCA_PCI_16_BIT_DPM_MODE;
			break;
		case 32:
			pxa_info->plx_timing = NX_PCA_PCI_32_BIT_DPM_MODE;
			break;
		default:
			return -EINVAL;
	}
	
	return 0;
}

/*****************************************************************************/
/*!
*   \brief  cifx_pxa_get_dpm_mode
*
*   \param  [in]	info  	cifx rtdm device information
*
*   \return 0 (OK) or Error
*
*   \note   Get dpm mode
*/
/*****************************************************************************/
static int cifx_pxa_get_dpm_mode(struct rtdm_device *info)
{
	pxa_dev_info 		*pxa_info = (pxa_dev_info *) ((io_info_t *)info->device_data)->priv;
	uint32_t __iomem 	*plx_gpio;
	
	if (!pxa_info)
		return -ENODEV;
		
	plx_gpio = pxa_info->plx + PLX_GPIO_OFFSET;
	
	if ((*plx_gpio & PLX_GPIO_DATA0_MASK) && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
		pxa_info->dpm_mode = 8;
	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK) && (*plx_gpio & PLX_GPIO_DATA1_MASK))
		pxa_info->dpm_mode = 32;
	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK) && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
		pxa_info->dpm_mode = 16;
	else
		return -EINVAL;
		
	return 0;
}

/*****************************************************************************/
/*!
*   \brief  cifx_pci_open
*
*   \param  [in]	context  	context
*	\param	[in]	user_info	user information
*	\param	[in]	oflags		flags
*
*   \return 0 (OK) or Error
*
*   \note   Open
*/
/*****************************************************************************/
static int cifx_pci_open(struct rtdm_dev_context *context, rtdm_user_info_t * user_info, int oflags)
{
	struct rtdm_device 		*info = (struct rtdm_device *)context->device;
	int32_t					ret;

	if (oflags == TRUE)
	{
		if (((io_info_t *)info->device_data)->irq_registered == FALSE)
		{	
			if ((ret = rtdm_irq_request(&(((io_info_t *)info->device_data)->irq_handle), ((io_info_t *)info->device_data)->irq, cifx_handler, RTDM_IRQTYPE_SHARED, info->device_name, (void *)info)) != 0)
			{
#ifdef DEBUG
				switch (ret)
				{
					case -EINVAL :
			
						rtdm_printk("cifx rtdm driver error : rtdm_irq_request error : an invalid parameter was passed\n");
						break;
				
					case -EBUSY :
			
						rtdm_printk("cifx rtdm driver error : rtdm_irq_request error : the specified IRQ line is already in use\n");
						break;
		
					default :
			
						rtdm_printk("cifx rtdm driver error : rtdm_irq_request error\n");
						break;
				}				
#endif /* DEBUG */

				return -ENODEV;
			}
			else
			{
				((io_info_t *)info->device_data)->irq_registered = TRUE;
			}
		}
	}

	return 0;
}

/*****************************************************************************/
/*!
*   \brief  cifx_pci_close
*
*   \param  [in]	context  	context
*	\param	[in]	user_info	user information
*
*   \return 0 (OK) or Error
*
*   \note   Close
*/
/*****************************************************************************/
static int cifx_pci_close(struct rtdm_dev_context *context, rtdm_user_info_t * user_info)
{
	struct rtdm_device 		*info = (struct rtdm_device *)context->device;
			
	if (((io_info_t *)info->device_data)->irq_registered == TRUE)
	{
		if (((io_info_t *)info->device_data)->irq_enable == TRUE)
		{
			if (rtdm_irq_disable(&(((io_info_t *)info->device_data)->irq_handle)) != 0)
			{
#ifdef DEBUG
				rtdm_printk("cifx rtdm driver error : rtdm_irq_disable error\n");				
#endif /* DEBUG */
		
				return -ENODEV;
			}
		}
	}

	return 0;
}
	
/*****************************************************************************/
/*!
*   \brief  cifx_pci_read
*
*   \param  [in]	context  	context
*	\param	[in]	user_info	user information
*	\param	[in]	buf	user 	buffer
*	\param	[in]	nbyte		number of byte to read
*
*   \return size read
*
*   \note   Read
*/
/*****************************************************************************/
static ssize_t cifx_pci_read(struct rtdm_dev_context *context, rtdm_user_info_t *user_info, void *buf, size_t nbyte)
{
	struct rtdm_device 		*info = (struct rtdm_device *)context->device;
	
	if (nbyte > sizeof(io_info_t))
	{
#ifdef DEBUG
		rtdm_printk("cifx rtdm driver error : data user size too big\n");
#endif /* DEBUG */
	
		return 0;
	}
	
	if (rtdm_safe_copy_to_user(user_info, buf, ((io_info_t *)info->device_data), nbyte))
	{
#ifdef DEBUG
		rtdm_printk("cifx rtdm driver error : can't copy data from driver\n");
#endif /* DEBUG */
	}

	return nbyte;
}

/*****************************************************************************/
/*!
*   \brief  cifx_pci_write
*
*   \param  [in]	context  	context
*	\param	[in]	user_info	user information
*	\param	[in]	buf	user 	buffer
*	\param	[in]	nbyte		number of byte to read
*
*   \return size read
*
*   \note   Read
*/
/*****************************************************************************/
static ssize_t cifx_pci_write(struct rtdm_dev_context *context, rtdm_user_info_t * user_info, const void *buf, size_t nbyte)
{
	struct rtdm_device 	*info = (struct rtdm_device *)context->device;
	uint8_t				irq_enable;
	io_map_mem			map_mem;
	int					ret;
	
	if (nbyte > sizeof(io_map_mem))
	{
#ifdef DEBUG
		rtdm_printk("cifx rtdm driver error : data user size too big\n");
#endif /* DEBUG */
	
		return 0;
	}

	if (nbyte == sizeof(uint8_t))
	{
		if (rtdm_safe_copy_from_user(user_info, &irq_enable, buf, nbyte))
		{
			nbyte = 0;
							
#ifdef DEBUG
			rtdm_printk("cifx rtdm driver error : can't copy data from driver\n");
#endif /* DEBUG */
		}
		else
		{
			if ((((io_info_t *)info->device_data)->irq_enable) != irq_enable)
			{
				if (((io_info_t *)info->device_data)->irq_registered == TRUE)
				{
					if (irq_enable == TRUE)
					{
						if (rtdm_irq_enable(&(((io_info_t *)info->device_data)->irq_handle)) != 0)
						{
#ifdef DEBUG
							rtdm_printk("cifx rtdm driver error : rtdm_irq_enable error\n");				
#endif /* DEBUG */
					
							return -ENODEV;
						}
					}
					else
					{
						if (rtdm_irq_disable(&(((io_info_t *)info->device_data)->irq_handle)) != 0)
						{
#ifdef DEBUG
							rtdm_printk("cifx rtdm driver error : rtdm_irq_disable error\n");				
#endif /* DEBUG */
					
							return -ENODEV;
						}
					}				
				
					((io_info_t *)info->device_data)->irq_enable = irq_enable;
				}
				else
				{
#ifdef DEBUG
					rtdm_printk("cifx rtdm driver error : try to enable or diable IRQ but not registered\n");				
#endif /* DEBUG */
				}
			}
		}
	}
	else if (nbyte == sizeof(io_map_mem))
	{
		if (rtdm_safe_copy_from_user(user_info, &map_mem, buf, nbyte))
		{
			nbyte = 0;
							
#ifdef DEBUG
			rtdm_printk("cifx rtdm driver error : can't copy data from driver\n");
#endif /* DEBUG */
		}
		else
		{
			if (*map_mem.virt_addr == NULL)
			{
				ret = rtdm_iomap_to_user(user_info, (phys_addr_t)map_mem.phys_addr, (size_t)map_mem.length, (PROT_READ | PROT_WRITE), map_mem.virt_addr, NULL, NULL);
				
				if (ret != 0)
				{
					nbyte = 0;

#ifdef DEBUG					
					switch (ret)
					{
						case -EINVAL :				

								rtdm_printk("cifx rtdm driver error : an invalid start address, size, or destination address was passed\n");				

							break;
							
						case -ENOMEM :				

								rtdm_printk("cifx rtdm driver error : there is insufficient free memory or the limit of memory mapping for the user process was reached\n");				

							break;
							
						case -EAGAIN:		

								rtdm_printk("cifx rtdm driver error : too much memory has been already locked by the user process\n");				
		
							break;
							
						case -EPERM :	

								rtdm_printk("cifx rtdm driver error : an illegal invocation environment is detected\n");				
	
							break;
							
						default :

								rtdm_printk("cifx rtdm driver error : rtdm_safe_copy_from_user error\n");				
			
							break;
					}
#endif /* DEBUG */	
				}
			}	
			else
			{
				ret = rtdm_munmap(user_info, *map_mem.virt_addr, (size_t)map_mem.length);
				
				if (ret != 0)
				{
					nbyte = 0;

#ifdef DEBUG				
					switch (ret)
					{
						case -EINVAL :
					
							rtdm_printk("cifx rtdm driver error : an invalid address or size was passed\n");				
					
							break;
				
						case -EPERM :
					
							rtdm_printk("cifx rtdm driver error : an illegal invocation environment is detected\n");	
					
							break;			
				
						default :
					
							rtdm_printk("cifx rtdm driver error : rtdm_safe_copy_from_user error\n");				
			
							break;
					}
#endif /* DEBUG */
				}
			}
		}	
	}
	else
	{
		nbyte = 0;
	}
	
	return nbyte;
}

/*****************************************************************************/
/*!
*   \brief  cifx_pci_probe
*
*   \param  [in]	dev  		
*	\param	[in]	id			
*
*   \return 0 (OK) or Error
*
*   \note   Open the device. 
*			This function is called when the device shall be opened.
*/
/*****************************************************************************/	
static int cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
	struct rtdm_device 	*info			=	NULL;
	io_info_t			*device_data	=	NULL;	
	int32_t 			bar;
	int32_t				ret;
		
	info = rtdm_malloc(sizeof(struct rtdm_device));
				
	if (info == NULL)
	{
#ifdef DEBUG
		rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
#endif /* DEBUG */

		return -ENOMEM;
	}
	
	if ((ret = pci_enable_device(dev)) != 0)
	{
#ifdef DEBUG
		rtdm_printk("cifx rtdm driver error : pci_enable_device error : %i\n", ret);
#endif /* DEBUG */
 
		goto out_free;
	}
	
	if ((ret = pci_request_regions(dev, DRIVER_NAME)) != 0)
	{
#ifdef DEBUG
		rtdm_printk("cifx rtdm driver error : pci_request_regions error : %i\n", ret);
#endif /* DEBUG */
	
		goto out_disable;
	}
	
	memcpy(info, &cifx_device_tmpl, sizeof(struct rtdm_device));
	
	info->device_id	= id->device;
	snprintf((char *)info->device_name, RTDM_MAX_DEVNAME_LEN, "cifx%i", cifx_num);
	info->proc_name	= info->device_name;
	
	switch (id->device) 
	{
		case PCI_DEVICE_ID_HILSCHER_NETX:
			bar = DPM_BAR;
			info->peripheral_name = CIFX_RTDM_CARD_NAME;
			break;
		case PCI_DEVICE_ID_HILSCHER_NETPLC:
			bar = DPM_BAR;
			info->peripheral_name = CIFX_RTDM_NETPLC_CARD_NAME;
			break;
		case PCI_DEVICE_ID_HILSCHER_NETJACK:
			bar = DPM_BAR;
			info->peripheral_name = CIFX_RTDM_NETJACK_CARD_NAME;
			break;
		default:
			bar = PLX_DPM_BAR;
			info->peripheral_name = CIFX_RTDM_PLX_CARD_NAME;
			break;
	}
	
	info->device_data = NULL;
	device_data = rtdm_malloc(sizeof(io_info_t));
	
	if (device_data == NULL)
	{
#ifdef DEBUG
		rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
#endif /* DEBUG */

		goto out_release;
	}
	
	memset(device_data, 0, sizeof(io_info_t));
	
	/* BAR 0 or 2 points to the card's dual port memory */
	device_data->mem[DPM_INDEX].addr = pci_resource_start(dev, bar);
  
	if (device_data->mem[DPM_INDEX].addr == 0)
	{
#ifdef DEBUG
		rtdm_printk("cifx rtdm driver error : pci_resource_start error\n");
#endif /* DEBUG */

		goto out_release;
	}
	
	device_data->mem[DPM_INDEX].internal_addr = ioremap_nocache(pci_resource_start(dev, bar), pci_resource_len(dev, bar));
    
	if (device_data->mem[DPM_INDEX].internal_addr == 0)
	{
#ifdef DEBUG
		rtdm_printk("cifx rtdm driver error : ioremap_nocache error\n");
#endif /* DEBUG */
	
		goto out_release;
	}
	
  	dev_info(&dev->dev, "DPM at %08lX\n", (long unsigned int)device_data->mem[DPM_INDEX].addr);
  	device_data->mem[DPM_INDEX].size = pci_resource_len(dev, bar);
  	device_data->mem[DPM_INDEX].memtype = MEM_PHYS;
  
	/* map extended mem (BAR 1 points to the extended memory) */
 	device_data->mem[EXT_MEM_INDEX].addr = pci_resource_start(dev, EXT_MEM_BAR);
 
	/* extended memory is optional, so don't care if it is not present */
	if (device_data->mem[EXT_MEM_INDEX].addr != 0)
	{
		device_data->mem[EXT_MEM_INDEX].internal_addr = ioremap_nocache(pci_resource_start(dev, EXT_MEM_BAR), pci_resource_len(dev, EXT_MEM_BAR));  
		
		if (device_data->mem[EXT_MEM_INDEX].internal_addr == 0)
		{
#ifdef DEBUG
			rtdm_printk("cifx rtdm driver error : ioremap_nocache error\n");
#endif /* DEBUG */			
		
			goto out_unmap;
		}
		
		dev_info(&dev->dev, "extended memory at %08lX\n", (long unsigned int)device_data->mem[EXT_MEM_INDEX].addr);
		device_data->mem[EXT_MEM_INDEX].size    = pci_resource_len(dev, EXT_MEM_BAR);
		device_data->mem[EXT_MEM_INDEX].memtype = MEM_PHYS;
	}
  	
	if ((id->device == PCI_DEVICE_ID_HILSCHER_NETX) 
	||	(id->device == PCI_DEVICE_ID_HILSCHER_NETPLC) 
	||	(id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)) 
	{
		/* make sure all interrupts are disabled */
		iowrite32(0, device_data->mem[DPM_INDEX].internal_addr + DPM_HOST_INT_EN0);
		device_data->priv = NULL;
	} 
	else if (id->subdevice == PCI_SUBDEVICE_ID_NXPCA) 
	{
		/* map PLX registers */
		pxa_dev_info *pxa_info = (pxa_dev_info *)rtdm_malloc(sizeof(pxa_dev_info));
		
		if (pxa_info == NULL)
		{
#ifdef DEBUG
			rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
#endif /* DEBUG */	

			goto out_unmap;
		}
		
		device_data->priv = pxa_info;
		
		/* set PXA PLX Timings */
		pxa_info->plx = ioremap_nocache(pci_resource_start(dev, PXA_PLX_BAR), pci_resource_len(dev, PXA_PLX_BAR));
		
		if (!pxa_info->plx)
			goto out_unmap;
		if (cifx_pxa_get_dpm_mode(info))
			goto out_unmap_plx;
		if (cifx_pxa_get_plx_timing(info))
			goto out_unmap_plx;
		if (cifx_pxa_set_plx_timing(info))
			goto out_unmap_plx;
	} 
	else 
	{
		pxa_dev_info *pxa_info = (pxa_dev_info *)rtdm_malloc(sizeof(pxa_dev_info));
		
		if (pxa_info == NULL)
		{
#ifdef DEBUG
			rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
#endif /* DEBUG */

			goto out_free_pxa;
		}
		
		pxa_info->plx = NULL;
		pxa_info->plx_timing = 0;
		pxa_info->dpm_mode = 0;
		device_data->priv = pxa_info;
	}
	
	device_data->irq = dev->irq;
	device_data->irq_enable = FALSE;
	device_data->irq_registered = FALSE;
	
	info->device_data = device_data;

	if ((ret = rtdm_dev_register(info)) != 0)
	{
#ifdef DEBUG
		switch(ret)
		{
			case -EINVAL :

				rtdm_printk("cifx rtdm driver error : rtdm_dev_register error : the device structure contains invalid entries. Check kernel log in this case\n");
				break;
				
			case -ENOMEM :
			
				rtdm_printk("cifx rtdm driver error : rtdm_dev_register error : the context for an exclusive device cannot be allocated\n");
				break;
				
			case -EEXIST :
			
				rtdm_printk("cifx rtdm driver error : rtdm_dev_register error : the specified device name of protocol ID is already in use\n");
				break;
				
			case -EAGAIN :
			
				rtdm_printk("cifx rtdm driver error : rtdm_dev_register error : some /proc entry cannot be created\n");
				break;	
		
			default :
			
				rtdm_printk("cifx rtdm driver error : rtdm_dev_register error\n");
				break;
		}
#endif /* DEBUG */
	
		if (id->subdevice != PCI_SUBDEVICE_ID_NXPCA)
			goto out_unmap;
		else
			goto out_unmap_plx;
	}
	
	pci_set_drvdata(dev, info);
	
	if (id->device == PCI_DEVICE_ID_HILSCHER_NETX)
		dev_info(&dev->dev, "registered CifX card\n");
	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
		dev_info(&dev->dev, "registered netPLC card\n");
	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)
		dev_info(&dev->dev, "registered netJACK card\n");
	else if (id->subdevice == PCI_SUBDEVICE_ID_NXSB_PCA)
		dev_info(&dev->dev,	"registered NXSB-PCA adapter card\n");
	else 
	{
		pxa_dev_info *pxa_info = (pxa_dev_info *)((io_info_t *)info->device_data)->priv;
		dev_info(&dev->dev, "registered NXPCA-PCI adapter card in %d bit mode\n", pxa_info->dpm_mode);
	}
		
	cifx_num++;
	
	return 0;

out_unmap_plx:
	iounmap(((pxa_dev_info *)(((io_info_t *)info->device_data)->priv))->plx);
	
out_free_pxa:
	rtdm_free(((io_info_t *)info->device_data)->priv);
	
out_unmap:
	iounmap(((io_info_t *)info->device_data)->mem[DPM_INDEX].internal_addr);
	if (((io_info_t *)info->device_data)->mem[EXT_MEM_INDEX].internal_addr != 0)
		iounmap(((io_info_t *)info->device_data)->mem[EXT_MEM_INDEX].internal_addr);
out_release:
	pci_release_regions(dev);
	
out_disable:
	pci_disable_device(dev);
	
out_free:
	if (info->device_data != NULL)
	{
		rtdm_free(info->device_data);
	}
	rtdm_free(info);
	
	return -ENODEV;
}

/*****************************************************************************/
/*!
*   \brief  cifx_pci_remove
*
*   \param  [in]	dev  			
*
*   \return None
*
*   \note   Close the device. 
*			This function is called when the device shall be closed.
*/
/*****************************************************************************/	
static void cifx_pci_remove(struct pci_dev *dev)
{
	struct rtdm_device 	*info 			= pci_get_drvdata(dev);
	io_info_t			*device_data 	= (io_info_t *)info->device_data;	
	pxa_dev_info 		*pxa_info 		= (pxa_dev_info *)device_data->priv;
	int32_t				ret;

	if (info->device_data == NULL)
	{
#ifdef DEBUG
		rtdm_printk("cifx rtdm driver error : device_data NULL pointer\n");
#endif /* DEBUG */
		return;
	}
	
	if (pxa_info != NULL) 
	{
		/* Disable all interrupts */
		iowrite32(0, device_data->mem[DPM_INDEX].internal_addr + DPM_HOST_INT_EN0);
	
		if (pxa_info->plx != NULL)
			iounmap((void *)pxa_info->plx);

		rtdm_free((void *)pxa_info);		
	}
	
	if ((ret = rtdm_dev_unregister(info, 1000)) != 0)
	{
#ifdef DEBUG
		switch(ret)
		{
			case -ENODEV :
			
				rtdm_printk("cifx rtdm driver error : rtdm_dev_unregister error : the device was not registered\n");
				break;
				
			case -EAGAIN :
			
				rtdm_printk("cifx rtdm driver error : rtdm_dev_unregister error : the device is busy with open instances and 0 has been passed for poll_delay\n");
				break;			
			
			default :
			
				rtdm_printk("cifx rtdm driver error : rtdm_dev_unregister error\n");
				break;	
		}
#endif /* DEBUG */

		return;
	}

	pci_release_regions(dev);
	pci_disable_device(dev);
	pci_set_drvdata(dev, NULL);
	
	iounmap(device_data->mem[DPM_INDEX].internal_addr);
	if (device_data->mem[EXT_MEM_INDEX].internal_addr != 0)
		iounmap(device_data->mem[EXT_MEM_INDEX].internal_addr);

	rtdm_free(info->device_data);
	rtdm_free(info);
	
	if (cifx_num > 0)
		cifx_num--;
}

/*****************************************************************************/
/*!
*   \brief  cifx_pci_init			
*
*   \return None
*
*   \note   It simply registers the RTDM device. 
*			This function is called when the module is loaded.
*/
/*****************************************************************************/	
static int __init cifx_pci_init(void)
{
	return pci_register_driver(&cifx_pci_driver);
}

/*****************************************************************************/
/*!
*   \brief  cifx_pci_exit			
*
*   \return None
*
*   \note   It unregister the RTDM device. 
*			This function is called when the module is unloaded.
*/
/*****************************************************************************/	
static void __exit cifx_pci_exit(void)
{
	pci_unregister_driver(&cifx_pci_driver);
}

/*****************************************************************************/
/*! \}     cifx_pci_Core	                   				     			 */
/*****************************************************************************/

module_init(cifx_pci_init);
module_exit(cifx_pci_exit);

/* End of file : cifx_pci.c */

^ permalink raw reply	[flat|nested] 57+ messages in thread
* [Xenomai] Hilscher driver for cifX boards
@ 2013-02-12 11:37 Stéphane LOS
  2013-02-12 11:51 ` Jan Kiszka
  0 siblings, 1 reply; 57+ messages in thread
From: Stéphane LOS @ 2013-02-12 11:37 UTC (permalink / raw)
  To: Xenomai

Hello there,

It seems we have managed to build an RTDM module and we can insmod it 
and it shows up in the named devices list.

If we forget to rmmod the module, the kernel crashes when stopping or 
rebooting.

Is there a preferred method to insmod / rmmod modules automatically with 
Xenomai ?

Thank you for your kind support.

-- 
Best Regards,
Cordialement,

Stéphane LOS
slos@hilscher.com
Support technique

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Hilscher France
12, rue du 35ème Régiment d'Aviation
Miniparc du Chêne
69500 BRON
France
Tél. : +33 (0) 4 72 37 98 40
Fax  : +33 (0) 4 78 26 83 27
http ://www.hilscher.fr
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~



^ permalink raw reply	[flat|nested] 57+ messages in thread
* [Xenomai] Hilscher driver for cifX boards
@ 2013-02-07 14:53 Stéphane LOS
  2013-02-07 16:11 ` Gilles Chanteperdrix
  0 siblings, 1 reply; 57+ messages in thread
From: Stéphane LOS @ 2013-02-07 14:53 UTC (permalink / raw)
  To: xenomai

Hello Sirs,

Hilscher is offering a Linux driver based on UIO for cifX boards.

In my understanding, down to 1ms cycle time, a PREEMPT RT solution 
should be enough.

The cifX boards can manage with bus cycle times down to 250µs like with 
EtherCAT or Sercos III firmwares.

So it seems in that cases that using Xenomai would be the way to go.
I suppose that it would be needed to modify or change the existing 
driver but I can't figure out how things (Xenomai / RTDM / UIO) fit 
together.

UIO is the kernel module that allows the mapping of the board memory to 
user space.

The cifX driver uses the libpciaccess to pick up the board and retrieve 
some board information from UIO before the mapping.
Then it uses pthread and rt functions when accessing the board.

Since UIO and libpciaccess are only used during the initialization, is 
it a problem for a Xenomai application ?

We have setup a Xenomai system and tried to compile the user land 
library with Xenomai options and flags and it seems we have been successful.
The driver should be using the POSIX skin of Xenomai if we have been lucky.

I can't see why we would need RTDM. Any hint please ?

I am an absolute beginner in the Xenomai arena, don't throw me to the 
lions...

-- 
Best Regards,
Cordialement,

Stéphane LOS
slos@hilscher.com
Support technique

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Hilscher France
12, rue du 35ème Régiment d'Aviation
Miniparc du Chêne
69500 BRON
France
Tél. : +33 (0) 4 72 37 98 40
Fax  : +33 (0) 4 78 26 83 27
http ://www.hilscher.fr
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~



^ permalink raw reply	[flat|nested] 57+ messages in thread

end of thread, other threads:[~2013-03-19 13:42 UTC | newest]

Thread overview: 57+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-02-26  9:29 [Xenomai] Hilscher driver for cifX boards Jerome Poncin
2013-02-26 11:37 ` Jan Kiszka
2013-02-26 14:25   ` Jerome Poncin
2013-02-26 14:28     ` Jan Kiszka
2013-02-28  8:15       ` Jerome Poncin
2013-02-28 11:31         ` Jan Kiszka
2013-02-28 12:08           ` Jerome Poncin
2013-03-01 13:56             ` Jerome Poncin
2013-03-01 17:02               ` Jan Kiszka
2013-03-01 20:06               ` Gilles Chanteperdrix
2013-03-04  9:13               ` Jerome Poncin
2013-03-04 21:08                 ` Gilles Chanteperdrix
2013-03-05 10:45                   ` Jerome Poncin
2013-03-05 11:26                     ` Jan Kiszka
2013-03-05 12:21                       ` Gilles Chanteperdrix
2013-03-05 12:30                       ` Gilles Chanteperdrix
2013-03-05 15:42                       ` Jerome Poncin
2013-03-05 19:41                         ` Gilles Chanteperdrix
2013-03-06  8:10                           ` Jerome Poncin
2013-03-06  8:19                             ` Gilles Chanteperdrix
2013-03-06  8:55                               ` Jerome Poncin
2013-03-06 10:33                               ` Jerome Poncin
2013-03-06 12:04                                 ` Gilles Chanteperdrix
2013-03-06 13:58                                   ` Jerome Poncin
2013-03-06 15:28                                     ` Jan Kiszka
2013-03-06 21:05                                       ` Gilles Chanteperdrix
2013-03-07 15:33                                         ` Jerome Poncin
2013-03-08 10:17                                           ` Jerome Poncin
2013-03-08 12:22                                             ` Gilles Chanteperdrix
2013-03-12  9:10                                               ` Jerome Poncin
2013-03-12 12:21                                                 ` Gilles Chanteperdrix
2013-03-12 15:27                                                   ` Jerome Poncin
2013-03-12 19:38                                                     ` Gilles Chanteperdrix
2013-03-13 11:08                                                       ` Jerome Poncin
2013-03-15  9:09                                                         ` Jerome Poncin
2013-03-15 11:07                                                           ` Jan Kiszka
2013-03-15 13:04                                                             ` Jerome Poncin
2013-03-15 13:24                                                               ` Jan Kiszka
2013-03-18 10:02                                                                 ` Jerome Poncin
2013-03-19 13:42                                                                   ` Jerome Poncin
2013-03-06 20:42                                     ` Gilles Chanteperdrix
  -- strict thread matches above, loose matches on Subject: below --
2013-02-12 11:37 Stéphane LOS
2013-02-12 11:51 ` Jan Kiszka
2013-02-13 14:09   ` Stéphane LOS
2013-02-14 13:36     ` Stéphane LOS
2013-02-14 15:01       ` Stéphane LOS
2013-02-15 14:54         ` Jan Kiszka
2013-02-18 11:43           ` Stéphane LOS
2013-02-07 14:53 Stéphane LOS
2013-02-07 16:11 ` Gilles Chanteperdrix
2013-02-08  9:07   ` Stéphane LOS
2013-02-08  9:18     ` Gilles Chanteperdrix
2013-02-08 11:28       ` Jan Kiszka
2013-02-08 11:35         ` Gilles Chanteperdrix
2013-02-08 11:46           ` Jan Kiszka
     [not found]         ` <5114FD7B.20902@hilscher.com>
2013-02-08 13:40           ` Jan Kiszka
2013-02-08 14:33             ` Stéphane LOS

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.