All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jerome Poncin <JPoncin@hilscher.com>
To: "xenomai@xenomai.org" <xenomai@xenomai.org>
Subject: Re: [Xenomai] Hilscher driver for cifX boards
Date: Tue, 19 Mar 2013 14:42:30 +0100	[thread overview]
Message-ID: <51486B46.1000901@hilscher.com> (raw)
In-Reply-To: <5146E61E.4080606@hilscher.com>

Le 18/03/2013 11:02, Jerome Poncin a écrit :
> Le 15/03/2013 14:24, Jan Kiszka a écrit :
>> On 2013-03-15 14:04, Jerome Poncin wrote:
>>> Hello Jan,
>>>
>>> Yes you're right. I have 1 thread for test (main) application and the
>>> driver create one or two thread if IRQ or polling is enable.
>>> The driver thread are loop waiting event with delay.
>>> At Driver start it take few second to download firmware and 
>>> configuration.
>>> My question is why it's a problem to have a real time that that run few
>>> second.
>>> If this task have the bigger priority, it's normal to not release hand
>>> and to not sleep, I'm right or not ?
>> Linux is not capable (yet) of handling the case that an online CPU is
>> 100% occupied. Sooner or later, the whole (Linux) system will lock up,
>> also the timekeeping can be negatively affected. That's nothing Xenomai
>> can change.
>>
>> Therefore, every real-time task has to behave properly, sleep on
>> asynchronous external events or suspend itself for a certain while when
>> there is nothing to do. In good real-time designs, that is usually no
>> problem, specifically if the number of tasks is moderate and the
>> workload is clear. I've seen less obvious problems in large
>> applications, but those were typically bugs as well.
>>
>> Jan
>>
> Hello Jan,
>
> I investigated my problem and the problem come from some lock on thread.
> I think my thread management is not correct... I
> Is there an example in posix with multiple thread management ?
>
> Thank you for your help,
>
> Jerome
Hello,

I corrected my problem with thread management running with posix skin. 
Now I have all thread that run in Real Time with IRQ.
I send you my last version of patch to see if kernel driver is correct 
for you, and can be integrated to the main line.

Thank you for your help,

Jerome
-------------- next part --------------
diff --git a/include/asm-generic/pci_ids.h b/include/asm-generic/pci_ids.h
index d298bf4..3f8d7cc 100644
--- a/include/asm-generic/pci_ids.h
+++ b/include/asm-generic/pci_ids.h
@@ -40,4 +40,45 @@
 #define PCI_DEVICE_ID_PLX_9056 0x9056
 #endif
 
+/* cifx */
+#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
+
 #endif /* _XENO_ASM_GENERIC_PCI_IDS_H */
diff --git a/ksrc/drivers/cifx/Kconfig b/ksrc/drivers/cifx/Kconfig
new file mode 100644
index 0000000..715a45e
--- /dev/null
+++ b/ksrc/drivers/cifx/Kconfig
@@ -0,0 +1,11 @@
+menu "Hilscher cifX driver"
+
+config XENO_DRIVERS_CIFX
+	depends on XENO_SKIN_RTDM
+	tristate "Hilscher cifX"
+	help
+
+	This driver provides Hilscher cifX 
+	over RTDM.
+
+endmenu
diff --git a/ksrc/drivers/cifx/Makefile b/ksrc/drivers/cifx/Makefile
new file mode 100644
index 0000000..42550bd
--- /dev/null
+++ b/ksrc/drivers/cifx/Makefile
@@ -0,0 +1,13 @@
+ifneq ($(VERSION).$(PATCHLEVEL),2.4)
+
+# Makefile frag for Linux v2.6 and v3.x
+
+EXTRA_CFLAGS += -D__IN_XENOMAI__ -Iinclude/xenomai -Idrivers/xenomai/cifx
+
+obj-$(CONFIG_XENO_DRIVERS_CIFX) += xeno_cifx_pci.o
+
+xeno_cifx_pci-y := cifx_pci.o
+
+xeno_cifx_pci-$(CONFIG_XENO_DRIVERS_RTIPC_CIFX) += cifx_pci.o
+
+endif
diff --git a/ksrc/drivers/cifx/cifx_pci.c b/ksrc/drivers/cifx/cifx_pci.c
new file mode 100644
index 0000000..cae04aa
--- /dev/null
+++ b/ksrc/drivers/cifx/cifx_pci.c
@@ -0,0 +1,854 @@
+/*
+ * Copyright (C) 2013 Hilscher France (JP) <www.hilscher.fr>
+ *
+ * Xenomai 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.
+ *
+ * Xenomai 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 Xenomai; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/mman.h>
+
+#include <asm-generic/xenomai/pci_ids.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>");
+
+#define RTCIFX_GET_MEM_INFO				0x00
+#define RTCIFX_MMAP						0x01
+#define RTCIFX_MUNMAP					0x02
+#define RTCIFX_REQUEST_IRQ				0x03
+#define RTCIFX_FREE_IRQ					0x04
+#define RTCIFX_ENABLE_IRQ				0x05
+#define RTCIFX_DISABLE_IRQ				0x06
+#define RTCIFX_WAIT_IRQ					0x07
+
+#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 */
+/* points to the DPM -> netX, netPLC, netJACK */
+#define DPM_BAR                         0
+/* points to the optional extended memory     */
+#define EXT_MEM_BAR                     1
+/* points to the DPM -> netXPLX               */
+#define PLX_DPM_BAR                     2
+/* timing config register                     */
+#define PXA_PLX_BAR                     0
+
+/* Index of io_info structure's memory array */
+/* first mapping describes DPM              */
+#define DPM_INDEX                       0
+/* second mapping describes extended memory */
+#define EXT_MEM_INDEX                   1
+
+#define MAX_MAPS                        2
+
+#define MEM_PHYS                        1
+
+#define DRIVER_NAME                     "rtdm_cifx"
+#define PERIPHERAL_NAME                 "cifx"
+#define PROVIDER_NAME                   "Hilscher"
+
+/* name of a NXSB-PCA or NXPCA-PCI card */
+#define CIFX_RTDM_PLX_CARD_NAME         "netx_plx"
+/* name of a cifX PCI card              */
+#define CIFX_RTDM_CARD_NAME             "netx"
+/* name of a netPLC PCI card            */
+#define CIFX_RTDM_NETPLC_CARD_NAME      "netplc"
+/* name of a netJACK PCI card           */
+#define CIFX_RTDM_NETJACK_CARD_NAME     "netjack"
+
+struct io_mem {
+	uint32_t addr;
+	uint32_t size;
+	int32_t memtype;
+	void __iomem *internal_addr;
+};
+
+struct io_info {
+	struct io_mem mem[MAX_MAPS];
+	int32_t irq;
+	bool irq_enable;
+	bool irq_registered;
+	rtdm_irq_t irq_handle;
+	rtdm_event_t irq_event;
+	rtdm_nrtsig_t irq_nrtsig;
+	bool irq_sig;
+	struct ext_io_info *priv;
+};
+
+struct ext_io_info {
+	uint32_t __iomem *plx;
+	uint8_t dpm_mode;
+	uint32_t plx_timing;
+};
+
+struct io_map_mem {
+	uint32_t phys_addr;
+	uint32_t virt_addr;
+	uint32_t length;
+};
+
+static struct io_info *cifx_get_device_data(struct rtdm_device *info);
+static struct ext_io_info *cifx_get_private(struct rtdm_device *info);
+
+static int cifx_set_plx_timing(struct ext_io_info *ext_info);
+static int cifx_get_plx_timing(struct ext_io_info *ext_info);
+static int cifx_get_dpm_mode(struct ext_io_info *ext_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 int cifx_pci_ioctl_nrt(struct rtdm_dev_context *context,
+			      rtdm_user_info_t *user_info,
+			      unsigned int request, void *arg);
+static int cifx_pci_ioctl_rt(struct rtdm_dev_context *context,
+			     rtdm_user_info_t *user_info,
+			     unsigned int request, void *arg);
+static int cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id);
+static void cifx_pci_remove(struct pci_dev *dev);
+
+static inline int cifx_handler(rtdm_irq_t *irq);
+
+/* Number or cifx found and open */
+static int32_t cifx_num;
+
+/* RTDM Device information structure */
+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,
+
+		.ioctl_rt = cifx_pci_ioctl_rt,
+		.ioctl_nrt = cifx_pci_ioctl_nrt,
+		},
+
+	.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,
+};
+
+/* Device table */
+static DEFINE_PCI_DEVICE_TABLE(cifx_pci_tbl) = {
+	{
+	PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETX, 0, 0}, {
+	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
+		    PCI_VENDOR_ID_PLX, PCI_SUBDEVICE_ID_NXSB_PCA}, {
+	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
+		    PCI_VENDOR_ID_PLX, PCI_SUBDEVICE_ID_NXPCA}, {
+	PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETPLC,
+		    PCI_VENDOR_ID_HILSCHER, PCI_SUBDEVICE_ID_NETPLC_RAM}, {
+	PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETPLC,
+		    PCI_VENDOR_ID_HILSCHER, PCI_SUBDEVICE_ID_NETPLC_FLASH}, {
+	PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETJACK,
+		    PCI_VENDOR_ID_HILSCHER, PCI_SUBDEVICE_ID_NETJACK_RAM}, {
+	PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETJACK,
+		    PCI_VENDOR_ID_HILSCHER, PCI_SUBDEVICE_ID_NETJACK_FLASH}, {
+	0,}
+};
+
+/* cifX Driver */
+static struct pci_driver cifx_pci_driver = {
+	.name = "cifx",
+	.id_table = cifx_pci_tbl,
+	.probe = cifx_pci_probe,
+	.remove = cifx_pci_remove,
+};
+
+/*
+ *	cifx_rtdm_device_to_device_data
+ *	Get device_data structure
+ */
+static struct io_info *cifx_get_device_data(struct rtdm_device *info)
+{
+	return info->device_data;
+}
+
+/*
+ *	cifx_rtdm_device_to_private
+ *	Get ext_io_info structure
+ */
+static struct ext_io_info *cifx_get_private(struct rtdm_device *info)
+{
+	return ((struct io_info *)info->device_data)->priv;
+}
+
+/*
+ * cifx_handler
+ * cifx interrupt handler
+ */
+static inline int cifx_handler(rtdm_irq_t *irq)
+{
+	struct rtdm_device *info = rtdm_irq_get_arg(irq, void);
+	struct io_info *device_data = info->device_data;
+
+	/* Test if request is for this driver */
+	if ((device_data->priv != NULL)
+	    || (device_data->irq_registered == 0)
+	    || (device_data->irq_enable == 0)) {
+		/* This is a PLX device and cannot produce an IRQ,
+		   IRQ not registred or not enable (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 RTDM_IRQ_NONE;
+
+		/* Disable interrupt */
+		iowrite32(ioread32(int_enable_reg)
+			  & ~DPM_HOST_INT_GLOBAL_EN, int_enable_reg);
+
+		if (device_data->irq_registered == 1)
+			rtdm_event_signal(&device_data->irq_event);
+
+		return RTDM_IRQ_HANDLED;
+	}
+}
+
+/*
+ *	cifx_set_plx_timing
+ *	Set plx timing
+ */
+static int cifx_set_plx_timing(struct ext_io_info *ext_info)
+{
+	uint32_t __iomem *plx_timing;
+
+	if (ext_info == NULL)
+		return -ENODEV;
+
+	plx_timing = ext_info->plx + PLX_TIMING_OFFSET;
+	*plx_timing = ext_info->plx_timing;
+
+	return 0;
+}
+
+/*
+ * cifx_get_plx_timing
+ * Get plx timing
+ */
+static int cifx_get_plx_timing(struct ext_io_info *ext_info)
+{
+	if (ext_info == NULL)
+		return -ENODEV;
+
+	switch (ext_info->dpm_mode) {
+	case 8:
+		ext_info->plx_timing = NX_PCA_PCI_8_BIT_DPM_MODE;
+		break;
+	case 16:
+		ext_info->plx_timing = NX_PCA_PCI_16_BIT_DPM_MODE;
+		break;
+	case 32:
+		ext_info->plx_timing = NX_PCA_PCI_32_BIT_DPM_MODE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * cifx_get_dpm_mode
+ * Get dpm mode
+ */
+static int cifx_get_dpm_mode(struct ext_io_info *ext_info)
+{
+	uint32_t __iomem *plx_gpio;
+
+	if (ext_info == NULL)
+		return -ENODEV;
+
+	plx_gpio = ext_info->plx + PLX_GPIO_OFFSET;
+
+	if ((*plx_gpio & PLX_GPIO_DATA0_MASK)
+	    && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
+		ext_info->dpm_mode = 8;
+	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK)
+		 && (*plx_gpio & PLX_GPIO_DATA1_MASK))
+		ext_info->dpm_mode = 32;
+	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK)
+		 && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
+		ext_info->dpm_mode = 16;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+/*
+ * cifx_pci_open
+ * Open cifx pci driver
+ */
+static int cifx_pci_open(struct rtdm_dev_context *context,
+			 rtdm_user_info_t *user_info, int oflags)
+{
+	return 0;
+}
+
+/*
+ * cifx_pci_close
+ * Close cifx pci driver
+ */
+static int cifx_pci_close(struct rtdm_dev_context *context,
+			  rtdm_user_info_t *user_info)
+{
+	return 0;
+}
+
+/*
+ * cifx_pci_ioctl_nrt
+ * ioctl
+ */
+static int cifx_pci_ioctl_nrt(struct rtdm_dev_context *context,
+			      rtdm_user_info_t *user_info,
+			      unsigned int request, void *arg)
+{
+	int ret = 0;
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+	struct io_info *device_data = cifx_get_device_data(info);
+	struct io_map_mem map_mem;
+
+	switch (request) {
+	case RTCIFX_GET_MEM_INFO:
+		if (arg == NULL)
+			return -EINVAL;
+
+		ret = rtdm_safe_copy_to_user(user_info,
+					     arg,
+					     device_data->mem,
+					     (2 * sizeof(uint32_t)));
+		break;
+
+	case RTCIFX_MMAP:
+		if (arg == NULL)
+			return -EINVAL;
+
+		ret = rtdm_safe_copy_from_user(user_info,
+					       &map_mem, arg, sizeof(map_mem));
+		if (ret != 0)
+			break;
+
+		/* Map physical on virtual memory */
+		ret = rtdm_iomap_to_user(user_info,
+					 map_mem.phys_addr,
+					 map_mem.length,
+					 (PROT_READ | PROT_WRITE),
+					 (void **)&map_mem.virt_addr,
+					 NULL, NULL);
+		if (ret != 0)
+			break;
+
+		ret = rtdm_safe_copy_to_user(user_info,
+					     arg, &map_mem, sizeof(map_mem));
+		break;
+
+	case RTCIFX_MUNMAP:
+		if (arg == NULL)
+			return -EINVAL;
+
+		ret = rtdm_safe_copy_from_user(user_info,
+					       &map_mem, arg, sizeof(map_mem));
+		if (ret != 0)
+			break;
+
+		/* Unap virtual memory */
+		ret = rtdm_munmap(user_info,
+				  (void *)map_mem.virt_addr, map_mem.length);
+		break;
+
+	case RTCIFX_REQUEST_IRQ:
+		if (device_data->irq_registered == 0) {
+			ret = rtdm_irq_request(&device_data->irq_handle,
+					       device_data->irq,
+					       cifx_handler,
+					       RTDM_IRQTYPE_SHARED,
+					       info->device_name, (void *)info);
+
+			if (ret == 0) {
+				rtdm_event_init(&device_data->irq_event, 0);
+
+				device_data->irq_registered = 1;
+			}
+		}
+		break;
+
+	case RTCIFX_FREE_IRQ:
+		if (device_data->irq_registered == 1) {
+			ret = rtdm_irq_free(&device_data->irq_handle);
+
+			if (ret == 0) {
+				device_data->irq_registered = 0;
+
+				rtdm_event_destroy(&device_data->irq_event);
+			}
+		}
+		break;
+
+	case RTCIFX_ENABLE_IRQ:
+		if (device_data->irq_registered == 1) {
+			ret = rtdm_irq_enable(&device_data->irq_handle);
+
+			if (ret == 0)
+				device_data->irq_enable = 1;
+		}
+		break;
+
+	case RTCIFX_DISABLE_IRQ:
+		if (device_data->irq_registered == 1) {
+			ret = rtdm_irq_disable(&device_data->irq_handle);
+
+			if (ret == 0)
+				device_data->irq_enable = 0;
+		}
+		break;
+
+	case RTCIFX_WAIT_IRQ:
+		if (device_data->irq_enable == 1)
+			ret = -EPERM;
+		else
+			ret = -EAGAIN;
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+/*
+ * cifx_pci_ioctl_rt
+ * ioctl
+ */
+static int cifx_pci_ioctl_rt(struct rtdm_dev_context *context,
+			     rtdm_user_info_t *user_info,
+			     unsigned int request, void *arg)
+{
+	int ret = 0;
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+	struct io_info *device_data = cifx_get_device_data(info);
+	struct io_map_mem map_mem;
+
+	switch (request) {
+	case RTCIFX_GET_MEM_INFO:
+		if (arg == NULL)
+			return -EINVAL;
+
+		ret = rtdm_safe_copy_to_user(user_info,
+					     arg,
+					     device_data->mem,
+					     (2 * sizeof(uint32_t)));
+		break;
+
+	case RTCIFX_MMAP:
+		if (arg == NULL)
+			return -EINVAL;
+
+		ret = rtdm_safe_copy_from_user(user_info,
+					       &map_mem, arg, sizeof(map_mem));
+		if (ret != 0)
+			break;
+
+		/* Map physical on virtual memory */
+		ret = rtdm_iomap_to_user(user_info,
+					 map_mem.phys_addr,
+					 map_mem.length,
+					 (PROT_READ | PROT_WRITE),
+					 (void **)&map_mem.virt_addr,
+					 NULL, NULL);
+		if (ret != 0)
+			break;
+
+		ret = rtdm_safe_copy_to_user(user_info,
+					     arg, &map_mem, sizeof(map_mem));
+		break;
+
+	case RTCIFX_MUNMAP:
+		if (arg == NULL)
+			return -EINVAL;
+
+		ret = rtdm_safe_copy_from_user(user_info,
+					       &map_mem, arg, sizeof(map_mem));
+		if (ret != 0)
+			break;
+
+		/* Unap virtual memory */
+		ret = rtdm_munmap(user_info,
+				  (void *)map_mem.virt_addr, map_mem.length);
+		break;
+
+	case RTCIFX_REQUEST_IRQ:
+		if (device_data->irq_registered == 0) {
+			ret = rtdm_irq_request(&device_data->irq_handle,
+					       device_data->irq,
+					       cifx_handler,
+					       RTDM_IRQTYPE_SHARED,
+					       info->device_name, (void *)info);
+
+			if (ret == 0) {
+				rtdm_event_init(&device_data->irq_event, 0);
+
+				device_data->irq_registered = 1;
+			}
+		}
+		break;
+
+	case RTCIFX_FREE_IRQ:
+		if (device_data->irq_registered == 1) {
+			ret = rtdm_irq_free(&device_data->irq_handle);
+
+			if (ret == 0) {
+				device_data->irq_registered = 0;
+
+				rtdm_event_destroy(&device_data->irq_event);
+			}
+		}
+		break;
+
+	case RTCIFX_ENABLE_IRQ:
+		if (device_data->irq_registered == 1) {
+			ret = rtdm_irq_enable(&device_data->irq_handle);
+
+			if (ret == 0)
+				device_data->irq_enable = 1;
+		}
+		break;
+
+	case RTCIFX_DISABLE_IRQ:
+		if (device_data->irq_registered == 1) {
+			ret = rtdm_irq_disable(&device_data->irq_handle);
+
+			if (ret == 0)
+				device_data->irq_enable = 0;
+		}
+		break;
+
+	case RTCIFX_WAIT_IRQ:
+		if (device_data->irq_enable == 1) {
+			/* default Timeout 500 ms */
+			ret = rtdm_event_timedwait(&device_data->irq_event,
+						   (500 * 1000 * 1000), NULL);
+		} else {
+			ret = -EAGAIN;
+		}
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	struct rtdm_device *info = NULL;
+	struct io_info *device_data = NULL;
+	int32_t bar;
+	int32_t ret = -ENODEV;
+
+	/* Allocate device driver structure */
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+
+	if (info == NULL)
+		return -ENOMEM;
+
+	ret = pci_enable_device(dev);
+	if (ret != 0)
+		goto out_free;
+
+	ret = pci_request_regions(dev, DRIVER_NAME);
+	if (ret != 0)
+		goto out_disable;
+
+	/* Initialize structure with default values */
+	memcpy(info, &cifx_device_tmpl, sizeof(*info));
+
+	info->device_id = id->device;
+	snprintf(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;
+
+	/* Allocate specific data strcuture for device */
+	device_data = kmalloc(sizeof(*device_data), GFP_KERNEL);
+
+	if (device_data == NULL) {
+		ret = -ENOMEM;
+		goto out_release;
+	}
+
+	memset(device_data, 0, sizeof(*device_data));
+
+	/* 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)
+		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)
+		goto out_release;
+
+	dev_info(&dev->dev, "DPM at %08X\n", 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)
+			goto out_unmap;
+
+		dev_info(&dev->dev,
+			 "extended memory at %08X\n",
+			 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 */
+		struct ext_io_info *ext_info;
+
+		ext_info = kmalloc(sizeof(*ext_info), GFP_KERNEL);
+
+		if (ext_info == NULL) {
+			ret = -ENOMEM;
+			goto out_unmap;
+		}
+
+		device_data->priv = ext_info;
+
+		/* set PXA PLX Timings */
+		ext_info->plx =
+		    ioremap_nocache(pci_resource_start(dev, PXA_PLX_BAR),
+				    pci_resource_len(dev, PXA_PLX_BAR));
+
+		if (ext_info->plx == NULL)
+			goto out_unmap;
+		if (cifx_get_dpm_mode(ext_info))
+			goto out_unmap_plx;
+		if (cifx_get_plx_timing(ext_info))
+			goto out_unmap_plx;
+		if (cifx_set_plx_timing(ext_info))
+			goto out_unmap_plx;
+	} else {
+		struct ext_io_info *ext_info;
+
+		ext_info = kmalloc(sizeof(*ext_info), GFP_KERNEL);
+
+		if (ext_info == NULL) {
+			ret = -ENOMEM;
+			goto out_free_pxa;
+		}
+
+		ext_info->plx = NULL;
+		ext_info->plx_timing = 0;
+		ext_info->dpm_mode = 0;
+		device_data->priv = ext_info;
+	}
+
+	/* Initialize irq data */
+	device_data->irq = dev->irq;
+	device_data->irq_enable = 0;
+	device_data->irq_registered = 0;
+
+	info->device_data = device_data;
+
+	/* Register RTDM device driver */
+	ret = rtdm_dev_register(info);
+	if (ret != 0) {
+		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 {
+		struct ext_io_info *ext_info = device_data->priv;
+		dev_info(&dev->dev,
+			 "registered NXPCA-PCI adapter card in %d bit mode\n",
+			 ((struct ext_io_info *)ext_info)->dpm_mode);
+	}
+
+	cifx_num++;
+
+	return 0;
+
+out_unmap_plx:
+	iounmap((device_data->priv)->plx);
+
+out_free_pxa:
+	kfree(device_data->priv);
+
+out_unmap:
+	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);
+
+out_release:
+	pci_release_regions(dev);
+
+out_disable:
+	pci_disable_device(dev);
+
+out_free:
+	if (info->device_data != NULL)
+		kfree(info->device_data);
+
+	kfree(info);
+
+	return ret;
+}
+
+static void cifx_pci_remove(struct pci_dev *dev)
+{
+	struct rtdm_device *info = pci_get_drvdata(dev);
+	struct io_info *device_data = cifx_get_device_data(info);
+	struct ext_io_info *ext_info = cifx_get_private(info);
+
+	if (cifx_num > 0) {
+		if (info->device_data == NULL)
+			return;
+
+		if (ext_info != NULL) {
+			/* Disable all interrupts */
+			iowrite32(0, device_data->mem[DPM_INDEX].internal_addr
+				  + DPM_HOST_INT_EN0);
+
+			if (ext_info->plx != NULL)
+				iounmap((void *)ext_info->plx);
+
+			kfree((void *)ext_info);
+		}
+
+		/* Unregister device driver */
+		rtdm_dev_unregister(info, 1000);
+
+		pci_release_regions(dev);
+		pci_disable_device(dev);
+		pci_set_drvdata(dev, NULL);
+
+		/* Unmap memory */
+		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);
+
+		/* Release structure memory allocation */
+		kfree(info->device_data);
+		kfree(info);
+
+		cifx_num--;
+	}
+}
+
+static int __init cifx_pci_init(void)
+{
+	return pci_register_driver(&cifx_pci_driver);
+}
+
+static void __exit cifx_pci_exit(void)
+{
+	pci_unregister_driver(&cifx_pci_driver);
+}
+
+module_init(cifx_pci_init);
+module_exit(cifx_pci_exit);

  reply	other threads:[~2013-03-19 13:42 UTC|newest]

Thread overview: 57+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 [this message]
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=51486B46.1000901@hilscher.com \
    --to=jponcin@hilscher.com \
    --cc=xenomai@xenomai.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.