From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933804AbdC3MPy (ORCPT ); Thu, 30 Mar 2017 08:15:54 -0400 Received: from mga02.intel.com ([134.134.136.20]:12144 "EHLO mga02.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933765AbdC3MPu (ORCPT ); Thu, 30 Mar 2017 08:15:50 -0400 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.36,246,1486454400"; d="scan'208";a="840018203" From: Wu Hao To: atull@kernel.org, moritz.fischer@ettus.com, linux-fpga@vger.kernel.org, linux-kernel@vger.kernel.org Cc: luwei.kang@intel.com, yi.z.zhang@intel.com, hao.wu@intel.com, Xiao Guangrong , Tim Whisonant , Enno Luebbers , Shiva Rao , Christopher Rauer Subject: [PATCH 07/16] fpga: intel: add feature device infrastructure Date: Thu, 30 Mar 2017 20:08:07 +0800 Message-Id: <1490875696-15145-8-git-send-email-hao.wu@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1490875696-15145-1-git-send-email-hao.wu@intel.com> References: <1490875696-15145-1-git-send-email-hao.wu@intel.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Xiao Guangrong This patch abstracts the common operations of the sub features, and defines the feature_ops data structure, including init, uinit and ioctl function pointers. And this patch adds some common helper functions for FME and AFU drivers, e.g feature_dev_use_begin/end which are used to ensure exclusive usage of the feature device file. Signed-off-by: Tim Whisonant Signed-off-by: Enno Luebbers Signed-off-by: Shiva Rao Signed-off-by: Christopher Rauer Signed-off-by: Kang Luwei Signed-off-by: Zhang Yi Signed-off-by: Xiao Guangrong Signed-off-by: Wu Hao --- drivers/fpga/intel/feature-dev.c | 66 +++++++++++++++++++++++++++++++++++++ drivers/fpga/intel/feature-dev.h | 71 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) diff --git a/drivers/fpga/intel/feature-dev.c b/drivers/fpga/intel/feature-dev.c index ada6548..d729db8 100644 --- a/drivers/fpga/intel/feature-dev.c +++ b/drivers/fpga/intel/feature-dev.c @@ -59,6 +59,72 @@ int port_feature_num(void) return PORT_FEATURE_ID_MAX; } +int fme_feature_to_resource_index(int feature_id) +{ + WARN_ON(feature_id >= FME_FEATURE_ID_MAX); + return feature_id; +} + +void fpga_dev_feature_uinit(struct platform_device *pdev) +{ + struct feature *feature; + struct feature_platform_data *pdata = dev_get_platdata(&pdev->dev); + + fpga_dev_for_each_feature(pdata, feature) + if (feature->ops) { + feature->ops->uinit(pdev, feature); + feature->ops = NULL; + } +} +EXPORT_SYMBOL_GPL(fpga_dev_feature_uinit); + +static int +feature_instance_init(struct platform_device *pdev, + struct feature_platform_data *pdata, + struct feature *feature, struct feature_driver *drv) +{ + int ret; + + WARN_ON(!feature->ioaddr); + + ret = drv->ops->init(pdev, feature); + if (ret) + return ret; + + feature->ops = drv->ops; + return ret; +} + +int fpga_dev_feature_init(struct platform_device *pdev, + struct feature_driver *feature_drvs) +{ + struct feature *feature; + struct feature_driver *drv = feature_drvs; + struct feature_platform_data *pdata = dev_get_platdata(&pdev->dev); + int ret; + + while (drv->ops) { + fpga_dev_for_each_feature(pdata, feature) { + /* skip the feature which is not initialized. */ + if (!feature->name) + continue; + + if (!strcmp(drv->name, feature->name)) { + ret = feature_instance_init(pdev, pdata, + feature, drv); + if (ret) + goto exit; + } + } + drv++; + } + return 0; +exit: + fpga_dev_feature_uinit(pdev); + return ret; +} +EXPORT_SYMBOL_GPL(fpga_dev_feature_init); + struct fpga_chardev_info { const char *name; dev_t devt; diff --git a/drivers/fpga/intel/feature-dev.h b/drivers/fpga/intel/feature-dev.h index 38531f8..9d39b94 100644 --- a/drivers/fpga/intel/feature-dev.h +++ b/drivers/fpga/intel/feature-dev.h @@ -207,12 +207,20 @@ struct feature_port_stp { #pragma pack() +struct feature_driver { + const char *name; + struct feature_ops *ops; +}; + struct feature { const char *name; int resource_index; void __iomem *ioaddr; + struct feature_ops *ops; }; +#define DEV_STATUS_IN_USE 0 + struct feature_platform_data { /* list the feature dev to cci_drvdata->port_dev_list. */ struct list_head node; @@ -220,6 +228,9 @@ struct feature_platform_data { struct cdev cdev; struct platform_device *dev; unsigned int disable_count; /* count for port disable */ + unsigned long dev_status; + + void *private; /* ptr to feature dev private data */ struct platform_device *(*fpga_for_each_port)(struct platform_device *, void *, int (*match)(struct platform_device *, void *)); @@ -228,6 +239,38 @@ struct feature_platform_data { struct feature features[0]; }; +static inline int feature_dev_use_begin(struct feature_platform_data *pdata) +{ + /* Test and set IN_USE flags to ensure file is exclusively used */ + if (test_and_set_bit_lock(DEV_STATUS_IN_USE, &pdata->dev_status)) + return -EBUSY; + + return 0; +} + +static inline void feature_dev_use_end(struct feature_platform_data *pdata) +{ + clear_bit_unlock(DEV_STATUS_IN_USE, &pdata->dev_status); +} + +static inline void +fpga_pdata_set_private(struct feature_platform_data *pdata, void *private) +{ + pdata->private = private; +} + +static inline void *fpga_pdata_get_private(struct feature_platform_data *pdata) +{ + return pdata->private; +} + +struct feature_ops { + int (*init)(struct platform_device *pdev, struct feature *feature); + void (*uinit)(struct platform_device *pdev, struct feature *feature); + long (*ioctl)(struct platform_device *pdev, struct feature *feature, + unsigned int cmd, unsigned long arg); +}; + enum fme_feature_id { FME_FEATURE_ID_HEADER = 0x0, FME_FEATURE_ID_THERMAL_MGMT = 0x1, @@ -261,6 +304,10 @@ int feature_platform_data_size(int num); struct feature_platform_data * feature_platform_data_alloc_and_init(struct platform_device *dev, int num); +void fpga_dev_feature_uinit(struct platform_device *pdev); +int fpga_dev_feature_init(struct platform_device *pdev, + struct feature_driver *feature_drvs); + enum fpga_devt_type { FPGA_DEVT_FME, FPGA_DEVT_PORT, @@ -330,6 +377,15 @@ static inline int fpga_port_reset(struct platform_device *pdev) return ret; } +static inline +struct platform_device *fpga_inode_to_feature_dev(struct inode *inode) +{ + struct feature_platform_data *pdata; + + pdata = container_of(inode->i_cdev, struct feature_platform_data, cdev); + return pdata->dev; +} + static inline void __iomem * get_feature_ioaddr_by_index(struct device *dev, int index) { @@ -338,12 +394,27 @@ get_feature_ioaddr_by_index(struct device *dev, int index) return pdata->features[index].ioaddr; } +static inline bool is_feature_present(struct device *dev, int index) +{ + return !!get_feature_ioaddr_by_index(dev, index); +} + static inline struct device * fpga_feature_dev_to_pcidev(struct platform_device *dev) { return dev->dev.parent->parent; } +static inline struct device * +fpga_pdata_to_pcidev(struct feature_platform_data *pdata) +{ + return fpga_feature_dev_to_pcidev(pdata->dev); +} + +#define fpga_dev_for_each_feature(pdata, feature) \ + for ((feature) = (pdata)->features; \ + (feature) < (pdata)->features + (pdata)->num; (feature)++) + /* * Wait register's _field to be changed to the given value (_expect's _field) * by polling with given interval and timeout. -- 2.7.4