From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752275AbbCYJzN (ORCPT ); Wed, 25 Mar 2015 05:55:13 -0400 Received: from www.linutronix.de ([62.245.132.108]:50543 "EHLO Galois.linutronix.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751673AbbCYJwn (ORCPT ); Wed, 25 Mar 2015 05:52:43 -0400 From: Holger Dengler To: linux-kernel@vger.kernel.org Cc: Peter Mahler , Juergen Bubeck , Benedikt Spranger , Holger Dengler , Samuel Ortiz , Lee Jones Subject: [PATCH 02/11] mfd: flexcard: add flexcard core device Date: Wed, 25 Mar 2015 10:51:51 +0100 Message-Id: <1427277120-16924-3-git-send-email-dengler@linutronix.de> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1427277120-16924-1-git-send-email-dengler@linutronix.de> References: <1427277120-16924-1-git-send-email-dengler@linutronix.de> X-Linutronix-Spam-Score: -1.0 X-Linutronix-Spam-Level: - X-Linutronix-Spam-Status: No , -1.0 points, 5.0 required, ALL_TRUSTED=-1,SHORTCIRCUIT=-0.0001,URIBL_BLOCKED=0.001 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Benedikt Spranger The Flexcard PCI BAR0 contain registers for configuration but also for informational purpose like error counter, statistical information and some timestamps. The read-only mmap of the misc device offers the userspace a fast access to these registers. Signed-off-by: Holger Dengler Signed-off-by: Benedikt Spranger cc: Samuel Ortiz cc: Lee Jones --- drivers/mfd/flexcard/core.c | 107 ++++++++++++++++++++++++++++++++++++++++++- include/linux/mfd/flexcard.h | 6 +++ include/uapi/linux/Kbuild | 1 + 3 files changed, 112 insertions(+), 2 deletions(-) diff --git a/drivers/mfd/flexcard/core.c b/drivers/mfd/flexcard/core.c index 99df3d5..1e7fb0f 100644 --- a/drivers/mfd/flexcard/core.c +++ b/drivers/mfd/flexcard/core.c @@ -14,11 +14,16 @@ #include #include #include +#include +#include +#include #include #include #include #include +static DEFINE_IDA(flexcard_ida); + static const char drv_name[] = "flexcard"; static int flexcard_tiny_can(struct flexcard_device *priv, @@ -104,23 +109,106 @@ static int flexcard_tiny_probe(struct flexcard_device *priv) return mfd_add_devices(&pdev->dev, 0, priv->cells, nr, NULL, 0, NULL); } +static int flexcard_misc_open(struct inode *inode, struct file *filp) +{ + struct flexcard_device *priv = + container_of(filp->private_data, struct flexcard_device, dev); + int ret; + + filp->private_data = priv; + ret = nonseekable_open(inode, filp); + if (ret) { + dev_err(&priv->pdev->dev, "unable to open file: %d\n", ret); + return ret; + } + + kref_get(&priv->ref); + return 0; +} + +static void flexcard_dev_release(struct kref *ref) +{ + struct flexcard_device *priv = + container_of(ref, struct flexcard_device, ref); + + kfree(priv); + dev_info(&priv->pdev->dev, "misc device release"); +} + +static int flexcard_misc_release(struct inode *inode, struct file *filp) +{ + struct flexcard_device *priv = filp->private_data; + + filp->private_data = NULL; + kref_put(&priv->ref, flexcard_dev_release); + + return 0; +} + +static int flexcard_misc_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct flexcard_device *priv = filp->private_data; + unsigned long offset, vsize, psize, addr; + + if (vma->vm_flags & (VM_WRITE | VM_EXEC)) + return -EPERM; + + offset = vma->vm_pgoff << PAGE_SHIFT; + vsize = vma->vm_end - vma->vm_start; + psize = pci_resource_len(priv->pdev, 0) - offset; + addr = (pci_resource_start(priv->pdev, 0) + offset) >> PAGE_SHIFT; + + if (vsize > psize) { + dev_err(&priv->pdev->dev, + "requested mmap mapping too large\n"); + return -EINVAL; + } + + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + return io_remap_pfn_range(vma, vma->vm_start, addr, vsize, + vma->vm_page_prot); +} + +static const struct file_operations flexcard_misc_fops = { + .owner = THIS_MODULE, + .open = flexcard_misc_open, + .release = flexcard_misc_release, + .mmap = flexcard_misc_mmap, + .llseek = no_llseek, +}; + static int flexcard_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct flexcard_device *priv; int ret; - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; + ret = ida_simple_get(&flexcard_ida, 0, 0, GFP_KERNEL); + if (ret < 0) { + dev_err(&pdev->dev, "could not get new Flexcard id:%d\n", ret); + goto out_free; + } + + priv->cardnr = ret; pci_set_drvdata(pdev, priv); priv->pdev = pdev; + kref_init(&priv->ref); + + snprintf(priv->name, sizeof(priv->name), "flexcard%d", priv->cardnr); + priv->dev.minor = MISC_DYNAMIC_MINOR; + priv->dev.name = priv->name; + priv->dev.fops = &flexcard_misc_fops; + priv->dev.parent = &pdev->dev; ret = pci_enable_device(pdev); if (ret) { dev_err(&pdev->dev, "unable to enable device: %d\n", ret); - return ret; + goto out_put; } pci_set_master(pdev); @@ -143,6 +231,12 @@ static int flexcard_probe(struct pci_dev *pdev, goto out_unmap; } + ret = misc_register(&priv->dev); + if (ret) { + dev_err(&pdev->dev, "unable to register miscdevice: %d\n", ret); + goto out_remove; + } + dev_info(&pdev->dev, "HW %02x.%02x.%02x FW %02x.%02x.%02x\n", priv->conf->fc_hw_ver.maj, priv->conf->fc_hw_ver.min, priv->conf->fc_hw_ver.dev, priv->conf->fc_fw_ver.maj, @@ -150,12 +244,18 @@ static int flexcard_probe(struct pci_dev *pdev, return 0; +out_remove: + mfd_remove_devices(&pdev->dev); out_unmap: iounmap(priv->conf); out_release: pci_release_regions(pdev); out_disable: pci_disable_device(pdev); +out_put: + ida_simple_remove(&flexcard_ida, priv->cardnr); +out_free: + kref_put(&priv->ref, flexcard_dev_release); return ret; } @@ -164,10 +264,13 @@ static void flexcard_remove(struct pci_dev *pdev) { struct flexcard_device *priv = pci_get_drvdata(pdev); + misc_deregister(&priv->dev); mfd_remove_devices(&pdev->dev); iounmap(priv->conf); pci_release_regions(pdev); pci_disable_device(pdev); + ida_simple_remove(&flexcard_ida, priv->cardnr); + kref_put(&priv->ref, flexcard_dev_release); } #define PCI_VENDOR_ID_EBEL 0x1974 diff --git a/include/linux/mfd/flexcard.h b/include/linux/mfd/flexcard.h index 20d0f40..84e155c 100644 --- a/include/linux/mfd/flexcard.h +++ b/include/linux/mfd/flexcard.h @@ -19,11 +19,17 @@ #define FLEXCARD_FR_OFFSET 0x4000 #define FLEXCARD_FR_SIZE 0x2000 +#define FLEXCARD_MAX_NAME 16 + struct flexcard_device { struct pci_dev *pdev; struct fc_conf_bar __iomem *conf; struct mfd_cell *cells; struct resource *res; + struct miscdevice dev; + struct kref ref; + int cardnr; + char name[FLEXCARD_MAX_NAME]; }; enum flexcard_cell_id { diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild index 68ceb97..d5c5002 100644 --- a/include/uapi/linux/Kbuild +++ b/include/uapi/linux/Kbuild @@ -127,6 +127,7 @@ header-y += filter.h header-y += firewire-cdev.h header-y += firewire-constants.h header-y += flat.h +header-y += flexcard.h header-y += fou.h header-y += fs.h header-y += fsl_hypervisor.h -- 2.1.4