get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/52179/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 52179,
    "url": "http://patches.dpdk.org/api/patches/52179/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/1554292065-186702-9-git-send-email-rosen.xu@intel.com/",
    "project": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<1554292065-186702-9-git-send-email-rosen.xu@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1554292065-186702-9-git-send-email-rosen.xu@intel.com",
    "date": "2019-04-03T11:47:39",
    "name": "[v5,08/14] raw/ifpga/base: store private features in FME and Port list",
    "commit_ref": null,
    "pull_url": null,
    "state": "changes-requested",
    "archived": true,
    "hash": "f36244c95a002e46317f8b9c0f5cc17ebbb8bd2d",
    "submitter": {
        "id": 946,
        "url": "http://patches.dpdk.org/api/people/946/?format=api",
        "name": "Xu, Rosen",
        "email": "rosen.xu@intel.com"
    },
    "delegate": {
        "id": 319,
        "url": "http://patches.dpdk.org/api/users/319/?format=api",
        "username": "fyigit",
        "first_name": "Ferruh",
        "last_name": "Yigit",
        "email": "ferruh.yigit@amd.com"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/1554292065-186702-9-git-send-email-rosen.xu@intel.com/mbox/",
    "series": [
        {
            "id": 4084,
            "url": "http://patches.dpdk.org/api/series/4084/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=4084",
            "date": "2019-04-03T11:47:31",
            "name": "Add patch set for IPN3KE",
            "version": 5,
            "mbox": "http://patches.dpdk.org/series/4084/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/52179/comments/",
    "check": "success",
    "checks": "http://patches.dpdk.org/api/patches/52179/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id AB98B1B3DA;\n\tWed,  3 Apr 2019 13:47:14 +0200 (CEST)",
            "from mga11.intel.com (mga11.intel.com [192.55.52.93])\n\tby dpdk.org (Postfix) with ESMTP id 72A2C1B3D8\n\tfor <dev@dpdk.org>; Wed,  3 Apr 2019 13:47:13 +0200 (CEST)",
            "from fmsmga005.fm.intel.com ([10.253.24.32])\n\tby fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t03 Apr 2019 04:47:08 -0700",
            "from dpdkx8602.sh.intel.com ([10.67.110.200])\n\tby fmsmga005.fm.intel.com with ESMTP; 03 Apr 2019 04:47:06 -0700"
        ],
        "X-Amp-Result": "SKIPPED(no attachment in message)",
        "X-Amp-File-Uploaded": "False",
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.60,304,1549958400\"; d=\"scan'208\";a=\"334606320\"",
        "From": "Rosen Xu <rosen.xu@intel.com>",
        "To": "dev@dpdk.org",
        "Cc": "ferruh.yigit@intel.com, tianfei.zhang@intel.com, dan.wei@intel.com,\n\trosen.xu@intel.com, andy.pei@intel.com, qiming.yang@intel.com,\n\thaiyue.wang@intel.com, santos.chen@intel.com, zhang.zhang@intel.com, \n\tdavid.lomartire@intel.com",
        "Date": "Wed,  3 Apr 2019 19:47:39 +0800",
        "Message-Id": "<1554292065-186702-9-git-send-email-rosen.xu@intel.com>",
        "X-Mailer": "git-send-email 1.8.3.1",
        "In-Reply-To": "<1554292065-186702-1-git-send-email-rosen.xu@intel.com>",
        "References": "<1551338000-120348-1-git-send-email-rosen.xu@intel.com>\n\t<1554292065-186702-1-git-send-email-rosen.xu@intel.com>",
        "Subject": "[dpdk-dev] [PATCH v5 08/14] raw/ifpga/base: store private features\n\tin FME and Port list",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "From: \"Zhang, Tianfei\" <tianfei.zhang@intel.com>\n\nGet private features attrubite like size, id, address after\nenumeration, and insert into FEM or Port dedicate list.\n\nwhen initial the private feature driver, we just compare the\nprivate feature id between the list and feature drivers array\nto match the proper drivers.\n\nThis patch avoid the hardcore in feature_info array in previous\nimplementation. and the same time we can use one driver for mulitple\ndevices which the id is the same.\n\nSigned-off-by: Zhang, Tianfei <tianfei.zhang@intel.com>\n---\n drivers/raw/ifpga_rawdev/base/ifpga_defines.h     |  46 ++-\n drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c   | 347 ++++++++--------------\n drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c | 160 +++++++---\n drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h |  46 ++-\n drivers/raw/ifpga_rawdev/base/ifpga_fme.c         |  32 ++\n drivers/raw/ifpga_rawdev/base/ifpga_hw.h          |  16 +-\n drivers/raw/ifpga_rawdev/base/ifpga_port.c        |  21 ++\n 7 files changed, 363 insertions(+), 305 deletions(-)",
    "diff": "diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_defines.h b/drivers/raw/ifpga_rawdev/base/ifpga_defines.h\nindex aa02527..217d0b1 100644\n--- a/drivers/raw/ifpga_rawdev/base/ifpga_defines.h\n+++ b/drivers/raw/ifpga_rawdev/base/ifpga_defines.h\n@@ -15,6 +15,7 @@\n #define FME_FEATURE_GLOBAL_IPERF    \"fme_iperf\"\n #define FME_FEATURE_GLOBAL_ERR      \"fme_error\"\n #define FME_FEATURE_PR_MGMT         \"fme_pr\"\n+#define FME_FEATURE_EMIF_MGMT       \"fme_emif\"\n #define FME_FEATURE_HSSI_ETH        \"fme_hssi\"\n #define FME_FEATURE_GLOBAL_DPERF    \"fme_dperf\"\n #define FME_FEATURE_QSPI_FLASH\t    \"fme_qspi_flash\"\n@@ -59,7 +60,8 @@\n #define FEATURE_FIU_ID_FME\t0x0\n #define FEATURE_FIU_ID_PORT\t0x1\n \n-#define FEATURE_ID_HEADER\t0x0\n+/* Reserved 0xfe for Header, 0xff for AFU*/\n+#define FEATURE_ID_FIU_HEADER\t0xfe\n #define FEATURE_ID_AFU\t\t0xff\n \n enum fpga_id_type {\n@@ -68,31 +70,23 @@ enum fpga_id_type {\n \tFPGA_ID_MAX,\n };\n \n-enum fme_feature_id {\n-\tFME_FEATURE_ID_HEADER = 0x0,\n-\n-\tFME_FEATURE_ID_THERMAL_MGMT\t= 0x1,\n-\tFME_FEATURE_ID_POWER_MGMT = 0x2,\n-\tFME_FEATURE_ID_GLOBAL_IPERF = 0x3,\n-\tFME_FEATURE_ID_GLOBAL_ERR = 0x4,\n-\tFME_FEATURE_ID_PR_MGMT = 0x5,\n-\tFME_FEATURE_ID_HSSI_ETH = 0x6,\n-\tFME_FEATURE_ID_GLOBAL_DPERF = 0x7,\n-\tFME_FEATURE_ID_QSPI_FLASH = 0x8,\n-\n-\t/* one for fme header. */\n-\tFME_FEATURE_ID_MAX = 0x9,\n-};\n-\n-enum port_feature_id {\n-\tPORT_FEATURE_ID_HEADER = 0x0,\n-\tPORT_FEATURE_ID_ERROR = 0x1,\n-\tPORT_FEATURE_ID_UMSG = 0x2,\n-\tPORT_FEATURE_ID_UINT = 0x3,\n-\tPORT_FEATURE_ID_STP = 0x4,\n-\tPORT_FEATURE_ID_UAFU = 0x5,\n-\tPORT_FEATURE_ID_MAX = 0x6,\n-};\n+#define FME_FEATURE_ID_HEADER FEATURE_ID_FIU_HEADER\n+#define FME_FEATURE_ID_THERMAL_MGMT 0x1\n+#define FME_FEATURE_ID_POWER_MGMT 0x2\n+#define FME_FEATURE_ID_GLOBAL_IPERF 0x3\n+#define FME_FEATURE_ID_GLOBAL_ERR 0x4\n+#define FME_FEATURE_ID_PR_MGMT 0x5\n+#define FME_FEATURE_ID_HSSI_ETH 0x6\n+#define FME_FEATURE_ID_GLOBAL_DPERF 0x7\n+#define FME_FEATURE_ID_QSPI_FLASH 0x8\n+#define FME_FEATURE_ID_EMIF_MGMT  0x9\n+\n+#define PORT_FEATURE_ID_HEADER FEATURE_ID_FIU_HEADER\n+#define PORT_FEATURE_ID_ERROR 0x10\n+#define PORT_FEATURE_ID_UMSG 0x12\n+#define PORT_FEATURE_ID_UINT 0x13\n+#define PORT_FEATURE_ID_STP 0x14\n+#define PORT_FEATURE_ID_UAFU FEATURE_ID_AFU\n \n /*\n  * All headers and structures must be byte-packed to match the spec.\ndiff --git a/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c\nindex 848e518..c779e0c 100644\n--- a/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c\n+++ b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c\n@@ -28,121 +28,24 @@ struct build_feature_devs_info {\n \tstruct ifpga_hw *hw;\n };\n \n-struct feature_info {\n-\tconst char *name;\n-\tu32 resource_size;\n-\tint feature_index;\n-\tint revision_id;\n-\tunsigned int vec_start;\n-\tunsigned int vec_cnt;\n-\n-\tstruct feature_ops *ops;\n-};\n+static int feature_revision(void __iomem *start)\n+{\n+\tstruct feature_header header;\n \n-/* indexed by fme feature IDs which are defined in 'enum fme_feature_id'. */\n-static struct feature_info fme_features[] = {\n-\t{\n-\t\t.name = FME_FEATURE_HEADER,\n-\t\t.resource_size = sizeof(struct feature_fme_header),\n-\t\t.feature_index = FME_FEATURE_ID_HEADER,\n-\t\t.revision_id = FME_HEADER_REVISION,\n-\t\t.ops = &fme_hdr_ops,\n-\t},\n-\t{\n-\t\t.name = FME_FEATURE_THERMAL_MGMT,\n-\t\t.resource_size = sizeof(struct feature_fme_thermal),\n-\t\t.feature_index = FME_FEATURE_ID_THERMAL_MGMT,\n-\t\t.revision_id = FME_THERMAL_MGMT_REVISION,\n-\t\t.ops = &fme_thermal_mgmt_ops,\n-\t},\n-\t{\n-\t\t.name = FME_FEATURE_POWER_MGMT,\n-\t\t.resource_size = sizeof(struct feature_fme_power),\n-\t\t.feature_index = FME_FEATURE_ID_POWER_MGMT,\n-\t\t.revision_id = FME_POWER_MGMT_REVISION,\n-\t\t.ops = &fme_power_mgmt_ops,\n-\t},\n-\t{\n-\t\t.name = FME_FEATURE_GLOBAL_IPERF,\n-\t\t.resource_size = sizeof(struct feature_fme_iperf),\n-\t\t.feature_index = FME_FEATURE_ID_GLOBAL_IPERF,\n-\t\t.revision_id = FME_GLOBAL_IPERF_REVISION,\n-\t\t.ops = &fme_global_iperf_ops,\n-\t},\n-\t{\n-\t\t.name = FME_FEATURE_GLOBAL_ERR,\n-\t\t.resource_size = sizeof(struct feature_fme_err),\n-\t\t.feature_index = FME_FEATURE_ID_GLOBAL_ERR,\n-\t\t.revision_id = FME_GLOBAL_ERR_REVISION,\n-\t\t.ops = &fme_global_err_ops,\n-\t},\n-\t{\n-\t\t.name = FME_FEATURE_PR_MGMT,\n-\t\t.resource_size = sizeof(struct feature_fme_pr),\n-\t\t.feature_index = FME_FEATURE_ID_PR_MGMT,\n-\t\t.revision_id = FME_PR_MGMT_REVISION,\n-\t\t.ops = &fme_pr_mgmt_ops,\n-\t},\n-\t{\n-\t\t.name = FME_FEATURE_HSSI_ETH,\n-\t\t.resource_size = sizeof(struct feature_fme_hssi),\n-\t\t.feature_index = FME_FEATURE_ID_HSSI_ETH,\n-\t\t.revision_id = FME_HSSI_ETH_REVISION\n-\t},\n-\t{\n-\t\t.name = FME_FEATURE_GLOBAL_DPERF,\n-\t\t.resource_size = sizeof(struct feature_fme_dperf),\n-\t\t.feature_index = FME_FEATURE_ID_GLOBAL_DPERF,\n-\t\t.revision_id = FME_GLOBAL_DPERF_REVISION,\n-\t\t.ops = &fme_global_dperf_ops,\n-\t}\n-};\n+\theader.csr = readq(start);\n \n-static struct feature_info port_features[] = {\n-\t{\n-\t\t.name = PORT_FEATURE_HEADER,\n-\t\t.resource_size = sizeof(struct feature_port_header),\n-\t\t.feature_index = PORT_FEATURE_ID_HEADER,\n-\t\t.revision_id = PORT_HEADER_REVISION,\n-\t\t.ops = &ifpga_rawdev_port_hdr_ops,\n-\t},\n-\t{\n-\t\t.name = PORT_FEATURE_ERR,\n-\t\t.resource_size = sizeof(struct feature_port_error),\n-\t\t.feature_index = PORT_FEATURE_ID_ERROR,\n-\t\t.revision_id = PORT_ERR_REVISION,\n-\t\t.ops = &ifpga_rawdev_port_error_ops,\n-\t},\n-\t{\n-\t\t.name = PORT_FEATURE_UMSG,\n-\t\t.resource_size = sizeof(struct feature_port_umsg),\n-\t\t.feature_index = PORT_FEATURE_ID_UMSG,\n-\t\t.revision_id = PORT_UMSG_REVISION,\n-\t},\n-\t{\n-\t\t.name = PORT_FEATURE_UINT,\n-\t\t.resource_size = sizeof(struct feature_port_uint),\n-\t\t.feature_index = PORT_FEATURE_ID_UINT,\n-\t\t.revision_id = PORT_UINT_REVISION,\n-\t\t.ops = &ifpga_rawdev_port_uint_ops,\n-\t},\n-\t{\n-\t\t.name = PORT_FEATURE_STP,\n-\t\t.resource_size = PORT_FEATURE_STP_REGION_SIZE,\n-\t\t.feature_index = PORT_FEATURE_ID_STP,\n-\t\t.revision_id = PORT_STP_REVISION,\n-\t\t.ops = &ifpga_rawdev_port_stp_ops,\n-\t},\n-\t{\n-\t\t.name = PORT_FEATURE_UAFU,\n-\t\t/* UAFU feature size should be read from PORT_CAP.MMIOSIZE.\n-\t\t * Will set uafu feature size while parse port device.\n-\t\t */\n-\t\t.resource_size = 0,\n-\t\t.feature_index = PORT_FEATURE_ID_UAFU,\n-\t\t.revision_id = PORT_UAFU_REVISION\n-\t},\n-};\n+\treturn header.revision;\n+}\n+\n+static u32 feature_size(void __iomem *start)\n+{\n+\tstruct feature_header header;\n+\n+\theader.csr = readq(start);\n+\n+\t/*the size of private feature is 4KB aligned*/\n+\treturn header.next_header_offset ? header.next_header_offset:4096;\n+}\n \n static u64 feature_id(void __iomem *start)\n {\n@@ -152,7 +55,7 @@ static u64 feature_id(void __iomem *start)\n \n \tswitch (header.type) {\n \tcase FEATURE_TYPE_FIU:\n-\t\treturn FEATURE_ID_HEADER;\n+\t\treturn FEATURE_ID_FIU_HEADER;\n \tcase FEATURE_TYPE_PRIVATE:\n \t\treturn header.id;\n \tcase FEATURE_TYPE_AFU:\n@@ -165,37 +68,36 @@ static u64 feature_id(void __iomem *start)\n \n static int\n build_info_add_sub_feature(struct build_feature_devs_info *binfo,\n-\t\t\t   struct feature_info *finfo, void __iomem *start)\n+\t\tvoid __iomem *start, u64 fid, unsigned int size,\n+\t\tunsigned int vec_start,\n+\t\tunsigned int vec_cnt)\n {\n \tstruct ifpga_hw *hw = binfo->hw;\n \tstruct feature *feature = NULL;\n-\tint feature_idx = finfo->feature_index;\n-\tunsigned int vec_start = finfo->vec_start;\n-\tunsigned int vec_cnt = finfo->vec_cnt;\n \tstruct feature_irq_ctx *ctx = NULL;\n \tint port_id, ret = 0;\n \tunsigned int i;\n \n-\tif (binfo->current_type == FME_ID) {\n-\t\tfeature = &hw->fme.sub_feature[feature_idx];\n-\t\tfeature->parent = &hw->fme;\n-\t} else if (binfo->current_type == PORT_ID) {\n-\t\tport_id = binfo->current_port_id;\n-\t\tfeature = &hw->port[port_id].sub_feature[feature_idx];\n-\t\tfeature->parent = &hw->port[port_id];\n-\t} else {\n-\t\treturn -EFAULT;\n-\t}\n+\tfid = fid?fid:feature_id(start);\n+\tsize = size?size:feature_size(start);\n+\n+\tfeature = opae_malloc(sizeof(struct feature));\n+\tif (!feature)\n+\t\treturn -ENOMEM;\n \n \tfeature->state = IFPGA_FEATURE_ATTACHED;\n \tfeature->addr = start;\n-\tfeature->id = feature_id(start);\n-\tfeature->size = finfo->resource_size;\n-\tfeature->name = finfo->name;\n-\tfeature->revision = finfo->revision_id;\n-\tfeature->ops = finfo->ops;\n+\tfeature->id = fid;\n+\tfeature->size = size;\n+\tfeature->revision = feature_revision(start);\n \tfeature->phys_addr = binfo->phys_addr +\n \t\t\t\t((u8 *)start - (u8 *)binfo->ioaddr);\n+\tfeature->vec_start = vec_start;\n+\tfeature->vec_cnt = vec_cnt;\n+\n+\tdev_debug(binfo, \"%s: id=0x%llx, phys_addr=0x%llx, size=%u\\n\",\n+\t\t\t__func__, (unsigned long long)feature->id,\n+\t\t\t(unsigned long long)feature->phys_addr, size);\n \n \tif (vec_cnt) {\n \t\tif (vec_start + vec_cnt <= vec_start)\n@@ -215,22 +117,32 @@ static u64 feature_id(void __iomem *start)\n \tfeature->ctx_num = vec_cnt;\n \tfeature->vfio_dev_fd = binfo->pci_data->vfio_dev_fd;\n \n+\tif (binfo->current_type == FME_ID) {\n+\t\tfeature->parent = &hw->fme;\n+\t\tfeature->type = FEATURE_FME_TYPE;\n+\t\tfeature->name = get_fme_feature_name(fid);\n+\t\tTAILQ_INSERT_TAIL(&hw->fme.feature_list, feature, next);\n+\t} else if (binfo->current_type == PORT_ID) {\n+\t\tport_id = binfo->current_port_id;\n+\t\tfeature->parent = &hw->port[port_id];\n+\t\tfeature->type = FEATURE_PORT_TYPE;\n+\t\tfeature->name = get_port_feature_name(fid);\n+\t\tTAILQ_INSERT_TAIL(&hw->port[port_id].feature_list,\n+\t\t\t\tfeature, next);\n+\t} else {\n+\t\treturn -EFAULT;\n+\t}\n \treturn ret;\n }\n \n static int\n create_feature_instance(struct build_feature_devs_info *binfo,\n-\t\t\tvoid __iomem *start, struct feature_info *finfo)\n+\t\t\tvoid __iomem *start, u64 fid,\n+\t\t\tunsigned int size, unsigned int vec_start,\n+\t\t\tunsigned int vec_cnt)\n {\n-\tstruct feature_header *hdr = start;\n-\n-\tif (finfo->revision_id != SKIP_REVISION_CHECK &&\n-\t    hdr->revision > finfo->revision_id) {\n-\t\tdev_err(binfo, \"feature %s revision :default:%x, now at:%x, mis-match.\\n\",\n-\t\t\tfinfo->name, finfo->revision_id, hdr->revision);\n-\t}\n-\n-\treturn build_info_add_sub_feature(binfo, finfo, start);\n+\treturn build_info_add_sub_feature(binfo, start, fid, size, vec_start,\n+\t\t\tvec_cnt);\n }\n \n /*\n@@ -249,31 +161,30 @@ static bool feature_is_UAFU(struct build_feature_devs_info *binfo)\n static int parse_feature_port_uafu(struct build_feature_devs_info *binfo,\n \t\t\t\t   struct feature_header *hdr)\n {\n-\tenum port_feature_id id = PORT_FEATURE_ID_UAFU;\n+\tu64 id = PORT_FEATURE_ID_UAFU;\n \tstruct ifpga_afu_info *info;\n \tvoid *start = (void *)hdr;\n+\tstruct feature_port_header *port_hdr = binfo->ioaddr;\n+\tstruct feature_port_capability capability;\n \tint ret;\n+\tint size;\n \n-\tif (port_features[id].resource_size) {\n-\t\tret = create_feature_instance(binfo, hdr, &port_features[id]);\n-\t} else {\n-\t\tdev_err(binfo, \"the uafu feature header is mis-configured.\\n\");\n-\t\tret = -EINVAL;\n-\t}\n+\tcapability.csr = readq(&port_hdr->capability);\n+\n+\tsize = capability.mmio_size << 10;\n \n+\tret = create_feature_instance(binfo, hdr, id, size, 0, 0);\n \tif (ret)\n \t\treturn ret;\n \n-\t/* FIXME: need to figure out a better name */\n-\tinfo = malloc(sizeof(*info));\n+\tinfo = opae_malloc(sizeof(*info));\n \tif (!info)\n \t\treturn -ENOMEM;\n \n \tinfo->region[0].addr = start;\n \tinfo->region[0].phys_addr = binfo->phys_addr +\n \t\t\t(uint8_t *)start - (uint8_t *)binfo->ioaddr;\n-\tinfo->region[0].len = port_features[id].resource_size;\n-\tport_features[id].resource_size = 0;\n+\tinfo->region[0].len = size;\n \tinfo->num_regions = 1;\n \n \tbinfo->acc_info = info;\n@@ -320,6 +231,8 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)\n \tstruct opae_manager *mgr;\n \tstruct opae_bridge *br;\n \tstruct opae_accelerator *acc;\n+\tstruct ifpga_port_hw *port;\n+\tstruct feature *feature;\n \n \tif (!binfo->fiu)\n \t\treturn 0;\n@@ -337,7 +250,11 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)\n \t\tbr->id = binfo->current_port_id;\n \n \t\t/* update irq info */\n-\t\tinfo->num_irqs = port_features[PORT_FEATURE_ID_UINT].vec_cnt;\n+\t\tport = &hw->port[binfo->current_port_id];\n+\t\tfeature = get_feature_by_id(&port->feature_list,\n+\t\t\t\tPORT_FEATURE_ID_UINT);\n+\t\tif (feature)\n+\t\t\tinfo->num_irqs = feature->vec_cnt;\n \n \t\tacc = opae_accelerator_alloc(hw->adapter->name,\n \t\t\t\t\t     &ifpga_acc_ops, info);\n@@ -353,7 +270,7 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)\n \n \t} else if (binfo->current_type == FME_ID) {\n \t\tmgr = opae_manager_alloc(hw->adapter->name, &ifpga_mgr_ops,\n-\t\t\t\t\t binfo->fiu);\n+\t\t\t\tbinfo->fiu);\n \t\tif (!mgr)\n \t\t\treturn -ENOMEM;\n \n@@ -402,10 +319,10 @@ static int parse_feature_fme(struct build_feature_devs_info *binfo,\n \t/* Update FME states */\n \tfme->state = IFPGA_FME_IMPLEMENTED;\n \tfme->parent = hw;\n+\tTAILQ_INIT(&fme->feature_list);\n \tspinlock_init(&fme->lock);\n \n-\treturn create_feature_instance(binfo, start,\n-\t\t\t\t       &fme_features[FME_FEATURE_ID_HEADER]);\n+\treturn create_feature_instance(binfo, start, 0, 0, 0, 0);\n }\n \n static int parse_feature_port(struct build_feature_devs_info *binfo,\n@@ -433,29 +350,19 @@ static int parse_feature_port(struct build_feature_devs_info *binfo,\n \tport->parent = hw;\n \tport->state = IFPGA_PORT_ATTACHED;\n \tspinlock_init(&port->lock);\n+\tTAILQ_INIT(&port->feature_list);\n \n-\treturn create_feature_instance(binfo, start,\n-\t\t\t\t      &port_features[PORT_FEATURE_ID_HEADER]);\n+\treturn create_feature_instance(binfo, start, 0, 0, 0, 0);\n }\n \n static void enable_port_uafu(struct build_feature_devs_info *binfo,\n \t\t\t     void __iomem *start)\n {\n-\tenum port_feature_id id = PORT_FEATURE_ID_UAFU;\n-\tstruct feature_port_header *port_hdr;\n-\tstruct feature_port_capability capability;\n \tstruct ifpga_port_hw *port = &binfo->hw->port[binfo->current_port_id];\n \n-\tport_hdr = (struct feature_port_header *)start;\n-\tcapability.csr = readq(&port_hdr->capability);\n-\tport_features[id].resource_size = (capability.mmio_size << 10);\n-\n-\t/*\n-\t * From spec, to Enable UAFU, we should reset related port,\n-\t * or the whole mmio space in this UAFU will be invalid\n-\t */\n-\tif (port_features[id].resource_size)\n-\t\tfpga_port_reset(port);\n+\tUNUSED(start);\n+\n+\tfpga_port_reset(port);\n }\n \n static int parse_feature_fiu(struct build_feature_devs_info *binfo,\n@@ -505,44 +412,45 @@ static int parse_feature_fiu(struct build_feature_devs_info *binfo,\n }\n \n static void parse_feature_irqs(struct build_feature_devs_info *binfo,\n-\t\t\t       void __iomem *start, struct feature_info *finfo)\n+\t\tvoid __iomem *start, unsigned int *vec_start,\n+\t\tunsigned int *vec_cnt)\n {\n-\tfinfo->vec_start = 0;\n-\tfinfo->vec_cnt = 0;\n-\n \tUNUSED(binfo);\n+\tu64 id;\n+\n+\tid = feature_id(start);\n \n-\tif (!strcmp(finfo->name, PORT_FEATURE_UINT)) {\n+\tif (id == PORT_FEATURE_ID_UINT) {\n \t\tstruct feature_port_uint *port_uint = start;\n \t\tstruct feature_port_uint_cap uint_cap;\n \n \t\tuint_cap.csr = readq(&port_uint->capability);\n \t\tif (uint_cap.intr_num) {\n-\t\t\tfinfo->vec_start = uint_cap.first_vec_num;\n-\t\t\tfinfo->vec_cnt = uint_cap.intr_num;\n+\t\t\t*vec_start = uint_cap.first_vec_num;\n+\t\t\t*vec_cnt = uint_cap.intr_num;\n \t\t} else {\n \t\t\tdev_debug(binfo, \"UAFU doesn't support interrupt\\n\");\n \t\t}\n-\t} else if (!strcmp(finfo->name, PORT_FEATURE_ERR)) {\n+\t} else if (id == PORT_FEATURE_ID_ERROR) {\n \t\tstruct feature_port_error *port_err = start;\n \t\tstruct feature_port_err_capability port_err_cap;\n \n \t\tport_err_cap.csr = readq(&port_err->error_capability);\n \t\tif (port_err_cap.support_intr) {\n-\t\t\tfinfo->vec_start = port_err_cap.intr_vector_num;\n-\t\t\tfinfo->vec_cnt = 1;\n+\t\t\t*vec_start = port_err_cap.intr_vector_num;\n+\t\t\t*vec_cnt = 1;\n \t\t} else {\n \t\t\tdev_debug(&binfo, \"Port error doesn't support interrupt\\n\");\n \t\t}\n \n-\t} else if (!strcmp(finfo->name, FME_FEATURE_GLOBAL_ERR)) {\n+\t} else if (id == FME_FEATURE_ID_GLOBAL_ERR) {\n \t\tstruct feature_fme_err *fme_err = start;\n \t\tstruct feature_fme_error_capability fme_err_cap;\n \n \t\tfme_err_cap.csr = readq(&fme_err->fme_err_capability);\n \t\tif (fme_err_cap.support_intr) {\n-\t\t\tfinfo->vec_start = fme_err_cap.intr_vector_num;\n-\t\t\tfinfo->vec_cnt = 1;\n+\t\t\t*vec_start = fme_err_cap.intr_vector_num;\n+\t\t\t*vec_cnt = 1;\n \t\t} else {\n \t\t\tdev_debug(&binfo, \"FME error doesn't support interrupt\\n\");\n \t\t}\n@@ -552,43 +460,23 @@ static void parse_feature_irqs(struct build_feature_devs_info *binfo,\n static int parse_feature_fme_private(struct build_feature_devs_info *binfo,\n \t\t\t\t     struct feature_header *hdr)\n {\n-\tstruct feature_header header;\n-\n-\theader.csr = readq(hdr);\n-\n-\tif (header.id >= ARRAY_SIZE(fme_features)) {\n-\t\tdev_err(binfo, \"FME feature id %x is not supported yet.\\n\",\n-\t\t\theader.id);\n-\t\treturn 0;\n-\t}\n+\tunsigned int vec_start = 0;\n+\tunsigned int vec_cnt = 0;\n \n-\tparse_feature_irqs(binfo, hdr, &fme_features[header.id]);\n+\tparse_feature_irqs(binfo, hdr, &vec_start, &vec_cnt);\n \n-\treturn create_feature_instance(binfo, hdr, &fme_features[header.id]);\n+\treturn create_feature_instance(binfo, hdr, 0, 0, vec_start, vec_cnt);\n }\n \n static int parse_feature_port_private(struct build_feature_devs_info *binfo,\n \t\t\t\t      struct feature_header *hdr)\n {\n-\tstruct feature_header header;\n-\tenum port_feature_id id;\n+\tunsigned int vec_start = 0;\n+\tunsigned int vec_cnt = 0;\n \n-\theader.csr = readq(hdr);\n-\t/*\n-\t * the region of port feature id is [0x10, 0x13], + 1 to reserve 0\n-\t * which is dedicated for port-hdr.\n-\t */\n-\tid = (header.id & 0x000f) + 1;\n-\n-\tif (id >= ARRAY_SIZE(port_features)) {\n-\t\tdev_err(binfo, \"Port feature id %x is not supported yet.\\n\",\n-\t\t\theader.id);\n-\t\treturn 0;\n-\t}\n-\n-\tparse_feature_irqs(binfo, hdr, &port_features[id]);\n+\tparse_feature_irqs(binfo, hdr, &vec_start, &vec_cnt);\n \n-\treturn create_feature_instance(binfo, hdr, &port_features[id]);\n+\treturn create_feature_instance(binfo, hdr, 0, 0, vec_start, vec_cnt);\n }\n \n static int parse_feature_private(struct build_feature_devs_info *binfo,\n@@ -651,12 +539,18 @@ static int parse_feature(struct build_feature_devs_info *binfo,\n \t\t}\n \n \t\thdr = (struct feature_header *)start;\n+\t\theader.csr = readq(hdr);\n+\n+\t\tdev_debug(binfo, \"%s: address=0x%p, val=0x%llx, header.id=0x%x, header.next_offset=0x%x, header.eol=0x%x, header.type=0x%x\\n\",\n+\t\t\t__func__, hdr, (unsigned long long)header.csr,\n+\t\t\theader.id, header.next_header_offset,\n+\t\t\theader.end_of_list, header.type);\n+\n \t\tret = parse_feature(binfo, hdr);\n \t\tif (ret)\n \t\t\treturn ret;\n \n-\t\theader.csr = readq(hdr);\n-\t\tif (!header.next_header_offset)\n+\t\tif (header.end_of_list || !header.next_header_offset)\n \t\t\tbreak;\n \t}\n \n@@ -746,20 +640,20 @@ static void ifpga_print_device_feature_list(struct ifpga_hw *hw)\n \tstruct ifpga_fme_hw *fme = &hw->fme;\n \tstruct ifpga_port_hw *port;\n \tstruct feature *feature;\n-\tint i, j;\n+\tint i;\n \n \tdev_info(hw, \"found fme_device, is in PF: %s\\n\",\n \t\t is_ifpga_hw_pf(hw) ? \"yes\" : \"no\");\n \n-\tfor (i = 0; i < FME_FEATURE_ID_MAX; i++) {\n-\t\tfeature = &fme->sub_feature[i];\n+\tifpga_for_each_fme_feature(fme, feature) {\n \t\tif (feature->state != IFPGA_FEATURE_ATTACHED)\n \t\t\tcontinue;\n \n-\t\tdev_info(hw, \"%12s:\t0x%p - 0x%p  - paddr: 0x%lx\\n\",\n+\t\tdev_info(hw, \"%12s:\t%p - %p  - paddr: 0x%lx\\n\",\n \t\t\t feature->name, feature->addr,\n \t\t\t feature->addr + feature->size - 1,\n \t\t\t (unsigned long)feature->phys_addr);\n+\n \t}\n \n \tfor (i = 0; i < MAX_FPGA_PORT_NUM; i++) {\n@@ -770,18 +664,18 @@ static void ifpga_print_device_feature_list(struct ifpga_hw *hw)\n \n \t\tdev_info(hw, \"port device: %d\\n\", port->port_id);\n \n-\t\tfor (j = 0; j < PORT_FEATURE_ID_MAX; j++) {\n-\t\t\tfeature = &port->sub_feature[j];\n+\t\tifpga_for_each_port_feature(port, feature) {\n \t\t\tif (feature->state != IFPGA_FEATURE_ATTACHED)\n \t\t\t\tcontinue;\n \n-\t\t\tdev_info(hw, \"%12s:\t0x%p - 0x%p  - paddr:0x%lx\\n\",\n+\t\t\tdev_info(hw, \"%12s:\t%p - %p  - paddr:0x%lx\\n\",\n \t\t\t\t feature->name,\n \t\t\t\t feature->addr,\n \t\t\t\t feature->addr +\n \t\t\t\t feature->size - 1,\n \t\t\t\t (unsigned long)feature->phys_addr);\n \t\t}\n+\n \t}\n }\n \n@@ -812,10 +706,13 @@ int ifpga_bus_enumerate(struct ifpga_hw *hw)\n int ifpga_bus_init(struct ifpga_hw *hw)\n {\n \tint i;\n+\tstruct ifpga_port_hw *port;\n \n \tfme_hw_init(&hw->fme);\n-\tfor (i = 0; i < MAX_FPGA_PORT_NUM; i++)\n-\t\tport_hw_init(&hw->port[i]);\n+\tfor (i = 0; i < MAX_FPGA_PORT_NUM; i++) {\n+\t\tport = &hw->port[i];\n+\t\tport_hw_init(port);\n+\t}\n \n \treturn 0;\n }\ndiff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c\nindex 0a27c38..d82a890 100644\n--- a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c\n+++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c\n@@ -70,6 +70,9 @@ int fpga_get_afu_uuid(struct ifpga_port_hw *port, struct uuid *uuid)\n \tstruct feature_port_header *port_hdr;\n \tu64 guidl, guidh;\n \n+\tif (!uuid)\n+\t\treturn -EINVAL;\n+\n \tport_hdr = get_port_feature_ioaddr_by_index(port, PORT_FEATURE_ID_UAFU);\n \n \tspinlock_lock(&port->lock);\n@@ -177,77 +180,146 @@ int port_clear_error(struct ifpga_port_hw *port)\n \treturn port_err_clear(port, error.csr);\n }\n \n-void fme_hw_uinit(struct ifpga_fme_hw *fme)\n+static struct feature_driver fme_feature_drvs[] = {\n+\t{FEATURE_DRV(FME_FEATURE_ID_HEADER, FME_FEATURE_HEADER,\n+\t\t\t&fme_hdr_ops),},\n+\t{FEATURE_DRV(FME_FEATURE_ID_THERMAL_MGMT, FME_FEATURE_THERMAL_MGMT,\n+\t\t\t&fme_thermal_mgmt_ops),},\n+\t{FEATURE_DRV(FME_FEATURE_ID_POWER_MGMT, FME_FEATURE_POWER_MGMT,\n+\t\t\t&fme_power_mgmt_ops),},\n+\t{FEATURE_DRV(FME_FEATURE_ID_GLOBAL_ERR, FME_FEATURE_GLOBAL_ERR,\n+\t\t\t&fme_global_err_ops),},\n+\t{FEATURE_DRV(FME_FEATURE_ID_PR_MGMT, FME_FEATURE_PR_MGMT,\n+\t\t\t&fme_pr_mgmt_ops),},\n+\t{FEATURE_DRV(FME_FEATURE_ID_GLOBAL_DPERF, FME_FEATURE_GLOBAL_DPERF,\n+\t\t\t&fme_global_dperf_ops),},\n+\t{FEATURE_DRV(FME_FEATURE_ID_HSSI_ETH, FME_FEATURE_HSSI_ETH,\n+\t&fme_hssi_eth_ops),},\n+\t{FEATURE_DRV(FME_FEATURE_ID_EMIF_MGMT, FME_FEATURE_EMIF_MGMT,\n+\t&fme_emif_ops),},\n+\t{0, NULL, NULL}, /* end of arrary */\n+};\n+\n+static struct feature_driver port_feature_drvs[] = {\n+\t{FEATURE_DRV(PORT_FEATURE_ID_HEADER, PORT_FEATURE_HEADER,\n+\t\t\t&ifpga_rawdev_port_hdr_ops)},\n+\t{FEATURE_DRV(PORT_FEATURE_ID_ERROR, PORT_FEATURE_ERR,\n+\t\t\t&ifpga_rawdev_port_error_ops)},\n+\t{FEATURE_DRV(PORT_FEATURE_ID_UINT, PORT_FEATURE_UINT,\n+\t\t\t&ifpga_rawdev_port_uint_ops)},\n+\t{FEATURE_DRV(PORT_FEATURE_ID_STP, PORT_FEATURE_STP,\n+\t\t\t&ifpga_rawdev_port_stp_ops)},\n+\t{FEATURE_DRV(PORT_FEATURE_ID_UAFU, PORT_FEATURE_UAFU,\n+\t\t\t&ifpga_rawdev_port_afu_ops)},\n+\t{0, NULL, NULL}, /* end of array */\n+};\n+\n+const char *get_fme_feature_name(unsigned int id)\n {\n-\tstruct feature *feature;\n-\tint i;\n+\tstruct feature_driver *drv = fme_feature_drvs;\n \n-\tif (fme->state != IFPGA_FME_IMPLEMENTED)\n-\t\treturn;\n+\twhile (drv->name) {\n+\t\tif (drv->id == id)\n+\t\t\treturn drv->name;\n \n-\tfor (i = 0; i < FME_FEATURE_ID_MAX; i++) {\n-\t\tfeature = &fme->sub_feature[i];\n-\t\tif (feature->state == IFPGA_FEATURE_ATTACHED &&\n-\t\t    feature->ops && feature->ops->uinit)\n-\t\t\tfeature->ops->uinit(feature);\n+\t\tdrv++;\n \t}\n+\n+\treturn NULL;\n }\n \n-int fme_hw_init(struct ifpga_fme_hw *fme)\n+const char *get_port_feature_name(unsigned int id)\n+{\n+\tstruct feature_driver *drv = port_feature_drvs;\n+\n+\twhile (drv->name) {\n+\t\tif (drv->id == id)\n+\t\t\treturn drv->name;\n+\n+\t\tdrv++;\n+\t}\n+\n+\treturn NULL;\n+}\n+\n+static void feature_uinit(struct ifpga_feature_list *list)\n {\n \tstruct feature *feature;\n-\tint i, ret;\n \n-\tif (fme->state != IFPGA_FME_IMPLEMENTED)\n-\t\treturn -EINVAL;\n+\tTAILQ_FOREACH(feature, list, next) {\n+\t\tif (feature->state != IFPGA_FEATURE_ATTACHED)\n+\t\t\tcontinue;\n+\t\tif (feature->ops && feature->ops->uinit)\n+\t\t\tfeature->ops->uinit(feature);\n+\t}\n+}\n \n-\tfor (i = 0; i < FME_FEATURE_ID_MAX; i++) {\n-\t\tfeature = &fme->sub_feature[i];\n-\t\tif (feature->state == IFPGA_FEATURE_ATTACHED &&\n-\t\t    feature->ops && feature->ops->init) {\n-\t\t\tret = feature->ops->init(feature);\n-\t\t\tif (ret) {\n-\t\t\t\tfme_hw_uinit(fme);\n-\t\t\t\treturn ret;\n+static int feature_init(struct feature_driver *drv,\n+\t\tstruct ifpga_feature_list *list)\n+{\n+\tstruct feature *feature;\n+\tint ret;\n+\n+\twhile (drv->ops) {\n+\t\tTAILQ_FOREACH(feature, list, next) {\n+\t\t\tif (feature->state != IFPGA_FEATURE_ATTACHED)\n+\t\t\t\tcontinue;\n+\t\t\tif (feature->id == drv->id) {\n+\t\t\t\tfeature->ops = drv->ops;\n+\t\t\t\tfeature->name = drv->name;\n+\t\t\t\tif (feature->ops->init) {\n+\t\t\t\t\tret = feature->ops->init(feature);\n+\t\t\t\t\tif (ret)\n+\t\t\t\t\t\tgoto error;\n+\t\t\t\t}\n \t\t\t}\n \t\t}\n+\t\tdrv++;\n \t}\n \n \treturn 0;\n+error:\n+\tfeature_uinit(list);\n+\treturn ret;\n }\n \n-void port_hw_uinit(struct ifpga_port_hw *port)\n+int fme_hw_init(struct ifpga_fme_hw *fme)\n {\n-\tstruct feature *feature;\n-\tint i;\n+\tint ret;\n \n-\tfor (i = 0; i < PORT_FEATURE_ID_MAX; i++) {\n-\t\tfeature = &port->sub_feature[i];\n-\t\tif (feature->state == IFPGA_FEATURE_ATTACHED &&\n-\t\t    feature->ops && feature->ops->uinit)\n-\t\t\tfeature->ops->uinit(feature);\n-\t}\n+\tif (fme->state != IFPGA_FME_IMPLEMENTED)\n+\t\treturn -ENODEV;\n+\n+\tret = feature_init(fme_feature_drvs, &fme->feature_list);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\treturn 0;\n+}\n+\n+void fme_hw_uinit(struct ifpga_fme_hw *fme)\n+{\n+\tfeature_uinit(&fme->feature_list);\n+}\n+\n+void port_hw_uinit(struct ifpga_port_hw *port)\n+{\n+\tfeature_uinit(&port->feature_list);\n }\n \n int port_hw_init(struct ifpga_port_hw *port)\n {\n-\tstruct feature *feature;\n-\tint i, ret;\n+\tint ret;\n \n \tif (port->state == IFPGA_PORT_UNUSED)\n \t\treturn 0;\n \n-\tfor (i = 0; i < PORT_FEATURE_ID_MAX; i++) {\n-\t\tfeature = &port->sub_feature[i];\n-\t\tif (feature->ops && feature->ops->init) {\n-\t\t\tret = feature->ops->init(feature);\n-\t\t\tif (ret) {\n-\t\t\t\tport_hw_uinit(port);\n-\t\t\t\treturn ret;\n-\t\t\t}\n-\t\t}\n-\t}\n+\tret = feature_init(port_feature_drvs, &port->feature_list);\n+\tif (ret)\n+\t\tgoto error;\n \n \treturn 0;\n+error:\n+\tport_hw_uinit(port);\n+\treturn ret;\n }\n-\ndiff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h\nindex 4391f2f..1d80f1d 100644\n--- a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h\n+++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h\n@@ -7,6 +7,18 @@\n \n #include \"ifpga_hw.h\"\n \n+struct feature_driver {\n+\tu64 id;\n+\tconst char *name;\n+\tstruct feature_ops *ops;\n+};\n+\n+/**\n+ * FEATURE_DRV - macro used to describe a specific feature driver\n+ */\n+#define FEATURE_DRV(n, s, p) \\\n+\t.id = (n), .name = (s), .ops = (p)\n+\n static inline struct ifpga_port_hw *\n get_port(struct ifpga_hw *hw, u32 port_id)\n {\n@@ -17,12 +29,10 @@\n }\n \n #define ifpga_for_each_fme_feature(hw, feature)\t\t\\\n-\tfor ((feature) = (hw)->sub_feature;\t\t\t\\\n-\t   (feature) < (hw)->sub_feature + (FME_FEATURE_ID_MAX); (feature)++)\n+\tTAILQ_FOREACH(feature, &hw->feature_list, next)\n \n-#define ifpga_for_each_port_feature(hw, feature)\t\t\\\n-\tfor ((feature) = (hw)->sub_feature;\t\t\t\\\n-\t   (feature) < (hw)->sub_feature + (PORT_FEATURE_ID_MAX); (feature)++)\n+#define ifpga_for_each_port_feature(port, feature)\t\t\\\n+\tTAILQ_FOREACH(feature, &port->feature_list, next)\n \n static inline struct feature *\n get_fme_feature_by_id(struct ifpga_fme_hw *fme, u64 id)\n@@ -50,16 +60,32 @@\n \treturn NULL;\n }\n \n+static inline struct feature *\n+get_feature_by_id(struct ifpga_feature_list *list, u64 id)\n+{\n+\tstruct feature *feature;\n+\n+\tTAILQ_FOREACH(feature, list, next)\n+\t\tif (feature->id == id)\n+\t\t\treturn feature;\n+\n+\treturn NULL;\n+}\n+\n static inline void  *\n get_fme_feature_ioaddr_by_index(struct ifpga_fme_hw *fme, int index)\n {\n-\treturn fme->sub_feature[index].addr;\n+\tstruct feature *feature = get_feature_by_id(&fme->feature_list, index);\n+\n+\treturn feature ? feature->addr : NULL;\n }\n \n static inline void  *\n get_port_feature_ioaddr_by_index(struct ifpga_port_hw *port, int index)\n {\n-\treturn port->sub_feature[index].addr;\n+\tstruct feature *feature = get_feature_by_id(&port->feature_list, index);\n+\n+\treturn feature ? feature->addr : NULL;\n }\n \n static inline bool\n@@ -143,6 +169,8 @@ int do_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size,\n extern struct feature_ops fme_pr_mgmt_ops;\n extern struct feature_ops fme_global_iperf_ops;\n extern struct feature_ops fme_global_dperf_ops;\n+extern struct feature_ops fme_hssi_eth_ops;\n+extern struct feature_ops fme_emif_ops;\n \n int port_get_prop(struct ifpga_port_hw *port, struct feature_prop *prop);\n int port_set_prop(struct ifpga_port_hw *port, struct feature_prop *prop);\n@@ -155,14 +183,16 @@ struct fpga_uafu_irq_set {\n };\n \n int port_set_irq(struct ifpga_port_hw *port, u32 feature_id, void *irq_set);\n+const char *get_fme_feature_name(unsigned int id);\n+const char *get_port_feature_name(unsigned int id);\n \n extern struct feature_ops ifpga_rawdev_port_hdr_ops;\n extern struct feature_ops ifpga_rawdev_port_error_ops;\n extern struct feature_ops ifpga_rawdev_port_stp_ops;\n extern struct feature_ops ifpga_rawdev_port_uint_ops;\n+extern struct feature_ops ifpga_rawdev_port_afu_ops;\n \n /* help functions for feature ops */\n int fpga_msix_set_block(struct feature *feature, unsigned int start,\n \t\t\tunsigned int count, s32 *fds);\n-\n #endif /* _IFPGA_FEATURE_DEV_H_ */\ndiff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme.c\nindex 4be60c0..9451086 100644\n--- a/drivers/raw/ifpga_rawdev/base/ifpga_fme.c\n+++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme.c\n@@ -732,3 +732,35 @@ struct feature_ops fme_power_mgmt_ops = {\n \t.get_prop = fme_power_mgmt_get_prop,\n \t.set_prop = fme_power_mgmt_set_prop,\n };\n+\n+static int fme_hssi_eth_init(struct feature *feature)\n+{\n+\tUNUSED(feature);\n+\treturn 0;\n+}\n+\n+static void fme_hssi_eth_uinit(struct feature *feature)\n+{\n+\tUNUSED(feature);\n+}\n+\n+struct feature_ops fme_hssi_eth_ops = {\n+\t.init = fme_hssi_eth_init,\n+\t.uinit = fme_hssi_eth_uinit,\n+};\n+\n+static int fme_emif_init(struct feature *feature)\n+{\n+\tUNUSED(feature);\n+\treturn 0;\n+}\n+\n+static void fme_emif_uinit(struct feature *feature)\n+{\n+\tUNUSED(feature);\n+}\n+\n+struct feature_ops fme_emif_ops = {\n+\t.init = fme_emif_init,\n+\t.uinit = fme_emif_uinit,\n+};\ndiff --git a/drivers/raw/ifpga_rawdev/base/ifpga_hw.h b/drivers/raw/ifpga_rawdev/base/ifpga_hw.h\nindex a20520c..8aaa056 100644\n--- a/drivers/raw/ifpga_rawdev/base/ifpga_hw.h\n+++ b/drivers/raw/ifpga_rawdev/base/ifpga_hw.h\n@@ -8,18 +8,28 @@\n #include \"ifpga_defines.h\"\n #include \"opae_ifpga_hw_api.h\"\n \n+/** List of private feateues */\n+TAILQ_HEAD(ifpga_feature_list, feature);\n+\n enum ifpga_feature_state {\n \tIFPGA_FEATURE_UNUSED = 0,\n \tIFPGA_FEATURE_ATTACHED,\n };\n \n+enum feature_type {\n+\tFEATURE_FME_TYPE = 0,\n+\tFEATURE_PORT_TYPE,\n+};\n+\n struct feature_irq_ctx {\n \tint eventfd;\n \tint idx;\n };\n \n struct feature {\n+\tTAILQ_ENTRY(feature)next;\n \tenum ifpga_feature_state state;\n+\tenum feature_type type;\n \tconst char *name;\n \tu64 id;\n \tu8 *addr;\n@@ -34,6 +44,8 @@ struct feature {\n \tvoid *parent;\t\t/* to parent hw data structure */\n \n \tstruct feature_ops *ops;/* callback to this private feature */\n+\tunsigned int vec_start;\n+\tunsigned int vec_cnt;\n };\n \n struct feature_ops {\n@@ -52,7 +64,7 @@ enum ifpga_fme_state {\n struct ifpga_fme_hw {\n \tenum ifpga_fme_state state;\n \n-\tstruct feature sub_feature[FME_FEATURE_ID_MAX];\n+\tstruct ifpga_feature_list feature_list;\n \tspinlock_t lock;\t/* protect hardware access */\n \n \tvoid *parent;\t\t/* pointer to ifpga_hw */\n@@ -78,7 +90,7 @@ enum ifpga_port_state {\n struct ifpga_port_hw {\n \tenum ifpga_port_state state;\n \n-\tstruct feature sub_feature[PORT_FEATURE_ID_MAX];\n+\tstruct ifpga_feature_list feature_list;\n \tspinlock_t lock;\t/* protect access to hw */\n \n \tvoid *parent;\t\t/* pointer to ifpga_hw */\ndiff --git a/drivers/raw/ifpga_rawdev/base/ifpga_port.c b/drivers/raw/ifpga_rawdev/base/ifpga_port.c\nindex 8b5668d..4628783 100644\n--- a/drivers/raw/ifpga_rawdev/base/ifpga_port.c\n+++ b/drivers/raw/ifpga_rawdev/base/ifpga_port.c\n@@ -386,3 +386,24 @@ struct feature_ops ifpga_rawdev_port_uint_ops = {\n \t.init = port_uint_init,\n \t.uinit = port_uint_uinit,\n };\n+\n+static int port_afu_init(struct feature *feature)\n+{\n+\tUNUSED(feature);\n+\n+\tdev_info(NULL, \"PORT AFU Init.\\n\");\n+\n+\treturn 0;\n+}\n+\n+static void port_afu_uinit(struct feature *feature)\n+{\n+\tUNUSED(feature);\n+\n+\tdev_info(NULL, \"PORT AFU UInit.\\n\");\n+}\n+\n+struct feature_ops ifpga_rawdev_port_afu_ops = {\n+\t.init = port_afu_init,\n+\t.uinit = port_afu_uinit,\n+};\n",
    "prefixes": [
        "v5",
        "08/14"
    ]
}