diff --git a/Documentation/ABI/testing/sysfs-bus-dfl b/Documentation/ABI/testing/sysfs-bus-dfl index b0265ab1..4d09774f 100644 --- a/Documentation/ABI/testing/sysfs-bus-dfl +++ b/Documentation/ABI/testing/sysfs-bus-dfl @@ -15,3 +15,12 @@ Description: Read-only. It returns feature identifier local to its DFL FIU type. Format: 0x%x + +What: /sys/bus/dfl/devices/dfl_dev.X/guid +Date: Nov 2023 +KernelVersion: 6.6 +Contact: Basheer Ahmed Muddebihal +Description: Read-only. It returns DFL feature identifier in the form GUID + (8-4-4-4-12) if the feature header version is 1(DFHv1). + + Format: 03020100-0504-0706-0809-0A0B0C0D0E0F (Little Endian) diff --git a/Documentation/devicetree/bindings/soc/intel/intel,dfl-mmio.yaml b/Documentation/devicetree/bindings/soc/intel/intel,dfl-mmio.yaml index 16f181d9..5d1f5e32 100644 --- a/Documentation/devicetree/bindings/soc/intel/intel,dfl-mmio.yaml +++ b/Documentation/devicetree/bindings/soc/intel/intel,dfl-mmio.yaml @@ -31,19 +31,19 @@ properties: This property establishes a reference to the Interrupt Controller Node, which manages interrupts for the device. - interrupt-user-start: + intel,user-interrupt-start: maxItems: 1 description: This property defines the initial user interrupts available on the specified controller. GIC are reserved for local purposes - fpga-interrupt-start: + intel,fpga-interrupt-start: maxItems: 1 descritpion: This property indicates the starting interrupt number within the GIC where FPGA-specific interrupts are mapped. - fpga-interrupt-lines: + intel,fpga-interrupt-lines: maxItems: 1 descritpions: This property specifies the total count of Interrupt Requests (IRQs) @@ -61,7 +61,7 @@ examples: compatible = "intel,dfl-mmio"; reg = <0xF9000000 0x00002000>; interrupt-parent = <&intc>; - interrupt-user-start = <32>; - fpga-interrupt-start = <49>; - fpga-interrupt-lines = <64>; + intel,user-interrupt-start = <32>; + intel,fpga-interrupt-start = <49>; + intel,fpga-interrupt-lines = <64>; }; diff --git a/Makefile b/Makefile index bf342cd2..2af3a173 100644 --- a/Makefile +++ b/Makefile @@ -48,9 +48,11 @@ endif # The module order matters; it determines the module order for # both the insmod and rmmod targets. The module order is also # leveraged for install packages by the dkms.conf file. +ifneq ($(CONFIG_FPGA),y) obj-m += fpga-mgr.o obj-m += fpga-bridge.o obj-m += fpga-region.o +endif ifndef CONFIG_FW_UPLOAD obj-m += fpga-image-load.o endif @@ -61,6 +63,7 @@ obj-m += dfl-fme-mgr.o obj-m += dfl-fme-region.o obj-m += dfl-fme-br.o obj-m += dfl-priv-feat.o +obj-m += dfl-branch.o obj-m += dfl-hssi.o obj-m += dfl-n3000-nios.o obj-m += dfl-emif.o @@ -107,6 +110,7 @@ dfl-fme-y += drivers/fpga/dfl-fme-perf.o dfl-fme-y += drivers/fpga/dfl-fme-error.o dfl-priv-feat-y += drivers/fpga/dfl-priv-feat-main.o +dfl-branch-y += drivers/fpga/dfl-branch.o dfl-fme-br-y := drivers/fpga/dfl-fme-br.o dfl-fme-mgr-y := drivers/fpga/dfl-fme-mgr.o diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index a41037f7..11defb68 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -202,6 +202,17 @@ config FPGA_DFL_PRIV_FEAT To compile this driver as a module, choose M here: the module will be called dfl_priv_feat. +config FPGA_DFL_BRANCH + tristate "FPGA DFL Branch Driver" + depends on FPGA_DFL + help + This is the feature driver for Branch DFL (Device Feature List), + which binds the DFL driver for the branch DFL feature using GUID, + and processes branch parameters and enumerates DFL devices in + the branch list. + + To compile this as a module, choose M here. + config FPGA_DFL_NIOS_INTEL_PAC_N3000 tristate "FPGA DFL NIOS Driver for Intel PAC N3000" depends on FPGA_DFL diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile index 027c651c..41e74da2 100644 --- a/drivers/fpga/Makefile +++ b/drivers/fpga/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_OF_FPGA_REGION) += of-fpga-region.o # FPGA Device Feature List Support obj-$(CONFIG_FPGA_DFL) += dfl.o +obj-$(CONFIG_FPGA_DFL_BRANCH) += dfl-branch.o obj-$(CONFIG_FPGA_DFL_FME) += dfl-fme.o obj-$(CONFIG_FPGA_DFL_PRIV_FEAT) += dfl-priv-feat.o obj-$(CONFIG_FPGA_DFL_FME_MGR) += dfl-fme-mgr.o diff --git a/drivers/fpga/dfl-branch.c b/drivers/fpga/dfl-branch.c new file mode 100644 index 00000000..f2a9168d --- /dev/null +++ b/drivers/fpga/dfl-branch.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for FPGA BRANCH DFL + * + * Copyright (C) 2023 Intel Corporation. + * + * Authors: + * Basheer Ahmed Muddebihal + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "dfl.h" + +#define DRV_NAME "dfl-branch" + +#define DFHv1_PARAM_ID_BRANCH_DFL 0xF00C +#define DFL_BRANCH_SIZE 0x2000 /*default DFL ROM Size*/ +#define DFL_BRANCH_PARAM_DATA_LEN 16 /*two 8-byte words*/ + +/* + * REL_N, 1'b0 = relative (offset from feature DFH start), + * 1'b1 = absolute (ARM or other non-PCIe use) + */ +#define DFHv1_BRANCH_DFL_ADDR_REL_N BIT_ULL(0) +#define DFHv1_BRANCH_DFL_ADDR GENMASK_ULL(63, 3) /* 63:3 of DFL address */ +#define DFHv1_BRANCH_DFL_SIZE GENMASK_ULL(63, 32) /* 63:32 size of DFL */ + +static int dfh_branch_get_param_vals(struct dfl_device *dfl_dev, int param_id, + u64 *bdfl_addr, size_t *bdfl_size, bool *rel_addr) +{ + struct device *dev = &dfl_dev->dev; + u64 addr_val, size_val; + size_t psize; + u64 *p; + + p = dfh_find_param(dfl_dev, param_id, &psize); + if (IS_ERR(p)) + return PTR_ERR(p); + + if (psize == DFL_BRANCH_PARAM_DATA_LEN) { + addr_val = *p; + size_val = *(p + 1); + dev_info(dev, "addr_val = %pa, size_val=%pa\n", &addr_val, &size_val); + } else { + dev_err(dev, "Branch parameters data is missing\n"); + return -EINVAL; + } + + if (FIELD_GET(DFHv1_BRANCH_DFL_ADDR_REL_N, addr_val)) + *rel_addr = false; + else + *rel_addr = true; + + *bdfl_addr = FIELD_GET(DFHv1_BRANCH_DFL_ADDR, addr_val) << 3; + *bdfl_size = FIELD_GET(DFHv1_BRANCH_DFL_SIZE, size_val); + + return 0; +} + +static int dfl_branch_process_dfl(struct dfl_device *dfl_dev) +{ + struct device *dev = &dfl_dev->dev; + struct dfl_fpga_enum_info *info; + struct dfl_fpga_cdev *cdev; + resource_size_t start, len; + resource_size_t feat_base; + bool rel_addr = true; + u64 *pstart, *pend; + size_t bdfl_size; + u64 bdfl_addr; + u64 next, v; + int ret; + + /* allocate enumeration info */ + info = dfl_fpga_enum_info_alloc(dev); + if (!info) + return -ENOMEM; + + pstart = dfl_dev->params; + pend = dfl_dev->params + dfl_dev->param_size / sizeof(u64); + + feat_base = dfl_dev->mmio_res.start; + + while (pstart < pend) { + v = *pstart; + + ret = dfh_branch_get_param_vals(dfl_dev, DFHv1_PARAM_ID_BRANCH_DFL, + &bdfl_addr, &bdfl_size, &rel_addr); + + if (!ret) { + if (rel_addr) { + start = feat_base + bdfl_addr; + dev_info(dev, "Start=%pa\n", &start); + } else { + start = bdfl_addr; + } + + len = bdfl_size ? bdfl_size : DFL_BRANCH_SIZE; + dfl_fpga_enum_info_add_dfl(info, start, len); + } + next = FIELD_GET(DFHv1_PARAM_HDR_NEXT_OFFSET, v); + pstart += next; + } + + /* start enumeration with prepared enumeration information */ + cdev = dfl_fpga_feature_devs_enumerate(info); + if (IS_ERR(cdev)) { + dev_err(&dfl_dev->dev, "Enumeration failure\n"); + ret = PTR_ERR(cdev); + goto info_free_exit; + } + + dfl_dev->cdev = cdev; + +info_free_exit: + dfl_fpga_enum_info_free(info); + + return ret; +} + +static int dfl_branch_probe(struct dfl_device *dfl_dev) +{ + struct device *dev = &dfl_dev->dev; + int ret; + + ret = dfl_branch_process_dfl(dfl_dev); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to find the branch dfl\n"); + + return 0; +} + +static void dfl_branch_remove(struct dfl_device *dfl_dev) +{ + dfl_fpga_feature_devs_remove(dfl_dev->cdev); +} + +#define DFL_BRANCH_GUID "30C45AEA-68F6-42E6-AEFB-15B4B5E28284" + +static const struct dfl_device_id dfl_branch_ids[] = { + { .guid_string = DFL_BRANCH_GUID }, + { } +}; +MODULE_DEVICE_TABLE(dfl, dfl_branch_ids); + +static struct dfl_driver dfl_branch_driver = { + .drv = { + .name = "dfl-branch", + }, + .id_table = dfl_branch_ids, + .probe = dfl_branch_probe, + .remove = dfl_branch_remove, +}; +module_dfl_driver(dfl_branch_driver); + +MODULE_ALIAS("dfl:t*f*g{" DFL_BRANCH_GUID "}"); +MODULE_DESCRIPTION("DFL Intel Branch DFL driver"); +MODULE_AUTHOR("Intel Corporation"); +MODULE_LICENSE("GPL"); diff --git a/drivers/fpga/dfl-platform.c b/drivers/fpga/dfl-platform.c index 28b4f25b..f07e18a0 100644 --- a/drivers/fpga/dfl-platform.c +++ b/drivers/fpga/dfl-platform.c @@ -20,6 +20,10 @@ #define DRV_NAME "dfl-platform" +#define USER_INTERRUPT_START 32 +#define FPGA_INTERRUPT_START 49 +#define FPGA_INTERRUPT_LINES 64 + struct dfl_platform_drvdata { struct dfl_fpga_cdev *cdev; /* container device */ }; @@ -37,6 +41,34 @@ static int dfl_platform_init_drvdata(struct platform_device *pdev) return 0; } +static void dfl_platform_process_intr_params(struct platform_device *pdev, + struct dfl_fpga_enum_info *info) +{ + struct device_node *node = pdev->dev.of_node; + int user_intr_start = USER_INTERRUPT_START; + int fpga_intr_start = FPGA_INTERRUPT_START; + int fpga_intr_lines = FPGA_INTERRUPT_LINES; + int reg; + + if (of_property_read_u32(node, "intel,user-interrupt-start", ®)) + dev_warn(&pdev->dev, "intel,user-interrupt-start value not set in device tree\n"); + else + user_intr_start = reg; + + if (of_property_read_u32(node, "intel,fpga-interrupt-start", ®)) + dev_warn(&pdev->dev, "intel,fpga-interrupt-start not set in device tree\n"); + else + fpga_intr_start = reg; + + if (of_property_read_u32(node, "intel,fpga-interrupt-lines", ®)) + dev_warn(&pdev->dev, "intel,interrupt-user-offset value not set in device tree\n"); + else + fpga_intr_lines = reg; + + info->gic_arm_ref = fpga_intr_start - user_intr_start; + info->fpga_intr_lines = fpga_intr_lines; +} + static void dfl_platform_remove_feature_devs(struct platform_device *pdev) { struct dfl_platform_drvdata *drvdata = platform_get_drvdata(pdev); @@ -68,6 +100,8 @@ static int dfl_platform_process_dfl_node(struct platform_device *pdev, goto err_map; } + dfl_platform_process_intr_params(pdev, info); + dfl_fpga_enum_info_add_dfl(info, start, len); /* release I/O mappings for next step enumeration */ @@ -113,6 +147,7 @@ static int dfl_platform_enumerate_feature_devs(struct platform_device *pdev, return ret; } + static int dfl_platform_probe(struct platform_device *pdev) { struct resource dfl_location; @@ -163,13 +198,13 @@ static int dfl_platform_remove(struct platform_device *pdev) static const struct of_device_id dfl_platform_match[] = { { .compatible = "intel,dfl-mmio", }, - {}, + {} }; MODULE_DEVICE_TABLE(of, dfl_platform_match); static const struct platform_device_id dfl_platform_ids[] = { { DRV_NAME, 0 }, - { } + {} }; MODULE_DEVICE_TABLE(platform, dfl_platform_ids); diff --git a/drivers/fpga/dfl-priv-feat-main.c b/drivers/fpga/dfl-priv-feat-main.c index 8d469a7d..b2cc621e 100644 --- a/drivers/fpga/dfl-priv-feat-main.c +++ b/drivers/fpga/dfl-priv-feat-main.c @@ -14,20 +14,29 @@ #include "dfl.h" #include "dfl-priv-feat.h" -static ssize_t -guid_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t group_id_show(struct device *dev, struct device_attribute *attr, char *buf) { struct dfl_device *ddev = to_dfl_dev(dev); + if (!ddev->dfh_version) + return -ENOENT; + + return sysfs_emit(buf, "0x%X\n", ddev->group_id); +} +static DEVICE_ATTR_RO(group_id); +static ssize_t inst_id_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct dfl_device *ddev = to_dfl_dev(dev); if (!ddev->dfh_version) return -ENOENT; - return sysfs_emit(buf, "%pUL\n", &ddev->guid); + return sysfs_emit(buf, "0x%X\n", ddev->inst_id); } -static DEVICE_ATTR_RO(guid); +static DEVICE_ATTR_RO(inst_id); static struct attribute *dfl_priv_feat_attrs[] = { - &dev_attr_guid.attr, + &dev_attr_group_id.attr, + &dev_attr_inst_id.attr, NULL, }; @@ -129,3 +138,4 @@ module_platform_driver(dfl_priv_feat_driver); MODULE_DESCRIPTION("FPGA Privare Feature driver"); MODULE_AUTHOR("Intel Corporation"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:dfl-priv-feat"); diff --git a/drivers/fpga/dfl.c b/drivers/fpga/dfl.c index 036a397d..a6b5d6ad 100644 --- a/drivers/fpga/dfl.c +++ b/drivers/fpga/dfl.c @@ -244,11 +244,49 @@ EXPORT_SYMBOL_GPL(dfl_fpga_check_port_id); static DEFINE_IDA(dfl_device_ida); +static bool dfl_feature_id_is_match(const struct dfl_device_id *id, struct dfl_device *ddev) +{ + return id->type == ddev->type && id->feature_id == ddev->feature_id; +} + +static bool dfl_guid_is_match(const char *guid_str, const guid_t *guid_dev) +{ + return dfl_guid_is_valid(guid_dev) && guid_parse_and_compare(guid_str, guid_dev); +} + +static int dfl_match_one_guid(struct device_driver *drv, void *data) +{ + struct dfl_driver *ddrv = to_dfl_drv(drv); + const struct dfl_device_id *id_entry; + struct dfl_device *ddev = data; + + id_entry = ddrv->id_table; + if (!id_entry) + return 0; + + while (*id_entry->guid_string) { + if (dfl_guid_is_match(id_entry->guid_string, &ddev->guid)) + return 1; + id_entry++; + } + return 0; +} + +static struct bus_type dfl_bus_type; + +static bool can_match_guid(struct dfl_device *ddev) +{ + return bus_for_each_drv(&dfl_bus_type, NULL, ddev, dfl_match_one_guid) > 0; +} + static const struct dfl_device_id * dfl_match_one_device(const struct dfl_device_id *id, struct dfl_device *ddev) { - if ((dfl_guid_is_valid(&ddev->guid) && guid_equal(&id->guid, &ddev->guid)) || - (id->type == ddev->type && id->feature_id == ddev->feature_id)) + if (dfl_guid_is_match(id->guid_string, &ddev->guid)) + return id; + + if (dfl_feature_id_is_match(id, ddev) && + !(dfl_guid_is_valid(&ddev->guid) && can_match_guid(ddev))) return id; return NULL; @@ -262,7 +300,7 @@ static int dfl_bus_match(struct device *dev, struct device_driver *drv) id_entry = ddrv->id_table; if (id_entry) { - while (id_entry->feature_id || dfl_guid_is_valid(&id_entry->guid)) { + while (id_entry->feature_id || *id_entry->guid_string) { if (dfl_match_one_device(id_entry, ddev)) { ddev->id_entry = id_entry; return 1; @@ -312,12 +350,14 @@ static int dfl_bus_uevent(const struct device *dev, struct kobj_uevent_env *env) #else const struct dfl_device *ddev = to_dfl_dev(dev); #endif - char alias[DFL_ALIAS_BUF_LEN]; + char alias[sizeof("dfl:tXXXXfXXXXg{}") + UUID_STRING_LEN]; - scnprintf(alias, DFL_ALIAS_BUF_LEN, "dfl:t%04Xf%04X", ddev->type, ddev->feature_id); - - if (!guid_is_null(&ddev->guid)) - scnprintf(alias + strlen(alias), DFL_ALIAS_BUF_LEN, "g{%pUL}", &ddev->guid); + if (guid_is_null(&ddev->guid)) + snprintf(alias, sizeof("dfl:tXXXXfXXXX"), "dfl:t%04Xf%04X", + ddev->type, ddev->feature_id); + else + snprintf(alias,sizeof("dfl:tXXXXfXXXXg{}") + UUID_STRING_LEN, + "dfl:t%04Xf%04Xg{%pUL}", ddev->type, ddev->feature_id, &ddev->guid); return add_uevent_var(env, "MODALIAS=%s", alias); } @@ -417,7 +457,12 @@ dfl_dev_add(struct dfl_feature_dev_data *fdata, ddev->feature_id = feature->id; ddev->revision = feature->revision; ddev->dfh_version = feature->dfh_version; + ddev->group_id = feature->group_id; + ddev->inst_id = feature->inst_id; ddev->cdev = fdata->dfl_cdev; + ddev->gic_arm_ref = feature->gic_arm_ref; + ddev->fpga_intr_lines = feature->fpga_intr_lines; + if (feature->param_size) { ddev->params = kmemdup(feature->params, feature->param_size, GFP_KERNEL); if (!ddev->params) { @@ -756,13 +801,14 @@ struct build_feature_devs_info { struct dfl_fpga_cdev *cdev; unsigned int nr_irqs; int *irq_table; - enum dfl_id_type type; void __iomem *ioaddr; resource_size_t start; resource_size_t len; struct list_head sub_features; int feature_num; + int gic_arm_ref; + int fpga_intr_lines; }; /** @@ -771,7 +817,9 @@ struct build_feature_devs_info { * @fid: id of this sub feature. * @revision: revision of this sub feature * @dfh_version: device feature header version. - * @guid: guid of this sub feature. + * @guid: GUID of this sub feature. + * @group_id: specify the group id of the feature. + * @inst_id: Instance id of the feature. * @mmio_res: mmio resource of this sub feature. * @ioaddr: mapped base address of mmio resource. * @node: node in sub_features linked list. @@ -785,11 +833,15 @@ struct dfl_feature_info { u8 revision; u8 dfh_version; guid_t guid; + u16 group_id; + u16 inst_id; struct resource mmio_res; void __iomem *ioaddr; struct list_head node; unsigned int irq_base; unsigned int nr_irqs; + int gic_arm_ref; + int fpga_intr_lines; unsigned int param_size; u64 params[]; }; @@ -846,6 +898,7 @@ binfo_create_feature_dev_data(struct build_feature_devs_info *binfo) fdata->num = binfo->feature_num; fdata->dfl_cdev = binfo->cdev; fdata->id = FEATURE_DEV_ID_UNUSED; + mutex_init(&fdata->lock); lockdep_set_class_and_name(&fdata->lock, &dfl_pdata_keys[type], dfl_pdata_key_strings[type]); @@ -868,6 +921,8 @@ binfo_create_feature_dev_data(struct build_feature_devs_info *binfo) feature->id = finfo->fid; feature->revision = finfo->revision; feature->dfh_version = finfo->dfh_version; + feature->gic_arm_ref = finfo->gic_arm_ref; + feature->fpga_intr_lines = finfo->fpga_intr_lines; if (finfo->param_size) { feature->params = devm_kmemdup(binfo->dev, @@ -1310,6 +1365,11 @@ create_feature_instance(struct build_feature_devs_info *binfo, finfo->fid = fid; finfo->revision = revision; finfo->dfh_version = dfh_ver; + finfo->group_id = dfl_feature_group_id(binfo->ioaddr + ofst); + finfo->inst_id = dfl_feature_inst_id(binfo->ioaddr + ofst); + finfo->gic_arm_ref = binfo->gic_arm_ref; + finfo->fpga_intr_lines = binfo->fpga_intr_lines; + if (dfh_ver == 1) { v = readq(binfo->ioaddr + ofst + DFHv1_CSR_ADDR); addr_off = FIELD_GET(DFHv1_CSR_ADDR_MASK, v) << 1; @@ -1341,22 +1401,10 @@ create_feature_instance(struct build_feature_devs_info *binfo, guid_l = readq(binfo->ioaddr + ofst + GUID_L); guid_h = readq(binfo->ioaddr + ofst + GUID_H); + finfo->guid = dfl_guid_init(guid_h, guid_l); + dev_dbg(binfo->dev, "dfl: GUID_H = 0x%llx , GUID_L = 0x%llx\n GUID = %pUL\n", + guid_h, guid_l, &finfo->guid); - if (guid_l || guid_h) { - dev_dbg(binfo->dev, "dfl: GUID_H = 0x%llx , GUID_L = 0x%llx\n", - guid_h, guid_l); - finfo->guid = GUID_INIT(FIELD_GET(DFL_GUID_H_A, guid_h), - FIELD_GET(DFL_GUID_H_B, guid_h), - FIELD_GET(DFL_GUID_H_C, guid_h), - FIELD_GET(DFL_GUID_L_D0, guid_l), - FIELD_GET(DFL_GUID_L_D1, guid_l), - FIELD_GET(DFL_GUID_L_D2, guid_l), - FIELD_GET(DFL_GUID_L_D3, guid_l), - FIELD_GET(DFL_GUID_L_D4, guid_l), - FIELD_GET(DFL_GUID_L_D5, guid_l), - FIELD_GET(DFL_GUID_L_D6, guid_l), - FIELD_GET(DFL_GUID_L_D7, guid_l)); - } } else { start = binfo->start + ofst; end = start + size - 1; @@ -1763,6 +1811,8 @@ dfl_fpga_feature_devs_enumerate(struct dfl_fpga_enum_info *info) binfo->cdev = cdev; INIT_LIST_HEAD(&binfo->sub_features); + binfo->gic_arm_ref = info->gic_arm_ref; + binfo->fpga_intr_lines = info->fpga_intr_lines; binfo->nr_irqs = info->nr_irqs; if (info->nr_irqs) binfo->irq_table = info->irq_table; diff --git a/drivers/fpga/dfl.h b/drivers/fpga/dfl.h index 32fb9c19..30af97da 100644 --- a/drivers/fpga/dfl.h +++ b/drivers/fpga/dfl.h @@ -239,7 +239,7 @@ int dfl_fpga_check_port_id(struct dfl_feature_dev_data *fdata, void *pport_id); * struct dfl_feature_id - dfl private feature id * * @id: unique dfl private feature id. - * @guid: unique dfl private guid. + * @guid: unique dfl private GUID. */ struct dfl_feature_id { u16 id; @@ -285,10 +285,12 @@ struct dfl_feature_irq_ctx { * @ops: ops of this sub feature. * @ddev: ptr to the dfl device of this sub feature. * @priv: priv data of this feature. + * @guid: sub feature GUID. * @dfh_version: version of the DFH + * @group_id: specify the group id of the feature. + * @inst_id: Instance id of the feature. * @param_size: size of dfh parameters * @params: point to memory copy of dfh parameters - * @guid: unique dfl private guid. */ struct dfl_feature { struct platform_device *dev; @@ -301,10 +303,14 @@ struct dfl_feature { const struct dfl_feature_ops *ops; struct dfl_device *ddev; void *priv; + guid_t guid; u8 dfh_version; + u16 group_id; + u16 inst_id; + int gic_arm_ref; + int fpga_intr_lines; unsigned int param_size; void *params; - guid_t guid; }; #define FEATURE_DEV_ID_UNUSED (-1) @@ -508,34 +514,41 @@ static inline u8 dfl_feature_revision(void __iomem *base) return (u8)FIELD_GET(DFH_REVISION, readq(base + DFH)); } -#define DFL_GUID_INVALID \ - GUID_INIT(0xffffffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff) +static inline u16 dfl_feature_inst_id(void __iomem *base) +{ + return (u16)FIELD_GET(DFHv1_CSR_SIZE_GRP_INSTANCE_ID, readq(base + DFHv1_CSR_SIZE_GRP)); +} + +static inline u16 dfl_feature_group_id(void __iomem *base) +{ + return (u16)FIELD_GET(DFHv1_CSR_SIZE_GRP_GROUPING_ID, readq(base + DFHv1_CSR_SIZE_GRP)); +} + +#define DFL_GUID_INVALID \ + GUID_INIT(0xffffffff, 0xffff, 0xffff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff) static inline bool dfl_guid_is_valid(const guid_t *guid) { - bool ret = true; - guid_t *guid_invalid = &DFL_GUID_INVALID; + guid_t *guid_invalid = &DFL_GUID_INVALID; - if (guid_is_null(guid) || guid_equal(guid, guid_invalid)) - ret = false; - return ret; + return !guid_is_null(guid) && !guid_equal(guid, guid_invalid); } -/* - * Bit definitions masks extract from GUID_H and GUID_L - * GUID_INIT(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) - */ -#define DFL_GUID_H_A GENMASK_ULL(63, 32) -#define DFL_GUID_H_B GENMASK_ULL(31, 16) -#define DFL_GUID_H_C GENMASK_ULL(15, 0) -#define DFL_GUID_L_D0 GENMASK_ULL(63, 56) -#define DFL_GUID_L_D1 GENMASK_ULL(55, 48) -#define DFL_GUID_L_D2 GENMASK_ULL(47, 40) -#define DFL_GUID_L_D3 GENMASK_ULL(39, 32) -#define DFL_GUID_L_D4 GENMASK_ULL(31, 24) -#define DFL_GUID_L_D5 GENMASK_ULL(23, 16) -#define DFL_GUID_L_D6 GENMASK_ULL(15, 8) -#define DFL_GUID_L_D7 GENMASK_ULL(7, 0) +static inline guid_t dfl_guid_init(u64 guid_h, u64 guid_l) +{ + return GUID_INIT(FIELD_GET(GENMASK_ULL(63, 32), guid_h), + FIELD_GET(GENMASK_ULL(31, 16), guid_h), + FIELD_GET(GENMASK_ULL(15, 0), guid_h), + FIELD_GET(GENMASK_ULL(63, 56), guid_l), + FIELD_GET(GENMASK_ULL(55, 48), guid_l), + FIELD_GET(GENMASK_ULL(47, 40), guid_l), + FIELD_GET(GENMASK_ULL(39, 32), guid_l), + FIELD_GET(GENMASK_ULL(31, 24), guid_l), + FIELD_GET(GENMASK_ULL(23, 16), guid_l), + FIELD_GET(GENMASK_ULL(15, 8), guid_l), + FIELD_GET(GENMASK_ULL(7, 0), guid_l)); +} /** * struct dfl_fpga_enum_info - DFL FPGA enumeration information @@ -550,6 +563,8 @@ struct dfl_fpga_enum_info { struct list_head dfls; unsigned int nr_irqs; int *irq_table; + int gic_arm_ref; + int fpga_intr_lines; }; /** diff --git a/drivers/tty/serial/8250/8250_dfl.c b/drivers/tty/serial/8250/8250_dfl.c index e04c9284..bb3cf1f1 100644 --- a/drivers/tty/serial/8250/8250_dfl.c +++ b/drivers/tty/serial/8250/8250_dfl.c @@ -150,12 +150,10 @@ static void dfl_uart_remove(struct dfl_device *dfl_dev) #define FME_FEATURE_ID_UART 0x24 -#define FME_GUID_UART \ - GUID_INIT(0x9e6641a6, 0xca26, 0xcc04, 0xe1, 0xdf, \ - 0x0d, 0x4a, 0xce, 0x8e, 0x48, 0x6c) +#define DFL_GUID_UART "9E6641A6-CA26-CC04-E1DF-0D4ACE8E486C" static const struct dfl_device_id dfl_uart_ids[] = { - { FME_ID, FME_FEATURE_ID_UART, .guid = FME_GUID_UART }, + { FME_ID, FME_FEATURE_ID_UART, .guid_string = DFL_GUID_UART }, { } }; MODULE_DEVICE_TABLE(dfl, dfl_uart_ids); diff --git a/include/linux/dfl.h b/include/linux/dfl.h index 6d66aa4a..d22a5c0f 100644 --- a/include/linux/dfl.h +++ b/include/linux/dfl.h @@ -34,10 +34,12 @@ enum dfl_id_type { * @num_irqs: number of IRQs supported by this dfl device. * @cdev: pointer to DFL FPGA container device this dfl device belongs to. * @id_entry: matched id entry in dfl driver's id table. - * @dfh_version: version of DFH for the device + * @guid: feature GUID of the dfl device. + * @dfh_version: version of DFH for the device. + * @group_id: specify the group id of the feature. + * @inst_id: Instance id of the feature. * @param_size: size of the block parameters in bytes * @params: pointer to block of parameters copied memory - * @guid: feature GUID of the dfl device. */ struct dfl_device { struct device dev; @@ -50,10 +52,14 @@ struct dfl_device { unsigned int num_irqs; struct dfl_fpga_cdev *cdev; const struct dfl_device_id *id_entry; + guid_t guid; u8 dfh_version; + u16 group_id; + u16 inst_id; + int gic_arm_ref; + int fpga_intr_lines; unsigned int param_size; void *params; - guid_t guid; }; /** diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index af5a9710..cc44214f 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -28,13 +28,14 @@ * @type: DFL FIU type of the device. See enum dfl_id_type. * @feature_id: feature identifier local to its DFL FIU type. * @driver_data: driver specific data. + * @guid_string: 36 char string of the form 03020100-0504-0706-0809-0A0B0C0D0E0F */ #define dfl_device_id BACKPORT_dfl_device_id struct BACKPORT_dfl_device_id { __u16 type; __u16 feature_id; - guid_t guid; kernel_ulong_t driver_data; + const char guid_string[UUID_STRING_LEN + 1]; }; #endif /* BACKPORT_LINUX_MOD_DEVICETABLE_H */ diff --git a/include/linux/uuid.h b/include/linux/uuid.h new file mode 100644 index 00000000..5a533c20 --- /dev/null +++ b/include/linux/uuid.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __BACKPORT_UUID_H +#define __BACKPORT_UUID_H + +#include +#include_next + +static inline +bool guid_parse_and_compare(const char *string, const guid_t *guid) +{ + guid_t guid_input; + if (guid_parse(string, &guid_input)) + return false; + return guid_equal(&guid_input, guid); +} + +static inline +bool uuid_parse_and_compare(const char *string, const uuid_t *uuid) +{ + uuid_t uuid_input; + if (uuid_parse(string, &uuid_input)) + return false; + return uuid_equal(&uuid_input, uuid); +} + +#endif diff --git a/scripts/mod/devicetable-offsets.c b/scripts/mod/devicetable-offsets.c index 993394b2..eaf79aec 100644 --- a/scripts/mod/devicetable-offsets.c +++ b/scripts/mod/devicetable-offsets.c @@ -246,7 +246,7 @@ int main(void) DEVID(dfl_device_id); DEVID_FIELD(dfl_device_id, type); DEVID_FIELD(dfl_device_id, feature_id); - DEVID_FIELD(dfl_device_id, guid); + DEVID_FIELD(dfl_device_id, guid_string); return 0; } diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 0d0df135..4389b3a0 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -1379,32 +1379,33 @@ static int do_mhi_entry(const char *filename, void *symval, char *alias) return 1; } -/* Looks like: dfl:tNfNg{guid} */ +/* Looks like: dfl:tNfNg{GUID} */ static int do_dfl_entry(const char *filename, void *symval, char *alias) { - int guid_cmp_val; - guid_t null_guid = {0}; + bool with_guid = true; + int len; DEF_FIELD(symval, dfl_device_id, type); DEF_FIELD(symval, dfl_device_id, feature_id); - DEF_FIELD(symval, dfl_device_id, guid); + DEF_FIELD_ADDR(symval, dfl_device_id, guid_string); - guid_cmp_val = memcmp(&null_guid, &guid, sizeof(guid_t)); + if (__uuid_is_valid(*guid_string) < 0) + with_guid = false; - if (feature_id == 0 && guid_cmp_val == 0) { - warn("Invalid dfl Device ID for in '%s'\n", filename); + if (feature_id == 0 && !with_guid) { + warn("Invalid dfl Device ID in '%s'\n", filename); return 0; } if (feature_id == 0) - strcpy(alias, "dfl:t*f*"); + len = snprintf(alias, ALIAS_SIZE, "dfl:t*f*"); else - snprintf(alias, ALIAS_SIZE, "dfl:t%04Xf%04X", type, feature_id); + len = snprintf(alias, ALIAS_SIZE, "dfl:t%04Xf%04X", type, feature_id); - if (guid_cmp_val) { - strcat(alias + strlen(alias), "g{"); - add_guid(alias, guid); - strcat(alias + strlen(alias), "}"); + if(with_guid) { + __uuid_uppercase((char *)guid_string); + snprintf(alias + len, ALIAS_SIZE - len, "g{%s}", *guid_string); } + add_wildcard(alias); return 1; }