diff --git a/prepare_source b/prepare_source index e665a4d..743e1c8 100644 --- a/prepare_source +++ b/prepare_source @@ -27,3 +27,5 @@ cp -r config "$dir/src/debian/" rm "$dir/src/debian/patches/debian/Revert-docs-kernel_feat.py-fix-potential-command-inj.patch" sed -i '/debian\/Revert-docs-kernel_feat\.py-fix-potential-command-inj\.patch/d' "$dir/src/debian/patches/series" + +import_upstream_patches diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0001-fpga-dfl-afu-use-PFN_DOWN-and-PFN_PHYS-helper-macros.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0001-fpga-dfl-afu-use-PFN_DOWN-and-PFN_PHYS-helper-macros.patch new file mode 100644 index 0000000..b6b2115 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0001-fpga-dfl-afu-use-PFN_DOWN-and-PFN_PHYS-helper-macros.patch @@ -0,0 +1,87 @@ +From 15acf7e9d055c32ec1f87643340febb9ea2fa7e6 Mon Sep 17 00:00:00 2001 +From: Peter Colberg +Date: Mon, 19 Jun 2023 15:56:34 -0400 +Subject: [PATCH] fpga: dfl: afu: use PFN_DOWN() and PFN_PHYS() helper macros + +Replace all shifts by PAGE_SHIFT with PFN_DOWN() and PFN_PHYS() helper +macros to convert between physical addresses and page frame numbers. + +These changes are cosmetic only; no functional changes. + +Suggested-by: Andy Shevchenko +Signed-off-by: Peter Colberg +Reviewed-by: Andy Shevchenko +--- + drivers/fpga/dfl-afu-dma-region.c | 7 ++++--- + drivers/fpga/dfl-afu-main.c | 5 +++-- + 2 files changed, 7 insertions(+), 5 deletions(-) + +diff --git a/drivers/fpga/dfl-afu-dma-region.c b/drivers/fpga/dfl-afu-dma-region.c +index 02b60fde0430..e8d54cfbb301 100644 +--- a/drivers/fpga/dfl-afu-dma-region.c ++++ b/drivers/fpga/dfl-afu-dma-region.c +@@ -10,6 +10,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -34,7 +35,7 @@ void afu_dma_region_init(struct dfl_feature_platform_data *pdata) + static int afu_dma_pin_pages(struct dfl_feature_platform_data *pdata, + struct dfl_afu_dma_region *region) + { +- int npages = region->length >> PAGE_SHIFT; ++ int npages = PFN_DOWN(region->length); + struct device *dev = &pdata->dev->dev; + int ret, pinned; + +@@ -82,7 +83,7 @@ static int afu_dma_pin_pages(struct dfl_feature_platform_data *pdata, + static void afu_dma_unpin_pages(struct dfl_feature_platform_data *pdata, + struct dfl_afu_dma_region *region) + { +- long npages = region->length >> PAGE_SHIFT; ++ long npages = PFN_DOWN(region->length); + struct device *dev = &pdata->dev->dev; + + unpin_user_pages(region->pages, npages); +@@ -101,7 +102,7 @@ static void afu_dma_unpin_pages(struct dfl_feature_platform_data *pdata, + */ + static bool afu_dma_check_continuous_pages(struct dfl_afu_dma_region *region) + { +- int npages = region->length >> PAGE_SHIFT; ++ int npages = PFN_DOWN(region->length); + int i; + + for (i = 0; i < npages - 1; i++) +diff --git a/drivers/fpga/dfl-afu-main.c b/drivers/fpga/dfl-afu-main.c +index 7f621e96d3b8..048c9b418c8b 100644 +--- a/drivers/fpga/dfl-afu-main.c ++++ b/drivers/fpga/dfl-afu-main.c +@@ -16,6 +16,7 @@ + + #include + #include ++#include + #include + #include + +@@ -816,7 +817,7 @@ static int afu_mmap(struct file *filp, struct vm_area_struct *vma) + + pdata = dev_get_platdata(&pdev->dev); + +- offset = vma->vm_pgoff << PAGE_SHIFT; ++ offset = PFN_PHYS(vma->vm_pgoff); + ret = afu_mmio_region_get_by_offset(pdata, offset, size, ®ion); + if (ret) + return ret; +@@ -837,7 +838,7 @@ static int afu_mmap(struct file *filp, struct vm_area_struct *vma) + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + return remap_pfn_range(vma, vma->vm_start, +- (region.phys + (offset - region.offset)) >> PAGE_SHIFT, ++ PFN_DOWN(region.phys + (offset - region.offset)), + size, vma->vm_page_prot); + } + diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0002-fpga-dfl-use-sysfs_emit-to-format-sysfs-values.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0002-fpga-dfl-use-sysfs_emit-to-format-sysfs-values.patch new file mode 100644 index 0000000..f6bc0c1 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0002-fpga-dfl-use-sysfs_emit-to-format-sysfs-values.patch @@ -0,0 +1,418 @@ +From f5b25480e04e342945b7f80b3979baa9b6f1c8d2 Mon Sep 17 00:00:00 2001 +From: Peter Colberg +Date: Mon, 19 Jun 2023 18:21:37 -0400 +Subject: [PATCH] fpga: dfl: use sysfs_emit() to format sysfs values + +Use sysfs_emit() to format sysfs values, which wraps vscnprintf() for a +PAGE_SIZE buffer. Remove explicit casts in favour of using the printk() +format specifier corresponding to the type of the formatted value. + +These changes are cosmetic only; no functional changes. + +Suggested-by: Andy Shevchenko +Signed-off-by: Peter Colberg +--- + drivers/fpga/dfl-afu-error.c | 7 +++---- + drivers/fpga/dfl-afu-main.c | 17 ++++++++--------- + drivers/fpga/dfl-fme-error.c | 19 ++++++++----------- + drivers/fpga/dfl-fme-main.c | 26 ++++++++++---------------- + drivers/fpga/dfl-fme-perf.c | 16 +++++++--------- + drivers/fpga/dfl.c | 4 ++-- + drivers/fpga/fpga-bridge.c | 2 +- + drivers/fpga/fpga-mgr.c | 4 ++-- + drivers/fpga/fpga-region.c | 5 ++--- + 9 files changed, 43 insertions(+), 57 deletions(-) + +diff --git a/drivers/fpga/dfl-afu-error.c b/drivers/fpga/dfl-afu-error.c +index ab7be6217368..6d113d606560 100644 +--- a/drivers/fpga/dfl-afu-error.c ++++ b/drivers/fpga/dfl-afu-error.c +@@ -125,7 +125,7 @@ static ssize_t errors_show(struct device *dev, struct device_attribute *attr, + error = readq(base + PORT_ERROR); + mutex_unlock(&pdata->lock); + +- return sprintf(buf, "0x%llx\n", (unsigned long long)error); ++ return sysfs_emit(buf, "0x%llx\n", error); + } + + static ssize_t errors_store(struct device *dev, struct device_attribute *attr, +@@ -156,7 +156,7 @@ static ssize_t first_error_show(struct device *dev, + error = readq(base + PORT_FIRST_ERROR); + mutex_unlock(&pdata->lock); + +- return sprintf(buf, "0x%llx\n", (unsigned long long)error); ++ return sysfs_emit(buf, "0x%llx\n", error); + } + static DEVICE_ATTR_RO(first_error); + +@@ -175,8 +175,7 @@ static ssize_t first_malformed_req_show(struct device *dev, + req1 = readq(base + PORT_MALFORMED_REQ1); + mutex_unlock(&pdata->lock); + +- return sprintf(buf, "0x%016llx%016llx\n", +- (unsigned long long)req1, (unsigned long long)req0); ++ return sysfs_emit(buf, "0x%016llx%016llx\n", req1, req0); + } + static DEVICE_ATTR_RO(first_malformed_req); + +diff --git a/drivers/fpga/dfl-afu-main.c b/drivers/fpga/dfl-afu-main.c +index 048c9b418c8b..dfb82d50ca56 100644 +--- a/drivers/fpga/dfl-afu-main.c ++++ b/drivers/fpga/dfl-afu-main.c +@@ -156,7 +156,7 @@ id_show(struct device *dev, struct device_attribute *attr, char *buf) + { + int id = port_get_id(to_platform_device(dev)); + +- return scnprintf(buf, PAGE_SIZE, "%d\n", id); ++ return sysfs_emit(buf, "%d\n", id); + } + static DEVICE_ATTR_RO(id); + +@@ -173,7 +173,7 @@ ltr_show(struct device *dev, struct device_attribute *attr, char *buf) + v = readq(base + PORT_HDR_CTRL); + mutex_unlock(&pdata->lock); + +- return sprintf(buf, "%x\n", (u8)FIELD_GET(PORT_CTRL_LATENCY, v)); ++ return sysfs_emit(buf, "%llx\n", FIELD_GET(PORT_CTRL_LATENCY, v)); + } + + static ssize_t +@@ -214,7 +214,7 @@ ap1_event_show(struct device *dev, struct device_attribute *attr, char *buf) + v = readq(base + PORT_HDR_STS); + mutex_unlock(&pdata->lock); + +- return sprintf(buf, "%x\n", (u8)FIELD_GET(PORT_STS_AP1_EVT, v)); ++ return sysfs_emit(buf, "%llx\n", FIELD_GET(PORT_STS_AP1_EVT, v)); + } + + static ssize_t +@@ -252,7 +252,7 @@ ap2_event_show(struct device *dev, struct device_attribute *attr, + v = readq(base + PORT_HDR_STS); + mutex_unlock(&pdata->lock); + +- return sprintf(buf, "%x\n", (u8)FIELD_GET(PORT_STS_AP2_EVT, v)); ++ return sysfs_emit(buf, "%llx\n", FIELD_GET(PORT_STS_AP2_EVT, v)); + } + + static ssize_t +@@ -289,7 +289,7 @@ power_state_show(struct device *dev, struct device_attribute *attr, char *buf) + v = readq(base + PORT_HDR_STS); + mutex_unlock(&pdata->lock); + +- return sprintf(buf, "0x%x\n", (u8)FIELD_GET(PORT_STS_PWR_STATE, v)); ++ return sysfs_emit(buf, "0x%llx\n", FIELD_GET(PORT_STS_PWR_STATE, v)); + } + static DEVICE_ATTR_RO(power_state); + +@@ -349,7 +349,7 @@ userclk_freqsts_show(struct device *dev, struct device_attribute *attr, + userclk_freqsts = readq(base + PORT_HDR_USRCLK_STS0); + mutex_unlock(&pdata->lock); + +- return sprintf(buf, "0x%llx\n", (unsigned long long)userclk_freqsts); ++ return sysfs_emit(buf, "0x%llx\n", userclk_freqsts); + } + static DEVICE_ATTR_RO(userclk_freqsts); + +@@ -367,8 +367,7 @@ userclk_freqcntrsts_show(struct device *dev, struct device_attribute *attr, + userclk_freqcntrsts = readq(base + PORT_HDR_USRCLK_STS1); + mutex_unlock(&pdata->lock); + +- return sprintf(buf, "0x%llx\n", +- (unsigned long long)userclk_freqcntrsts); ++ return sysfs_emit(buf, "0x%llx\n", userclk_freqcntrsts); + } + static DEVICE_ATTR_RO(userclk_freqcntrsts); + +@@ -473,7 +472,7 @@ afu_id_show(struct device *dev, struct device_attribute *attr, char *buf) + guidh = readq(base + GUID_H); + mutex_unlock(&pdata->lock); + +- return scnprintf(buf, PAGE_SIZE, "%016llx%016llx\n", guidh, guidl); ++ return sysfs_emit(buf, "%016llx%016llx\n", guidh, guidl); + } + static DEVICE_ATTR_RO(afu_id); + +diff --git a/drivers/fpga/dfl-fme-error.c b/drivers/fpga/dfl-fme-error.c +index 51c2892ec06d..a570f294ad82 100644 +--- a/drivers/fpga/dfl-fme-error.c ++++ b/drivers/fpga/dfl-fme-error.c +@@ -52,7 +52,7 @@ static ssize_t pcie0_errors_show(struct device *dev, + value = readq(base + PCIE0_ERROR); + mutex_unlock(&pdata->lock); + +- return sprintf(buf, "0x%llx\n", (unsigned long long)value); ++ return sysfs_emit(buf, "0x%llx\n", value); + } + + static ssize_t pcie0_errors_store(struct device *dev, +@@ -97,7 +97,7 @@ static ssize_t pcie1_errors_show(struct device *dev, + value = readq(base + PCIE1_ERROR); + mutex_unlock(&pdata->lock); + +- return sprintf(buf, "0x%llx\n", (unsigned long long)value); ++ return sysfs_emit(buf, "0x%llx\n", value); + } + + static ssize_t pcie1_errors_store(struct device *dev, +@@ -136,8 +136,7 @@ static ssize_t nonfatal_errors_show(struct device *dev, + + base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); + +- return sprintf(buf, "0x%llx\n", +- (unsigned long long)readq(base + RAS_NONFAT_ERROR)); ++ return sysfs_emit(buf, "0x%llx\n", readq(base + RAS_NONFAT_ERROR)); + } + static DEVICE_ATTR_RO(nonfatal_errors); + +@@ -148,8 +147,7 @@ static ssize_t catfatal_errors_show(struct device *dev, + + base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); + +- return sprintf(buf, "0x%llx\n", +- (unsigned long long)readq(base + RAS_CATFAT_ERROR)); ++ return sysfs_emit(buf, "0x%llx\n", readq(base + RAS_CATFAT_ERROR)); + } + static DEVICE_ATTR_RO(catfatal_errors); + +@@ -166,8 +164,7 @@ static ssize_t inject_errors_show(struct device *dev, + v = readq(base + RAS_ERROR_INJECT); + mutex_unlock(&pdata->lock); + +- return sprintf(buf, "0x%llx\n", +- (unsigned long long)FIELD_GET(INJECT_ERROR_MASK, v)); ++ return sysfs_emit(buf, "0x%llx\n", FIELD_GET(INJECT_ERROR_MASK, v)); + } + + static ssize_t inject_errors_store(struct device *dev, +@@ -211,7 +208,7 @@ static ssize_t fme_errors_show(struct device *dev, + value = readq(base + FME_ERROR); + mutex_unlock(&pdata->lock); + +- return sprintf(buf, "0x%llx\n", (unsigned long long)value); ++ return sysfs_emit(buf, "0x%llx\n", value); + } + + static ssize_t fme_errors_store(struct device *dev, +@@ -258,7 +255,7 @@ static ssize_t first_error_show(struct device *dev, + value = readq(base + FME_FIRST_ERROR); + mutex_unlock(&pdata->lock); + +- return sprintf(buf, "0x%llx\n", (unsigned long long)value); ++ return sysfs_emit(buf, "0x%llx\n", value); + } + static DEVICE_ATTR_RO(first_error); + +@@ -275,7 +272,7 @@ static ssize_t next_error_show(struct device *dev, + value = readq(base + FME_NEXT_ERROR); + mutex_unlock(&pdata->lock); + +- return sprintf(buf, "0x%llx\n", (unsigned long long)value); ++ return sysfs_emit(buf, "0x%llx\n", value); + } + static DEVICE_ATTR_RO(next_error); + +diff --git a/drivers/fpga/dfl-fme-main.c b/drivers/fpga/dfl-fme-main.c +index 3dcf990bd261..504febcc7c4d 100644 +--- a/drivers/fpga/dfl-fme-main.c ++++ b/drivers/fpga/dfl-fme-main.c +@@ -35,8 +35,7 @@ static ssize_t ports_num_show(struct device *dev, + + v = readq(base + FME_HDR_CAP); + +- return scnprintf(buf, PAGE_SIZE, "%u\n", +- (unsigned int)FIELD_GET(FME_CAP_NUM_PORTS, v)); ++ return sysfs_emit(buf, "%llu\n", FIELD_GET(FME_CAP_NUM_PORTS, v)); + } + static DEVICE_ATTR_RO(ports_num); + +@@ -54,7 +53,7 @@ static ssize_t bitstream_id_show(struct device *dev, + + v = readq(base + FME_HDR_BITSTREAM_ID); + +- return scnprintf(buf, PAGE_SIZE, "0x%llx\n", (unsigned long long)v); ++ return sysfs_emit(buf, "0x%llx\n", v); + } + static DEVICE_ATTR_RO(bitstream_id); + +@@ -72,7 +71,7 @@ static ssize_t bitstream_metadata_show(struct device *dev, + + v = readq(base + FME_HDR_BITSTREAM_MD); + +- return scnprintf(buf, PAGE_SIZE, "0x%llx\n", (unsigned long long)v); ++ return sysfs_emit(buf, "0x%llx\n", v); + } + static DEVICE_ATTR_RO(bitstream_metadata); + +@@ -86,8 +85,7 @@ static ssize_t cache_size_show(struct device *dev, + + v = readq(base + FME_HDR_CAP); + +- return sprintf(buf, "%u\n", +- (unsigned int)FIELD_GET(FME_CAP_CACHE_SIZE, v)); ++ return sysfs_emit(buf, "%llu\n", FIELD_GET(FME_CAP_CACHE_SIZE, v)); + } + static DEVICE_ATTR_RO(cache_size); + +@@ -101,8 +99,7 @@ static ssize_t fabric_version_show(struct device *dev, + + v = readq(base + FME_HDR_CAP); + +- return sprintf(buf, "%u\n", +- (unsigned int)FIELD_GET(FME_CAP_FABRIC_VERID, v)); ++ return sysfs_emit(buf, "%llu\n", FIELD_GET(FME_CAP_FABRIC_VERID, v)); + } + static DEVICE_ATTR_RO(fabric_version); + +@@ -116,8 +113,7 @@ static ssize_t socket_id_show(struct device *dev, + + v = readq(base + FME_HDR_CAP); + +- return sprintf(buf, "%u\n", +- (unsigned int)FIELD_GET(FME_CAP_SOCKET_ID, v)); ++ return sysfs_emit(buf, "%llu\n", FIELD_GET(FME_CAP_SOCKET_ID, v)); + } + static DEVICE_ATTR_RO(socket_id); + +@@ -286,8 +282,7 @@ static ssize_t temp1_max_policy_show(struct device *dev, + + v = readq(feature->ioaddr + FME_THERM_THRESHOLD); + +- return sprintf(buf, "%u\n", +- (unsigned int)FIELD_GET(TEMP_THRESHOLD1_POLICY, v)); ++ return sysfs_emit(buf, "%llu\n", FIELD_GET(TEMP_THRESHOLD1_POLICY, v)); + } + + static DEVICE_ATTR_RO(temp1_max_policy); +@@ -490,7 +485,7 @@ static ssize_t power1_xeon_limit_show(struct device *dev, + if (FIELD_GET(XEON_PWR_EN, v)) + xeon_limit = FIELD_GET(XEON_PWR_LIMIT, v); + +- return sprintf(buf, "%u\n", xeon_limit * 100000); ++ return sysfs_emit(buf, "%u\n", xeon_limit * 100000); + } + + static ssize_t power1_fpga_limit_show(struct device *dev, +@@ -505,7 +500,7 @@ static ssize_t power1_fpga_limit_show(struct device *dev, + if (FIELD_GET(FPGA_PWR_EN, v)) + fpga_limit = FIELD_GET(FPGA_PWR_LIMIT, v); + +- return sprintf(buf, "%u\n", fpga_limit * 100000); ++ return sysfs_emit(buf, "%u\n", fpga_limit * 100000); + } + + static ssize_t power1_ltr_show(struct device *dev, +@@ -516,8 +511,7 @@ static ssize_t power1_ltr_show(struct device *dev, + + v = readq(feature->ioaddr + FME_PWR_STATUS); + +- return sprintf(buf, "%u\n", +- (unsigned int)FIELD_GET(FME_LATENCY_TOLERANCE, v)); ++ return sysfs_emit(buf, "%llu\n", FIELD_GET(FME_LATENCY_TOLERANCE, v)); + } + + static DEVICE_ATTR_RO(power1_xeon_limit); +diff --git a/drivers/fpga/dfl-fme-perf.c b/drivers/fpga/dfl-fme-perf.c +index 7422d2bc6f37..1b072416069b 100644 +--- a/drivers/fpga/dfl-fme-perf.c ++++ b/drivers/fpga/dfl-fme-perf.c +@@ -524,20 +524,18 @@ static ssize_t fme_perf_event_show(struct device *dev, + { + struct dev_ext_attribute *eattr; + unsigned long config; +- char *ptr = buf; + + eattr = container_of(attr, struct dev_ext_attribute, attr); + config = (unsigned long)eattr->var; + +- ptr += sprintf(ptr, "event=0x%02x", (unsigned int)get_event(config)); +- ptr += sprintf(ptr, ",evtype=0x%02x", (unsigned int)get_evtype(config)); ++ if (!is_portid_root(get_portid(config))) ++ return sysfs_emit(buf, ++ "event=0x%02llx,evtype=0x%02llx,portid=?\n", ++ get_event(config), get_evtype(config)); + +- if (is_portid_root(get_portid(config))) +- ptr += sprintf(ptr, ",portid=0x%02x\n", FME_PORTID_ROOT); +- else +- ptr += sprintf(ptr, ",portid=?\n"); +- +- return (ssize_t)(ptr - buf); ++ return sysfs_emit(buf, "event=0x%02llx,evtype=0x%02llx,portid=0x%02x\n", ++ get_event(config), get_evtype(config), ++ FME_PORTID_ROOT); + } + + #define FME_EVENT_ATTR(_name) \ +diff --git a/drivers/fpga/dfl.c b/drivers/fpga/dfl.c +index dd7a783d53b5..db8141b68f79 100644 +--- a/drivers/fpga/dfl.c ++++ b/drivers/fpga/dfl.c +@@ -307,7 +307,7 @@ type_show(struct device *dev, struct device_attribute *attr, char *buf) + { + struct dfl_device *ddev = to_dfl_dev(dev); + +- return sprintf(buf, "0x%x\n", ddev->type); ++ return sysfs_emit(buf, "0x%x\n", ddev->type); + } + static DEVICE_ATTR_RO(type); + +@@ -316,7 +316,7 @@ feature_id_show(struct device *dev, struct device_attribute *attr, char *buf) + { + struct dfl_device *ddev = to_dfl_dev(dev); + +- return sprintf(buf, "0x%x\n", ddev->feature_id); ++ return sysfs_emit(buf, "0x%x\n", ddev->feature_id); + } + static DEVICE_ATTR_RO(feature_id); + +diff --git a/drivers/fpga/fpga-bridge.c b/drivers/fpga/fpga-bridge.c +index a024be2b84e2..d782054e56df 100644 +--- a/drivers/fpga/fpga-bridge.c ++++ b/drivers/fpga/fpga-bridge.c +@@ -287,7 +287,7 @@ static ssize_t name_show(struct device *dev, + { + struct fpga_bridge *bridge = to_fpga_bridge(dev); + +- return sprintf(buf, "%s\n", bridge->name); ++ return sysfs_emit(buf, "%s\n", bridge->name); + } + + static ssize_t state_show(struct device *dev, +diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c +index 06651389c592..26c311730950 100644 +--- a/drivers/fpga/fpga-mgr.c ++++ b/drivers/fpga/fpga-mgr.c +@@ -618,7 +618,7 @@ static ssize_t name_show(struct device *dev, + { + struct fpga_manager *mgr = to_fpga_manager(dev); + +- return sprintf(buf, "%s\n", mgr->name); ++ return sysfs_emit(buf, "%s\n", mgr->name); + } + + static ssize_t state_show(struct device *dev, +@@ -626,7 +626,7 @@ static ssize_t state_show(struct device *dev, + { + struct fpga_manager *mgr = to_fpga_manager(dev); + +- return sprintf(buf, "%s\n", state_str[mgr->state]); ++ return sysfs_emit(buf, "%s\n", state_str[mgr->state]); + } + + static ssize_t status_show(struct device *dev, +diff --git a/drivers/fpga/fpga-region.c b/drivers/fpga/fpga-region.c +index b364a929425c..eb50836c7789 100644 +--- a/drivers/fpga/fpga-region.c ++++ b/drivers/fpga/fpga-region.c +@@ -167,9 +167,8 @@ static ssize_t compat_id_show(struct device *dev, + if (!region->compat_id) + return -ENOENT; + +- return sprintf(buf, "%016llx%016llx\n", +- (unsigned long long)region->compat_id->id_h, +- (unsigned long long)region->compat_id->id_l); ++ return sysfs_emit(buf, "%016llx%016llx\n", region->compat_id->id_h, ++ region->compat_id->id_l); + } + + static DEVICE_ATTR_RO(compat_id); diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0003-fpga-dfl-omit-unneeded-casts-of-u64-values-for-dev_d.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0003-fpga-dfl-omit-unneeded-casts-of-u64-values-for-dev_d.patch new file mode 100644 index 0000000..bb5c92e --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0003-fpga-dfl-omit-unneeded-casts-of-u64-values-for-dev_d.patch @@ -0,0 +1,111 @@ +From 2dcebd1b35f4e13138b3af5dbe1bcadefad39362 Mon Sep 17 00:00:00 2001 +From: Peter Colberg +Date: Mon, 19 Jun 2023 18:21:38 -0400 +Subject: [PATCH] fpga: dfl: omit unneeded casts of u64 values for dev_dbg() + +Omit unneeded casts of u64 values to unsigned long long for use with +printk() format specifier %llx. Unlike user space, the kernel defines +u64 as unsigned long long for all architectures; see commit 2a7930bd77fe +("Documentation/printk-formats.txt: No casts needed for u64/s64"). + +These changes are cosmetic only; no functional changes. + +Suggested-by: Andy Shevchenko +Signed-off-by: Peter Colberg +--- + drivers/fpga/dfl-afu-dma-region.c | 14 ++++++-------- + drivers/fpga/dfl-afu-main.c | 4 +--- + drivers/fpga/dfl-fme-mgr.c | 5 ++--- + 3 files changed, 9 insertions(+), 14 deletions(-) + +diff --git a/drivers/fpga/dfl-afu-dma-region.c b/drivers/fpga/dfl-afu-dma-region.c +index e8d54cfbb301..374d96d5f6a6 100644 +--- a/drivers/fpga/dfl-afu-dma-region.c ++++ b/drivers/fpga/dfl-afu-dma-region.c +@@ -147,8 +147,7 @@ static int afu_dma_region_add(struct dfl_feature_platform_data *pdata, + struct dfl_afu *afu = dfl_fpga_pdata_get_private(pdata); + struct rb_node **new, *parent = NULL; + +- dev_dbg(&pdata->dev->dev, "add region (iova = %llx)\n", +- (unsigned long long)region->iova); ++ dev_dbg(&pdata->dev->dev, "add region (iova = %llx)\n", region->iova); + + new = &afu->dma_regions.rb_node; + +@@ -188,8 +187,7 @@ static void afu_dma_region_remove(struct dfl_feature_platform_data *pdata, + { + struct dfl_afu *afu; + +- dev_dbg(&pdata->dev->dev, "del region (iova = %llx)\n", +- (unsigned long long)region->iova); ++ dev_dbg(&pdata->dev->dev, "del region (iova = %llx)\n", region->iova); + + afu = dfl_fpga_pdata_get_private(pdata); + rb_erase(®ion->node, &afu->dma_regions); +@@ -211,7 +209,7 @@ void afu_dma_region_destroy(struct dfl_feature_platform_data *pdata) + region = container_of(node, struct dfl_afu_dma_region, node); + + dev_dbg(&pdata->dev->dev, "del region (iova = %llx)\n", +- (unsigned long long)region->iova); ++ region->iova); + + rb_erase(node, &afu->dma_regions); + +@@ -256,7 +254,7 @@ afu_dma_region_find(struct dfl_feature_platform_data *pdata, u64 iova, u64 size) + + if (dma_region_check_iova(region, iova, size)) { + dev_dbg(dev, "find region (iova = %llx)\n", +- (unsigned long long)region->iova); ++ region->iova); + return region; + } + +@@ -269,8 +267,8 @@ afu_dma_region_find(struct dfl_feature_platform_data *pdata, u64 iova, u64 size) + break; + } + +- dev_dbg(dev, "region with iova %llx and size %llx is not found\n", +- (unsigned long long)iova, (unsigned long long)size); ++ dev_dbg(dev, "region with iova %llx and size %llx is not found\n", iova, ++ size); + + return NULL; + } +diff --git a/drivers/fpga/dfl-afu-main.c b/drivers/fpga/dfl-afu-main.c +index dfb82d50ca56..2f10ecec3f64 100644 +--- a/drivers/fpga/dfl-afu-main.c ++++ b/drivers/fpga/dfl-afu-main.c +@@ -730,9 +730,7 @@ afu_ioctl_dma_map(struct dfl_feature_platform_data *pdata, void __user *arg) + } + + dev_dbg(&pdata->dev->dev, "dma map: ua=%llx, len=%llx, iova=%llx\n", +- (unsigned long long)map.user_addr, +- (unsigned long long)map.length, +- (unsigned long long)map.iova); ++ map.user_addr, map.length, map.iova); + + return 0; + } +diff --git a/drivers/fpga/dfl-fme-mgr.c b/drivers/fpga/dfl-fme-mgr.c +index ab228d8837a0..da3cb9c35de5 100644 +--- a/drivers/fpga/dfl-fme-mgr.c ++++ b/drivers/fpga/dfl-fme-mgr.c +@@ -150,7 +150,7 @@ static int fme_mgr_write_init(struct fpga_manager *mgr, + priv->pr_error = fme_mgr_pr_error_handle(fme_pr); + if (priv->pr_error) + dev_dbg(dev, "previous PR error detected %llx\n", +- (unsigned long long)priv->pr_error); ++ priv->pr_error); + + dev_dbg(dev, "set PR port ID\n"); + +@@ -242,8 +242,7 @@ static int fme_mgr_write_complete(struct fpga_manager *mgr, + dev_dbg(dev, "PR operation complete, checking status\n"); + priv->pr_error = fme_mgr_pr_error_handle(fme_pr); + if (priv->pr_error) { +- dev_dbg(dev, "PR error detected %llx\n", +- (unsigned long long)priv->pr_error); ++ dev_dbg(dev, "PR error detected %llx\n", priv->pr_error); + return -EIO; + } + diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0004-fpga-dfl-afu-remove-unused-member-pdata-from-struct-.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0004-fpga-dfl-afu-remove-unused-member-pdata-from-struct-.patch new file mode 100644 index 0000000..4b49636 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0004-fpga-dfl-afu-remove-unused-member-pdata-from-struct-.patch @@ -0,0 +1,51 @@ +From 0654554c9c703fc14abec4da66707f4d7597c9ba Mon Sep 17 00:00:00 2001 +From: Peter Colberg +Date: Fri, 16 Jun 2023 22:19:57 -0400 +Subject: [PATCH] fpga: dfl: afu: remove unused member pdata from struct + dfl_afu + +The member pdata was added to struct dfl_afu in commit 857a26222ff7 +("fpga: dfl: afu: add afu sub feature support") and is set in function +afu_dev_init() but otherwise never used. + +Signed-off-by: Peter Colberg +Reviewed-by: Matthew Gerlach +--- + drivers/fpga/dfl-afu-main.c | 2 -- + drivers/fpga/dfl-afu.h | 3 --- + 2 files changed, 5 deletions(-) + +diff --git a/drivers/fpga/dfl-afu-main.c b/drivers/fpga/dfl-afu-main.c +index 2f10ecec3f64..cafb4dc0186d 100644 +--- a/drivers/fpga/dfl-afu-main.c ++++ b/drivers/fpga/dfl-afu-main.c +@@ -856,8 +856,6 @@ static int afu_dev_init(struct platform_device *pdev) + if (!afu) + return -ENOMEM; + +- afu->pdata = pdata; +- + mutex_lock(&pdata->lock); + dfl_fpga_pdata_set_private(pdata, afu); + afu_mmio_region_init(pdata); +diff --git a/drivers/fpga/dfl-afu.h b/drivers/fpga/dfl-afu.h +index 674e9772f0ea..7bef3e300aa2 100644 +--- a/drivers/fpga/dfl-afu.h ++++ b/drivers/fpga/dfl-afu.h +@@ -67,7 +67,6 @@ struct dfl_afu_dma_region { + * @regions: the mmio region linked list of this afu feature device. + * @dma_regions: root of dma regions rb tree. + * @num_umsgs: num of umsgs. +- * @pdata: afu platform device's pdata. + */ + struct dfl_afu { + u64 region_cur_offset; +@@ -75,8 +74,6 @@ struct dfl_afu { + u8 num_umsgs; + struct list_head regions; + struct rb_root dma_regions; +- +- struct dfl_feature_platform_data *pdata; + }; + + /* hold pdata->lock when call __afu_port_enable/disable */ diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0005-mfd-intel-m10-bmc-Change-staging-size-to-a-variable.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0005-mfd-intel-m10-bmc-Change-staging-size-to-a-variable.patch new file mode 100644 index 0000000..cf8df82 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0005-mfd-intel-m10-bmc-Change-staging-size-to-a-variable.patch @@ -0,0 +1,83 @@ +From dc09ca2cfd94135cbcae960d434ea0232e51380a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= +Date: Thu, 5 Jan 2023 12:10:50 +0200 +Subject: [PATCH] mfd: intel-m10-bmc: Change staging size to a variable +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The size of the staging area in FLASH for FPGA updates is dependent on the +size of the FPGA. Currently, the staging size is defined as a constant. +Larger FPGAs are coming soon and it will soon be necessary to support +different sizes for the staging area. Add a new staging_size member to the +csr_map structure to support a variable staging size. + +The secure update driver does a sanity-check of the image size in +comparison to the size of the staging area in FLASH. Change the +staging size reference to a variable instead of a constant in order +to more readily support future, larger FPGAs. + +Co-developed-by: Russ Weight +Signed-off-by: Russ Weight +Signed-off-by: Ilpo Järvinen +--- + drivers/fpga/intel-m10-bmc-sec-update.c | 3 ++- + drivers/mfd/intel-m10-bmc-pmci.c | 1 + + drivers/mfd/intel-m10-bmc-spi.c | 1 + + include/linux/mfd/intel-m10-bmc.h | 1 + + 4 files changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/fpga/intel-m10-bmc-sec-update.c b/drivers/fpga/intel-m10-bmc-sec-update.c +index 31af2e08c825..0f0d1d5f9e31 100644 +--- a/drivers/fpga/intel-m10-bmc-sec-update.c ++++ b/drivers/fpga/intel-m10-bmc-sec-update.c +@@ -529,11 +529,12 @@ static enum fw_upload_err m10bmc_sec_prepare(struct fw_upload *fwl, + const u8 *data, u32 size) + { + struct m10bmc_sec *sec = fwl->dd_handle; ++ const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; + u32 ret; + + sec->cancel_request = false; + +- if (!size || size > M10BMC_STAGING_SIZE) ++ if (!size || size > csr_map->staging_size) + return FW_UPLOAD_ERR_INVALID_SIZE; + + if (sec->m10bmc->flash_bulk_ops) +diff --git a/drivers/mfd/intel-m10-bmc-pmci.c b/drivers/mfd/intel-m10-bmc-pmci.c +index 0392ef8b57d8..698c5933938b 100644 +--- a/drivers/mfd/intel-m10-bmc-pmci.c ++++ b/drivers/mfd/intel-m10-bmc-pmci.c +@@ -370,6 +370,7 @@ static const struct m10bmc_csr_map m10bmc_n6000_csr_map = { + .pr_reh_addr = M10BMC_N6000_PR_REH_ADDR, + .pr_magic = M10BMC_N6000_PR_PROG_MAGIC, + .rsu_update_counter = M10BMC_N6000_STAGING_FLASH_COUNT, ++ .staging_size = M10BMC_STAGING_SIZE, + }; + + static const struct intel_m10bmc_platform_info m10bmc_pmci_n6000 = { +diff --git a/drivers/mfd/intel-m10-bmc-spi.c b/drivers/mfd/intel-m10-bmc-spi.c +index cbeb7de9e041..d64d28199df6 100644 +--- a/drivers/mfd/intel-m10-bmc-spi.c ++++ b/drivers/mfd/intel-m10-bmc-spi.c +@@ -109,6 +109,7 @@ static const struct m10bmc_csr_map m10bmc_n3000_csr_map = { + .pr_reh_addr = M10BMC_N3000_PR_REH_ADDR, + .pr_magic = M10BMC_N3000_PR_PROG_MAGIC, + .rsu_update_counter = M10BMC_N3000_STAGING_FLASH_COUNT, ++ .staging_size = M10BMC_STAGING_SIZE, + }; + + static struct mfd_cell m10bmc_d5005_subdevs[] = { +diff --git a/include/linux/mfd/intel-m10-bmc.h b/include/linux/mfd/intel-m10-bmc.h +index ee66c9751003..988f1cd90032 100644 +--- a/include/linux/mfd/intel-m10-bmc.h ++++ b/include/linux/mfd/intel-m10-bmc.h +@@ -205,6 +205,7 @@ struct m10bmc_csr_map { + unsigned int pr_reh_addr; + unsigned int pr_magic; + unsigned int rsu_update_counter; ++ unsigned int staging_size; + }; + + /** diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0006-fpga-dfl-Fix-handling-of-CSR-relative-addresses.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0006-fpga-dfl-Fix-handling-of-CSR-relative-addresses.patch new file mode 100644 index 0000000..a4f2727 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0006-fpga-dfl-Fix-handling-of-CSR-relative-addresses.patch @@ -0,0 +1,73 @@ +From d74bd99804353826829b89feff5ece6060778bec Mon Sep 17 00:00:00 2001 +From: Basheer Ahmed Muddebihal +Date: Fri, 16 Jun 2023 13:35:30 -0700 +Subject: [PATCH] fpga: dfl: Fix handling of CSR-relative addresses + +To accommodate both negative and positive offsets in CSR-relative +addresses, the addr_off value has been typecasted to int64_t for +signed representation, ensuring proper support for negative offsets. + +The CSR ADDR register value is stored in bits 63:1 of CSR_ADDR [63:1], +along with CSR_ADDR_REL_N [0]. When calculating the address/offset +value, the CSR_ADDR_REL_N bit should be masked to ensure 16-bit address +alignment. + +Fixes the address value shift by restoring the shift from FIELD_GET as +addr_off << 1, aligning with the intent specified in the DFHv1 +specification. This adjustment ensures that the calculated csr_address +matches the desired behavior of *csr_addr_register & ~1, similar to how +PCIe BARs handle address alignment. + +Signed-off-by: Basheer Ahmed Muddebihal +--- + Documentation/fpga/dfl.rst | 16 +++++++++++++--- + drivers/fpga/dfl.c | 7 ++++--- + 2 files changed, 17 insertions(+), 6 deletions(-) + +diff --git a/Documentation/fpga/dfl.rst b/Documentation/fpga/dfl.rst +index 80255e2dc3e6..fb1c72006b1d 100644 +--- a/Documentation/fpga/dfl.rst ++++ b/Documentation/fpga/dfl.rst +@@ -170,9 +170,19 @@ The format of Version 1 of the Device Feature Header (DFH) is shown below:: + + - Offset 0x18 + +- * Reg Address/Offset - If Rel bit is set, then the value is the high 63 bits +- of a 16-bit aligned absolute address of the feature's registers. Otherwise +- the value is the offset from the start of the DFH of the feature's registers. ++ * CSR_ADDR[63:1]: the value is the high 63 bits of a 16-bit aligned ++ address/offset of the feature's registers. ++ ++ * CSR_ADDR_REL_N [0]: This bit controls whether the address is an absolute ++ address or a relative offset. ++ When CSR_ADDR_REL_N is set to 1, it indicates that the address is an unsigned ++ absolute address. In this case, the 64-bit value of the register is read, and ++ bit 0 is masked (set to 0). ++ When CSR_ADDR_REL_N is set to 0, it signifies that the offset is a signed relative ++ offset from the DFH start. Again, the 64-bit value of the register is read, ++ and bit 0 is masked. ++ In both cases, the purpose of masking bit 0 is to ensure that the resulting address ++ or offset is aligned. + + - Offset 0x20 + +diff --git a/drivers/fpga/dfl.c b/drivers/fpga/dfl.c +index db8141b68f79..75580ba0419f 100644 +--- a/drivers/fpga/dfl.c ++++ b/drivers/fpga/dfl.c +@@ -1178,11 +1178,12 @@ create_feature_instance(struct build_feature_devs_info *binfo, + finfo->dfh_version = dfh_ver; + if (dfh_ver == 1) { + v = readq(binfo->ioaddr + ofst + DFHv1_CSR_ADDR); +- addr_off = FIELD_GET(DFHv1_CSR_ADDR_MASK, v); ++ addr_off = FIELD_GET(DFHv1_CSR_ADDR_MASK, v) << 1; ++ + if (FIELD_GET(DFHv1_CSR_ADDR_REL, v)) +- start = addr_off << 1; ++ start = addr_off; + else +- start = binfo->start + ofst + addr_off; ++ start = binfo->start + ofst + (int64_t)addr_off; + + v = readq(binfo->ioaddr + ofst + DFHv1_CSR_SIZE_GRP); + end = start + FIELD_GET(DFHv1_CSR_SIZE_GRP_SIZE, v) - 1; diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0007-fpga-m10bmc-sec-add-sysfs-to-load-bmc-images.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0007-fpga-m10bmc-sec-add-sysfs-to-load-bmc-images.patch new file mode 100644 index 0000000..7ac797b --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0007-fpga-m10bmc-sec-add-sysfs-to-load-bmc-images.patch @@ -0,0 +1,343 @@ +From fb82e0ba04db797dab306c1be4e17bd74362c73a Mon Sep 17 00:00:00 2001 +From: Russ Weight +Date: Thu, 30 Sep 2021 11:32:57 -0700 +Subject: [PATCH] fpga: m10bmc-sec: add sysfs to load bmc images +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add the available_images and image_load syfs files. The available_images +file returns a space separated list of key words that may be written +into the image_load file. These keywords decribe an FPGA, BMC, or +firmware image in FLASH or EEPROM storage that may be loaded. + +The image_load syfs file may be written with a key word to trigger a +reload of an FPGA, BMC, or firmware image from FLASH or EEPROM. + +Co-developed-by: Russ Weight +Signed-off-by: Russ Weight +Co-developed-by: Tianfei zhang +Signed-off-by: Tianfei zhang +Signed-off-by: Ilpo Järvinen +--- + .../sysfs-driver-intel-m10-bmc-sec-update | 21 ++ + drivers/fpga/intel-m10-bmc-sec-update.c | 218 +++++++++++++++++- + include/linux/mfd/intel-m10-bmc.h | 10 + + 3 files changed, 248 insertions(+), 1 deletion(-) + +diff --git a/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update b/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update +index 9051695d2211..cd22dab15cff 100644 +--- a/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update ++++ b/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update +@@ -59,3 +59,24 @@ Contact: Peter Colberg + Description: Read only. Returns number of times the secure update + staging area has been flashed. + Format: "%u". ++ ++What: /sys/bus/platform/drivers/intel-m10bmc-sec-update/.../control/available_images ++Date: Nov 2021 ++KernelVersion: 5.16 ++Contact: Russ Weight ++Description: Read-only. This file returns a space separated list of ++ key words that may be written into the image_load file ++ described below. These keywords decribe an FPGA, BMC, ++ or firmware image in FLASH or EEPROM storage that may ++ be loaded. ++ ++What: /sys/bus/platform/drivers/intel-m10bmc-sec-update/.../control/image_load ++Date: Nov 2021 ++KernelVersion: 5.16 ++Contact: Russ Weight ++Description: Write-only. A key word may be written to this file to ++ trigger a reload of an FPGA, BMC, or firmware image from ++ FLASH or EEPROM. Refer to the available_images file for a ++ list of supported key words for the underlying device. ++ Writing an unsupported string to this file will result in ++ EINVAL being returned. +diff --git a/drivers/fpga/intel-m10-bmc-sec-update.c b/drivers/fpga/intel-m10-bmc-sec-update.c +index 0f0d1d5f9e31..f30dd498fc1e 100644 +--- a/drivers/fpga/intel-m10-bmc-sec-update.c ++++ b/drivers/fpga/intel-m10-bmc-sec-update.c +@@ -16,8 +16,14 @@ + + struct m10bmc_sec; + ++struct image_load { ++ const char *name; ++ int (*load_image)(struct m10bmc_sec *sec); ++}; ++ + struct m10bmc_sec_ops { + int (*rsu_status)(struct m10bmc_sec *sec); ++ struct image_load *image_load; /* terminated with { } member */ + }; + + struct m10bmc_sec { +@@ -30,6 +36,162 @@ struct m10bmc_sec { + const struct m10bmc_sec_ops *ops; + }; + ++static int m10bmc_sec_bmc_image_load(struct m10bmc_sec *sec, unsigned int val) ++{ ++ const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; ++ u32 doorbell; ++ int ret; ++ ++ if (val > 1) { ++ dev_err(sec->dev, "secure update image load invalid reload val = %u\n", val); ++ return -EINVAL; ++ } ++ ++ ret = m10bmc_sys_read(sec->m10bmc, csr_map->doorbell, &doorbell); ++ if (ret) ++ return ret; ++ ++ if (doorbell & DRBL_REBOOT_DISABLED) ++ return -EBUSY; ++ ++ return m10bmc_sys_update_bits(sec->m10bmc, csr_map->doorbell, ++ DRBL_CONFIG_SEL | DRBL_REBOOT_REQ, ++ FIELD_PREP(DRBL_CONFIG_SEL, val) | ++ DRBL_REBOOT_REQ); ++} ++ ++static int m10bmc_n6000_sec_bmc_image_load(struct m10bmc_sec *sec, unsigned int val) ++{ ++ const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; ++ u32 doorbell; ++ int ret; ++ ++ if (val > 1) { ++ dev_err(sec->dev, "secure update image load invalid reload val = %u\n", val); ++ return -EINVAL; ++ } ++ ++ ret = m10bmc_sys_read(sec->m10bmc, csr_map->doorbell, &doorbell); ++ if (ret) ++ return ret; ++ ++ if (doorbell & PMCI_DRBL_REBOOT_DISABLED) ++ return -EBUSY; ++ ++ return regmap_update_bits(sec->m10bmc->regmap, ++ csr_map->base + M10BMC_PMCI_MAX10_RECONF, ++ PMCI_MAX10_REBOOT_REQ | PMCI_MAX10_REBOOT_PAGE, ++ FIELD_PREP(PMCI_MAX10_REBOOT_PAGE, val) | ++ PMCI_MAX10_REBOOT_REQ); ++} ++ ++static int pmci_sec_fpga_image_load(struct m10bmc_sec *sec, unsigned int val) ++{ ++ const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; ++ int ret; ++ ++ if (val > 2) { ++ dev_err(sec->dev, "secure update image load invalid reload val = %u\n", val); ++ return -EINVAL; ++ } ++ ++ ret = regmap_update_bits(sec->m10bmc->regmap, ++ csr_map->base + M10BMC_PMCI_FPGA_RECONF, ++ PMCI_FPGA_RP_LOAD, 0); ++ if (ret) ++ return ret; ++ ++ return regmap_update_bits(sec->m10bmc->regmap, ++ csr_map->base + M10BMC_PMCI_FPGA_RECONF, ++ PMCI_FPGA_RECONF_PAGE | PMCI_FPGA_RP_LOAD, ++ FIELD_PREP(PMCI_FPGA_RECONF_PAGE, val) | ++ PMCI_FPGA_RP_LOAD); ++} ++ ++static int m10bmc_sec_bmc_image_load_0(struct m10bmc_sec *sec) ++{ ++ return m10bmc_sec_bmc_image_load(sec, 0); ++} ++ ++static int m10bmc_sec_bmc_image_load_1(struct m10bmc_sec *sec) ++{ ++ return m10bmc_sec_bmc_image_load(sec, 1); ++} ++ ++static int pmci_sec_bmc_image_load_0(struct m10bmc_sec *sec) ++{ ++ return m10bmc_n6000_sec_bmc_image_load(sec, 0); ++} ++ ++static int pmci_sec_bmc_image_load_1(struct m10bmc_sec *sec) ++{ ++ return m10bmc_n6000_sec_bmc_image_load(sec, 1); ++} ++ ++static int pmci_sec_fpga_image_load_0(struct m10bmc_sec *sec) ++{ ++ return pmci_sec_fpga_image_load(sec, 0); ++} ++ ++static int pmci_sec_fpga_image_load_1(struct m10bmc_sec *sec) ++{ ++ return pmci_sec_fpga_image_load(sec, 1); ++} ++ ++static int pmci_sec_fpga_image_load_2(struct m10bmc_sec *sec) ++{ ++ return pmci_sec_fpga_image_load(sec, 2); ++} ++ ++ ++static struct image_load n3000_image_load_hndlrs[] = { ++ { ++ .name = "bmc_factory", ++ .load_image = m10bmc_sec_bmc_image_load_1, ++ }, ++ { ++ .name = "bmc_user", ++ .load_image = m10bmc_sec_bmc_image_load_0, ++ }, ++ {} ++}; ++ ++static struct image_load d5005_image_load_hndlrs[] = { ++ { ++ .name = "bmc_factory", ++ .load_image = m10bmc_sec_bmc_image_load_0, ++ }, ++ { ++ .name = "bmc_user", ++ .load_image = m10bmc_sec_bmc_image_load_1, ++ }, ++ {} ++}; ++ ++static struct image_load n6000_image_load_hndlrs[] = { ++ { ++ .name = "bmc_factory", ++ .load_image = pmci_sec_bmc_image_load_0, ++ }, ++ { ++ .name = "bmc_user", ++ .load_image = pmci_sec_bmc_image_load_1, ++ }, ++ { ++ .name = "fpga_factory", ++ .load_image = pmci_sec_fpga_image_load_0, ++ }, ++ { ++ .name = "fpga_user1", ++ .load_image = pmci_sec_fpga_image_load_1, ++ }, ++ { ++ .name = "fpga_user2", ++ .load_image = pmci_sec_fpga_image_load_2, ++ }, ++ {} ++}; ++ + static DEFINE_XARRAY_ALLOC(fw_upload_xa); + + /* Root Entry Hash (REH) support */ +@@ -254,8 +416,55 @@ static struct attribute_group m10bmc_security_attr_group = { + .attrs = m10bmc_security_attrs, + }; + ++static ssize_t available_images_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct m10bmc_sec *sec = dev_get_drvdata(dev); ++ const struct image_load *hndlr; ++ ssize_t count = 0; ++ ++ for (hndlr = sec->ops->image_load; hndlr->name; hndlr++) ++ count += scnprintf(buf + count, PAGE_SIZE - count, "%s ", hndlr->name); ++ ++ buf[count - 1] = '\n'; ++ ++ return count; ++} ++static DEVICE_ATTR_RO(available_images); ++ ++static ssize_t image_load_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct m10bmc_sec *sec = dev_get_drvdata(dev); ++ const struct image_load *hndlr; ++ int ret = -EINVAL; ++ ++ for (hndlr = sec->ops->image_load; hndlr->name; hndlr++) { ++ if (sysfs_streq(buf, hndlr->name)) { ++ ret = hndlr->load_image(sec); ++ break; ++ } ++ } ++ ++ return ret ? : count; ++} ++static DEVICE_ATTR_WO(image_load); ++ ++static struct attribute *m10bmc_control_attrs[] = { ++ &dev_attr_available_images.attr, ++ &dev_attr_image_load.attr, ++ NULL, ++}; ++ ++static struct attribute_group m10bmc_control_attr_group = { ++ .name = "control", ++ .attrs = m10bmc_control_attrs, ++}; ++ + static const struct attribute_group *m10bmc_sec_attr_groups[] = { + &m10bmc_security_attr_group, ++ &m10bmc_control_attr_group, + NULL, + }; + +@@ -676,10 +885,17 @@ static const struct fw_upload_ops m10bmc_ops = { + + static const struct m10bmc_sec_ops m10sec_n3000_ops = { + .rsu_status = m10bmc_sec_n3000_rsu_status, ++ .image_load = n3000_image_load_hndlrs, ++}; ++ ++static const struct m10bmc_sec_ops m10sec_d5005_ops = { ++ .rsu_status = m10bmc_sec_n3000_rsu_status, ++ .image_load = d5005_image_load_hndlrs, + }; + + static const struct m10bmc_sec_ops m10sec_n6000_ops = { + .rsu_status = m10bmc_sec_n6000_rsu_status, ++ .image_load = n6000_image_load_hndlrs, + }; + + #define SEC_UPDATE_LEN_MAX 32 +@@ -749,7 +965,7 @@ static const struct platform_device_id intel_m10bmc_sec_ids[] = { + }, + { + .name = "d5005bmc-sec-update", +- .driver_data = (kernel_ulong_t)&m10sec_n3000_ops, ++ .driver_data = (kernel_ulong_t)&m10sec_d5005_ops, + }, + { + .name = "n6000bmc-sec-update", +diff --git a/include/linux/mfd/intel-m10-bmc.h b/include/linux/mfd/intel-m10-bmc.h +index 988f1cd90032..16cbdcf05e0c 100644 +--- a/include/linux/mfd/intel-m10-bmc.h ++++ b/include/linux/mfd/intel-m10-bmc.h +@@ -131,7 +131,17 @@ + #define M10BMC_N6000_SYS_BASE 0x0 + #define M10BMC_N6000_SYS_END 0xfff + ++#define M10BMC_PMCI_FPGA_RECONF 0x0b8 ++#define PMCI_FPGA_RECONF_PAGE GENMASK(22, 20) ++#define PMCI_FPGA_RP_LOAD BIT(23) ++ ++#define M10BMC_PMCI_MAX10_RECONF 0x0fc ++#define PMCI_MAX10_REBOOT_REQ BIT(0) ++#define PMCI_MAX10_REBOOT_PAGE BIT(1) ++ + #define M10BMC_N6000_DOORBELL 0x1c0 ++#define PMCI_DRBL_REBOOT_DISABLED BIT(1) ++ + #define M10BMC_N6000_AUTH_RESULT 0x1c4 + #define AUTH_RESULT_RSU_STATUS GENMASK(23, 16) + diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0008-fpga-m10bmc-sec-m10bmc_sec_retimer_load-callback.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0008-fpga-m10bmc-sec-m10bmc_sec_retimer_load-callback.patch new file mode 100644 index 0000000..9807761 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0008-fpga-m10bmc-sec-m10bmc_sec_retimer_load-callback.patch @@ -0,0 +1,334 @@ +From b2930476537f6abb8f45657b0d8f312a2759c8d2 Mon Sep 17 00:00:00 2001 +From: Russ Weight +Date: Thu, 4 Mar 2021 18:08:17 -0800 +Subject: [PATCH] fpga: m10bmc-sec: m10bmc_sec_retimer_load callback +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Create m10bmc_sec_retimer_load() callback function +to provide a trigger for new retimer firmware. + +Signed-off-by: Russ Weight +Signed-off-by: Xu Yilun +Signed-off-by: Ilpo Järvinen +--- + drivers/fpga/intel-m10-bmc-sec-update.c | 211 ++++++++++++++++++++---- + drivers/mfd/intel-m10-bmc-core.c | 3 +- + include/linux/mfd/intel-m10-bmc.h | 32 ++++ + 3 files changed, 214 insertions(+), 32 deletions(-) + +diff --git a/drivers/fpga/intel-m10-bmc-sec-update.c b/drivers/fpga/intel-m10-bmc-sec-update.c +index f30dd498fc1e..ecd7959ce8aa 100644 +--- a/drivers/fpga/intel-m10-bmc-sec-update.c ++++ b/drivers/fpga/intel-m10-bmc-sec-update.c +@@ -36,6 +36,37 @@ struct m10bmc_sec { + const struct m10bmc_sec_ops *ops; + }; + ++static void log_error_regs(struct m10bmc_sec *sec, u32 doorbell) ++{ ++ const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; ++ u32 auth_result; ++ ++ dev_err(sec->dev, "Doorbell: 0x%08x\n", doorbell); ++ ++ if (!m10bmc_sys_read(sec->m10bmc, csr_map->auth_result, &auth_result)) ++ dev_err(sec->dev, "RSU auth result: 0x%08x\n", auth_result); ++} ++ ++static int m10bmc_sec_progress_status(struct m10bmc_sec *sec, u32 *doorbell_reg, ++ u32 *progress, u32 *status) ++{ ++ const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; ++ int ret; ++ ++ ret = m10bmc_sys_read(sec->m10bmc, csr_map->doorbell, doorbell_reg); ++ if (ret) ++ return ret; ++ ++ ret = sec->ops->rsu_status(sec); ++ if (ret < 0) ++ return ret; ++ ++ *status = ret; ++ *progress = rsu_prog(*doorbell_reg); ++ ++ return 0; ++} ++ + static int m10bmc_sec_bmc_image_load(struct m10bmc_sec *sec, unsigned int val) + { + const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; +@@ -143,6 +174,151 @@ static int pmci_sec_fpga_image_load_2(struct m10bmc_sec *sec) + return pmci_sec_fpga_image_load(sec, 2); + } + ++static int retimer_check_idle(struct m10bmc_sec *sec) ++{ ++ const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; ++ u32 doorbell; ++ int ret; ++ ++ ret = m10bmc_sys_read(sec->m10bmc, csr_map->doorbell, &doorbell); ++ if (ret) ++ return -EIO; ++ ++ if (rsu_prog(doorbell) != RSU_PROG_IDLE && ++ rsu_prog(doorbell) != RSU_PROG_RSU_DONE && ++ rsu_prog(doorbell) != RSU_PROG_PKVL_PROM_DONE) { ++ log_error_regs(sec, doorbell); ++ return -EBUSY; ++ } ++ ++ return 0; ++} ++ ++static int trigger_retimer_eeprom_load(struct m10bmc_sec *sec) ++{ ++ const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; ++ struct intel_m10bmc *m10bmc = sec->m10bmc; ++ unsigned int val; ++ int ret; ++ ++ ret = m10bmc_sys_update_bits(m10bmc, csr_map->doorbell, ++ DRBL_PKVL_EEPROM_LOAD_SEC, ++ DRBL_PKVL_EEPROM_LOAD_SEC); ++ if (ret) ++ return ret; ++ ++ /* ++ * If the current NIOS FW supports this retimer update feature, then ++ * it will clear the same PKVL_EEPROM_LOAD bit in 2 seconds. Otherwise ++ * the driver needs to clear the PKVL_EEPROM_LOAD bit manually and ++ * return an error code. ++ */ ++ ret = regmap_read_poll_timeout(m10bmc->regmap, ++ csr_map->base + csr_map->doorbell, ++ val, ++ (!(val & DRBL_PKVL_EEPROM_LOAD_SEC)), ++ M10BMC_PKVL_LOAD_INTERVAL_US, ++ M10BMC_PKVL_LOAD_TIMEOUT_US); ++ if (ret == -ETIMEDOUT) { ++ dev_err(sec->dev, "PKVL_EEPROM_LOAD clear timedout\n"); ++ m10bmc_sys_update_bits(m10bmc, csr_map->doorbell, ++ DRBL_PKVL_EEPROM_LOAD_SEC, 0); ++ ret = -ENODEV; ++ } else if (ret) { ++ dev_err(sec->dev, "Poll EEPROM_LOAD error %d\n", ret); ++ } ++ ++ return ret; ++} ++ ++static int poll_retimer_eeprom_load_done(struct m10bmc_sec *sec) ++{ ++ u32 doorbell_reg, progress, status; ++ int ret, err; ++ ++ /* ++ * RSU_STAT_PKVL_REJECT indicates that the current image is ++ * already programmed. RSU_PROG_PKVL_PROM_DONE that the firmware ++ * update process has finished, but does not necessarily indicate ++ * a successful update. ++ */ ++ ret = read_poll_timeout(m10bmc_sec_progress_status, err, ++ err < 0 || ++ progress == RSU_PROG_PKVL_PROM_DONE || ++ status == RSU_STAT_PKVL_REJECT, ++ M10BMC_PKVL_PRELOAD_INTERVAL_US, ++ M10BMC_PKVL_PRELOAD_TIMEOUT_US, ++ false, ++ sec, &doorbell_reg, &progress, &status); ++ if (ret == -ETIMEDOUT) { ++ dev_err(sec->dev, "Doorbell check timedout: 0x%08x\n", doorbell_reg); ++ return ret; ++ } else if (err) { ++ dev_err(sec->dev, "Poll Doorbell error\n"); ++ return ret; ++ } ++ ++ if (status == RSU_STAT_PKVL_REJECT) { ++ dev_err(sec->dev, "duplicate image rejected\n"); ++ return -ECANCELED; ++ } ++ ++ return 0; ++} ++ ++static int poll_retimer_preload_done(struct m10bmc_sec *sec) ++{ ++ const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; ++ struct intel_m10bmc *m10bmc = sec->m10bmc; ++ unsigned int val; ++ int ret; ++ ++ /* ++ * Wait for the updated firmware to be loaded by the PKVL device ++ * and confirm that the updated firmware is operational ++ */ ++ ret = regmap_read_poll_timeout(m10bmc->regmap, ++ csr_map->base + M10BMC_PKVL_POLL_CTRL, val, ++ ((val & M10BMC_PKVL_PRELOAD) == M10BMC_PKVL_PRELOAD), ++ M10BMC_PKVL_PRELOAD_INTERVAL_US, ++ M10BMC_PKVL_PRELOAD_TIMEOUT_US); ++ if (ret) { ++ dev_err(sec->dev, "Poll M10BMC_PKVL_PRELOAD error %d\n", ret); ++ return ret; ++ } ++ ++ if ((val & M10BMC_PKVL_UPG_STATUS_MASK) != M10BMC_PKVL_UPG_STATUS_GOOD) { ++ dev_err(sec->dev, "Error detected during M10BMC PKVL upgrade\n"); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static int m10bmc_sec_retimer_eeprom_load(struct m10bmc_sec *sec) ++{ ++ int ret; ++ ++ m10bmc_fw_state_set(sec->m10bmc, M10BMC_FW_RETIMER_EEPROM_LOAD); ++ ++ ret = retimer_check_idle(sec); ++ if (ret) ++ goto fw_state_exit; ++ ++ ret = trigger_retimer_eeprom_load(sec); ++ if (ret) ++ goto fw_state_exit; ++ ++ ret = poll_retimer_eeprom_load_done(sec); ++ if (ret) ++ goto fw_state_exit; ++ ++ ret = poll_retimer_preload_done(sec); ++ ++fw_state_exit: ++ m10bmc_fw_state_set(sec->m10bmc, M10BMC_FW_STATE_NORMAL); ++ return ret; ++} + + static struct image_load n3000_image_load_hndlrs[] = { + { +@@ -153,6 +329,10 @@ static struct image_load n3000_image_load_hndlrs[] = { + .name = "bmc_user", + .load_image = m10bmc_sec_bmc_image_load_0, + }, ++ { ++ .name = "retimer_fw", ++ .load_image = m10bmc_sec_retimer_eeprom_load, ++ }, + {} + }; + +@@ -468,17 +648,6 @@ static const struct attribute_group *m10bmc_sec_attr_groups[] = { + NULL, + }; + +-static void log_error_regs(struct m10bmc_sec *sec, u32 doorbell) +-{ +- const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; +- u32 auth_result; +- +- dev_err(sec->dev, "Doorbell: 0x%08x\n", doorbell); +- +- if (!m10bmc_sys_read(sec->m10bmc, csr_map->auth_result, &auth_result)) +- dev_err(sec->dev, "RSU auth result: 0x%08x\n", auth_result); +-} +- + static int m10bmc_sec_n3000_rsu_status(struct m10bmc_sec *sec) + { + const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; +@@ -527,26 +696,6 @@ static bool rsu_progress_busy(u32 progress) + progress == RSU_PROG_PROGRAM_KEY_HASH); + } + +-static int m10bmc_sec_progress_status(struct m10bmc_sec *sec, u32 *doorbell_reg, +- u32 *progress, u32 *status) +-{ +- const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; +- int ret; +- +- ret = m10bmc_sys_read(sec->m10bmc, csr_map->doorbell, doorbell_reg); +- if (ret) +- return ret; +- +- ret = sec->ops->rsu_status(sec); +- if (ret < 0) +- return ret; +- +- *status = ret; +- *progress = rsu_prog(*doorbell_reg); +- +- return 0; +-} +- + static enum fw_upload_err rsu_check_idle(struct m10bmc_sec *sec) + { + const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; +diff --git a/drivers/mfd/intel-m10-bmc-core.c b/drivers/mfd/intel-m10-bmc-core.c +index 8ad5b3821584..742819ded93b 100644 +--- a/drivers/mfd/intel-m10-bmc-core.c ++++ b/drivers/mfd/intel-m10-bmc-core.c +@@ -49,7 +49,8 @@ static bool m10bmc_reg_always_available(struct intel_m10bmc *m10bmc, unsigned in + static bool m10bmc_handshake_reg_unavailable(struct intel_m10bmc *m10bmc) + { + return m10bmc->bmcfw_state == M10BMC_FW_STATE_SEC_UPDATE_PREPARE || +- m10bmc->bmcfw_state == M10BMC_FW_STATE_SEC_UPDATE_WRITE; ++ m10bmc->bmcfw_state == M10BMC_FW_STATE_SEC_UPDATE_WRITE || ++ m10bmc->bmcfw_state == M10BMC_FW_RETIMER_EEPROM_LOAD; + } + + /* +diff --git a/include/linux/mfd/intel-m10-bmc.h b/include/linux/mfd/intel-m10-bmc.h +index 16cbdcf05e0c..e50c9b10f696 100644 +--- a/include/linux/mfd/intel-m10-bmc.h ++++ b/include/linux/mfd/intel-m10-bmc.h +@@ -40,6 +40,37 @@ + #define M10BMC_N3000_VER_PCB_INFO_MSK GENMASK(31, 24) + #define M10BMC_N3000_VER_LEGACY_INVALID 0xffffffff + ++/* Retimer related registers, in system register region */ ++#define M10BMC_PKVL_POLL_CTRL 0x80 ++#define M10BMC_PKVL_A_PRELOAD BIT(16) ++#define M10BMC_PKVL_A_PRELOAD_TO BIT(17) ++#define M10BMC_PKVL_A_DATA_TOO_BIG BIT(18) ++#define M10BMC_PKVL_A_HDR_CKSUM BIT(20) ++#define M10BMC_PKVL_B_PRELOAD BIT(24) ++#define M10BMC_PKVL_B_PRELOAD_TO BIT(25) ++#define M10BMC_PKVL_B_DATA_TOO_BIG BIT(26) ++#define M10BMC_PKVL_B_HDR_CKSUM BIT(28) ++ ++#define M10BMC_PKVL_PRELOAD (M10BMC_PKVL_A_PRELOAD | M10BMC_PKVL_B_PRELOAD) ++#define M10BMC_PKVL_PRELOAD_TIMEOUT (M10BMC_PKVL_A_PRELOAD_TO | \ ++ M10BMC_PKVL_B_PRELOAD_TO) ++#define M10BMC_PKVL_DATA_TOO_BIG (M10BMC_PKVL_A_DATA_TOO_BIG | \ ++ M10BMC_PKVL_B_DATA_TOO_BIG) ++#define M10BMC_PKVL_HDR_CHECKSUM (M10BMC_PKVL_A_HDR_CKSUM | \ ++ M10BMC_PKVL_B_HDR_CKSUM) ++ ++#define M10BMC_PKVL_UPG_STATUS_MASK (M10BMC_PKVL_PRELOAD | M10BMC_PKVL_PRELOAD_TIMEOUT |\ ++ M10BMC_PKVL_DATA_TOO_BIG | M10BMC_PKVL_HDR_CHECKSUM) ++#define M10BMC_PKVL_UPG_STATUS_GOOD (M10BMC_PKVL_PRELOAD | M10BMC_PKVL_HDR_CHECKSUM) ++ ++/* interval 100ms and timeout 2s */ ++#define M10BMC_PKVL_LOAD_INTERVAL_US (100 * 1000) ++#define M10BMC_PKVL_LOAD_TIMEOUT_US (2 * 1000 * 1000) ++ ++/* interval 100ms and timeout 30s */ ++#define M10BMC_PKVL_PRELOAD_INTERVAL_US (100 * 1000) ++#define M10BMC_PKVL_PRELOAD_TIMEOUT_US (30 * 1000 * 1000) ++ + /* Telemetry registers */ + #define M10BMC_N3000_TELEM_START 0x100 + #define M10BMC_N3000_TELEM_END 0x250 +@@ -258,6 +289,7 @@ enum m10bmc_fw_state { + M10BMC_FW_STATE_SEC_UPDATE_PREPARE, + M10BMC_FW_STATE_SEC_UPDATE_WRITE, + M10BMC_FW_STATE_SEC_UPDATE_PROGRAM, ++ M10BMC_FW_RETIMER_EEPROM_LOAD, + }; + + /** diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0009-fpga-dfl-Add-GUID-support-in-mod-device-table.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0009-fpga-dfl-Add-GUID-support-in-mod-device-table.patch new file mode 100644 index 0000000..182bed3 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0009-fpga-dfl-Add-GUID-support-in-mod-device-table.patch @@ -0,0 +1,88 @@ +From c11b48dea976a3f6237dbcd6e133c872094ed026 Mon Sep 17 00:00:00 2001 +From: Basheer Ahmed Muddebihal +Date: Tue, 19 Jul 2022 13:53:03 -0700 +Subject: [PATCH] fpga: dfl: Add GUID support in mod device table + +In the modalias table, dfl devices use the type id and feature id to +create the dfl device string entry "dfl:t0000f0009*". This patch adds +support for the use of a GUID for dfl devices. Device drivers may match +on type id and feature id, on the GUID, or on a combination of the type id, +feature id and GUID. + +If the feature id and GUID are both non-zero, then the modalias string is: +"dfl:t0000f0009g{525074DC-8985-46E2-8057-A307DC18A509}*" +If the feature id is zero and the GUID is non-zero, then the string is: +"dfl:t*f*g{525074DC-8985-46E2-8057-A307DC18A509}*" +If the feature id is non-zero and the GUID is zero, then the string is +"dfl:t0000f0009*" + +Signed-off-by: Basheer Ahmed Muddebihal +--- + include/linux/mod_devicetable.h | 1 + + scripts/mod/devicetable-offsets.c | 1 + + scripts/mod/file2alias.c | 22 ++++++++++++++++++++-- + 3 files changed, 22 insertions(+), 2 deletions(-) + +diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h +index b0678b093cb2..018f5fb583ec 100644 +--- a/include/linux/mod_devicetable.h ++++ b/include/linux/mod_devicetable.h +@@ -908,6 +908,7 @@ struct ssam_device_id { + struct dfl_device_id { + __u16 type; + __u16 feature_id; ++ guid_t guid; + kernel_ulong_t driver_data; + }; + +diff --git a/scripts/mod/devicetable-offsets.c b/scripts/mod/devicetable-offsets.c +index abe65f8968dd..460a76f5b2c0 100644 +--- a/scripts/mod/devicetable-offsets.c ++++ b/scripts/mod/devicetable-offsets.c +@@ -258,6 +258,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(ishtp_device_id); + DEVID_FIELD(ishtp_device_id, guid); +diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c +index 7056751c29b1..981b7707d7f6 100644 +--- a/scripts/mod/file2alias.c ++++ b/scripts/mod/file2alias.c +@@ -1440,14 +1440,32 @@ static int do_ssam_entry(const char *filename, void *symval, char *alias) + return 1; + } + +-/* Looks like: dfl:tNfN */ ++/* 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}; + DEF_FIELD(symval, dfl_device_id, type); + DEF_FIELD(symval, dfl_device_id, feature_id); ++ DEF_FIELD(symval, dfl_device_id, guid); + +- sprintf(alias, "dfl:t%04Xf%04X", type, feature_id); ++ guid_cmp_val = memcmp(&null_guid, &guid, sizeof(guid_t)); + ++ if (feature_id == 0 && guid_cmp_val == 0) { ++ warn("Invalid dfl Device ID for in '%s'\n", filename); ++ return 0; ++ } ++ ++ if (feature_id == 0) ++ strcpy(alias, "dfl:t*f*"); ++ else ++ 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), "}"); ++ } + add_wildcard(alias); + return 1; + } diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0010-fpga-dfl-Add-feature-device-driver-match-by-GUID.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0010-fpga-dfl-Add-feature-device-driver-match-by-GUID.patch new file mode 100644 index 0000000..7642f49 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0010-fpga-dfl-Add-feature-device-driver-match-by-GUID.patch @@ -0,0 +1,277 @@ +From c4d834e5161305f95828a1f71db861eec3be4770 Mon Sep 17 00:00:00 2001 +From: Basheer Ahmed Muddebihal +Date: Mon, 28 Nov 2022 15:03:35 -0800 +Subject: [PATCH] fpga: dfl: Add feature device driver match by GUID +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch adds the DFL enumeration and binding of the driver  +using GUID match for DFHv1 FPGA IPs.  + +- Changed the GUID match logic to first bind GUID + if GUID is valid for DFHv1 headers +- Added the method to check for invalid ID's such as + NULL and all F in GUID +- Added the read-only sysfs attribute "guid" of DFHv1 FPGA IP +- Added uevent string to support GUID match + +Signed-off-by: Basheer Ahmed Muddebihal +--- + drivers/fpga/dfl.c | 65 ++++++++++++++++++++++++++++++++++++++++----- + drivers/fpga/dfl.h | 33 +++++++++++++++++++++++ + include/linux/dfl.h | 2 ++ + 3 files changed, 93 insertions(+), 7 deletions(-) + +diff --git a/drivers/fpga/dfl.c b/drivers/fpga/dfl.c +index 75580ba0419f..684db4379d58 100644 +--- a/drivers/fpga/dfl.c ++++ b/drivers/fpga/dfl.c +@@ -251,7 +251,8 @@ static DEFINE_IDA(dfl_device_ida); + static const struct dfl_device_id * + dfl_match_one_device(const struct dfl_device_id *id, struct dfl_device *ddev) + { +- if (id->type == ddev->type && id->feature_id == ddev->feature_id) ++ if ((dfl_guid_is_valid(&ddev->guid) && guid_equal(&id->guid, &ddev->guid)) || ++ (id->type == ddev->type && id->feature_id == ddev->feature_id)) + return id; + + return NULL; +@@ -265,7 +266,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) { ++ while (id_entry->feature_id || dfl_guid_is_valid(&id_entry->guid)) { + if (dfl_match_one_device(id_entry, ddev)) { + ddev->id_entry = id_entry; + return 1; +@@ -294,12 +295,19 @@ static void dfl_bus_remove(struct device *dev) + ddrv->remove(ddev); + } + ++#define DFL_ALIAS_BUF_LEN 64 ++ + static int dfl_bus_uevent(const struct device *dev, struct kobj_uevent_env *env) + { + const struct dfl_device *ddev = to_dfl_dev(dev); ++ char alias[DFL_ALIAS_BUF_LEN]; ++ ++ scnprintf(alias, DFL_ALIAS_BUF_LEN, "dfl:t%04Xf%04X", ddev->type, ddev->feature_id); + +- return add_uevent_var(env, "MODALIAS=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); ++ ++ return add_uevent_var(env, "MODALIAS=%s", alias); + } + + static ssize_t +@@ -320,9 +328,22 @@ feature_id_show(struct device *dev, struct device_attribute *attr, char *buf) + } + static DEVICE_ATTR_RO(feature_id); + ++static ssize_t ++guid_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); ++} ++static DEVICE_ATTR_RO(guid); ++ + static struct attribute *dfl_dev_attrs[] = { + &dev_attr_type.attr, + &dev_attr_feature_id.attr, ++ &dev_attr_guid.attr, + NULL, + }; + ATTRIBUTE_GROUPS(dfl_dev); +@@ -394,6 +415,9 @@ dfl_dev_add(struct dfl_feature_platform_data *pdata, + ddev->param_size = feature->param_size; + } + ++ if (ddev->dfh_version == 1) ++ guid_copy(&ddev->guid, &feature->guid); ++ + /* add mmio resource */ + parent_res = &pdev->resource[feature->resource_index]; + ddev->mmio_res.flags = IORESOURCE_MEM; +@@ -557,8 +581,10 @@ static bool dfl_feature_drv_match(struct dfl_feature *feature, + const struct dfl_feature_id *ids = driver->id_table; + + if (ids) { +- while (ids->id) { +- if (ids->id == feature->id) ++ while (ids->id || dfl_guid_is_valid(&ids->guid)) { ++ if ((dfl_guid_is_valid(&feature->guid) && ++ guid_equal(&ids->guid, &feature->guid)) || ++ ids->id == feature->id) + return true; + ids++; + } +@@ -721,7 +747,8 @@ struct build_feature_devs_info { + * + * @fid: id of this sub feature. + * @revision: revision of this sub feature +- * @dfh_version: version of Device Feature Header (DFH) ++ * @dfh_version: device feature header version. ++ * @guid: guid of this sub feature. + * @mmio_res: mmio resource of this sub feature. + * @ioaddr: mapped base address of mmio resource. + * @node: node in sub_features linked list. +@@ -734,6 +761,7 @@ struct dfl_feature_info { + u16 fid; + u8 revision; + u8 dfh_version; ++ guid_t guid; + struct resource mmio_res; + void __iomem *ioaddr; + struct list_head node; +@@ -827,6 +855,8 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo) + + feature->param_size = finfo->param_size; + } ++ if (feature->dfh_version == 1) ++ guid_copy(&feature->guid, &finfo->guid); + /* + * the FIU header feature has some fundamental functions (sriov + * set, port enable/disable) needed for the dfl bus device and +@@ -1139,6 +1169,7 @@ create_feature_instance(struct build_feature_devs_info *binfo, + struct dfl_feature_info *finfo; + resource_size_t start, end; + int dfh_psize = 0; ++ u64 guid_l, guid_h; + u8 revision = 0; + u64 v, addr_off; + u8 dfh_ver = 0; +@@ -1148,6 +1179,7 @@ create_feature_instance(struct build_feature_devs_info *binfo, + v = readq(binfo->ioaddr + ofst); + revision = FIELD_GET(DFH_REVISION, v); + dfh_ver = FIELD_GET(DFH_VERSION, v); ++ + /* read feature size and id if inputs are invalid */ + size = size ? size : feature_size(v); + fid = fid ? fid : feature_id(v); +@@ -1187,10 +1219,29 @@ create_feature_instance(struct build_feature_devs_info *binfo, + + v = readq(binfo->ioaddr + ofst + DFHv1_CSR_SIZE_GRP); + end = start + FIELD_GET(DFHv1_CSR_SIZE_GRP_SIZE, v) - 1; ++ guid_l = readq(binfo->ioaddr + ofst + GUID_L); ++ guid_h = readq(binfo->ioaddr + ofst + GUID_H); ++ ++ 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; + } ++ + finfo->mmio_res.flags = IORESOURCE_MEM; + finfo->mmio_res.start = start; + finfo->mmio_res.end = end; +diff --git a/drivers/fpga/dfl.h b/drivers/fpga/dfl.h +index 1d724a28f00a..d9cb13980e8d 100644 +--- a/drivers/fpga/dfl.h ++++ b/drivers/fpga/dfl.h +@@ -233,9 +233,11 @@ int dfl_fpga_check_port_id(struct platform_device *pdev, void *pport_id); + * struct dfl_feature_id - dfl private feature id + * + * @id: unique dfl private feature id. ++ * @guid: unique dfl private guid. + */ + struct dfl_feature_id { + u16 id; ++ guid_t guid; + }; + + /** +@@ -280,6 +282,7 @@ struct dfl_feature_irq_ctx { + * @dfh_version: version of the DFH + * @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; +@@ -295,6 +298,7 @@ struct dfl_feature { + u8 dfh_version; + unsigned int param_size; + void *params; ++ guid_t guid; + }; + + #define FEATURE_DEV_ID_UNUSED (-1) +@@ -469,6 +473,35 @@ 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 bool dfl_guid_is_valid(const guid_t *guid) ++{ ++ bool ret = true; ++ guid_t *guid_invalid = &DFL_GUID_INVALID; ++ ++ if (guid_is_null(guid) || guid_equal(guid, guid_invalid)) ++ ret = false; ++ return ret; ++} ++ ++/* ++ * 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) ++ + /** + * struct dfl_fpga_enum_info - DFL FPGA enumeration information + * +diff --git a/include/linux/dfl.h b/include/linux/dfl.h +index 0a7a00a0ee7f..a62449b70708 100644 +--- a/include/linux/dfl.h ++++ b/include/linux/dfl.h +@@ -36,6 +36,7 @@ enum dfl_id_type { + * @dfh_version: version of DFH for the device + * @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; +@@ -51,6 +52,7 @@ struct dfl_device { + u8 dfh_version; + unsigned int param_size; + void *params; ++ guid_t guid; + }; + + /** diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0011-tty-serial-8250-Add-the-GUID-definition-for-UART.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0011-tty-serial-8250-Add-the-GUID-definition-for-UART.patch new file mode 100644 index 0000000..21b4d85 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0011-tty-serial-8250-Add-the-GUID-definition-for-UART.patch @@ -0,0 +1,30 @@ +From 9d2d1fb1329c52fd6f504b023e4005a0bd394353 Mon Sep 17 00:00:00 2001 +From: Basheer Ahmed Muddebihal +Date: Thu, 3 Nov 2022 22:56:09 -0700 +Subject: [PATCH] tty: serial: 8250: Add the GUID definition for UART + +Added the GUID for the UART DFL device IP + +Signed-off-by: Basheer Ahmed Muddebihal +--- + drivers/tty/serial/8250/8250_dfl.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/tty/serial/8250/8250_dfl.c b/drivers/tty/serial/8250/8250_dfl.c +index 6c5ff019df4b..4f5eb8216934 100644 +--- a/drivers/tty/serial/8250/8250_dfl.c ++++ b/drivers/tty/serial/8250/8250_dfl.c +@@ -146,8 +146,12 @@ 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) ++ + static const struct dfl_device_id dfl_uart_ids[] = { +- { FME_ID, FME_FEATURE_ID_UART }, ++ { FME_ID, FME_FEATURE_ID_UART, .guid = FME_GUID_UART }, + { } + }; + MODULE_DEVICE_TABLE(dfl, dfl_uart_ids); diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0012-fpga-dfl-fix-the-kernel-warning-when-release-assign-.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0012-fpga-dfl-fix-the-kernel-warning-when-release-assign-.patch new file mode 100644 index 0000000..fdb16af --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0012-fpga-dfl-fix-the-kernel-warning-when-release-assign-.patch @@ -0,0 +1,3348 @@ +From 294699dad8a453cf908e843bcf0c71e4601e3c46 Mon Sep 17 00:00:00 2001 +From: Xu Yilun +Date: Mon, 22 Feb 2021 16:48:15 +0800 +Subject: [PATCH] fpga: dfl: fix the kernel warning when release/assign ports + for SRIOV +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The dfl ports are registered as platform devices in PF mode. The port +device should be removed from host when the user wants to configure the +port as VF and pass through to VM. The FME dev ioctls +DFL_FPGA_FME_PORT_RELEASE/ASSIGN are designed for this purpose. + +In previous implementation, the port platform device is not completely +destroyed on port release. It is removed from system by +platform_device_del(), but the platform device instance is retained. +When the port assign ioctl is called, it is added back by +platform_device_add(). It conflicts to the comments of device_add(): +"Do not call this routine more than once for any device structure", +and will cause kernel warning at runtime. + +The patch tries to completely unregisters the port platform device on +release and registers a new one on assign. But the main work is to +remove the dependency of struct dfl_feature_platform_data for many +internal DFL APIs. This structure holds many DFL enumeration info for +feature devices. Many DFL APIs are expected to work with these info even +when the port platform device is unregistered. But with the change the +platform_data will be freed in this case. So this patch introduced a new +structure dfl_feature_dev_data for these APIs, it acts similarly as the +previous dfl_feature_platform_data. The dfl_feature_platform_data then +only needs a pointer this dfl_feature_dev_data to make feature device +driver work. + +Signed-off-by: Xu Yilun +Signed-off-by: Russ Weight +Signed-off-by: Ilpo Järvinen +--- + drivers/fpga/dfl-afu-dma-region.c | 119 +++++---- + drivers/fpga/dfl-afu-error.c | 59 ++-- + drivers/fpga/dfl-afu-main.c | 254 +++++++++--------- + drivers/fpga/dfl-afu-region.c | 51 ++-- + drivers/fpga/dfl-afu.h | 26 +- + drivers/fpga/dfl-fme-br.c | 24 +- + drivers/fpga/dfl-fme-error.c | 98 +++---- + drivers/fpga/dfl-fme-main.c | 70 +++-- + drivers/fpga/dfl-fme-pr.c | 84 +++--- + drivers/fpga/dfl.c | 431 +++++++++++++++--------------- + drivers/fpga/dfl.h | 138 ++++++---- + 11 files changed, 698 insertions(+), 656 deletions(-) + +diff --git a/drivers/fpga/dfl-afu-dma-region.c b/drivers/fpga/dfl-afu-dma-region.c +index 374d96d5f6a6..6632c51eaa62 100644 +--- a/drivers/fpga/dfl-afu-dma-region.c ++++ b/drivers/fpga/dfl-afu-dma-region.c +@@ -17,26 +17,26 @@ + + #include "dfl-afu.h" + +-void afu_dma_region_init(struct dfl_feature_platform_data *pdata) ++void afu_dma_region_init(struct dfl_feature_dev_data *fdata) + { +- struct dfl_afu *afu = dfl_fpga_pdata_get_private(pdata); ++ struct dfl_afu *afu = dfl_fpga_fdata_get_private(fdata); + + afu->dma_regions = RB_ROOT; + } + + /** + * afu_dma_pin_pages - pin pages of given dma memory region +- * @pdata: feature device platform data ++ * @fdata: feature dev data + * @region: dma memory region to be pinned + * + * Pin all the pages of given dfl_afu_dma_region. + * Return 0 for success or negative error code. + */ +-static int afu_dma_pin_pages(struct dfl_feature_platform_data *pdata, ++static int afu_dma_pin_pages(struct dfl_feature_dev_data *fdata, + struct dfl_afu_dma_region *region) + { + int npages = PFN_DOWN(region->length); +- struct device *dev = &pdata->dev->dev; ++ struct device *dev = &fdata->dev->dev; + int ret, pinned; + + ret = account_locked_vm(current->mm, npages, true); +@@ -74,17 +74,17 @@ static int afu_dma_pin_pages(struct dfl_feature_platform_data *pdata, + + /** + * afu_dma_unpin_pages - unpin pages of given dma memory region +- * @pdata: feature device platform data ++ * @fdata: feature dev data + * @region: dma memory region to be unpinned + * + * Unpin all the pages of given dfl_afu_dma_region. + * Return 0 for success or negative error code. + */ +-static void afu_dma_unpin_pages(struct dfl_feature_platform_data *pdata, ++static void afu_dma_unpin_pages(struct dfl_feature_dev_data *fdata, + struct dfl_afu_dma_region *region) + { + long npages = PFN_DOWN(region->length); +- struct device *dev = &pdata->dev->dev; ++ struct device *dev = &fdata->dev->dev; + + unpin_user_pages(region->pages, npages); + kfree(region->pages); +@@ -134,20 +134,21 @@ static bool dma_region_check_iova(struct dfl_afu_dma_region *region, + + /** + * afu_dma_region_add - add given dma region to rbtree +- * @pdata: feature device platform data ++ * @fdata: feature dev data + * @region: dma region to be added + * + * Return 0 for success, -EEXIST if dma region has already been added. + * +- * Needs to be called with pdata->lock heold. ++ * Needs to be called with fdata->lock held. + */ +-static int afu_dma_region_add(struct dfl_feature_platform_data *pdata, ++static int afu_dma_region_add(struct dfl_feature_dev_data *fdata, + struct dfl_afu_dma_region *region) + { +- struct dfl_afu *afu = dfl_fpga_pdata_get_private(pdata); ++ struct dfl_afu *afu = dfl_fpga_fdata_get_private(fdata); ++ struct device *dev = &fdata->dev->dev; + struct rb_node **new, *parent = NULL; + +- dev_dbg(&pdata->dev->dev, "add region (iova = %llx)\n", region->iova); ++ dev_dbg(dev, "add region (iova = %llx)\n", region->iova); + + new = &afu->dma_regions.rb_node; + +@@ -177,49 +178,50 @@ static int afu_dma_region_add(struct dfl_feature_platform_data *pdata, + + /** + * afu_dma_region_remove - remove given dma region from rbtree +- * @pdata: feature device platform data ++ * @fdata: feature dev data + * @region: dma region to be removed + * +- * Needs to be called with pdata->lock heold. ++ * Needs to be called with fdata->lock held. + */ +-static void afu_dma_region_remove(struct dfl_feature_platform_data *pdata, ++static void afu_dma_region_remove(struct dfl_feature_dev_data *fdata, + struct dfl_afu_dma_region *region) + { ++ struct device *dev = &fdata->dev->dev; + struct dfl_afu *afu; + +- dev_dbg(&pdata->dev->dev, "del region (iova = %llx)\n", region->iova); ++ dev_dbg(dev, "del region (iova = %llx)\n", region->iova); + +- afu = dfl_fpga_pdata_get_private(pdata); ++ afu = dfl_fpga_fdata_get_private(fdata); + rb_erase(®ion->node, &afu->dma_regions); + } + + /** + * afu_dma_region_destroy - destroy all regions in rbtree +- * @pdata: feature device platform data ++ * @fdata: feature dev data + * +- * Needs to be called with pdata->lock heold. ++ * Needs to be called with fdata->lock held. + */ +-void afu_dma_region_destroy(struct dfl_feature_platform_data *pdata) ++void afu_dma_region_destroy(struct dfl_feature_dev_data *fdata) + { +- struct dfl_afu *afu = dfl_fpga_pdata_get_private(pdata); ++ struct dfl_afu *afu = dfl_fpga_fdata_get_private(fdata); + struct rb_node *node = rb_first(&afu->dma_regions); + struct dfl_afu_dma_region *region; + + while (node) { + region = container_of(node, struct dfl_afu_dma_region, node); + +- dev_dbg(&pdata->dev->dev, "del region (iova = %llx)\n", ++ dev_dbg(&fdata->dev->dev, "del region (iova = %llx)\n", + region->iova); + + rb_erase(node, &afu->dma_regions); + + if (region->iova) +- dma_unmap_page(dfl_fpga_pdata_to_parent(pdata), ++ dma_unmap_page(dfl_fpga_fdata_to_parent(fdata), + region->iova, region->length, + DMA_BIDIRECTIONAL); + + if (region->pages) +- afu_dma_unpin_pages(pdata, region); ++ afu_dma_unpin_pages(fdata, region); + + node = rb_next(node); + kfree(region); +@@ -228,7 +230,7 @@ void afu_dma_region_destroy(struct dfl_feature_platform_data *pdata) + + /** + * afu_dma_region_find - find the dma region from rbtree based on iova and size +- * @pdata: feature device platform data ++ * @fdata: feature dev data + * @iova: address of the dma memory area + * @size: size of the dma memory area + * +@@ -238,14 +240,14 @@ void afu_dma_region_destroy(struct dfl_feature_platform_data *pdata) + * [@iova, @iova+size) + * If nothing is matched returns NULL. + * +- * Needs to be called with pdata->lock held. ++ * Needs to be called with fdata->lock held. + */ + struct dfl_afu_dma_region * +-afu_dma_region_find(struct dfl_feature_platform_data *pdata, u64 iova, u64 size) ++afu_dma_region_find(struct dfl_feature_dev_data *fdata, u64 iova, u64 size) + { +- struct dfl_afu *afu = dfl_fpga_pdata_get_private(pdata); ++ struct dfl_afu *afu = dfl_fpga_fdata_get_private(fdata); + struct rb_node *node = afu->dma_regions.rb_node; +- struct device *dev = &pdata->dev->dev; ++ struct device *dev = &fdata->dev->dev; + + while (node) { + struct dfl_afu_dma_region *region; +@@ -275,20 +277,20 @@ afu_dma_region_find(struct dfl_feature_platform_data *pdata, u64 iova, u64 size) + + /** + * afu_dma_region_find_iova - find the dma region from rbtree by iova +- * @pdata: feature device platform data ++ * @fdata: feature dev data + * @iova: address of the dma region + * +- * Needs to be called with pdata->lock held. ++ * Needs to be called with fdata->lock held. + */ + static struct dfl_afu_dma_region * +-afu_dma_region_find_iova(struct dfl_feature_platform_data *pdata, u64 iova) ++afu_dma_region_find_iova(struct dfl_feature_dev_data *fdata, u64 iova) + { +- return afu_dma_region_find(pdata, iova, 0); ++ return afu_dma_region_find(fdata, iova, 0); + } + + /** + * afu_dma_map_region - map memory region for dma +- * @pdata: feature device platform data ++ * @fdata: feature dev data + * @user_addr: address of the memory region + * @length: size of the memory region + * @iova: pointer of iova address +@@ -297,9 +299,10 @@ afu_dma_region_find_iova(struct dfl_feature_platform_data *pdata, u64 iova) + * of the memory region via @iova. + * Return 0 for success, otherwise error code. + */ +-int afu_dma_map_region(struct dfl_feature_platform_data *pdata, ++int afu_dma_map_region(struct dfl_feature_dev_data *fdata, + u64 user_addr, u64 length, u64 *iova) + { ++ struct device *dev = &fdata->dev->dev; + struct dfl_afu_dma_region *region; + int ret; + +@@ -322,47 +325,47 @@ int afu_dma_map_region(struct dfl_feature_platform_data *pdata, + region->length = length; + + /* Pin the user memory region */ +- ret = afu_dma_pin_pages(pdata, region); ++ ret = afu_dma_pin_pages(fdata, region); + if (ret) { +- dev_err(&pdata->dev->dev, "failed to pin memory region\n"); ++ dev_err(dev, "failed to pin memory region\n"); + goto free_region; + } + + /* Only accept continuous pages, return error else */ + if (!afu_dma_check_continuous_pages(region)) { +- dev_err(&pdata->dev->dev, "pages are not continuous\n"); ++ dev_err(dev, "pages are not continuous\n"); + ret = -EINVAL; + goto unpin_pages; + } + + /* As pages are continuous then start to do DMA mapping */ +- region->iova = dma_map_page(dfl_fpga_pdata_to_parent(pdata), ++ region->iova = dma_map_page(dfl_fpga_fdata_to_parent(fdata), + region->pages[0], 0, + region->length, + DMA_BIDIRECTIONAL); +- if (dma_mapping_error(dfl_fpga_pdata_to_parent(pdata), region->iova)) { +- dev_err(&pdata->dev->dev, "failed to map for dma\n"); ++ if (dma_mapping_error(dfl_fpga_fdata_to_parent(fdata), region->iova)) { ++ dev_err(dev, "failed to map for dma\n"); + ret = -EFAULT; + goto unpin_pages; + } + + *iova = region->iova; + +- mutex_lock(&pdata->lock); +- ret = afu_dma_region_add(pdata, region); +- mutex_unlock(&pdata->lock); ++ mutex_lock(&fdata->lock); ++ ret = afu_dma_region_add(fdata, region); ++ mutex_unlock(&fdata->lock); + if (ret) { +- dev_err(&pdata->dev->dev, "failed to add dma region\n"); ++ dev_err(dev, "failed to add dma region\n"); + goto unmap_dma; + } + + return 0; + + unmap_dma: +- dma_unmap_page(dfl_fpga_pdata_to_parent(pdata), ++ dma_unmap_page(dfl_fpga_fdata_to_parent(fdata), + region->iova, region->length, DMA_BIDIRECTIONAL); + unpin_pages: +- afu_dma_unpin_pages(pdata, region); ++ afu_dma_unpin_pages(fdata, region); + free_region: + kfree(region); + return ret; +@@ -370,34 +373,34 @@ int afu_dma_map_region(struct dfl_feature_platform_data *pdata, + + /** + * afu_dma_unmap_region - unmap dma memory region +- * @pdata: feature device platform data ++ * @fdata: feature dev data + * @iova: dma address of the region + * + * Unmap dma memory region based on @iova. + * Return 0 for success, otherwise error code. + */ +-int afu_dma_unmap_region(struct dfl_feature_platform_data *pdata, u64 iova) ++int afu_dma_unmap_region(struct dfl_feature_dev_data *fdata, u64 iova) + { + struct dfl_afu_dma_region *region; + +- mutex_lock(&pdata->lock); +- region = afu_dma_region_find_iova(pdata, iova); ++ mutex_lock(&fdata->lock); ++ region = afu_dma_region_find_iova(fdata, iova); + if (!region) { +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + return -EINVAL; + } + + if (region->in_use) { +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + return -EBUSY; + } + +- afu_dma_region_remove(pdata, region); +- mutex_unlock(&pdata->lock); ++ afu_dma_region_remove(fdata, region); ++ mutex_unlock(&fdata->lock); + +- dma_unmap_page(dfl_fpga_pdata_to_parent(pdata), ++ dma_unmap_page(dfl_fpga_fdata_to_parent(fdata), + region->iova, region->length, DMA_BIDIRECTIONAL); +- afu_dma_unpin_pages(pdata, region); ++ afu_dma_unpin_pages(fdata, region); + kfree(region); + + return 0; +diff --git a/drivers/fpga/dfl-afu-error.c b/drivers/fpga/dfl-afu-error.c +index 6d113d606560..a36db24384f6 100644 +--- a/drivers/fpga/dfl-afu-error.c ++++ b/drivers/fpga/dfl-afu-error.c +@@ -28,37 +28,36 @@ + #define ERROR_MASK GENMASK_ULL(63, 0) + + /* mask or unmask port errors by the error mask register. */ +-static void __afu_port_err_mask(struct device *dev, bool mask) ++static void __afu_port_err_mask(struct dfl_feature_dev_data *fdata, bool mask) + { + void __iomem *base; + +- base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_ERROR); ++ base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_ERROR); + + writeq(mask ? ERROR_MASK : 0, base + PORT_ERROR_MASK); + } + + static void afu_port_err_mask(struct device *dev, bool mask) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + +- mutex_lock(&pdata->lock); +- __afu_port_err_mask(dev, mask); +- mutex_unlock(&pdata->lock); ++ mutex_lock(&fdata->lock); ++ __afu_port_err_mask(fdata, mask); ++ mutex_unlock(&fdata->lock); + } + + /* clear port errors. */ + static int afu_port_err_clear(struct device *dev, u64 err) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); +- struct platform_device *pdev = to_platform_device(dev); ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + void __iomem *base_err, *base_hdr; + int enable_ret = 0, ret = -EBUSY; + u64 v; + +- base_err = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_ERROR); +- base_hdr = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); ++ base_err = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_ERROR); ++ base_hdr = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_HEADER); + +- mutex_lock(&pdata->lock); ++ mutex_lock(&fdata->lock); + + /* + * clear Port Errors +@@ -80,12 +79,12 @@ static int afu_port_err_clear(struct device *dev, u64 err) + } + + /* Halt Port by keeping Port in reset */ +- ret = __afu_port_disable(pdev); ++ ret = __afu_port_disable(fdata); + if (ret) + goto done; + + /* Mask all errors */ +- __afu_port_err_mask(dev, true); ++ __afu_port_err_mask(fdata, true); + + /* Clear errors if err input matches with current port errors.*/ + v = readq(base_err + PORT_ERROR); +@@ -102,28 +101,28 @@ static int afu_port_err_clear(struct device *dev, u64 err) + } + + /* Clear mask */ +- __afu_port_err_mask(dev, false); ++ __afu_port_err_mask(fdata, false); + + /* Enable the Port by clearing the reset */ +- enable_ret = __afu_port_enable(pdev); ++ enable_ret = __afu_port_enable(fdata); + + done: +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + return enable_ret ? enable_ret : ret; + } + + static ssize_t errors_show(struct device *dev, struct device_attribute *attr, + char *buf) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + void __iomem *base; + u64 error; + +- base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_ERROR); ++ base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_ERROR); + +- mutex_lock(&pdata->lock); ++ mutex_lock(&fdata->lock); + error = readq(base + PORT_ERROR); +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + + return sysfs_emit(buf, "0x%llx\n", error); + } +@@ -146,15 +145,15 @@ static DEVICE_ATTR_RW(errors); + static ssize_t first_error_show(struct device *dev, + struct device_attribute *attr, char *buf) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + void __iomem *base; + u64 error; + +- base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_ERROR); ++ base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_ERROR); + +- mutex_lock(&pdata->lock); ++ mutex_lock(&fdata->lock); + error = readq(base + PORT_FIRST_ERROR); +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + + return sysfs_emit(buf, "0x%llx\n", error); + } +@@ -164,16 +163,16 @@ static ssize_t first_malformed_req_show(struct device *dev, + struct device_attribute *attr, + char *buf) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + void __iomem *base; + u64 req0, req1; + +- base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_ERROR); ++ base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_ERROR); + +- mutex_lock(&pdata->lock); ++ mutex_lock(&fdata->lock); + req0 = readq(base + PORT_MALFORMED_REQ0); + req1 = readq(base + PORT_MALFORMED_REQ1); +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + + return sysfs_emit(buf, "0x%016llx%016llx\n", req1, req0); + } +@@ -190,12 +189,14 @@ static umode_t port_err_attrs_visible(struct kobject *kobj, + struct attribute *attr, int n) + { + struct device *dev = kobj_to_dev(kobj); ++ struct dfl_feature_dev_data *fdata; + ++ fdata = to_dfl_feature_dev_data(dev); + /* + * sysfs entries are visible only if related private feature is + * enumerated. + */ +- if (!dfl_get_feature_by_id(dev, PORT_FEATURE_ID_ERROR)) ++ if (!dfl_get_feature_by_id(fdata, PORT_FEATURE_ID_ERROR)) + return 0; + + return attr->mode; +diff --git a/drivers/fpga/dfl-afu-main.c b/drivers/fpga/dfl-afu-main.c +index cafb4dc0186d..2e49740dbaf6 100644 +--- a/drivers/fpga/dfl-afu-main.c ++++ b/drivers/fpga/dfl-afu-main.c +@@ -27,7 +27,7 @@ + + /** + * __afu_port_enable - enable a port by clear reset +- * @pdev: port platform device. ++ * @fdata: port feature dev data. + * + * Enable Port by clear the port soft reset bit, which is set by default. + * The AFU is unable to respond to any MMIO access while in reset. +@@ -36,18 +36,17 @@ + * + * The caller needs to hold lock for protection. + */ +-int __afu_port_enable(struct platform_device *pdev) ++int __afu_port_enable(struct dfl_feature_dev_data *fdata) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); + void __iomem *base; + u64 v; + +- WARN_ON(!pdata->disable_count); ++ WARN_ON(!fdata->disable_count); + +- if (--pdata->disable_count != 0) ++ if (--fdata->disable_count != 0) + return 0; + +- base = dfl_get_feature_ioaddr_by_id(&pdev->dev, PORT_FEATURE_ID_HEADER); ++ base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_HEADER); + + /* Clear port soft reset */ + v = readq(base + PORT_HDR_CTRL); +@@ -61,7 +60,8 @@ int __afu_port_enable(struct platform_device *pdev) + if (readq_poll_timeout(base + PORT_HDR_CTRL, v, + !(v & PORT_CTRL_SFTRST_ACK), + RST_POLL_INVL, RST_POLL_TIMEOUT)) { +- dev_err(&pdev->dev, "timeout, failure to enable device\n"); ++ dev_err(fdata->dfl_cdev->parent, ++ "timeout, failure to enable device\n"); + return -ETIMEDOUT; + } + +@@ -70,22 +70,21 @@ int __afu_port_enable(struct platform_device *pdev) + + /** + * __afu_port_disable - disable a port by hold reset +- * @pdev: port platform device. ++ * @fdata: port feature dev data. + * + * Disable Port by setting the port soft reset bit, it puts the port into reset. + * + * The caller needs to hold lock for protection. + */ +-int __afu_port_disable(struct platform_device *pdev) ++int __afu_port_disable(struct dfl_feature_dev_data *fdata) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); + void __iomem *base; + u64 v; + +- if (pdata->disable_count++ != 0) ++ if (fdata->disable_count++ != 0) + return 0; + +- base = dfl_get_feature_ioaddr_by_id(&pdev->dev, PORT_FEATURE_ID_HEADER); ++ base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_HEADER); + + /* Set port soft reset */ + v = readq(base + PORT_HDR_CTRL); +@@ -100,7 +99,8 @@ int __afu_port_disable(struct platform_device *pdev) + if (readq_poll_timeout(base + PORT_HDR_CTRL, v, + v & PORT_CTRL_SFTRST_ACK, + RST_POLL_INVL, RST_POLL_TIMEOUT)) { +- dev_err(&pdev->dev, "timeout, failure to disable device\n"); ++ dev_err(fdata->dfl_cdev->parent, ++ "timeout, failure to disable device\n"); + return -ETIMEDOUT; + } + +@@ -119,34 +119,36 @@ int __afu_port_disable(struct platform_device *pdev) + * (disabled). Any attempts on MMIO access to AFU while in reset, will + * result errors reported via port error reporting sub feature (if present). + */ +-static int __port_reset(struct platform_device *pdev) ++static int __port_reset(struct dfl_feature_dev_data *fdata) + { + int ret; + +- ret = __afu_port_disable(pdev); ++ ret = __afu_port_disable(fdata); + if (ret) + return ret; + +- return __afu_port_enable(pdev); ++ return __afu_port_enable(fdata); + } + + static int port_reset(struct platform_device *pdev) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); ++ struct dfl_feature_dev_data *fdata; + int ret; + +- mutex_lock(&pdata->lock); +- ret = __port_reset(pdev); +- mutex_unlock(&pdata->lock); ++ fdata = to_dfl_feature_dev_data(&pdev->dev); ++ ++ mutex_lock(&fdata->lock); ++ ret = __port_reset(fdata); ++ mutex_unlock(&fdata->lock); + + return ret; + } + +-static int port_get_id(struct platform_device *pdev) ++static int port_get_id(struct dfl_feature_dev_data *fdata) + { + void __iomem *base; + +- base = dfl_get_feature_ioaddr_by_id(&pdev->dev, PORT_FEATURE_ID_HEADER); ++ base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_HEADER); + + return FIELD_GET(PORT_CAP_PORT_NUM, readq(base + PORT_HDR_CAP)); + } +@@ -154,7 +156,8 @@ static int port_get_id(struct platform_device *pdev) + static ssize_t + id_show(struct device *dev, struct device_attribute *attr, char *buf) + { +- int id = port_get_id(to_platform_device(dev)); ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); ++ int id = port_get_id(fdata); + + return sysfs_emit(buf, "%d\n", id); + } +@@ -163,15 +166,15 @@ static DEVICE_ATTR_RO(id); + static ssize_t + ltr_show(struct device *dev, struct device_attribute *attr, char *buf) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + void __iomem *base; + u64 v; + +- base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); ++ base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_HEADER); + +- mutex_lock(&pdata->lock); ++ mutex_lock(&fdata->lock); + v = readq(base + PORT_HDR_CTRL); +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + + return sysfs_emit(buf, "%llx\n", FIELD_GET(PORT_CTRL_LATENCY, v)); + } +@@ -180,7 +183,7 @@ static ssize_t + ltr_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + void __iomem *base; + bool ltr; + u64 v; +@@ -188,14 +191,14 @@ ltr_store(struct device *dev, struct device_attribute *attr, + if (kstrtobool(buf, <r)) + return -EINVAL; + +- base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); ++ base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_HEADER); + +- mutex_lock(&pdata->lock); ++ mutex_lock(&fdata->lock); + v = readq(base + PORT_HDR_CTRL); + v &= ~PORT_CTRL_LATENCY; + v |= FIELD_PREP(PORT_CTRL_LATENCY, ltr ? 1 : 0); + writeq(v, base + PORT_HDR_CTRL); +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + + return count; + } +@@ -204,15 +207,15 @@ static DEVICE_ATTR_RW(ltr); + static ssize_t + ap1_event_show(struct device *dev, struct device_attribute *attr, char *buf) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + void __iomem *base; + u64 v; + +- base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); ++ base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_HEADER); + +- mutex_lock(&pdata->lock); ++ mutex_lock(&fdata->lock); + v = readq(base + PORT_HDR_STS); +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + + return sysfs_emit(buf, "%llx\n", FIELD_GET(PORT_STS_AP1_EVT, v)); + } +@@ -221,18 +224,18 @@ static ssize_t + ap1_event_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + void __iomem *base; + bool clear; + + if (kstrtobool(buf, &clear) || !clear) + return -EINVAL; + +- base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); ++ base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_HEADER); + +- mutex_lock(&pdata->lock); ++ mutex_lock(&fdata->lock); + writeq(PORT_STS_AP1_EVT, base + PORT_HDR_STS); +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + + return count; + } +@@ -242,15 +245,15 @@ static ssize_t + ap2_event_show(struct device *dev, struct device_attribute *attr, + char *buf) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + void __iomem *base; + u64 v; + +- base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); ++ base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_HEADER); + +- mutex_lock(&pdata->lock); ++ mutex_lock(&fdata->lock); + v = readq(base + PORT_HDR_STS); +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + + return sysfs_emit(buf, "%llx\n", FIELD_GET(PORT_STS_AP2_EVT, v)); + } +@@ -259,18 +262,18 @@ static ssize_t + ap2_event_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + void __iomem *base; + bool clear; + + if (kstrtobool(buf, &clear) || !clear) + return -EINVAL; + +- base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); ++ base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_HEADER); + +- mutex_lock(&pdata->lock); ++ mutex_lock(&fdata->lock); + writeq(PORT_STS_AP2_EVT, base + PORT_HDR_STS); +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + + return count; + } +@@ -279,15 +282,15 @@ static DEVICE_ATTR_RW(ap2_event); + static ssize_t + power_state_show(struct device *dev, struct device_attribute *attr, char *buf) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + void __iomem *base; + u64 v; + +- base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); ++ base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_HEADER); + +- mutex_lock(&pdata->lock); ++ mutex_lock(&fdata->lock); + v = readq(base + PORT_HDR_STS); +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + + return sysfs_emit(buf, "0x%llx\n", FIELD_GET(PORT_STS_PWR_STATE, v)); + } +@@ -297,18 +300,18 @@ static ssize_t + userclk_freqcmd_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + u64 userclk_freq_cmd; + void __iomem *base; + + if (kstrtou64(buf, 0, &userclk_freq_cmd)) + return -EINVAL; + +- base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); ++ base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_HEADER); + +- mutex_lock(&pdata->lock); ++ mutex_lock(&fdata->lock); + writeq(userclk_freq_cmd, base + PORT_HDR_USRCLK_CMD0); +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + + return count; + } +@@ -318,18 +321,18 @@ static ssize_t + userclk_freqcntrcmd_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + u64 userclk_freqcntr_cmd; + void __iomem *base; + + if (kstrtou64(buf, 0, &userclk_freqcntr_cmd)) + return -EINVAL; + +- base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); ++ base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_HEADER); + +- mutex_lock(&pdata->lock); ++ mutex_lock(&fdata->lock); + writeq(userclk_freqcntr_cmd, base + PORT_HDR_USRCLK_CMD1); +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + + return count; + } +@@ -339,15 +342,15 @@ static ssize_t + userclk_freqsts_show(struct device *dev, struct device_attribute *attr, + char *buf) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + u64 userclk_freqsts; + void __iomem *base; + +- base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); ++ base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_HEADER); + +- mutex_lock(&pdata->lock); ++ mutex_lock(&fdata->lock); + userclk_freqsts = readq(base + PORT_HDR_USRCLK_STS0); +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + + return sysfs_emit(buf, "0x%llx\n", userclk_freqsts); + } +@@ -357,15 +360,15 @@ static ssize_t + userclk_freqcntrsts_show(struct device *dev, struct device_attribute *attr, + char *buf) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + u64 userclk_freqcntrsts; + void __iomem *base; + +- base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); ++ base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_HEADER); + +- mutex_lock(&pdata->lock); ++ mutex_lock(&fdata->lock); + userclk_freqcntrsts = readq(base + PORT_HDR_USRCLK_STS1); +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + + return sysfs_emit(buf, "0x%llx\n", userclk_freqcntrsts); + } +@@ -388,10 +391,12 @@ static umode_t port_hdr_attrs_visible(struct kobject *kobj, + struct attribute *attr, int n) + { + struct device *dev = kobj_to_dev(kobj); ++ struct dfl_feature_dev_data *fdata; + umode_t mode = attr->mode; + void __iomem *base; + +- base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); ++ fdata = to_dfl_feature_dev_data(dev); ++ base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_HEADER); + + if (dfl_feature_revision(base) > 0) { + /* +@@ -456,21 +461,21 @@ static const struct dfl_feature_ops port_hdr_ops = { + static ssize_t + afu_id_show(struct device *dev, struct device_attribute *attr, char *buf) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + void __iomem *base; + u64 guidl, guidh; + +- base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_AFU); ++ base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_AFU); + +- mutex_lock(&pdata->lock); +- if (pdata->disable_count) { +- mutex_unlock(&pdata->lock); ++ mutex_lock(&fdata->lock); ++ if (fdata->disable_count) { ++ mutex_unlock(&fdata->lock); + return -EBUSY; + } + + guidl = readq(base + GUID_L); + guidh = readq(base + GUID_H); +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + + return sysfs_emit(buf, "%016llx%016llx\n", guidh, guidl); + } +@@ -485,12 +490,15 @@ static umode_t port_afu_attrs_visible(struct kobject *kobj, + struct attribute *attr, int n) + { + struct device *dev = kobj_to_dev(kobj); ++ struct dfl_feature_dev_data *fdata; ++ ++ fdata = to_dfl_feature_dev_data(dev); + + /* + * sysfs entries are visible only if related private feature is + * enumerated. + */ +- if (!dfl_get_feature_by_id(dev, PORT_FEATURE_ID_AFU)) ++ if (!dfl_get_feature_by_id(fdata, PORT_FEATURE_ID_AFU)) + return 0; + + return attr->mode; +@@ -504,9 +512,11 @@ static const struct attribute_group port_afu_group = { + static int port_afu_init(struct platform_device *pdev, + struct dfl_feature *feature) + { ++ struct dfl_feature_dev_data *fdata = ++ to_dfl_feature_dev_data(&pdev->dev); + struct resource *res = &pdev->resource[feature->resource_index]; + +- return afu_mmio_region_add(dev_get_platdata(&pdev->dev), ++ return afu_mmio_region_add(fdata, + DFL_PORT_REGION_INDEX_AFU, + resource_size(res), res->start, + DFL_PORT_REGION_MMAP | DFL_PORT_REGION_READ | +@@ -525,9 +535,11 @@ static const struct dfl_feature_ops port_afu_ops = { + static int port_stp_init(struct platform_device *pdev, + struct dfl_feature *feature) + { ++ struct dfl_feature_dev_data *fdata = ++ to_dfl_feature_dev_data(&pdev->dev); + struct resource *res = &pdev->resource[feature->resource_index]; + +- return afu_mmio_region_add(dev_get_platdata(&pdev->dev), ++ return afu_mmio_region_add(fdata, + DFL_PORT_REGION_INDEX_STP, + resource_size(res), res->start, + DFL_PORT_REGION_MMAP | DFL_PORT_REGION_READ | +@@ -596,21 +608,19 @@ static struct dfl_feature_driver port_feature_drvs[] = { + static int afu_open(struct inode *inode, struct file *filp) + { + struct platform_device *fdev = dfl_fpga_inode_to_feature_dev(inode); +- struct dfl_feature_platform_data *pdata; ++ struct dfl_feature_dev_data *fdata; + int ret; + +- pdata = dev_get_platdata(&fdev->dev); +- if (WARN_ON(!pdata)) +- return -ENODEV; ++ fdata = to_dfl_feature_dev_data(&fdev->dev); + +- mutex_lock(&pdata->lock); +- ret = dfl_feature_dev_use_begin(pdata, filp->f_flags & O_EXCL); ++ mutex_lock(&fdata->lock); ++ ret = dfl_feature_dev_use_begin(fdata, filp->f_flags & O_EXCL); + if (!ret) { + dev_dbg(&fdev->dev, "Device File Opened %d Times\n", +- dfl_feature_dev_use_count(pdata)); ++ dfl_feature_dev_use_count(fdata)); + filp->private_data = fdev; + } +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + + return ret; + } +@@ -618,24 +628,24 @@ static int afu_open(struct inode *inode, struct file *filp) + static int afu_release(struct inode *inode, struct file *filp) + { + struct platform_device *pdev = filp->private_data; +- struct dfl_feature_platform_data *pdata; ++ struct dfl_feature_dev_data *fdata; + struct dfl_feature *feature; + + dev_dbg(&pdev->dev, "Device File Release\n"); + +- pdata = dev_get_platdata(&pdev->dev); ++ fdata = to_dfl_feature_dev_data(&pdev->dev); + +- mutex_lock(&pdata->lock); +- dfl_feature_dev_use_end(pdata); ++ mutex_lock(&fdata->lock); ++ dfl_feature_dev_use_end(fdata); + +- if (!dfl_feature_dev_use_count(pdata)) { +- dfl_fpga_dev_for_each_feature(pdata, feature) ++ if (!dfl_feature_dev_use_count(fdata)) { ++ dfl_fpga_dev_for_each_feature(fdata, feature) + dfl_fpga_set_irq_triggers(feature, 0, + feature->nr_irqs, NULL); +- __port_reset(pdev); +- afu_dma_region_destroy(pdata); ++ __port_reset(fdata); ++ afu_dma_region_destroy(fdata); + } +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + + return 0; + } +@@ -650,6 +660,7 @@ static long afu_ioctl_check_extension(struct dfl_feature_platform_data *pdata, + static long + afu_ioctl_get_info(struct dfl_feature_platform_data *pdata, void __user *arg) + { ++ struct dfl_feature_dev_data *fdata = pdata->fdata; + struct dfl_fpga_port_info info; + struct dfl_afu *afu; + unsigned long minsz; +@@ -662,12 +673,12 @@ afu_ioctl_get_info(struct dfl_feature_platform_data *pdata, void __user *arg) + if (info.argsz < minsz) + return -EINVAL; + +- mutex_lock(&pdata->lock); +- afu = dfl_fpga_pdata_get_private(pdata); ++ mutex_lock(&fdata->lock); ++ afu = dfl_fpga_fdata_get_private(fdata); + info.flags = 0; + info.num_regions = afu->num_regions; + info.num_umsgs = afu->num_umsgs; +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + + if (copy_to_user(arg, &info, sizeof(info))) + return -EFAULT; +@@ -691,7 +702,7 @@ static long afu_ioctl_get_region_info(struct dfl_feature_platform_data *pdata, + if (rinfo.argsz < minsz || rinfo.padding) + return -EINVAL; + +- ret = afu_mmio_region_get_by_index(pdata, rinfo.index, ®ion); ++ ret = afu_mmio_region_get_by_index(pdata->fdata, rinfo.index, ®ion); + if (ret) + return ret; + +@@ -708,6 +719,7 @@ static long afu_ioctl_get_region_info(struct dfl_feature_platform_data *pdata, + static long + afu_ioctl_dma_map(struct dfl_feature_platform_data *pdata, void __user *arg) + { ++ struct dfl_feature_dev_data *fdata = pdata->fdata; + struct dfl_fpga_port_dma_map map; + unsigned long minsz; + long ret; +@@ -720,16 +732,16 @@ afu_ioctl_dma_map(struct dfl_feature_platform_data *pdata, void __user *arg) + if (map.argsz < minsz || map.flags) + return -EINVAL; + +- ret = afu_dma_map_region(pdata, map.user_addr, map.length, &map.iova); ++ ret = afu_dma_map_region(fdata, map.user_addr, map.length, &map.iova); + if (ret) + return ret; + + if (copy_to_user(arg, &map, sizeof(map))) { +- afu_dma_unmap_region(pdata, map.iova); ++ afu_dma_unmap_region(fdata, map.iova); + return -EFAULT; + } + +- dev_dbg(&pdata->dev->dev, "dma map: ua=%llx, len=%llx, iova=%llx\n", ++ dev_dbg(&fdata->dev->dev, "dma map: ua=%llx, len=%llx, iova=%llx\n", + map.user_addr, map.length, map.iova); + + return 0; +@@ -749,7 +761,7 @@ afu_ioctl_dma_unmap(struct dfl_feature_platform_data *pdata, void __user *arg) + if (unmap.argsz < minsz || unmap.flags) + return -EINVAL; + +- return afu_dma_unmap_region(pdata, unmap.iova); ++ return afu_dma_unmap_region(pdata->fdata, unmap.iova); + } + + static long afu_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +@@ -783,7 +795,7 @@ static long afu_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) + * handled in this sub feature, and returns 0 and other + * error code if cmd is handled. + */ +- dfl_fpga_dev_for_each_feature(pdata, f) ++ dfl_fpga_dev_for_each_feature(pdata->fdata, f) + if (f->ops && f->ops->ioctl) { + ret = f->ops->ioctl(pdev, f, cmd, arg); + if (ret != -ENODEV) +@@ -815,7 +827,8 @@ static int afu_mmap(struct file *filp, struct vm_area_struct *vma) + pdata = dev_get_platdata(&pdev->dev); + + offset = PFN_PHYS(vma->vm_pgoff); +- ret = afu_mmio_region_get_by_offset(pdata, offset, size, ®ion); ++ ret = afu_mmio_region_get_by_offset(pdata->fdata, offset, size, ++ ®ion); + if (ret) + return ret; + +@@ -850,17 +863,18 @@ static const struct file_operations afu_fops = { + static int afu_dev_init(struct platform_device *pdev) + { + struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); ++ struct dfl_feature_dev_data *fdata = pdata->fdata; + struct dfl_afu *afu; + + afu = devm_kzalloc(&pdev->dev, sizeof(*afu), GFP_KERNEL); + if (!afu) + return -ENOMEM; + +- mutex_lock(&pdata->lock); +- dfl_fpga_pdata_set_private(pdata, afu); +- afu_mmio_region_init(pdata); +- afu_dma_region_init(pdata); +- mutex_unlock(&pdata->lock); ++ mutex_lock(&fdata->lock); ++ dfl_fpga_fdata_set_private(fdata, afu); ++ afu_mmio_region_init(fdata); ++ afu_dma_region_init(fdata); ++ mutex_unlock(&fdata->lock); + + return 0; + } +@@ -868,27 +882,27 @@ static int afu_dev_init(struct platform_device *pdev) + static int afu_dev_destroy(struct platform_device *pdev) + { + struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); ++ struct dfl_feature_dev_data *fdata = pdata->fdata; + +- mutex_lock(&pdata->lock); +- afu_mmio_region_destroy(pdata); +- afu_dma_region_destroy(pdata); +- dfl_fpga_pdata_set_private(pdata, NULL); +- mutex_unlock(&pdata->lock); ++ mutex_lock(&fdata->lock); ++ afu_mmio_region_destroy(fdata); ++ afu_dma_region_destroy(fdata); ++ dfl_fpga_fdata_set_private(fdata, NULL); ++ mutex_unlock(&fdata->lock); + + return 0; + } + +-static int port_enable_set(struct platform_device *pdev, bool enable) ++static int port_enable_set(struct dfl_feature_dev_data *fdata, bool enable) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); + int ret; + +- mutex_lock(&pdata->lock); ++ mutex_lock(&fdata->lock); + if (enable) +- ret = __afu_port_enable(pdev); ++ ret = __afu_port_enable(fdata); + else +- ret = __afu_port_disable(pdev); +- mutex_unlock(&pdata->lock); ++ ret = __afu_port_disable(fdata); ++ mutex_unlock(&fdata->lock); + + return ret; + } +diff --git a/drivers/fpga/dfl-afu-region.c b/drivers/fpga/dfl-afu-region.c +index 2e7b41629406..b11a5b21e666 100644 +--- a/drivers/fpga/dfl-afu-region.c ++++ b/drivers/fpga/dfl-afu-region.c +@@ -12,11 +12,11 @@ + + /** + * afu_mmio_region_init - init function for afu mmio region support +- * @pdata: afu platform device's pdata. ++ * @fdata: afu feature dev data + */ +-void afu_mmio_region_init(struct dfl_feature_platform_data *pdata) ++void afu_mmio_region_init(struct dfl_feature_dev_data *fdata) + { +- struct dfl_afu *afu = dfl_fpga_pdata_get_private(pdata); ++ struct dfl_afu *afu = dfl_fpga_fdata_get_private(fdata); + + INIT_LIST_HEAD(&afu->regions); + } +@@ -39,7 +39,7 @@ static struct dfl_afu_mmio_region *get_region_by_index(struct dfl_afu *afu, + /** + * afu_mmio_region_add - add a mmio region to given feature dev. + * +- * @pdata: afu platform device's pdata. ++ * @fdata: afu feature dev data + * @region_index: region index. + * @region_size: region size. + * @phys: region's physical address of this region. +@@ -47,14 +47,15 @@ static struct dfl_afu_mmio_region *get_region_by_index(struct dfl_afu *afu, + * + * Return: 0 on success, negative error code otherwise. + */ +-int afu_mmio_region_add(struct dfl_feature_platform_data *pdata, ++int afu_mmio_region_add(struct dfl_feature_dev_data *fdata, + u32 region_index, u64 region_size, u64 phys, u32 flags) + { ++ struct device *dev = &fdata->dev->dev; + struct dfl_afu_mmio_region *region; + struct dfl_afu *afu; + int ret = 0; + +- region = devm_kzalloc(&pdata->dev->dev, sizeof(*region), GFP_KERNEL); ++ region = devm_kzalloc(dev, sizeof(*region), GFP_KERNEL); + if (!region) + return -ENOMEM; + +@@ -63,13 +64,13 @@ int afu_mmio_region_add(struct dfl_feature_platform_data *pdata, + region->phys = phys; + region->flags = flags; + +- mutex_lock(&pdata->lock); ++ mutex_lock(&fdata->lock); + +- afu = dfl_fpga_pdata_get_private(pdata); ++ afu = dfl_fpga_fdata_get_private(fdata); + + /* check if @index already exists */ + if (get_region_by_index(afu, region_index)) { +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + ret = -EEXIST; + goto exit; + } +@@ -80,37 +81,37 @@ int afu_mmio_region_add(struct dfl_feature_platform_data *pdata, + + afu->region_cur_offset += region_size; + afu->num_regions++; +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + + return 0; + + exit: +- devm_kfree(&pdata->dev->dev, region); ++ devm_kfree(dev, region); + return ret; + } + + /** + * afu_mmio_region_destroy - destroy all mmio regions under given feature dev. +- * @pdata: afu platform device's pdata. ++ * @fdata: afu feature dev data + */ +-void afu_mmio_region_destroy(struct dfl_feature_platform_data *pdata) ++void afu_mmio_region_destroy(struct dfl_feature_dev_data *fdata) + { +- struct dfl_afu *afu = dfl_fpga_pdata_get_private(pdata); ++ struct dfl_afu *afu = dfl_fpga_fdata_get_private(fdata); + struct dfl_afu_mmio_region *tmp, *region; + + list_for_each_entry_safe(region, tmp, &afu->regions, node) +- devm_kfree(&pdata->dev->dev, region); ++ devm_kfree(&fdata->dev->dev, region); + } + + /** + * afu_mmio_region_get_by_index - find an afu region by index. +- * @pdata: afu platform device's pdata. ++ * @fdata: afu feature dev data + * @region_index: region index. + * @pregion: ptr to region for result. + * + * Return: 0 on success, negative error code otherwise. + */ +-int afu_mmio_region_get_by_index(struct dfl_feature_platform_data *pdata, ++int afu_mmio_region_get_by_index(struct dfl_feature_dev_data *fdata, + u32 region_index, + struct dfl_afu_mmio_region *pregion) + { +@@ -118,8 +119,8 @@ int afu_mmio_region_get_by_index(struct dfl_feature_platform_data *pdata, + struct dfl_afu *afu; + int ret = 0; + +- mutex_lock(&pdata->lock); +- afu = dfl_fpga_pdata_get_private(pdata); ++ mutex_lock(&fdata->lock); ++ afu = dfl_fpga_fdata_get_private(fdata); + region = get_region_by_index(afu, region_index); + if (!region) { + ret = -EINVAL; +@@ -127,14 +128,14 @@ int afu_mmio_region_get_by_index(struct dfl_feature_platform_data *pdata, + } + *pregion = *region; + exit: +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + return ret; + } + + /** + * afu_mmio_region_get_by_offset - find an afu mmio region by offset and size + * +- * @pdata: afu platform device's pdata. ++ * @fdata: afu feature dev data + * @offset: region offset from start of the device fd. + * @size: region size. + * @pregion: ptr to region for result. +@@ -144,7 +145,7 @@ int afu_mmio_region_get_by_index(struct dfl_feature_platform_data *pdata, + * + * Return: 0 on success, negative error code otherwise. + */ +-int afu_mmio_region_get_by_offset(struct dfl_feature_platform_data *pdata, ++int afu_mmio_region_get_by_offset(struct dfl_feature_dev_data *fdata, + u64 offset, u64 size, + struct dfl_afu_mmio_region *pregion) + { +@@ -152,8 +153,8 @@ int afu_mmio_region_get_by_offset(struct dfl_feature_platform_data *pdata, + struct dfl_afu *afu; + int ret = 0; + +- mutex_lock(&pdata->lock); +- afu = dfl_fpga_pdata_get_private(pdata); ++ mutex_lock(&fdata->lock); ++ afu = dfl_fpga_fdata_get_private(fdata); + for_each_region(region, afu) + if (region->offset <= offset && + region->offset + region->size >= offset + size) { +@@ -162,6 +163,6 @@ int afu_mmio_region_get_by_offset(struct dfl_feature_platform_data *pdata, + } + ret = -EINVAL; + exit: +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + return ret; + } +diff --git a/drivers/fpga/dfl-afu.h b/drivers/fpga/dfl-afu.h +index 7bef3e300aa2..03be4f0969c7 100644 +--- a/drivers/fpga/dfl-afu.h ++++ b/drivers/fpga/dfl-afu.h +@@ -76,27 +76,27 @@ struct dfl_afu { + struct rb_root dma_regions; + }; + +-/* hold pdata->lock when call __afu_port_enable/disable */ +-int __afu_port_enable(struct platform_device *pdev); +-int __afu_port_disable(struct platform_device *pdev); ++/* hold fdata->lock when call __afu_port_enable/disable */ ++int __afu_port_enable(struct dfl_feature_dev_data *fdata); ++int __afu_port_disable(struct dfl_feature_dev_data *fdata); + +-void afu_mmio_region_init(struct dfl_feature_platform_data *pdata); +-int afu_mmio_region_add(struct dfl_feature_platform_data *pdata, ++void afu_mmio_region_init(struct dfl_feature_dev_data *fdata); ++int afu_mmio_region_add(struct dfl_feature_dev_data *fdata, + u32 region_index, u64 region_size, u64 phys, u32 flags); +-void afu_mmio_region_destroy(struct dfl_feature_platform_data *pdata); +-int afu_mmio_region_get_by_index(struct dfl_feature_platform_data *pdata, ++void afu_mmio_region_destroy(struct dfl_feature_dev_data *fdata); ++int afu_mmio_region_get_by_index(struct dfl_feature_dev_data *fdata, + u32 region_index, + struct dfl_afu_mmio_region *pregion); +-int afu_mmio_region_get_by_offset(struct dfl_feature_platform_data *pdata, ++int afu_mmio_region_get_by_offset(struct dfl_feature_dev_data *fdata, + u64 offset, u64 size, + struct dfl_afu_mmio_region *pregion); +-void afu_dma_region_init(struct dfl_feature_platform_data *pdata); +-void afu_dma_region_destroy(struct dfl_feature_platform_data *pdata); +-int afu_dma_map_region(struct dfl_feature_platform_data *pdata, ++void afu_dma_region_init(struct dfl_feature_dev_data *fdata); ++void afu_dma_region_destroy(struct dfl_feature_dev_data *fdata); ++int afu_dma_map_region(struct dfl_feature_dev_data *fdata, + u64 user_addr, u64 length, u64 *iova); +-int afu_dma_unmap_region(struct dfl_feature_platform_data *pdata, u64 iova); ++int afu_dma_unmap_region(struct dfl_feature_dev_data *fdata, u64 iova); + struct dfl_afu_dma_region * +-afu_dma_region_find(struct dfl_feature_platform_data *pdata, ++afu_dma_region_find(struct dfl_feature_dev_data *fdata, + u64 iova, u64 size); + + extern const struct dfl_feature_ops port_err_ops; +diff --git a/drivers/fpga/dfl-fme-br.c b/drivers/fpga/dfl-fme-br.c +index 808d1f4d76df..fed9bc903f7a 100644 +--- a/drivers/fpga/dfl-fme-br.c ++++ b/drivers/fpga/dfl-fme-br.c +@@ -22,34 +22,34 @@ + struct fme_br_priv { + struct dfl_fme_br_pdata *pdata; + struct dfl_fpga_port_ops *port_ops; +- struct platform_device *port_pdev; ++ struct dfl_feature_dev_data *port_fdata; + }; + + static int fme_bridge_enable_set(struct fpga_bridge *bridge, bool enable) + { + struct fme_br_priv *priv = bridge->priv; +- struct platform_device *port_pdev; ++ struct dfl_feature_dev_data *port_fdata; + struct dfl_fpga_port_ops *ops; + +- if (!priv->port_pdev) { +- port_pdev = dfl_fpga_cdev_find_port(priv->pdata->cdev, +- &priv->pdata->port_id, +- dfl_fpga_check_port_id); +- if (!port_pdev) ++ if (!priv->port_fdata) { ++ port_fdata = dfl_fpga_cdev_find_port_data(priv->pdata->cdev, ++ &priv->pdata->port_id, ++ dfl_fpga_check_port_id); ++ if (!port_fdata) + return -ENODEV; + +- priv->port_pdev = port_pdev; ++ priv->port_fdata = port_fdata; + } + +- if (priv->port_pdev && !priv->port_ops) { +- ops = dfl_fpga_port_ops_get(priv->port_pdev); ++ if (priv->port_fdata && !priv->port_ops) { ++ ops = dfl_fpga_port_ops_get(priv->port_fdata); + if (!ops || !ops->enable_set) + return -ENOENT; + + priv->port_ops = ops; + } + +- return priv->port_ops->enable_set(priv->port_pdev, enable); ++ return priv->port_ops->enable_set(priv->port_fdata, enable); + } + + static const struct fpga_bridge_ops fme_bridge_ops = { +@@ -85,8 +85,6 @@ static int fme_br_remove(struct platform_device *pdev) + + fpga_bridge_unregister(br); + +- if (priv->port_pdev) +- put_device(&priv->port_pdev->dev); + if (priv->port_ops) + dfl_fpga_port_ops_put(priv->port_ops); + +diff --git a/drivers/fpga/dfl-fme-error.c b/drivers/fpga/dfl-fme-error.c +index a570f294ad82..697718a0ceac 100644 +--- a/drivers/fpga/dfl-fme-error.c ++++ b/drivers/fpga/dfl-fme-error.c +@@ -42,15 +42,15 @@ + static ssize_t pcie0_errors_show(struct device *dev, + struct device_attribute *attr, char *buf) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + void __iomem *base; + u64 value; + +- base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); ++ base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR); + +- mutex_lock(&pdata->lock); ++ mutex_lock(&fdata->lock); + value = readq(base + PCIE0_ERROR); +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + + return sysfs_emit(buf, "0x%llx\n", value); + } +@@ -59,7 +59,7 @@ static ssize_t pcie0_errors_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + void __iomem *base; + int ret = 0; + u64 v, val; +@@ -67,9 +67,9 @@ static ssize_t pcie0_errors_store(struct device *dev, + if (kstrtou64(buf, 0, &val)) + return -EINVAL; + +- base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); ++ base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR); + +- mutex_lock(&pdata->lock); ++ mutex_lock(&fdata->lock); + writeq(GENMASK_ULL(63, 0), base + PCIE0_ERROR_MASK); + + v = readq(base + PCIE0_ERROR); +@@ -79,7 +79,7 @@ static ssize_t pcie0_errors_store(struct device *dev, + ret = -EINVAL; + + writeq(0ULL, base + PCIE0_ERROR_MASK); +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + return ret ? ret : count; + } + static DEVICE_ATTR_RW(pcie0_errors); +@@ -87,15 +87,15 @@ static DEVICE_ATTR_RW(pcie0_errors); + static ssize_t pcie1_errors_show(struct device *dev, + struct device_attribute *attr, char *buf) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + void __iomem *base; + u64 value; + +- base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); ++ base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR); + +- mutex_lock(&pdata->lock); ++ mutex_lock(&fdata->lock); + value = readq(base + PCIE1_ERROR); +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + + return sysfs_emit(buf, "0x%llx\n", value); + } +@@ -104,7 +104,7 @@ static ssize_t pcie1_errors_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + void __iomem *base; + int ret = 0; + u64 v, val; +@@ -112,9 +112,9 @@ static ssize_t pcie1_errors_store(struct device *dev, + if (kstrtou64(buf, 0, &val)) + return -EINVAL; + +- base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); ++ base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR); + +- mutex_lock(&pdata->lock); ++ mutex_lock(&fdata->lock); + writeq(GENMASK_ULL(63, 0), base + PCIE1_ERROR_MASK); + + v = readq(base + PCIE1_ERROR); +@@ -124,7 +124,7 @@ static ssize_t pcie1_errors_store(struct device *dev, + ret = -EINVAL; + + writeq(0ULL, base + PCIE1_ERROR_MASK); +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + return ret ? ret : count; + } + static DEVICE_ATTR_RW(pcie1_errors); +@@ -132,9 +132,10 @@ static DEVICE_ATTR_RW(pcie1_errors); + static ssize_t nonfatal_errors_show(struct device *dev, + struct device_attribute *attr, char *buf) + { ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + void __iomem *base; + +- base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); ++ base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR); + + return sysfs_emit(buf, "0x%llx\n", readq(base + RAS_NONFAT_ERROR)); + } +@@ -143,9 +144,10 @@ static DEVICE_ATTR_RO(nonfatal_errors); + static ssize_t catfatal_errors_show(struct device *dev, + struct device_attribute *attr, char *buf) + { ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + void __iomem *base; + +- base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); ++ base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR); + + return sysfs_emit(buf, "0x%llx\n", readq(base + RAS_CATFAT_ERROR)); + } +@@ -154,15 +156,15 @@ static DEVICE_ATTR_RO(catfatal_errors); + static ssize_t inject_errors_show(struct device *dev, + struct device_attribute *attr, char *buf) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + void __iomem *base; + u64 v; + +- base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); ++ base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR); + +- mutex_lock(&pdata->lock); ++ mutex_lock(&fdata->lock); + v = readq(base + RAS_ERROR_INJECT); +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + + return sysfs_emit(buf, "0x%llx\n", FIELD_GET(INJECT_ERROR_MASK, v)); + } +@@ -171,7 +173,7 @@ static ssize_t inject_errors_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + void __iomem *base; + u8 inject_error; + u64 v; +@@ -182,14 +184,14 @@ static ssize_t inject_errors_store(struct device *dev, + if (inject_error & ~INJECT_ERROR_MASK) + return -EINVAL; + +- base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); ++ base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR); + +- mutex_lock(&pdata->lock); ++ mutex_lock(&fdata->lock); + v = readq(base + RAS_ERROR_INJECT); + v &= ~INJECT_ERROR_MASK; + v |= FIELD_PREP(INJECT_ERROR_MASK, inject_error); + writeq(v, base + RAS_ERROR_INJECT); +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + + return count; + } +@@ -198,15 +200,15 @@ static DEVICE_ATTR_RW(inject_errors); + static ssize_t fme_errors_show(struct device *dev, + struct device_attribute *attr, char *buf) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + void __iomem *base; + u64 value; + +- base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); ++ base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR); + +- mutex_lock(&pdata->lock); ++ mutex_lock(&fdata->lock); + value = readq(base + FME_ERROR); +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + + return sysfs_emit(buf, "0x%llx\n", value); + } +@@ -215,7 +217,7 @@ static ssize_t fme_errors_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + void __iomem *base; + u64 v, val; + int ret = 0; +@@ -223,9 +225,9 @@ static ssize_t fme_errors_store(struct device *dev, + if (kstrtou64(buf, 0, &val)) + return -EINVAL; + +- base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); ++ base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR); + +- mutex_lock(&pdata->lock); ++ mutex_lock(&fdata->lock); + writeq(GENMASK_ULL(63, 0), base + FME_ERROR_MASK); + + v = readq(base + FME_ERROR); +@@ -237,7 +239,7 @@ static ssize_t fme_errors_store(struct device *dev, + /* Workaround: disable MBP_ERROR if feature revision is 0 */ + writeq(dfl_feature_revision(base) ? 0ULL : MBP_ERROR, + base + FME_ERROR_MASK); +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + return ret ? ret : count; + } + static DEVICE_ATTR_RW(fme_errors); +@@ -245,15 +247,15 @@ static DEVICE_ATTR_RW(fme_errors); + static ssize_t first_error_show(struct device *dev, + struct device_attribute *attr, char *buf) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + void __iomem *base; + u64 value; + +- base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); ++ base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR); + +- mutex_lock(&pdata->lock); ++ mutex_lock(&fdata->lock); + value = readq(base + FME_FIRST_ERROR); +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + + return sysfs_emit(buf, "0x%llx\n", value); + } +@@ -262,15 +264,15 @@ static DEVICE_ATTR_RO(first_error); + static ssize_t next_error_show(struct device *dev, + struct device_attribute *attr, char *buf) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + void __iomem *base; + u64 value; + +- base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); ++ base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR); + +- mutex_lock(&pdata->lock); ++ mutex_lock(&fdata->lock); + value = readq(base + FME_NEXT_ERROR); +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + + return sysfs_emit(buf, "0x%llx\n", value); + } +@@ -292,12 +294,14 @@ static umode_t fme_global_err_attrs_visible(struct kobject *kobj, + struct attribute *attr, int n) + { + struct device *dev = kobj_to_dev(kobj); ++ struct dfl_feature_dev_data *fdata; + ++ fdata = to_dfl_feature_dev_data(dev); + /* + * sysfs entries are visible only if related private feature is + * enumerated. + */ +- if (!dfl_get_feature_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR)) ++ if (!dfl_get_feature_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR)) + return 0; + + return attr->mode; +@@ -311,12 +315,12 @@ const struct attribute_group fme_global_err_group = { + + static void fme_err_mask(struct device *dev, bool mask) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + void __iomem *base; + +- base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_GLOBAL_ERR); ++ base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR); + +- mutex_lock(&pdata->lock); ++ mutex_lock(&fdata->lock); + + /* Workaround: keep MBP_ERROR always masked if revision is 0 */ + if (dfl_feature_revision(base)) +@@ -329,7 +333,7 @@ static void fme_err_mask(struct device *dev, bool mask) + writeq(mask ? ERROR_MASK : 0, base + RAS_NONFAT_ERROR_MASK); + writeq(mask ? ERROR_MASK : 0, base + RAS_CATFAT_ERROR_MASK); + +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + } + + static int fme_global_err_init(struct platform_device *pdev, +diff --git a/drivers/fpga/dfl-fme-main.c b/drivers/fpga/dfl-fme-main.c +index 504febcc7c4d..740671ad288b 100644 +--- a/drivers/fpga/dfl-fme-main.c ++++ b/drivers/fpga/dfl-fme-main.c +@@ -28,10 +28,11 @@ + static ssize_t ports_num_show(struct device *dev, + struct device_attribute *attr, char *buf) + { ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + void __iomem *base; + u64 v; + +- base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER); ++ base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_HEADER); + + v = readq(base + FME_HDR_CAP); + +@@ -46,10 +47,11 @@ static DEVICE_ATTR_RO(ports_num); + static ssize_t bitstream_id_show(struct device *dev, + struct device_attribute *attr, char *buf) + { ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + void __iomem *base; + u64 v; + +- base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER); ++ base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_HEADER); + + v = readq(base + FME_HDR_BITSTREAM_ID); + +@@ -64,10 +66,11 @@ static DEVICE_ATTR_RO(bitstream_id); + static ssize_t bitstream_metadata_show(struct device *dev, + struct device_attribute *attr, char *buf) + { ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + void __iomem *base; + u64 v; + +- base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER); ++ base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_HEADER); + + v = readq(base + FME_HDR_BITSTREAM_MD); + +@@ -78,10 +81,11 @@ static DEVICE_ATTR_RO(bitstream_metadata); + static ssize_t cache_size_show(struct device *dev, + struct device_attribute *attr, char *buf) + { ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + void __iomem *base; + u64 v; + +- base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER); ++ base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_HEADER); + + v = readq(base + FME_HDR_CAP); + +@@ -92,10 +96,11 @@ static DEVICE_ATTR_RO(cache_size); + static ssize_t fabric_version_show(struct device *dev, + struct device_attribute *attr, char *buf) + { ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + void __iomem *base; + u64 v; + +- base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER); ++ base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_HEADER); + + v = readq(base + FME_HDR_CAP); + +@@ -106,10 +111,11 @@ static DEVICE_ATTR_RO(fabric_version); + static ssize_t socket_id_show(struct device *dev, + struct device_attribute *attr, char *buf) + { ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + void __iomem *base; + u64 v; + +- base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER); ++ base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_HEADER); + + v = readq(base + FME_HDR_CAP); + +@@ -134,7 +140,7 @@ static const struct attribute_group fme_hdr_group = { + static long fme_hdr_ioctl_release_port(struct dfl_feature_platform_data *pdata, + unsigned long arg) + { +- struct dfl_fpga_cdev *cdev = pdata->dfl_cdev; ++ struct dfl_fpga_cdev *cdev = pdata->fdata->dfl_cdev; + int port_id; + + if (get_user(port_id, (int __user *)arg)) +@@ -146,7 +152,7 @@ static long fme_hdr_ioctl_release_port(struct dfl_feature_platform_data *pdata, + static long fme_hdr_ioctl_assign_port(struct dfl_feature_platform_data *pdata, + unsigned long arg) + { +- struct dfl_fpga_cdev *cdev = pdata->dfl_cdev; ++ struct dfl_fpga_cdev *cdev = pdata->fdata->dfl_cdev; + int port_id; + + if (get_user(port_id, (int __user *)arg)) +@@ -406,14 +412,14 @@ static int power_hwmon_read(struct device *dev, enum hwmon_sensor_types type, + static int power_hwmon_write(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long val) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(dev->parent); ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + struct dfl_feature *feature = dev_get_drvdata(dev); + int ret = 0; + u64 v; + + val = clamp_val(val / MICRO, 0, PWR_THRESHOLD_MAX); + +- mutex_lock(&pdata->lock); ++ mutex_lock(&fdata->lock); + + switch (attr) { + case hwmon_power_max: +@@ -433,7 +439,7 @@ static int power_hwmon_write(struct device *dev, enum hwmon_sensor_types type, + break; + } + +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + + return ret; + } +@@ -594,19 +600,21 @@ static int fme_open(struct inode *inode, struct file *filp) + { + struct platform_device *fdev = dfl_fpga_inode_to_feature_dev(inode); + struct dfl_feature_platform_data *pdata = dev_get_platdata(&fdev->dev); ++ struct dfl_feature_dev_data *fdata; + int ret; + + if (WARN_ON(!pdata)) + return -ENODEV; + +- mutex_lock(&pdata->lock); +- ret = dfl_feature_dev_use_begin(pdata, filp->f_flags & O_EXCL); ++ fdata = pdata->fdata; ++ mutex_lock(&fdata->lock); ++ ret = dfl_feature_dev_use_begin(fdata, filp->f_flags & O_EXCL); + if (!ret) { + dev_dbg(&fdev->dev, "Device File Opened %d Times\n", +- dfl_feature_dev_use_count(pdata)); ++ dfl_feature_dev_use_count(fdata)); + filp->private_data = pdata; + } +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + + return ret; + } +@@ -614,19 +622,20 @@ static int fme_open(struct inode *inode, struct file *filp) + static int fme_release(struct inode *inode, struct file *filp) + { + struct dfl_feature_platform_data *pdata = filp->private_data; +- struct platform_device *pdev = pdata->dev; ++ struct dfl_feature_dev_data *fdata = pdata->fdata; ++ struct platform_device *pdev = fdata->dev; + struct dfl_feature *feature; + + dev_dbg(&pdev->dev, "Device File Release\n"); + +- mutex_lock(&pdata->lock); +- dfl_feature_dev_use_end(pdata); ++ mutex_lock(&fdata->lock); ++ dfl_feature_dev_use_end(fdata); + +- if (!dfl_feature_dev_use_count(pdata)) +- dfl_fpga_dev_for_each_feature(pdata, feature) ++ if (!dfl_feature_dev_use_count(fdata)) ++ dfl_fpga_dev_for_each_feature(fdata, feature) + dfl_fpga_set_irq_triggers(feature, 0, + feature->nr_irqs, NULL); +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + + return 0; + } +@@ -634,7 +643,8 @@ static int fme_release(struct inode *inode, struct file *filp) + static long fme_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) + { + struct dfl_feature_platform_data *pdata = filp->private_data; +- struct platform_device *pdev = pdata->dev; ++ struct dfl_feature_dev_data *fdata = pdata->fdata; ++ struct platform_device *pdev = fdata->dev; + struct dfl_feature *f; + long ret; + +@@ -652,7 +662,7 @@ static long fme_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) + * handled in this sub feature, and returns 0 or other + * error code if cmd is handled. + */ +- dfl_fpga_dev_for_each_feature(pdata, f) { ++ dfl_fpga_dev_for_each_feature(fdata, f) { + if (f->ops && f->ops->ioctl) { + ret = f->ops->ioctl(pdev, f, cmd, arg); + if (ret != -ENODEV) +@@ -667,6 +677,7 @@ static long fme_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) + static int fme_dev_init(struct platform_device *pdev) + { + struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); ++ struct dfl_feature_dev_data *fdata = pdata->fdata; + struct dfl_fme *fme; + + fme = devm_kzalloc(&pdev->dev, sizeof(*fme), GFP_KERNEL); +@@ -675,9 +686,9 @@ static int fme_dev_init(struct platform_device *pdev) + + fme->pdata = pdata; + +- mutex_lock(&pdata->lock); +- dfl_fpga_pdata_set_private(pdata, fme); +- mutex_unlock(&pdata->lock); ++ mutex_lock(&fdata->lock); ++ dfl_fpga_fdata_set_private(fdata, fme); ++ mutex_unlock(&fdata->lock); + + return 0; + } +@@ -685,10 +696,11 @@ static int fme_dev_init(struct platform_device *pdev) + static void fme_dev_destroy(struct platform_device *pdev) + { + struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); ++ struct dfl_feature_dev_data *fdata = pdata->fdata; + +- mutex_lock(&pdata->lock); +- dfl_fpga_pdata_set_private(pdata, NULL); +- mutex_unlock(&pdata->lock); ++ mutex_lock(&fdata->lock); ++ dfl_fpga_fdata_set_private(fdata, NULL); ++ mutex_unlock(&fdata->lock); + } + + static const struct file_operations fme_fops = { +diff --git a/drivers/fpga/dfl-fme-pr.c b/drivers/fpga/dfl-fme-pr.c +index cdcf6dea4cc9..2932d203a045 100644 +--- a/drivers/fpga/dfl-fme-pr.c ++++ b/drivers/fpga/dfl-fme-pr.c +@@ -65,7 +65,7 @@ static struct fpga_region *dfl_fme_region_find(struct dfl_fme *fme, int port_id) + + static int fme_pr(struct platform_device *pdev, unsigned long arg) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(&pdev->dev); + void __user *argp = (void __user *)arg; + struct dfl_fpga_fme_port_pr port_pr; + struct fpga_image_info *info; +@@ -87,8 +87,7 @@ static int fme_pr(struct platform_device *pdev, unsigned long arg) + return -EINVAL; + + /* get fme header region */ +- fme_hdr = dfl_get_feature_ioaddr_by_id(&pdev->dev, +- FME_FEATURE_ID_HEADER); ++ fme_hdr = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_HEADER); + + /* check port id */ + v = readq(fme_hdr + FME_HDR_CAP); +@@ -123,8 +122,8 @@ static int fme_pr(struct platform_device *pdev, unsigned long arg) + + info->flags |= FPGA_MGR_PARTIAL_RECONFIG; + +- mutex_lock(&pdata->lock); +- fme = dfl_fpga_pdata_get_private(pdata); ++ mutex_lock(&fdata->lock); ++ fme = dfl_fpga_fdata_get_private(fdata); + /* fme device has been unregistered. */ + if (!fme) { + ret = -EINVAL; +@@ -156,7 +155,7 @@ static int fme_pr(struct platform_device *pdev, unsigned long arg) + + put_device(®ion->dev); + unlock_exit: +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + free_exit: + vfree(buf); + return ret; +@@ -170,10 +169,10 @@ static int fme_pr(struct platform_device *pdev, unsigned long arg) + * Return: mgr platform device if successful, and error code otherwise. + */ + static struct platform_device * +-dfl_fme_create_mgr(struct dfl_feature_platform_data *pdata, ++dfl_fme_create_mgr(struct dfl_feature_dev_data *fdata, + struct dfl_feature *feature) + { +- struct platform_device *mgr, *fme = pdata->dev; ++ struct platform_device *mgr, *fme = fdata->dev; + struct dfl_fme_mgr_pdata mgr_pdata; + int ret = -ENOMEM; + +@@ -211,9 +210,9 @@ dfl_fme_create_mgr(struct dfl_feature_platform_data *pdata, + * dfl_fme_destroy_mgr - destroy fpga mgr platform device + * @pdata: fme platform device's pdata + */ +-static void dfl_fme_destroy_mgr(struct dfl_feature_platform_data *pdata) ++static void dfl_fme_destroy_mgr(struct dfl_feature_dev_data *fdata) + { +- struct dfl_fme *priv = dfl_fpga_pdata_get_private(pdata); ++ struct dfl_fme *priv = dfl_fpga_fdata_get_private(fdata); + + platform_device_unregister(priv->mgr); + } +@@ -221,15 +220,15 @@ static void dfl_fme_destroy_mgr(struct dfl_feature_platform_data *pdata) + /** + * dfl_fme_create_bridge - create fme fpga bridge platform device as child + * +- * @pdata: fme platform device's pdata ++ * @fdata: fme feature dev data + * @port_id: port id for the bridge to be created. + * + * Return: bridge platform device if successful, and error code otherwise. + */ + static struct dfl_fme_bridge * +-dfl_fme_create_bridge(struct dfl_feature_platform_data *pdata, int port_id) ++dfl_fme_create_bridge(struct dfl_feature_dev_data *fdata, int port_id) + { +- struct device *dev = &pdata->dev->dev; ++ struct device *dev = &fdata->dev->dev; + struct dfl_fme_br_pdata br_pdata; + struct dfl_fme_bridge *fme_br; + int ret = -ENOMEM; +@@ -238,7 +237,7 @@ dfl_fme_create_bridge(struct dfl_feature_platform_data *pdata, int port_id) + if (!fme_br) + return ERR_PTR(ret); + +- br_pdata.cdev = pdata->dfl_cdev; ++ br_pdata.cdev = fdata->dfl_cdev; + br_pdata.port_id = port_id; + + fme_br->br = platform_device_alloc(DFL_FPGA_FME_BRIDGE, +@@ -274,11 +273,11 @@ static void dfl_fme_destroy_bridge(struct dfl_fme_bridge *fme_br) + + /** + * dfl_fme_destroy_bridges - destroy all fpga bridge platform device +- * @pdata: fme platform device's pdata ++ * @fdata: fme feature dev data + */ +-static void dfl_fme_destroy_bridges(struct dfl_feature_platform_data *pdata) ++static void dfl_fme_destroy_bridges(struct dfl_feature_dev_data *fdata) + { +- struct dfl_fme *priv = dfl_fpga_pdata_get_private(pdata); ++ struct dfl_fme *priv = dfl_fpga_fdata_get_private(fdata); + struct dfl_fme_bridge *fbridge, *tmp; + + list_for_each_entry_safe(fbridge, tmp, &priv->bridge_list, node) { +@@ -290,7 +289,7 @@ static void dfl_fme_destroy_bridges(struct dfl_feature_platform_data *pdata) + /** + * dfl_fme_create_region - create fpga region platform device as child + * +- * @pdata: fme platform device's pdata ++ * @fdata: fme feature dev data + * @mgr: mgr platform device needed for region + * @br: br platform device needed for region + * @port_id: port id +@@ -298,12 +297,12 @@ static void dfl_fme_destroy_bridges(struct dfl_feature_platform_data *pdata) + * Return: fme region if successful, and error code otherwise. + */ + static struct dfl_fme_region * +-dfl_fme_create_region(struct dfl_feature_platform_data *pdata, ++dfl_fme_create_region(struct dfl_feature_dev_data *fdata, + struct platform_device *mgr, + struct platform_device *br, int port_id) + { + struct dfl_fme_region_pdata region_pdata; +- struct device *dev = &pdata->dev->dev; ++ struct device *dev = &fdata->dev->dev; + struct dfl_fme_region *fme_region; + int ret = -ENOMEM; + +@@ -353,11 +352,11 @@ static void dfl_fme_destroy_region(struct dfl_fme_region *fme_region) + + /** + * dfl_fme_destroy_regions - destroy all fme regions +- * @pdata: fme platform device's pdata ++ * @fdata: fme feature dev data + */ +-static void dfl_fme_destroy_regions(struct dfl_feature_platform_data *pdata) ++static void dfl_fme_destroy_regions(struct dfl_feature_dev_data *fdata) + { +- struct dfl_fme *priv = dfl_fpga_pdata_get_private(pdata); ++ struct dfl_fme *priv = dfl_fpga_fdata_get_private(fdata); + struct dfl_fme_region *fme_region, *tmp; + + list_for_each_entry_safe(fme_region, tmp, &priv->region_list, node) { +@@ -369,7 +368,8 @@ static void dfl_fme_destroy_regions(struct dfl_feature_platform_data *pdata) + static int pr_mgmt_init(struct platform_device *pdev, + struct dfl_feature *feature) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); ++ struct dfl_feature_dev_data *fdata = ++ to_dfl_feature_dev_data(&pdev->dev); + struct dfl_fme_region *fme_region; + struct dfl_fme_bridge *fme_br; + struct platform_device *mgr; +@@ -378,18 +378,17 @@ static int pr_mgmt_init(struct platform_device *pdev, + int ret = -ENODEV, i = 0; + u64 fme_cap, port_offset; + +- fme_hdr = dfl_get_feature_ioaddr_by_id(&pdev->dev, +- FME_FEATURE_ID_HEADER); ++ fme_hdr = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_HEADER); + +- mutex_lock(&pdata->lock); +- priv = dfl_fpga_pdata_get_private(pdata); ++ mutex_lock(&fdata->lock); ++ priv = dfl_fpga_fdata_get_private(fdata); + + /* Initialize the region and bridge sub device list */ + INIT_LIST_HEAD(&priv->region_list); + INIT_LIST_HEAD(&priv->bridge_list); + + /* Create fpga mgr platform device */ +- mgr = dfl_fme_create_mgr(pdata, feature); ++ mgr = dfl_fme_create_mgr(fdata, feature); + if (IS_ERR(mgr)) { + dev_err(&pdev->dev, "fail to create fpga mgr pdev\n"); + goto unlock; +@@ -405,7 +404,7 @@ static int pr_mgmt_init(struct platform_device *pdev, + continue; + + /* Create bridge for each port */ +- fme_br = dfl_fme_create_bridge(pdata, i); ++ fme_br = dfl_fme_create_bridge(fdata, i); + if (IS_ERR(fme_br)) { + ret = PTR_ERR(fme_br); + goto destroy_region; +@@ -414,7 +413,7 @@ static int pr_mgmt_init(struct platform_device *pdev, + list_add(&fme_br->node, &priv->bridge_list); + + /* Create region for each port */ +- fme_region = dfl_fme_create_region(pdata, mgr, ++ fme_region = dfl_fme_create_region(fdata, mgr, + fme_br->br, i); + if (IS_ERR(fme_region)) { + ret = PTR_ERR(fme_region); +@@ -423,30 +422,31 @@ static int pr_mgmt_init(struct platform_device *pdev, + + list_add(&fme_region->node, &priv->region_list); + } +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + + return 0; + + destroy_region: +- dfl_fme_destroy_regions(pdata); +- dfl_fme_destroy_bridges(pdata); +- dfl_fme_destroy_mgr(pdata); ++ dfl_fme_destroy_regions(fdata); ++ dfl_fme_destroy_bridges(fdata); ++ dfl_fme_destroy_mgr(fdata); + unlock: +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + return ret; + } + + static void pr_mgmt_uinit(struct platform_device *pdev, + struct dfl_feature *feature) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); ++ struct dfl_feature_dev_data *fdata = ++ to_dfl_feature_dev_data(&pdev->dev); + +- mutex_lock(&pdata->lock); ++ mutex_lock(&fdata->lock); + +- dfl_fme_destroy_regions(pdata); +- dfl_fme_destroy_bridges(pdata); +- dfl_fme_destroy_mgr(pdata); +- mutex_unlock(&pdata->lock); ++ dfl_fme_destroy_regions(fdata); ++ dfl_fme_destroy_bridges(fdata); ++ dfl_fme_destroy_mgr(fdata); ++ mutex_unlock(&fdata->lock); + } + + static long fme_pr_ioctl(struct platform_device *pdev, +diff --git a/drivers/fpga/dfl.c b/drivers/fpga/dfl.c +index 684db4379d58..dca7fea5960e 100644 +--- a/drivers/fpga/dfl.c ++++ b/drivers/fpga/dfl.c +@@ -119,17 +119,6 @@ static void dfl_id_free(enum dfl_id_type type, int id) + mutex_unlock(&dfl_id_mutex); + } + +-static enum dfl_id_type feature_dev_id_type(struct platform_device *pdev) +-{ +- int i; +- +- for (i = 0; i < ARRAY_SIZE(dfl_devs); i++) +- if (!strcmp(dfl_devs[i].name, pdev->name)) +- return i; +- +- return DFL_ID_MAX; +-} +- + static enum dfl_id_type dfh_id_to_type(u16 id) + { + int i; +@@ -161,7 +150,8 @@ static LIST_HEAD(dfl_port_ops_list); + * + * Please note that must dfl_fpga_port_ops_put after use the port_ops. + */ +-struct dfl_fpga_port_ops *dfl_fpga_port_ops_get(struct platform_device *pdev) ++struct dfl_fpga_port_ops * ++dfl_fpga_port_ops_get(struct dfl_feature_dev_data *fdata) + { + struct dfl_fpga_port_ops *ops = NULL; + +@@ -171,7 +161,7 @@ struct dfl_fpga_port_ops *dfl_fpga_port_ops_get(struct platform_device *pdev) + + list_for_each_entry(ops, &dfl_port_ops_list, node) { + /* match port_ops using the name of platform device */ +- if (!strcmp(pdev->name, ops->name)) { ++ if (!strcmp(fdata->pdev_name, ops->name)) { + if (!try_module_get(ops->owner)) + ops = NULL; + goto done; +@@ -227,22 +217,21 @@ EXPORT_SYMBOL_GPL(dfl_fpga_port_ops_del); + * + * Return: 1 if port device matches with given port id, otherwise 0. + */ +-int dfl_fpga_check_port_id(struct platform_device *pdev, void *pport_id) ++int dfl_fpga_check_port_id(struct dfl_feature_dev_data *fdata, void *pport_id) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); + struct dfl_fpga_port_ops *port_ops; + +- if (pdata->id != FEATURE_DEV_ID_UNUSED) +- return pdata->id == *(int *)pport_id; ++ if (fdata->id != FEATURE_DEV_ID_UNUSED) ++ return fdata->id == *(int *)pport_id; + +- port_ops = dfl_fpga_port_ops_get(pdev); ++ port_ops = dfl_fpga_port_ops_get(fdata); + if (!port_ops || !port_ops->get_id) + return 0; + +- pdata->id = port_ops->get_id(pdev); ++ fdata->id = port_ops->get_id(fdata); + dfl_fpga_port_ops_put(port_ops); + +- return pdata->id == *(int *)pport_id; ++ return fdata->id == *(int *)pport_id; + } + EXPORT_SYMBOL_GPL(dfl_fpga_check_port_id); + +@@ -372,10 +361,10 @@ static void release_dfl_dev(struct device *dev) + } + + static struct dfl_device * +-dfl_dev_add(struct dfl_feature_platform_data *pdata, ++dfl_dev_add(struct dfl_feature_dev_data *fdata, + struct dfl_feature *feature) + { +- struct platform_device *pdev = pdata->dev; ++ struct platform_device *pdev = fdata->dev; + struct resource *parent_res; + struct dfl_device *ddev; + int id, i, ret; +@@ -401,11 +390,11 @@ dfl_dev_add(struct dfl_feature_platform_data *pdata, + if (ret) + goto put_dev; + +- ddev->type = feature_dev_id_type(pdev); ++ ddev->type = fdata->type; + ddev->feature_id = feature->id; + ddev->revision = feature->revision; + ddev->dfh_version = feature->dfh_version; +- ddev->cdev = pdata->dfl_cdev; ++ ddev->cdev = fdata->dfl_cdev; + if (feature->param_size) { + ddev->params = kmemdup(feature->params, feature->param_size, GFP_KERNEL); + if (!ddev->params) { +@@ -459,11 +448,11 @@ dfl_dev_add(struct dfl_feature_platform_data *pdata, + return ERR_PTR(ret); + } + +-static void dfl_devs_remove(struct dfl_feature_platform_data *pdata) ++static void dfl_devs_remove(struct dfl_feature_dev_data *fdata) + { + struct dfl_feature *feature; + +- dfl_fpga_dev_for_each_feature(pdata, feature) { ++ dfl_fpga_dev_for_each_feature(fdata, feature) { + if (feature->ddev) { + device_unregister(&feature->ddev->dev); + feature->ddev = NULL; +@@ -471,13 +460,13 @@ static void dfl_devs_remove(struct dfl_feature_platform_data *pdata) + } + } + +-static int dfl_devs_add(struct dfl_feature_platform_data *pdata) ++static int dfl_devs_add(struct dfl_feature_dev_data *fdata) + { + struct dfl_feature *feature; + struct dfl_device *ddev; + int ret; + +- dfl_fpga_dev_for_each_feature(pdata, feature) { ++ dfl_fpga_dev_for_each_feature(fdata, feature) { + if (feature->ioaddr) + continue; + +@@ -486,7 +475,7 @@ static int dfl_devs_add(struct dfl_feature_platform_data *pdata) + goto err; + } + +- ddev = dfl_dev_add(pdata, feature); ++ ddev = dfl_dev_add(fdata, feature); + if (IS_ERR(ddev)) { + ret = PTR_ERR(ddev); + goto err; +@@ -498,7 +487,7 @@ static int dfl_devs_add(struct dfl_feature_platform_data *pdata) + return 0; + + err: +- dfl_devs_remove(pdata); ++ dfl_devs_remove(fdata); + return ret; + } + +@@ -529,11 +518,12 @@ EXPORT_SYMBOL(dfl_driver_unregister); + void dfl_fpga_dev_feature_uinit(struct platform_device *pdev) + { + struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); ++ struct dfl_feature_dev_data *fdata = pdata->fdata; + struct dfl_feature *feature; + +- dfl_devs_remove(pdata); ++ dfl_devs_remove(fdata); + +- dfl_fpga_dev_for_each_feature(pdata, feature) { ++ dfl_fpga_dev_for_each_feature(fdata, feature) { + if (feature->ops) { + if (feature->ops->uinit) + feature->ops->uinit(pdev, feature); +@@ -606,12 +596,13 @@ int dfl_fpga_dev_feature_init(struct platform_device *pdev, + struct dfl_feature_driver *feature_drvs) + { + struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); ++ struct dfl_feature_dev_data *fdata = pdata->fdata; + struct dfl_feature_driver *drv = feature_drvs; + struct dfl_feature *feature; + int ret; + + while (drv->ops) { +- dfl_fpga_dev_for_each_feature(pdata, feature) { ++ dfl_fpga_dev_for_each_feature(fdata, feature) { + if (dfl_feature_drv_match(feature, drv)) { + ret = dfl_feature_instance_init(pdev, pdata, + feature, drv); +@@ -622,7 +613,7 @@ int dfl_fpga_dev_feature_init(struct platform_device *pdev, + drv++; + } + +- ret = dfl_devs_add(pdata); ++ ret = dfl_devs_add(fdata); + if (ret) + goto exit; + +@@ -721,7 +712,7 @@ EXPORT_SYMBOL_GPL(dfl_fpga_dev_ops_unregister); + * @nr_irqs: number of irqs for all feature devices. + * @irq_table: Linux IRQ numbers for all irqs, indexed by local irq index of + * this device. +- * @feature_dev: current feature device. ++ * @type: the current FIU type. + * @ioaddr: header register region address of current FIU in enumeration. + * @start: register resource start of current FIU. + * @len: max register resource length of current FIU. +@@ -734,7 +725,7 @@ struct build_feature_devs_info { + unsigned int nr_irqs; + int *irq_table; + +- struct platform_device *feature_dev; ++ enum dfl_id_type type; + void __iomem *ioaddr; + resource_size_t start; + resource_size_t len; +@@ -771,50 +762,51 @@ struct dfl_feature_info { + u64 params[]; + }; + +-static void dfl_fpga_cdev_add_port_dev(struct dfl_fpga_cdev *cdev, +- struct platform_device *port) ++static void dfl_fpga_cdev_add_port_data(struct dfl_fpga_cdev *cdev, ++ struct dfl_feature_dev_data *fdata) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(&port->dev); +- + mutex_lock(&cdev->lock); +- list_add(&pdata->node, &cdev->port_dev_list); +- get_device(&pdata->dev->dev); ++ list_add(&fdata->node, &cdev->port_dev_list); + mutex_unlock(&cdev->lock); + } + +-/* +- * register current feature device, it is called when we need to switch to +- * another feature parsing or we have parsed all features on given device +- * feature list. +- */ +-static int build_info_commit_dev(struct build_feature_devs_info *binfo) ++static struct dfl_feature_dev_data * ++binfo_create_feature_dev_data(struct build_feature_devs_info *binfo) + { +- struct platform_device *fdev = binfo->feature_dev; +- struct dfl_feature_platform_data *pdata; ++ enum dfl_id_type type = binfo->type; + struct dfl_feature_info *finfo, *p; +- enum dfl_id_type type; ++ struct dfl_feature_dev_data *fdata; + int ret, index = 0, res_idx = 0; + +- type = feature_dev_id_type(fdev); + if (WARN_ON_ONCE(type >= DFL_ID_MAX)) +- return -EINVAL; ++ return ERR_PTR(-EINVAL); + +- /* +- * we do not need to care for the memory which is associated with +- * the platform device. After calling platform_device_unregister(), +- * it will be automatically freed by device's release() callback, +- * platform_device_release(). +- */ +- pdata = kzalloc(struct_size(pdata, features, binfo->feature_num), GFP_KERNEL); +- if (!pdata) +- return -ENOMEM; ++ fdata = devm_kzalloc(binfo->dev, sizeof(*fdata), GFP_KERNEL); ++ if (!fdata) ++ return ERR_PTR(-ENOMEM); ++ ++ fdata->features = devm_kcalloc(binfo->dev, binfo->feature_num, ++ sizeof(*fdata->features), GFP_KERNEL); ++ if (!fdata->features) ++ return ERR_PTR(-ENOMEM); ++ ++ fdata->resources = devm_kcalloc(binfo->dev, binfo->feature_num, ++ sizeof(*fdata->resources), GFP_KERNEL); ++ if (!fdata->resources) ++ return ERR_PTR(-ENOMEM); ++ ++ fdata->type = type; ++ ++ fdata->pdev_id = dfl_id_alloc(type, binfo->dev); ++ if (fdata->pdev_id < 0) ++ return ERR_PTR(fdata->pdev_id); + +- pdata->dev = fdev; +- pdata->num = binfo->feature_num; +- pdata->dfl_cdev = binfo->cdev; +- pdata->id = FEATURE_DEV_ID_UNUSED; +- mutex_init(&pdata->lock); +- lockdep_set_class_and_name(&pdata->lock, &dfl_pdata_keys[type], ++ fdata->pdev_name = dfl_devs[type].name; ++ 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]); + + /* +@@ -823,25 +815,15 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo) + * works properly for port device. + * and it should always be 0 for fme device. + */ +- WARN_ON(pdata->disable_count); +- +- fdev->dev.platform_data = pdata; +- +- /* each sub feature has one MMIO resource */ +- fdev->num_resources = binfo->feature_num; +- fdev->resource = kcalloc(binfo->feature_num, sizeof(*fdev->resource), +- GFP_KERNEL); +- if (!fdev->resource) +- return -ENOMEM; ++ WARN_ON(fdata->disable_count); + + /* fill features and resource information for feature dev */ + list_for_each_entry_safe(finfo, p, &binfo->sub_features, node) { +- struct dfl_feature *feature = &pdata->features[index++]; ++ struct dfl_feature *feature = &fdata->features[index++]; + struct dfl_feature_irq_ctx *ctx; + unsigned int i; + + /* save resource information for each feature */ +- feature->dev = fdev; + feature->id = finfo->fid; + feature->revision = finfo->revision; + feature->dfh_version = finfo->dfh_version; +@@ -851,7 +833,7 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo) + finfo->params, finfo->param_size, + GFP_KERNEL); + if (!feature->params) +- return -ENOMEM; ++ return ERR_PTR(-ENOMEM); + + feature->param_size = finfo->param_size; + } +@@ -869,19 +851,22 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo) + feature->ioaddr = + devm_ioremap_resource(binfo->dev, + &finfo->mmio_res); +- if (IS_ERR(feature->ioaddr)) +- return PTR_ERR(feature->ioaddr); ++ if (IS_ERR(feature->ioaddr)) { ++ ret = PTR_ERR(feature->ioaddr); ++ goto err_free_id; ++ } + } else { + feature->resource_index = res_idx; +- fdev->resource[res_idx++] = finfo->mmio_res; ++ fdata->resources[res_idx++] = finfo->mmio_res; + } + + if (finfo->nr_irqs) { + ctx = devm_kcalloc(binfo->dev, finfo->nr_irqs, + sizeof(*ctx), GFP_KERNEL); +- if (!ctx) +- return -ENOMEM; +- ++ if (!ctx) { ++ ret = -ENOMEM; ++ goto err_free_id; ++ } + for (i = 0; i < finfo->nr_irqs; i++) + ctx[i].irq = + binfo->irq_table[finfo->irq_base + i]; +@@ -894,55 +879,90 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo) + kfree(finfo); + } + +- ret = platform_device_add(binfo->feature_dev); +- if (!ret) { +- if (type == PORT_ID) +- dfl_fpga_cdev_add_port_dev(binfo->cdev, +- binfo->feature_dev); +- else +- binfo->cdev->fme_dev = +- get_device(&binfo->feature_dev->dev); +- /* +- * reset it to avoid build_info_free() freeing their resource. +- * +- * The resource of successfully registered feature devices +- * will be freed by platform_device_unregister(). See the +- * comments in build_info_create_dev(). +- */ +- binfo->feature_dev = NULL; +- } ++ fdata->resource_num = res_idx; + +- return ret; ++ return fdata; ++ ++err_free_id: ++ dfl_id_free(type, fdata->pdev_id); ++ ++ return ERR_PTR(ret); + } + +-static int +-build_info_create_dev(struct build_feature_devs_info *binfo, +- enum dfl_id_type type) ++/* ++ * register current feature device, it is called when we need to switch to ++ * another feature parsing or we have parsed all features on given device ++ * feature list. ++ */ ++static int feature_dev_register(struct dfl_feature_dev_data *fdata) + { ++ struct dfl_feature_platform_data pdata = { 0 }; + struct platform_device *fdev; ++ struct dfl_feature *feature; ++ int ret; + +- if (type >= DFL_ID_MAX) +- return -EINVAL; +- +- /* +- * we use -ENODEV as the initialization indicator which indicates +- * whether the id need to be reclaimed +- */ +- fdev = platform_device_alloc(dfl_devs[type].name, -ENODEV); ++ fdev = platform_device_alloc(fdata->pdev_name, fdata->pdev_id); + if (!fdev) + return -ENOMEM; + +- binfo->feature_dev = fdev; +- binfo->feature_num = 0; ++ fdata->dev = fdev; + +- INIT_LIST_HEAD(&binfo->sub_features); ++ fdev->dev.parent = &fdata->dfl_cdev->region->dev; ++ fdev->dev.devt = dfl_get_devt(dfl_devs[fdata->type].devt_type, ++ fdev->id); ++ ++ dfl_fpga_dev_for_each_feature(fdata, feature) ++ feature->dev = fdev; + +- fdev->id = dfl_id_alloc(type, &fdev->dev); +- if (fdev->id < 0) +- return fdev->id; ++ ret = platform_device_add_resources(fdev, fdata->resources, ++ fdata->resource_num); ++ if (ret) ++ goto err_put_dev; ++ ++ pdata.fdata = fdata; ++ ret = platform_device_add_data(fdev, &pdata, sizeof(pdata)); ++ if (ret) ++ goto err_put_dev; + +- fdev->dev.parent = &binfo->cdev->region->dev; +- fdev->dev.devt = dfl_get_devt(dfl_devs[type].devt_type, fdev->id); ++ ret = platform_device_add(fdev); ++ if (ret) ++ goto err_put_dev; ++ ++ return 0; ++ ++err_put_dev: ++ platform_device_put(fdev); ++ fdata->dev = NULL; ++ ++ return ret; ++} ++ ++static void feature_dev_unregister(struct dfl_feature_dev_data *fdata) ++{ ++ platform_device_unregister(fdata->dev); ++ fdata->dev = NULL; ++} ++ ++static int build_info_commit_dev(struct build_feature_devs_info *binfo) ++{ ++ struct dfl_feature_dev_data *fdata; ++ int ret; ++ ++ fdata = binfo_create_feature_dev_data(binfo); ++ if (IS_ERR(fdata)) ++ return PTR_ERR(fdata); ++ ++ ret = feature_dev_register(fdata); ++ if (ret) ++ return ret; ++ ++ if (binfo->type == PORT_ID) ++ dfl_fpga_cdev_add_port_data(binfo->cdev, fdata); ++ else ++ binfo->cdev->fme_dev = get_device(&fdata->dev->dev); ++ ++ /* reset the binfo for next FIU */ ++ binfo->type = DFL_ID_MAX; + + return 0; + } +@@ -951,22 +971,11 @@ static void build_info_free(struct build_feature_devs_info *binfo) + { + struct dfl_feature_info *finfo, *p; + +- /* +- * it is a valid id, free it. See comments in +- * build_info_create_dev() +- */ +- if (binfo->feature_dev && binfo->feature_dev->id >= 0) { +- dfl_id_free(feature_dev_id_type(binfo->feature_dev), +- binfo->feature_dev->id); +- +- list_for_each_entry_safe(finfo, p, &binfo->sub_features, node) { +- list_del(&finfo->node); +- kfree(finfo); +- } ++ list_for_each_entry_safe(finfo, p, &binfo->sub_features, node) { ++ list_del(&finfo->node); ++ kfree(finfo); + } + +- platform_device_put(binfo->feature_dev); +- + devm_kfree(binfo->dev, binfo); + } + +@@ -1055,7 +1064,7 @@ static int parse_feature_irqs(struct build_feature_devs_info *binfo, + * Instead, features with interrupt functionality provide + * the information in feature specific registers. + */ +- type = feature_dev_id_type(binfo->feature_dev); ++ type = binfo->type; + if (type == PORT_ID) { + switch (fid) { + case PORT_FEATURE_ID_UINT: +@@ -1269,7 +1278,7 @@ static int parse_feature_port_afu(struct build_feature_devs_info *binfo, + return create_feature_instance(binfo, ofst, size, FEATURE_ID_AFU); + } + +-#define is_feature_dev_detected(binfo) (!!(binfo)->feature_dev) ++#define is_feature_dev_detected(binfo) ((binfo)->type != DFL_ID_MAX) + + static int parse_feature_afu(struct build_feature_devs_info *binfo, + resource_size_t ofst) +@@ -1279,12 +1288,11 @@ static int parse_feature_afu(struct build_feature_devs_info *binfo, + return -EINVAL; + } + +- switch (feature_dev_id_type(binfo->feature_dev)) { ++ switch (binfo->type) { + case PORT_ID: + return parse_feature_port_afu(binfo, ofst); + default: +- dev_info(binfo->dev, "AFU belonging to FIU %s is not supported yet.\n", +- binfo->feature_dev->name); ++ dev_info(binfo->dev, "AFU belonging to FIU is not supported yet.\n"); + } + + return 0; +@@ -1325,6 +1333,7 @@ static void build_info_complete(struct build_feature_devs_info *binfo) + static int parse_feature_fiu(struct build_feature_devs_info *binfo, + resource_size_t ofst) + { ++ enum dfl_id_type type; + int ret = 0; + u32 offset; + u16 id; +@@ -1346,10 +1355,13 @@ static int parse_feature_fiu(struct build_feature_devs_info *binfo, + v = readq(binfo->ioaddr + DFH); + id = FIELD_GET(DFH_ID, v); + +- /* create platform device for dfl feature dev */ +- ret = build_info_create_dev(binfo, dfh_id_to_type(id)); +- if (ret) +- return ret; ++ type = dfh_id_to_type(id); ++ if (type >= DFL_ID_MAX) ++ return -EINVAL; ++ ++ binfo->type = type; ++ binfo->feature_num = 0; ++ INIT_LIST_HEAD(&binfo->sub_features); + + ret = create_feature_instance(binfo, 0, 0, 0); + if (ret) +@@ -1567,13 +1579,10 @@ EXPORT_SYMBOL_GPL(dfl_fpga_enum_info_add_irq); + + static int remove_feature_dev(struct device *dev, void *data) + { +- struct platform_device *pdev = to_platform_device(dev); +- enum dfl_id_type type = feature_dev_id_type(pdev); +- int id = pdev->id; +- +- platform_device_unregister(pdev); ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); + +- dfl_id_free(type, id); ++ feature_dev_unregister(fdata); ++ dfl_id_free(fdata->type, fdata->pdev_id); + + return 0; + } +@@ -1625,6 +1634,7 @@ dfl_fpga_feature_devs_enumerate(struct dfl_fpga_enum_info *info) + goto unregister_region_exit; + } + ++ binfo->type = DFL_ID_MAX; + binfo->dev = info->dev; + binfo->cdev = cdev; + +@@ -1666,25 +1676,10 @@ EXPORT_SYMBOL_GPL(dfl_fpga_feature_devs_enumerate); + */ + void dfl_fpga_feature_devs_remove(struct dfl_fpga_cdev *cdev) + { +- struct dfl_feature_platform_data *pdata, *ptmp; +- + mutex_lock(&cdev->lock); + if (cdev->fme_dev) + put_device(cdev->fme_dev); + +- list_for_each_entry_safe(pdata, ptmp, &cdev->port_dev_list, node) { +- struct platform_device *port_dev = pdata->dev; +- +- /* remove released ports */ +- if (!device_is_registered(&port_dev->dev)) { +- dfl_id_free(feature_dev_id_type(port_dev), +- port_dev->id); +- platform_device_put(port_dev); +- } +- +- list_del(&pdata->node); +- put_device(&port_dev->dev); +- } + mutex_unlock(&cdev->lock); + + remove_feature_devs(cdev); +@@ -1708,23 +1703,21 @@ EXPORT_SYMBOL_GPL(dfl_fpga_feature_devs_remove); + * + * NOTE: you will need to drop the device reference with put_device() after use. + */ +-struct platform_device * +-__dfl_fpga_cdev_find_port(struct dfl_fpga_cdev *cdev, void *data, +- int (*match)(struct platform_device *, void *)) ++struct dfl_feature_dev_data * ++__dfl_fpga_cdev_find_port_data(struct dfl_fpga_cdev *cdev, void *data, ++ int (*match)(struct dfl_feature_dev_data *, ++ void *)) + { +- struct dfl_feature_platform_data *pdata; +- struct platform_device *port_dev; +- +- list_for_each_entry(pdata, &cdev->port_dev_list, node) { +- port_dev = pdata->dev; ++ struct dfl_feature_dev_data *fdata; + +- if (match(port_dev, data) && get_device(&port_dev->dev)) +- return port_dev; ++ list_for_each_entry(fdata, &cdev->port_dev_list, node) { ++ if (match(fdata, data)) ++ return fdata; + } + + return NULL; + } +-EXPORT_SYMBOL_GPL(__dfl_fpga_cdev_find_port); ++EXPORT_SYMBOL_GPL(__dfl_fpga_cdev_find_port_data); + + static int __init dfl_fpga_init(void) + { +@@ -1758,33 +1751,29 @@ static int __init dfl_fpga_init(void) + */ + int dfl_fpga_cdev_release_port(struct dfl_fpga_cdev *cdev, int port_id) + { +- struct dfl_feature_platform_data *pdata; +- struct platform_device *port_pdev; ++ struct dfl_feature_dev_data *fdata; + int ret = -ENODEV; + + mutex_lock(&cdev->lock); +- port_pdev = __dfl_fpga_cdev_find_port(cdev, &port_id, +- dfl_fpga_check_port_id); +- if (!port_pdev) ++ fdata = __dfl_fpga_cdev_find_port_data(cdev, &port_id, ++ dfl_fpga_check_port_id); ++ if (!fdata) + goto unlock_exit; + +- if (!device_is_registered(&port_pdev->dev)) { ++ if (!fdata->dev) { + ret = -EBUSY; +- goto put_dev_exit; ++ goto unlock_exit; + } + +- pdata = dev_get_platdata(&port_pdev->dev); +- +- mutex_lock(&pdata->lock); +- ret = dfl_feature_dev_use_begin(pdata, true); +- mutex_unlock(&pdata->lock); ++ mutex_lock(&fdata->lock); ++ ret = dfl_feature_dev_use_begin(fdata, true); ++ mutex_unlock(&fdata->lock); + if (ret) +- goto put_dev_exit; ++ goto unlock_exit; + +- platform_device_del(port_pdev); ++ feature_dev_unregister(fdata); + cdev->released_port_num++; +-put_dev_exit: +- put_device(&port_pdev->dev); ++ + unlock_exit: + mutex_unlock(&cdev->lock); + return ret; +@@ -1804,34 +1793,30 @@ EXPORT_SYMBOL_GPL(dfl_fpga_cdev_release_port); + */ + int dfl_fpga_cdev_assign_port(struct dfl_fpga_cdev *cdev, int port_id) + { +- struct dfl_feature_platform_data *pdata; +- struct platform_device *port_pdev; ++ struct dfl_feature_dev_data *fdata; + int ret = -ENODEV; + + mutex_lock(&cdev->lock); +- port_pdev = __dfl_fpga_cdev_find_port(cdev, &port_id, +- dfl_fpga_check_port_id); +- if (!port_pdev) ++ fdata = __dfl_fpga_cdev_find_port_data(cdev, &port_id, ++ dfl_fpga_check_port_id); ++ if (!fdata) + goto unlock_exit; + +- if (device_is_registered(&port_pdev->dev)) { ++ if (fdata->dev) { + ret = -EBUSY; +- goto put_dev_exit; ++ goto unlock_exit; + } + +- ret = platform_device_add(port_pdev); ++ ret = feature_dev_register(fdata); + if (ret) +- goto put_dev_exit; +- +- pdata = dev_get_platdata(&port_pdev->dev); ++ goto unlock_exit; + +- mutex_lock(&pdata->lock); +- dfl_feature_dev_use_end(pdata); +- mutex_unlock(&pdata->lock); ++ mutex_lock(&fdata->lock); ++ dfl_feature_dev_use_end(fdata); ++ mutex_unlock(&fdata->lock); + + cdev->released_port_num--; +-put_dev_exit: +- put_device(&port_pdev->dev); ++ + unlock_exit: + mutex_unlock(&cdev->lock); + return ret; +@@ -1841,10 +1826,11 @@ EXPORT_SYMBOL_GPL(dfl_fpga_cdev_assign_port); + static void config_port_access_mode(struct device *fme_dev, int port_id, + bool is_vf) + { ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(fme_dev); + void __iomem *base; + u64 v; + +- base = dfl_get_feature_ioaddr_by_id(fme_dev, FME_FEATURE_ID_HEADER); ++ base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_HEADER); + + v = readq(base + FME_HDR_PORT_OFST(port_id)); + +@@ -1868,14 +1854,14 @@ static void config_port_access_mode(struct device *fme_dev, int port_id, + */ + void dfl_fpga_cdev_config_ports_pf(struct dfl_fpga_cdev *cdev) + { +- struct dfl_feature_platform_data *pdata; ++ struct dfl_feature_dev_data *fdata; + + mutex_lock(&cdev->lock); +- list_for_each_entry(pdata, &cdev->port_dev_list, node) { +- if (device_is_registered(&pdata->dev->dev)) ++ list_for_each_entry(fdata, &cdev->port_dev_list, node) { ++ if (fdata->dev) + continue; + +- config_port_pf_mode(cdev->fme_dev, pdata->id); ++ config_port_pf_mode(cdev->fme_dev, fdata->id); + } + mutex_unlock(&cdev->lock); + } +@@ -1894,7 +1880,7 @@ EXPORT_SYMBOL_GPL(dfl_fpga_cdev_config_ports_pf); + */ + int dfl_fpga_cdev_config_ports_vf(struct dfl_fpga_cdev *cdev, int num_vfs) + { +- struct dfl_feature_platform_data *pdata; ++ struct dfl_feature_dev_data *fdata; + int ret = 0; + + mutex_lock(&cdev->lock); +@@ -1908,11 +1894,11 @@ int dfl_fpga_cdev_config_ports_vf(struct dfl_fpga_cdev *cdev, int num_vfs) + goto done; + } + +- list_for_each_entry(pdata, &cdev->port_dev_list, node) { +- if (device_is_registered(&pdata->dev->dev)) ++ list_for_each_entry(fdata, &cdev->port_dev_list, node) { ++ if (fdata->dev) + continue; + +- config_port_vf_mode(cdev->fme_dev, pdata->id); ++ config_port_vf_mode(cdev->fme_dev, fdata->id); + } + done: + mutex_unlock(&cdev->lock); +@@ -2046,6 +2032,7 @@ long dfl_feature_ioctl_set_irq(struct platform_device *pdev, + unsigned long arg) + { + struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); ++ struct dfl_feature_dev_data *fdata = pdata->fdata; + struct dfl_fpga_irq_set hdr; + s32 *fds; + long ret; +@@ -2065,9 +2052,9 @@ long dfl_feature_ioctl_set_irq(struct platform_device *pdev, + if (IS_ERR(fds)) + return PTR_ERR(fds); + +- mutex_lock(&pdata->lock); ++ mutex_lock(&fdata->lock); + ret = dfl_fpga_set_irq_triggers(feature, hdr.start, hdr.count, fds); +- mutex_unlock(&pdata->lock); ++ mutex_unlock(&fdata->lock); + + kfree(fds); + return ret; +diff --git a/drivers/fpga/dfl.h b/drivers/fpga/dfl.h +index d9cb13980e8d..127e7e2e74f7 100644 +--- a/drivers/fpga/dfl.h ++++ b/drivers/fpga/dfl.h +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -206,6 +207,8 @@ + #define PORT_UINT_CAP_INT_NUM GENMASK_ULL(11, 0) /* Interrupts num */ + #define PORT_UINT_CAP_FST_VECT GENMASK_ULL(23, 12) /* First Vector */ + ++struct dfl_feature_dev_data; ++ + /** + * struct dfl_fpga_port_ops - port ops + * +@@ -219,15 +222,16 @@ struct dfl_fpga_port_ops { + const char *name; + struct module *owner; + struct list_head node; +- int (*get_id)(struct platform_device *pdev); +- int (*enable_set)(struct platform_device *pdev, bool enable); ++ int (*get_id)(struct dfl_feature_dev_data *fdata); ++ int (*enable_set)(struct dfl_feature_dev_data *fdata, bool enable); + }; + + void dfl_fpga_port_ops_add(struct dfl_fpga_port_ops *ops); + void dfl_fpga_port_ops_del(struct dfl_fpga_port_ops *ops); +-struct dfl_fpga_port_ops *dfl_fpga_port_ops_get(struct platform_device *pdev); ++struct dfl_fpga_port_ops * ++ dfl_fpga_port_ops_get(struct dfl_feature_dev_data *fdata); + void dfl_fpga_port_ops_put(struct dfl_fpga_port_ops *ops); +-int dfl_fpga_check_port_id(struct platform_device *pdev, void *pport_id); ++int dfl_fpga_check_port_id(struct dfl_feature_dev_data *fdata, void *pport_id); + + /** + * struct dfl_feature_id - dfl private feature id +@@ -304,26 +308,32 @@ struct dfl_feature { + #define FEATURE_DEV_ID_UNUSED (-1) + + /** +- * struct dfl_feature_platform_data - platform data for feature devices ++ * struct dfl_feature_dev_data - dfl enumeration data for dfl feature dev. + * +- * @node: node to link feature devs to container device's port_dev_list. +- * @lock: mutex to protect platform data. +- * @cdev: cdev of feature dev. +- * @dev: ptr to platform device linked with this platform data. ++ * @node: node to link the data structure to container device's port_dev_list. ++ * @lock: mutex to protect feature dev data. ++ * @dev: ptr to the feature's platform device linked with this structure. ++ * @type: type of DFL FIU for the feature dev. See enum dfl_id_type. ++ * @pdev_id: platform device id for the feature dev. ++ * @pdev_name: platform device name for the feature dev. + * @dfl_cdev: ptr to container device. +- * @id: id used for this feature device. ++ * @id: id used for the feature device. + * @disable_count: count for port disable. + * @excl_open: set on feature device exclusive open. + * @open_count: count for feature device open. + * @num: number for sub features. + * @private: ptr to feature dev private data. +- * @features: sub features of this feature dev. ++ * @features: sub features for the feature dev. ++ * @resource_num: number of resources for the feature dev. ++ * @resources: resources for the feature dev. + */ +-struct dfl_feature_platform_data { ++struct dfl_feature_dev_data { + struct list_head node; + struct mutex lock; +- struct cdev cdev; + struct platform_device *dev; ++ enum dfl_id_type type; ++ int pdev_id; ++ const char *pdev_name; + struct dfl_fpga_cdev *dfl_cdev; + int id; + unsigned int disable_count; +@@ -331,55 +341,68 @@ struct dfl_feature_platform_data { + int open_count; + void *private; + int num; +- struct dfl_feature features[]; ++ struct dfl_feature *features; ++ int resource_num; ++ struct resource *resources; ++}; ++ ++/** ++ * struct dfl_feature_platform_data - platform data for feature devices ++ * ++ * @fdata: dfl enumeration data for the dfl feature device. ++ * @cdev: cdev of feature dev. ++ */ ++struct dfl_feature_platform_data { ++ struct dfl_feature_dev_data *fdata; ++ struct cdev cdev; + }; + + static inline +-int dfl_feature_dev_use_begin(struct dfl_feature_platform_data *pdata, ++int dfl_feature_dev_use_begin(struct dfl_feature_dev_data *fdata, + bool excl) + { +- if (pdata->excl_open) ++ if (fdata->excl_open) + return -EBUSY; + + if (excl) { +- if (pdata->open_count) ++ if (fdata->open_count) + return -EBUSY; + +- pdata->excl_open = true; ++ fdata->excl_open = true; + } +- pdata->open_count++; ++ fdata->open_count++; + + return 0; + } + + static inline +-void dfl_feature_dev_use_end(struct dfl_feature_platform_data *pdata) ++void dfl_feature_dev_use_end(struct dfl_feature_dev_data *fdata) + { +- pdata->excl_open = false; ++ fdata->excl_open = false; + +- if (WARN_ON(pdata->open_count <= 0)) ++ if (WARN_ON(fdata->open_count <= 0)) + return; + +- pdata->open_count--; ++ fdata->open_count--; + } + + static inline +-int dfl_feature_dev_use_count(struct dfl_feature_platform_data *pdata) ++int dfl_feature_dev_use_count(struct dfl_feature_dev_data *fdata) + { +- return pdata->open_count; ++ return fdata->open_count; + } + + static inline +-void dfl_fpga_pdata_set_private(struct dfl_feature_platform_data *pdata, ++void dfl_fpga_fdata_set_private(struct dfl_feature_dev_data *fdata, + void *private) + { +- pdata->private = private; ++ fdata->private = private; + } + + static inline +-void *dfl_fpga_pdata_get_private(struct dfl_feature_platform_data *pdata) ++void *dfl_fpga_fdata_get_private(struct dfl_feature_dev_data *fdata) + { +- return pdata->private; ++ return fdata->private; + } + + struct dfl_feature_ops { +@@ -409,30 +432,29 @@ struct platform_device *dfl_fpga_inode_to_feature_dev(struct inode *inode) + + pdata = container_of(inode->i_cdev, struct dfl_feature_platform_data, + cdev); +- return pdata->dev; ++ return pdata->fdata->dev; + } + +-#define dfl_fpga_dev_for_each_feature(pdata, feature) \ +- for ((feature) = (pdata)->features; \ +- (feature) < (pdata)->features + (pdata)->num; (feature)++) ++#define dfl_fpga_dev_for_each_feature(fdata, feature) \ ++ for ((feature) = (fdata)->features; \ ++ (feature) < (fdata)->features + (fdata)->num; (feature)++) + +-static inline +-struct dfl_feature *dfl_get_feature_by_id(struct device *dev, u16 id) ++static inline struct dfl_feature * ++dfl_get_feature_by_id(struct dfl_feature_dev_data *fdata, u16 id) + { +- struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); + struct dfl_feature *feature; + +- dfl_fpga_dev_for_each_feature(pdata, feature) ++ dfl_fpga_dev_for_each_feature(fdata, feature) + if (feature->id == id) + return feature; + + return NULL; + } + +-static inline +-void __iomem *dfl_get_feature_ioaddr_by_id(struct device *dev, u16 id) ++static inline void __iomem * ++dfl_get_feature_ioaddr_by_id(struct dfl_feature_dev_data *fdata, u16 id) + { +- struct dfl_feature *feature = dfl_get_feature_by_id(dev, id); ++ struct dfl_feature *feature = dfl_get_feature_by_id(fdata, id); + + if (feature && feature->ioaddr) + return feature->ioaddr; +@@ -441,15 +463,18 @@ void __iomem *dfl_get_feature_ioaddr_by_id(struct device *dev, u16 id) + return NULL; + } + +-static inline bool is_dfl_feature_present(struct device *dev, u16 id) ++static inline struct dfl_feature_dev_data * ++to_dfl_feature_dev_data(struct device *dev) + { +- return !!dfl_get_feature_ioaddr_by_id(dev, id); ++ struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); ++ ++ return pdata->fdata; + } + + static inline +-struct device *dfl_fpga_pdata_to_parent(struct dfl_feature_platform_data *pdata) ++struct device *dfl_fpga_fdata_to_parent(struct dfl_feature_dev_data *fdata) + { +- return pdata->dev->dev.parent->parent; ++ return fdata->dev->dev.parent->parent; + } + + static inline bool dfl_feature_is_fme(void __iomem *base) +@@ -560,26 +585,23 @@ struct dfl_fpga_cdev * + dfl_fpga_feature_devs_enumerate(struct dfl_fpga_enum_info *info); + void dfl_fpga_feature_devs_remove(struct dfl_fpga_cdev *cdev); + +-/* +- * need to drop the device reference with put_device() after use port platform +- * device returned by __dfl_fpga_cdev_find_port and dfl_fpga_cdev_find_port +- * functions. +- */ +-struct platform_device * +-__dfl_fpga_cdev_find_port(struct dfl_fpga_cdev *cdev, void *data, +- int (*match)(struct platform_device *, void *)); ++struct dfl_feature_dev_data * ++__dfl_fpga_cdev_find_port_data(struct dfl_fpga_cdev *cdev, void *data, ++ int (*match)(struct dfl_feature_dev_data *, ++ void *)); + +-static inline struct platform_device * +-dfl_fpga_cdev_find_port(struct dfl_fpga_cdev *cdev, void *data, +- int (*match)(struct platform_device *, void *)) ++static inline struct dfl_feature_dev_data * ++dfl_fpga_cdev_find_port_data(struct dfl_fpga_cdev *cdev, void *data, ++ int (*match)(struct dfl_feature_dev_data *, ++ void *)) + { +- struct platform_device *pdev; ++ struct dfl_feature_dev_data *fdata; + + mutex_lock(&cdev->lock); +- pdev = __dfl_fpga_cdev_find_port(cdev, data, match); ++ fdata = __dfl_fpga_cdev_find_port_data(cdev, data, match); + mutex_unlock(&cdev->lock); + +- return pdev; ++ return fdata; + } + + int dfl_fpga_cdev_release_port(struct dfl_fpga_cdev *cdev, int port_id); diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0013-mfd-intel-m10-bmc-Create-BMC-log-sub-driver.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0013-mfd-intel-m10-bmc-Create-BMC-log-sub-driver.patch new file mode 100644 index 0000000..f04d2c6 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0013-mfd-intel-m10-bmc-Create-BMC-log-sub-driver.patch @@ -0,0 +1,421 @@ +From 79327e1fd11168dc1c6dc7be4a1672fd5ed4af7e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= +Date: Tue, 10 Jan 2023 10:35:33 +0200 +Subject: [PATCH] mfd: intel-m10-bmc: Create BMC log sub-driver +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The PMCI MAX10 BMC contains high and low timestamp registers that are +periodically written by the host driver to facilitate BMC error logs. +Add a kernel worker thread to update the BMC timestamp registers. The +frequency of timestamp updates is controlled through sysfs file (the +default frequency is once per minute). + +Use the nvmem API to expose the event MAX10 BMC event logs to +userspace. + +Co-developed-by: Russ Weight +Signed-off-by: Russ Weight +Co-developed-by: Tianfei Zhang +Signed-off-by: Tianfei Zhang +Co-developed-by: Matthew Gerlach +Signed-off-by: Matthew Gerlach +Signed-off-by: Ilpo Järvinen +--- + .../testing/sysfs-driver-intel-m10-bmc-log | 36 +++ + drivers/mfd/Kconfig | 9 + + drivers/mfd/Makefile | 1 + + drivers/mfd/intel-m10-bmc-log.c | 262 ++++++++++++++++++ + drivers/mfd/intel-m10-bmc-pmci.c | 1 + + include/linux/mfd/intel-m10-bmc.h | 14 + + 6 files changed, 323 insertions(+) + create mode 100644 Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-log + create mode 100644 drivers/mfd/intel-m10-bmc-log.c + +diff --git a/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-log b/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-log +new file mode 100644 +index 000000000000..3098f0d3f56e +--- /dev/null ++++ b/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-log +@@ -0,0 +1,36 @@ ++What: /sys/bus/platform/devices/intel-m10-bmc-log.*.auto/time_sync_frequency ++Date: Jan 2023 ++KernelVersion: 6.3 ++Contact: Russ Weight ++Description: Read/write. This sysfs node controls the frequency (in ++ seconds) that the host writes to the MAX10 BMC registers ++ to synchronize the timestamp registers used for the BMC ++ error log. Write zero to stop the timestamp synchronization. ++ Write a non-zero integer value to restart or modify the ++ update frequency. Reading from this file will return the ++ same integer value. ++ Format: %u ++ ++What: /sys/bus/platform/devices/intel-m10-bmc-log.*.auto/bmc_event_log*/nvmem ++Date: Jan 2023 ++KernelVersion: 6.3 ++Contact: Tianfei zhang ++Description: Read-only. This file returns the contents of the "error log" ++ partition in flash. This partition includes the error info for ++ the BMC. ++ ++What: /sys/bus/platform/devices/intel-m10-bmc-log.*.auto/fpga_image_directory*/nvmem ++Date: Jan 2023 ++KernelVersion: 6.3 ++Contact: Tianfei zhang ++Description: Read-only. This file returns the contents of the "FPGA image ++ directory" partition in flash. This partition includes ++ information like the FPGA Image versions and state. ++ ++What: /sys/bus/platform/devices/intel-m10-bmc-log.*.auto/bom_info*/nvmem ++Date: Jan 2023 ++KernelVersion: 6.3 ++Contact: Tianfei zhang ++Description: Read-only. This file returns the contents of the "BOM info" ++ partition in flash. This partition includes information such ++ as the BOM critical components, PBA#, MMID. +diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig +index 90ce58fd629e..b96033472f6a 100644 +--- a/drivers/mfd/Kconfig ++++ b/drivers/mfd/Kconfig +@@ -2304,6 +2304,15 @@ config MFD_INTEL_M10_BMC_PMCI + additional drivers must be enabled in order to use the functionality + of the device. + ++config MFD_INTEL_M10_BMC_LOG ++ tristate "Intel MAX 10 Board Management Controller Log Driver" ++ depends on MFD_INTEL_M10_BMC_CORE ++ help ++ Support for the Intel MAX 10 board management controller log ++ ++ This driver provides timestamp synchronization with the MAX10 ++ BMC log. ++ + config MFD_RSMU_I2C + tristate "Renesas Synchronization Management Unit with I2C" + depends on I2C && OF +diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile +index c66f07edcd0e..2849d5b8a8a5 100644 +--- a/drivers/mfd/Makefile ++++ b/drivers/mfd/Makefile +@@ -274,6 +274,7 @@ obj-$(CONFIG_MFD_SIMPLE_MFD_I2C) += simple-mfd-i2c.o + obj-$(CONFIG_MFD_SMPRO) += smpro-core.o + + obj-$(CONFIG_MFD_INTEL_M10_BMC_CORE) += intel-m10-bmc-core.o ++obj-$(CONFIG_MFD_INTEL_M10_BMC_LOG) += intel-m10-bmc-log.o + obj-$(CONFIG_MFD_INTEL_M10_BMC_SPI) += intel-m10-bmc-spi.o + obj-$(CONFIG_MFD_INTEL_M10_BMC_PMCI) += intel-m10-bmc-pmci.o + +diff --git a/drivers/mfd/intel-m10-bmc-log.c b/drivers/mfd/intel-m10-bmc-log.c +new file mode 100644 +index 000000000000..d5e64506c92f +--- /dev/null ++++ b/drivers/mfd/intel-m10-bmc-log.c +@@ -0,0 +1,262 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Intel Max10 Board Management Controller Log Driver ++ * ++ * Copyright (C) 2021-2023 Intel Corporation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define M10BMC_TIMESTAMP_FREQ 60 /* 60 secs between updates */ ++ ++struct m10bmc_log_cfg { ++ int el_size; ++ unsigned long el_off; ++ ++ int id_size; ++ unsigned long id_off; ++ ++ int bi_size; ++ unsigned long bi_off; ++}; ++ ++struct m10bmc_log { ++ struct device *dev; ++ struct intel_m10bmc *m10bmc; ++ unsigned int freq_s; /* update frequency in seconds */ ++ struct delayed_work dwork; ++ const struct m10bmc_log_cfg *log_cfg; ++ struct nvmem_device *bmc_event_log_nvmem; ++ struct nvmem_device *fpga_image_dir_nvmem; ++ struct nvmem_device *bom_info_nvmem; ++}; ++ ++static void m10bmc_log_time_sync(struct work_struct *work) ++{ ++ struct delayed_work *dwork = to_delayed_work(work); ++ const struct m10bmc_csr_map *csr_map; ++ struct m10bmc_log *log; ++ s64 time_ms; ++ int ret; ++ ++ log = container_of(dwork, struct m10bmc_log, dwork); ++ csr_map = log->m10bmc->info->csr_map; ++ ++ time_ms = ktime_to_ms(ktime_get_real()); ++ ret = regmap_write(log->m10bmc->regmap, csr_map->base + M10BMC_N6000_TIME_HIGH, ++ upper_32_bits(time_ms)); ++ if (!ret) { ++ ret = regmap_write(log->m10bmc->regmap, csr_map->base + M10BMC_N6000_TIME_LOW, ++ lower_32_bits(time_ms)); ++ } ++ if (ret) ++ dev_err_once(log->dev, "Failed to update BMC timestamp: %d\n", ret); ++ ++ schedule_delayed_work(&log->dwork, log->freq_s * HZ); ++} ++ ++static ssize_t time_sync_frequency_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct m10bmc_log *ddata = dev_get_drvdata(dev); ++ unsigned int old_freq = ddata->freq_s; ++ int ret; ++ ++ ret = kstrtouint(buf, 0, &ddata->freq_s); ++ if (ret) ++ return ret; ++ ++ if (old_freq) ++ cancel_delayed_work_sync(&ddata->dwork); ++ ++ if (ddata->freq_s) ++ m10bmc_log_time_sync(&ddata->dwork.work); ++ ++ return count; ++} ++ ++static ssize_t time_sync_frequency_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct m10bmc_log *ddata = dev_get_drvdata(dev); ++ ++ return sysfs_emit(buf, "%u\n", ddata->freq_s); ++} ++static DEVICE_ATTR_RW(time_sync_frequency); ++ ++static struct attribute *m10bmc_log_attrs[] = { ++ &dev_attr_time_sync_frequency.attr, ++ NULL, ++}; ++ATTRIBUTE_GROUPS(m10bmc_log); ++ ++static int bmc_nvmem_read(struct m10bmc_log *ddata, unsigned int addr, ++ unsigned int off, void *val, size_t count) ++{ ++ struct intel_m10bmc *m10bmc = ddata->m10bmc; ++ int ret; ++ ++ if (!m10bmc->flash_bulk_ops) ++ return -ENODEV; ++ ++ ret = m10bmc->flash_bulk_ops->read(m10bmc, val, addr + off, count); ++ if (ret) { ++ dev_err(ddata->dev, "failed to read flash %x (%d)\n", addr, ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int bmc_event_log_nvmem_read(void *priv, unsigned int off, void *val, size_t count) ++{ ++ struct m10bmc_log *ddata = priv; ++ ++ return bmc_nvmem_read(ddata, ddata->log_cfg->el_off, off, val, count); ++} ++ ++static int fpga_image_dir_nvmem_read(void *priv, unsigned int off, void *val, size_t count) ++{ ++ struct m10bmc_log *ddata = priv; ++ ++ return bmc_nvmem_read(ddata, ddata->log_cfg->id_off, off, val, count); ++} ++ ++static int bom_info_nvmem_read(void *priv, unsigned int off, void *val, size_t count) ++{ ++ struct m10bmc_log *ddata = priv; ++ ++ return bmc_nvmem_read(ddata, ddata->log_cfg->bi_off, off, val, count); ++} ++ ++static struct nvmem_config bmc_event_log_nvmem_config = { ++ .name = "bmc_event_log", ++ .stride = 4, ++ .word_size = 1, ++ .reg_read = bmc_event_log_nvmem_read, ++ .id = NVMEM_DEVID_AUTO, ++}; ++ ++static struct nvmem_config fpga_image_dir_nvmem_config = { ++ .name = "fpga_image_directory", ++ .stride = 4, ++ .word_size = 1, ++ .reg_read = fpga_image_dir_nvmem_read, ++ .id = NVMEM_DEVID_AUTO, ++}; ++ ++static struct nvmem_config bom_info_nvmem_config = { ++ .name = "bom_info", ++ .stride = 4, ++ .word_size = 1, ++ .reg_read = bom_info_nvmem_read, ++ .id = NVMEM_DEVID_AUTO, ++}; ++ ++static int m10bmc_log_probe(struct platform_device *pdev) ++{ ++ const struct platform_device_id *id = platform_get_device_id(pdev); ++ struct m10bmc_log *ddata; ++ struct nvmem_config nvconfig; ++ ++ ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); ++ if (!ddata) ++ return -ENOMEM; ++ ++ ddata->dev = &pdev->dev; ++ ddata->m10bmc = dev_get_drvdata(pdev->dev.parent); ++ ddata->freq_s = M10BMC_TIMESTAMP_FREQ; ++ INIT_DELAYED_WORK(&ddata->dwork, m10bmc_log_time_sync); ++ ddata->log_cfg = (struct m10bmc_log_cfg *)id->driver_data; ++ dev_set_drvdata(&pdev->dev, ddata); ++ ++ if (ddata->log_cfg->el_size > 0) { ++ m10bmc_log_time_sync(&ddata->dwork.work); ++ ++ memcpy(&nvconfig, &bmc_event_log_nvmem_config, sizeof(bmc_event_log_nvmem_config)); ++ nvconfig.dev = ddata->dev; ++ nvconfig.priv = ddata; ++ nvconfig.size = ddata->log_cfg->el_size; ++ ++ ddata->bmc_event_log_nvmem = devm_nvmem_register(ddata->dev, &nvconfig); ++ if (IS_ERR(ddata->bmc_event_log_nvmem)) ++ return PTR_ERR(ddata->bmc_event_log_nvmem); ++ } ++ ++ if (ddata->log_cfg->id_size > 0) { ++ memcpy(&nvconfig, &fpga_image_dir_nvmem_config, sizeof(fpga_image_dir_nvmem_config)); ++ nvconfig.dev = ddata->dev; ++ nvconfig.priv = ddata; ++ nvconfig.size = ddata->log_cfg->id_size; ++ ++ ddata->fpga_image_dir_nvmem = devm_nvmem_register(ddata->dev, &nvconfig); ++ if (IS_ERR(ddata->fpga_image_dir_nvmem)) ++ return PTR_ERR(ddata->fpga_image_dir_nvmem); ++ } ++ ++ if (ddata->log_cfg->bi_size > 0) { ++ memcpy(&nvconfig, &bom_info_nvmem_config, sizeof(bom_info_nvmem_config)); ++ nvconfig.dev = ddata->dev; ++ nvconfig.priv = ddata; ++ nvconfig.size = ddata->log_cfg->bi_size; ++ ++ ddata->bom_info_nvmem = devm_nvmem_register(ddata->dev, &nvconfig); ++ if (IS_ERR(ddata->bom_info_nvmem)) ++ return PTR_ERR(ddata->bom_info_nvmem); ++ } ++ ++ return 0; ++} ++ ++static int m10bmc_log_remove(struct platform_device *pdev) ++{ ++ struct m10bmc_log *ddata = dev_get_drvdata(&pdev->dev); ++ ++ cancel_delayed_work_sync(&ddata->dwork); ++ ++ return 0; ++} ++ ++static const struct m10bmc_log_cfg m10bmc_log_n6000_cfg = { ++ .el_size = M10BMC_N6000_ERROR_LOG_SIZE, ++ .el_off = M10BMC_N6000_ERROR_LOG_ADDR, ++ ++ .id_size = M10BMC_N6000_FPGA_IMAGE_DIR_SIZE, ++ .id_off = M10BMC_N6000_FPGA_IMAGE_DIR_ADDR, ++ ++ .bi_size = M10BMC_N6000_BOM_INFO_SIZE, ++ .bi_off = M10BMC_N6000_BOM_INFO_ADDR, ++}; ++ ++static const struct platform_device_id intel_m10bmc_log_ids[] = { ++ { ++ .name = "n6000bmc-log", ++ .driver_data = (unsigned long)&m10bmc_log_n6000_cfg, ++ }, ++ { } ++}; ++ ++static struct platform_driver intel_m10bmc_log_driver = { ++ .probe = m10bmc_log_probe, ++ .remove = m10bmc_log_remove, ++ .driver = { ++ .name = "intel-m10-bmc-log", ++ .dev_groups = m10bmc_log_groups, ++ }, ++ .id_table = intel_m10bmc_log_ids, ++}; ++module_platform_driver(intel_m10bmc_log_driver); ++ ++MODULE_DEVICE_TABLE(platform, intel_m10bmc_log_ids); ++MODULE_AUTHOR("Intel Corporation"); ++MODULE_DESCRIPTION("Intel MAX10 BMC Log"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/mfd/intel-m10-bmc-pmci.c b/drivers/mfd/intel-m10-bmc-pmci.c +index 698c5933938b..68eb3fc131f9 100644 +--- a/drivers/mfd/intel-m10-bmc-pmci.c ++++ b/drivers/mfd/intel-m10-bmc-pmci.c +@@ -350,6 +350,7 @@ static struct regmap_config m10bmc_pmci_regmap_config = { + static struct mfd_cell m10bmc_pmci_n6000_bmc_subdevs[] = { + { .name = "n6000bmc-hwmon" }, + { .name = "n6000bmc-sec-update" }, ++ { .name = "n6000bmc-log" }, + }; + + static const struct m10bmc_csr_map m10bmc_n6000_csr_map = { +diff --git a/include/linux/mfd/intel-m10-bmc.h b/include/linux/mfd/intel-m10-bmc.h +index e50c9b10f696..f0793663585f 100644 +--- a/include/linux/mfd/intel-m10-bmc.h ++++ b/include/linux/mfd/intel-m10-bmc.h +@@ -170,6 +170,10 @@ + #define PMCI_MAX10_REBOOT_REQ BIT(0) + #define PMCI_MAX10_REBOOT_PAGE BIT(1) + ++/* N6000 Timestamp registers */ ++#define M10BMC_N6000_TIME_LOW 0x178 ++#define M10BMC_N6000_TIME_HIGH 0x17c ++ + #define M10BMC_N6000_DOORBELL 0x1c0 + #define PMCI_DRBL_REBOOT_DISABLED BIT(1) + +@@ -181,6 +185,16 @@ + #define M10BMC_N6000_MAC_LOW 0x20 + #define M10BMC_N6000_MAC_HIGH (M10BMC_N6000_MAC_LOW + 4) + ++/* Addresses for BMC log data in FLASH */ ++#define M10BMC_N6000_ERROR_LOG_ADDR 0x7fb0000 ++#define M10BMC_N6000_ERROR_LOG_SIZE 0x40000 ++ ++#define M10BMC_N6000_FPGA_IMAGE_DIR_ADDR 0x7ff6000 ++#define M10BMC_N6000_FPGA_IMAGE_DIR_SIZE 0x3000 ++ ++#define M10BMC_N6000_BOM_INFO_ADDR 0x7ff0000 ++#define M10BMC_N6000_BOM_INFO_SIZE 0x2000 ++ + /* Addresses for security related data in FLASH */ + #define M10BMC_N6000_BMC_REH_ADDR 0x7ffc004 + #define M10BMC_N6000_BMC_PROG_ADDR 0x7ffc000 diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0014-fpga-dfl-Validate-length-field-in-DFHv1-header.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0014-fpga-dfl-Validate-length-field-in-DFHv1-header.patch new file mode 100644 index 0000000..2101934 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0014-fpga-dfl-Validate-length-field-in-DFHv1-header.patch @@ -0,0 +1,85 @@ +From bf0b56e571cd3420a42f8ce684c5ed790f31773a Mon Sep 17 00:00:00 2001 +From: Matthew Gerlach +Date: Mon, 30 Jan 2023 14:42:22 -0800 +Subject: [PATCH] fpga: dfl: Validate length field in DFHv1 header + +For relative addressing of the feature registers, validate the length +field in the DFHv1. Verify that the CSR start and end offsets fall within +the MMIO range for relative addresses. + +Co-developed-by: Basheer Ahmed Muddebihal +Signed-off-by: Basheer Ahmed Muddebihal +Signed-off-by: Matthew Gerlach +--- + drivers/fpga/dfl.c | 35 ++++++++++++++++++++++++++++++++--- + 1 file changed, 32 insertions(+), 3 deletions(-) + +diff --git a/drivers/fpga/dfl.c b/drivers/fpga/dfl.c +index dca7fea5960e..dcd90c0cbe5b 100644 +--- a/drivers/fpga/dfl.c ++++ b/drivers/fpga/dfl.c +@@ -1164,6 +1164,18 @@ static int dfh_get_param_size(void __iomem *dfh_base, resource_size_t max) + return -ENOENT; + } + ++static bool dfl_csr_blk_is_outside_mmio(resource_size_t csr_start, ++ resource_size_t csr_end, ++ resource_size_t mmio_start, ++ resource_size_t mmio_end) ++{ ++ /* ++ * CSR start and end is within MMIO space for relative address ++ */ ++ return !(csr_start >= mmio_start && csr_start <= mmio_end && ++ csr_end >= mmio_start && csr_end <= mmio_end); ++} ++ + /* + * when create sub feature instances, for private features, it doesn't need + * to provide resource size and feature id as they could be read from DFH +@@ -1177,11 +1189,14 @@ create_feature_instance(struct build_feature_devs_info *binfo, + { + struct dfl_feature_info *finfo; + resource_size_t start, end; ++ resource_size_t csr_size; ++ resource_size_t mmio_end; + int dfh_psize = 0; + u64 guid_l, guid_h; + u8 revision = 0; + u64 v, addr_off; + u8 dfh_ver = 0; ++ bool rel_addr; + int ret; + + if (fid != FEATURE_ID_AFU) { +@@ -1221,13 +1236,27 @@ create_feature_instance(struct build_feature_devs_info *binfo, + v = readq(binfo->ioaddr + ofst + DFHv1_CSR_ADDR); + addr_off = FIELD_GET(DFHv1_CSR_ADDR_MASK, v) << 1; + +- if (FIELD_GET(DFHv1_CSR_ADDR_REL, v)) ++ if (FIELD_GET(DFHv1_CSR_ADDR_REL, v)) { + start = addr_off; +- else ++ rel_addr = false; ++ } else { + start = binfo->start + ofst + (int64_t)addr_off; ++ rel_addr = true; ++ } + + v = readq(binfo->ioaddr + ofst + DFHv1_CSR_SIZE_GRP); +- end = start + FIELD_GET(DFHv1_CSR_SIZE_GRP_SIZE, v) - 1; ++ csr_size = FIELD_GET(DFHv1_CSR_SIZE_GRP_SIZE, v); ++ end = csr_size ? (start + csr_size - 1) : start; ++ mmio_end = binfo->len ? (binfo->start + binfo->len - 1) : binfo->start; ++ ++ if (rel_addr && dfl_csr_blk_is_outside_mmio(start, end, binfo->start, mmio_end)) { ++ kfree(finfo); ++ dev_warn(binfo->dev, ++ "Out of MMIO, CSR[St=%pa,End=%pa] MMIO[St=%pa,End=%pa]\n", ++ &start, &end, &binfo->start, &mmio_end); ++ return 0; ++ } ++ + guid_l = readq(binfo->ioaddr + ofst + GUID_L); + guid_h = readq(binfo->ioaddr + ofst + GUID_H); + diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0015-fpga-dfl-afu-add-read-only-write-only-dma-mapping-su.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0015-fpga-dfl-afu-add-read-only-write-only-dma-mapping-su.patch new file mode 100644 index 0000000..a07b34f --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0015-fpga-dfl-afu-add-read-only-write-only-dma-mapping-su.patch @@ -0,0 +1,218 @@ +From 304f653071ac681f0c48774686c94658d1f2c1b3 Mon Sep 17 00:00:00 2001 +From: Michael Adler +Date: Thu, 7 May 2020 19:30:56 +0800 +Subject: [PATCH] fpga: dfl: afu: add read-only/write-only dma mapping support + +This patch adds support for Read-only and Write-only DMA mapping +through existing DMA_MAP/UNMAP ioctl interface, it introduces +two new flags DFL_DMA_MAP_FLAG_READ (mem to dev) and +DFL_DMA_MAP_FLAG_WRITE (dev to mem). + +Signed-off-by: Michael Adler +Signed-off-by: Wu Hao +Signed-off-by: Xu Yilun +--- + drivers/fpga/dfl-afu-dma-region.c | 37 ++++++++++++++++++++++++++----- + drivers/fpga/dfl-afu-main.c | 6 +++-- + drivers/fpga/dfl-afu.h | 5 ++++- + include/uapi/linux/fpga-dfl.h | 10 ++++++++- + 4 files changed, 48 insertions(+), 10 deletions(-) + +diff --git a/drivers/fpga/dfl-afu-dma-region.c b/drivers/fpga/dfl-afu-dma-region.c +index 6632c51eaa62..b3e2abb195a0 100644 +--- a/drivers/fpga/dfl-afu-dma-region.c ++++ b/drivers/fpga/dfl-afu-dma-region.c +@@ -9,7 +9,7 @@ + * Xiao Guangrong + */ + +-#include ++#include + #include + #include + #include +@@ -37,6 +37,7 @@ static int afu_dma_pin_pages(struct dfl_feature_dev_data *fdata, + { + int npages = PFN_DOWN(region->length); + struct device *dev = &fdata->dev->dev; ++ unsigned int flags = 0; + int ret, pinned; + + ret = account_locked_vm(current->mm, npages, true); +@@ -49,7 +50,10 @@ static int afu_dma_pin_pages(struct dfl_feature_dev_data *fdata, + goto unlock_vm; + } + +- pinned = pin_user_pages_fast(region->user_addr, npages, FOLL_WRITE, ++ if (region->direction != DMA_TO_DEVICE) ++ flags |= FOLL_WRITE; ++ ++ pinned = pin_user_pages_fast(region->user_addr, npages, flags, + region->pages); + if (pinned < 0) { + ret = pinned; +@@ -288,11 +292,31 @@ afu_dma_region_find_iova(struct dfl_feature_dev_data *fdata, u64 iova) + return afu_dma_region_find(fdata, iova, 0); + } + ++static enum dma_data_direction dma_flag_to_dir(u32 flags) ++{ ++ u32 mask = DFL_DMA_MAP_FLAG_READ | DFL_DMA_MAP_FLAG_WRITE; ++ ++ /* ++ * DMA is bidirectional if both read and write are specified or if ++ * neither read nor write is specified. The latter supports legacy ++ * code, which did not pass any flags. ++ */ ++ switch (flags & mask) { ++ case DFL_DMA_MAP_FLAG_READ: ++ return DMA_TO_DEVICE; ++ case DFL_DMA_MAP_FLAG_WRITE: ++ return DMA_FROM_DEVICE; ++ } ++ ++ return DMA_BIDIRECTIONAL; ++} ++ + /** + * afu_dma_map_region - map memory region for dma + * @fdata: feature dev data + * @user_addr: address of the memory region + * @length: size of the memory region ++ * @flags: dma mapping flags + * @iova: pointer of iova address + * + * Map memory region defined by @user_addr and @length, and return dma address +@@ -300,7 +324,7 @@ afu_dma_region_find_iova(struct dfl_feature_dev_data *fdata, u64 iova) + * Return 0 for success, otherwise error code. + */ + int afu_dma_map_region(struct dfl_feature_dev_data *fdata, +- u64 user_addr, u64 length, u64 *iova) ++ u64 user_addr, u64 length, u32 flags, u64 *iova) + { + struct device *dev = &fdata->dev->dev; + struct dfl_afu_dma_region *region; +@@ -323,6 +347,7 @@ int afu_dma_map_region(struct dfl_feature_dev_data *fdata, + + region->user_addr = user_addr; + region->length = length; ++ region->direction = dma_flag_to_dir(flags); + + /* Pin the user memory region */ + ret = afu_dma_pin_pages(fdata, region); +@@ -342,7 +367,7 @@ int afu_dma_map_region(struct dfl_feature_dev_data *fdata, + region->iova = dma_map_page(dfl_fpga_fdata_to_parent(fdata), + region->pages[0], 0, + region->length, +- DMA_BIDIRECTIONAL); ++ region->direction); + if (dma_mapping_error(dfl_fpga_fdata_to_parent(fdata), region->iova)) { + dev_err(dev, "failed to map for dma\n"); + ret = -EFAULT; +@@ -363,7 +388,7 @@ int afu_dma_map_region(struct dfl_feature_dev_data *fdata, + + unmap_dma: + dma_unmap_page(dfl_fpga_fdata_to_parent(fdata), +- region->iova, region->length, DMA_BIDIRECTIONAL); ++ region->iova, region->length, region->direction); + unpin_pages: + afu_dma_unpin_pages(fdata, region); + free_region: +@@ -399,7 +424,7 @@ int afu_dma_unmap_region(struct dfl_feature_dev_data *fdata, u64 iova) + mutex_unlock(&fdata->lock); + + dma_unmap_page(dfl_fpga_fdata_to_parent(fdata), +- region->iova, region->length, DMA_BIDIRECTIONAL); ++ region->iova, region->length, region->direction); + afu_dma_unpin_pages(fdata, region); + kfree(region); + +diff --git a/drivers/fpga/dfl-afu-main.c b/drivers/fpga/dfl-afu-main.c +index 2e49740dbaf6..2f54cbb78a06 100644 +--- a/drivers/fpga/dfl-afu-main.c ++++ b/drivers/fpga/dfl-afu-main.c +@@ -719,6 +719,7 @@ static long afu_ioctl_get_region_info(struct dfl_feature_platform_data *pdata, + static long + afu_ioctl_dma_map(struct dfl_feature_platform_data *pdata, void __user *arg) + { ++ u32 dma_mask = DFL_DMA_MAP_FLAG_READ | DFL_DMA_MAP_FLAG_WRITE; + struct dfl_feature_dev_data *fdata = pdata->fdata; + struct dfl_fpga_port_dma_map map; + unsigned long minsz; +@@ -729,10 +730,11 @@ afu_ioctl_dma_map(struct dfl_feature_platform_data *pdata, void __user *arg) + if (copy_from_user(&map, arg, minsz)) + return -EFAULT; + +- if (map.argsz < minsz || map.flags) ++ if (map.argsz < minsz || map.flags & ~dma_mask) + return -EINVAL; + +- ret = afu_dma_map_region(fdata, map.user_addr, map.length, &map.iova); ++ ret = afu_dma_map_region(fdata, map.user_addr, map.length, map.flags, ++ &map.iova); + if (ret) + return ret; + +diff --git a/drivers/fpga/dfl-afu.h b/drivers/fpga/dfl-afu.h +index 03be4f0969c7..1e7030710be4 100644 +--- a/drivers/fpga/dfl-afu.h ++++ b/drivers/fpga/dfl-afu.h +@@ -17,6 +17,7 @@ + #ifndef __DFL_AFU_H + #define __DFL_AFU_H + ++#include + #include + + #include "dfl.h" +@@ -49,6 +50,7 @@ struct dfl_afu_mmio_region { + * @pages: ptr to pages of this region. + * @node: rb tree node. + * @in_use: flag to indicate if this region is in_use. ++ * @direction: dma data direction. + */ + struct dfl_afu_dma_region { + u64 user_addr; +@@ -57,6 +59,7 @@ struct dfl_afu_dma_region { + struct page **pages; + struct rb_node node; + bool in_use; ++ enum dma_data_direction direction; + }; + + /** +@@ -93,7 +96,7 @@ int afu_mmio_region_get_by_offset(struct dfl_feature_dev_data *fdata, + void afu_dma_region_init(struct dfl_feature_dev_data *fdata); + void afu_dma_region_destroy(struct dfl_feature_dev_data *fdata); + int afu_dma_map_region(struct dfl_feature_dev_data *fdata, +- u64 user_addr, u64 length, u64 *iova); ++ u64 user_addr, u64 length, u32 flags, u64 *iova); + int afu_dma_unmap_region(struct dfl_feature_dev_data *fdata, u64 iova); + struct dfl_afu_dma_region * + afu_dma_region_find(struct dfl_feature_dev_data *fdata, +diff --git a/include/uapi/linux/fpga-dfl.h b/include/uapi/linux/fpga-dfl.h +index 1621b077bf21..72d68e205eb9 100644 +--- a/include/uapi/linux/fpga-dfl.h ++++ b/include/uapi/linux/fpga-dfl.h +@@ -121,12 +121,20 @@ struct dfl_fpga_port_region_info { + * Map the dma memory per user_addr and length which are provided by caller. + * Driver fills the iova in provided struct afu_port_dma_map. + * This interface only accepts page-size aligned user memory for dma mapping. ++ * ++ * Setting only one of DFL_DMA_MAP_FLAG_READ or WRITE limits FPGA-initiated ++ * DMA requests to only reads or only writes. To be back-compatiable with ++ * legacy driver, setting neither flag is equivalent to setting both flags: ++ * both read and write are requests permitted. ++ * + * Return: 0 on success, -errno on failure. + */ + struct dfl_fpga_port_dma_map { + /* Input */ + __u32 argsz; /* Structure length */ +- __u32 flags; /* Zero for now */ ++ __u32 flags; ++#define DFL_DMA_MAP_FLAG_READ (1 << 0)/* readable from device */ ++#define DFL_DMA_MAP_FLAG_WRITE (1 << 1)/* writable from device */ + __u64 user_addr; /* Process virtual address */ + __u64 length; /* Length of mapping (bytes)*/ + /* Output */ diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0016-fpga-dfl-afu-add-FOLL_LONGTERM-flag-when-pin-user-pa.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0016-fpga-dfl-afu-add-FOLL_LONGTERM-flag-when-pin-user-pa.patch new file mode 100644 index 0000000..7f4ba42 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0016-fpga-dfl-afu-add-FOLL_LONGTERM-flag-when-pin-user-pa.patch @@ -0,0 +1,27 @@ +From d23018d276dfae889cc137d0cbd7f7c03506b3bd Mon Sep 17 00:00:00 2001 +From: Wu Hao +Date: Thu, 7 May 2020 19:30:57 +0800 +Subject: [PATCH] fpga: dfl: afu: add FOLL_LONGTERM flag when pin user pages + +This patch add FOLL_LONGTERM flag in case the buffers are +used for DMA. + +Signed-off-by: Wu Hao +Signed-off-by: Xu Yilun +--- + drivers/fpga/dfl-afu-dma-region.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/fpga/dfl-afu-dma-region.c b/drivers/fpga/dfl-afu-dma-region.c +index b3e2abb195a0..4bf9aa148222 100644 +--- a/drivers/fpga/dfl-afu-dma-region.c ++++ b/drivers/fpga/dfl-afu-dma-region.c +@@ -37,7 +37,7 @@ static int afu_dma_pin_pages(struct dfl_feature_dev_data *fdata, + { + int npages = PFN_DOWN(region->length); + struct device *dev = &fdata->dev->dev; +- unsigned int flags = 0; ++ unsigned int flags = FOLL_LONGTERM; + int ret, pinned; + + ret = account_locked_vm(current->mm, npages, true); diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0017-uio-uio_dfl-add-interrupt-support.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0017-uio-uio_dfl-add-interrupt-support.patch new file mode 100644 index 0000000..10c47d5 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0017-uio-uio_dfl-add-interrupt-support.patch @@ -0,0 +1,146 @@ +From 1dfef27f2b2449a7bd33973c7d264eaa05d9e7d5 Mon Sep 17 00:00:00 2001 +From: Xu Yilun +Date: Mon, 25 Jan 2021 10:37:03 +0800 +Subject: [PATCH] uio: uio_dfl: add interrupt support + +This patch is now hold internally cause there is no need to add +interrupt capable DFL features for UIO. + +Signed-off-by: Xu Yilun +--- + drivers/uio/uio_dfl.c | 97 ++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 92 insertions(+), 5 deletions(-) + +diff --git a/drivers/uio/uio_dfl.c b/drivers/uio/uio_dfl.c +index 6d99e5a06ae8..43e74194e013 100644 +--- a/drivers/uio/uio_dfl.c ++++ b/drivers/uio/uio_dfl.c +@@ -6,27 +6,85 @@ + */ + #include + #include ++#include ++#include + #include ++#include + #include + + #define DRIVER_NAME "uio_dfl" + ++struct uio_dfl_dev { ++ struct device *dev; ++ struct uio_info uioinfo; ++ spinlock_t lock; /* Serializes the irq handler and irqcontrol */ ++ unsigned long flags; ++}; ++ ++static irqreturn_t uio_dfl_handler(int irq, struct uio_info *uioinfo) ++{ ++ struct uio_dfl_dev *udd = uioinfo->priv; ++ ++ /* Just disable the interrupt in the interrupt controller, and ++ * remember the state so we can allow user space to enable it later. ++ */ ++ ++ spin_lock(&udd->lock); ++ if (!__test_and_set_bit(0, &udd->flags)) ++ disable_irq_nosync(irq); ++ spin_unlock(&udd->lock); ++ ++ return IRQ_HANDLED; ++} ++ ++static int uio_dfl_irqcontrol(struct uio_info *uioinfo, s32 irq_on) ++{ ++ struct uio_dfl_dev *udd = uioinfo->priv; ++ unsigned long flags; ++ ++ /* Allow user space to enable and disable the interrupt ++ * in the interrupt controller, but keep track of the ++ * state to prevent per-irq depth damage. ++ * ++ * Serialize this operation to support multiple tasks and concurrency ++ * with irq handler on SMP systems. ++ */ ++ ++ spin_lock_irqsave(&udd->lock, flags); ++ if (irq_on) { ++ if (__test_and_clear_bit(0, &udd->flags)) ++ enable_irq(uioinfo->irq); ++ } else { ++ if (!__test_and_set_bit(0, &udd->flags)) ++ disable_irq_nosync(uioinfo->irq); ++ } ++ spin_unlock_irqrestore(&udd->lock, flags); ++ ++ return 0; ++} ++ + static int uio_dfl_probe(struct dfl_device *ddev) + { + struct resource *r = &ddev->mmio_res; + struct device *dev = &ddev->dev; + struct uio_info *uioinfo; ++ struct uio_dfl_dev *udd; + struct uio_mem *uiomem; + int ret; + +- uioinfo = devm_kzalloc(dev, sizeof(struct uio_info), GFP_KERNEL); +- if (!uioinfo) ++ udd = devm_kzalloc(dev, sizeof(*udd), GFP_KERNEL); ++ if (!udd) + return -ENOMEM; + ++ spin_lock_init(&udd->lock); ++ udd->flags = 0; /* interrupt is enabled to begin with */ ++ udd->dev = &ddev->dev; ++ ++ uioinfo = &udd->uioinfo; + uioinfo->name = DRIVER_NAME; + uioinfo->version = "0"; + +- uiomem = &uioinfo->mem[0]; ++ uiomem = &udd->uioinfo.mem[0]; + uiomem->memtype = UIO_MEM_PHYS; + uiomem->addr = r->start & PAGE_MASK; + uiomem->offs = r->start & ~PAGE_MASK; +@@ -34,8 +92,37 @@ static int uio_dfl_probe(struct dfl_device *ddev) + + PAGE_SIZE - 1) & PAGE_MASK; + uiomem->name = r->name; + +- /* Irq is yet to be supported */ +- uioinfo->irq = UIO_IRQ_NONE; ++ if (ddev->num_irqs) { ++ if (ddev->num_irqs > 1) ++ dev_warn(dev, ++ "%d irqs for %s, but UIO only supports the first one\n", ++ ddev->num_irqs, dev_name(dev)); ++ ++ uioinfo->irq = ddev->irqs[0]; ++ } else { ++ uioinfo->irq = UIO_IRQ_NONE; ++ } ++ ++ if (uioinfo->irq) { ++ struct irq_data *irq_data = irq_get_irq_data(uioinfo->irq); ++ ++ /* ++ * If a level interrupt, dont do lazy disable. Otherwise the ++ * irq will fire again since clearing of the actual cause, on ++ * device level, is done in userspace ++ * irqd_is_level_type() isn't used since isn't valid until ++ * irq is configured. ++ */ ++ if (irq_data && ++ irqd_get_trigger_type(irq_data) & IRQ_TYPE_LEVEL_MASK) { ++ dev_dbg(dev, "disable lazy unmask\n"); ++ irq_set_status_flags(uioinfo->irq, IRQ_DISABLE_UNLAZY); ++ } ++ } ++ ++ uioinfo->handler = uio_dfl_handler; ++ uioinfo->irqcontrol = uio_dfl_irqcontrol; ++ uioinfo->priv = udd; + + ret = devm_uio_register_device(dev, uioinfo); + if (ret) diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0018-fpga-dfl-pci-gracefully-handle-misconfigured-port-en.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0018-fpga-dfl-pci-gracefully-handle-misconfigured-port-en.patch new file mode 100644 index 0000000..325e52a --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0018-fpga-dfl-pci-gracefully-handle-misconfigured-port-en.patch @@ -0,0 +1,58 @@ +From ffac003ed4cf3b6290f32a1fe1e4907d249505a0 Mon Sep 17 00:00:00 2001 +From: Matthew Gerlach +Date: Thu, 8 Apr 2021 07:09:37 -0700 +Subject: [PATCH] fpga: dfl: pci: gracefully handle misconfigured port entries + +Gracefully ignore misconfigured port entries encountered in +incorrect FPGA images. + +Signed-off-by: Matthew Gerlach +Signed-off-by: Xu Yilun +--- + drivers/fpga/dfl-pci.c | 16 +++++++++++++++- + 1 file changed, 15 insertions(+), 1 deletion(-) + +diff --git a/drivers/fpga/dfl-pci.c b/drivers/fpga/dfl-pci.c +index 98b8fd16183e..d1c04e16c9b9 100644 +--- a/drivers/fpga/dfl-pci.c ++++ b/drivers/fpga/dfl-pci.c +@@ -228,6 +228,7 @@ static int find_dfls_by_default(struct pci_dev *pcidev, + int port_num, bar, i, ret = 0; + resource_size_t start, len; + void __iomem *base; ++ int bars = 0; + u32 offset; + u64 v; + +@@ -244,6 +245,7 @@ static int find_dfls_by_default(struct pci_dev *pcidev, + if (dfl_feature_is_fme(base)) { + start = pci_resource_start(pcidev, 0); + len = pci_resource_len(pcidev, 0); ++ bars |= BIT(0); + + dfl_fpga_enum_info_add_dfl(info, start, len); + +@@ -277,10 +279,22 @@ static int find_dfls_by_default(struct pci_dev *pcidev, + ret = -EINVAL; + break; + } ++ if (bars & BIT(bar)) { ++ dev_warn(&pcidev->dev, ++ "skipping duplicate port BAR %d\n", bar); ++ continue; ++ } + + start = pci_resource_start(pcidev, bar) + offset; +- len = pci_resource_len(pcidev, bar) - offset; ++ len = pci_resource_len(pcidev, bar); ++ if (offset >= len) { ++ dev_warn(&pcidev->dev, "bad port offset %u >= %pa\n", ++ offset, &len); ++ continue; ++ } + ++ len -= offset; ++ bars |= BIT(bar); + dfl_fpga_enum_info_add_dfl(info, start, len); + } + } else if (dfl_feature_is_port(base)) { diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0019-fpga-dfl-fme-mgr-fix-potential-endian-issue.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0019-fpga-dfl-fme-mgr-fix-potential-endian-issue.patch new file mode 100644 index 0000000..9015d30 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0019-fpga-dfl-fme-mgr-fix-potential-endian-issue.patch @@ -0,0 +1,68 @@ +From c7804f1dd0c3f780c2e7a3fda69d503d113ea878 Mon Sep 17 00:00:00 2001 +From: Xu Yilun +Date: Fri, 18 Jun 2021 15:58:24 +0800 +Subject: [PATCH] fpga: dfl: fme-mgr: fix potential endian issue + +The PR engine pushes 32 bit PR data to FPGA in one batch. But it +requires host to issue a 64bit write to FME_PR_DATA register, with all +upper 32 bits being 0. + +So the driver needs to expand each 32 bit data to 64 bit then write to +hardware. During the process the byte will be swapped in big endian +systems. + +This patch uses memcpy() and __raw_writeX() calls, which ensure no byte +swap during the process. + +Signed-off-by: Xu Yilun +--- + drivers/fpga/dfl-fme-mgr.c | 20 +++++++++++++++----- + 1 file changed, 15 insertions(+), 5 deletions(-) + +diff --git a/drivers/fpga/dfl-fme-mgr.c b/drivers/fpga/dfl-fme-mgr.c +index da3cb9c35de5..9293bc5e133c 100644 +--- a/drivers/fpga/dfl-fme-mgr.c ++++ b/drivers/fpga/dfl-fme-mgr.c +@@ -162,6 +162,16 @@ static int fme_mgr_write_init(struct fpga_manager *mgr, + return 0; + } + ++static inline void pr_data_write(u64 val, void __iomem *addr) ++{ ++#ifdef CONFIG_64BIT ++ __raw_writeq(val, addr); ++#else ++ __raw_writel(val >> 32, addr + 4); ++ __raw_writel(val, addr); ++#endif ++} ++ + static int fme_mgr_write(struct fpga_manager *mgr, + const char *buf, size_t count) + { +@@ -169,7 +179,7 @@ static int fme_mgr_write(struct fpga_manager *mgr, + struct fme_mgr_priv *priv = mgr->priv; + void __iomem *fme_pr = priv->ioaddr; + u64 pr_ctrl, pr_status, pr_data; +- int delay = 0, pr_credit, i = 0; ++ int delay = 0, pr_credit; + + dev_dbg(dev, "start request\n"); + +@@ -206,12 +216,12 @@ static int fme_mgr_write(struct fpga_manager *mgr, + } + + pr_data = 0; +- pr_data |= FIELD_PREP(FME_PR_DATA_PR_DATA_RAW, +- *(((u32 *)buf) + i)); +- writeq(pr_data, fme_pr + FME_PR_DATA); ++ memcpy(&pr_data, buf, 4); ++ pr_data_write(pr_data, fme_pr + FME_PR_DATA); ++ ++ buf += 4; + count -= 4; + pr_credit--; +- i++; + } + + return 0; diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0020-fpga-dfl-move-the-handling-of-unaligned-image-size-i.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0020-fpga-dfl-move-the-handling-of-unaligned-image-size-i.patch new file mode 100644 index 0000000..df08860 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0020-fpga-dfl-move-the-handling-of-unaligned-image-size-i.patch @@ -0,0 +1,95 @@ +From 75a8c932fe56a52f2c7ee08a83f07b190830ad11 Mon Sep 17 00:00:00 2001 +From: Xu Yilun +Date: Fri, 18 Jun 2021 15:58:25 +0800 +Subject: [PATCH] fpga: dfl: move the handling of unaligned image size in fpga + mgr ops + +This is to better support the fpga APIs. Callers then don't have to +care about the specific image size alignment of the DFL PR engine. + +Signed-off-by: Xu Yilun +Signed-off-by: Jeff Boyd +--- + drivers/fpga/dfl-fme-mgr.c | 12 +++++------- + drivers/fpga/dfl-fme-pr.c | 13 +++---------- + 2 files changed, 8 insertions(+), 17 deletions(-) + +diff --git a/drivers/fpga/dfl-fme-mgr.c b/drivers/fpga/dfl-fme-mgr.c +index 9293bc5e133c..13d4473147a4 100644 +--- a/drivers/fpga/dfl-fme-mgr.c ++++ b/drivers/fpga/dfl-fme-mgr.c +@@ -180,6 +180,7 @@ static int fme_mgr_write(struct fpga_manager *mgr, + void __iomem *fme_pr = priv->ioaddr; + u64 pr_ctrl, pr_status, pr_data; + int delay = 0, pr_credit; ++ size_t chunk_size; + + dev_dbg(dev, "start request\n"); + +@@ -210,17 +211,14 @@ static int fme_mgr_write(struct fpga_manager *mgr, + pr_credit = FIELD_GET(FME_PR_STS_PR_CREDIT, pr_status); + } + +- if (count < 4) { +- dev_err(dev, "Invalid PR bitstream size\n"); +- return -EINVAL; +- } ++ chunk_size = min_t(size_t, count, 4); + + pr_data = 0; +- memcpy(&pr_data, buf, 4); ++ memcpy(&pr_data, buf, chunk_size); + pr_data_write(pr_data, fme_pr + FME_PR_DATA); + +- buf += 4; +- count -= 4; ++ buf += chunk_size; ++ count -= chunk_size; + pr_credit--; + } + +diff --git a/drivers/fpga/dfl-fme-pr.c b/drivers/fpga/dfl-fme-pr.c +index 2932d203a045..619db98b7011 100644 +--- a/drivers/fpga/dfl-fme-pr.c ++++ b/drivers/fpga/dfl-fme-pr.c +@@ -74,7 +74,6 @@ static int fme_pr(struct platform_device *pdev, unsigned long arg) + struct dfl_fme *fme; + unsigned long minsz; + void *buf = NULL; +- size_t length; + int ret = 0; + u64 v; + +@@ -83,7 +82,7 @@ static int fme_pr(struct platform_device *pdev, unsigned long arg) + if (copy_from_user(&port_pr, argp, minsz)) + return -EFAULT; + +- if (port_pr.argsz < minsz || port_pr.flags) ++ if (port_pr.argsz < minsz || port_pr.flags || !port_pr.buffer_size) + return -EINVAL; + + /* get fme header region */ +@@ -96,13 +95,7 @@ static int fme_pr(struct platform_device *pdev, unsigned long arg) + return -EINVAL; + } + +- /* +- * align PR buffer per PR bandwidth, as HW ignores the extra padding +- * data automatically. +- */ +- length = ALIGN(port_pr.buffer_size, 4); +- +- buf = vmalloc(length); ++ buf = vmalloc(port_pr.buffer_size); + if (!buf) + return -ENOMEM; + +@@ -139,7 +132,7 @@ static int fme_pr(struct platform_device *pdev, unsigned long arg) + fpga_image_info_free(region->info); + + info->buf = buf; +- info->count = length; ++ info->count = port_pr.buffer_size; + info->region_id = port_pr.port_id; + region->info = info; + diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0021-fpga-dfl-fme-fix-kernel-doc-comments-for-some-functi.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0021-fpga-dfl-fme-fix-kernel-doc-comments-for-some-functi.patch new file mode 100644 index 0000000..7b030ae --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0021-fpga-dfl-fme-fix-kernel-doc-comments-for-some-functi.patch @@ -0,0 +1,41 @@ +From f4ea011cd0387aa577236d53900de05b3c9d3fca Mon Sep 17 00:00:00 2001 +From: Xu Yilun +Date: Thu, 24 Jun 2021 13:34:30 +0800 +Subject: [PATCH] fpga: dfl: fme: fix kernel-doc comments for some functions + +lkp reported 2 build warnings: + + drivers/fpga/dfl/dfl-fme-pr.c:175: warning: Function parameter or member 'feature' not described in 'dfl_fme_create_mgr' + +>> drivers/fpga/dfl/dfl-fme-pr.c:280: warning: expecting prototype for +>> dfl_fme_destroy_bridge(). Prototype was for dfl_fme_destroy_bridges() +>> instead + +Fixes: 29de76240e86 ("fpga: dfl: fme: add partial reconfiguration sub feature support") +Reported-by: kernel test robot +Signed-off-by: Xu Yilun +--- + drivers/fpga/dfl-fme-pr.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/fpga/dfl-fme-pr.c b/drivers/fpga/dfl-fme-pr.c +index 619db98b7011..2d1f7718e883 100644 +--- a/drivers/fpga/dfl-fme-pr.c ++++ b/drivers/fpga/dfl-fme-pr.c +@@ -158,6 +158,7 @@ static int fme_pr(struct platform_device *pdev, unsigned long arg) + * dfl_fme_create_mgr - create fpga mgr platform device as child device + * @feature: sub feature info + * @pdata: fme platform_device's pdata ++ * @feature: the dfl fme PR sub feature + * + * Return: mgr platform device if successful, and error code otherwise. + */ +@@ -265,7 +266,7 @@ static void dfl_fme_destroy_bridge(struct dfl_fme_bridge *fme_br) + } + + /** +- * dfl_fme_destroy_bridges - destroy all fpga bridge platform device ++ * dfl_fme_destroy_bridges - destroy all fpga bridge platform devices + * @fdata: fme feature dev data + */ + static void dfl_fme_destroy_bridges(struct dfl_feature_dev_data *fdata) diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0022-fpga-dfl-fix-VF-creation-when-ports-have-no-local-BA.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0022-fpga-dfl-fix-VF-creation-when-ports-have-no-local-BA.patch new file mode 100644 index 0000000..0bb8830 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0022-fpga-dfl-fix-VF-creation-when-ports-have-no-local-BA.patch @@ -0,0 +1,44 @@ +From 9411f1666ebb7b98ca434baa310aba9132a89d0b Mon Sep 17 00:00:00 2001 +From: Matthew Gerlach +Date: Tue, 8 Jun 2021 08:30:46 -0700 +Subject: [PATCH] fpga: dfl: fix VF creation when ports have no local BAR space + +When a port is not connected to the same PCIe endpoint as +the FME, the port does not need to be released before being +virtualized. Fix VF creation code to handle this new use +case. + +Signed-off-by: Matthew Gerlach +--- + drivers/fpga/dfl.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/drivers/fpga/dfl.c b/drivers/fpga/dfl.c +index dcd90c0cbe5b..0755fbe85c62 100644 +--- a/drivers/fpga/dfl.c ++++ b/drivers/fpga/dfl.c +@@ -1910,15 +1910,22 @@ EXPORT_SYMBOL_GPL(dfl_fpga_cdev_config_ports_pf); + int dfl_fpga_cdev_config_ports_vf(struct dfl_fpga_cdev *cdev, int num_vfs) + { + struct dfl_feature_dev_data *fdata; +- int ret = 0; ++ int ret = 0, port_count = 0; + + mutex_lock(&cdev->lock); ++ ++ list_for_each_entry(fdata, &cdev->port_dev_list, node) { ++ if (fdata->dev) ++ continue; ++ port_count++; ++ } ++ + /* + * can't turn multiple ports into 1 VF device, only 1 port for 1 VF + * device, so if released port number doesn't match VF device number, + * then reject the request with -EINVAL error code. + */ +- if (cdev->released_port_num != num_vfs) { ++ if (port_count && (cdev->released_port_num != num_vfs)) { + ret = -EINVAL; + goto done; + } diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0023-fpga-dfl-handle-empty-port-list.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0023-fpga-dfl-handle-empty-port-list.patch new file mode 100644 index 0000000..3eb8def --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0023-fpga-dfl-handle-empty-port-list.patch @@ -0,0 +1,27 @@ +From 14b66ead129e54790db5172b7d8d9c080586c5a9 Mon Sep 17 00:00:00 2001 +From: Matthew Gerlach +Date: Mon, 11 Jan 2021 10:52:56 -0800 +Subject: [PATCH] fpga: dfl: handle empty port list + +Not all FPGA designs managed by the DFL driver have a port. +In these cases, don't write the Port Access Control register +when enabling SRIOV. + +Signed-off-by: Matthew Gerlach +--- + drivers/fpga/dfl.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/fpga/dfl.c b/drivers/fpga/dfl.c +index 0755fbe85c62..455ec70799b8 100644 +--- a/drivers/fpga/dfl.c ++++ b/drivers/fpga/dfl.c +@@ -1913,6 +1913,8 @@ int dfl_fpga_cdev_config_ports_vf(struct dfl_fpga_cdev *cdev, int num_vfs) + int ret = 0, port_count = 0; + + mutex_lock(&cdev->lock); ++ if (list_empty(&cdev->port_dev_list)) ++ goto done; + + list_for_each_entry(fdata, &cdev->port_dev_list, node) { + if (fdata->dev) diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0024-fpga-dfl-Handle-dfl-s-starting-with-AFU.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0024-fpga-dfl-Handle-dfl-s-starting-with-AFU.patch new file mode 100644 index 0000000..26efc74 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0024-fpga-dfl-Handle-dfl-s-starting-with-AFU.patch @@ -0,0 +1,81 @@ +From 552942daeac672f3583d61eeaf172568bdcc04d3 Mon Sep 17 00:00:00 2001 +From: Matthew Gerlach +Date: Tue, 1 Jun 2021 10:15:15 -0700 +Subject: [PATCH] fpga: dfl: Handle dfl's starting with AFU + +Allow for a Device Feature List (DFL) to start with +a Device Feature Header (DFH) of type Accelerator Function Unit (AFU) +by doing nothing. This allows for PCIe VFs to be created. + +Signed-off-by: Matthew Gerlach +--- + drivers/fpga/dfl-pci.c | 7 ++++++- + drivers/fpga/dfl.c | 23 ++++++++++++++--------- + 2 files changed, 20 insertions(+), 10 deletions(-) + +diff --git a/drivers/fpga/dfl-pci.c b/drivers/fpga/dfl-pci.c +index d1c04e16c9b9..e0640b2431ee 100644 +--- a/drivers/fpga/dfl-pci.c ++++ b/drivers/fpga/dfl-pci.c +@@ -303,7 +303,12 @@ static int find_dfls_by_default(struct pci_dev *pcidev, + + dfl_fpga_enum_info_add_dfl(info, start, len); + } else { +- ret = -ENODEV; ++ v = readq(base + DFH); ++ if (FIELD_GET(DFH_TYPE, v) != DFH_TYPE_AFU) { ++ dev_info(&pcidev->dev, "Unknown feature type 0x%llx id 0x%llx\n", ++ FIELD_GET(DFH_TYPE, v), FIELD_GET(DFH_ID, v)); ++ ret = -ENODEV; ++ } + } + + /* release I/O mappings for next step enumeration */ +diff --git a/drivers/fpga/dfl.c b/drivers/fpga/dfl.c +index 455ec70799b8..d87baf261391 100644 +--- a/drivers/fpga/dfl.c ++++ b/drivers/fpga/dfl.c +@@ -971,9 +971,11 @@ static void build_info_free(struct build_feature_devs_info *binfo) + { + struct dfl_feature_info *finfo, *p; + +- list_for_each_entry_safe(finfo, p, &binfo->sub_features, node) { +- list_del(&finfo->node); +- kfree(finfo); ++ if (!list_empty(&binfo->sub_features)) { ++ list_for_each_entry_safe(finfo, p, &binfo->sub_features, node) { ++ list_del(&finfo->node); ++ kfree(finfo); ++ } + } + + devm_kfree(binfo->dev, binfo); +@@ -1666,6 +1668,7 @@ dfl_fpga_feature_devs_enumerate(struct dfl_fpga_enum_info *info) + binfo->type = DFL_ID_MAX; + binfo->dev = info->dev; + binfo->cdev = cdev; ++ INIT_LIST_HEAD(&binfo->sub_features); + + binfo->nr_irqs = info->nr_irqs; + if (info->nr_irqs) +@@ -1675,12 +1678,14 @@ dfl_fpga_feature_devs_enumerate(struct dfl_fpga_enum_info *info) + * start enumeration for all feature devices based on Device Feature + * Lists. + */ +- list_for_each_entry(dfl, &info->dfls, node) { +- ret = parse_feature_list(binfo, dfl->start, dfl->len); +- if (ret) { +- remove_feature_devs(cdev); +- build_info_free(binfo); +- goto unregister_region_exit; ++ if (!list_empty(&info->dfls)) { ++ list_for_each_entry(dfl, &info->dfls, node) { ++ ret = parse_feature_list(binfo, dfl->start, dfl->len); ++ if (ret) { ++ remove_feature_devs(cdev); ++ build_info_free(binfo); ++ goto unregister_region_exit; ++ } + } + } + diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0025-fpga-dfl-add-an-API-to-get-the-base-device-for-dfl-d.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0025-fpga-dfl-add-an-API-to-get-the-base-device-for-dfl-d.patch new file mode 100644 index 0000000..dea81e0 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0025-fpga-dfl-add-an-API-to-get-the-base-device-for-dfl-d.patch @@ -0,0 +1,55 @@ +From b7cbdec6580bcf4d4bb421a9d3a9a1a04e180678 Mon Sep 17 00:00:00 2001 +From: Xu Yilun +Date: Tue, 21 Apr 2020 22:51:00 +0800 +Subject: [PATCH] fpga: dfl: add an API to get the base device for dfl device + +This patch adds an API for dfl devices to find which physical device +owns the DFL. + +This patch makes preparation for supporting DFL Ether Group private +feature driver. It uses this information to determine which retimer +device physically connects to which ether group. + +Signed-off-by: Xu Yilun +Reviewed-by: Matthew Gerlach +---- +v2: change commit msg according to Matthew's suggestion. +v3: no change. +--- + drivers/fpga/dfl.c | 9 +++++++++ + include/linux/dfl.h | 2 ++ + 2 files changed, 11 insertions(+) + +diff --git a/drivers/fpga/dfl.c b/drivers/fpga/dfl.c +index d87baf261391..62a48f4b4038 100644 +--- a/drivers/fpga/dfl.c ++++ b/drivers/fpga/dfl.c +@@ -509,6 +509,15 @@ void dfl_driver_unregister(struct dfl_driver *dfl_drv) + } + EXPORT_SYMBOL(dfl_driver_unregister); + ++struct device *dfl_dev_get_base_dev(struct dfl_device *dfl_dev) ++{ ++ if (!dfl_dev || !dfl_dev->cdev) ++ return NULL; ++ ++ return dfl_dev->cdev->parent; ++} ++EXPORT_SYMBOL_GPL(dfl_dev_get_base_dev); ++ + #define is_header_feature(feature) ((feature)->id == FEATURE_ID_FIU_HEADER) + + /** +diff --git a/include/linux/dfl.h b/include/linux/dfl.h +index a62449b70708..f230befc9efe 100644 +--- a/include/linux/dfl.h ++++ b/include/linux/dfl.h +@@ -75,6 +75,8 @@ struct dfl_driver { + #define to_dfl_dev(d) container_of(d, struct dfl_device, dev) + #define to_dfl_drv(d) container_of(d, struct dfl_driver, drv) + ++struct device *dfl_dev_get_base_dev(struct dfl_device *dfl_dev); ++ + /* + * use a macro to avoid include chaining to get THIS_MODULE. + */ diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0026-fpga-m10bmc-sec-add-n5010-device-id.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0026-fpga-m10bmc-sec-add-n5010-device-id.patch new file mode 100644 index 0000000..6e80787 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0026-fpga-m10bmc-sec-add-n5010-device-id.patch @@ -0,0 +1,47 @@ +From d3d3c088e0524eacb45fea947169c2d545b0d99f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Martin=20Hundeb=C3=B8ll?= +Date: Mon, 1 Feb 2021 13:20:46 +0100 +Subject: [PATCH] fpga: m10bmc-sec: add n5010 device id +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The Silicom n5010 PAC features the max10 bmc secure funtionality, so add +it to the list of device id's, and enable it in the intel-m10-bmc +multi-function driver. + +Co-developed-by: Martin Hundebøll +Signed-off-by: Martin Hundebøll +Signed-off-by: Ilpo Järvinen +--- + drivers/fpga/intel-m10-bmc-sec-update.c | 4 ++++ + drivers/mfd/intel-m10-bmc-spi.c | 1 + + 2 files changed, 5 insertions(+) + +diff --git a/drivers/fpga/intel-m10-bmc-sec-update.c b/drivers/fpga/intel-m10-bmc-sec-update.c +index ecd7959ce8aa..072552da8007 100644 +--- a/drivers/fpga/intel-m10-bmc-sec-update.c ++++ b/drivers/fpga/intel-m10-bmc-sec-update.c +@@ -1116,6 +1116,10 @@ static const struct platform_device_id intel_m10bmc_sec_ids[] = { + .name = "d5005bmc-sec-update", + .driver_data = (kernel_ulong_t)&m10sec_d5005_ops, + }, ++ { ++ .name = "n5010bmc-sec-update", ++ .driver_data = (kernel_ulong_t)&m10sec_d5005_ops, ++ }, + { + .name = "n6000bmc-sec-update", + .driver_data = (kernel_ulong_t)&m10sec_n6000_ops, +diff --git a/drivers/mfd/intel-m10-bmc-spi.c b/drivers/mfd/intel-m10-bmc-spi.c +index d64d28199df6..eb19b2e6a858 100644 +--- a/drivers/mfd/intel-m10-bmc-spi.c ++++ b/drivers/mfd/intel-m10-bmc-spi.c +@@ -133,6 +133,7 @@ static const struct regmap_range m10bmc_n3000_fw_handshake_regs[] = { + + static struct mfd_cell m10bmc_n5010_subdevs[] = { + { .name = "n5010bmc-hwmon" }, ++ { .name = "n5010bmc-sec-update" }, + }; + + static const struct intel_m10bmc_platform_info m10bmc_spi_n3000 = { diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0027-fpga-dfl-Add-PCI-IDs-for-new-N5013-and-N5014-cards.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0027-fpga-dfl-Add-PCI-IDs-for-new-N5013-and-N5014-cards.patch new file mode 100644 index 0000000..e39af29 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0027-fpga-dfl-Add-PCI-IDs-for-new-N5013-and-N5014-cards.patch @@ -0,0 +1,34 @@ +From c856ed915eebbd1442fd97a4686c79f21a6555d0 Mon Sep 17 00:00:00 2001 +From: Roger Christensen +Date: Wed, 24 Aug 2022 14:23:18 +0200 +Subject: [PATCH] fpga:dfl: Add PCI IDs for new N5013 and N5014 cards + +Add PCI IDs to support the Silicom N5013 and N5014 cards. + +Signed-off-by: Roger Christensen +--- + drivers/fpga/dfl-pci.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/fpga/dfl-pci.c b/drivers/fpga/dfl-pci.c +index e0640b2431ee..6d5b9de484e7 100644 +--- a/drivers/fpga/dfl-pci.c ++++ b/drivers/fpga/dfl-pci.c +@@ -76,6 +76,8 @@ static void cci_pci_free_irq(struct pci_dev *pcidev) + #define PCIE_DEVICE_ID_INTEL_PAC_D5005 0x0B2B + #define PCIE_DEVICE_ID_SILICOM_PAC_N5010 0x1000 + #define PCIE_DEVICE_ID_SILICOM_PAC_N5011 0x1001 ++#define PCIE_DEVICE_ID_SILICOM_PAC_N5013 0x1002 ++#define PCIE_DEVICE_ID_SILICOM_PAC_N5014 0x1003 + #define PCIE_DEVICE_ID_INTEL_DFL 0xbcce + /* PCI Subdevice ID for PCIE_DEVICE_ID_INTEL_DFL */ + #define PCIE_SUBDEVICE_ID_INTEL_N6000 0x1770 +@@ -101,6 +103,8 @@ static struct pci_device_id cci_pcie_id_tbl[] = { + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_PAC_D5005_VF),}, + {PCI_DEVICE(PCI_VENDOR_ID_SILICOM_DENMARK, PCIE_DEVICE_ID_SILICOM_PAC_N5010),}, + {PCI_DEVICE(PCI_VENDOR_ID_SILICOM_DENMARK, PCIE_DEVICE_ID_SILICOM_PAC_N5011),}, ++ {PCI_DEVICE(PCI_VENDOR_ID_SILICOM_DENMARK, PCIE_DEVICE_ID_SILICOM_PAC_N5013),}, ++ {PCI_DEVICE(PCI_VENDOR_ID_SILICOM_DENMARK, PCIE_DEVICE_ID_SILICOM_PAC_N5014),}, + {PCI_DEVICE_SUB(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_DFL, + PCI_VENDOR_ID_INTEL, PCIE_SUBDEVICE_ID_INTEL_N6000),}, + {PCI_DEVICE_SUB(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_DFL_VF, diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0028-hwmon-intel-m10-bmc-Add-support-N5013-and-N5014.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0028-hwmon-intel-m10-bmc-Add-support-N5013-and-N5014.patch new file mode 100644 index 0000000..7d3bc22 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0028-hwmon-intel-m10-bmc-Add-support-N5013-and-N5014.patch @@ -0,0 +1,153 @@ +From f97ceac113507d59c170a0d5a7365a5713e165ac Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= +Date: Wed, 4 Jan 2023 19:42:22 +0200 +Subject: [PATCH] hwmon: intel-m10-bmc: Add support N5013 and N5014 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add sensor support for the Silicom N5013 and N5014 cards. + +Co-developed-by: Roger Christensen +Signed-off-by: Roger Christensen +Signed-off-by: Ilpo Järvinen +--- + drivers/hwmon/intel-m10-bmc-hwmon.c | 118 ++++++++++++++++++++++++++++ + 1 file changed, 118 insertions(+) + +diff --git a/drivers/hwmon/intel-m10-bmc-hwmon.c b/drivers/hwmon/intel-m10-bmc-hwmon.c +index 6500ca548f9c..232f7d428efe 100644 +--- a/drivers/hwmon/intel-m10-bmc-hwmon.c ++++ b/drivers/hwmon/intel-m10-bmc-hwmon.c +@@ -340,6 +340,120 @@ static const struct m10bmc_hwmon_board_data n5010bmc_hwmon_bdata = { + .hinfo = n5010bmc_hinfo, + }; + ++static const struct m10bmc_sdata n5014bmc_temp_tbl[] = { ++ { 0x100, 0x0, 0x104, 0x0, 0x0, 125, "Board Front Temperature" }, ++ { 0x108, 0x0, 0x10c, 0x0, 0x0, 125, "FPGA Core Temperature" }, ++ { 0x110, 0x0, 0x114, 0x0, 0x0, 125, "FPGA P-TILE Temperature" }, ++ { 0x118, 0x0, 0x11c, 0x0, 0x0, 125, "FPGA E-TILE Temperature" }, ++ { 0x120, 0x0, 0x0, 0x0, 0x0, 1000, "Board Middle Temperature" }, ++ { 0x124, 0x0, 0x0, 0x0, 0x0, 1000, "Board Rear Temperature" }, ++ { 0x130, 0x0, 0x0, 0x0, 0x0, 1000, "1V2 FPGA Temperature" }, ++ { 0x13c, 0x0, 0x0, 0x0, 0x0, 1000, "5V FPGA Temperature" }, ++ { 0x148, 0x0, 0x0, 0x0, 0x0, 1000, "0V9 FPGA Temperature" }, ++ { 0x154, 0x0, 0x0, 0x0, 0x0, 1000, "0V85 FPGA Temperature" }, ++ { 0x160, 0x0, 0x0, 0x0, 0x0, 1000, "12V AUX Temperature" }, ++ { 0x16c, 0x0, 0x0, 0x0, 0x0, 1000, "12V PCIE Temperature" }, ++ { 0x1b0, 0x0, 0x0, 0x0, 0x0, 1000, "QSFP28-1 Temperature" }, ++ { 0x1b4, 0x0, 0x0, 0x0, 0x0, 1000, "QSFP28-2 Temperature" }, ++ { 0x1b8, 0x0, 0x0, 0x0, 0x0, 1000, "QSFP28-3 Temperature" }, ++ { 0x1bc, 0x0, 0x0, 0x0, 0x0, 1000, "QSFP28-4 Temperature" }, ++ { 0x1c0, 0x0, 0x0, 0x0, 0x0, 1000, "CVL1 Internal Temperature" }, ++ { 0x1c4, 0x0, 0x0, 0x0, 0x0, 1000, "CVL2 Internal Temperature" }, ++}; ++ ++static const struct m10bmc_sdata n5014bmc_in_tbl[] = { ++ { 0x128, 0x0, 0x0, 0x0, 0x0, 1, "1V2 FPGA Voltage" }, ++ { 0x134, 0x0, 0x0, 0x0, 0x0, 1, "5V FPGA Voltage" }, ++ { 0x140, 0x0, 0x0, 0x0, 0x0, 1, "0V9 FPGA Voltage" }, ++ { 0x14c, 0x0, 0x0, 0x0, 0x0, 1, "0V85 FPGA Voltage" }, ++ { 0x158, 0x0, 0x0, 0x0, 0x0, 1, "12V AUX Voltage" }, ++ { 0x164, 0x0, 0x0, 0x0, 0x0, 1, "12V PCIE Voltage" }, ++ { 0x174, 0x0, 0x0, 0x0, 0x0, 1, "CVL2 0V9 Voltage" }, ++ { 0x17c, 0x0, 0x0, 0x0, 0x0, 1, "1V2 Voltage" }, ++ { 0x184, 0x0, 0x0, 0x0, 0x0, 1, "FPGA 1V8 Voltage" }, ++ { 0x194, 0x0, 0x0, 0x0, 0x0, 1, "CVL1 0V8 Voltage" }, ++ { 0x19c, 0x0, 0x0, 0x0, 0x0, 1, "CVL1 0V9 Voltage" }, ++ { 0x1a4, 0x0, 0x0, 0x0, 0x0, 1, "CVL2 0V8 Voltage" }, ++ { 0x1ac, 0x0, 0x0, 0x0, 0x0, 1, "CVL1/2 AVDD_ETH 0V9 Voltage" }, ++}; ++ ++static const struct m10bmc_sdata n5014bmc_curr_tbl[] = { ++ { 0x12c, 0x0, 0x0, 0x0, 0x0, 1, "1V2 FPGA Current" }, ++ { 0x138, 0x0, 0x0, 0x0, 0x0, 1, "5V FPGA Current" }, ++ { 0x144, 0x0, 0x0, 0x0, 0x0, 1, "0V9 FPGA Current" }, ++ { 0x150, 0x0, 0x0, 0x0, 0x0, 1, "0V85 FPGA Current" }, ++ { 0x15c, 0x0, 0x0, 0x0, 0x0, 1, "12V AUX Current" }, ++ { 0x168, 0x0, 0x0, 0x0, 0x0, 1, "12V PCIE Current" }, ++ { 0x170, 0x0, 0x0, 0x0, 0x0, 1, "CVL2 0V9 Current" }, ++ { 0x178, 0x0, 0x0, 0x0, 0x0, 1, "1V2 Current" }, ++ { 0x180, 0x0, 0x0, 0x0, 0x0, 1, "FPGA 1V8 Current" }, ++ { 0x190, 0x0, 0x0, 0x0, 0x0, 1, "CVL1 0V8 Current" }, ++ { 0x198, 0x0, 0x0, 0x0, 0x0, 1, "CVL1 0V9 Current" }, ++ { 0x1a0, 0x0, 0x0, 0x0, 0x0, 1, "CVL2 0V8 Current" }, ++ { 0x1a8, 0x0, 0x0, 0x0, 0x0, 1, "CVL1/2 AVDD_ETH 0V9 Current" }, ++}; ++ ++static const struct hwmon_channel_info *n5014bmc_hinfo[] = { ++ HWMON_CHANNEL_INFO(temp, ++ HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL), ++ HWMON_CHANNEL_INFO(in, ++ HWMON_I_INPUT | HWMON_I_LABEL, ++ HWMON_I_INPUT | HWMON_I_LABEL, ++ HWMON_I_INPUT | HWMON_I_LABEL, ++ HWMON_I_INPUT | HWMON_I_LABEL, ++ HWMON_I_INPUT | HWMON_I_LABEL, ++ HWMON_I_INPUT | HWMON_I_LABEL, ++ HWMON_I_INPUT | HWMON_I_LABEL, ++ HWMON_I_INPUT | HWMON_I_LABEL, ++ HWMON_I_INPUT | HWMON_I_LABEL, ++ HWMON_I_INPUT | HWMON_I_LABEL, ++ HWMON_I_INPUT | HWMON_I_LABEL, ++ HWMON_I_INPUT | HWMON_I_LABEL, ++ HWMON_I_INPUT | HWMON_I_LABEL), ++ HWMON_CHANNEL_INFO(curr, ++ HWMON_C_INPUT | HWMON_C_LABEL, ++ HWMON_C_INPUT | HWMON_C_LABEL, ++ HWMON_C_INPUT | HWMON_C_LABEL, ++ HWMON_C_INPUT | HWMON_C_LABEL, ++ HWMON_C_INPUT | HWMON_C_LABEL, ++ HWMON_C_INPUT | HWMON_C_LABEL, ++ HWMON_C_INPUT | HWMON_C_LABEL, ++ HWMON_C_INPUT | HWMON_C_LABEL, ++ HWMON_C_INPUT | HWMON_C_LABEL, ++ HWMON_C_INPUT | HWMON_C_LABEL, ++ HWMON_C_INPUT | HWMON_C_LABEL, ++ HWMON_C_INPUT | HWMON_C_LABEL, ++ HWMON_C_INPUT | HWMON_C_LABEL), ++ NULL ++}; ++ ++static const struct m10bmc_hwmon_board_data n5014bmc_hwmon_bdata = { ++ .tables = { ++ [hwmon_temp] = n5014bmc_temp_tbl, ++ [hwmon_in] = n5014bmc_in_tbl, ++ [hwmon_curr] = n5014bmc_curr_tbl, ++ }, ++ ++ .hinfo = n5014bmc_hinfo, ++}; ++ + static const struct m10bmc_sdata n6000bmc_temp_tbl[] = { + { 0x444, 0x448, 0x44c, 0x0, 0x0, 500, "FPGA E-TILE Temperature #1" }, + { 0x450, 0x454, 0x458, 0x0, 0x0, 500, "FPGA E-TILE Temperature #2" }, +@@ -774,6 +888,10 @@ static const struct platform_device_id intel_m10bmc_hwmon_ids[] = { + .name = "n5010bmc-hwmon", + .driver_data = (unsigned long)&n5010bmc_hwmon_bdata, + }, ++ { ++ .name = "n5014bmc-hwmon", ++ .driver_data = (unsigned long)&n5014bmc_hwmon_bdata, ++ }, + { + .name = "n6000bmc-hwmon", + .driver_data = (unsigned long)&n6000bmc_hwmon_bdata, diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0029-spi-spi-altera-dfl-Add-support-for-N5013-and-N5014.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0029-spi-spi-altera-dfl-Add-support-for-N5013-and-N5014.patch new file mode 100644 index 0000000..0b52a66 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0029-spi-spi-altera-dfl-Add-support-for-N5013-and-N5014.patch @@ -0,0 +1,35 @@ +From 6e423ff7394dfe7f01f9a10962847f7c3aeee783 Mon Sep 17 00:00:00 2001 +From: Roger Christensen +Date: Wed, 24 Aug 2022 14:23:18 +0200 +Subject: [PATCH] spi: spi-altera-dfl: Add support for N5013 and N5014 + +The N5013 and N5014 cards are recognized by the Device Feature Header +revision number. Extend the spi-altera-dfl driver to recognize and +support these cards. + +Signed-off-by: Roger Christensen +--- + drivers/spi/spi-altera-dfl.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/spi/spi-altera-dfl.c b/drivers/spi/spi-altera-dfl.c +index 5d6e08c12dff..8b32956ac380 100644 +--- a/drivers/spi/spi-altera-dfl.c ++++ b/drivers/spi/spi-altera-dfl.c +@@ -24,6 +24,7 @@ + + #define FME_FEATURE_ID_MAX10_SPI 0xe + #define FME_FEATURE_REV_MAX10_SPI_N5010 0x1 ++#define FME_FEATURE_REV_MAX10_SPI_N5014 0x2 + + #define SPI_CORE_PARAMETER 0x8 + #define SHIFT_MODE BIT_ULL(1) +@@ -165,6 +166,8 @@ static int dfl_spi_altera_probe(struct dfl_device *dfl_dev) + + if (dfl_dev->revision == FME_FEATURE_REV_MAX10_SPI_N5010) + strscpy(board_info.modalias, "m10-n5010", SPI_NAME_SIZE); ++ else if (dfl_dev->revision == FME_FEATURE_REV_MAX10_SPI_N5014) ++ strscpy(board_info.modalias, "m10-n5014", SPI_NAME_SIZE); + else + strscpy(board_info.modalias, "m10-d5005", SPI_NAME_SIZE); + diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0030-mfd-intel-m10-bmc-Extend-BMC-for-N5013-and-N5014.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0030-mfd-intel-m10-bmc-Extend-BMC-for-N5013-and-N5014.patch new file mode 100644 index 0000000..534ffd1 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0030-mfd-intel-m10-bmc-Extend-BMC-for-N5013-and-N5014.patch @@ -0,0 +1,55 @@ +From 80e1895e6a39c957c6c80a11f9ce787342e8b766 Mon Sep 17 00:00:00 2001 +From: Roger Christensen +Date: Wed, 24 Aug 2022 14:23:18 +0200 +Subject: [PATCH] mfd: intel-m10-bmc: Extend BMC for N5013 and N5014 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Extend the MAX10 BMC driver to include support for the Silicom N5013 and +N5014 cards under the common name of N5014. + +Co-developed-by: Roger Christensen +Signed-off-by: Roger Christensen +Signed-off-by: Ilpo Järvinen +--- + drivers/mfd/intel-m10-bmc-spi.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/mfd/intel-m10-bmc-spi.c b/drivers/mfd/intel-m10-bmc-spi.c +index eb19b2e6a858..b7904145f518 100644 +--- a/drivers/mfd/intel-m10-bmc-spi.c ++++ b/drivers/mfd/intel-m10-bmc-spi.c +@@ -136,6 +136,12 @@ static struct mfd_cell m10bmc_n5010_subdevs[] = { + { .name = "n5010bmc-sec-update" }, + }; + ++static struct mfd_cell m10bmc_n5014_subdevs[] = { ++ { .name = "n5014bmc-hwmon" }, ++ { .name = "n5010bmc-sec-update" }, ++ { .name = "n5010bmc-phy" }, ++}; ++ + static const struct intel_m10bmc_platform_info m10bmc_spi_n3000 = { + .cells = m10bmc_pacn3000_subdevs, + .n_cells = ARRAY_SIZE(m10bmc_pacn3000_subdevs), +@@ -160,10 +166,19 @@ static const struct intel_m10bmc_platform_info m10bmc_spi_n5010 = { + .csr_map = &m10bmc_n3000_csr_map, + }; + ++static const struct intel_m10bmc_platform_info m10bmc_spi_n5014 = { ++ .cells = m10bmc_n5014_subdevs, ++ .n_cells = ARRAY_SIZE(m10bmc_n5014_subdevs), ++ .handshake_sys_reg_ranges = m10bmc_n3000_fw_handshake_regs, ++ .handshake_sys_reg_nranges = ARRAY_SIZE(m10bmc_n3000_fw_handshake_regs), ++ .csr_map = &m10bmc_n3000_csr_map, ++}; ++ + static const struct spi_device_id m10bmc_spi_id[] = { + { "m10-n3000", (kernel_ulong_t)&m10bmc_spi_n3000 }, + { "m10-d5005", (kernel_ulong_t)&m10bmc_spi_d5005 }, + { "m10-n5010", (kernel_ulong_t)&m10bmc_spi_n5010 }, ++ { "m10-n5014", (kernel_ulong_t)&m10bmc_spi_n5014 }, + { } + }; + MODULE_DEVICE_TABLE(spi, m10bmc_spi_id); diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0031-fpga-m10bmc-sec-support-power-on-image.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0031-fpga-m10bmc-sec-support-power-on-image.patch new file mode 100644 index 0000000..04fe7b4 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0031-fpga-m10bmc-sec-support-power-on-image.patch @@ -0,0 +1,359 @@ +From d5557c5c2e6915ab861b210d90af4d591670de7b Mon Sep 17 00:00:00 2001 +From: Tianfei zhang +Date: Mon, 8 Mar 2021 07:05:20 -0500 +Subject: [PATCH] fpga: m10bmc-sec: support power on image +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch supports the ability to set a default power-on FPGA image. +Additionally, one can select the fall-back image sequence. Two sysfs +files are added to the Intel MAX10 BMC Secure driver: + +available_fpga_images (RO) +power-on-image (WO) + +The expected string to be read from available_fpga_images is: + + fpga_factory fpga_user1 fpga_user2 + +A string to be written to power-on-image is expected to be one of +the following: + + fpga_user1 + fpga_user2 + fpga_factory + fpga_factory fpga_user1 + fpga_factory fpga_user2 + +Signed-off-by: Russ Weight +Signed-off-by: Tianfei Zhang +Signed-off-by: Ilpo Järvinen +--- + .../sysfs-driver-intel-m10-bmc-sec-update | 28 +++ + drivers/fpga/intel-m10-bmc-sec-update.c | 213 ++++++++++++++++++ + include/linux/mfd/intel-m10-bmc.h | 14 ++ + 3 files changed, 255 insertions(+) + +diff --git a/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update b/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update +index cd22dab15cff..e5a300dc0dfc 100644 +--- a/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update ++++ b/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update +@@ -80,3 +80,31 @@ Description: Write-only. A key word may be written to this file to + list of supported key words for the underlying device. + Writing an unsupported string to this file will result in + EINVAL being returned. ++ ++What: /sys/bus/platform/drivers/intel-m10bmc-sec-update/.../control/available_power_on_images ++Date: Nov 2021 ++KernelVersion: 5.16 ++Contact: Tianfei zhang ++Description: Read-only. This file returns a space separated list of ++ key words that may be written into the power_on_image file ++ described below. These keywords identify the possible fpga ++ images that may be used as a default on the next boot of ++ the FPGA card. ++ ++What: /sys/bus/platform/drivers/intel-m10bmc-sec-update/.../control/power_on_image ++Date: Nov 2021 ++KernelVersion: 5.16 ++Contact: Tianfei zhang ++Description: Read/Write. A key word from the available_fpga_images file ++ may be written to this file to select the FPGA image to be ++ configured on the next boot of the FPGA card. One or more ++ additional keywords may be specified, separated by spaces, ++ to identify a sequence of fall-back images in the event that ++ the selected FPGA image fails to load. Reading this file ++ will return the space separated list of keywords identifying ++ the default power-on image and the current fall-back sequence. ++ Your specific device may not support all possible fall-back ++ sequences. The EINVAL error code will be returned if you ++ attempt to select an unsupported image or fall-back sequence. ++ Consult your product documentation for supported ++ configurations. +diff --git a/drivers/fpga/intel-m10-bmc-sec-update.c b/drivers/fpga/intel-m10-bmc-sec-update.c +index 072552da8007..c31d8bdff5eb 100644 +--- a/drivers/fpga/intel-m10-bmc-sec-update.c ++++ b/drivers/fpga/intel-m10-bmc-sec-update.c +@@ -16,6 +16,26 @@ + + struct m10bmc_sec; + ++/* Supported names for power-on images */ ++enum fpga_image { ++ FPGA_FACTORY, ++ FPGA_USER1, ++ FPGA_USER2, ++ FPGA_MAX ++}; ++ ++static const char * const fpga_image_names[] = { ++ [FPGA_FACTORY] = "fpga_factory", ++ [FPGA_USER1] = "fpga_user1", ++ [FPGA_USER2] = "fpga_user2" ++}; ++ ++struct fpga_power_on { ++ u32 avail_image_mask; ++ int (*get_sequence)(struct m10bmc_sec *sec, char *buf); ++ int (*set_sequence)(struct m10bmc_sec *sec, enum fpga_image images[]); ++}; ++ + struct image_load { + const char *name; + int (*load_image)(struct m10bmc_sec *sec); +@@ -24,6 +44,7 @@ struct image_load { + struct m10bmc_sec_ops { + int (*rsu_status)(struct m10bmc_sec *sec); + struct image_load *image_load; /* terminated with { } member */ ++ const struct fpga_power_on *poc; /* power on image configuration */ + }; + + struct m10bmc_sec { +@@ -596,6 +617,181 @@ static struct attribute_group m10bmc_security_attr_group = { + .attrs = m10bmc_security_attrs, + }; + ++static enum fpga_image ++fpga_image_by_name(struct m10bmc_sec *sec, char *image_name) ++{ ++ enum fpga_image i; ++ ++ for (i = 0; i < FPGA_MAX; i++) ++ if (sysfs_streq(image_name, fpga_image_names[i])) ++ return i; ++ ++ return FPGA_MAX; ++} ++ ++static int ++fpga_images(struct m10bmc_sec *sec, char *names, enum fpga_image images[]) ++{ ++ u32 image_mask = sec->ops->poc->avail_image_mask; ++ enum fpga_image image; ++ char *image_name; ++ int i = 0; ++ ++ while ((image_name = strsep(&names, " \n"))) { ++ image = fpga_image_by_name(sec, image_name); ++ if (image >= FPGA_MAX || !(image_mask & BIT(image))) ++ return -EINVAL; ++ ++ images[i++] = image; ++ image_mask &= ~BIT(image); ++ } ++ ++ return (i == 0) ? -EINVAL : 0; ++} ++ ++static int ++pmci_set_power_on_image(struct m10bmc_sec *sec, enum fpga_image images[]) ++{ ++ const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; ++ u32 poc_mask = PMCI_FACTORY_IMAGE_SEL|PMCI_USER_IMAGE_PAGE; ++ int ret, first_user = 0; ++ u32 val, poc = 0; ++ ++ if (images[1] == FPGA_FACTORY) ++ return -EINVAL; ++ ++ if (images[0] == FPGA_FACTORY) { ++ poc = PMCI_FACTORY_IMAGE_SEL; ++ first_user = 1; ++ } ++ ++ if (images[first_user] == FPGA_USER1 || images[first_user] == FPGA_USER2) { ++ if (images[first_user] == FPGA_USER1) ++ poc |= FIELD_PREP(PMCI_USER_IMAGE_PAGE, POC_USER_IMAGE_1); ++ else ++ poc |= FIELD_PREP(PMCI_USER_IMAGE_PAGE, POC_USER_IMAGE_2); ++ } else { ++ dev_dbg(sec->dev, "%s first_user = %d not USER1 or USER2\n", __func__, first_user); ++ ret = m10bmc_sys_read(sec->m10bmc, M10BMC_PMCI_FPGA_POC_STS_BL, &val); ++ if (ret) ++ return ret; ++ ++ if (FIELD_GET(PMCI_USER_IMAGE_PAGE, val) == POC_USER_IMAGE_1) ++ poc |= FIELD_PREP(PMCI_USER_IMAGE_PAGE, POC_USER_IMAGE_1); ++ else ++ poc |= FIELD_PREP(PMCI_USER_IMAGE_PAGE, POC_USER_IMAGE_2); ++ } ++ ++ dev_dbg(sec->dev, "%s poc = 0x%x pock_mask = 0x%x\n", __func__, poc, poc_mask); ++ ++ ret = m10bmc_sys_update_bits(sec->m10bmc, ++ csr_map->base + M10BMC_PMCI_FPGA_POC, ++ poc_mask | PMCI_FPGA_POC, poc | PMCI_FPGA_POC); ++ if (ret) { ++ dev_err(sec->dev, "%s m10bmc_sys_update_bits failed %d\n", __func__, ret); ++ return ret; ++ } ++ ++ ret = regmap_read_poll_timeout(sec->m10bmc->regmap, ++ csr_map->base + M10BMC_PMCI_FPGA_POC, ++ poc, ++ (!(poc & PMCI_FPGA_POC)), ++ NIOS_HANDSHAKE_INTERVAL_US, ++ NIOS_HANDSHAKE_TIMEOUT_US); ++ ++ if (ret || (FIELD_GET(PMCI_NIOS_STATUS, poc) != NIOS_STATUS_SUCCESS)) { ++ dev_err(sec->dev, "%s readback poc = 0x%x\n", __func__, poc); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static int pmci_get_power_on_image(struct m10bmc_sec *sec, char *buf) ++{ ++ const char *image_names[FPGA_MAX] = { 0 }; ++ int ret, i = 0; ++ u32 poc; ++ ++ ret = m10bmc_sys_read(sec->m10bmc, M10BMC_PMCI_FPGA_POC_STS_BL, &poc); ++ if (ret) ++ return ret; ++ ++ if (poc & PMCI_FACTORY_IMAGE_SEL) ++ image_names[i++] = fpga_image_names[FPGA_FACTORY]; ++ ++ if (FIELD_GET(PMCI_USER_IMAGE_PAGE, poc) == POC_USER_IMAGE_1) { ++ image_names[i++] = fpga_image_names[FPGA_USER1]; ++ image_names[i++] = fpga_image_names[FPGA_USER2]; ++ } else { ++ image_names[i++] = fpga_image_names[FPGA_USER2]; ++ image_names[i++] = fpga_image_names[FPGA_USER1]; ++ } ++ ++ if (!(poc & PMCI_FACTORY_IMAGE_SEL)) ++ image_names[i] = fpga_image_names[FPGA_FACTORY]; ++ ++ return sysfs_emit(buf, "%s %s %s\n", image_names[0], image_names[1], image_names[2]); ++} ++ ++static ssize_t ++available_power_on_images_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct m10bmc_sec *sec = dev_get_drvdata(dev); ++ ssize_t count = 0; ++ enum fpga_image i; ++ ++ for (i = 0; i < FPGA_MAX; i++) ++ if (BIT(i) & sec->ops->poc->avail_image_mask) ++ count += scnprintf(buf + count, PAGE_SIZE - count, ++ "%s ", fpga_image_names[i]); ++ buf[count - 1] = '\n'; ++ ++ return count; ++} ++static DEVICE_ATTR_RO(available_power_on_images); ++ ++static ssize_t ++power_on_image_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct m10bmc_sec *sec = dev_get_drvdata(dev); ++ ++ return sec->ops->poc->get_sequence(sec, buf); ++} ++ ++static ssize_t ++power_on_image_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ enum fpga_image images[FPGA_MAX] = { [0 ... FPGA_MAX - 1] = FPGA_MAX }; ++ struct m10bmc_sec *sec = dev_get_drvdata(dev); ++ char *tokens; ++ int ret; ++ ++ tokens = kmemdup_nul(buf, count, GFP_KERNEL); ++ if (!tokens) ++ return -ENOMEM; ++ ++ ret = fpga_images(sec, tokens, images); ++ if (ret) ++ goto free_exit; ++ ++ ret = sec->ops->poc->set_sequence(sec, images); ++ ++free_exit: ++ kfree(tokens); ++ return ret ? : count; ++} ++static DEVICE_ATTR_RW(power_on_image); ++ ++static const struct fpga_power_on pmci_power_on_image = { ++ .avail_image_mask = BIT(FPGA_FACTORY) | BIT(FPGA_USER1) | BIT(FPGA_USER2), ++ .set_sequence = pmci_set_power_on_image, ++ .get_sequence = pmci_get_power_on_image, ++}; ++ + static ssize_t available_images_show(struct device *dev, + struct device_attribute *attr, char *buf) + { +@@ -631,15 +827,31 @@ static ssize_t image_load_store(struct device *dev, + } + static DEVICE_ATTR_WO(image_load); + ++static umode_t ++m10bmc_is_visible(struct kobject *kobj, struct attribute *attr, int n) ++{ ++ struct m10bmc_sec *sec = dev_get_drvdata(kobj_to_dev(kobj)); ++ ++ if (!sec->ops->poc && ++ (attr == &dev_attr_power_on_image.attr || ++ attr == &dev_attr_available_power_on_images.attr)) ++ return 0; ++ ++ return attr->mode; ++} ++ + static struct attribute *m10bmc_control_attrs[] = { + &dev_attr_available_images.attr, + &dev_attr_image_load.attr, ++ &dev_attr_power_on_image.attr, ++ &dev_attr_available_power_on_images.attr, + NULL, + }; + + static struct attribute_group m10bmc_control_attr_group = { + .name = "control", + .attrs = m10bmc_control_attrs, ++ .is_visible = m10bmc_is_visible, + }; + + static const struct attribute_group *m10bmc_sec_attr_groups[] = { +@@ -1045,6 +1257,7 @@ static const struct m10bmc_sec_ops m10sec_d5005_ops = { + static const struct m10bmc_sec_ops m10sec_n6000_ops = { + .rsu_status = m10bmc_sec_n6000_rsu_status, + .image_load = n6000_image_load_hndlrs, ++ .poc = &pmci_power_on_image, + }; + + #define SEC_UPDATE_LEN_MAX 32 +diff --git a/include/linux/mfd/intel-m10-bmc.h b/include/linux/mfd/intel-m10-bmc.h +index f0793663585f..63093ff8bbd7 100644 +--- a/include/linux/mfd/intel-m10-bmc.h ++++ b/include/linux/mfd/intel-m10-bmc.h +@@ -71,6 +71,20 @@ + #define M10BMC_PKVL_PRELOAD_INTERVAL_US (100 * 1000) + #define M10BMC_PKVL_PRELOAD_TIMEOUT_US (30 * 1000 * 1000) + ++#define M10BMC_PMCI_FPGA_POC 0x0b0 ++#define PMCI_FPGA_POC BIT(0) ++#define PMCI_NIOS_REQ_CLEAR BIT(1) ++#define PMCI_NIOS_STATUS GENMASK(5, 4) ++#define NIOS_STATUS_IDLE 0 ++#define NIOS_STATUS_SUCCESS 1 ++#define NIOS_STATUS_FAIL 2 ++#define PMCI_USER_IMAGE_PAGE GENMASK(10, 8) ++#define POC_USER_IMAGE_1 1 ++#define POC_USER_IMAGE_2 2 ++#define PMCI_FACTORY_IMAGE_SEL BIT(31) ++ ++#define M10BMC_PMCI_FPGA_POC_STS_BL 0x0b4 ++ + /* Telemetry registers */ + #define M10BMC_N3000_TELEM_START 0x100 + #define M10BMC_N3000_TELEM_END 0x250 diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0032-net-phy-add-memory-based-QSFP-controller.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0032-net-phy-add-memory-based-QSFP-controller.patch new file mode 100644 index 0000000..5887a0f --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0032-net-phy-add-memory-based-QSFP-controller.patch @@ -0,0 +1,210 @@ +From 1faff4b2a6b516d8cb7fe1b0231a9de818b14883 Mon Sep 17 00:00:00 2001 +From: Matthew Gerlach +Date: Tue, 29 Dec 2020 10:55:17 -0800 +Subject: [PATCH] net: phy: add memory based QSFP controller + +Add a memory based QSFP controller to read QSFP information +out of the shadow registers using the regmap debugfs interface. + +Signed-off-by: Matthew Gerlach +Signed-off-by: Tianfei Zhang +--- + drivers/net/phy/Kconfig | 7 ++ + drivers/net/phy/Makefile | 2 + + drivers/net/phy/qsfp-mem.c | 156 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 165 insertions(+) + create mode 100644 drivers/net/phy/qsfp-mem.c + +diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig +index 107880d13d21..eb79aae0a0f6 100644 +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -66,6 +66,13 @@ config SFP + depends on HWMON || HWMON=n + select MDIO_I2C + ++config QSFP_MEM ++ tristate "Memory based QSFP support" ++ depends on HWMON || HWMON=n ++ help ++ Adds support for a QSFP controller that shadows the QSFP module's ++ memory pages in memory. ++ + comment "MII PHY device drivers" + + config AMD_PHY +diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile +index c945ed9bd14b..bd1dce127f4a 100644 +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -32,6 +32,8 @@ obj-$(CONFIG_SFP) += sfp.o + sfp-obj-$(CONFIG_SFP) += sfp-bus.o + obj-y += $(sfp-obj-y) $(sfp-obj-m) + ++obj-$(CONFIG_QSFP_MEM) += qsfp-mem.o ++ + obj-$(CONFIG_ADIN_PHY) += adin.o + obj-$(CONFIG_ADIN1100_PHY) += adin1100.o + obj-$(CONFIG_AMD_PHY) += amd.o +diff --git a/drivers/net/phy/qsfp-mem.c b/drivers/net/phy/qsfp-mem.c +new file mode 100644 +index 000000000000..1a6dcbbe9ff3 +--- /dev/null ++++ b/drivers/net/phy/qsfp-mem.c +@@ -0,0 +1,156 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++/* Intel(R) Memory based QSFP driver. ++ * ++ * Copyright (C) 2020 Intel Corporation. All rights reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define CONF_OFF 0x20 ++#define CONF_RST_MOD BIT(0) ++#define CONF_RST_CON BIT(1) ++#define CONF_MOD_SEL BIT(2) ++#define CONF_LOW_POW BIT(3) ++#define CONF_POLL_EN BIT(4) ++ ++#define STAT_OFF 0x28 ++#define STAT_END 0x2c ++#define DELAY_REG 0x38 ++#define DELAY_VALUE 0xffffff ++ ++#define I2C_CTRL 0x48 ++#define I2C_CTRL_EN BIT(0) ++#define I2C_CTRL_BSP BIT(1) ++#define I2C_CTRL_FIFO GENMASK(3, 2) ++#define I2C_CTRL_FIFO_NOT_FULL 3 ++ ++#define I2C_ISER 0x4c ++#define I2C_ISER_TXRDY BIT(0) ++#define I2C_ISER_RXRDY BIT(1) ++#define I2C_SCL_LOW 0x60 ++#define COUNT_PERIOD_LOW 0x82 ++#define I2C_SCL_HIGH 0x64 ++#define COUNT_PERIOD_HIGH 0x3c ++#define I2C_SDA_HOLD 0x68 ++#define COUNT_PERIOD_HOLD 0x28 ++ ++#define QSFP_SHADOW_CSRS_BASE_OFF 0x100 ++#define QSFP_SHADOW_CSRS_BASE_END 0x3fc ++ ++#define DELAY_US 1000 ++ ++struct qsfp { ++ void __iomem *base; ++ struct regmap *regmap; ++}; ++ ++/* The QSFP controller defines 64-bit wide registers, but support ++ * for 64-bit IO in regmap-mmio was removed in upstream commit ++ * 159dfabd207628c983e0c3c5ef607f496ff5e6a5. Hence the regmap ++ * register ranges are defined in terms of 32-bit wide registers. ++ */ ++static const struct regmap_range qsfp_mem_regmap_range[] = { ++ regmap_reg_range(CONF_OFF, STAT_END), ++ regmap_reg_range(QSFP_SHADOW_CSRS_BASE_OFF, QSFP_SHADOW_CSRS_BASE_END), ++}; ++ ++static const struct regmap_access_table qsfp_mem_access_table = { ++ .yes_ranges = qsfp_mem_regmap_range, ++ .n_yes_ranges = ARRAY_SIZE(qsfp_mem_regmap_range), ++}; ++ ++static void qsfp_init_i2c(struct device *dev, struct qsfp *qsfp) ++{ ++ writel(I2C_ISER_TXRDY | I2C_ISER_RXRDY, qsfp->base + I2C_ISER); ++ writel(COUNT_PERIOD_LOW, qsfp->base + I2C_SCL_LOW); ++ writel(COUNT_PERIOD_HIGH, qsfp->base + I2C_SCL_HIGH); ++ writel(COUNT_PERIOD_HOLD, qsfp->base + I2C_SDA_HOLD); ++ ++ writel(FIELD_PREP(I2C_CTRL_FIFO, I2C_CTRL_FIFO_NOT_FULL) | ++ I2C_CTRL_EN | I2C_CTRL_BSP, qsfp->base + I2C_CTRL); ++} ++ ++static const struct regmap_config mmio_cfg = { ++ .reg_bits = 32, ++ .reg_stride = 4, ++ .val_bits = 32, ++ .fast_io = true, ++ .rd_table = &qsfp_mem_access_table, ++ .max_register = QSFP_SHADOW_CSRS_BASE_END, ++}; ++ ++static int qsfp_probe(struct dfl_device *dfl_dev) ++{ ++ struct device *dev = &dfl_dev->dev; ++ struct qsfp *qsfp; ++ ++ qsfp = devm_kzalloc(dev, sizeof(*qsfp), GFP_KERNEL); ++ if (!qsfp) ++ return -ENOMEM; ++ ++ dev_set_drvdata(dev, qsfp); ++ ++ qsfp->base = devm_ioremap_resource(dev, &dfl_dev->mmio_res); ++ if (!qsfp->base) ++ return -ENOMEM; ++ ++ writeq(CONF_RST_MOD | CONF_RST_CON | CONF_MOD_SEL, ++ qsfp->base + CONF_OFF); ++ udelay(DELAY_US); ++ writeq(CONF_MOD_SEL, qsfp->base + CONF_OFF); ++ udelay(DELAY_US); ++ ++ qsfp_init_i2c(dev, qsfp); ++ ++ udelay(DELAY_US); ++ writeq(DELAY_VALUE, qsfp->base + DELAY_REG); ++ ++ writeq(CONF_POLL_EN | CONF_MOD_SEL, qsfp->base + CONF_OFF); ++ udelay(DELAY_US); ++ ++ qsfp->regmap = devm_regmap_init_mmio(dev, qsfp->base, &mmio_cfg); ++ if (IS_ERR(qsfp->regmap)) ++ dev_err(dev, "Failed to create qsfp regmap\n"); ++ ++ return PTR_ERR_OR_ZERO(qsfp->regmap); ++} ++ ++static void qsfp_remove(struct dfl_device *dfl_dev) ++{ ++ struct device *dev = &dfl_dev->dev; ++ struct qsfp *qsfp = dev_get_drvdata(dev); ++ ++ writeq(CONF_MOD_SEL, qsfp->base + CONF_OFF); ++} ++ ++#define FME_FEATURE_ID_QSFP 0x13 ++ ++static const struct dfl_device_id qsfp_ids[] = { ++ { FME_ID, FME_FEATURE_ID_QSFP }, ++ { } ++}; ++ ++static struct dfl_driver qsfp_driver = { ++ .drv = { ++ .name = "qsfp-mem", ++ }, ++ .id_table = qsfp_ids, ++ .probe = qsfp_probe, ++ .remove = qsfp_remove, ++}; ++ ++module_dfl_driver(qsfp_driver); ++MODULE_DEVICE_TABLE(dfl, qsfp_ids); ++MODULE_DESCRIPTION("Intel(R) Memory based QSFP driver"); ++MODULE_AUTHOR("Intel Corporation"); ++MODULE_LICENSE("GPL v2"); diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0033-net-phy-add-qsfp-plugin-status-checking.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0033-net-phy-add-qsfp-plugin-status-checking.patch new file mode 100644 index 0000000..825628b --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0033-net-phy-add-qsfp-plugin-status-checking.patch @@ -0,0 +1,196 @@ +From 6aa5985e4a2f45ff3d28d74582b6b7a0dcf562d8 Mon Sep 17 00:00:00 2001 +From: Tianfei zhang +Date: Wed, 13 Apr 2022 05:15:08 +0800 +Subject: [PATCH] net: phy: add qsfp plugin status checking + +Check the QSFP cable plugin status at 500ms intervals. +This is a software plugin detection using the delay worker +framework. + +Signed-off-by: Tianfei zhang +--- + drivers/net/phy/qsfp-mem.c | 120 ++++++++++++++++++++++++++++++++----- + 1 file changed, 106 insertions(+), 14 deletions(-) + +diff --git a/drivers/net/phy/qsfp-mem.c b/drivers/net/phy/qsfp-mem.c +index 1a6dcbbe9ff3..8ba3c747a106 100644 +--- a/drivers/net/phy/qsfp-mem.c ++++ b/drivers/net/phy/qsfp-mem.c +@@ -25,6 +25,7 @@ + + #define STAT_OFF 0x28 + #define STAT_END 0x2c ++#define MODPRSL BIT(0) + #define DELAY_REG 0x38 + #define DELAY_VALUE 0xffffff + +@@ -49,9 +50,29 @@ + + #define DELAY_US 1000 + ++#define QSFP_CHECK_TIME 500 ++ ++enum qsfp_init_status { ++ QSFP_INIT_RESET = 0, ++ QSFP_INIT_DONE, ++}; ++ ++/** ++ * struct qsfp - device private data structure ++ * @base: base address of the device. ++ * @regmap: regmap for device. ++ * @dwork: work struct for checking qsfp plugin status. ++ * @dev: point to dfl device. ++ * @init: qsfp init status. ++ * @lock: lock for qsfp initial function and status. ++ */ + struct qsfp { + void __iomem *base; + struct regmap *regmap; ++ struct delayed_work dwork; ++ struct device *dev; ++ enum qsfp_init_status init; ++ struct mutex lock; + }; + + /* The QSFP controller defines 64-bit wide registers, but support +@@ -69,7 +90,7 @@ static const struct regmap_access_table qsfp_mem_access_table = { + .n_yes_ranges = ARRAY_SIZE(qsfp_mem_regmap_range), + }; + +-static void qsfp_init_i2c(struct device *dev, struct qsfp *qsfp) ++static void qsfp_init_i2c(struct qsfp *qsfp) + { + writel(I2C_ISER_TXRDY | I2C_ISER_RXRDY, qsfp->base + I2C_ISER); + writel(COUNT_PERIOD_LOW, qsfp->base + I2C_SCL_LOW); +@@ -89,6 +110,82 @@ static const struct regmap_config mmio_cfg = { + .max_register = QSFP_SHADOW_CSRS_BASE_END, + }; + ++static void qsfp_init(struct qsfp *qsfp) ++{ ++ writeq(CONF_RST_MOD | CONF_RST_CON | CONF_MOD_SEL, ++ qsfp->base + CONF_OFF); ++ udelay(DELAY_US); ++ writeq(CONF_MOD_SEL, qsfp->base + CONF_OFF); ++ udelay(DELAY_US); ++ ++ qsfp_init_i2c(qsfp); ++ ++ udelay(DELAY_US); ++ writeq(DELAY_VALUE, qsfp->base + DELAY_REG); ++ ++ writeq(CONF_POLL_EN | CONF_MOD_SEL, qsfp->base + CONF_OFF); ++ udelay(DELAY_US); ++} ++ ++static int check_qsfp_plugin(struct qsfp *qsfp) ++{ ++ u64 status; ++ ++ status = readq(qsfp->base + STAT_OFF); ++ ++ return (!(status & MODPRSL)); ++} ++ ++static void qsfp_check_hotplug(struct work_struct *work) ++{ ++ struct delayed_work *dwork; ++ struct qsfp *qsfp; ++ u64 status; ++ ++ dwork = to_delayed_work(work); ++ qsfp = container_of(dwork, struct qsfp, dwork); ++ ++ mutex_lock(&qsfp->lock); ++ ++ status = readq(qsfp->base + STAT_OFF); ++ dev_dbg(qsfp->dev, "qsfp status 0x%llx\n", status); ++ ++ if (check_qsfp_plugin(qsfp) && ++ qsfp->init == QSFP_INIT_RESET) { ++ dev_info(qsfp->dev, "detected QSFP plugin\n"); ++ qsfp_init(qsfp); ++ WRITE_ONCE(qsfp->init, QSFP_INIT_DONE); ++ } else if (!check_qsfp_plugin(qsfp) && ++ qsfp->init == QSFP_INIT_DONE) { ++ dev_info(qsfp->dev, "detected QSFP unplugin\n"); ++ WRITE_ONCE(qsfp->init, QSFP_INIT_RESET); ++ } ++ mutex_unlock(&qsfp->lock); ++ ++ schedule_delayed_work(&qsfp->dwork, msecs_to_jiffies(QSFP_CHECK_TIME)); ++} ++ ++static ssize_t qsfp_connected_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct qsfp *qsfp = dev_get_drvdata(dev); ++ u32 plugin; ++ ++ mutex_lock(&qsfp->lock); ++ plugin = check_qsfp_plugin(qsfp) && (qsfp->init == QSFP_INIT_DONE); ++ mutex_unlock(&qsfp->lock); ++ ++ return sysfs_emit(buf, "%u\n", plugin); ++} ++ ++static DEVICE_ATTR_RO(qsfp_connected); ++ ++static struct attribute *qsfp_mem_attrs[] = { ++ &dev_attr_qsfp_connected.attr, ++ NULL, ++}; ++ATTRIBUTE_GROUPS(qsfp_mem); ++ + static int qsfp_probe(struct dfl_device *dfl_dev) + { + struct device *dev = &dfl_dev->dev; +@@ -98,25 +195,17 @@ static int qsfp_probe(struct dfl_device *dfl_dev) + if (!qsfp) + return -ENOMEM; + +- dev_set_drvdata(dev, qsfp); +- + qsfp->base = devm_ioremap_resource(dev, &dfl_dev->mmio_res); + if (!qsfp->base) + return -ENOMEM; + +- writeq(CONF_RST_MOD | CONF_RST_CON | CONF_MOD_SEL, +- qsfp->base + CONF_OFF); +- udelay(DELAY_US); +- writeq(CONF_MOD_SEL, qsfp->base + CONF_OFF); +- udelay(DELAY_US); +- +- qsfp_init_i2c(dev, qsfp); ++ qsfp->dev = dev; ++ mutex_init(&qsfp->lock); + +- udelay(DELAY_US); +- writeq(DELAY_VALUE, qsfp->base + DELAY_REG); ++ dev_set_drvdata(dev, qsfp); + +- writeq(CONF_POLL_EN | CONF_MOD_SEL, qsfp->base + CONF_OFF); +- udelay(DELAY_US); ++ INIT_DELAYED_WORK(&qsfp->dwork, qsfp_check_hotplug); ++ qsfp_check_hotplug(&qsfp->dwork.work); + + qsfp->regmap = devm_regmap_init_mmio(dev, qsfp->base, &mmio_cfg); + if (IS_ERR(qsfp->regmap)) +@@ -131,6 +220,8 @@ static void qsfp_remove(struct dfl_device *dfl_dev) + struct qsfp *qsfp = dev_get_drvdata(dev); + + writeq(CONF_MOD_SEL, qsfp->base + CONF_OFF); ++ ++ cancel_delayed_work_sync(&qsfp->dwork); + } + + #define FME_FEATURE_ID_QSFP 0x13 +@@ -143,6 +234,7 @@ static const struct dfl_device_id qsfp_ids[] = { + static struct dfl_driver qsfp_driver = { + .drv = { + .name = "qsfp-mem", ++ .dev_groups = qsfp_mem_groups, + }, + .id_table = qsfp_ids, + .probe = qsfp_probe, diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0034-net-phy-QSFP-controller-subsystem-driver-for-Intel-F.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0034-net-phy-QSFP-controller-subsystem-driver-for-Intel-F.patch new file mode 100644 index 0000000..88bdde9 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0034-net-phy-QSFP-controller-subsystem-driver-for-Intel-F.patch @@ -0,0 +1,727 @@ +From 7579b25b84f4d1ff6f0aa50ae7061035ca502a69 Mon Sep 17 00:00:00 2001 +From: KrishnaSimmadhari <91877513+KrishnaSimmadhari@users.noreply.github.com> +Date: Fri, 9 Dec 2022 09:21:33 +0530 +Subject: [PATCH] net: phy: QSFP controller subsystem driver for Intel FPGAs + +Qsfp controller driver to include platform and DFL interface driver. DFL driver is used +for the host which accesses the QSFP controller subsystem using the PCIe bus and +the platform driver is used where the subsystem is accessed through the AXI/AXI-Lite bus. + +Co-developed-by: Russ Weight +Signed-off-by: Russ Weight +Co-developed-by: Krishna Kumar S R +Signed-off-by: Krishna Kumar S R +--- + .../ABI/testing/sysfs-driver-qsfp-mem | 8 + + .../bindings/phy/intel,qsfp-mem.txt | 16 ++ + drivers/net/phy/Kconfig | 24 +- + drivers/net/phy/Makefile | 4 +- + .../net/phy/{qsfp-mem.c => qsfp-mem-core.c} | 244 ++++++++++-------- + drivers/net/phy/qsfp-mem-dfl.c | 80 ++++++ + drivers/net/phy/qsfp-mem-platform.c | 106 ++++++++ + include/linux/phy/qsfp-mem.h | 50 ++++ + 8 files changed, 423 insertions(+), 109 deletions(-) + create mode 100644 Documentation/ABI/testing/sysfs-driver-qsfp-mem + create mode 100644 Documentation/devicetree/bindings/phy/intel,qsfp-mem.txt + rename drivers/net/phy/{qsfp-mem.c => qsfp-mem-core.c} (54%) + create mode 100644 drivers/net/phy/qsfp-mem-dfl.c + create mode 100644 drivers/net/phy/qsfp-mem-platform.c + create mode 100644 include/linux/phy/qsfp-mem.h + +diff --git a/Documentation/ABI/testing/sysfs-driver-qsfp-mem b/Documentation/ABI/testing/sysfs-driver-qsfp-mem +new file mode 100644 +index 000000000000..b0126ce4e6d6 +--- /dev/null ++++ b/Documentation/ABI/testing/sysfs-driver-qsfp-mem +@@ -0,0 +1,8 @@ ++What: /sys/bus/.../drivers/qsfp-mem/.../qsfp_connected ++Date: February 2023 ++KernelVersion: 6.3 ++Contact: Russ Weight ++Description: Read only. Returns the plug-in status of the QSFP module. ++ 1 means that the QSFP module is connected to a live network, ++ 0 means that it is not. ++ Format: "%u". +diff --git a/Documentation/devicetree/bindings/phy/intel,qsfp-mem.txt b/Documentation/devicetree/bindings/phy/intel,qsfp-mem.txt +new file mode 100644 +index 000000000000..4a5161dc5cff +--- /dev/null ++++ b/Documentation/devicetree/bindings/phy/intel,qsfp-mem.txt +@@ -0,0 +1,16 @@ ++* Intel QSFP Memory controller subsystem ++ ++Required properties: ++- compatible: Should be "intel,qsfp-mem" ++- reg: Address and length of the register set for the device. It contains ++ the information of registers in the same order as described by reg-names ++- reg-names: Should contain the reg names ++ ++Example: ++ ++ qsfp_eth0: qsfp-eth0 { ++ compatible = "intel,qsfp-mem"; ++ reg-names = "qsfp-mem-controller"; ++ reg = <0x00000001 0x80112000 0x00001000>, ++ status = "okay"; ++ }; +diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig +index eb79aae0a0f6..0257154b48d0 100644 +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -66,12 +66,28 @@ config SFP + depends on HWMON || HWMON=n + select MDIO_I2C + +-config QSFP_MEM +- tristate "Memory based QSFP support" ++config QSFP_MEM_CORE ++ tristate "QSFP Controller subsystem core code" if COMPILE_TEST + depends on HWMON || HWMON=n + help +- Adds support for a QSFP controller that shadows the QSFP module's +- memory pages in memory. ++ The core code for the QSFP Controller subsystem for Intel FPGAs used ++ by other interafce module drivers for access to the QSFP controller ++ subsystem registers ++ ++config QSFP_MEM ++ tristate "Memory based platform driver for QSFP Controller subsystem in Intel FPGAs" ++ select QSFP_MEM_CORE ++ help ++ Adds support for a QSFP controller subsystem that shadows the QSFP module's ++ memory pages in memory ++ ++config QSFP_MEM_DFL ++ tristate "DFL bus driver for QSFP Controller subsystem in Intel FPGAs" ++ depends on FPGA_DFL ++ select QSFP_MEM_CORE ++ help ++ This is a Device Feature List (DFL) bus driver for the ++ QSFP Controller subsystem in Intel FPGAs. + + comment "MII PHY device drivers" + +diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile +index bd1dce127f4a..4c568ff878cc 100644 +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -32,7 +32,9 @@ obj-$(CONFIG_SFP) += sfp.o + sfp-obj-$(CONFIG_SFP) += sfp-bus.o + obj-y += $(sfp-obj-y) $(sfp-obj-m) + +-obj-$(CONFIG_QSFP_MEM) += qsfp-mem.o ++obj-$(CONFIG_QSFP_MEM_CORE) += qsfp-mem-core.o ++obj-$(CONFIG_QSFP_MEM_DFL) += qsfp-mem-dfl.o ++obj-$(CONFIG_QSFP_MEM) += qsfp-mem-platform.o + + obj-$(CONFIG_ADIN_PHY) += adin.o + obj-$(CONFIG_ADIN1100_PHY) += adin1100.o +diff --git a/drivers/net/phy/qsfp-mem.c b/drivers/net/phy/qsfp-mem-core.c +similarity index 54% +rename from drivers/net/phy/qsfp-mem.c +rename to drivers/net/phy/qsfp-mem-core.c +index 8ba3c747a106..fb3422868e48 100644 +--- a/drivers/net/phy/qsfp-mem.c ++++ b/drivers/net/phy/qsfp-mem-core.c +@@ -2,11 +2,10 @@ + + /* Intel(R) Memory based QSFP driver. + * +- * Copyright (C) 2020 Intel Corporation. All rights reserved. ++ * Copyright (C) 2020,2022 Intel Corporation. All rights reserved. + */ + + #include +-#include + #include + #include + #include +@@ -15,6 +14,7 @@ + #include + #include + #include ++#include + + #define CONF_OFF 0x20 + #define CONF_RST_MOD BIT(0) +@@ -29,6 +29,11 @@ + #define DELAY_REG 0x38 + #define DELAY_VALUE 0xffffff + ++#define I2C_TX_FIFO 0x40 ++#define I2C_TX_FIFO_START BIT(9) ++#define I2C_TX_FIFO_STOP BIT(8) ++#define I2C_TX_FIFO_WRITE (0) ++ + #define I2C_CTRL 0x48 + #define I2C_CTRL_EN BIT(0) + #define I2C_CTRL_BSP BIT(1) +@@ -38,12 +43,23 @@ + #define I2C_ISER 0x4c + #define I2C_ISER_TXRDY BIT(0) + #define I2C_ISER_RXRDY BIT(1) ++ ++#define I2C_ISR 0x50 ++#define I2C_ISR_NACK_DET BIT(2) ++#define I2C_ISR_ARBLOST_DET BIT(3) ++#define I2C_ISR_RX_OVER BIT(4) ++#define I2C_ISR_CLEAR_FLAGS (I2C_ISR_NACK_DET | I2C_ISR_ARBLOST_DET | I2C_ISR_RX_OVER) ++ ++#define I2C_STATUS 0x54 ++#define I2C_STATUS_CORE BIT(0) /* 0 = idle */ ++#define I2C_TX_FIFO_LVL 0x58 ++ + #define I2C_SCL_LOW 0x60 +-#define COUNT_PERIOD_LOW 0x82 ++#define COUNT_PERIOD_LOW 170 + #define I2C_SCL_HIGH 0x64 +-#define COUNT_PERIOD_HIGH 0x3c ++#define COUNT_PERIOD_HIGH 80 + #define I2C_SDA_HOLD 0x68 +-#define COUNT_PERIOD_HOLD 0x28 ++#define COUNT_PERIOD_HOLD 60 + + #define QSFP_SHADOW_CSRS_BASE_OFF 0x100 + #define QSFP_SHADOW_CSRS_BASE_END 0x3fc +@@ -51,29 +67,11 @@ + #define DELAY_US 1000 + + #define QSFP_CHECK_TIME 500 ++#define QSFP_CHK_RDY_CNT 1000 + +-enum qsfp_init_status { +- QSFP_INIT_RESET = 0, +- QSFP_INIT_DONE, +-}; ++#define I2C_QFSP_ADDR 0x50 + +-/** +- * struct qsfp - device private data structure +- * @base: base address of the device. +- * @regmap: regmap for device. +- * @dwork: work struct for checking qsfp plugin status. +- * @dev: point to dfl device. +- * @init: qsfp init status. +- * @lock: lock for qsfp initial function and status. +- */ +-struct qsfp { +- void __iomem *base; +- struct regmap *regmap; +- struct delayed_work dwork; +- struct device *dev; +- enum qsfp_init_status init; +- struct mutex lock; +-}; ++#define I2C_MAX_TIMEOUT 100 + + /* The QSFP controller defines 64-bit wide registers, but support + * for 64-bit IO in regmap-mmio was removed in upstream commit +@@ -98,7 +96,7 @@ static void qsfp_init_i2c(struct qsfp *qsfp) + writel(COUNT_PERIOD_HOLD, qsfp->base + I2C_SDA_HOLD); + + writel(FIELD_PREP(I2C_CTRL_FIFO, I2C_CTRL_FIFO_NOT_FULL) | +- I2C_CTRL_EN | I2C_CTRL_BSP, qsfp->base + I2C_CTRL); ++ I2C_CTRL_EN | I2C_CTRL_BSP, qsfp->base + I2C_CTRL); + } + + static const struct regmap_config mmio_cfg = { +@@ -110,24 +108,88 @@ static const struct regmap_config mmio_cfg = { + .max_register = QSFP_SHADOW_CSRS_BASE_END, + }; + +-static void qsfp_init(struct qsfp *qsfp) ++static int i2c_txcmp(struct qsfp *qsfp) ++{ ++ u32 fifo_lvl; ++ ++ return readl_poll_timeout(qsfp->base + I2C_TX_FIFO_LVL, fifo_lvl, !fifo_lvl, ++ 10, I2C_MAX_TIMEOUT); ++} ++ ++static int i2c_send(struct qsfp *qsfp, int data) + { +- writeq(CONF_RST_MOD | CONF_RST_CON | CONF_MOD_SEL, +- qsfp->base + CONF_OFF); ++ int ret = i2c_txcmp(qsfp); ++ ++ if (ret) ++ return ret; ++ ++ writel(data, qsfp->base + I2C_TX_FIFO); ++ return 0; ++} ++ ++static int send_qsfp_cmd_page0(struct qsfp *qsfp) ++{ ++ int st, ret; ++ ++ i2c_send(qsfp, I2C_TX_FIFO_START | (I2C_QFSP_ADDR << 1) | I2C_TX_FIFO_WRITE); ++ i2c_send(qsfp, 0x7f); ++ i2c_send(qsfp, I2C_TX_FIFO_STOP); ++ ++ ret = i2c_txcmp(qsfp); ++ if (ret) ++ return ret; ++ ++ /* Check status */ ++ st = readl(qsfp->base + I2C_ISR); ++ dev_dbg(qsfp->dev, "QSFP I2C ISR = 0x%02X STAT = 0x%x\n", st, ++ readl(qsfp->base + I2C_STATUS)); ++ if (st & I2C_ISR_CLEAR_FLAGS) { ++ writel(I2C_ISR_CLEAR_FLAGS, qsfp->base + I2C_ISR); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static int qsfp_init(struct qsfp *qsfp) ++{ ++ int cnt; ++ ++ /* Reset QSFP Module and QSFP Controller */ ++ writeq(CONF_RST_MOD | CONF_RST_CON | CONF_MOD_SEL, qsfp->base + CONF_OFF); ++ + udelay(DELAY_US); ++ + writeq(CONF_MOD_SEL, qsfp->base + CONF_OFF); +- udelay(DELAY_US); + ++ /* Initialize Intel FPGA Avalon I2C (Master) Core */ + qsfp_init_i2c(qsfp); ++ writel(I2C_ISR_CLEAR_FLAGS, qsfp->base + I2C_ISR); + +- udelay(DELAY_US); + writeq(DELAY_VALUE, qsfp->base + DELAY_REG); + ++ /* Check QSFP Module Ready */ ++ for (cnt = 0; cnt < QSFP_CHK_RDY_CNT; cnt++) { ++ /* try to send a command to change page 0 */ ++ if (!send_qsfp_cmd_page0(qsfp)) { ++ dev_info(qsfp->dev, "QSFP module ready after waiting for %dms", cnt); ++ break; ++ } ++ ++ udelay(DELAY_US); ++ } ++ ++ if (cnt >= QSFP_CHK_RDY_CNT) { ++ dev_err(qsfp->dev, "QSFP I2C check ready timeout error"); ++ return -ETIMEDOUT; ++ } ++ ++ /* Enable Polling mode */ + writeq(CONF_POLL_EN | CONF_MOD_SEL, qsfp->base + CONF_OFF); +- udelay(DELAY_US); ++ return 0; + } + +-static int check_qsfp_plugin(struct qsfp *qsfp) ++int check_qsfp_plugin(struct qsfp *qsfp) + { + u64 status; + +@@ -135,8 +197,37 @@ static int check_qsfp_plugin(struct qsfp *qsfp) + + return (!(status & MODPRSL)); + } ++EXPORT_SYMBOL_GPL(check_qsfp_plugin); ++ ++ssize_t qsfp_connected_show(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct qsfp *qsfp = dev_get_drvdata(dev); ++ u32 plugin; ++ ++ mutex_lock(&qsfp->lock); ++ plugin = check_qsfp_plugin(qsfp) && (qsfp->init == QSFP_INIT_DONE); ++ mutex_unlock(&qsfp->lock); ++ ++ return sysfs_emit(buf, "%u\n", plugin); ++} ++static DEVICE_ATTR_RO(qsfp_connected); + +-static void qsfp_check_hotplug(struct work_struct *work) ++static struct attribute *qsfp_mem_attrs[] = { ++ &dev_attr_qsfp_connected.attr, ++ NULL, ++}; ++ ++static const struct attribute_group qsfp_mem_group = { ++ .attrs = qsfp_mem_attrs, ++}; ++ ++const struct attribute_group *qsfp_mem_groups[] = { ++ &qsfp_mem_group, ++ NULL, ++}; ++EXPORT_SYMBOL_GPL(qsfp_mem_groups); ++ ++void qsfp_check_hotplug(struct work_struct *work) + { + struct delayed_work *dwork; + struct qsfp *qsfp; +@@ -150,11 +241,10 @@ static void qsfp_check_hotplug(struct work_struct *work) + status = readq(qsfp->base + STAT_OFF); + dev_dbg(qsfp->dev, "qsfp status 0x%llx\n", status); + +- if (check_qsfp_plugin(qsfp) && +- qsfp->init == QSFP_INIT_RESET) { ++ if (check_qsfp_plugin(qsfp) && qsfp->init == QSFP_INIT_RESET) { + dev_info(qsfp->dev, "detected QSFP plugin\n"); +- qsfp_init(qsfp); +- WRITE_ONCE(qsfp->init, QSFP_INIT_DONE); ++ if (!qsfp_init(qsfp)) ++ WRITE_ONCE(qsfp->init, QSFP_INIT_DONE); + } else if (!check_qsfp_plugin(qsfp) && + qsfp->init == QSFP_INIT_DONE) { + dev_info(qsfp->dev, "detected QSFP unplugin\n"); +@@ -165,47 +255,17 @@ static void qsfp_check_hotplug(struct work_struct *work) + schedule_delayed_work(&qsfp->dwork, msecs_to_jiffies(QSFP_CHECK_TIME)); + } + +-static ssize_t qsfp_connected_show(struct device *dev, +- struct device_attribute *attr, char *buf) ++int qsfp_init_work(struct qsfp *qsfp) + { +- struct qsfp *qsfp = dev_get_drvdata(dev); +- u32 plugin; +- +- mutex_lock(&qsfp->lock); +- plugin = check_qsfp_plugin(qsfp) && (qsfp->init == QSFP_INIT_DONE); +- mutex_unlock(&qsfp->lock); +- +- return sysfs_emit(buf, "%u\n", plugin); ++ INIT_DELAYED_WORK(&qsfp->dwork, qsfp_check_hotplug); ++ qsfp_check_hotplug(&qsfp->dwork.work); ++ return 0; + } ++EXPORT_SYMBOL_GPL(qsfp_init_work); + +-static DEVICE_ATTR_RO(qsfp_connected); +- +-static struct attribute *qsfp_mem_attrs[] = { +- &dev_attr_qsfp_connected.attr, +- NULL, +-}; +-ATTRIBUTE_GROUPS(qsfp_mem); +- +-static int qsfp_probe(struct dfl_device *dfl_dev) ++int qsfp_register_regmap(struct qsfp *qsfp) + { +- struct device *dev = &dfl_dev->dev; +- struct qsfp *qsfp; +- +- qsfp = devm_kzalloc(dev, sizeof(*qsfp), GFP_KERNEL); +- if (!qsfp) +- return -ENOMEM; +- +- qsfp->base = devm_ioremap_resource(dev, &dfl_dev->mmio_res); +- if (!qsfp->base) +- return -ENOMEM; +- +- qsfp->dev = dev; +- mutex_init(&qsfp->lock); +- +- dev_set_drvdata(dev, qsfp); +- +- INIT_DELAYED_WORK(&qsfp->dwork, qsfp_check_hotplug); +- qsfp_check_hotplug(&qsfp->dwork.work); ++ struct device *dev = qsfp->dev; + + qsfp->regmap = devm_regmap_init_mmio(dev, qsfp->base, &mmio_cfg); + if (IS_ERR(qsfp->regmap)) +@@ -213,36 +273,12 @@ static int qsfp_probe(struct dfl_device *dfl_dev) + + return PTR_ERR_OR_ZERO(qsfp->regmap); + } ++EXPORT_SYMBOL_GPL(qsfp_register_regmap); + +-static void qsfp_remove(struct dfl_device *dfl_dev) ++void qsfp_remove_device(struct qsfp *qsfp) + { +- struct device *dev = &dfl_dev->dev; +- struct qsfp *qsfp = dev_get_drvdata(dev); +- + writeq(CONF_MOD_SEL, qsfp->base + CONF_OFF); +- + cancel_delayed_work_sync(&qsfp->dwork); + } +- +-#define FME_FEATURE_ID_QSFP 0x13 +- +-static const struct dfl_device_id qsfp_ids[] = { +- { FME_ID, FME_FEATURE_ID_QSFP }, +- { } +-}; +- +-static struct dfl_driver qsfp_driver = { +- .drv = { +- .name = "qsfp-mem", +- .dev_groups = qsfp_mem_groups, +- }, +- .id_table = qsfp_ids, +- .probe = qsfp_probe, +- .remove = qsfp_remove, +-}; +- +-module_dfl_driver(qsfp_driver); +-MODULE_DEVICE_TABLE(dfl, qsfp_ids); +-MODULE_DESCRIPTION("Intel(R) Memory based QSFP driver"); +-MODULE_AUTHOR("Intel Corporation"); +-MODULE_LICENSE("GPL v2"); ++EXPORT_SYMBOL_GPL(qsfp_remove_device); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/net/phy/qsfp-mem-dfl.c b/drivers/net/phy/qsfp-mem-dfl.c +new file mode 100644 +index 000000000000..1607213998fa +--- /dev/null ++++ b/drivers/net/phy/qsfp-mem-dfl.c +@@ -0,0 +1,80 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++/* Intel(R) Memory based QSFP driver For DFL based devices. ++ * ++ * Copyright (C) 2022 Intel Corporation. All rights reserved. ++ */ ++#include ++#include ++#include ++ ++static int qsfp_dfl_probe(struct dfl_device *dfl_dev) ++{ ++ struct device *dev = &dfl_dev->dev; ++ struct qsfp *qsfp; ++ int ret; ++ ++ qsfp = devm_kzalloc(dev, sizeof(*qsfp), GFP_KERNEL); ++ if (!qsfp) ++ return -ENOMEM; ++ ++ qsfp->base = devm_ioremap_resource(dev, &dfl_dev->mmio_res); ++ if (!qsfp->base) ++ return -ENOMEM; ++ ++ qsfp->dev = dev; ++ mutex_init(&qsfp->lock); ++ ++ dev_set_drvdata(dev, qsfp); ++ ++ ret = qsfp_init_work(qsfp); ++ if (ret) { ++ dev_err_probe(dev, ret, ++ "Failed to initialize delayed work to read QSFP\n"); ++ goto exit; ++ } ++ ++ ret = qsfp_register_regmap(qsfp); ++ if (ret) ++ goto cancel_work; ++ ++ return 0; ++ ++cancel_work: ++ qsfp_remove_device(qsfp); ++exit: ++ mutex_destroy(&qsfp->lock); ++ return ret; ++} ++ ++static void qsfp_dfl_remove(struct dfl_device *dfl_dev) ++{ ++ struct device *dev = &dfl_dev->dev; ++ struct qsfp *qsfp = dev_get_drvdata(dev); ++ ++ qsfp_remove_device(qsfp); ++ mutex_destroy(&qsfp->lock); ++} ++ ++#define FME_FEATURE_ID_QSFP 0x13 ++ ++static const struct dfl_device_id qsfp_ids[] = { ++ { FME_ID, FME_FEATURE_ID_QSFP }, ++ { } ++}; ++ ++static struct dfl_driver qsfp_driver = { ++ .drv = { ++ .name = "qsfp-mem", ++ .dev_groups = qsfp_mem_groups, ++ }, ++ .id_table = qsfp_ids, ++ .probe = qsfp_dfl_probe, ++ .remove = qsfp_dfl_remove, ++}; ++ ++module_dfl_driver(qsfp_driver); ++MODULE_DEVICE_TABLE(dfl, qsfp_ids); ++MODULE_DESCRIPTION("Intel(R) Memory based QSFP DFL driver"); ++MODULE_AUTHOR("Intel Corporation"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/net/phy/qsfp-mem-platform.c b/drivers/net/phy/qsfp-mem-platform.c +new file mode 100644 +index 000000000000..82ad58f866bc +--- /dev/null ++++ b/drivers/net/phy/qsfp-mem-platform.c +@@ -0,0 +1,106 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++/* Intel(R) Memory based QSFP driver for platform devices. ++ * ++ * Copyright (C) 2022 Intel Corporation. All rights reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define INTEL_QSFP_MEM_CONTROLLER_NAME "qsfp-mem-ctrl" ++ ++static int qsfp_platform_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct resource *region = NULL; ++ struct resource *qsfpconfig = NULL; ++ struct qsfp *qsfp = NULL; ++ int ret; ++ ++ qsfp = devm_kzalloc(dev, sizeof(*qsfp), GFP_KERNEL); ++ if (!qsfp) ++ return -ENOMEM; ++ ++ qsfp->dev = dev; ++ mutex_init(&qsfp->lock); ++ platform_set_drvdata(pdev, qsfp); ++ ++ /* QSFP Mem address space */ ++ qsfpconfig = platform_get_resource_byname(pdev, IORESOURCE_MEM, ++ INTEL_QSFP_MEM_CONTROLLER_NAME); ++ if (!qsfpconfig) { ++ dev_err(dev, "resource %s not defined\n", INTEL_QSFP_MEM_CONTROLLER_NAME); ++ return -ENODEV; ++ } ++ ++ region = devm_request_mem_region(dev, qsfpconfig->start, ++ resource_size(qsfpconfig), dev_name(dev)); ++ if (!region) { ++ dev_err(dev, "unable to request %s\n", INTEL_QSFP_MEM_CONTROLLER_NAME); ++ return -EBUSY; ++ } ++ qsfp->base = devm_ioremap(dev, region->start, resource_size(region)); ++ if (!(qsfp->base)) { ++ dev_err(dev, "ioremap of %s failed!", INTEL_QSFP_MEM_CONTROLLER_NAME); ++ return -ENOMEM; ++ } ++ ++ ret = qsfp_init_work(qsfp); ++ if (ret) { ++ dev_err_probe(dev, ret, ++ "Failed to initialize delayed work to read QSFP\n"); ++ goto exit; ++ } ++ ++ ret = qsfp_register_regmap(qsfp); ++ if (ret) ++ goto cancel_work; ++ ++ return 0; ++ ++cancel_work: ++ qsfp_remove_device(qsfp); ++exit: ++ mutex_destroy(&qsfp->lock); ++ return ret; ++} ++ ++static int qsfp_platform_remove(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct qsfp *qsfp = dev_get_drvdata(dev); ++ ++ qsfp_remove_device(qsfp); ++ mutex_destroy(&qsfp->lock); ++ return 0; ++} ++ ++static const struct of_device_id intel_fpga_qsfp_mem_ids[] = { ++ { .compatible = "intel,qsfp-mem", .data = NULL, }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, intel_fpga_qsfp_mem_ids); ++ ++static struct platform_driver qsfp_driver = { ++ .probe = qsfp_platform_probe, ++ .remove = qsfp_platform_remove, ++ .suspend = NULL, ++ .resume = NULL, ++ .driver = { ++ .name = "qsfp-mem", ++ .dev_groups = qsfp_mem_groups, ++ .owner = THIS_MODULE, ++ .of_match_table = intel_fpga_qsfp_mem_ids, ++ }, ++}; ++ ++module_platform_driver(qsfp_driver); ++MODULE_DESCRIPTION("Intel(R) Memory based QSFP Platform driver"); ++MODULE_AUTHOR("Intel Corporation"); ++MODULE_LICENSE("GPL"); +diff --git a/include/linux/phy/qsfp-mem.h b/include/linux/phy/qsfp-mem.h +new file mode 100644 +index 000000000000..aece97c081f3 +--- /dev/null ++++ b/include/linux/phy/qsfp-mem.h +@@ -0,0 +1,50 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++ ++/* Intel(R) Memory based core QSFP driver header. ++ * ++ * Copyright (C) 2022 Intel Corporation. All rights reserved. ++ */ ++ ++#ifndef __LINUX_QSFP_MEM_H ++#define __LINUX_QSFP_MEM_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++enum qsfp_init_status { ++ QSFP_INIT_RESET = 0, ++ QSFP_INIT_DONE, ++}; ++ ++/** ++ * struct qsfp - device private data structure ++ * @base: base address of the device. ++ * @regmap: regmap for device. ++ * @dwork: work struct for checking qsfp plugin status. ++ * @dev: point to device. ++ * @init: qsfp init status. ++ * @lock: lock for qsfp initial function and status. ++ */ ++struct qsfp { ++ void __iomem *base; ++ struct regmap *regmap; ++ struct delayed_work dwork; ++ struct device *dev; ++ enum qsfp_init_status init; ++ struct mutex lock; ++}; ++ ++int qsfp_init_work(struct qsfp *qsfp); ++int qsfp_register_regmap(struct qsfp *qsfp); ++void qsfp_remove_device(struct qsfp *qsfp); ++int check_qsfp_plugin(struct qsfp *qsfp); ++extern const struct attribute_group *qsfp_mem_groups[]; ++ ++#endif //__LINUX_QSFP_MEM_H diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0035-fpga-m10bmc-sec-add-fpga_boot_image.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0035-fpga-m10bmc-sec-add-fpga_boot_image.patch new file mode 100644 index 0000000..8f6f398 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0035-fpga-m10bmc-sec-add-fpga_boot_image.patch @@ -0,0 +1,105 @@ +From becacf5ddc1ac4ae77a4bd5a9d89cf68c2ca4c39 Mon Sep 17 00:00:00 2001 +From: Tianfei zhang +Date: Mon, 9 Aug 2021 09:17:25 +0800 +Subject: [PATCH] fpga: m10bmc-sec: add fpga_boot_image +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add the fpga_boot_image sysfs node to indicate which image FPGA was loaded +when the FPGA booted. + +Co-developed-by: Tianfei zhang +Signed-off-by: Tianfei zhang +Signed-off-by: Ilpo Järvinen +--- + .../sysfs-driver-intel-m10-bmc-sec-update | 8 +++++ + drivers/fpga/intel-m10-bmc-sec-update.c | 29 ++++++++++++++++++- + include/linux/mfd/intel-m10-bmc.h | 4 +++ + 3 files changed, 40 insertions(+), 1 deletion(-) + +diff --git a/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update b/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update +index e5a300dc0dfc..472225a7a5d4 100644 +--- a/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update ++++ b/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update +@@ -108,3 +108,11 @@ Description: Read/Write. A key word from the available_fpga_images file + attempt to select an unsupported image or fall-back sequence. + Consult your product documentation for supported + configurations. ++ ++What: /sys/bus/platform/drivers/intel-m10bmc-sec-update/.../control/fpga_boot_image ++Date: Nov 2021 ++KernelVersion: 5.16 ++Contact: Tianfei zhang ++Description: Read-only. Reading this file will return the name of image booted ++ from FPGA. The EINVAL error code will be returned if no image booted ++ from FPGA. +diff --git a/drivers/fpga/intel-m10-bmc-sec-update.c b/drivers/fpga/intel-m10-bmc-sec-update.c +index c31d8bdff5eb..24ae852ea4fb 100644 +--- a/drivers/fpga/intel-m10-bmc-sec-update.c ++++ b/drivers/fpga/intel-m10-bmc-sec-update.c +@@ -786,6 +786,31 @@ power_on_image_store(struct device *dev, + } + static DEVICE_ATTR_RW(power_on_image); + ++static ssize_t ++fpga_boot_image_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct m10bmc_sec *sec = dev_get_drvdata(dev); ++ const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; ++ int ret; ++ u32 status; ++ int boot_page; ++ ++ ret = m10bmc_sys_read(sec->m10bmc, csr_map->base + M10BMC_PMCI_FPGA_CONF_STS, &status); ++ if (ret) ++ return ret; ++ ++ if (!FIELD_GET(PMCI_FPGA_CONFIGED, status)) ++ return -EINVAL; ++ ++ boot_page = FIELD_GET(PMCI_FPGA_BOOT_PAGE, status); ++ if (boot_page >= FPGA_MAX) ++ return -EINVAL; ++ ++ return sysfs_emit(buf, "%s\n", fpga_image_names[boot_page]); ++} ++static DEVICE_ATTR_RO(fpga_boot_image); ++ + static const struct fpga_power_on pmci_power_on_image = { + .avail_image_mask = BIT(FPGA_FACTORY) | BIT(FPGA_USER1) | BIT(FPGA_USER2), + .set_sequence = pmci_set_power_on_image, +@@ -834,7 +859,8 @@ m10bmc_is_visible(struct kobject *kobj, struct attribute *attr, int n) + + if (!sec->ops->poc && + (attr == &dev_attr_power_on_image.attr || +- attr == &dev_attr_available_power_on_images.attr)) ++ attr == &dev_attr_available_power_on_images.attr || ++ attr == &dev_attr_fpga_boot_image.attr)) + return 0; + + return attr->mode; +@@ -845,6 +871,7 @@ static struct attribute *m10bmc_control_attrs[] = { + &dev_attr_image_load.attr, + &dev_attr_power_on_image.attr, + &dev_attr_available_power_on_images.attr, ++ &dev_attr_fpga_boot_image.attr, + NULL, + }; + +diff --git a/include/linux/mfd/intel-m10-bmc.h b/include/linux/mfd/intel-m10-bmc.h +index 63093ff8bbd7..73e26a288478 100644 +--- a/include/linux/mfd/intel-m10-bmc.h ++++ b/include/linux/mfd/intel-m10-bmc.h +@@ -71,6 +71,10 @@ + #define M10BMC_PKVL_PRELOAD_INTERVAL_US (100 * 1000) + #define M10BMC_PKVL_PRELOAD_TIMEOUT_US (30 * 1000 * 1000) + ++#define M10BMC_PMCI_FPGA_CONF_STS 0xa0 ++#define PMCI_FPGA_BOOT_PAGE GENMASK(2, 0) ++#define PMCI_FPGA_CONFIGED BIT(3) ++ + #define M10BMC_PMCI_FPGA_POC 0x0b0 + #define PMCI_FPGA_POC BIT(0) + #define PMCI_NIOS_REQ_CLEAR BIT(1) diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0036-fpga-m10bmc-sec-Support-for-SDM-key-provisioning.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0036-fpga-m10bmc-sec-Support-for-SDM-key-provisioning.patch new file mode 100644 index 0000000..5c6a4e1 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0036-fpga-m10bmc-sec-Support-for-SDM-key-provisioning.patch @@ -0,0 +1,66 @@ +From 69ffe45399e44e8a80a0ce8ba2433eb6af161c91 Mon Sep 17 00:00:00 2001 +From: Russ Weight +Date: Mon, 4 Oct 2021 14:43:12 -0700 +Subject: [PATCH] fpga: m10bmc-sec: Support for SDM key provisioning +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +SDM key provisioning for the N6000 requires a new handshake with +N6000 BMC firmware. This change adds the "sdm" keyword to the +available_images sysfs file and extends the image_load sysfs support +accordingly. + +Co-developed-by: Russ Weight +Signed-off-by: Russ Weight +Signed-off-by: Ilpo Järvinen +--- + drivers/fpga/intel-m10-bmc-sec-update.c | 13 +++++++++++++ + include/linux/mfd/intel-m10-bmc.h | 3 +++ + 2 files changed, 16 insertions(+) + +diff --git a/drivers/fpga/intel-m10-bmc-sec-update.c b/drivers/fpga/intel-m10-bmc-sec-update.c +index 24ae852ea4fb..9e41afa83b68 100644 +--- a/drivers/fpga/intel-m10-bmc-sec-update.c ++++ b/drivers/fpga/intel-m10-bmc-sec-update.c +@@ -160,6 +160,15 @@ static int pmci_sec_fpga_image_load(struct m10bmc_sec *sec, unsigned int val) + PMCI_FPGA_RP_LOAD); + } + ++static int pmci_sec_sdm_image_load(struct m10bmc_sec *sec) ++{ ++ const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; ++ ++ return regmap_update_bits(sec->m10bmc->regmap, ++ csr_map->base + M10BMC_PMCI_SDM_SR_CTRL_STS, ++ PMCI_SDM_SR_IMG_REQ, PMCI_SDM_SR_IMG_REQ); ++} ++ + static int m10bmc_sec_bmc_image_load_0(struct m10bmc_sec *sec) + { + return m10bmc_sec_bmc_image_load(sec, 0); +@@ -390,6 +399,10 @@ static struct image_load n6000_image_load_hndlrs[] = { + .name = "fpga_user2", + .load_image = pmci_sec_fpga_image_load_2, + }, ++ { ++ .name = "sdm", ++ .load_image = pmci_sec_sdm_image_load, ++ }, + {} + }; + +diff --git a/include/linux/mfd/intel-m10-bmc.h b/include/linux/mfd/intel-m10-bmc.h +index 73e26a288478..e8fccb685b4f 100644 +--- a/include/linux/mfd/intel-m10-bmc.h ++++ b/include/linux/mfd/intel-m10-bmc.h +@@ -198,6 +198,9 @@ + #define M10BMC_N6000_AUTH_RESULT 0x1c4 + #define AUTH_RESULT_RSU_STATUS GENMASK(23, 16) + ++#define M10BMC_PMCI_SDM_SR_CTRL_STS 0x230 ++#define PMCI_SDM_SR_IMG_REQ BIT(0) ++ + #define M10BMC_N6000_BUILD_VER 0x0 + #define NIOS2_N6000_FW_VERSION 0x4 + #define M10BMC_N6000_MAC_LOW 0x20 diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0037-fpga-m10bmc-sec-Expose-SDM-SR-provisioning-status.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0037-fpga-m10bmc-sec-Expose-SDM-SR-provisioning-status.patch new file mode 100644 index 0000000..c66e420 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0037-fpga-m10bmc-sec-Expose-SDM-SR-provisioning-status.patch @@ -0,0 +1,223 @@ +From 5db63c01092793592ee4e3706114c4a0a4c0e963 Mon Sep 17 00:00:00 2001 +From: Russ Weight +Date: Mon, 4 Oct 2021 16:02:24 -0700 +Subject: [PATCH] fpga: m10bmc-sec: Expose SDM SR provisioning status +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Provide a new read-only sysfs file, sdm_sr_provision_status, to report +the N6000 SDM key provisioning status. + +Co-developed-by: Russ Weight +Signed-off-by: Russ Weight +Signed-off-by: Ilpo Järvinen +--- + .../sysfs-driver-intel-m10-bmc-sec-update | 8 +++ + drivers/fpga/intel-m10-bmc-sec-update.c | 57 +++++++++++++++++-- + include/linux/mfd/intel-m10-bmc.h | 31 ++++++++++ + 3 files changed, 91 insertions(+), 5 deletions(-) + +diff --git a/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update b/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update +index 472225a7a5d4..92d34c2c96b4 100644 +--- a/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update ++++ b/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update +@@ -60,6 +60,14 @@ Description: Read only. Returns number of times the secure update + staging area has been flashed. + Format: "%u". + ++What: /sys/bus/platform/drivers/intel-m10bmc-sec-update/.../security/sdm_sr_provision_status ++Date: November 2021 ++KernelVersion: 5.16 ++Contact: Russ Weight ++Description: Read-only. Read this file to determine the status of SDM ++ static region key provisioning. ++ Format: "0x%x". ++ + What: /sys/bus/platform/drivers/intel-m10bmc-sec-update/.../control/available_images + Date: Nov 2021 + KernelVersion: 5.16 +diff --git a/drivers/fpga/intel-m10-bmc-sec-update.c b/drivers/fpga/intel-m10-bmc-sec-update.c +index 9e41afa83b68..a092b5f10989 100644 +--- a/drivers/fpga/intel-m10-bmc-sec-update.c ++++ b/drivers/fpga/intel-m10-bmc-sec-update.c +@@ -45,6 +45,7 @@ struct m10bmc_sec_ops { + int (*rsu_status)(struct m10bmc_sec *sec); + struct image_load *image_load; /* terminated with { } member */ + const struct fpga_power_on *poc; /* power on image configuration */ ++ bool sec_visible; + }; + + struct m10bmc_sec { +@@ -61,11 +62,27 @@ static void log_error_regs(struct m10bmc_sec *sec, u32 doorbell) + { + const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; + u32 auth_result; ++ int status; + + dev_err(sec->dev, "Doorbell: 0x%08x\n", doorbell); + + if (!m10bmc_sys_read(sec->m10bmc, csr_map->auth_result, &auth_result)) + dev_err(sec->dev, "RSU auth result: 0x%08x\n", auth_result); ++ ++ status = sec->ops->rsu_status(sec); ++ if (status < 0) ++ return; ++ ++ if (status == RSU_STAT_SDM_PR_FAILED) { ++ if (!m10bmc_sys_read(sec->m10bmc, M10BMC_PMCI_SDM_PR_STS, &status)) ++ dev_err(sec->dev, "SDM Key Program Status: 0x%08x\n", status); ++ } else if (status == RSU_STAT_SDM_SR_SDM_FAILED || ++ status == RSU_STAT_SDM_KEY_FAILED) { ++ if (!m10bmc_sys_read(sec->m10bmc, M10BMC_PMCI_CERT_PROG_STS, &status)) ++ dev_err(sec->dev, "Certificate Program Status: 0x%08x\n", status); ++ if (!m10bmc_sys_read(sec->m10bmc, M10BMC_PMCI_CERT_SPEC_STS, &status)) ++ dev_err(sec->dev, "Certificate Specific Status: 0x%08x\n", status); ++ } + } + + static int m10bmc_sec_progress_status(struct m10bmc_sec *sec, u32 *doorbell_reg, +@@ -160,7 +177,7 @@ static int pmci_sec_fpga_image_load(struct m10bmc_sec *sec, unsigned int val) + PMCI_FPGA_RP_LOAD); + } + +-static int pmci_sec_sdm_image_load(struct m10bmc_sec *sec) ++static int pmci_sec_sdm_sr_image_load(struct m10bmc_sec *sec) + { + const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; + +@@ -400,8 +417,8 @@ static struct image_load n6000_image_load_hndlrs[] = { + .load_image = pmci_sec_fpga_image_load_2, + }, + { +- .name = "sdm", +- .load_image = pmci_sec_sdm_image_load, ++ .name = "sdm_sr", ++ .load_image = pmci_sec_sdm_sr_image_load, + }, + {} + }; +@@ -614,6 +631,33 @@ static ssize_t flash_count_show(struct device *dev, + } + static DEVICE_ATTR_RO(flash_count); + ++static ssize_t sdm_sr_provision_status_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct m10bmc_sec *sec = dev_get_drvdata(dev); ++ const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; ++ u32 status; ++ int ret; ++ ++ ret = m10bmc_sys_read(sec->m10bmc, csr_map->base + M10BMC_PMCI_SDM_SR_CTRL_STS, &status); ++ if (ret) ++ return ret; ++ ++ return sysfs_emit(buf, "0x%x\n", (unsigned int)FIELD_GET(PMCI_SDM_SR_PGM_ERROR, status)); ++} ++static DEVICE_ATTR_RO(sdm_sr_provision_status); ++ ++static umode_t m10bmc_security_is_visible(struct kobject *kobj, struct attribute *attr, int n) ++{ ++ struct m10bmc_sec *sec = dev_get_drvdata(kobj_to_dev(kobj)); ++ ++ if (!sec->ops->sec_visible && ++ attr == &dev_attr_sdm_sr_provision_status.attr) ++ return 0; ++ ++ return attr->mode; ++} ++ + static struct attribute *m10bmc_security_attrs[] = { + &dev_attr_flash_count.attr, + &dev_attr_bmc_root_entry_hash.attr, +@@ -622,12 +666,14 @@ static struct attribute *m10bmc_security_attrs[] = { + &dev_attr_sr_canceled_csks.attr, + &dev_attr_pr_canceled_csks.attr, + &dev_attr_bmc_canceled_csks.attr, ++ &dev_attr_sdm_sr_provision_status.attr, + NULL, + }; + + static struct attribute_group m10bmc_security_attr_group = { + .name = "security", + .attrs = m10bmc_security_attrs, ++ .is_visible = m10bmc_security_is_visible, + }; + + static enum fpga_image +@@ -866,7 +912,7 @@ static ssize_t image_load_store(struct device *dev, + static DEVICE_ATTR_WO(image_load); + + static umode_t +-m10bmc_is_visible(struct kobject *kobj, struct attribute *attr, int n) ++m10bmc_image_is_visible(struct kobject *kobj, struct attribute *attr, int n) + { + struct m10bmc_sec *sec = dev_get_drvdata(kobj_to_dev(kobj)); + +@@ -891,7 +937,7 @@ static struct attribute *m10bmc_control_attrs[] = { + static struct attribute_group m10bmc_control_attr_group = { + .name = "control", + .attrs = m10bmc_control_attrs, +- .is_visible = m10bmc_is_visible, ++ .is_visible = m10bmc_image_is_visible, + }; + + static const struct attribute_group *m10bmc_sec_attr_groups[] = { +@@ -1298,6 +1344,7 @@ static const struct m10bmc_sec_ops m10sec_n6000_ops = { + .rsu_status = m10bmc_sec_n6000_rsu_status, + .image_load = n6000_image_load_hndlrs, + .poc = &pmci_power_on_image, ++ .sec_visible = true, + }; + + #define SEC_UPDATE_LEN_MAX 32 +diff --git a/include/linux/mfd/intel-m10-bmc.h b/include/linux/mfd/intel-m10-bmc.h +index e8fccb685b4f..65c9ff8b9bb5 100644 +--- a/include/linux/mfd/intel-m10-bmc.h ++++ b/include/linux/mfd/intel-m10-bmc.h +@@ -133,6 +133,32 @@ + #define RSU_STAT_NON_INC 0x6 + #define RSU_STAT_ERASE_FAIL 0x7 + #define RSU_STAT_WEAROUT 0x8 ++#define RSU_STAT_PMCI_SS_FAIL 0x9 ++#define RSU_STAT_FLASH_CMD 0xa ++#define RSU_STAT_FACTORY_UNVERITY 0xb ++#define RSU_STAT_FACTORY_ACTIVE 0xc ++#define RSU_STAT_POWER_DOWN 0xd ++#define RSU_STAT_CANCELLATION 0xe ++#define RSU_STAT_HASH 0xf ++#define RSU_STAT_FLASH_ACCESS 0x10 ++#define RSU_STAT_SDM_PR_CERT 0x20 ++#define RSU_STAT_SDM_PR_NIOS_BUSY 0x21 ++#define RSU_STAT_SDM_PR_TIMEOUT 0x22 ++#define RSU_STAT_SDM_PR_FAILED 0x23 ++#define RSU_STAT_SDM_PR_MISMATCH 0x24 ++#define RSU_STAT_SDM_PR_FLUSH 0x25 ++#define RSU_STAT_SDM_SR_CERT 0x30 ++#define RSU_STAT_SDM_SR_NIOS_BUSY 0x31 ++#define RSU_STAT_SDM_SR_TIMEOUT 0x32 ++#define RSU_STAT_SDM_SR_SDM_FAILED 0x33 ++#define RSU_STAT_SDM_SR_MISMATCH 0x34 ++#define RSU_STAT_SDM_SR_FLUSH 0x35 ++#define RSU_STAT_SDM_KEY_CERT 0x40 ++#define RSU_STAT_SDM_KEY_NIOS_BUSY 0x41 ++#define RSU_STAT_SDM_KEY_TIMEOUT 0x42 ++#define RSU_STAT_SDM_KEY_FAILED 0x43 ++#define RSU_STAT_SDM_KEY_MISMATCH 0x44 ++#define RSU_STAT_SDM_KEY_FLUSH 0x45 + #define RSU_STAT_NIOS_OK 0x80 + #define RSU_STAT_USER_OK 0x81 + #define RSU_STAT_FACTORY_OK 0x82 +@@ -200,6 +226,11 @@ + + #define M10BMC_PMCI_SDM_SR_CTRL_STS 0x230 + #define PMCI_SDM_SR_IMG_REQ BIT(0) ++#define PMCI_SDM_SR_PGM_ERROR GENMASK(23, 16) ++ ++#define M10BMC_PMCI_SDM_PR_STS 0x820 ++#define M10BMC_PMCI_CERT_PROG_STS 0x824 ++#define M10BMC_PMCI_CERT_SPEC_STS 0x828 + + #define M10BMC_N6000_BUILD_VER 0x0 + #define NIOS2_N6000_FW_VERSION 0x4 diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0038-fpga-m10bmc-sec-Expose-SDM-PR-provisioning-status.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0038-fpga-m10bmc-sec-Expose-SDM-PR-provisioning-status.patch new file mode 100644 index 0000000..2e34e31 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0038-fpga-m10bmc-sec-Expose-SDM-PR-provisioning-status.patch @@ -0,0 +1,126 @@ +From 4b6b06450a2689703508dd5338235fc388b57729 Mon Sep 17 00:00:00 2001 +From: Russ Weight +Date: Wed, 3 Aug 2022 11:35:51 -0700 +Subject: [PATCH] fpga: m10bmc-sec: Expose SDM PR provisioning status +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Provide a new read-only sysfs file, sdm_pr_provision_status, to report the +N6000 SDM Partial Configuration key provisioning status. + +Co-developed-by: Russ Weight +Signed-off-by: Russ Weight +Signed-off-by: Ilpo Järvinen +--- + .../sysfs-driver-intel-m10-bmc-sec-update | 8 +++++ + drivers/fpga/intel-m10-bmc-sec-update.c | 36 +++++++++++++++++-- + include/linux/mfd/intel-m10-bmc.h | 4 +++ + 3 files changed, 46 insertions(+), 2 deletions(-) + +diff --git a/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update b/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update +index 92d34c2c96b4..761a1bc442fd 100644 +--- a/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update ++++ b/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update +@@ -68,6 +68,14 @@ Description: Read-only. Read this file to determine the status of SDM + static region key provisioning. + Format: "0x%x". + ++What: /sys/bus/platform/drivers/intel-m10bmc-sec-update/.../security/sdm_pr_provision_status ++Date: Dec 2022 ++KernelVersion: 6.1 ++Contact: Russ Weight ++Description: Read-only. Read this file to determine the status of SDM ++ partial reconfiguration key provisioning. ++ Format: "0x%x". ++ + What: /sys/bus/platform/drivers/intel-m10bmc-sec-update/.../control/available_images + Date: Nov 2021 + KernelVersion: 5.16 +diff --git a/drivers/fpga/intel-m10-bmc-sec-update.c b/drivers/fpga/intel-m10-bmc-sec-update.c +index a092b5f10989..7147f580e246 100644 +--- a/drivers/fpga/intel-m10-bmc-sec-update.c ++++ b/drivers/fpga/intel-m10-bmc-sec-update.c +@@ -186,6 +186,15 @@ static int pmci_sec_sdm_sr_image_load(struct m10bmc_sec *sec) + PMCI_SDM_SR_IMG_REQ, PMCI_SDM_SR_IMG_REQ); + } + ++static int pmci_sec_sdm_pr_image_load(struct m10bmc_sec *sec) ++{ ++ const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; ++ ++ return regmap_update_bits(sec->m10bmc->regmap, ++ csr_map->base + M10BMC_PMCI_SDM_PR_CTRL_STS, ++ PMCI_SDM_PR_IMG_REQ, PMCI_SDM_PR_IMG_REQ); ++} ++ + static int m10bmc_sec_bmc_image_load_0(struct m10bmc_sec *sec) + { + return m10bmc_sec_bmc_image_load(sec, 0); +@@ -420,6 +429,10 @@ static struct image_load n6000_image_load_hndlrs[] = { + .name = "sdm_sr", + .load_image = pmci_sec_sdm_sr_image_load, + }, ++ { ++ .name = "sdm_pr", ++ .load_image = pmci_sec_sdm_pr_image_load, ++ }, + {} + }; + +@@ -647,12 +660,30 @@ static ssize_t sdm_sr_provision_status_show(struct device *dev, + } + static DEVICE_ATTR_RO(sdm_sr_provision_status); + +-static umode_t m10bmc_security_is_visible(struct kobject *kobj, struct attribute *attr, int n) ++static ssize_t sdm_pr_provision_status_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct m10bmc_sec *sec = dev_get_drvdata(dev); ++ const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; ++ u32 status; ++ int ret; ++ ++ ret = m10bmc_sys_read(sec->m10bmc, csr_map->base + M10BMC_PMCI_SDM_PR_CTRL_STS, &status); ++ if (ret) ++ return ret; ++ ++ return sysfs_emit(buf, "0x%x\n", (unsigned int)FIELD_GET(PMCI_SDM_PR_PGM_ERROR, status)); ++} ++static DEVICE_ATTR_RO(sdm_pr_provision_status); ++ ++static umode_t ++m10bmc_security_is_visible(struct kobject *kobj, struct attribute *attr, int n) + { + struct m10bmc_sec *sec = dev_get_drvdata(kobj_to_dev(kobj)); + + if (!sec->ops->sec_visible && +- attr == &dev_attr_sdm_sr_provision_status.attr) ++ (attr == &dev_attr_sdm_sr_provision_status.attr || ++ attr == &dev_attr_sdm_pr_provision_status.attr)) + return 0; + + return attr->mode; +@@ -667,6 +698,7 @@ static struct attribute *m10bmc_security_attrs[] = { + &dev_attr_pr_canceled_csks.attr, + &dev_attr_bmc_canceled_csks.attr, + &dev_attr_sdm_sr_provision_status.attr, ++ &dev_attr_sdm_pr_provision_status.attr, + NULL, + }; + +diff --git a/include/linux/mfd/intel-m10-bmc.h b/include/linux/mfd/intel-m10-bmc.h +index 65c9ff8b9bb5..deb55fec524e 100644 +--- a/include/linux/mfd/intel-m10-bmc.h ++++ b/include/linux/mfd/intel-m10-bmc.h +@@ -228,6 +228,10 @@ + #define PMCI_SDM_SR_IMG_REQ BIT(0) + #define PMCI_SDM_SR_PGM_ERROR GENMASK(23, 16) + ++#define M10BMC_PMCI_SDM_PR_CTRL_STS 0x238 ++#define PMCI_SDM_PR_IMG_REQ BIT(0) ++#define PMCI_SDM_PR_PGM_ERROR GENMASK(23, 16) ++ + #define M10BMC_PMCI_SDM_PR_STS 0x820 + #define M10BMC_PMCI_CERT_PROG_STS 0x824 + #define M10BMC_PMCI_CERT_SPEC_STS 0x828 diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0039-fpga-m10bmc-sec-Support-SDM-SR-PR-cancellation.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0039-fpga-m10bmc-sec-Support-SDM-SR-PR-cancellation.patch new file mode 100644 index 0000000..178fedb --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0039-fpga-m10bmc-sec-Support-SDM-SR-PR-cancellation.patch @@ -0,0 +1,191 @@ +From 31d93e7621a86554c9a9e378f837bfbf5bfa7d6b Mon Sep 17 00:00:00 2001 +From: Russ Weight +Date: Mon, 22 Aug 2022 16:57:11 -0700 +Subject: [PATCH] fpga: m10bmc-sec: Support SDM SR/PR cancellation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add new image-load triggers to support SDM SR and PR cancellation. Add +sdm_sr_cancel_status amd sdm_pr_cancel_status sysfs nodes to the security +directory to provide status on SDM key cancellation. + +Co-developed-by: Russ Weight +Signed-off-by: Russ Weight +Signed-off-by: Ilpo Järvinen +--- + .../sysfs-driver-intel-m10-bmc-sec-update | 16 +++++ + drivers/fpga/intel-m10-bmc-sec-update.c | 66 ++++++++++++++++++- + include/linux/mfd/intel-m10-bmc.h | 8 +++ + 3 files changed, 89 insertions(+), 1 deletion(-) + +diff --git a/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update b/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update +index 761a1bc442fd..5a486e76dfde 100644 +--- a/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update ++++ b/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update +@@ -76,6 +76,22 @@ Description: Read-only. Read this file to determine the status of SDM + partial reconfiguration key provisioning. + Format: "0x%x". + ++What: /sys/bus/platform/drivers/intel-m10bmc-sec-update/.../security/sdm_sr_cancel_status ++Date: Dec 2022 ++KernelVersion: 6.1 ++Contact: Russ Weight ++Description: Read-only. Read this file to determine the status of SDM ++ static region key cancellation. ++ Format: "0x%x". ++ ++What: /sys/bus/platform/drivers/intel-m10bmc-sec-update/.../security/sdm_pr_cancel_status ++Date: Dec 2022 ++KernelVersion: 6.1 ++Contact: Russ Weight ++Description: Read-only. Read this file to determine the status of SDM ++ partial reconfiguration key cancellation. ++ Format: "0x%x". ++ + What: /sys/bus/platform/drivers/intel-m10bmc-sec-update/.../control/available_images + Date: Nov 2021 + KernelVersion: 5.16 +diff --git a/drivers/fpga/intel-m10-bmc-sec-update.c b/drivers/fpga/intel-m10-bmc-sec-update.c +index 7147f580e246..6670a28d6075 100644 +--- a/drivers/fpga/intel-m10-bmc-sec-update.c ++++ b/drivers/fpga/intel-m10-bmc-sec-update.c +@@ -186,6 +186,15 @@ static int pmci_sec_sdm_sr_image_load(struct m10bmc_sec *sec) + PMCI_SDM_SR_IMG_REQ, PMCI_SDM_SR_IMG_REQ); + } + ++static int pmci_sec_sdm_sr_cancel(struct m10bmc_sec *sec) ++{ ++ const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; ++ ++ return regmap_update_bits(sec->m10bmc->regmap, ++ csr_map->base + M10BMC_PMCI_SDM_SR_CNCL_CTRL_STS, ++ PMCI_SDM_SR_CNCL_REQ, PMCI_SDM_SR_CNCL_REQ); ++} ++ + static int pmci_sec_sdm_pr_image_load(struct m10bmc_sec *sec) + { + const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; +@@ -195,6 +204,15 @@ static int pmci_sec_sdm_pr_image_load(struct m10bmc_sec *sec) + PMCI_SDM_PR_IMG_REQ, PMCI_SDM_PR_IMG_REQ); + } + ++static int pmci_sec_sdm_pr_cancel(struct m10bmc_sec *sec) ++{ ++ const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; ++ ++ return regmap_update_bits(sec->m10bmc->regmap, ++ csr_map->base + M10BMC_PMCI_SDM_PR_CNCL_CTRL_STS, ++ PMCI_SDM_PR_CNCL_REQ, PMCI_SDM_PR_CNCL_REQ); ++} ++ + static int m10bmc_sec_bmc_image_load_0(struct m10bmc_sec *sec) + { + return m10bmc_sec_bmc_image_load(sec, 0); +@@ -429,10 +447,18 @@ static struct image_load n6000_image_load_hndlrs[] = { + .name = "sdm_sr", + .load_image = pmci_sec_sdm_sr_image_load, + }, ++ { ++ .name = "sdm_sr_cancel", ++ .load_image = pmci_sec_sdm_sr_cancel, ++ }, + { + .name = "sdm_pr", + .load_image = pmci_sec_sdm_pr_image_load, + }, ++ { ++ .name = "sdm_pr_cancel", ++ .load_image = pmci_sec_sdm_pr_cancel, ++ }, + {} + }; + +@@ -660,6 +686,23 @@ static ssize_t sdm_sr_provision_status_show(struct device *dev, + } + static DEVICE_ATTR_RO(sdm_sr_provision_status); + ++static ssize_t sdm_sr_cancel_status_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct m10bmc_sec *sec = dev_get_drvdata(dev); ++ const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; ++ u32 status; ++ int ret; ++ ++ ret = m10bmc_sys_read(sec->m10bmc, ++ csr_map->base + M10BMC_PMCI_SDM_SR_CNCL_CTRL_STS, &status); ++ if (ret) ++ return ret; ++ ++ return sysfs_emit(buf, "0x%x\n", (unsigned int)FIELD_GET(PMCI_SDM_SR_CNCL_ERROR, status)); ++} ++static DEVICE_ATTR_RO(sdm_sr_cancel_status); ++ + static ssize_t sdm_pr_provision_status_show(struct device *dev, + struct device_attribute *attr, char *buf) + { +@@ -676,6 +719,23 @@ static ssize_t sdm_pr_provision_status_show(struct device *dev, + } + static DEVICE_ATTR_RO(sdm_pr_provision_status); + ++static ssize_t sdm_pr_cancel_status_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct m10bmc_sec *sec = dev_get_drvdata(dev); ++ const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; ++ u32 status; ++ int ret; ++ ++ ret = m10bmc_sys_read(sec->m10bmc, ++ csr_map->base + M10BMC_PMCI_SDM_PR_CNCL_CTRL_STS, &status); ++ if (ret) ++ return ret; ++ ++ return sysfs_emit(buf, "0x%x\n", (unsigned int)FIELD_GET(PMCI_SDM_PR_CNCL_ERROR, status)); ++} ++static DEVICE_ATTR_RO(sdm_pr_cancel_status); ++ + static umode_t + m10bmc_security_is_visible(struct kobject *kobj, struct attribute *attr, int n) + { +@@ -683,7 +743,9 @@ m10bmc_security_is_visible(struct kobject *kobj, struct attribute *attr, int n) + + if (!sec->ops->sec_visible && + (attr == &dev_attr_sdm_sr_provision_status.attr || +- attr == &dev_attr_sdm_pr_provision_status.attr)) ++ attr == &dev_attr_sdm_sr_cancel_status.attr || ++ attr == &dev_attr_sdm_pr_provision_status.attr || ++ attr == &dev_attr_sdm_pr_cancel_status.attr)) + return 0; + + return attr->mode; +@@ -698,7 +760,9 @@ static struct attribute *m10bmc_security_attrs[] = { + &dev_attr_pr_canceled_csks.attr, + &dev_attr_bmc_canceled_csks.attr, + &dev_attr_sdm_sr_provision_status.attr, ++ &dev_attr_sdm_sr_cancel_status.attr, + &dev_attr_sdm_pr_provision_status.attr, ++ &dev_attr_sdm_pr_cancel_status.attr, + NULL, + }; + +diff --git a/include/linux/mfd/intel-m10-bmc.h b/include/linux/mfd/intel-m10-bmc.h +index deb55fec524e..a66446fd7956 100644 +--- a/include/linux/mfd/intel-m10-bmc.h ++++ b/include/linux/mfd/intel-m10-bmc.h +@@ -232,6 +232,14 @@ + #define PMCI_SDM_PR_IMG_REQ BIT(0) + #define PMCI_SDM_PR_PGM_ERROR GENMASK(23, 16) + ++#define M10BMC_PMCI_SDM_SR_CNCL_CTRL_STS 0x23c ++#define PMCI_SDM_SR_CNCL_REQ BIT(0) ++#define PMCI_SDM_SR_CNCL_ERROR GENMASK(18, 8) ++ ++#define M10BMC_PMCI_SDM_PR_CNCL_CTRL_STS 0x240 ++#define PMCI_SDM_PR_CNCL_REQ BIT(0) ++#define PMCI_SDM_PR_CNCL_ERROR GENMASK(18, 8) ++ + #define M10BMC_PMCI_SDM_PR_STS 0x820 + #define M10BMC_PMCI_CERT_PROG_STS 0x824 + #define M10BMC_PMCI_CERT_SPEC_STS 0x828 diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0040-fpga-m10bmc-sec-PR-SR-root-key-hash-support-for-VAB.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0040-fpga-m10bmc-sec-PR-SR-root-key-hash-support-for-VAB.patch new file mode 100644 index 0000000..d2f1760 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0040-fpga-m10bmc-sec-PR-SR-root-key-hash-support-for-VAB.patch @@ -0,0 +1,218 @@ +From 4fa87e11cd81d5c89fc760625620ec8c91f23501 Mon Sep 17 00:00:00 2001 +From: Tianfei zhang +Date: Thu, 13 Jan 2022 16:07:34 +0800 +Subject: [PATCH] fpga: m10bmc-sec: PR/SR root key hash support for VAB +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add support for reading the Secure Device Manager (SDM) PR/SR +Root Entry Hash and Cancellation Key. This support is required +for Vender Authenticated Boot (VAB). + +Co-developed-by: Tianfei zhang +Signed-off-by: Tianfei zhang +Signed-off-by: Ilpo Järvinen +--- + .../sysfs-driver-intel-m10-bmc-sec-update | 37 +++++++++ + drivers/fpga/intel-m10-bmc-sec-update.c | 77 ++++++++++++++++++- + drivers/mfd/intel-m10-bmc-pmci.c | 4 + + include/linux/mfd/intel-m10-bmc.h | 9 +++ + 4 files changed, 126 insertions(+), 1 deletion(-) + +diff --git a/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update b/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update +index 5a486e76dfde..8837c0ed3b89 100644 +--- a/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update ++++ b/Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update +@@ -148,3 +148,40 @@ Contact: Tianfei zhang + Description: Read-only. Reading this file will return the name of image booted + from FPGA. The EINVAL error code will be returned if no image booted + from FPGA. ++ ++What: /sys/bus/platform/drivers/intel-m10bmc-sec-update/.../security/sr_sdm_root_entry_hash ++Date: Jan 2022 ++KernelVersion: 5.16 ++Contact: Tianfei Zhang ++Description: Read only. Returns the root entry hash of SDM (Secure Device ++ Manager) for the static region if one is programmed, else it ++ returns the string: "hash not programmed". This file is only ++ visible if the underlying device supports it. ++ Format: "0x%x". ++ ++What: /sys/bus/platform/drivers/intel-m10bmc-sec-update/.../security/pr_sdm_root_entry_hash ++Date: Jan 2022 ++KernelVersion: 5.16 ++Contact: Tianfei Zhang ++Description: Read only. Returns the root entry hash of SDM (Secure Device ++ Manager) for the partial reconfiguration region if one is programmed, ++ else it returns the string: "hash not programmed". This file ++ is only visible if the underlying device supports it. ++ Format: "0x%x". ++ ++What: /sys/bus/platform/drivers/intel-m10bmc-sec-update/.../security/pr_sdm_canceled_csks ++Date: Jan 2022 ++KernelVersion: 5.16 ++Contact: Tianfei Zhang ++Description: Read only. Returns a list of indices for canceled code ++ signing keys of SDM (Secure Device Manager) for the partial ++ reconfiguration region. The standard bitmap list format is ++ used (e.g. "1,2-6,9"). ++ ++What: /sys/bus/platform/drivers/intel-m10bmc-sec-update/.../security/sr_sdm_canceled_csks ++Date: Jan 2022 ++KernelVersion: 5.16 ++Contact: Tianfei Zhang ++Description: Read only. Returns a list of indices for canceled code ++ signing keys of SDM (Secure Device Manager) for the static ++ region. The standard bitmap list format is used (e.g. "1,2-6,9"). +diff --git a/drivers/fpga/intel-m10-bmc-sec-update.c b/drivers/fpga/intel-m10-bmc-sec-update.c +index 6670a28d6075..17936f3a70dc 100644 +--- a/drivers/fpga/intel-m10-bmc-sec-update.c ++++ b/drivers/fpga/intel-m10-bmc-sec-update.c +@@ -591,6 +591,44 @@ DEVICE_ATTR_SEC_REH_RO(bmc); + DEVICE_ATTR_SEC_REH_RO(sr); + DEVICE_ATTR_SEC_REH_RO(pr); + ++#define SDM_ROOT_HASH_REG_NUM 12 ++ ++static ssize_t ++show_sdm_root_entry_hash(struct device *dev, u32 start, char *buf) ++{ ++ struct m10bmc_sec *sec = dev_get_drvdata(dev); ++ const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; ++ int i, cnt, ret; ++ u32 key; ++ ++ cnt = sprintf(buf, "0x"); ++ for (i = 0; i < SDM_ROOT_HASH_REG_NUM; i++) { ++ ret = m10bmc_sys_read(sec->m10bmc, csr_map->base + start + i * 4, &key); ++ if (ret) ++ return ret; ++ ++ cnt += sprintf(buf + cnt, "%08x", key); ++ } ++ cnt += sprintf(buf + cnt, "\n"); ++ ++ return cnt; ++} ++ ++#define DEVICE_ATTR_SDM_SEC_REH_RO(_name) \ ++static ssize_t _name##_sdm_root_entry_hash_show(struct device *dev, \ ++ struct device_attribute *attr, \ ++ char *buf) \ ++{ \ ++ struct m10bmc_sec *sec = dev_get_drvdata(dev); \ ++ const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; \ ++ \ ++ return show_sdm_root_entry_hash(dev, csr_map->_name##_sdm_reh_reg, buf);\ ++} \ ++static DEVICE_ATTR_RO(_name##_sdm_root_entry_hash) ++ ++DEVICE_ATTR_SDM_SEC_REH_RO(pr); ++DEVICE_ATTR_SDM_SEC_REH_RO(sr); ++ + #define CSK_BIT_LEN 128U + #define CSK_32ARRAY_SIZE DIV_ROUND_UP(CSK_BIT_LEN, 32) + +@@ -638,6 +676,35 @@ DEVICE_ATTR_SEC_CSK_RO(bmc); + DEVICE_ATTR_SEC_CSK_RO(sr); + DEVICE_ATTR_SEC_CSK_RO(pr); + ++static ssize_t ++show_sdm_canceled_csk(struct device *dev, u32 addr, char *buf) ++{ ++ struct m10bmc_sec *sec = dev_get_drvdata(dev); ++ const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; ++ int ret; ++ u32 val; ++ ++ ret = m10bmc_sys_read(sec->m10bmc, csr_map->base + addr, &val); ++ if (ret) ++ return ret; ++ ++ return sysfs_emit(buf, "%08x\n", val); ++} ++ ++#define DEVICE_ATTR_SDM_SEC_CSK_RO(_name) \ ++static ssize_t _name##_sdm_canceled_csks_show(struct device *dev, \ ++ struct device_attribute *attr, \ ++ char *buf) \ ++{ \ ++ struct m10bmc_sec *sec = dev_get_drvdata(dev); \ ++ const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; \ ++ \ ++ return show_sdm_canceled_csk(dev, csr_map->_name##_sdm_csk_reg, buf); \ ++} \ ++static DEVICE_ATTR_RO(_name##_sdm_canceled_csks) ++DEVICE_ATTR_SDM_SEC_CSK_RO(pr); ++DEVICE_ATTR_SDM_SEC_CSK_RO(sr); ++ + #define FLASH_COUNT_SIZE 4096 /* count stored as inverted bit vector */ + + static ssize_t flash_count_show(struct device *dev, +@@ -745,7 +812,11 @@ m10bmc_security_is_visible(struct kobject *kobj, struct attribute *attr, int n) + (attr == &dev_attr_sdm_sr_provision_status.attr || + attr == &dev_attr_sdm_sr_cancel_status.attr || + attr == &dev_attr_sdm_pr_provision_status.attr || +- attr == &dev_attr_sdm_pr_cancel_status.attr)) ++ attr == &dev_attr_sdm_pr_cancel_status.attr || ++ attr == &dev_attr_pr_sdm_root_entry_hash.attr || ++ attr == &dev_attr_pr_sdm_canceled_csks.attr || ++ attr == &dev_attr_sr_sdm_root_entry_hash.attr || ++ attr == &dev_attr_sr_sdm_canceled_csks.attr)) + return 0; + + return attr->mode; +@@ -763,6 +834,10 @@ static struct attribute *m10bmc_security_attrs[] = { + &dev_attr_sdm_sr_cancel_status.attr, + &dev_attr_sdm_pr_provision_status.attr, + &dev_attr_sdm_pr_cancel_status.attr, ++ &dev_attr_pr_sdm_root_entry_hash.attr, ++ &dev_attr_pr_sdm_canceled_csks.attr, ++ &dev_attr_sr_sdm_root_entry_hash.attr, ++ &dev_attr_sr_sdm_canceled_csks.attr, + NULL, + }; + +diff --git a/drivers/mfd/intel-m10-bmc-pmci.c b/drivers/mfd/intel-m10-bmc-pmci.c +index 68eb3fc131f9..c3e0e392dd2b 100644 +--- a/drivers/mfd/intel-m10-bmc-pmci.c ++++ b/drivers/mfd/intel-m10-bmc-pmci.c +@@ -371,6 +371,10 @@ static const struct m10bmc_csr_map m10bmc_n6000_csr_map = { + .pr_reh_addr = M10BMC_N6000_PR_REH_ADDR, + .pr_magic = M10BMC_N6000_PR_PROG_MAGIC, + .rsu_update_counter = M10BMC_N6000_STAGING_FLASH_COUNT, ++ .pr_sdm_reh_reg = M10BMC_PMCI_PR_RH0, ++ .pr_sdm_csk_reg = M10BMC_PMCI_PR_CSK, ++ .sr_sdm_reh_reg = M10BMC_PMCI_SR_RH0, ++ .sr_sdm_csk_reg = M10BMC_PMCI_SR_CSK, + .staging_size = M10BMC_STAGING_SIZE, + }; + +diff --git a/include/linux/mfd/intel-m10-bmc.h b/include/linux/mfd/intel-m10-bmc.h +index a66446fd7956..c2a7888ef17e 100644 +--- a/include/linux/mfd/intel-m10-bmc.h ++++ b/include/linux/mfd/intel-m10-bmc.h +@@ -244,6 +244,11 @@ + #define M10BMC_PMCI_CERT_PROG_STS 0x824 + #define M10BMC_PMCI_CERT_SPEC_STS 0x828 + ++#define M10BMC_PMCI_SR_RH0 0x848 ++#define M10BMC_PMCI_SR_CSK 0x878 ++#define M10BMC_PMCI_PR_RH0 0x87c ++#define M10BMC_PMCI_PR_CSK 0x8ac ++ + #define M10BMC_N6000_BUILD_VER 0x0 + #define NIOS2_N6000_FW_VERSION 0x4 + #define M10BMC_N6000_MAC_LOW 0x20 +@@ -324,6 +329,10 @@ struct m10bmc_csr_map { + unsigned int pr_reh_addr; + unsigned int pr_magic; + unsigned int rsu_update_counter; ++ unsigned int pr_sdm_reh_reg; ++ unsigned int pr_sdm_csk_reg; ++ unsigned int sr_sdm_reh_reg; ++ unsigned int sr_sdm_csk_reg; + unsigned int staging_size; + }; + diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0041-fpga-m10bmc-sec-Add-trigger-to-read-SDM-key-hashes.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0041-fpga-m10bmc-sec-Add-trigger-to-read-SDM-key-hashes.patch new file mode 100644 index 0000000..99dc7b2 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0041-fpga-m10bmc-sec-Add-trigger-to-read-SDM-key-hashes.patch @@ -0,0 +1,164 @@ +From 6be329c2c090bf7b5d083c82b34f1235b37ed450 Mon Sep 17 00:00:00 2001 +From: Tianfei Zhang +Date: Fri, 8 Jul 2022 22:36:14 +0800 +Subject: [PATCH] fpga: m10bmc-sec: Add trigger to read SDM key hashes +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Trigger the reading of the SDM key hashes to BMC registers during driver +initialization and check for completion of the read before completing +a sysfs read for the same data. The SDM trigger is executed in a +worker thread and flush_work() is used to guarantee that the work +has completed before responding to a sysfs read of the data. + +Signed-off-by: Tianfei Zhang +Signed-off-by: Russ Weight +Signed-off-by: Ilpo Järvinen +--- + drivers/fpga/intel-m10-bmc-sec-update.c | 80 +++++++++++++++++++++++++ + include/linux/mfd/intel-m10-bmc.h | 12 ++++ + 2 files changed, 92 insertions(+) + +diff --git a/drivers/fpga/intel-m10-bmc-sec-update.c b/drivers/fpga/intel-m10-bmc-sec-update.c +index 17936f3a70dc..605574796617 100644 +--- a/drivers/fpga/intel-m10-bmc-sec-update.c ++++ b/drivers/fpga/intel-m10-bmc-sec-update.c +@@ -56,6 +56,7 @@ struct m10bmc_sec { + u32 fw_name_id; + bool cancel_request; + const struct m10bmc_sec_ops *ops; ++ struct work_struct work; + }; + + static void log_error_regs(struct m10bmc_sec *sec, u32 doorbell) +@@ -593,6 +594,72 @@ DEVICE_ATTR_SEC_REH_RO(pr); + + #define SDM_ROOT_HASH_REG_NUM 12 + ++static int sdm_check_config_status(struct m10bmc_sec *sec) ++{ ++ struct intel_m10bmc *m10bmc = sec->m10bmc; ++ u32 val; ++ int ret; ++ ++ ret = m10bmc_sys_read(m10bmc, M10BMC_PMCI_SDM_CTRL, &val); ++ if (ret) ++ return -EIO; ++ ++ return FIELD_GET(SDM_CMD_DONE, val); ++} ++ ++static int sdm_trigger_prov_data(struct m10bmc_sec *sec) ++{ ++ const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; ++ struct intel_m10bmc *m10bmc = sec->m10bmc; ++ u32 cmd = 0; ++ int ret; ++ ++ ret = m10bmc_sys_update_bits(m10bmc, ++ M10BMC_PMCI_SDM_CTRL, ++ SDM_CMD_SELECT, ++ FIELD_PREP(SDM_CMD_SELECT, SDM_CMD_PROV_DATA)); ++ if (ret) ++ return ret; ++ ++ ret = m10bmc_sys_update_bits(m10bmc, ++ M10BMC_PMCI_SDM_CTRL, ++ SDM_CMD_TRIGGER, SDM_CMD_TRIGGER); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read_poll_timeout(m10bmc->regmap, ++ csr_map->base + M10BMC_PMCI_SDM_CTRL, ++ cmd, sdm_status(cmd) == SDM_CMD_STATUS_IDLE, ++ NIOS_HANDSHAKE_INTERVAL_US, ++ NIOS_HANDSHAKE_TIMEOUT_US); ++ if (ret) { ++ dev_err(sec->dev, "Error polling SDM CTRL register: %d\n", ret); ++ return ret; ++ } else if (sdm_error(cmd) != SDM_CMD_SUCC) { ++ dev_err(sec->dev, "SDM trigger failure: %ld\n", sdm_error(cmd)); ++ return -EIO; ++ } ++ ++ ret = regmap_read_poll_timeout(m10bmc->regmap, ++ csr_map->base + M10BMC_PMCI_SDM_CTRL, ++ cmd, (cmd & SDM_CMD_DONE), ++ NIOS_HANDSHAKE_INTERVAL_US, ++ 2 * NIOS_HANDSHAKE_TIMEOUT_US); ++ if (ret) { ++ dev_err(sec->dev, "Error polling for SDM operation done: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void sdm_work(struct work_struct *work) ++{ ++ struct m10bmc_sec *sec = container_of(work, struct m10bmc_sec, work); ++ ++ sdm_trigger_prov_data(sec); ++} ++ + static ssize_t + show_sdm_root_entry_hash(struct device *dev, u32 start, char *buf) + { +@@ -601,6 +668,11 @@ show_sdm_root_entry_hash(struct device *dev, u32 start, char *buf) + int i, cnt, ret; + u32 key; + ++ flush_work(&sec->work); ++ ++ if (sdm_check_config_status(sec) <= 0) ++ return -EIO; ++ + cnt = sprintf(buf, "0x"); + for (i = 0; i < SDM_ROOT_HASH_REG_NUM; i++) { + ret = m10bmc_sys_read(sec->m10bmc, csr_map->base + start + i * 4, &key); +@@ -1536,6 +1608,11 @@ static int m10bmc_sec_probe(struct platform_device *pdev) + sec->ops = (struct m10bmc_sec_ops *)platform_get_device_id(pdev)->driver_data; + dev_set_drvdata(&pdev->dev, sec); + ++ if (sec->ops->sec_visible) { ++ INIT_WORK(&sec->work, sdm_work); ++ queue_work(system_long_wq, &sec->work); ++ } ++ + ret = xa_alloc(&fw_upload_xa, &sec->fw_name_id, sec, + xa_limit_32b, GFP_KERNEL); + if (ret) +@@ -1571,6 +1648,9 @@ static int m10bmc_sec_remove(struct platform_device *pdev) + { + struct m10bmc_sec *sec = dev_get_drvdata(&pdev->dev); + ++ if (sec->ops->sec_visible) ++ flush_work(&sec->work); ++ + firmware_upload_unregister(sec->fwl); + kfree(sec->fw_name); + xa_erase(&fw_upload_xa, sec->fw_name_id); +diff --git a/include/linux/mfd/intel-m10-bmc.h b/include/linux/mfd/intel-m10-bmc.h +index c2a7888ef17e..0933d768e0bb 100644 +--- a/include/linux/mfd/intel-m10-bmc.h ++++ b/include/linux/mfd/intel-m10-bmc.h +@@ -228,6 +228,18 @@ + #define PMCI_SDM_SR_IMG_REQ BIT(0) + #define PMCI_SDM_SR_PGM_ERROR GENMASK(23, 16) + ++#define M10BMC_PMCI_SDM_CTRL 0x234 ++#define SDM_CMD_TRIGGER BIT(0) ++#define SDM_CMD_DONE BIT(2) ++#define SDM_CMD_SELECT GENMASK(11, 4) ++#define SDM_CMD_PROV_DATA 0x3 ++#define SDM_CMD_STATUS GENMASK(15, 12) ++#define sdm_status(cmd) FIELD_GET(SDM_CMD_STATUS, cmd) ++#define SDM_CMD_STATUS_IDLE 0x0 ++#define SDM_CMD_ERROR GENMASK(23, 16) ++#define sdm_error(cmd) FIELD_GET(SDM_CMD_ERROR, cmd) ++#define SDM_CMD_SUCC 0x0 ++ + #define M10BMC_PMCI_SDM_PR_CTRL_STS 0x238 + #define PMCI_SDM_PR_IMG_REQ BIT(0) + #define PMCI_SDM_PR_PGM_ERROR GENMASK(23, 16) diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0042-hwmon-Add-sensor-support-for-the-C6100-card.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0042-hwmon-Add-sensor-support-for-the-C6100-card.patch new file mode 100644 index 0000000..b998c7e --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0042-hwmon-Add-sensor-support-for-the-C6100-card.patch @@ -0,0 +1,176 @@ +From 0e1fdb3dbb578eb8de850f4b3915d56fd16e30a9 Mon Sep 17 00:00:00 2001 +From: Matthew Gerlach +Date: Tue, 10 Jan 2023 10:35:35 +0200 +Subject: [PATCH] hwmon: Add sensor support for the C6100 card + +Add sensor support for C61000 FPGA card. + +Signed-off-by: Matthew Gerlach +--- + drivers/hwmon/intel-m10-bmc-hwmon.c | 146 ++++++++++++++++++++++++++++ + 1 file changed, 146 insertions(+) + +diff --git a/drivers/hwmon/intel-m10-bmc-hwmon.c b/drivers/hwmon/intel-m10-bmc-hwmon.c +index 232f7d428efe..1dc6a1db5b4e 100644 +--- a/drivers/hwmon/intel-m10-bmc-hwmon.c ++++ b/drivers/hwmon/intel-m10-bmc-hwmon.c +@@ -679,6 +679,148 @@ static const struct m10bmc_hwmon_board_data n6000bmc_hwmon_bdata = { + .hinfo = n6000bmc_hinfo, + }; + ++static const struct m10bmc_sdata c6100bmc_temp_tbl[] = { ++ { 0x440, 0x0, 0x0, 0x0, 0x0, 500, "FPGA E-TILE Max Temperature" }, ++ { 0x444, 0x448, 0x44c, 0x0, 0x0, 500, "FPGA E-TILE Temperature #1" }, ++ { 0x450, 0x454, 0x458, 0x0, 0x0, 500, "FPGA E-TILE Temperature #2" }, ++ { 0x45c, 0x460, 0x464, 0x0, 0x0, 500, "FPGA E-TILE Temperature #3" }, ++ { 0x468, 0x46c, 0x470, 0x0, 0x0, 500, "FPGA E-TILE Temperature #4" }, ++ { 0x474, 0x478, 0x47c, 0x0, 0x0, 500, "FPGA P-TILE Temperature" }, ++ { 0x5b4, 0x5b8, 0x5bc, 0x0, 0x0, 500, "FPGA P-TILE2 DTS Temperature" }, ++ { 0x480, 0x0, 0x0, 0x0, 0x0, 500, "FPGA FABRIC Max Temperature" }, ++ { 0x484, 0x488, 0x48c, 0x0, 0x0, 500, "FPGA FABRIC Digital Temperature#1" }, ++ { 0x490, 0x494, 0x498, 0x0, 0x0, 500, "FPGA FABRIC Digital Temperature#2" }, ++ { 0x49c, 0x4a0, 0x4a4, 0x0, 0x0, 500, "FPGA FABRIC Digital Temperature#3" }, ++ { 0x4a8, 0x4ac, 0x4b0, 0x0, 0x0, 500, "FPGA FABRIC Digital Temperature#4" }, ++ { 0x4b4, 0x4b8, 0x4bc, 0x0, 0x0, 500, "FPGA FABRIC Digital Temperature#5" }, ++ { 0x4d8, 0x4dc, 0x4e0, 0x0, 0x0, 500, "FPGA FABRIC Remote Digital Temperature#3" }, ++ { 0x4e4, 0x4e8, 0x4ec, 0x0, 0x0, 500, "FPGA FABRIC Remote Digital Temperature#4" }, ++ { 0x4fc, 0x500, 0x504, 0x5c0, 0x0, 500, "Board Bottom Temperature" }, ++ { 0x5e8, 0x5ec, 0x5f0, 0x5c0, 0x0, 500, "FPGA Corner (SDM) Temperature [Remote]" }, ++ { 0x5dc, 0x5e0, 0x5e4, 0x5c0, 0x0, 500, "FPGA Core Fabric Temperature [Remote]" }, ++ { 0x5c4, 0x5c8, 0x5cc, 0x5c0, 0x0, 500, "FPGA P-Tile Temperature [Remote]" }, ++ { 0x5d0, 0x5d4, 0x5d8, 0x5c0, 0x0, 500, "FPGA E-Tile Temperature [Remote]" }, ++ { 0x4f0, 0x4f4, 0x4f8, 0x52c, 0x0, 500, "Board Top Temperature" }, ++ { 0x520, 0x524, 0x528, 0x52c, 0x0, 500, "Board Rear Side Temperature" }, ++ { 0x530, 0x534, 0x538, 0x52c, 0x0, 500, "Board Front Side Temperature" }, ++ { 0x508, 0x50c, 0x510, 0x52c, 0x0, 500, "FPGA Ambient Temperature" }, ++ { 0x514, 0x518, 0x51c, 0x52c, 0x0, 500, "FPGA PTILE2 External Temperature" }, ++ { 0x53c, 0x540, 0x544, 0x0, 0x0, 500, "QSFP1 Temperature" }, ++ { 0x548, 0x54c, 0x550, 0x0, 0x0, 500, "QSFP2 Temperature" }, ++ { 0x728, 0x72c, 0x730, 0x0, 0x0, 500, "Virt FPGA Temperature" }, ++ { 0x758, 0x750, 0x754, 0x0, 0x0, 15, "SOC Package Temperature" }, ++}; ++ ++static const struct m10bmc_sdata c6100bmc_in_tbl[] = { ++ { 0x5f4, 0x0, 0x0, 0x0, 0x0, 1, "Inlet 12V PCIe Rail Voltage" }, ++ { 0x60c, 0x0, 0x0, 0x0, 0x0, 1, "Inlet 12V Aux Rail Voltage" }, ++ { 0x624, 0x0, 0x0, 0x0, 0x0, 1, "Inlet 3V3 PCIe Rail Voltage" }, ++ { 0x6b4, 0x0, 0x0, 0x0, 0x0, 1, "QSFP 3V3 Rail Voltage" }, ++ { 0x6c4, 0x0, 0x0, 0x0, 0x0, 1, "QSFP (Primary) Supply Rail Voltage" }, ++ { 0x6c8, 0x0, 0x0, 0x0, 0x0, 1, "QSFP (Secondary) Supply Rail Voltage" }, ++}; ++ ++static const struct m10bmc_sdata c6100bmc_curr_tbl[] = { ++ { 0x600, 0x604, 0x608, 0x0, 0x0, 1, "Inlet 12V PCIe Rail Current" }, ++ { 0x618, 0x61c, 0x620, 0x0, 0x0, 1, "Inlet 12V Aux Rail Current" }, ++ { 0x630, 0x634, 0x638, 0x0, 0x0, 1, "Inlet 3V3 PCIe Rail Current" }, ++ { 0x6b8, 0x6bc, 0x6c0, 0x0, 0x0, 1, "QSFP 3V3 Rail Current" }, ++}; ++ ++static const struct m10bmc_sdata c6100bmc_power_tbl[] = { ++ { 0x724, 0x0, 0x0, 0x0, 0x0, 1, "Board Power" }, ++ { 0x788, 0x0, 0x0, 0x0, 0x0, 1, "SOC Package Power" }, ++ { 0x694, 0x0, 0x0, 0x0, 0x0, 1, "FPGA Package Power" }, ++}; ++ ++static const struct hwmon_channel_info *c6100bmc_hinfo[] = { ++ HWMON_CHANNEL_INFO(temp, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST | ++ HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST | ++ HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST | ++ HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST | ++ HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST | ++ HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST | ++ HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST | ++ HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST | ++ HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST | ++ HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST | ++ HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL), ++ HWMON_CHANNEL_INFO(in, ++ HWMON_I_INPUT | HWMON_I_LABEL, ++ HWMON_I_INPUT | HWMON_I_LABEL, ++ HWMON_I_INPUT | HWMON_I_LABEL, ++ HWMON_I_INPUT | HWMON_I_LABEL, ++ HWMON_I_INPUT | HWMON_I_LABEL, ++ HWMON_I_INPUT | HWMON_I_LABEL), ++ HWMON_CHANNEL_INFO(curr, ++ HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_CRIT | ++ HWMON_C_LABEL, ++ HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_CRIT | ++ HWMON_C_LABEL, ++ HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_CRIT | ++ HWMON_C_LABEL, ++ HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_CRIT | ++ HWMON_C_LABEL), ++ HWMON_CHANNEL_INFO(power, ++ HWMON_P_INPUT | HWMON_P_LABEL, ++ HWMON_P_INPUT | HWMON_P_LABEL, ++ HWMON_P_INPUT | HWMON_P_LABEL), ++ NULL ++}; ++ ++static const struct m10bmc_hwmon_board_data c6100bmc_hwmon_bdata = { ++ .tables = { ++ [hwmon_temp] = c6100bmc_temp_tbl, ++ [hwmon_in] = c6100bmc_in_tbl, ++ [hwmon_curr] = c6100bmc_curr_tbl, ++ [hwmon_power] = c6100bmc_power_tbl, ++ }, ++ ++ .hinfo = c6100bmc_hinfo, ++}; ++ + static umode_t + m10bmc_hwmon_is_visible(const void *data, enum hwmon_sensor_types type, + u32 attr, int channel) +@@ -896,6 +1038,10 @@ static const struct platform_device_id intel_m10bmc_hwmon_ids[] = { + .name = "n6000bmc-hwmon", + .driver_data = (unsigned long)&n6000bmc_hwmon_bdata, + }, ++ { ++ .name = "c6100bmc-hwmon", ++ .driver_data = (unsigned long)&c6100bmc_hwmon_bdata, ++ }, + { } + }; + diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0043-mfd-intel-m10-bmc-Add-C6100-support.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0043-mfd-intel-m10-bmc-Add-C6100-support.patch new file mode 100644 index 0000000..eed456a --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0043-mfd-intel-m10-bmc-Add-C6100-support.patch @@ -0,0 +1,172 @@ +From 5e4338264f3793571cb44327ab9cb814920113cc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= +Date: Wed, 4 Jan 2023 16:26:45 +0200 +Subject: [PATCH] mfd: intel-m10-bmc: Add C6100 support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add support for the C6100 FPGA card into Intel M10 BMC MFD driver. + +Co-developed-by: Matthew Gerlach +Signed-off-by: Matthew Gerlach +Signed-off-by: Ilpo Järvinen +--- + drivers/mfd/intel-m10-bmc-log.c | 12 ++++++++ + drivers/mfd/intel-m10-bmc-pmci.c | 51 ++++++++++++++++++++++++++++++- + include/linux/mfd/intel-m10-bmc.h | 16 ++++++++++ + 3 files changed, 78 insertions(+), 1 deletion(-) + +diff --git a/drivers/mfd/intel-m10-bmc-log.c b/drivers/mfd/intel-m10-bmc-log.c +index d5e64506c92f..12ef1100da79 100644 +--- a/drivers/mfd/intel-m10-bmc-log.c ++++ b/drivers/mfd/intel-m10-bmc-log.c +@@ -237,11 +237,23 @@ static const struct m10bmc_log_cfg m10bmc_log_n6000_cfg = { + .bi_off = M10BMC_N6000_BOM_INFO_ADDR, + }; + ++static const struct m10bmc_log_cfg m10bmc_log_c6100_cfg = { ++ .el_size = M10BMC_N6000_ERROR_LOG_SIZE, ++ .el_off = M10BMC_C6100_ERROR_LOG_ADDR, ++ ++ .id_size = M10BMC_C6100_FPGA_IMAGE_DIR_SIZE, ++ .id_off = M10BMC_C6100_FPGA_IMAGE_DIR_ADDR, ++}; ++ + static const struct platform_device_id intel_m10bmc_log_ids[] = { + { + .name = "n6000bmc-log", + .driver_data = (unsigned long)&m10bmc_log_n6000_cfg, + }, ++ { ++ .name = "c6100bmc-log", ++ .driver_data = (unsigned long)&m10bmc_log_c6100_cfg, ++ }, + { } + }; + +diff --git a/drivers/mfd/intel-m10-bmc-pmci.c b/drivers/mfd/intel-m10-bmc-pmci.c +index c3e0e392dd2b..af2ddb92df6f 100644 +--- a/drivers/mfd/intel-m10-bmc-pmci.c ++++ b/drivers/mfd/intel-m10-bmc-pmci.c +@@ -353,6 +353,12 @@ static struct mfd_cell m10bmc_pmci_n6000_bmc_subdevs[] = { + { .name = "n6000bmc-log" }, + }; + ++static struct mfd_cell m10bmc_pmci_c6100_bmc_subdevs[] = { ++ { .name = "c6100bmc-hwmon" }, ++ { .name = "n6000bmc-sec-update" }, ++ { .name = "c6100bmc-log" }, ++}; ++ + static const struct m10bmc_csr_map m10bmc_n6000_csr_map = { + .base = M10BMC_N6000_SYS_BASE, + .build_version = M10BMC_N6000_BUILD_VER, +@@ -378,19 +384,62 @@ static const struct m10bmc_csr_map m10bmc_n6000_csr_map = { + .staging_size = M10BMC_STAGING_SIZE, + }; + ++static const struct m10bmc_csr_map m10bmc_c6100_csr_map = { ++ .base = M10BMC_N6000_SYS_BASE, ++ .build_version = M10BMC_N6000_BUILD_VER, ++ .fw_version = NIOS2_N6000_FW_VERSION, ++ .mac_low = M10BMC_N6000_MAC_LOW, ++ .mac_high = M10BMC_N6000_MAC_HIGH, ++ .doorbell = M10BMC_N6000_DOORBELL, ++ .auth_result = M10BMC_N6000_AUTH_RESULT, ++ .bmc_prog_addr = M10BMC_C6100_BMC_PROG_ADDR, ++ .bmc_reh_addr = M10BMC_C6100_BMC_REH_ADDR, ++ .bmc_magic = M10BMC_N6000_BMC_PROG_MAGIC, ++ .sr_prog_addr = M10BMC_C6100_SR_PROG_ADDR, ++ .sr_reh_addr = M10BMC_C6100_SR_REH_ADDR, ++ .sr_magic = M10BMC_N6000_SR_PROG_MAGIC, ++ .pr_prog_addr = M10BMC_C6100_PR_PROG_ADDR, ++ .pr_reh_addr = M10BMC_C6100_PR_REH_ADDR, ++ .pr_magic = M10BMC_N6000_PR_PROG_MAGIC, ++ .rsu_update_counter = M10BMC_C6100_STAGING_FLASH_COUNT, ++ .pr_sdm_reh_reg = M10BMC_PMCI_PR_RH0, ++ .pr_sdm_csk_reg = M10BMC_PMCI_PR_CSK, ++ .sr_sdm_reh_reg = M10BMC_PMCI_SR_RH0, ++ .sr_sdm_csk_reg = M10BMC_PMCI_SR_CSK, ++ .staging_size = M10BMC_STAGING_SIZE, ++}; ++ + static const struct intel_m10bmc_platform_info m10bmc_pmci_n6000 = { + .cells = m10bmc_pmci_n6000_bmc_subdevs, + .n_cells = ARRAY_SIZE(m10bmc_pmci_n6000_bmc_subdevs), + .csr_map = &m10bmc_n6000_csr_map, + }; + ++static const struct intel_m10bmc_platform_info m10bmc_pmci_c6100 = { ++ .cells = m10bmc_pmci_c6100_bmc_subdevs, ++ .n_cells = ARRAY_SIZE(m10bmc_pmci_c6100_bmc_subdevs), ++ .csr_map = &m10bmc_c6100_csr_map, ++}; ++ + static int m10bmc_pmci_probe(struct dfl_device *ddev) + { ++ const struct intel_m10bmc_platform_info *pinfo; + struct device *dev = &ddev->dev; + struct m10bmc_pmci_device *pmci; + struct indirect_ctx *ctx; + int ret; + ++ switch (ddev->revision) { ++ case 1: ++ pinfo = &m10bmc_pmci_n6000; ++ break; ++ case 2: ++ pinfo = &m10bmc_pmci_c6100; ++ break; ++ default: ++ return -ENODEV; ++ } ++ + pmci = devm_kzalloc(dev, sizeof(*pmci), GFP_KERNEL); + if (!pmci) + return -ENOMEM; +@@ -418,7 +467,7 @@ static int m10bmc_pmci_probe(struct dfl_device *ddev) + goto destroy_mutex; + } + +- ret = m10bmc_dev_init(&pmci->m10bmc, &m10bmc_pmci_n6000); ++ ret = m10bmc_dev_init(&pmci->m10bmc, pinfo); + if (ret) + goto destroy_mutex; + return 0; +diff --git a/include/linux/mfd/intel-m10-bmc.h b/include/linux/mfd/intel-m10-bmc.h +index 0933d768e0bb..bd91b48ef79a 100644 +--- a/include/linux/mfd/intel-m10-bmc.h ++++ b/include/linux/mfd/intel-m10-bmc.h +@@ -276,6 +276,11 @@ + #define M10BMC_N6000_BOM_INFO_ADDR 0x7ff0000 + #define M10BMC_N6000_BOM_INFO_SIZE 0x2000 + ++#define M10BMC_C6100_ERROR_LOG_ADDR 0x00a80000 ++ ++#define M10BMC_C6100_FPGA_IMAGE_DIR_SIZE 0x30000 ++#define M10BMC_C6100_FPGA_IMAGE_DIR_ADDR 0x00910000 ++ + /* Addresses for security related data in FLASH */ + #define M10BMC_N6000_BMC_REH_ADDR 0x7ffc004 + #define M10BMC_N6000_BMC_PROG_ADDR 0x7ffc000 +@@ -289,8 +294,19 @@ + #define M10BMC_N6000_PR_PROG_ADDR 0x7ffe000 + #define M10BMC_N6000_PR_PROG_MAGIC 0x5250 + ++#define M10BMC_C6100_BMC_REH_ADDR 0x00830004 ++#define M10BMC_C6100_BMC_PROG_ADDR 0x00830000 ++ ++#define M10BMC_C6100_SR_REH_ADDR 0x00820004 ++#define M10BMC_C6100_SR_PROG_ADDR 0x00820000 ++ ++#define M10BMC_C6100_PR_REH_ADDR 0x00810004 ++#define M10BMC_C6100_PR_PROG_ADDR 0x00810000 ++ + #define M10BMC_N6000_STAGING_FLASH_COUNT 0x7ff5000 + ++#define M10BMC_C6100_STAGING_FLASH_COUNT 0x00860000 ++ + #define M10BMC_N6000_FLASH_MUX_CTRL 0x1d0 + #define M10BMC_N6000_FLASH_MUX_SELECTION GENMASK(2, 0) + #define M10BMC_N6000_FLASH_MUX_IDLE 0 diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0044-Documentation-fpga-dfl-add-documentation-for-Interfa.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0044-Documentation-fpga-dfl-add-documentation-for-Interfa.patch new file mode 100644 index 0000000..26742d4 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0044-Documentation-fpga-dfl-add-documentation-for-Interfa.patch @@ -0,0 +1,79 @@ +From 74ae6cc5aa296de4cca6bf357ae15b6dbc1918d1 Mon Sep 17 00:00:00 2001 +From: Matthew Gerlach +Date: Wed, 13 Apr 2022 10:00:34 -0700 +Subject: [PATCH] Documentation: fpga: dfl: add documentation for Interface + type of DFH + +Introduce a new type of Device Feature Header (DFH), Interface, by +adding appropriate documentation. + +Signed-off-by: Matthew Gerlach +--- + Documentation/fpga/dfl.rst | 38 +++++++++++++++++++++++--------------- + 1 file changed, 23 insertions(+), 15 deletions(-) + +diff --git a/Documentation/fpga/dfl.rst b/Documentation/fpga/dfl.rst +index fb1c72006b1d..bd69d16c1de4 100644 +--- a/Documentation/fpga/dfl.rst ++++ b/Documentation/fpga/dfl.rst +@@ -28,30 +28,30 @@ as illustrated below:: + Header Header Header Header + +----------+ +-->+----------+ +-->+----------+ +-->+----------+ + | Type | | | Type | | | Type | | | Type | +- | FIU | | | Private | | | Private | | | Private | ++ | FIU | | | Private | | | Interface| | | Private | + +----------+ | | Feature | | | Feature | | | Feature | + | Next_DFH |--+ +----------+ | +----------+ | +----------+ + +----------+ | Next_DFH |--+ | Next_DFH |--+ | Next_DFH |--> NULL + | ID | +----------+ +----------+ +----------+ + +----------+ | ID | | ID | | ID | + | Next_AFU |--+ +----------+ +----------+ +----------+ +- +----------+ | | Feature | | Feature | | Feature | ++ +----------+ | | Feature | | Interface| | Feature | + | Header | | | Register | | Register | | Register | + | Register | | | Set | | Set | | Set | + | Set | | +----------+ +----------+ +----------+ +- +----------+ | Header +- +-->+----------+ +- | Type | +- | AFU | +- +----------+ +- | Next_DFH |--> NULL +- +----------+ +- | GUID | +- +----------+ +- | Header | +- | Register | +- | Set | +- +----------+ ++ +----------+ | Header Header ++ +-->+----------+ +-->+----------+ ++ | Type | | | Type | ++ | AFU | | | Interface| ++ +----------+ | +----------+ ++ | Next_DFH |--+ | Next_DFH |--> NULL ++ +----------+ +----------+ ++ | GUID | | GUID | ++ +----------+ +----------+ ++ | Header | | Interface| ++ | Register | | Register | ++ | Set | | Set | ++ +----------+ +----------+ + + FPGA Interface Unit (FIU) represents a standalone functional unit for the + interface to FPGA, e.g. the FPGA Management Engine (FME) and Port (more +@@ -70,6 +70,14 @@ The functional register set for FIU and AFU, is named as Header Register Set, + e.g. FME Header Register Set, and the one for Private Feature, is named as + Feature Register Set, e.g. FME Partial Reconfiguration Feature Register Set. + ++Each FIU, AFU and Private Feature could have its own set of child DFH's of the ++type, interface. These interface DFHs indicate IP blocks that could be ++reused in any FIU, AFU or Private Feature. The intent is that the specific ++driver for any FIU, AFU or Private Feature could reuse shared code for ++accessing the IP associated with the interface DFH. The DFL bus ++enumeration code ignores these DFH types except for the calculation of the size ++of a FIU, AFU or Private Feature. ++ + This Device Feature List provides a way of linking features together, it's + convenient for software to locate each feature by walking through this list, + and can be implemented in register regions of any FPGA device. diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0045-fpga-dfl-add-support-for-Interface-type-of-DFH.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0045-fpga-dfl-add-support-for-Interface-type-of-DFH.patch new file mode 100644 index 0000000..4c97b68 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0045-fpga-dfl-add-support-for-Interface-type-of-DFH.patch @@ -0,0 +1,87 @@ +From bc00582aaaa3f86e345b009cc659f6e462807c96 Mon Sep 17 00:00:00 2001 +From: Matthew Gerlach +Date: Tue, 12 Apr 2022 16:09:06 -0700 +Subject: [PATCH] fpga: dfl: add support for Interface type of DFH + +Add support for a new type of Device Feature Header (DFH), Interface. +An interface DFH is considered a child of the FIU, AFU, and Private feature +and is ignored by the DFL bus code. + +Signed-off-by: Matthew Gerlach +--- + drivers/fpga/dfl.c | 32 +++++++++++++++++++++++++++++--- + drivers/fpga/dfl.h | 1 + + 2 files changed, 30 insertions(+), 3 deletions(-) + +diff --git a/drivers/fpga/dfl.c b/drivers/fpga/dfl.c +index 62a48f4b4038..3a27bdeeff17 100644 +--- a/drivers/fpga/dfl.c ++++ b/drivers/fpga/dfl.c +@@ -990,11 +990,30 @@ static void build_info_free(struct build_feature_devs_info *binfo) + devm_kfree(binfo->dev, binfo); + } + +-static inline u32 feature_size(u64 value) ++static inline u32 feature_size(void __iomem *dfh_ioaddr, void __iomem *end, u64 value) + { + u32 ofst = FIELD_GET(DFH_NEXT_HDR_OFST, value); + /* workaround for private features with invalid size, use 4K instead */ +- return ofst ? ofst : 4096; ++ if (!ofst) ++ return 4096; ++ ++ if (value & DFH_EOL) ++ return ofst; ++ ++ do { ++ value = readq(dfh_ioaddr + ofst); ++ ++ if (FIELD_GET(DFH_TYPE, value) != DFH_TYPE_INTERFACE) ++ return ofst; ++ ++ ofst += FIELD_GET(DFH_NEXT_HDR_OFST, value); ++ ++ if (value & DFH_EOL) ++ return ofst; ++ ++ } while ((dfh_ioaddr + ofst) < end); ++ ++ return 0; + } + + static u16 feature_id(u64 value) +@@ -1216,7 +1235,12 @@ create_feature_instance(struct build_feature_devs_info *binfo, + dfh_ver = FIELD_GET(DFH_VERSION, v); + + /* read feature size and id if inputs are invalid */ +- size = size ? size : feature_size(v); ++ size = size ? size : feature_size(binfo->ioaddr + ofst, ++ binfo->ioaddr + binfo->len, v); ++ if (!size) { ++ dev_err(binfo->dev, "illegal feature with size of 0\n"); ++ return -EINVAL; ++ } + fid = fid ? fid : feature_id(v); + if (dfh_ver == 1) { + dfh_psize = dfh_get_param_size(binfo->ioaddr + ofst, size); +@@ -1455,6 +1479,8 @@ static int parse_feature(struct build_feature_devs_info *binfo, + return parse_feature_private(binfo, ofst); + case DFH_TYPE_FIU: + return parse_feature_fiu(binfo, ofst); ++ case DFH_TYPE_INTERFACE: ++ break; + default: + dev_info(binfo->dev, + "Feature Type %x is not supported.\n", type); +diff --git a/drivers/fpga/dfl.h b/drivers/fpga/dfl.h +index 127e7e2e74f7..f79ba69f170b 100644 +--- a/drivers/fpga/dfl.h ++++ b/drivers/fpga/dfl.h +@@ -80,6 +80,7 @@ + #define DFH_TYPE_AFU 1 + #define DFH_TYPE_PRIVATE 3 + #define DFH_TYPE_FIU 4 ++#define DFH_TYPE_INTERFACE 5 + + /* + * DFHv1 Register Offset definitons diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0046-fpga-dfl-Add-support-for-CMC-card.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0046-fpga-dfl-Add-support-for-CMC-card.patch new file mode 100644 index 0000000..e6d5b3d --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0046-fpga-dfl-Add-support-for-CMC-card.patch @@ -0,0 +1,32 @@ +From f9adc8147eb21782ec9368a87029358d19261d65 Mon Sep 17 00:00:00 2001 +From: Krishna Kumar S R +Date: Tue, 8 Aug 2023 23:08:14 +0530 +Subject: [PATCH] fpga: dfl: Add support for CMC card + +Add DFL support for the new CXL based CMC card. + +Signed-off-by: Krishna Kumar S R +--- + drivers/fpga/dfl-pci.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/fpga/dfl-pci.c b/drivers/fpga/dfl-pci.c +index 6d5b9de484e7..a41f4f6fd985 100644 +--- a/drivers/fpga/dfl-pci.c ++++ b/drivers/fpga/dfl-pci.c +@@ -72,6 +72,7 @@ static void cci_pci_free_irq(struct pci_dev *pcidev) + #define PCIE_DEVICE_ID_PF_INT_5_X 0xBCBD + #define PCIE_DEVICE_ID_PF_INT_6_X 0xBCC0 + #define PCIE_DEVICE_ID_PF_DSC_1_X 0x09C4 ++#define PCIE_DEVICE_ID_INTEL_CMC 0x0DDB + #define PCIE_DEVICE_ID_INTEL_PAC_N3000 0x0B30 + #define PCIE_DEVICE_ID_INTEL_PAC_D5005 0x0B2B + #define PCIE_DEVICE_ID_SILICOM_PAC_N5010 0x1000 +@@ -99,6 +100,7 @@ static struct pci_device_id cci_pcie_id_tbl[] = { + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_DSC_1_X),}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_DSC_1_X),}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_PAC_N3000),}, ++ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_CMC),}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_PAC_D5005),}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_PAC_D5005_VF),}, + {PCI_DEVICE(PCI_VENDOR_ID_SILICOM_DENMARK, PCIE_DEVICE_ID_SILICOM_PAC_N5010),}, diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0047-hwmon-intel-m10-bmc-Add-support-for-CMC-card.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0047-hwmon-intel-m10-bmc-Add-support-for-CMC-card.patch new file mode 100644 index 0000000..d9b8476 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0047-hwmon-intel-m10-bmc-Add-support-for-CMC-card.patch @@ -0,0 +1,167 @@ +From 314554c495229a96e77930d0a3035764a286b6b4 Mon Sep 17 00:00:00 2001 +From: Krishna Kumar S R +Date: Tue, 8 Aug 2023 23:14:41 +0530 +Subject: [PATCH] hwmon: intel-m10-bmc: Add support for CMC card + +Add hardware monitor support for CMC card. + +Signed-off-by: Krishna Kumar S R +--- + drivers/hwmon/intel-m10-bmc-hwmon.c | 137 ++++++++++++++++++++++++++++ + 1 file changed, 137 insertions(+) + +diff --git a/drivers/hwmon/intel-m10-bmc-hwmon.c b/drivers/hwmon/intel-m10-bmc-hwmon.c +index 1dc6a1db5b4e..fc892403c8e8 100644 +--- a/drivers/hwmon/intel-m10-bmc-hwmon.c ++++ b/drivers/hwmon/intel-m10-bmc-hwmon.c +@@ -821,6 +821,139 @@ static const struct m10bmc_hwmon_board_data c6100bmc_hwmon_bdata = { + .hinfo = c6100bmc_hinfo, + }; + ++static const struct m10bmc_sdata cmcbmc_temp_tbl[] = { ++ { 0x440, 0x0, 0x0, 0x0, 0x0, 500, "FPGA R-TILE Max Temperature" }, ++ { 0x444, 0x448, 0x44c, 0x0, 0x0, 500, "FPGA R-TILE Temperature #1" }, ++ { 0x450, 0x454, 0x458, 0x0, 0x0, 500, "FPGA R-TILE Temperature #2" }, ++ { 0x45c, 0x460, 0x464, 0x0, 0x0, 500, "FPGA R-TILE Temperature #3" }, ++ { 0x468, 0x46c, 0x470, 0x0, 0x0, 500, "FPGA R-TILE Temperature #4" }, ++ { 0x474, 0x478, 0x47C, 0x0, 0x0, 500, "FPGA R-TILE Temperature #5" }, ++ { 0x480, 0x484, 0x488, 0x0, 0x0, 500, "FPGA R-TILE Temperature #6" }, ++ { 0x48C, 0x0, 0x0, 0x0, 0x0, 500, "FPGA F-TILE Max Temperature" }, ++ { 0x490, 0x494, 0x498, 0x0, 0x0, 500, "FPGA F-TILE Temperature #1" }, ++ { 0x49C, 0x4A0, 0x4A4, 0x0, 0x0, 500, "FPGA F-TILE Temperature #2" }, ++ { 0x4A8, 0x4AC, 0x4B0, 0x0, 0x0, 500, "FPGA F-TILE Temperature #3" }, ++ { 0x4B4, 0x4B8, 0x4BC, 0x0, 0x0, 500, "FPGA F-TILE Temperature #4" }, ++ { 0x4C0, 0x4C4, 0x4C8, 0x0, 0x0, 500, "FPGA F-TILE Temperature #5" }, ++ { 0x4CC, 0x0, 0x0, 0x0, 0x0, 500, "FPGA FABRIC Max Temperature" }, ++ { 0x4D0, 0x4D4, 0x4D8, 0x0, 0x0, 500, "FPGA FABRIC Digital Temperature#1" }, ++ { 0x4DC, 0x4E0, 0x4E4, 0x0, 0x0, 500, "FPGA FABRIC Digital Temperature#2" }, ++ { 0x4E8, 0x4EC, 0x4F0, 0x0, 0x0, 500, "FPGA FABRIC Digital Temperature#3" }, ++ { 0x4F4, 0x4F8, 0x4FC, 0x0, 0x0, 500, "FPGA FABRIC Digital Temperature#4" }, ++ { 0x500, 0x504, 0x508, 0x0, 0x0, 500, "FPGA FABRIC Digital Temperature#5" }, ++ { 0x50C, 0x510, 0x514, 0x0, 0x0, 500, "FPGA FABRIC Remote Digital Temperature#1" }, ++ { 0x518, 0x51C, 0x520, 0x0, 0x0, 500, "FPGA FABRIC Remote Digital Temperature#2" }, ++ { 0x524, 0x528, 0x52C, 0x0, 0x0, 500, "FPGA FABRIC Remote Digital Temperature#3" }, ++ { 0x530, 0x534, 0x538, 0x0, 0x0, 500, "FPGA FABRIC Remote Digital Temperature#4" }, ++ { 0x588, 0x58C, 0x590, 0x0, 0x0, 500, "FPGA Core A (SDM) Temperature [Remote]" }, ++ { 0x594, 0x598, 0x59C, 0x0, 0x0, 500, "FPGA Core C Temperature [Remote]" }, ++ { 0x5A0, 0x5A4, 0x5A8, 0x0, 0x0, 500, "FPGA F-Tile Temperature [Remote]" }, ++ { 0x5AC, 0x5B0, 0x5B4, 0x0, 0x0, 500, "Board Temperature #1" }, ++ { 0x5D0, 0x5D4, 0x5D8, 0x0, 0x0, 500, "FPGA R-Tile 14C Temperature [Remote]" }, ++ { 0x5DC, 0x5E0, 0x5E4, 0x0, 0x0, 500, "FPGA R-Tile 15C Temperature [Remote]" }, ++ { 0x5F4, 0x5F8, 0x5FC, 0x0, 0x0, 500, "Board Temperature #2" }, ++ { 0x600, 0x0, 0x0, 0x0, 0x0, 500, "FPGA VCC_HSSI_GXR VR Temperature" }, ++ { 0x60C, 0x0, 0x0, 0x0, 0x0, 500, "FPGA VCCR_CORE VR Temperature" }, ++ { 0x618, 0x0, 0x0, 0x0, 0x0, 500, "FPGA VCC_HSSI_GXF Temperature" }, ++ { 0x728, 0x72C, 0x730, 0x0, 0x0, 500, "FPGA Virtual Sensor Temperature" }, ++}; ++ ++static const struct m10bmc_sdata cmcbmc_in_tbl[] = { ++ { 0x624, 0x0, 0x0, 0x0, 0x0, 1, "FPGA VCC_HSSI_GXR Rail Voltage" }, ++ { 0x63c, 0x0, 0x0, 0x0, 0x0, 1, "FPGA VCCR_CORE Rail Voltage" }, ++ { 0x654, 0x0, 0x0, 0x0, 0x0, 1, "FPGA VCC_HSSI_GXF Rail Voltage" }, ++}; ++ ++static const struct m10bmc_sdata cmcbmc_curr_tbl[] = { ++ { 0x630, 0x0, 0x0, 0x0, 0x0, 1, "FPGA VCC_HSSI_GXR Voltage Rail Current" }, ++ { 0x648, 0x0, 0x0, 0x0, 0x0, 1, "FPGA VCCR_CORE Voltage Rail Current" }, ++ { 0x660, 0x0, 0x0, 0x0, 0x0, 1, "FPGA VCC_HSSI_GXF Voltage Rail Current" }, ++}; ++ ++static const struct hwmon_channel_info *cmcbmc_hinfo[] = { ++ HWMON_CHANNEL_INFO(temp, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL), ++ HWMON_CHANNEL_INFO(in, ++ HWMON_I_INPUT | HWMON_I_LABEL, ++ HWMON_I_INPUT | HWMON_I_LABEL, ++ HWMON_I_INPUT | HWMON_I_LABEL), ++ HWMON_CHANNEL_INFO(curr, ++ HWMON_C_INPUT | HWMON_C_LABEL, ++ HWMON_C_INPUT | HWMON_C_LABEL, ++ HWMON_C_INPUT | HWMON_C_LABEL), ++ NULL ++}; ++static const struct m10bmc_hwmon_board_data cmcbmc_hwmon_bdata = { ++ .tables = { ++ [hwmon_temp] = cmcbmc_temp_tbl, ++ [hwmon_in] = cmcbmc_in_tbl, ++ [hwmon_curr] = cmcbmc_curr_tbl, ++ }, ++ ++ .hinfo = cmcbmc_hinfo, ++}; ++ + static umode_t + m10bmc_hwmon_is_visible(const void *data, enum hwmon_sensor_types type, + u32 attr, int channel) +@@ -1042,6 +1175,10 @@ static const struct platform_device_id intel_m10bmc_hwmon_ids[] = { + .name = "c6100bmc-hwmon", + .driver_data = (unsigned long)&c6100bmc_hwmon_bdata, + }, ++ { ++ .name = "cmcbmc-hwmon", ++ .driver_data = (unsigned long)&cmcbmc_hwmon_bdata, ++ }, + { } + }; + diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0048-mfd-intel-m10-bmc-Add-support-for-CMC-card.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0048-mfd-intel-m10-bmc-Add-support-for-CMC-card.patch new file mode 100644 index 0000000..8781fdc --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0048-mfd-intel-m10-bmc-Add-support-for-CMC-card.patch @@ -0,0 +1,52 @@ +From 3c76c6978c994117ec868c9662300b79f71f6feb Mon Sep 17 00:00:00 2001 +From: Krishna Kumar S R +Date: Tue, 8 Aug 2023 23:14:41 +0530 +Subject: [PATCH] mfd: intel-m10-bmc: Add support for CMC card + +Add BMC driver support for the CMC card. + +Signed-off-by: Krishna Kumar S R +--- + drivers/mfd/intel-m10-bmc-pmci.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/mfd/intel-m10-bmc-pmci.c b/drivers/mfd/intel-m10-bmc-pmci.c +index af2ddb92df6f..f5042042a8aa 100644 +--- a/drivers/mfd/intel-m10-bmc-pmci.c ++++ b/drivers/mfd/intel-m10-bmc-pmci.c +@@ -359,6 +359,12 @@ static struct mfd_cell m10bmc_pmci_c6100_bmc_subdevs[] = { + { .name = "c6100bmc-log" }, + }; + ++static struct mfd_cell m10bmc_pmci_cmc_bmc_subdevs[] = { ++ { .name = "cmcbmc-hwmon" }, ++ { .name = "n6000bmc-sec-update" }, ++ { .name = "n6000bmc-log" }, ++}; ++ + static const struct m10bmc_csr_map m10bmc_n6000_csr_map = { + .base = M10BMC_N6000_SYS_BASE, + .build_version = M10BMC_N6000_BUILD_VER, +@@ -421,6 +427,12 @@ static const struct intel_m10bmc_platform_info m10bmc_pmci_c6100 = { + .csr_map = &m10bmc_c6100_csr_map, + }; + ++static const struct intel_m10bmc_platform_info m10bmc_pmci_cmc = { ++ .cells = m10bmc_pmci_cmc_bmc_subdevs, ++ .n_cells = ARRAY_SIZE(m10bmc_pmci_cmc_bmc_subdevs), ++ .csr_map = &m10bmc_n6000_csr_map, ++}; ++ + static int m10bmc_pmci_probe(struct dfl_device *ddev) + { + const struct intel_m10bmc_platform_info *pinfo; +@@ -436,6 +448,9 @@ static int m10bmc_pmci_probe(struct dfl_device *ddev) + case 2: + pinfo = &m10bmc_pmci_c6100; + break; ++ case 3: ++ pinfo = &m10bmc_pmci_cmc; ++ break; + default: + return -ENODEV; + } diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0049-mfd-intel-m10-bmc-PMCI-and-log-changes-for-CMC.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0049-mfd-intel-m10-bmc-PMCI-and-log-changes-for-CMC.patch new file mode 100644 index 0000000..af92193 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0049-mfd-intel-m10-bmc-PMCI-and-log-changes-for-CMC.patch @@ -0,0 +1,63 @@ +From 086b798c0d4ce17a409a04988910242868035f89 Mon Sep 17 00:00:00 2001 +From: KrishnaSimmadhari <91877513+KrishnaSimmadhari@users.noreply.github.com> +Date: Wed, 30 Aug 2023 22:49:03 +0530 +Subject: [PATCH] mfd: intel-m10-bmc: PMCI and log changes for CMC + +Change register map for CMC card to c6100 register csr set. Change the FPGA info +structure to point to the right location. + +Signed-off-by: Krishna Kumar S R +--- + drivers/mfd/intel-m10-bmc-log.c | 9 +++++++++ + drivers/mfd/intel-m10-bmc-pmci.c | 4 ++-- + 2 files changed, 11 insertions(+), 2 deletions(-) + +diff --git a/drivers/mfd/intel-m10-bmc-log.c b/drivers/mfd/intel-m10-bmc-log.c +index 12ef1100da79..0c747ba0d0bc 100644 +--- a/drivers/mfd/intel-m10-bmc-log.c ++++ b/drivers/mfd/intel-m10-bmc-log.c +@@ -245,6 +245,11 @@ static const struct m10bmc_log_cfg m10bmc_log_c6100_cfg = { + .id_off = M10BMC_C6100_FPGA_IMAGE_DIR_ADDR, + }; + ++static const struct m10bmc_log_cfg m10bmc_log_cmc_cfg = { ++ .id_size = M10BMC_C6100_FPGA_IMAGE_DIR_SIZE, ++ .id_off = M10BMC_C6100_FPGA_IMAGE_DIR_ADDR, ++}; ++ + static const struct platform_device_id intel_m10bmc_log_ids[] = { + { + .name = "n6000bmc-log", +@@ -254,6 +259,10 @@ static const struct platform_device_id intel_m10bmc_log_ids[] = { + .name = "c6100bmc-log", + .driver_data = (unsigned long)&m10bmc_log_c6100_cfg, + }, ++ { ++ .name = "cmcbmc-log", ++ .driver_data = (unsigned long)&m10bmc_log_cmc_cfg, ++ }, + { } + }; + +diff --git a/drivers/mfd/intel-m10-bmc-pmci.c b/drivers/mfd/intel-m10-bmc-pmci.c +index f5042042a8aa..35e880bec80d 100644 +--- a/drivers/mfd/intel-m10-bmc-pmci.c ++++ b/drivers/mfd/intel-m10-bmc-pmci.c +@@ -362,7 +362,7 @@ static struct mfd_cell m10bmc_pmci_c6100_bmc_subdevs[] = { + static struct mfd_cell m10bmc_pmci_cmc_bmc_subdevs[] = { + { .name = "cmcbmc-hwmon" }, + { .name = "n6000bmc-sec-update" }, +- { .name = "n6000bmc-log" }, ++ { .name = "cmcbmc-log" }, + }; + + static const struct m10bmc_csr_map m10bmc_n6000_csr_map = { +@@ -430,7 +430,7 @@ static const struct intel_m10bmc_platform_info m10bmc_pmci_c6100 = { + static const struct intel_m10bmc_platform_info m10bmc_pmci_cmc = { + .cells = m10bmc_pmci_cmc_bmc_subdevs, + .n_cells = ARRAY_SIZE(m10bmc_pmci_cmc_bmc_subdevs), +- .csr_map = &m10bmc_n6000_csr_map, ++ .csr_map = &m10bmc_c6100_csr_map, + }; + + static int m10bmc_pmci_probe(struct dfl_device *ddev) diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0050-fpga-dfl-add-vendor-IDs-and-device-IDs-for-ALIBABA-F.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0050-fpga-dfl-add-vendor-IDs-and-device-IDs-for-ALIBABA-F.patch new file mode 100644 index 0000000..8c1157f --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0050-fpga-dfl-add-vendor-IDs-and-device-IDs-for-ALIBABA-F.patch @@ -0,0 +1,47 @@ +From 0bda19d1237ef490cb6005f9946ccd897ec61417 Mon Sep 17 00:00:00 2001 +From: "richard.li" +Date: Fri, 28 Oct 2022 15:54:41 +0800 +Subject: [PATCH] fpga: dfl: add vendor IDs and device IDs for ALIBABA F5 cards + +This patch adds the approved PCI Express Vendor IDs and Device IDs for the +ALIBABA cards. + +Signed-off-by: richard.li +--- + drivers/fpga/dfl-pci.c | 2 ++ + include/linux/pci_ids.h | 2 ++ + 2 files changed, 4 insertions(+) + +diff --git a/drivers/fpga/dfl-pci.c b/drivers/fpga/dfl-pci.c +index a41f4f6fd985..02801e600bf2 100644 +--- a/drivers/fpga/dfl-pci.c ++++ b/drivers/fpga/dfl-pci.c +@@ -80,6 +80,7 @@ static void cci_pci_free_irq(struct pci_dev *pcidev) + #define PCIE_DEVICE_ID_SILICOM_PAC_N5013 0x1002 + #define PCIE_DEVICE_ID_SILICOM_PAC_N5014 0x1003 + #define PCIE_DEVICE_ID_INTEL_DFL 0xbcce ++#define PCIE_DEVICE_ID_ALIBABA_F5 0x8103 + /* PCI Subdevice ID for PCIE_DEVICE_ID_INTEL_DFL */ + #define PCIE_SUBDEVICE_ID_INTEL_N6000 0x1770 + #define PCIE_SUBDEVICE_ID_INTEL_N6001 0x1771 +@@ -119,6 +120,7 @@ static struct pci_device_id cci_pcie_id_tbl[] = { + PCI_VENDOR_ID_INTEL, PCIE_SUBDEVICE_ID_INTEL_C6100),}, + {PCI_DEVICE_SUB(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_DFL_VF, + PCI_VENDOR_ID_INTEL, PCIE_SUBDEVICE_ID_INTEL_C6100),}, ++ {PCI_DEVICE(PCI_VENDOR_ID_ALIBABA, PCIE_DEVICE_ID_ALIBABA_F5),}, + {0,} + }; + MODULE_DEVICE_TABLE(pci, cci_pcie_id_tbl); +diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h +index 5fb3d4c393a9..66677b12a089 100644 +--- a/include/linux/pci_ids.h ++++ b/include/linux/pci_ids.h +@@ -1378,6 +1378,8 @@ + #define PCI_DEVICE_ID_IMS_TT128 0x9128 + #define PCI_DEVICE_ID_IMS_TT3D 0x9135 + ++#define PCI_VENDOR_ID_ALIBABA 0x1ded ++ + #define PCI_VENDOR_ID_AMCC 0x10e8 + #define PCI_VENDOR_ID_AMPERE 0x1def + diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0051-dfl-add-generic-indirect-regmap-support.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0051-dfl-add-generic-indirect-regmap-support.patch new file mode 100644 index 0000000..bf1f1cb --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0051-dfl-add-generic-indirect-regmap-support.patch @@ -0,0 +1,223 @@ +From f5d12a37a186752229fa870a9bc7ab881ec226bf Mon Sep 17 00:00:00 2001 +From: Matthew Gerlach +Date: Tue, 28 Jul 2020 16:48:01 -0700 +Subject: [PATCH] dfl: add generic indirect regmap support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add support for a generic indirect register access via a regmap +interface. + +Co-developed-by: Matthew Gerlach +Signed-off-by: Matthew Gerlach +Signed-off-by: Ilpo Järvinen +--- + drivers/base/regmap/Kconfig | 5 +- + drivers/base/regmap/Makefile | 1 + + .../base/regmap/regmap-indirect-register.c | 144 ++++++++++++++++++ + include/linux/regmap.h | 11 ++ + 4 files changed, 160 insertions(+), 1 deletion(-) + create mode 100644 drivers/base/regmap/regmap-indirect-register.c + +diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig +index b1affac70d5d..e862d99925ed 100644 +--- a/drivers/base/regmap/Kconfig ++++ b/drivers/base/regmap/Kconfig +@@ -5,7 +5,7 @@ + + config REGMAP + bool +- default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_SOUNDWIRE || REGMAP_SOUNDWIRE_MBQ || REGMAP_SCCB || REGMAP_I3C || REGMAP_SPI_AVMM || REGMAP_MDIO || REGMAP_FSI) ++ default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_SOUNDWIRE || REGMAP_SOUNDWIRE_MBQ || REGMAP_SCCB || REGMAP_I3C || REGMAP_SPI_AVMM || REGMAP_MDIO || REGMAP_FSI || REGMAP_INDIRECT_REGISTER) + select IRQ_DOMAIN if REGMAP_IRQ + select MDIO_BUS if REGMAP_MDIO + help +@@ -91,3 +91,6 @@ config REGMAP_SPI_AVMM + config REGMAP_FSI + tristate + depends on FSI ++ ++config REGMAP_INDIRECT_REGISTER ++ tristate +diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile +index 5fdd0845b45e..76930a193724 100644 +--- a/drivers/base/regmap/Makefile ++++ b/drivers/base/regmap/Makefile +@@ -22,3 +22,4 @@ obj-$(CONFIG_REGMAP_I3C) += regmap-i3c.o + obj-$(CONFIG_REGMAP_SPI_AVMM) += regmap-spi-avmm.o + obj-$(CONFIG_REGMAP_MDIO) += regmap-mdio.o + obj-$(CONFIG_REGMAP_FSI) += regmap-fsi.o ++obj-$(CONFIG_REGMAP_INDIRECT_REGISTER) += regmap-indirect-register.o +diff --git a/drivers/base/regmap/regmap-indirect-register.c b/drivers/base/regmap/regmap-indirect-register.c +new file mode 100644 +index 000000000000..a42a0ad340bd +--- /dev/null ++++ b/drivers/base/regmap/regmap-indirect-register.c +@@ -0,0 +1,144 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Indirect Register Access. ++ * ++ * Copyright (C) 2020 Intel Corporation, Inc. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define INDIRECT_CMD_OFF 0 ++#define INDIRECT_CMD_CLR 0 ++#define INDIRECT_CMD_RD BIT(0) ++#define INDIRECT_CMD_WR BIT(1) ++#define INDIRECT_CMD_ACK BIT(2) ++ ++#define INDIRECT_ADDR_OFF 0x4 ++#define INDIRECT_RD_OFF 0x8 ++#define INDIRECT_WR_OFF 0xc ++ ++#define INDIRECT_INT_US 1 ++#define INDIRECT_TIMEOUT_US 10000 ++ ++struct indirect_ctx { ++ void __iomem *base; ++ struct device *dev; ++}; ++ ++static int indirect_bus_clear_cmd(struct indirect_ctx *ctx) ++{ ++ unsigned int cmd; ++ int ret; ++ ++ writel(INDIRECT_CMD_CLR, ctx->base + INDIRECT_CMD_OFF); ++ ++ ret = readl_poll_timeout(ctx->base + INDIRECT_CMD_OFF, cmd, ++ cmd == INDIRECT_CMD_CLR, ++ INDIRECT_INT_US, INDIRECT_TIMEOUT_US); ++ if (ret) ++ dev_err(ctx->dev, "timed out waiting clear cmd (residual cmd=0x%x)\n", cmd); ++ ++ return ret; ++} ++ ++static int indirect_bus_reg_read(void *context, unsigned int reg, unsigned int *val) ++{ ++ struct indirect_ctx *ctx = context; ++ unsigned int cmd, ack, tmpval; ++ int ret, ret2; ++ ++ cmd = readl(ctx->base + INDIRECT_CMD_OFF); ++ if (cmd != INDIRECT_CMD_CLR) ++ dev_warn(ctx->dev, "residual cmd 0x%x on read entry\n", cmd); ++ ++ writel(reg, ctx->base + INDIRECT_ADDR_OFF); ++ writel(INDIRECT_CMD_RD, ctx->base + INDIRECT_CMD_OFF); ++ ++ ret = readl_poll_timeout(ctx->base + INDIRECT_CMD_OFF, ack, ++ (ack & INDIRECT_CMD_ACK) == INDIRECT_CMD_ACK, ++ INDIRECT_INT_US, INDIRECT_TIMEOUT_US); ++ if (ret) ++ dev_err(ctx->dev, "read timed out on reg 0x%x ack 0x%x\n", reg, ack); ++ else ++ tmpval = readl(ctx->base + INDIRECT_RD_OFF); ++ ++ ret2 = indirect_bus_clear_cmd(ctx); ++ ++ if (ret) ++ return ret; ++ if (ret2) ++ return ret2; ++ ++ *val = tmpval; ++ return 0; ++} ++ ++static int indirect_bus_reg_write(void *context, unsigned int reg, unsigned int val) ++{ ++ struct indirect_ctx *ctx = context; ++ unsigned int cmd, ack; ++ int ret, ret2; ++ ++ cmd = readl(ctx->base + INDIRECT_CMD_OFF); ++ if (cmd != INDIRECT_CMD_CLR) ++ dev_warn(ctx->dev, "residual cmd 0x%x on write entry\n", cmd); ++ ++ writel(val, ctx->base + INDIRECT_WR_OFF); ++ writel(reg, ctx->base + INDIRECT_ADDR_OFF); ++ writel(INDIRECT_CMD_WR, ctx->base + INDIRECT_CMD_OFF); ++ ++ ret = readl_poll_timeout(ctx->base + INDIRECT_CMD_OFF, ack, ++ (ack & INDIRECT_CMD_ACK) == INDIRECT_CMD_ACK, ++ INDIRECT_INT_US, INDIRECT_TIMEOUT_US); ++ if (ret) ++ dev_err(ctx->dev, "write timed out on reg 0x%x ack 0x%x\n", reg, ack); ++ ++ ret2 = indirect_bus_clear_cmd(ctx); ++ ++ if (ret) ++ return ret; ++ return ret2; ++} ++ ++static const struct regmap_bus indirect_bus = { ++ .reg_write = indirect_bus_reg_write, ++ .reg_read = indirect_bus_reg_read, ++}; ++ ++/** ++ * devm_regmap_init_indirect_register - create a regmap for indirect register access ++ * @dev: device creating the regmap ++ * @base: __iomem point to base of memory with mailbox ++ * @cfg: regmap_config describing interface ++ * ++ * Return: 0 on success, negative error code otherwise. ++ */ ++struct regmap *devm_regmap_init_indirect_register(struct device *dev, ++ void __iomem *base, ++ struct regmap_config *cfg) ++{ ++ struct indirect_ctx *ctx; ++ ++ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); ++ ++ if (!ctx) ++ return NULL; ++ ++ ctx->base = base; ++ ctx->dev = dev; ++ ++ /* Reset any previous commands */ ++ indirect_bus_clear_cmd(ctx); ++ ++ return devm_regmap_init(dev, &indirect_bus, ctx, cfg); ++} ++EXPORT_SYMBOL_GPL(devm_regmap_init_indirect_register); ++ ++MODULE_DESCRIPTION("Indirect Register Access"); ++MODULE_AUTHOR("Intel Corporation"); ++MODULE_LICENSE("GPL v2"); +diff --git a/include/linux/regmap.h b/include/linux/regmap.h +index c9182a47736e..e214f0821332 100644 +--- a/include/linux/regmap.h ++++ b/include/linux/regmap.h +@@ -719,6 +719,17 @@ struct regmap *__devm_regmap_init_fsi(struct fsi_device *fsi_dev, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name); ++/** ++ * devm_regmap_init_indirect_register - create a regmap for indirect register access ++ * @dev: device creating the regmap ++ * @base: __iomem point to base of memory with mailbox ++ * @cfg: regmap_config describing interface ++ * ++ * Return: 0 on success, negative error code otherwise. ++ */ ++struct regmap *devm_regmap_init_indirect_register(struct device *dev, ++ void __iomem *base, ++ struct regmap_config *cfg); + + /* + * Wrapper for regmap_init macros to include a unique lockdep key and name diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0052-mfd-intel-m10-bmc-Use-the-generic-regmap-indirect.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0052-mfd-intel-m10-bmc-Use-the-generic-regmap-indirect.patch new file mode 100644 index 0000000..232b77c --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0052-mfd-intel-m10-bmc-Use-the-generic-regmap-indirect.patch @@ -0,0 +1,175 @@ +From 4c0c1ae32985db712e55944eb0f35d1fa6689717 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= +Date: Wed, 4 Jan 2023 17:08:26 +0200 +Subject: [PATCH] mfd: intel-m10-bmc: Use the generic regmap indirect +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +M10BMC PMCI driver provided in-driver regmap indirect, convert it to +use the generic version and remove the in-driver one. + +Signed-off-by: Ilpo Järvinen +--- + drivers/mfd/Kconfig | 1 + + drivers/mfd/intel-m10-bmc-pmci.c | 112 ++----------------------------- + 2 files changed, 5 insertions(+), 108 deletions(-) + +diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig +index b96033472f6a..09da5a095c7b 100644 +--- a/drivers/mfd/Kconfig ++++ b/drivers/mfd/Kconfig +@@ -2297,6 +2297,7 @@ config MFD_INTEL_M10_BMC_PMCI + depends on FPGA_DFL + select MFD_INTEL_M10_BMC_CORE + select REGMAP ++ select REGMAP_INDIRECT_REGISTER + help + Support for the Intel MAX 10 board management controller via PMCI. + +diff --git a/drivers/mfd/intel-m10-bmc-pmci.c b/drivers/mfd/intel-m10-bmc-pmci.c +index 35e880bec80d..7272d35ef74b 100644 +--- a/drivers/mfd/intel-m10-bmc-pmci.c ++++ b/drivers/mfd/intel-m10-bmc-pmci.c +@@ -22,102 +22,6 @@ struct m10bmc_pmci_device { + bool flash_busy; + }; + +-/* +- * Intel FGPA indirect register access via hardware controller/bridge. +- */ +-#define INDIRECT_CMD_OFF 0 +-#define INDIRECT_CMD_CLR 0 +-#define INDIRECT_CMD_RD BIT(0) +-#define INDIRECT_CMD_WR BIT(1) +-#define INDIRECT_CMD_ACK BIT(2) +- +-#define INDIRECT_ADDR_OFF 0x4 +-#define INDIRECT_RD_OFF 0x8 +-#define INDIRECT_WR_OFF 0xc +- +-#define INDIRECT_INT_US 1 +-#define INDIRECT_TIMEOUT_US 10000 +- +-struct indirect_ctx { +- void __iomem *base; +- struct device *dev; +-}; +- +-static int indirect_clear_cmd(struct indirect_ctx *ctx) +-{ +- unsigned int cmd; +- int ret; +- +- writel(INDIRECT_CMD_CLR, ctx->base + INDIRECT_CMD_OFF); +- +- ret = readl_poll_timeout(ctx->base + INDIRECT_CMD_OFF, cmd, +- cmd == INDIRECT_CMD_CLR, +- INDIRECT_INT_US, INDIRECT_TIMEOUT_US); +- if (ret) +- dev_err(ctx->dev, "timed out waiting clear cmd (residual cmd=0x%x)\n", cmd); +- +- return ret; +-} +- +-static int indirect_reg_read(void *context, unsigned int reg, unsigned int *val) +-{ +- struct indirect_ctx *ctx = context; +- unsigned int cmd, ack, tmpval; +- int ret, ret2; +- +- cmd = readl(ctx->base + INDIRECT_CMD_OFF); +- if (cmd != INDIRECT_CMD_CLR) +- dev_warn(ctx->dev, "residual cmd 0x%x on read entry\n", cmd); +- +- writel(reg, ctx->base + INDIRECT_ADDR_OFF); +- writel(INDIRECT_CMD_RD, ctx->base + INDIRECT_CMD_OFF); +- +- ret = readl_poll_timeout(ctx->base + INDIRECT_CMD_OFF, ack, +- (ack & INDIRECT_CMD_ACK) == INDIRECT_CMD_ACK, +- INDIRECT_INT_US, INDIRECT_TIMEOUT_US); +- if (ret) +- dev_err(ctx->dev, "read timed out on reg 0x%x ack 0x%x\n", reg, ack); +- else +- tmpval = readl(ctx->base + INDIRECT_RD_OFF); +- +- ret2 = indirect_clear_cmd(ctx); +- +- if (ret) +- return ret; +- if (ret2) +- return ret2; +- +- *val = tmpval; +- return 0; +-} +- +-static int indirect_reg_write(void *context, unsigned int reg, unsigned int val) +-{ +- struct indirect_ctx *ctx = context; +- unsigned int cmd, ack; +- int ret, ret2; +- +- cmd = readl(ctx->base + INDIRECT_CMD_OFF); +- if (cmd != INDIRECT_CMD_CLR) +- dev_warn(ctx->dev, "residual cmd 0x%x on write entry\n", cmd); +- +- writel(val, ctx->base + INDIRECT_WR_OFF); +- writel(reg, ctx->base + INDIRECT_ADDR_OFF); +- writel(INDIRECT_CMD_WR, ctx->base + INDIRECT_CMD_OFF); +- +- ret = readl_poll_timeout(ctx->base + INDIRECT_CMD_OFF, ack, +- (ack & INDIRECT_CMD_ACK) == INDIRECT_CMD_ACK, +- INDIRECT_INT_US, INDIRECT_TIMEOUT_US); +- if (ret) +- dev_err(ctx->dev, "write timed out on reg 0x%x ack 0x%x\n", reg, ack); +- +- ret2 = indirect_clear_cmd(ctx); +- +- if (ret) +- return ret; +- return ret2; +-} +- + static void pmci_write_fifo(void __iomem *base, const u32 *buf, size_t count) + { + while (count--) +@@ -342,8 +246,6 @@ static struct regmap_config m10bmc_pmci_regmap_config = { + .val_bits = 32, + .wr_table = &m10bmc_pmci_access_table, + .rd_table = &m10bmc_pmci_access_table, +- .reg_read = &indirect_reg_read, +- .reg_write = &indirect_reg_write, + .max_register = M10BMC_N6000_SYS_END, + }; + +@@ -438,7 +340,6 @@ static int m10bmc_pmci_probe(struct dfl_device *ddev) + const struct intel_m10bmc_platform_info *pinfo; + struct device *dev = &ddev->dev; + struct m10bmc_pmci_device *pmci; +- struct indirect_ctx *ctx; + int ret; + + switch (ddev->revision) { +@@ -466,17 +367,12 @@ static int m10bmc_pmci_probe(struct dfl_device *ddev) + if (IS_ERR(pmci->base)) + return PTR_ERR(pmci->base); + +- ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); +- if (!ctx) +- return -ENOMEM; +- + mutex_init(&pmci->flash_mutex); + +- ctx->base = pmci->base + M10BMC_N6000_INDIRECT_BASE; +- ctx->dev = dev; +- indirect_clear_cmd(ctx); +- pmci->m10bmc.regmap = devm_regmap_init(dev, NULL, ctx, &m10bmc_pmci_regmap_config); +- ++ pmci->m10bmc.regmap = ++ devm_regmap_init_indirect_register(dev, ++ pmci->base + M10BMC_N6000_INDIRECT_BASE, ++ &m10bmc_pmci_regmap_config); + if (IS_ERR(pmci->m10bmc.regmap)) { + ret = PTR_ERR(pmci->m10bmc.regmap); + goto destroy_mutex; diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0053-fpga-dfl-hssi-driver.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0053-fpga-dfl-hssi-driver.patch new file mode 100644 index 0000000..20178cd --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0053-fpga-dfl-hssi-driver.patch @@ -0,0 +1,240 @@ +From 4e922b7cbd9fc18e57e808abe09fbd7768c21924 Mon Sep 17 00:00:00 2001 +From: Russ Weight +Date: Tue, 21 Apr 2020 17:10:20 -0700 +Subject: [PATCH] fpga: dfl: hssi driver + +This driver provides the ability to view and change tuning +parameters for the ethernet transceivers for the HSSI +private feature on dfl devices. It is designed as a +dfl device (it is on the dfl bus) and creates an +intel-s10-phy platform device for each QSFP. + +Signed-off-by: Russ Weight +--- + drivers/fpga/Kconfig | 8 ++ + drivers/fpga/Makefile | 1 + + drivers/fpga/dfl-hssi.c | 184 ++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 193 insertions(+) + create mode 100644 drivers/fpga/dfl-hssi.c + +diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig +index 2f689ac4ba3a..5bcce59d3815 100644 +--- a/drivers/fpga/Kconfig ++++ b/drivers/fpga/Kconfig +@@ -225,6 +225,14 @@ config FPGA_DFL_PCI + + To compile this as a module, choose M here. + ++config FPGA_DFL_HSSI ++ tristate "FPGA DFL HSSI Driver" ++ depends on FPGA_DFL ++ help ++ This is the HSSI Ethernet driver for the Intel Stratix 10 FPGA. ++ This driver provides the ability to view and change some of the ++ transceiver tuning parameters. ++ + config FPGA_MGR_ZYNQMP_FPGA + tristate "Xilinx ZynqMP FPGA" + depends on ZYNQMP_FIRMWARE || (!ZYNQMP_FIRMWARE && COMPILE_TEST) +diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile +index 352a2612623e..55ac2be413d7 100644 +--- a/drivers/fpga/Makefile ++++ b/drivers/fpga/Makefile +@@ -55,6 +55,7 @@ obj-$(CONFIG_FPGA_DFL_NIOS_INTEL_PAC_N3000) += dfl-n3000-nios.o + + # Drivers for FPGAs which implement DFL + obj-$(CONFIG_FPGA_DFL_PCI) += dfl-pci.o ++obj-$(CONFIG_FPGA_DFL_HSSI) += dfl-hssi.o + + # KUnit tests + obj-$(CONFIG_FPGA_KUNIT_TESTS) += tests/ +diff --git a/drivers/fpga/dfl-hssi.c b/drivers/fpga/dfl-hssi.c +new file mode 100644 +index 000000000000..a23e1e32818b +--- /dev/null ++++ b/drivers/fpga/dfl-hssi.c +@@ -0,0 +1,184 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Driver for DFL HSSI Configurable Ethernet private feature ++ * ++ * Copyright 2019-2020 Intel Corporation, Inc. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "dfl.h" ++ ++/* HSSI Private Feature: Capability - Read-Only */ ++#define HSSI_CAPABILITY 0x8 ++#define DATA_RATE_AVAIL_1G BIT_ULL(0) ++#define DATA_RATE_AVAIL_10G BIT_ULL(1) ++#define DATA_RATE_AVAIL_25G BIT_ULL(2) ++#define DATA_RATE_AVAIL_40G BIT_ULL(3) ++#define DATA_RATE_AVAIL_50G BIT_ULL(4) ++#define DATA_RATE_AVAIL_100G BIT_ULL(5) ++#define DATA_RATE_AVAIL_200G BIT_ULL(6) ++#define DATA_RATE_AVAIL_400G BIT_ULL(7) ++#define CONTAINS_PCS_1G BIT_ULL(8) ++#define CONTAINS_PCS_10G BIT_ULL(9) ++#define CONTAINS_PCS_25G BIT_ULL(10) ++#define CONTAINS_PCS_40G BIT_ULL(11) ++#define CONTAINS_PCS_50G BIT_ULL(12) ++#define CONTAINS_PCS_100G BIT_ULL(13) ++#define CONTAINS_PCS_200G BIT_ULL(14) ++#define CONTAINS_PCS_400G BIT_ULL(15) ++#define CONTAINS_FEC_1G BIT_ULL(16) ++#define CONTAINS_FEC_10G BIT_ULL(17) ++#define CONTAINS_FEC_25G BIT_ULL(18) ++#define CONTAINS_FEC_40G BIT_ULL(19) ++#define CONTAINS_FEC_50G BIT_ULL(20) ++#define CONTAINS_FEC_100G BIT_ULL(21) ++#define CONTAINS_FEC_200G BIT_ULL(22) ++#define CONTAINS_FEC_400G BIT_ULL(23) ++#define DATA_RATE_SWITCH BIT_ULL(24) ++#define LINK_TRAINING BIT_ULL(25) ++#define AUTO_NEGOTIATION BIT_ULL(26) ++#define CONTAINS_MAC BIT_ULL(27) ++#define NUM_QSFP_INTERFACES GENMASK_ULL(39, 32) ++ ++/* QSFP register space */ ++#define HSSI_QSFP_BASE 0x10 ++#define HSSI_QSFP_SIZE 0x20 ++ ++struct dfl_hssi { ++ void __iomem *csr_base; ++ struct device *dev; ++ unsigned int qsfp_cnt; ++ struct platform_device *intel_s10_phy[]; ++}; ++ ++static int hssi_create_qsfp(struct dfl_hssi *hssi, struct dfl_device *dfl_dev, ++ int index) ++{ ++ struct intel_s10_platform_data pdata = { 0 }; ++ struct platform_device_info pdevinfo = { 0 }; ++ struct platform_device *pdev; ++ ++ pdata.csr_base = hssi->csr_base; ++ pdata.phy_offset = HSSI_QSFP_BASE + index * HSSI_QSFP_SIZE; ++ ++ pdevinfo.name = INTEL_S10_PHY_DRV_NAME; ++ pdevinfo.id = PLATFORM_DEVID_AUTO; ++ pdevinfo.parent = hssi->dev; ++ pdevinfo.data = &pdata; ++ pdevinfo.size_data = sizeof(pdata); ++ ++ pdev = platform_device_register_full(&pdevinfo); ++ if (IS_ERR(pdev)) ++ return PTR_ERR(pdev); ++ ++ hssi->qsfp_cnt++; ++ hssi->intel_s10_phy[index] = pdev; ++ ++ return 0; ++} ++ ++static void hssi_destroy_qsfp(struct dfl_hssi *hssi, int index) ++{ ++ platform_device_unregister(hssi->intel_s10_phy[index]); ++} ++ ++static ssize_t capability_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct dfl_hssi *hssi = dev_get_drvdata(dev); ++ u64 v = readq(hssi->csr_base + HSSI_CAPABILITY); ++ ++ return sprintf(buf, "0x%016llx\n", v); ++} ++static DEVICE_ATTR_RO(capability); ++ ++static struct attribute *hssi_attrs[] = { ++ &dev_attr_capability.attr, ++ NULL, ++}; ++ATTRIBUTE_GROUPS(hssi); ++ ++static int dfl_hssi_probe(struct dfl_device *dfl_dev) ++{ ++ struct device *dev = &dfl_dev->dev; ++ struct dfl_hssi *hssi; ++ int ret, qsfp_cnt, i; ++ void __iomem *csr_base; ++ u64 v; ++ ++ csr_base = devm_ioremap_resource(&dfl_dev->dev, &dfl_dev->mmio_res); ++ if (IS_ERR(csr_base)) { ++ dev_err(dev, "get mem resource fail!\n"); ++ return PTR_ERR(csr_base); ++ } ++ ++ if (!dfl_feature_revision(csr_base)) { ++ dev_info(dev, "hssi feature revision 0 not supported\n"); ++ return -ENOTSUPP; ++ } ++ ++ v = readq(csr_base + HSSI_CAPABILITY); ++ qsfp_cnt = FIELD_GET(NUM_QSFP_INTERFACES, v); ++ ++ hssi = devm_kzalloc(dev, sizeof(*hssi) + qsfp_cnt * sizeof(void *), ++ GFP_KERNEL); ++ if (!hssi) ++ return -ENOMEM; ++ ++ dev_set_drvdata(&dfl_dev->dev, hssi); ++ ++ hssi->csr_base = csr_base; ++ hssi->dev = dev; ++ ++ for (i = 0; i < qsfp_cnt; i++) { ++ ret = hssi_create_qsfp(hssi, dfl_dev, i); ++ if (ret) ++ goto error_exit; ++ } ++ ++ return 0; ++ ++error_exit: ++ for (i = 0; i < hssi->qsfp_cnt; i++) ++ hssi_destroy_qsfp(hssi, i); ++ ++ return ret; ++} ++ ++static void dfl_hssi_remove(struct dfl_device *dfl_dev) ++{ ++ struct dfl_hssi *hssi = dev_get_drvdata(&dfl_dev->dev); ++ int i; ++ ++ for (i = 0; i < hssi->qsfp_cnt; i++) ++ hssi_destroy_qsfp(hssi, i); ++} ++ ++#define FME_FEATURE_ID_HSSI_ETH 0xa ++ ++static const struct dfl_device_id dfl_hssi_ids[] = { ++ { FME_ID, FME_FEATURE_ID_HSSI_ETH }, ++ { } ++}; ++ ++static struct dfl_driver dfl_hssi_driver = { ++ .drv = { ++ .name = "intel-s10-hssi", ++ .dev_groups = hssi_groups, ++ }, ++ .id_table = dfl_hssi_ids, ++ .probe = dfl_hssi_probe, ++ .remove = dfl_hssi_remove, ++}; ++ ++module_dfl_driver(dfl_hssi_driver); ++ ++MODULE_DEVICE_TABLE(dfl, dfl_hssi_ids); ++MODULE_DESCRIPTION("DFL HSSI driver"); ++MODULE_AUTHOR("Intel Corporation"); ++MODULE_LICENSE("GPL v2"); diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0054-net-phy-intel-driver-for-stratix10-phy.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0054-net-phy-intel-driver-for-stratix10-phy.patch new file mode 100644 index 0000000..a95ed04 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0054-net-phy-intel-driver-for-stratix10-phy.patch @@ -0,0 +1,666 @@ +From 8e21725d9c7afa1f6512847964b0e5b74ed88369 Mon Sep 17 00:00:00 2001 +From: Russ Weight +Date: Thu, 23 Apr 2020 12:34:26 -0700 +Subject: [PATCH] net: phy: intel: driver for stratix10 phy + +Create a driver for the QSFP interfaces that are part of +the Intel Stratix 10 FPGA. This driver exposes four +parameters per channel via sysfs, allowing these +parameters to be viewed and changed: + +tx-pre-tap: Pre-emphasis 1st post-tap magnitude (0 - 24) & polarity (+/-) +tx-post-tap: Pre-emphasis 1st pre-tap magnitude (0 - 15) & polarity (+/-) +tx-vod: Sets TX output swing level (17 - 31) +tx-comp: Sets TX Compensation (0 = OFF, 1 = ON) + +These parameters are exposed in per-channel sysfs groups: + + chan0/tx-pre-tap + chan0/tx-post-tap + chan0/tx-vod + chan0/tx-comp + chan1/tx-pre-tap + ... + chan3/tx-pre-tap + chan3/tx-post-tap + chan3/tx-vod + chan3/tx-comp + +Signed-off-by: Russ Weight +--- + MAINTAINERS | 7 + + drivers/net/phy/Kconfig | 9 + + drivers/net/phy/Makefile | 1 + + drivers/net/phy/intel-s10-phy.c | 550 ++++++++++++++++++++++++++++++ + include/linux/phy/intel-s10-phy.h | 21 ++ + 5 files changed, 588 insertions(+) + create mode 100644 drivers/net/phy/intel-s10-phy.c + create mode 100644 include/linux/phy/intel-s10-phy.h + +diff --git a/MAINTAINERS b/MAINTAINERS +index dd5de540ec0b..20dc4f186bef 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -10819,6 +10819,13 @@ F: drivers/firmware/stratix10-svc.c + F: include/linux/firmware/intel/stratix10-smc.h + F: include/linux/firmware/intel/stratix10-svc-client.h + ++INTEL STRATIX10 PHY DRIVER ++M: Russ Weight ++L: linux-fpga@vger.kernel.org ++S: Maintained ++F: drivers/net/phy/intel-s10-phy.c ++F: include/linux/phy/intel-s10-phy.h ++ + INTEL TELEMETRY DRIVER + M: Rajneesh Bhardwaj + M: "David E. Box" +diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig +index 0257154b48d0..ea936d90732c 100644 +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -437,3 +437,12 @@ endif # PHYLIB + config MICREL_KS8995MA + tristate "Micrel KS8995MA 5-ports 10/100 managed Ethernet switch" + depends on SPI ++ ++config INTEL_S10_PHY ++ tristate "Intel HSSI configurable ethernet phy driver" ++ depends on FPGA_DFL ++ select FPGA_DFL_HSSI ++ help ++ This is the Intel HSSI configurable ethernet phy driver. It ++ provides the ability to view and change some of the transceiver ++ tuner parameters for a QSFP interface. +diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile +index 4c568ff878cc..2802517b1896 100644 +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -99,3 +99,4 @@ obj-$(CONFIG_STE10XP) += ste10Xp.o + obj-$(CONFIG_TERANETICS_PHY) += teranetics.o + obj-$(CONFIG_VITESSE_PHY) += vitesse.o + obj-$(CONFIG_XILINX_GMII2RGMII) += xilinx_gmii2rgmii.o ++obj-$(CONFIG_INTEL_S10_PHY) += intel-s10-phy.o +diff --git a/drivers/net/phy/intel-s10-phy.c b/drivers/net/phy/intel-s10-phy.c +new file mode 100644 +index 000000000000..5c3f714507ab +--- /dev/null ++++ b/drivers/net/phy/intel-s10-phy.c +@@ -0,0 +1,550 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Driver for Stratix 10 HSSI Phy ++ * ++ * Copyright 2019-2020 Intel Corporation, Inc. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* HSSI QSFP Control & Status Registers */ ++#define HSSI_QSFP_RCFG_CMD(phy) ((phy)->phy_offset + 0x0) ++#define QSFP_RCFG_CMD GENMASK_ULL(1, 0) ++#define QSFP_RCFG_CMD_CLR 0 ++#define QSFP_RCFG_CMD_RD 1 ++#define QSFP_RCFG_CMD_WRT 2 ++#define QSFP_RCFG_CMD_SEL_XCVR GENMASK_ULL(5, 4) /* XCVR 0 - 3 */ ++#define QSFP_RCFG_XCVR_ADDR GENMASK_ULL(26, 16) ++#define QSFP_RCFG_XCVR_ACK BIT_ULL(32) ++ ++#define HSSI_QSFP_RCFG_DATA(phy) ((phy)->phy_offset + 0x8) ++#define XCVR_RCFG_RDATA GENMASK_ULL(31, 0) /* RO: rd data */ ++#define XCVR_RCFG_WDATA GENMASK_ULL(63, 32) /* RW: wrt data */ ++ ++#define HSSI_QSFP_CTRL(phy) ((phy)->phy_offset + 0x10) ++#define DATA_RATE_SEL_1G BIT_ULL(0) /* 1 = Selected */ ++#define DATA_RATE_SEL_10G BIT_ULL(1) ++#define DATA_RATE_SEL_25G BIT_ULL(2) ++#define DATA_RATE_SEL_40G BIT_ULL(3) ++#define DATA_RATE_SEL_50G BIT_ULL(4) ++#define DATA_RATE_SEL_100G BIT_ULL(5) ++#define DATA_RATE_SEL_200G BIT_ULL(6) ++#define DATA_RATE_SEL_400G BIT_ULL(7) ++#define GLOBAL_RESET BIT_ULL(8) /* 1 = Active */ ++#define RECONFIG_RESET BIT_ULL(9) ++#define CHAN0_RESET BIT_ULL(10) ++#define CHAN1_RESET BIT_ULL(11) ++#define CHAN2_RESET BIT_ULL(12) ++#define CHAN3_RESET BIT_ULL(13) ++#define SELECT_ATX_PLL BIT_ULL(14) /* 0 = 10G, 1 = 25G */ ++#define SELECT_TX_CORE_CLK BIT_ULL(15) /* 0 = PHY, 1 = IOPLL */ ++#define SELECT_RX_CORE_CLK BIT_ULL(16) /* 0 = PHY, 1 = IOPLL */ ++ ++#define HSSI_QSFP_STAT(phy) ((phy)->phy_offset + 0x18) ++#define HSSI_QSFP_STAT_CHAN0 GENMASK_ULL(15, 0) ++#define HSSI_QSFP_STAT_CHAN1 GENMASK_ULL(31, 16) ++#define HSSI_QSFP_STAT_CHAN2 GENMASK_ULL(47, 32) ++#define HSSI_QSFP_STAT_CHAN3 GENMASK_ULL(63, 48) ++#define TX_ANALOG_RST_STAT BIT_ULL(0) ++#define TX_DIG_RST_STAT BIT_ULL(1) ++#define RX_ANALOG_RST_STAT BIT_ULL(2) ++#define RX_DIG_RST_STAT BIT_ULL(3) ++#define TX_DIG_RST_TIMEOUT BIT_ULL(4) ++#define RX_DIG_RST_TIMEOUT BIT_ULL(5) ++#define TX_FIFO_READY BIT_ULL(6) ++#define RX_FIFO_READY BIT_ULL(7) ++#define TX_XFER_READY BIT_ULL(8) ++#define RX_XFER_READY BIT_ULL(9) ++#define TX_CAL_BUSY BIT_ULL(10) ++#define RX_CAL_BUSY BIT_ULL(11) ++#define RX_LOCKED_TO_DATA BIT_ULL(12) ++#define RX_LOCKED_TO_REF BIT_ULL(13) ++#define TX_READY BIT_ULL(14) ++#define RX_READY BIT_ULL(15) ++ ++#define HSSI_WRITE_POLL_INVL_US 10 /* Write poll interval */ ++#define HSSI_WRITE_POLL_TIMEOUT_US 100000 /* Write poll timeout */ ++ ++/* Analog preemphasis tuning parameters */ ++#define PRE_TAP_ADDR 0x107 ++#define PRE_TAP_MAGNITUDE_MASK GENMASK(4, 0) ++#define PRE_TAP_MAX 15 ++#define PRE_TAP_POLARITY BIT(5) /* 1 = negative polarity */ ++ ++#define POST_TAP_ADDR 0x105 ++#define POST_TAP_MAGNITUDE_MASK GENMASK(4, 0) ++#define POST_TAP_MAX 24 ++#define POST_TAP_POLARITY BIT(6) /* 1 = negative polarity */ ++ ++#define VOD_COMP_ADDR 0x109 ++#define VOD_MASK GENMASK(4, 0) ++#define VOD_MIN 17 ++#define VOD_MAX 31 ++ ++#define COMPENSATION_FLAG BIT(5) /* 1 = ON; 0 = OFF */ ++ ++struct hssi_phy { ++ void __iomem *csr_base; ++ u32 phy_offset; ++ struct device *dev; ++ struct mutex lock; /* serialize access to phy registers */ ++}; ++ ++static int hssi_await_ack(struct hssi_phy *phy) ++{ ++ int ret; ++ u64 v; ++ ++ /* Poll for the expected state of acknowlege bit */ ++ ret = readq_poll_timeout(phy->csr_base + HSSI_QSFP_RCFG_CMD(phy), v, ++ v & QSFP_RCFG_XCVR_ACK, ++ HSSI_WRITE_POLL_INVL_US, ++ HSSI_WRITE_POLL_TIMEOUT_US); ++ if (ret) { ++ dev_err(phy->dev, "timeout, phy ack not received\n"); ++ return ret; ++ } ++ ++ /* Clear ACK state */ ++ v = readq(phy->csr_base + HSSI_QSFP_RCFG_CMD(phy)); ++ v &= ~QSFP_RCFG_CMD; ++ v |= FIELD_PREP(QSFP_RCFG_CMD, QSFP_RCFG_CMD_CLR); ++ writeq(v, phy->csr_base + HSSI_QSFP_RCFG_CMD(phy)); ++ ++ return 0; ++} ++ ++static int hssi_xcvr_read(struct hssi_phy *phy, u8 chan_num, ++ u16 addr, u32 *data) ++{ ++ int ret; ++ u64 v; ++ ++ /* Read the desired address */ ++ v = FIELD_PREP(QSFP_RCFG_CMD, QSFP_RCFG_CMD_RD); ++ v |= FIELD_PREP(QSFP_RCFG_CMD_SEL_XCVR, chan_num); ++ v |= FIELD_PREP(QSFP_RCFG_XCVR_ADDR, addr); ++ writeq(v, phy->csr_base + HSSI_QSFP_RCFG_CMD(phy)); ++ ++ /* Poll for read complete */ ++ ret = hssi_await_ack(phy); ++ if (ret) ++ return ret; ++ ++ /* Return data */ ++ v = readq(phy->csr_base + HSSI_QSFP_RCFG_DATA(phy)); ++ *data = FIELD_GET(XCVR_RCFG_RDATA, v); ++ ++ return 0; ++} ++ ++static int hssi_xcvr_write(struct hssi_phy *phy, u8 chan_num, ++ u16 addr, u32 data) ++{ ++ u64 v; ++ ++ /* Set up the write data */ ++ v = FIELD_PREP(XCVR_RCFG_WDATA, data); ++ writeq(v, phy->csr_base + HSSI_QSFP_RCFG_DATA(phy)); ++ ++ /* Trigger the write */ ++ v = FIELD_PREP(QSFP_RCFG_CMD, QSFP_RCFG_CMD_WRT); ++ v |= FIELD_PREP(QSFP_RCFG_CMD_SEL_XCVR, chan_num); ++ v |= FIELD_PREP(QSFP_RCFG_XCVR_ADDR, addr); ++ writeq(v, phy->csr_base + HSSI_QSFP_RCFG_CMD(phy)); ++ ++ /* Poll for write complete */ ++ return hssi_await_ack(phy); ++} ++ ++static int hssi_xcvr_rmw(struct hssi_phy *phy, u8 chan_num, ++ u16 addr, u32 mask, u32 data) ++{ ++ u32 value; ++ int ret; ++ ++ ret = hssi_xcvr_read(phy, chan_num, addr, &value); ++ if (ret) ++ return ret; ++ ++ value &= ~mask; ++ value |= (data & mask); ++ ++ return hssi_xcvr_write(phy, chan_num, addr, value); ++} ++ ++static ssize_t tx_pre_tap_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct hssi_phy *phy = dev_get_drvdata(dev); ++ struct dev_ext_attribute *eattr; ++ u8 magnitude, polarity = 0; ++ const char *p = buf; ++ unsigned long chan; ++ int ret; ++ ++ if ((buf[0] == '+') || (buf[0] == '-')) { ++ if (buf[0] == '-') ++ polarity = PRE_TAP_POLARITY; ++ p++; ++ } ++ ++ ret = kstrtou8(p, 0, &magnitude); ++ if (ret) ++ return ret; ++ ++ if (magnitude > PRE_TAP_MAX) { ++ dev_err(phy->dev, "Max pre-tap is %d\n", PRE_TAP_MAX); ++ return -EINVAL; ++ } ++ ++ eattr = container_of(attr, struct dev_ext_attribute, attr); ++ chan = (unsigned long)eattr->var; ++ ++ mutex_lock(&phy->lock); ++ ret = hssi_xcvr_rmw(phy, (u8)chan, PRE_TAP_ADDR, ++ PRE_TAP_POLARITY | PRE_TAP_MAGNITUDE_MASK, ++ polarity | magnitude); ++ mutex_unlock(&phy->lock); ++ ++ return ret ? : count; ++} ++ ++static ssize_t tx_pre_tap_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct hssi_phy *phy = dev_get_drvdata(dev); ++ struct dev_ext_attribute *eattr; ++ char polarity = '\0'; ++ unsigned long chan; ++ u8 magnitude; ++ u32 pre_tap; ++ int ret; ++ ++ eattr = container_of(attr, struct dev_ext_attribute, attr); ++ chan = (unsigned long)eattr->var; ++ ++ mutex_lock(&phy->lock); ++ ret = hssi_xcvr_read(phy, (u8)chan, PRE_TAP_ADDR, &pre_tap); ++ mutex_unlock(&phy->lock); ++ ++ if (ret) ++ return ret; ++ ++ magnitude = pre_tap & PRE_TAP_MAGNITUDE_MASK; ++ if (magnitude) ++ polarity = pre_tap & PRE_TAP_POLARITY ? '-' : '+'; ++ ++ return scnprintf(buf, PAGE_SIZE, "%c%u\n", polarity, magnitude); ++} ++ ++static ssize_t tx_post_tap_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct hssi_phy *phy = dev_get_drvdata(dev); ++ struct dev_ext_attribute *eattr; ++ u8 magnitude, polarity = 0; ++ const char *p = buf; ++ unsigned long chan; ++ int ret; ++ ++ if ((buf[0] == '+') || (buf[0] == '-')) { ++ if (buf[0] == '-') ++ polarity = POST_TAP_POLARITY; ++ p++; ++ } ++ ++ ret = kstrtou8(p, 0, &magnitude); ++ if (ret) ++ return ret; ++ ++ if (magnitude > POST_TAP_MAX) { ++ dev_err(phy->dev, "Max post-tap is %d\n", POST_TAP_MAX); ++ return -EINVAL; ++ } ++ ++ eattr = container_of(attr, struct dev_ext_attribute, attr); ++ chan = (unsigned long)eattr->var; ++ ++ mutex_lock(&phy->lock); ++ ret = hssi_xcvr_rmw(phy, (u8)chan, POST_TAP_ADDR, ++ POST_TAP_POLARITY | POST_TAP_MAGNITUDE_MASK, ++ polarity | magnitude); ++ mutex_unlock(&phy->lock); ++ ++ return ret ? : count; ++} ++ ++static ssize_t tx_post_tap_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct hssi_phy *phy = dev_get_drvdata(dev); ++ struct dev_ext_attribute *eattr; ++ char polarity = '\0'; ++ unsigned long chan; ++ u8 magnitude; ++ u32 post_tap; ++ int ret; ++ ++ eattr = container_of(attr, struct dev_ext_attribute, attr); ++ chan = (unsigned long)eattr->var; ++ ++ mutex_lock(&phy->lock); ++ ret = hssi_xcvr_read(phy, (u8)chan, POST_TAP_ADDR, &post_tap); ++ mutex_unlock(&phy->lock); ++ ++ if (ret) ++ return ret; ++ ++ magnitude = post_tap & POST_TAP_MAGNITUDE_MASK; ++ if (magnitude) ++ polarity = post_tap & POST_TAP_POLARITY ? '-' : '+'; ++ ++ return scnprintf(buf, PAGE_SIZE, "%c%u\n", polarity, magnitude); ++} ++ ++static ssize_t tx_vod_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct hssi_phy *phy = dev_get_drvdata(dev); ++ struct dev_ext_attribute *eattr; ++ unsigned long chan; ++ int ret; ++ u8 vod; ++ ++ ret = kstrtou8(buf, 0, &vod); ++ if (ret) ++ return ret; ++ ++ if (vod > VOD_MAX || vod < VOD_MIN) { ++ dev_err(phy->dev, "Valid VOD range is %d to %d\n", ++ VOD_MIN, VOD_MAX); ++ return -EINVAL; ++ } ++ ++ eattr = container_of(attr, struct dev_ext_attribute, attr); ++ chan = (unsigned long)eattr->var; ++ ++ mutex_lock(&phy->lock); ++ ret = hssi_xcvr_rmw(phy, (u8)chan, VOD_COMP_ADDR, VOD_MASK, vod); ++ mutex_unlock(&phy->lock); ++ ++ return ret ? : count; ++} ++ ++static ssize_t tx_vod_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct hssi_phy *phy = dev_get_drvdata(dev); ++ struct dev_ext_attribute *eattr; ++ unsigned long chan; ++ int ret; ++ u32 vod; ++ ++ eattr = container_of(attr, struct dev_ext_attribute, attr); ++ chan = (unsigned long)eattr->var; ++ ++ mutex_lock(&phy->lock); ++ ret = hssi_xcvr_read(phy, (u8)chan, VOD_COMP_ADDR, &vod); ++ mutex_unlock(&phy->lock); ++ ++ return ret ? : scnprintf(buf, PAGE_SIZE, "%lu\n", vod & VOD_MASK); ++} ++ ++static ssize_t tx_comp_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct hssi_phy *phy = dev_get_drvdata(dev); ++ struct dev_ext_attribute *eattr; ++ unsigned long chan; ++ u8 compensation; ++ int ret; ++ ++ ret = kstrtou8(buf, 0, &compensation); ++ if (ret) ++ return ret; ++ ++ if (compensation > 1) { ++ dev_err(phy->dev, "Compensation must be 1 or 0"); ++ return -EINVAL; ++ } ++ ++ eattr = container_of(attr, struct dev_ext_attribute, attr); ++ chan = (unsigned long)eattr->var; ++ ++ mutex_lock(&phy->lock); ++ ret = hssi_xcvr_rmw(phy, (u8)chan, VOD_COMP_ADDR, COMPENSATION_FLAG, ++ compensation ? COMPENSATION_FLAG : 0); ++ mutex_unlock(&phy->lock); ++ ++ return ret ? : count; ++} ++ ++static ssize_t tx_comp_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct hssi_phy *phy = dev_get_drvdata(dev); ++ struct dev_ext_attribute *eattr; ++ unsigned long chan; ++ u32 compensation; ++ int ret; ++ ++ eattr = container_of(attr, struct dev_ext_attribute, attr); ++ chan = (unsigned long)eattr->var; ++ ++ mutex_lock(&phy->lock); ++ ret = hssi_xcvr_read(phy, (u8)chan, VOD_COMP_ADDR, &compensation); ++ mutex_unlock(&phy->lock); ++ ++ return ret ? : scnprintf(buf, PAGE_SIZE, "%u\n", ++ compensation & COMPENSATION_FLAG ? 1 : 0); ++} ++ ++#define PHY_TUNE_ATTR(_name, _chan) \ ++static struct dev_ext_attribute phy_tune_##_name##_chan = { \ ++ .attr = __ATTR_RW(_name), \ ++ .var = (void *)_chan, \ ++} ++ ++#define PHY_TUNE_ATTRS(_chan) \ ++PHY_TUNE_ATTR(tx_comp, _chan); \ ++PHY_TUNE_ATTR(tx_post_tap, _chan); \ ++PHY_TUNE_ATTR(tx_pre_tap, _chan); \ ++PHY_TUNE_ATTR(tx_vod, _chan); \ ++static struct attribute *chan##_chan##_attrs[] = { \ ++ &phy_tune_tx_pre_tap##_chan.attr.attr, \ ++ &phy_tune_tx_post_tap##_chan.attr.attr, \ ++ &phy_tune_tx_vod##_chan.attr.attr, \ ++ &phy_tune_tx_comp##_chan.attr.attr, \ ++ NULL, \ ++}; \ ++static struct attribute_group chan##_chan##_attr_group = { \ ++ .name = __stringify(chan##_chan), \ ++ .attrs = chan##_chan##_attrs, \ ++} ++ ++PHY_TUNE_ATTRS(0); ++PHY_TUNE_ATTRS(1); ++PHY_TUNE_ATTRS(2); ++PHY_TUNE_ATTRS(3); ++ ++static ssize_t ctrl_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct hssi_phy *phy = dev_get_drvdata(dev); ++ int ret; ++ u64 v; ++ ++ ret = kstrtou64(buf, 0, &v); ++ if (ret) ++ return ret; ++ ++ mutex_lock(&phy->lock); ++ writeq(v, phy->csr_base + HSSI_QSFP_CTRL(phy)); ++ mutex_unlock(&phy->lock); ++ ++ return count; ++} ++ ++static ssize_t ctrl_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct hssi_phy *phy = dev_get_drvdata(dev); ++ u64 v; ++ ++ mutex_lock(&phy->lock); ++ v = readq(phy->csr_base + HSSI_QSFP_CTRL(phy)); ++ mutex_unlock(&phy->lock); ++ ++ return scnprintf(buf, PAGE_SIZE, "0x%016llx\n", v); ++} ++static DEVICE_ATTR_RW(ctrl); ++ ++static ssize_t stat_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct hssi_phy *phy = dev_get_drvdata(dev); ++ u64 v; ++ ++ mutex_lock(&phy->lock); ++ v = readq(phy->csr_base + HSSI_QSFP_STAT(phy)); ++ mutex_unlock(&phy->lock); ++ ++ return scnprintf(buf, PAGE_SIZE, "0x%016llx\n", v); ++} ++static DEVICE_ATTR_RO(stat); ++ ++static struct attribute *qsfp_attrs[] = { ++ &dev_attr_ctrl.attr, ++ &dev_attr_stat.attr, ++ NULL, ++}; ++ ++static struct attribute_group qsfp_attr_group = { ++ .attrs = qsfp_attrs, ++}; ++ ++static const struct attribute_group *qsfp_attr_groups[] = { ++ &qsfp_attr_group, ++ &chan0_attr_group, ++ &chan1_attr_group, ++ &chan2_attr_group, ++ &chan3_attr_group, ++ NULL, ++}; ++ ++static int intel_s10_phy_probe(struct platform_device *pdev) ++{ ++ struct intel_s10_platform_data *pdata; ++ struct device *dev = &pdev->dev; ++ struct hssi_phy *phy; ++ ++ pdata = dev_get_platdata(dev); ++ if (!pdata) ++ return -ENODEV; ++ ++ phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); ++ if (!phy) ++ return -ENOMEM; ++ ++ phy->csr_base = pdata->csr_base; ++ phy->phy_offset = pdata->phy_offset; ++ phy->dev = dev; ++ mutex_init(&phy->lock); ++ dev_set_drvdata(dev, phy); ++ ++ return 0; ++} ++ ++static int intel_s10_phy_remove(struct platform_device *pdev) ++{ ++ struct hssi_phy *phy = dev_get_drvdata(&pdev->dev); ++ ++ mutex_destroy(&phy->lock); ++ return 0; ++} ++ ++static struct platform_driver intel_s10_phy_driver = { ++ .driver = { ++ .name = INTEL_S10_PHY_DRV_NAME, ++ .dev_groups = qsfp_attr_groups, ++ }, ++ .probe = intel_s10_phy_probe, ++ .remove = intel_s10_phy_remove, ++}; ++ ++module_platform_driver(intel_s10_phy_driver); ++ ++MODULE_DESCRIPTION("Intel HSSI Ethernet Phy"); ++MODULE_AUTHOR("Intel Corporation"); ++MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("platform:" INTEL_S10_PHY_DRV_NAME); +diff --git a/include/linux/phy/intel-s10-phy.h b/include/linux/phy/intel-s10-phy.h +new file mode 100644 +index 000000000000..a68a5e1d2ba6 +--- /dev/null ++++ b/include/linux/phy/intel-s10-phy.h +@@ -0,0 +1,21 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Header File for Intel Stratix 10 Phy Driver. ++ * ++ * Copyright 2019-2020 Intel Corporation, Inc. ++ */ ++#ifndef __INTEL_S10_PHY_H ++#define __INTEL_S10_PHY_H ++ ++#define INTEL_S10_PHY_DRV_NAME "intel-s10-phy" ++ ++/** ++ * struct intel_s10_platform_data - Platform data of the Intel S10 Phy Driver ++ * @csr_base: Base address of Control & Status registers ++ */ ++struct intel_s10_platform_data { ++ void __iomem *csr_base; ++ u32 phy_offset; ++}; ++ ++#endif /* __INTEL_S10_PHY_H */ diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0055-net-ethernet-intel-add-s10hssi-driver.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0055-net-ethernet-intel-add-s10hssi-driver.patch new file mode 100644 index 0000000..6900c08 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0055-net-ethernet-intel-add-s10hssi-driver.patch @@ -0,0 +1,593 @@ +From 7776d7d7bd16b2b1a9313094c84ba0d2cab01216 Mon Sep 17 00:00:00 2001 +From: Matthew Gerlach +Date: Mon, 20 Apr 2020 17:31:44 -0700 +Subject: [PATCH] net: ethernet: intel: add s10hssi driver + +Add stratix 10 high speed interface driver supporting both +10G and 100G ethernet. + +Signed-off-by: Matthew Gerlach +Based-on: Wu Hao +Based-on: Xu Yilun +Signed-off-by: Chen Guanqiao +Signed-off-by: Tom Rix +--- + drivers/net/ethernet/intel/Kconfig | 13 + + drivers/net/ethernet/intel/Makefile | 1 + + drivers/net/ethernet/intel/s10hssi.c | 536 +++++++++++++++++++++++++++ + 3 files changed, 550 insertions(+) + create mode 100644 drivers/net/ethernet/intel/s10hssi.c + +diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig +index 9bc0a9519899..eb963f5c0261 100644 +--- a/drivers/net/ethernet/intel/Kconfig ++++ b/drivers/net/ethernet/intel/Kconfig +@@ -356,4 +356,17 @@ config IGC + To compile this driver as a module, choose M here. The module + will be called igc. + ++config S10HSSI ++ tristate "Control Plane Driver for Stratix 10 HSSI" ++ select REGMAP_INDIRECT_REGISTER ++ help ++ This driver provides control plane support for an Stratix 10 ++ High Speed Serial Interface. ++ ++ The Stratix 10 High Speed Serial Interface provides a data ++ path between the FPGA and the external QSFP interfaces. This ++ data path does not involve packets transferred between host ++ memory and the fpga. As such a very limited set of networking ++ functionality is provided. ++ + endif # NET_VENDOR_INTEL +diff --git a/drivers/net/ethernet/intel/Makefile b/drivers/net/ethernet/intel/Makefile +index d80d04132073..75d2caeea061 100644 +--- a/drivers/net/ethernet/intel/Makefile ++++ b/drivers/net/ethernet/intel/Makefile +@@ -15,3 +15,4 @@ obj-$(CONFIG_I40E) += i40e/ + obj-$(CONFIG_IAVF) += iavf/ + obj-$(CONFIG_FM10K) += fm10k/ + obj-$(CONFIG_ICE) += ice/ ++obj-$(CONFIG_S10HSSI) += s10hssi.o +diff --git a/drivers/net/ethernet/intel/s10hssi.c b/drivers/net/ethernet/intel/s10hssi.c +new file mode 100644 +index 000000000000..ee97a08e74b6 +--- /dev/null ++++ b/drivers/net/ethernet/intel/s10hssi.c +@@ -0,0 +1,536 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++/* Intel(R) Low Latency 10G Network Driver ++ * ++ * Copyright (C) 2020 Intel Corporation. All rights reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define CAPABILITY_OFF 0x08 ++#define CAP_AVAILABLE_RATES GENMASK_ULL(7, 0) ++#define CAP_CONTAINS_PCS GENMASK_ULL(15, 8) ++#define CAP_CONTAINS_FEC GENMASK_ULL(23, 16) ++#define CAP_RATE_1G BIT_ULL(0) ++#define CAP_RATE_10G BIT_ULL(1) ++#define CAP_RATE_25G BIT_ULL(2) ++#define CAP_RATE_40G BIT_ULL(3) ++#define CAP_RATE_50G BIT_ULL(4) ++#define CAP_RATE_100G BIT_ULL(5) ++#define CAP_RATE_200G BIT_ULL(6) ++#define CAP_RATE_400G BIT_ULL(7) ++ ++#define MB_BASE_OFF 0x28 ++ ++#define PHY_BASE_OFF 0x2000 ++#define PHY_RX_SER_LOOP_BACK 0x4e1 ++#define PHY_MAX_OFF 0x541 ++ ++#define ILL_10G_BASE_OFF 0 ++#define ILL_10G_MAX_OFF 0x1d00 ++#define ILL_10G_TX_STATS_CLR 0x1c00 ++#define ILL_10G_RX_STATS_CLR 0x0c00 ++ ++#define ILL_100G_BASE_OFF 0x400 ++#define ILL_100G_MAX_OFF 0x9ff ++#define ILL_100G_TX_STATS_CLR 0x845 ++#define ILL_100G_RX_STATS_CLR 0x945 ++ ++#define ILL_100G_PHY_BASE_OFF 0x300 ++#define ILL_100G_PHY_MAX_OFF 0x3ff ++#define ILL_100G_LPBK_OFF 0x313 ++#define ILL_100G_LPBK_EN_VAL 0xffff ++ ++#define STATS_CLR_INT_US 1 ++#define STATS_CLR_INT_TIMEOUT_US 1000 ++ ++struct s10hssi_drvdata { ++ struct net_device *netdev; ++}; ++ ++struct s10hssi_ops_params { ++ struct stat_info *stats; ++ u32 num_stats; ++ u32 tx_clr_off; ++ u32 rx_clr_off; ++ u32 lpbk_off; ++ u32 lpbk_en_val; ++}; ++ ++struct s10hssi_netdata { ++ struct dfl_device *dfl_dev; ++ struct regmap *regmap; ++ const struct s10hssi_ops_params *ops_params; ++}; ++ ++static int netdev_change_mtu(struct net_device *netdev, int new_mtu) ++{ ++ netdev->mtu = new_mtu; ++ ++ return 0; ++} ++ ++static int netdev_set_loopback(struct net_device *netdev, bool en) ++{ ++ struct s10hssi_netdata *npriv = netdev_priv(netdev); ++ u32 val = 0; ++ ++ if (en) ++ val = npriv->ops_params->lpbk_en_val; ++ ++ return regmap_write(npriv->regmap, npriv->ops_params->lpbk_off, val); ++} ++ ++static int netdev_set_features(struct net_device *netdev, ++ netdev_features_t features) ++{ ++ netdev_features_t changed = netdev->features ^ features; ++ ++ if (changed & NETIF_F_LOOPBACK) ++ return netdev_set_loopback(netdev, !!(features & NETIF_F_LOOPBACK)); ++ ++ return 0; ++} ++ ++static int netdev_set_mac_address(struct net_device *ndev, void *p) ++{ ++ struct sockaddr *addr = p; ++ ++ memcpy((void *)ndev->dev_addr, addr->sa_data, ETH_ALEN); ++ ++ /* TODO program hardware */ ++ ++ return 0; ++} ++ ++static netdev_tx_t s10hssi_dummy_netdev_xmit(struct sk_buff *skb, ++ struct net_device *dev) ++{ ++ if (!dev) ++ return -EINVAL; ++ ++ kfree_skb(skb); ++ net_warn_ratelimited("%s(): Dropping skb.\n", __func__); ++ return NETDEV_TX_OK; ++} ++ ++static const struct net_device_ops netdev_ops = { ++ .ndo_change_mtu = netdev_change_mtu, ++ .ndo_set_features = netdev_set_features, ++ .ndo_set_mac_address = netdev_set_mac_address, ++ .ndo_start_xmit = s10hssi_dummy_netdev_xmit, ++}; ++ ++struct stat_info { ++ unsigned int addr; ++ char string[ETH_GSTRING_LEN]; ++}; ++ ++#define STAT_INFO(_addr, _string) \ ++ .addr = _addr, .string = _string, ++ ++static struct stat_info stats_10g[] = { ++ /* TX Statistics */ ++ {STAT_INFO(0x1c02, "tx_frame_ok")}, ++ {STAT_INFO(0x1c04, "tx_frame_err")}, ++ {STAT_INFO(0x1c06, "tx_frame_crc_err")}, ++ {STAT_INFO(0x1c08, "tx_octets_ok")}, ++ {STAT_INFO(0x1c0a, "tx_pause_mac_ctrl_frames")}, ++ {STAT_INFO(0x1c0c, "tx_if_err")}, ++ {STAT_INFO(0x1c0e, "tx_unicast_frame_ok")}, ++ {STAT_INFO(0x1c10, "tx_unicast_frame_err")}, ++ {STAT_INFO(0x1c12, "tx_multicast_frame_ok")}, ++ {STAT_INFO(0x1c14, "tx_multicast_frame_err")}, ++ {STAT_INFO(0x1c16, "tx_broadcast_frame_ok")}, ++ {STAT_INFO(0x1c18, "tx_broadcast_frame_err")}, ++ {STAT_INFO(0x1c1a, "tx_ether_octets")}, ++ {STAT_INFO(0x1c1c, "tx_ether_pkts")}, ++ {STAT_INFO(0x1c1e, "tx_ether_undersize_pkts")}, ++ {STAT_INFO(0x1c20, "tx_ether_oversize_pkts")}, ++ {STAT_INFO(0x1c22, "tx_ether_pkts_64_octets")}, ++ {STAT_INFO(0x1c24, "tx_ether_pkts_65_127_octets")}, ++ {STAT_INFO(0x1c26, "tx_ether_pkts_128_255_octets")}, ++ {STAT_INFO(0x1c28, "tx_ether_pkts_256_511_octets")}, ++ {STAT_INFO(0x1c2a, "tx_ether_pkts_512_1023_octets")}, ++ {STAT_INFO(0x1c2c, "tx_ether_pkts_1024_1518_octets")}, ++ {STAT_INFO(0x1c2e, "tx_ether_pkts_1519_x_octets")}, ++ {STAT_INFO(0x1c30, "tx_ether_fragments")}, ++ {STAT_INFO(0x1c32, "tx_ether_jabbers")}, ++ {STAT_INFO(0x1c34, "tx_ether_crc_err")}, ++ {STAT_INFO(0x1c36, "tx_unicast_mac_ctrl_frames")}, ++ {STAT_INFO(0x1c38, "tx_multicast_mac_ctrl_frames")}, ++ {STAT_INFO(0x1c3a, "tx_broadcast_mac_ctrl_frames")}, ++ {STAT_INFO(0x1c3c, "tx_pfc_mac_ctrl_frames")}, ++ ++ /* RX Statistics */ ++ {STAT_INFO(0x0c02, "rx_frame_ok")}, ++ {STAT_INFO(0x0c04, "rx_frame_err")}, ++ {STAT_INFO(0x0c06, "rx_frame_crc_err")}, ++ {STAT_INFO(0x0c08, "rx_octets_ok")}, ++ {STAT_INFO(0x0c0a, "rx_pause_mac_ctrl_frames")}, ++ {STAT_INFO(0x0c0c, "rx_if_err")}, ++ {STAT_INFO(0x0c0e, "rx_unicast_frame_ok")}, ++ {STAT_INFO(0x0c10, "rx_unicast_frame_err")}, ++ {STAT_INFO(0x0c12, "rx_multicast_frame_ok")}, ++ {STAT_INFO(0x0c14, "rx_multicast_frame_err")}, ++ {STAT_INFO(0x0c16, "rx_broadcast_frame_ok")}, ++ {STAT_INFO(0x0c18, "rx_broadcast_frame_err")}, ++ {STAT_INFO(0x0c1a, "rx_ether_octets")}, ++ {STAT_INFO(0x0c1c, "rx_ether_pkts")}, ++ {STAT_INFO(0x0c1e, "rx_ether_undersize_pkts")}, ++ {STAT_INFO(0x0c20, "rx_ether_oversize_pkts")}, ++ {STAT_INFO(0x0c22, "rx_ether_pkts_64_octets")}, ++ {STAT_INFO(0x0c24, "rx_ether_pkts_65_127_octets")}, ++ {STAT_INFO(0x0c26, "rx_ether_pkts_128_255_octets")}, ++ {STAT_INFO(0x0c28, "rx_ether_pkts_256_511_octets")}, ++ {STAT_INFO(0x0c2a, "rx_ether_pkts_512_1023_octets")}, ++ {STAT_INFO(0x0c2c, "rx_ether_pkts_1024_1518_octets")}, ++ {STAT_INFO(0x0c2e, "rx_ether_pkts_1519_x_octets")}, ++ {STAT_INFO(0x0c30, "rx_ether_fragments")}, ++ {STAT_INFO(0x0c32, "rx_ether_jabbers")}, ++ {STAT_INFO(0x0c34, "rx_ether_crc_err")}, ++ {STAT_INFO(0x0c36, "rx_unicast_mac_ctrl_frames")}, ++ {STAT_INFO(0x0c38, "rx_multicast_mac_ctrl_frames")}, ++ {STAT_INFO(0x0c3a, "rx_broadcast_mac_ctrl_frames")}, ++ {STAT_INFO(0x0c3c, "rx_pfc_mac_ctrl_frames")}, ++}; ++ ++static void ethtool_get_strings(struct net_device *netdev, u32 stringset, ++ u8 *s) ++{ ++ struct s10hssi_netdata *npriv = netdev_priv(netdev); ++ unsigned int i, stats_num = 0; ++ struct stat_info *stat; ++ ++ switch (stringset) { ++ case ETH_SS_STATS: ++ stat = npriv->ops_params->stats; ++ stats_num = npriv->ops_params->num_stats; ++ break; ++ default: ++ return; ++ } ++ ++ for (i = 0; i < stats_num; i++, s += ETH_GSTRING_LEN) ++ memcpy(s, stat[i].string, ETH_GSTRING_LEN); ++} ++ ++static int ethtool_get_sset_count(struct net_device *netdev, int stringset) ++{ ++ struct s10hssi_netdata *npriv = netdev_priv(netdev); ++ ++ switch (stringset) { ++ case ETH_SS_STATS: ++ return npriv->ops_params->num_stats; ++ ++ default: ++ return 0; ++ } ++} ++ ++static u64 read_mac_stat(struct regmap *regmap, unsigned int addr) ++{ ++ u32 data_l, data_h; ++ ++ regmap_read(regmap, addr, &data_l); ++ regmap_read(regmap, addr + 1, &data_h); ++ ++ return data_l + ((u64)data_h << 32); ++} ++ ++static int ethtool_reset(struct net_device *netdev, u32 *flags) ++{ ++ struct s10hssi_netdata *npriv = netdev_priv(netdev); ++ struct device *dev = &npriv->dfl_dev->dev; ++ int ret; ++ u32 val; ++ ++ if (*flags | ETH_RESET_MGMT) { ++ regmap_write(npriv->regmap, npriv->ops_params->tx_clr_off, 1); ++ ++ ret = regmap_read_poll_timeout(npriv->regmap, npriv->ops_params->tx_clr_off, ++ val, (!val), STATS_CLR_INT_US, ++ STATS_CLR_INT_TIMEOUT_US); ++ ++ if (ret) { ++ dev_err(dev, "%s failed to clear tx stats\n", __func__); ++ return ret; ++ } ++ ++ regmap_write(npriv->regmap, npriv->ops_params->rx_clr_off, 1); ++ ++ ret = regmap_read_poll_timeout(npriv->regmap, npriv->ops_params->rx_clr_off, ++ val, (!val), STATS_CLR_INT_US, ++ STATS_CLR_INT_TIMEOUT_US); ++ ++ if (ret) { ++ dev_err(dev, "%s failed to clear rx stats\n", __func__); ++ return ret; ++ } ++ dev_info(dev, "%s reset statistics registers\n", __func__); ++ } ++ ++ return 0; ++} ++ ++static void ethtool_get_stats(struct net_device *netdev, ++ struct ethtool_stats *stats, u64 *data) ++{ ++ struct s10hssi_netdata *npriv = netdev_priv(netdev); ++ unsigned int i, stats_num = npriv->ops_params->num_stats; ++ struct stat_info *stat = npriv->ops_params->stats; ++ u32 flags = ETH_RESET_MGMT; ++ ++ for (i = 0; i < stats_num; i++) ++ data[i] = read_mac_stat(npriv->regmap, stat[i].addr); ++ ++ ethtool_reset(netdev, &flags); ++} ++ ++static const struct ethtool_ops ethtool_ops = { ++ .get_strings = ethtool_get_strings, ++ .get_sset_count = ethtool_get_sset_count, ++ .get_ethtool_stats = ethtool_get_stats, ++ .reset = ethtool_reset, ++}; ++ ++static const struct s10hssi_ops_params s10hssi_params = { ++ .stats = stats_10g, ++ .num_stats = ARRAY_SIZE(stats_10g), ++ .tx_clr_off = ILL_10G_TX_STATS_CLR, ++ .rx_clr_off = ILL_10G_RX_STATS_CLR, ++ .lpbk_off = PHY_BASE_OFF + PHY_RX_SER_LOOP_BACK, ++ .lpbk_en_val = 1, ++}; ++ ++static const struct regmap_range regmap_range_10g[] = { ++ regmap_reg_range(ILL_10G_BASE_OFF, ILL_10G_MAX_OFF), ++ regmap_reg_range(PHY_BASE_OFF, PHY_BASE_OFF + PHY_MAX_OFF), ++}; ++ ++static const struct regmap_access_table access_table_10g = { ++ .yes_ranges = regmap_range_10g, ++ .n_yes_ranges = ARRAY_SIZE(regmap_range_10g), ++}; ++ ++static struct stat_info stats_100g[] = { ++ /* tx statistics */ ++ {STAT_INFO(0x800, "tx_fragments")}, ++ {STAT_INFO(0x802, "tx_jabbers")}, ++ {STAT_INFO(0x804, "tx_crcerr")}, ++ {STAT_INFO(0x806, "tx_crcerr_sizeok")}, ++ {STAT_INFO(0x808, "tx_mcast_data_err")}, ++ {STAT_INFO(0x80a, "tx_bcast_data_err")}, ++ {STAT_INFO(0x80c, "tx_ucast_data_err")}, ++ {STAT_INFO(0x80e, "tx_mcast_ctrl_err")}, ++ {STAT_INFO(0x810, "tx_bcast_ctrl_err")}, ++ {STAT_INFO(0x812, "tx_ucast_ctrl_err")}, ++ {STAT_INFO(0x814, "tx_pause_err")}, ++ {STAT_INFO(0x816, "tx_64b")}, ++ {STAT_INFO(0x818, "tx_65to127b")}, ++ {STAT_INFO(0x81a, "tx_128to255b")}, ++ {STAT_INFO(0x81c, "tx_256to511b")}, ++ {STAT_INFO(0x81e, "tx_512to1023b")}, ++ {STAT_INFO(0x820, "tx_1024to1518b")}, ++ {STAT_INFO(0x822, "tx_1519tomaxb")}, ++ {STAT_INFO(0x824, "tx_oversize")}, ++ {STAT_INFO(0x836, "tx_st")}, ++ {STAT_INFO(0x826, "tx_mcast_data_ok")}, ++ {STAT_INFO(0x828, "tx_bcast_data_ok")}, ++ {STAT_INFO(0x82a, "tx_ucast_data_ok")}, ++ {STAT_INFO(0x82c, "tx_mcast_ctrl_ok")}, ++ {STAT_INFO(0x82e, "tx_bcast_ctrl_ok")}, ++ {STAT_INFO(0x830, "tx_ucast_ctrl_ok")}, ++ {STAT_INFO(0x832, "tx_pause")}, ++ {STAT_INFO(0x860, "tx_payload_octets_ok")}, ++ {STAT_INFO(0x862, "tx_frame_octets_ok")}, ++ ++ /* rx statistics */ ++ {STAT_INFO(0x900, "rx_fragments")}, ++ {STAT_INFO(0x902, "rx_jabbers")}, ++ {STAT_INFO(0x904, "rx_crcerr")}, ++ {STAT_INFO(0x906, "rx_crcerr_sizeok")}, ++ {STAT_INFO(0x908, "rx_mcast_data_err")}, ++ {STAT_INFO(0x90a, "rx_bcast_data_err")}, ++ {STAT_INFO(0x90c, "rx_ucast_data_err")}, ++ {STAT_INFO(0x90e, "rx_mcast_ctrl_err")}, ++ {STAT_INFO(0x910, "rx_bcast_ctrl_err")}, ++ {STAT_INFO(0x912, "rx_ucast_ctrl_err")}, ++ {STAT_INFO(0x914, "rx_pause_err")}, ++ {STAT_INFO(0x916, "rx_64b")}, ++ {STAT_INFO(0x918, "rx_65to127b")}, ++ {STAT_INFO(0x91a, "rx_128to255b")}, ++ {STAT_INFO(0x91c, "rx_256to511b")}, ++ {STAT_INFO(0x91e, "rx_512to1023b")}, ++ {STAT_INFO(0x920, "rx_1024to1518b")}, ++ {STAT_INFO(0x922, "rx_1519tomaxb")}, ++ {STAT_INFO(0x924, "rx_oversize")}, ++ {STAT_INFO(0x936, "rx_st")}, ++ {STAT_INFO(0x926, "rx_mcast_data_ok")}, ++ {STAT_INFO(0x928, "rx_bcast_data_ok")}, ++ {STAT_INFO(0x92a, "rx_ucast_data_ok")}, ++ {STAT_INFO(0x92c, "rx_mcast_ctrl_ok")}, ++ {STAT_INFO(0x92e, "rx_bcast_ctrl_ok")}, ++ {STAT_INFO(0x930, "rx_ucast_ctrl_ok")}, ++ {STAT_INFO(0x932, "rx_pause")}, ++ {STAT_INFO(0x960, "rx_payload_octets_ok")}, ++ {STAT_INFO(0x962, "rx_frame_octets_ok")} ++}; ++ ++static const struct s10hssi_ops_params intel_ll_100g_params = { ++ .stats = stats_100g, ++ .num_stats = ARRAY_SIZE(stats_100g), ++ .tx_clr_off = ILL_100G_TX_STATS_CLR, ++ .rx_clr_off = ILL_100G_RX_STATS_CLR, ++ .lpbk_off = ILL_100G_LPBK_OFF, ++ .lpbk_en_val = ILL_100G_LPBK_EN_VAL, ++}; ++ ++static const struct regmap_range regmap_range_100g[] = { ++ regmap_reg_range(ILL_100G_PHY_BASE_OFF, ILL_100G_PHY_MAX_OFF), ++ regmap_reg_range(ILL_100G_BASE_OFF, ILL_100G_MAX_OFF), ++}; ++ ++static const struct regmap_access_table access_table_100g = { ++ .yes_ranges = regmap_range_100g, ++ .n_yes_ranges = ARRAY_SIZE(regmap_range_100g), ++}; ++ ++static void s10hssi_init_netdev(struct net_device *netdev) ++{ ++ netdev->ethtool_ops = ðtool_ops; ++ netdev->netdev_ops = &netdev_ops; ++ netdev->features = 0; ++ netdev->hw_features |= NETIF_F_LOOPBACK; ++ netdev->hard_header_len = 0; ++ netdev->priv_flags |= IFF_NO_QUEUE; ++ ++ netdev->needs_free_netdev = true; ++ ++ ether_setup(netdev); ++} ++ ++static int s10hssi_mac_probe(struct dfl_device *dfl_dev) ++{ ++ struct device *dev = &dfl_dev->dev; ++ struct regmap_config cfg = {0}; ++ struct s10hssi_netdata *npriv; ++ struct s10hssi_drvdata *priv; ++ struct regmap *regmap; ++ void __iomem *base; ++ u64 val, pcs_speed; ++ u32 flags; ++ int ret; ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ ++ if (!priv) ++ return -ENOMEM; ++ ++ dev_set_drvdata(dev, priv); ++ ++ base = devm_ioremap_resource(dev, &dfl_dev->mmio_res); ++ ++ if (!base) ++ return -ENOMEM; ++ ++ priv->netdev = alloc_netdev(sizeof(struct s10hssi_netdata), ++ "s10hssi%d", NET_NAME_UNKNOWN, ++ s10hssi_init_netdev); ++ ++ if (!priv->netdev) ++ return -ENOMEM; ++ ++ npriv = netdev_priv(priv->netdev); ++ ++ npriv->dfl_dev = dfl_dev; ++ ++ val = readq(base + CAPABILITY_OFF); ++ ++ dev_info(dev, "%s capability register 0x%llx\n", __func__, val); ++ ++ pcs_speed = FIELD_GET(CAP_CONTAINS_PCS, val); ++ ++ if (pcs_speed == CAP_RATE_10G) { ++ dev_info(dev, "%s found 10G\n", __func__); ++ npriv->ops_params = &s10hssi_params; ++ cfg.wr_table = &access_table_10g; ++ cfg.rd_table = &access_table_10g; ++ cfg.max_register = PHY_BASE_OFF + PHY_MAX_OFF; ++ } else if (pcs_speed == CAP_RATE_100G) { ++ dev_info(dev, "%s found 100G\n", __func__); ++ npriv->ops_params = &intel_ll_100g_params; ++ cfg.wr_table = &access_table_100g; ++ cfg.rd_table = &access_table_100g; ++ cfg.max_register = ILL_100G_MAX_OFF; ++ } else { ++ dev_err(dev, "%s unsupported pcs data rate 0x%llx\n", ++ __func__, pcs_speed); ++ return -EINVAL; ++ } ++ ++ cfg.reg_bits = 32; ++ cfg.val_bits = 32; ++ ++ regmap = devm_regmap_init_indirect_register(dev, base + MB_BASE_OFF, &cfg); ++ ++ if (!regmap) ++ return -ENOMEM; ++ ++ npriv->regmap = regmap; ++ ++ SET_NETDEV_DEV(priv->netdev, &dfl_dev->dev); ++ ++ flags = ETH_RESET_MGMT; ++ ++ ret = ethtool_reset(priv->netdev, &flags); ++ ++ if (ret) ++ dev_err(&dfl_dev->dev, "failed to reset MGMT %s: %d", ++ priv->netdev->name, ret); ++ ++ ret = register_netdev(priv->netdev); ++ ++ if (ret) ++ dev_err(&dfl_dev->dev, "failed to register %s: %d", ++ priv->netdev->name, ret); ++ ++ return ret; ++} ++ ++static void s10hssi_mac_remove(struct dfl_device *dfl_dev) ++{ ++ struct s10hssi_drvdata *priv = dev_get_drvdata(&dfl_dev->dev); ++ ++ unregister_netdev(priv->netdev); ++} ++ ++#define FME_FEATURE_ID_LL_10G_MAC 0xf ++ ++static const struct dfl_device_id s10hssi_mac_ids[] = { ++ { FME_ID, FME_FEATURE_ID_LL_10G_MAC }, ++ { } ++}; ++ ++static struct dfl_driver s10hssi_mac_driver = { ++ .drv = { ++ .name = "s10hssi", ++ }, ++ .id_table = s10hssi_mac_ids, ++ .probe = s10hssi_mac_probe, ++ .remove = s10hssi_mac_remove, ++}; ++ ++module_dfl_driver(s10hssi_mac_driver); ++MODULE_DEVICE_TABLE(dfl, s10hssi_mac_ids); ++MODULE_DESCRIPTION("Network Device Driver for Intel(R) Startix10 HSSI"); ++MODULE_AUTHOR("Intel Corporation"); ++MODULE_LICENSE("GPL v2"); diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0056-net-ethernet-intel-add-polling-of-link-status.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0056-net-ethernet-intel-add-polling-of-link-status.patch new file mode 100644 index 0000000..c98d631 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0056-net-ethernet-intel-add-polling-of-link-status.patch @@ -0,0 +1,186 @@ +From f3cce3181fbb032de938cac2b010d6c1517b7892 Mon Sep 17 00:00:00 2001 +From: Matthew Gerlach +Date: Thu, 17 Dec 2020 12:14:00 -0800 +Subject: [PATCH] net: ethernet: intel: add polling of link status +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add polling for the link status in the phy and update +the netdev object accordingly. + +Signed-off-by: Matthew Gerlach +Based-on: Martin Hundebøll +--- + drivers/net/ethernet/intel/s10hssi.c | 87 ++++++++++++++++++++++++++-- + 1 file changed, 82 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/ethernet/intel/s10hssi.c b/drivers/net/ethernet/intel/s10hssi.c +index ee97a08e74b6..f0fa9ad3b5df 100644 +--- a/drivers/net/ethernet/intel/s10hssi.c ++++ b/drivers/net/ethernet/intel/s10hssi.c +@@ -31,6 +31,9 @@ + #define MB_BASE_OFF 0x28 + + #define PHY_BASE_OFF 0x2000 ++#define PHY_RX_LOCKED_OFF 0x480 ++#define PHY_RX_LOCKED_DATA (BIT(0) | BIT(1)) ++ + #define PHY_RX_SER_LOOP_BACK 0x4e1 + #define PHY_MAX_OFF 0x541 + +@@ -45,15 +48,29 @@ + #define ILL_100G_RX_STATS_CLR 0x945 + + #define ILL_100G_PHY_BASE_OFF 0x300 +-#define ILL_100G_PHY_MAX_OFF 0x3ff ++#define ILL_100G_RX_PCS_ALN_OFF 0x326 ++#define ILL_100G_RX_RCS_ALIGNED BIT(0) ++ + #define ILL_100G_LPBK_OFF 0x313 + #define ILL_100G_LPBK_EN_VAL 0xffff + ++#define ILL_100G_PHY_MAX_OFF 0x3ff ++ ++#define ILL_100G_TX_FEC_OFF 0xc00 ++#define ILL_100G_TX_FEC_MAX_OFF 0xc07 ++ ++#define ILL_100G_RX_FEC_OFF 0xd00 ++#define ILL_100G_RX_FEC_ST 0xd06 ++#define ILL_100G_RX_FEC_ST_ALN BIT(4) ++#define ILL_100G_RX_FEC_MAX_OFF 0xd08 ++ + #define STATS_CLR_INT_US 1 + #define STATS_CLR_INT_TIMEOUT_US 1000 + + struct s10hssi_drvdata { + struct net_device *netdev; ++ struct timer_list poll_timer; ++ struct work_struct poll_workq; + }; + + struct s10hssi_ops_params { +@@ -63,14 +80,47 @@ struct s10hssi_ops_params { + u32 rx_clr_off; + u32 lpbk_off; + u32 lpbk_en_val; ++ u32 link_off; ++ u32 link_mask; + }; + + struct s10hssi_netdata { + struct dfl_device *dfl_dev; + struct regmap *regmap; +- const struct s10hssi_ops_params *ops_params; ++ struct s10hssi_ops_params *ops_params; ++ u32 link_status; + }; + ++static void poll_work(struct work_struct *arg) ++{ ++ struct s10hssi_netdata *npriv; ++ struct s10hssi_drvdata *priv; ++ u32 link_status = 0; ++ ++ priv = container_of(arg, struct s10hssi_drvdata, poll_workq); ++ npriv = netdev_priv(priv->netdev); ++ ++ regmap_read(npriv->regmap, npriv->ops_params->link_off, &link_status); ++ link_status &= npriv->ops_params->link_mask; ++ if (link_status != npriv->link_status) { ++ npriv->link_status = link_status; ++ dev_dbg(&priv->netdev->dev, "link state: %u\n", link_status); ++ ++ if (link_status == npriv->ops_params->link_mask) ++ netif_carrier_on(priv->netdev); ++ else ++ netif_carrier_off(priv->netdev); ++ } ++} ++ ++static void poll_timerf(struct timer_list *timer_arg) ++{ ++ struct s10hssi_drvdata *priv = from_timer(priv, timer_arg, poll_timer); ++ ++ schedule_work(&priv->poll_workq); ++ mod_timer(&priv->poll_timer, jiffies + msecs_to_jiffies(1000)); ++} ++ + static int netdev_change_mtu(struct net_device *netdev, int new_mtu) + { + netdev->mtu = new_mtu; +@@ -309,6 +359,8 @@ static const struct s10hssi_ops_params s10hssi_params = { + .rx_clr_off = ILL_10G_RX_STATS_CLR, + .lpbk_off = PHY_BASE_OFF + PHY_RX_SER_LOOP_BACK, + .lpbk_en_val = 1, ++ .link_off = PHY_BASE_OFF + PHY_RX_LOCKED_OFF, ++ .link_mask = PHY_RX_LOCKED_DATA, + }; + + static const struct regmap_range regmap_range_10g[] = { +@@ -397,6 +449,8 @@ static const struct s10hssi_ops_params intel_ll_100g_params = { + static const struct regmap_range regmap_range_100g[] = { + regmap_reg_range(ILL_100G_PHY_BASE_OFF, ILL_100G_PHY_MAX_OFF), + regmap_reg_range(ILL_100G_BASE_OFF, ILL_100G_MAX_OFF), ++ regmap_reg_range(ILL_100G_TX_FEC_OFF, ILL_100G_TX_FEC_MAX_OFF), ++ regmap_reg_range(ILL_100G_RX_FEC_OFF, ILL_100G_RX_FEC_MAX_OFF), + }; + + static const struct regmap_access_table access_table_100g = { +@@ -461,16 +515,30 @@ static int s10hssi_mac_probe(struct dfl_device *dfl_dev) + + if (pcs_speed == CAP_RATE_10G) { + dev_info(dev, "%s found 10G\n", __func__); +- npriv->ops_params = &s10hssi_params; ++ npriv->ops_params = (struct s10hssi_ops_params *)&s10hssi_params; + cfg.wr_table = &access_table_10g; + cfg.rd_table = &access_table_10g; + cfg.max_register = PHY_BASE_OFF + PHY_MAX_OFF; + } else if (pcs_speed == CAP_RATE_100G) { + dev_info(dev, "%s found 100G\n", __func__); +- npriv->ops_params = &intel_ll_100g_params; ++ npriv->ops_params = devm_kmalloc(dev, sizeof(*npriv->ops_params), GFP_KERNEL); ++ if (!npriv->ops_params) ++ return -ENOMEM; ++ ++ *npriv->ops_params = intel_ll_100g_params; ++ if (FIELD_GET(CAP_CONTAINS_FEC, val)) { ++ dev_info(dev, "%s contains FEC\n", __func__); ++ npriv->ops_params->link_off = ILL_100G_RX_FEC_ST; ++ npriv->ops_params->link_mask = ILL_100G_RX_FEC_ST_ALN; ++ } else { ++ dev_info(dev, "%s no FEC\n", __func__); ++ npriv->ops_params->link_off = ILL_100G_RX_PCS_ALN_OFF; ++ npriv->ops_params->link_mask = ILL_100G_RX_RCS_ALIGNED; ++ } ++ + cfg.wr_table = &access_table_100g; + cfg.rd_table = &access_table_100g; +- cfg.max_register = ILL_100G_MAX_OFF; ++ cfg.max_register = ILL_100G_RX_FEC_MAX_OFF; + } else { + dev_err(dev, "%s unsupported pcs data rate 0x%llx\n", + __func__, pcs_speed); +@@ -503,6 +571,13 @@ static int s10hssi_mac_probe(struct dfl_device *dfl_dev) + dev_err(&dfl_dev->dev, "failed to register %s: %d", + priv->netdev->name, ret); + ++ dev_info(&dfl_dev->dev, "setting carrier off\n"); ++ netif_carrier_off(priv->netdev); ++ ++ INIT_WORK(&priv->poll_workq, poll_work); ++ timer_setup(&priv->poll_timer, poll_timerf, 0); ++ mod_timer(&priv->poll_timer, jiffies + msecs_to_jiffies(1000)); ++ + return ret; + } + +@@ -511,6 +586,8 @@ static void s10hssi_mac_remove(struct dfl_device *dfl_dev) + struct s10hssi_drvdata *priv = dev_get_drvdata(&dfl_dev->dev); + + unregister_netdev(priv->netdev); ++ ++ del_timer_sync(&priv->poll_timer); + } + + #define FME_FEATURE_ID_LL_10G_MAC 0xf diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0057-net-ethernet-silicom-add-n5010-phy-driver.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0057-net-ethernet-silicom-add-n5010-phy-driver.patch new file mode 100644 index 0000000..8e5edd4 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0057-net-ethernet-silicom-add-n5010-phy-driver.patch @@ -0,0 +1,392 @@ +From 17912eef51fae71ad1ae40c3b449e451c5be597d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Martin=20Hundeb=C3=B8ll?= +Date: Mon, 1 Feb 2021 13:20:47 +0100 +Subject: [PATCH] net: ethernet: silicom: add n5010-phy driver +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The n5010 PAC uses its board management controller to some aspects of +the line-side handling. Add a driver to setup a fixed link phy for the +n5010-hssi network driver. + +Co-developed-by: Martin Hundebøll +Signed-off-by: Martin Hundebøll +Signed-off-by: Ilpo Järvinen +--- + MAINTAINERS | 6 + + drivers/mfd/intel-m10-bmc-spi.c | 1 + + drivers/net/ethernet/Kconfig | 1 + + drivers/net/ethernet/Makefile | 1 + + drivers/net/ethernet/silicom/Kconfig | 27 +++ + drivers/net/ethernet/silicom/Makefile | 6 + + drivers/net/ethernet/silicom/n5010-phy.c | 236 +++++++++++++++++++++++ + drivers/net/ethernet/silicom/n5010-phy.h | 16 ++ + 8 files changed, 294 insertions(+) + create mode 100644 drivers/net/ethernet/silicom/Kconfig + create mode 100644 drivers/net/ethernet/silicom/Makefile + create mode 100644 drivers/net/ethernet/silicom/n5010-phy.c + create mode 100644 drivers/net/ethernet/silicom/n5010-phy.h + +diff --git a/MAINTAINERS b/MAINTAINERS +index 20dc4f186bef..6c16d2f92dd9 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -19615,6 +19615,12 @@ S: Maintained + F: drivers/input/touchscreen/silead.c + F: drivers/platform/x86/touchscreen_dmi.c + ++SILICOM PAC N5010 DRIVER ++M: Esa Leskinen ++L: netdev@vger.kernel.org ++S: Maintained ++F: drivers/net/ethernet/silicom/n5010-phy.c ++ + SILICON LABS WIRELESS DRIVERS (for WFxxx series) + M: Jérôme Pouiller + S: Supported +diff --git a/drivers/mfd/intel-m10-bmc-spi.c b/drivers/mfd/intel-m10-bmc-spi.c +index b7904145f518..29060f10edc4 100644 +--- a/drivers/mfd/intel-m10-bmc-spi.c ++++ b/drivers/mfd/intel-m10-bmc-spi.c +@@ -134,6 +134,7 @@ static const struct regmap_range m10bmc_n3000_fw_handshake_regs[] = { + static struct mfd_cell m10bmc_n5010_subdevs[] = { + { .name = "n5010bmc-hwmon" }, + { .name = "n5010bmc-sec-update" }, ++ { .name = "n5010bmc-phy" }, + }; + + static struct mfd_cell m10bmc_n5014_subdevs[] = { +diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig +index 5a274b99f299..95532ce0b276 100644 +--- a/drivers/net/ethernet/Kconfig ++++ b/drivers/net/ethernet/Kconfig +@@ -174,6 +174,7 @@ source "drivers/net/ethernet/samsung/Kconfig" + source "drivers/net/ethernet/seeq/Kconfig" + source "drivers/net/ethernet/sgi/Kconfig" + source "drivers/net/ethernet/silan/Kconfig" ++source "drivers/net/ethernet/silicom/Kconfig" + source "drivers/net/ethernet/sis/Kconfig" + source "drivers/net/ethernet/sfc/Kconfig" + source "drivers/net/ethernet/smsc/Kconfig" +diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile +index 0d872d4efcd1..50aa464460e9 100644 +--- a/drivers/net/ethernet/Makefile ++++ b/drivers/net/ethernet/Makefile +@@ -84,6 +84,7 @@ obj-$(CONFIG_NET_VENDOR_ROCKER) += rocker/ + obj-$(CONFIG_NET_VENDOR_SAMSUNG) += samsung/ + obj-$(CONFIG_NET_VENDOR_SEEQ) += seeq/ + obj-$(CONFIG_NET_VENDOR_SILAN) += silan/ ++obj-$(CONFIG_NET_VENDOR_SILICOM) += silicom/ + obj-$(CONFIG_NET_VENDOR_SIS) += sis/ + obj-$(CONFIG_NET_VENDOR_SOLARFLARE) += sfc/ + obj-$(CONFIG_NET_VENDOR_SGI) += sgi/ +diff --git a/drivers/net/ethernet/silicom/Kconfig b/drivers/net/ethernet/silicom/Kconfig +new file mode 100644 +index 000000000000..e12a6901ceee +--- /dev/null ++++ b/drivers/net/ethernet/silicom/Kconfig +@@ -0,0 +1,27 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++# ++# Silicom network device configuration ++# ++ ++config NET_VENDOR_SILICOM ++ bool "Silicom devices" ++ default y ++ help ++ If you have a network (Ethernet) card belonging to this class, say Y. ++ ++ Note that the answer to this question doesn't directly affect the ++ kernel: saying N will just cause the configurator to skip all ++ the questions about Silicom cards. If you say Y, you will be asked for ++ your specific card in the following questions. ++ ++if NET_VENDOR_SILICOM ++ ++config N5010_PHY ++ tristate "Fixed Phy Driver for Silicom PAC N5010" ++ depends on MFD_INTEL_M10_BMC_CORE && FIXED_PHY ++ help ++ The n5010 card consists of a primary FPGA running the network controller, ++ and a side-fpga running the board management controller (bmc). This driver ++ reads status bits and controls link LEDs via the bmc. ++ ++endif # NET_VENDOR_SILICOM +diff --git a/drivers/net/ethernet/silicom/Makefile b/drivers/net/ethernet/silicom/Makefile +new file mode 100644 +index 000000000000..c51cd4b4c517 +--- /dev/null ++++ b/drivers/net/ethernet/silicom/Makefile +@@ -0,0 +1,6 @@ ++# SPDX-License-Identifier: GPL-2.0 ++# ++# Makefile for the Silicom network device drivers. ++# ++ ++obj-$(CONFIG_N5010_PHY) += n5010-phy.o +diff --git a/drivers/net/ethernet/silicom/n5010-phy.c b/drivers/net/ethernet/silicom/n5010-phy.c +new file mode 100644 +index 000000000000..c25b9eddc8d4 +--- /dev/null ++++ b/drivers/net/ethernet/silicom/n5010-phy.c +@@ -0,0 +1,236 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Intel Max10 BMC Lightning Creek phy Driver ++ * ++ * Copyright (C) 2020 Silicom Denmark A/S. All rights reserved. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "n5010-phy.h" ++ ++#define N5010_PHY_CSR_0 0x40c ++#define N5010_PHY_CSR_1 0x410 ++ ++#define N5010_PHY_ABSENT_0 BIT(7) ++#define N5010_PHY_ABSENT_1 BIT(23) ++ ++#define N5010_PHY_LED_0 GENMASK(5, 3) ++#define N5010_PHY_LED_1 GENMASK(21, 19) ++ ++struct n5010_phy { ++ struct intel_m10bmc *m10bmc; ++}; ++ ++struct n5010_port { ++ u64 num; ++ bool sfp_in; ++ struct n5010_phy *priv; ++ struct phy_device *phy; ++ bool (*get_link)(struct net_device *netdev); ++}; ++ ++static struct fixed_phy_status n5010_phy_status = { ++ .link = 0, ++ .speed = 1000, ++ .duplex = 1, ++}; ++ ++static int n5010_phy_sfp_status(struct n5010_port *port) ++{ ++ unsigned int offset, bit, val; ++ int ret; ++ ++ switch (port->num) { ++ case 0: ++ offset = N5010_PHY_CSR_1; ++ bit = N5010_PHY_ABSENT_0; ++ break; ++ case 1: ++ offset = N5010_PHY_CSR_1; ++ bit = N5010_PHY_ABSENT_1; ++ break; ++ case 2: ++ offset = N5010_PHY_CSR_0; ++ bit = N5010_PHY_ABSENT_0; ++ break; ++ case 3: ++ offset = N5010_PHY_CSR_0; ++ bit = N5010_PHY_ABSENT_1; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ ret = m10bmc_sys_read(port->priv->m10bmc, offset, &val); ++ if (ret) ++ return ret; ++ ++ port->sfp_in = !(val & bit); ++ ++ return 0; ++} ++ ++static int n5010_phy_set_led(struct n5010_port *port, bool link) ++{ ++ unsigned int offset, mask, val; ++ ++ switch (port->num) { ++ case 0: ++ offset = N5010_PHY_CSR_1; ++ mask = N5010_PHY_LED_0; ++ break; ++ case 1: ++ offset = N5010_PHY_CSR_1; ++ mask = N5010_PHY_LED_1; ++ break; ++ case 2: ++ offset = N5010_PHY_CSR_0; ++ mask = N5010_PHY_LED_0; ++ break; ++ case 3: ++ offset = N5010_PHY_CSR_0; ++ mask = N5010_PHY_LED_1; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ val = link ? mask : 0; ++ ++ return m10bmc_sys_update_bits(port->priv->m10bmc, offset, mask, val); ++} ++ ++static void n5010_phy_adjust_link(struct net_device *netdev) ++{ ++ struct n5010_port *port = netdev->phydev->priv; ++ bool link = netdev->phydev->link; ++ int err; ++ ++ netdev_info(netdev, "link: %i\n", link); ++ ++ err = n5010_phy_set_led(port, link); ++ if (err) ++ netdev_info(netdev, "failed to set led: %i\n", err); ++} ++ ++static int n5010_phy_update_link(struct net_device *netdev, ++ struct fixed_phy_status *status) ++{ ++ struct n5010_port *port = netdev->phydev->priv; ++ bool sfp_in = port->sfp_in; ++ ++ n5010_phy_sfp_status(port); ++ status->link = port->get_link(netdev); ++ ++ if (sfp_in != port->sfp_in) ++ netdev_info(netdev, "sfp: %s\n", port->sfp_in ? "in" : "out"); ++ ++ return 0; ++} ++ ++int n5010_phy_module_info(struct net_device *netdev) ++{ ++ struct n5010_port *port = netdev->phydev->priv; ++ ++ return port->sfp_in ? -ENODATA : -ENODEV; ++} ++EXPORT_SYMBOL(n5010_phy_module_info); ++ ++int n5010_phy_attach(struct device *dev, struct net_device *netdev, ++ bool (*get_link)(struct net_device *), u64 port_num) ++{ ++ struct n5010_phy *priv = dev_get_drvdata(dev); ++ struct phy_device *phy; ++ struct n5010_port *port; ++ int ret; ++ ++ phy = fixed_phy_register(PHY_POLL, &n5010_phy_status, NULL); ++ if (IS_ERR(phy)) ++ return PTR_ERR(phy); ++ ++ port = devm_kzalloc(&phy->mdio.dev, sizeof(*port), GFP_KERNEL); ++ if (!port) ++ return -ENOMEM; ++ ++ port->num = port_num; ++ port->priv = priv; ++ port->phy = phy; ++ port->get_link = get_link; ++ ++ phy->priv = port; ++ ++ ret = phy_connect_direct(netdev, phy, &n5010_phy_adjust_link, ++ PHY_INTERFACE_MODE_NA); ++ if (ret) ++ goto err_deregister; ++ ++ fixed_phy_set_link_update(phy, n5010_phy_update_link); ++ fixed_phy_change_carrier(netdev, false); ++ n5010_phy_sfp_status(port); ++ ++ netdev_info(netdev, "sfp: %s\n", port->sfp_in ? "in" : "out"); ++ ++ return 0; ++ ++err_deregister: ++ fixed_phy_unregister(phy); ++ ++ return ret; ++} ++EXPORT_SYMBOL(n5010_phy_attach); ++ ++int n5010_phy_detach(struct net_device *netdev) ++{ ++ struct phy_device *phy = netdev->phydev; ++ ++ phy_detach(phy); ++ fixed_phy_unregister(phy); ++ phy_device_free(phy); ++ ++ return 0; ++} ++EXPORT_SYMBOL(n5010_phy_detach); ++ ++static int n5010_phy_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct n5010_phy *priv; ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ dev_set_drvdata(dev, priv); ++ priv->m10bmc = dev_get_drvdata(dev->parent); ++ ++ return 0; ++} ++ ++static const struct platform_device_id n5010_phy_ids[] = { ++ { ++ .name = "n5010bmc-phy", ++ }, ++ { } ++}; ++ ++static struct platform_driver n5010_phy_driver = { ++ .probe = n5010_phy_probe, ++ .driver = { ++ .name = "n5010bmc-phy", ++ }, ++ .id_table = n5010_phy_ids, ++}; ++module_platform_driver(n5010_phy_driver); ++ ++MODULE_DEVICE_TABLE(platform, n5010_phy_ids); ++MODULE_AUTHOR("Intel Corporation"); ++MODULE_DESCRIPTION("Intel MAX10 BMC phy driver for n5010"); ++MODULE_LICENSE("GPL v2"); ++MODULE_IMPORT_NS(INTEL_M10_BMC_CORE); +diff --git a/drivers/net/ethernet/silicom/n5010-phy.h b/drivers/net/ethernet/silicom/n5010-phy.h +new file mode 100644 +index 000000000000..9d466f88fb1a +--- /dev/null ++++ b/drivers/net/ethernet/silicom/n5010-phy.h +@@ -0,0 +1,16 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Header File for DFL driver and device API ++ * ++ * Copyright (C) 2020 Silicom Denmark A/S. All rights reserved. ++ */ ++ ++#ifndef __SILICOM_N5010_PHY_H ++#define __SILICOM_N5010_PHY_H ++ ++int n5010_phy_module_info(struct net_device *netdev); ++int n5010_phy_attach(struct device *dev, struct net_device *netdev, ++ bool (*update)(struct net_device *netdev), u64 port_num); ++int n5010_phy_detach(struct net_device *netdev); ++ ++#endif diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0058-net-ethernet-silicom-add-n5010-hssi-driver.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0058-net-ethernet-silicom-add-n5010-hssi-driver.patch new file mode 100644 index 0000000..afb963f --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0058-net-ethernet-silicom-add-n5010-hssi-driver.patch @@ -0,0 +1,677 @@ +From c706060700e1afc220a750ea60858177c18843ff Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Martin=20Hundeb=C3=B8ll?= +Date: Mon, 1 Feb 2021 13:20:47 +0100 +Subject: [PATCH] net: ethernet: silicom: add n5010-hssi driver +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add Silicom Lightning Creek high speed driver. + +Signed-off-by: Martin Hundebøll +--- + MAINTAINERS | 1 + + drivers/net/ethernet/silicom/Kconfig | 10 + + drivers/net/ethernet/silicom/Makefile | 1 + + drivers/net/ethernet/silicom/n5010-hssi.c | 612 ++++++++++++++++++++++ + 4 files changed, 624 insertions(+) + create mode 100644 drivers/net/ethernet/silicom/n5010-hssi.c + +diff --git a/MAINTAINERS b/MAINTAINERS +index 6c16d2f92dd9..087367988378 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -19619,6 +19619,7 @@ SILICOM PAC N5010 DRIVER + M: Esa Leskinen + L: netdev@vger.kernel.org + S: Maintained ++F: drivers/net/ethernet/silicom/n5010-hssi.c + F: drivers/net/ethernet/silicom/n5010-phy.c + + SILICON LABS WIRELESS DRIVERS (for WFxxx series) +diff --git a/drivers/net/ethernet/silicom/Kconfig b/drivers/net/ethernet/silicom/Kconfig +index e12a6901ceee..204e1d97e15a 100644 +--- a/drivers/net/ethernet/silicom/Kconfig ++++ b/drivers/net/ethernet/silicom/Kconfig +@@ -24,4 +24,14 @@ config N5010_PHY + and a side-fpga running the board management controller (bmc). This driver + reads status bits and controls link LEDs via the bmc. + ++config N5010_HSSI ++ tristate "Control Plane Driver for Silicom PAC N5010 HSSI" ++ select N5010_PHY ++ select REGMAP_INDIRECT_REGISTER ++ help ++ This driver provides control plane support for the Silicom N5010 ++ Programmable Acceleration Card. This driver adds network interfaces ++ for the line-side QFSP modules, supporting various control/status ++ operations. ++ + endif # NET_VENDOR_SILICOM +diff --git a/drivers/net/ethernet/silicom/Makefile b/drivers/net/ethernet/silicom/Makefile +index c51cd4b4c517..e613043ae1c1 100644 +--- a/drivers/net/ethernet/silicom/Makefile ++++ b/drivers/net/ethernet/silicom/Makefile +@@ -4,3 +4,4 @@ + # + + obj-$(CONFIG_N5010_PHY) += n5010-phy.o ++obj-$(CONFIG_N5010_HSSI) += n5010-hssi.o +diff --git a/drivers/net/ethernet/silicom/n5010-hssi.c b/drivers/net/ethernet/silicom/n5010-hssi.c +new file mode 100644 +index 000000000000..654e758e5048 +--- /dev/null ++++ b/drivers/net/ethernet/silicom/n5010-hssi.c +@@ -0,0 +1,612 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++/* Silicom(R) Low Latency 100G Network Driver ++ * ++ * Copyright (C) 2020 Silicom Denmark. All rights reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "n5010-phy.h" ++ ++#define CAPABILITY_OFFSET 0x08 ++#define CAP_AVAILABLE_RATES GENMASK_ULL(7, 0) ++#define CAP_CONTAINS_PCS GENMASK_ULL(15, 8) ++#define CAP_CONTAINS_FEC GENMASK_ULL(23, 16) ++#define CAP_PORT_CNT GENMASK_ULL(43, 40) ++#define CAP_RATE_1G BIT_ULL(0) ++#define CAP_RATE_10G BIT_ULL(1) ++#define CAP_RATE_25G BIT_ULL(2) ++#define CAP_RATE_40G BIT_ULL(3) ++#define CAP_RATE_50G BIT_ULL(4) ++#define CAP_RATE_100G BIT_ULL(5) ++#define CAP_RATE_200G BIT_ULL(6) ++#define CAP_RATE_400G BIT_ULL(7) ++ ++#define MB_MAC_OFFSET 0x28 ++#define MB_FEC_OFFSET 0x68 ++#define MB_PHY_OFFSET 0xa8 ++#define MB_PORT_SIZE 0x10 ++ ++#define PHY_BASE_OFF 0x2000 ++#define PHY_RX_SER_LOOP_BACK 0x4e1 ++ ++#define FEC_RX_STATUS 0x180 ++#define FEC_RX_STATUS_LINK 0x0ULL ++#define FEC_RX_STATUS_LINK_NO 0x3ULL ++ ++#define MAC_TX_SRC_ADDR_LO 0x40c ++#define MAC_TX_SRC_ADDR_HI 0x40d ++#define MAC_RX_MTU 0x506 ++#define MAC_MAX_MTU 9600 ++ ++#define ILL_100G_TX_STATS_CLR 0x845 ++#define ILL_100G_RX_STATS_CLR 0x945 ++#define ILL_100G_LPBK_OFF 0x313 ++#define ILL_100G_LPBK_EN_VAL 0xffff ++ ++#define STATS_CLR_INT_US 1 ++#define STATS_CLR_INT_TIMEOUT_US 1000 ++ ++struct n5010_hssi_ops_params { ++ struct stat_info *stats; ++ u32 num_stats; ++ u32 tx_clr_off; ++ u32 rx_clr_off; ++}; ++ ++struct n5010_hssi_regmaps { ++ struct regmap *regmap; ++}; ++ ++struct n5010_hssi_netdata { ++ struct dfl_device *dfl_dev; ++ struct regmap *regmap_mac; ++ struct regmap *regmap_fec; ++ struct regmap *regmap_phy; ++ u32 link_status; ++ const struct n5010_hssi_ops_params *ops_params; ++}; ++ ++struct n5010_hssi_drvdata { ++ struct dfl_device *dfl_dev; ++ void __iomem *base; ++ u64 port_cnt; ++ struct net_device *netdev[]; ++}; ++ ++static bool n5010_hssi_update_link(struct net_device *netdev) ++{ ++ struct n5010_hssi_netdata *npriv = netdev_priv(netdev); ++ u32 link_status = FEC_RX_STATUS_LINK_NO; ++ ++ regmap_read(npriv->regmap_fec, FEC_RX_STATUS, &link_status); ++ ++ return link_status == FEC_RX_STATUS_LINK; ++} ++ ++static int netdev_open(struct net_device *netdev) ++{ ++ if (netdev->phydev) ++ phy_start(netdev->phydev); ++ ++ return 0; ++} ++ ++static int netdev_stop(struct net_device *netdev) ++{ ++ if (netdev->phydev) ++ phy_stop(netdev->phydev); ++ ++ return 0; ++} ++ ++static int netdev_change_mtu(struct net_device *netdev, int new_mtu) ++{ ++ struct n5010_hssi_netdata *npriv = netdev_priv(netdev); ++ ++ netdev->mtu = new_mtu; ++ ++ return regmap_write(npriv->regmap_mac, MAC_RX_MTU, new_mtu); ++} ++ ++static int netdev_set_features(struct net_device *netdev, ++ netdev_features_t features) ++{ ++ return 0; ++} ++ ++static int netdev_set_mac_address(struct net_device *netdev, void *p) ++{ ++ struct n5010_hssi_netdata *npriv = netdev_priv(netdev); ++ struct sockaddr *addr = p; ++ u32 mac_part1, mac_part2; ++ int ret; ++ ++ memcpy((void *)netdev->dev_addr, addr->sa_data, ETH_ALEN); ++ ++ mac_part1 = (addr->sa_data[0] << 8) | addr->sa_data[1]; ++ mac_part2 = (addr->sa_data[2] << 24) | (addr->sa_data[3] << 16) | ++ (addr->sa_data[4] << 8) | addr->sa_data[5]; ++ ++ ret = regmap_write(npriv->regmap_mac, MAC_TX_SRC_ADDR_HI, mac_part1); ++ if (ret) ++ return ret; ++ ++ return regmap_write(npriv->regmap_mac, MAC_TX_SRC_ADDR_LO, mac_part2); ++} ++ ++static netdev_tx_t netdev_xmit(struct sk_buff *skb, struct net_device *netdev) ++{ ++ kfree_skb(skb); ++ ++ return NETDEV_TX_OK; ++} ++ ++static const struct net_device_ops netdev_ops = { ++ .ndo_open = netdev_open, ++ .ndo_stop = netdev_stop, ++ .ndo_start_xmit = netdev_xmit, ++ .ndo_change_mtu = netdev_change_mtu, ++ .ndo_set_features = netdev_set_features, ++ .ndo_set_mac_address = netdev_set_mac_address, ++}; ++ ++struct stat_info { ++ unsigned int addr; ++ char string[ETH_GSTRING_LEN]; ++}; ++ ++#define STAT_INFO(_addr, _string) \ ++ .addr = _addr, .string = _string, ++ ++static void ethtool_get_strings(struct net_device *netdev, u32 stringset, ++ u8 *s) ++{ ++ struct n5010_hssi_netdata *npriv = netdev_priv(netdev); ++ unsigned int i, stats_num = 0; ++ struct stat_info *stat; ++ ++ if (stringset != ETH_SS_STATS) ++ return; ++ ++ stat = npriv->ops_params->stats; ++ stats_num = npriv->ops_params->num_stats; ++ ++ for (i = 0; i < stats_num; i++, s += ETH_GSTRING_LEN) ++ memcpy(s, stat[i].string, ETH_GSTRING_LEN); ++} ++ ++static int ethtool_get_sset_count(struct net_device *netdev, int stringset) ++{ ++ struct n5010_hssi_netdata *npriv = netdev_priv(netdev); ++ ++ if (stringset == ETH_SS_STATS) ++ return npriv->ops_params->num_stats; ++ ++ return 0; ++} ++ ++static u64 read_mac_stat(struct regmap *regmap, unsigned int addr) ++{ ++ u32 data_l, data_h; ++ ++ regmap_read(regmap, addr, &data_l); ++ regmap_read(regmap, addr + 1, &data_h); ++ ++ return data_l + ((u64)data_h << 32); ++} ++ ++static int ethtool_reset(struct net_device *netdev, u32 *flags) ++{ ++ struct n5010_hssi_netdata *npriv = netdev_priv(netdev); ++ struct regmap *regmap = npriv->regmap_mac; ++ u32 reg, val; ++ int ret; ++ ++ if (*flags | ETH_RESET_MGMT) { ++ reg = npriv->ops_params->tx_clr_off; ++ ++ ret = regmap_write(regmap, reg, 1); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(regmap, reg, 0); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read_poll_timeout(regmap, reg, val, (val & 1) == 0, ++ STATS_CLR_INT_US, ++ STATS_CLR_INT_TIMEOUT_US); ++ if (ret) { ++ dev_err(&netdev->dev, "failed to clear tx stats\n"); ++ return ret; ++ } ++ ++ reg = npriv->ops_params->rx_clr_off; ++ ++ ret = regmap_write(regmap, reg, 1); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(regmap, reg, 0); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read_poll_timeout(regmap, reg, val, (val & 1) == 0, ++ STATS_CLR_INT_US, ++ STATS_CLR_INT_TIMEOUT_US); ++ if (ret) { ++ dev_err(&netdev->dev, "failed to clear rx stats\n"); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static void ethtool_get_stats(struct net_device *netdev, ++ struct ethtool_stats *stats, u64 *data) ++{ ++ struct n5010_hssi_netdata *npriv = netdev_priv(netdev); ++ unsigned int i, stats_num = npriv->ops_params->num_stats; ++ struct stat_info *stat = npriv->ops_params->stats; ++ ++ for (i = 0; i < stats_num; i++) ++ data[i] = read_mac_stat(npriv->regmap_mac, stat[i].addr); ++} ++ ++static int ethtool_module_info(struct net_device *netdev, ++ struct ethtool_modinfo *modinfo) ++{ ++ return n5010_phy_module_info(netdev); ++} ++ ++static const struct ethtool_ops ethtool_ops = { ++ .get_strings = ethtool_get_strings, ++ .get_sset_count = ethtool_get_sset_count, ++ .get_ethtool_stats = ethtool_get_stats, ++ .get_link = ethtool_op_get_link, ++ .get_module_info = ethtool_module_info, ++ .reset = ethtool_reset, ++}; ++ ++static struct stat_info stats_100g[] = { ++ /* tx statistics */ ++ {STAT_INFO(0x800, "tx_fragments")}, ++ {STAT_INFO(0x802, "tx_jabbers")}, ++ {STAT_INFO(0x804, "tx_crcerr")}, ++ {STAT_INFO(0x806, "tx_crcerr_sizeok")}, ++ {STAT_INFO(0x808, "tx_mcast_data_err")}, ++ {STAT_INFO(0x80a, "tx_bcast_data_err")}, ++ {STAT_INFO(0x80c, "tx_ucast_data_err")}, ++ {STAT_INFO(0x80e, "tx_mcast_ctrl_err")}, ++ {STAT_INFO(0x810, "tx_bcast_ctrl_err")}, ++ {STAT_INFO(0x812, "tx_ucast_ctrl_err")}, ++ {STAT_INFO(0x814, "tx_pause_err")}, ++ {STAT_INFO(0x816, "tx_64b")}, ++ {STAT_INFO(0x818, "tx_65to127b")}, ++ {STAT_INFO(0x81a, "tx_128to255b")}, ++ {STAT_INFO(0x81c, "tx_256to511b")}, ++ {STAT_INFO(0x81e, "tx_512to1023b")}, ++ {STAT_INFO(0x820, "tx_1024to1518b")}, ++ {STAT_INFO(0x822, "tx_1519tomaxb")}, ++ {STAT_INFO(0x824, "tx_oversize")}, ++ {STAT_INFO(0x836, "tx_st")}, ++ {STAT_INFO(0x826, "tx_mcast_data_ok")}, ++ {STAT_INFO(0x828, "tx_bcast_data_ok")}, ++ {STAT_INFO(0x82a, "tx_ucast_data_ok")}, ++ {STAT_INFO(0x82c, "tx_mcast_ctrl_ok")}, ++ {STAT_INFO(0x82e, "tx_bcast_ctrl_ok")}, ++ {STAT_INFO(0x830, "tx_ucast_ctrl_ok")}, ++ {STAT_INFO(0x832, "tx_pause")}, ++ {STAT_INFO(0x860, "tx_payload_octets_ok")}, ++ {STAT_INFO(0x862, "tx_frame_octets_ok")}, ++ ++ /* rx statistics */ ++ {STAT_INFO(0x900, "rx_fragments")}, ++ {STAT_INFO(0x902, "rx_jabbers")}, ++ {STAT_INFO(0x904, "rx_crcerr")}, ++ {STAT_INFO(0x906, "rx_crcerr_sizeok")}, ++ {STAT_INFO(0x908, "rx_mcast_data_err")}, ++ {STAT_INFO(0x90a, "rx_bcast_data_err")}, ++ {STAT_INFO(0x90c, "rx_ucast_data_err")}, ++ {STAT_INFO(0x90e, "rx_mcast_ctrl_err")}, ++ {STAT_INFO(0x910, "rx_bcast_ctrl_err")}, ++ {STAT_INFO(0x912, "rx_ucast_ctrl_err")}, ++ {STAT_INFO(0x914, "rx_pause_err")}, ++ {STAT_INFO(0x916, "rx_64b")}, ++ {STAT_INFO(0x918, "rx_65to127b")}, ++ {STAT_INFO(0x91a, "rx_128to255b")}, ++ {STAT_INFO(0x91c, "rx_256to511b")}, ++ {STAT_INFO(0x91e, "rx_512to1023b")}, ++ {STAT_INFO(0x920, "rx_1024to1518b")}, ++ {STAT_INFO(0x922, "rx_1519tomaxb")}, ++ {STAT_INFO(0x924, "rx_oversize")}, ++ {STAT_INFO(0x936, "rx_st")}, ++ {STAT_INFO(0x926, "rx_mcast_data_ok")}, ++ {STAT_INFO(0x928, "rx_bcast_data_ok")}, ++ {STAT_INFO(0x92a, "rx_ucast_data_ok")}, ++ {STAT_INFO(0x92c, "rx_mcast_ctrl_ok")}, ++ {STAT_INFO(0x92e, "rx_bcast_ctrl_ok")}, ++ {STAT_INFO(0x930, "rx_ucast_ctrl_ok")}, ++ {STAT_INFO(0x932, "rx_pause")}, ++ {STAT_INFO(0x960, "rx_payload_octets_ok")}, ++ {STAT_INFO(0x962, "rx_frame_octets_ok")}, ++}; ++ ++static const struct n5010_hssi_ops_params n5010_100g_params = { ++ .stats = stats_100g, ++ .num_stats = ARRAY_SIZE(stats_100g), ++ .tx_clr_off = ILL_100G_TX_STATS_CLR, ++ .rx_clr_off = ILL_100G_RX_STATS_CLR, ++}; ++ ++static void n5010_hssi_init_netdev(struct net_device *netdev) ++{ ++ netdev->ethtool_ops = ðtool_ops; ++ netdev->netdev_ops = &netdev_ops; ++ netdev->features = 0; ++ netdev->hard_header_len = 0; ++ netdev->priv_flags |= IFF_NO_QUEUE; ++ netdev->max_mtu = MAC_MAX_MTU; ++ netdev->needs_free_netdev = true; ++ ++ ether_setup(netdev); ++} ++ ++enum n5010_hssi_regmap { ++ regmap_mac, ++ regmap_fec, ++ regmap_phy, ++}; ++ ++#ifndef devm_regmap_init_indirect_register ++struct regmap *devm_regmap_init_indirect_register(struct device *dev, ++ void __iomem *base, ++ struct regmap_config *cfg); ++#endif ++ ++#define REGMAP_NAME_SIZE 20 ++static struct regmap *n5010_hssi_create_regmap(struct n5010_hssi_drvdata *priv, ++ u64 port, ++ enum n5010_hssi_regmap type) ++{ ++ void __iomem *base = priv->base + port * MB_PORT_SIZE; ++ struct device *dev = &priv->dfl_dev->dev; ++ struct regmap_config cfg = {0}; ++ char regmap_name[REGMAP_NAME_SIZE]; ++ ++ switch (type) { ++ case regmap_mac: ++ scnprintf(regmap_name, REGMAP_NAME_SIZE, ++ "n5010_hssi_mac%llu", port); ++ base += MB_MAC_OFFSET; ++ cfg.val_bits = 32; ++ cfg.max_register = 0xbbf; ++ break; ++ case regmap_fec: ++ scnprintf(regmap_name, REGMAP_NAME_SIZE, ++ "n5010_hssi_fec%llu", port); ++ base += MB_FEC_OFFSET; ++ cfg.val_bits = 8; ++ cfg.max_register = 0x29c; ++ break; ++ case regmap_phy: ++ scnprintf(regmap_name, REGMAP_NAME_SIZE, ++ "n5010_hssi_phy%llu", port); ++ base += MB_PHY_OFFSET; ++ cfg.val_bits = 8; ++ cfg.max_register = 0x40144; ++ break; ++ } ++ ++ cfg.name = regmap_name; ++ cfg.reg_bits = 32; ++ ++ return devm_regmap_init_indirect_register(dev, base, &cfg); ++} ++ ++static int n5010_hssi_create_netdev(struct n5010_hssi_drvdata *priv, ++ struct device *phy, u64 port) ++{ ++ struct device *dev = &priv->dfl_dev->dev; ++ struct n5010_hssi_netdata *npriv; ++ struct net_device *netdev; ++ int err = -ENOMEM; ++ u32 flags; ++ ++ netdev = alloc_netdev(sizeof(struct n5010_hssi_netdata), ++ "n5010_hssi%d", NET_NAME_UNKNOWN, ++ n5010_hssi_init_netdev); ++ priv->netdev[port] = netdev; ++ ++ if (!netdev) ++ return -ENOMEM; ++ ++ npriv = netdev_priv(netdev); ++ ++ npriv->dfl_dev = priv->dfl_dev; ++ ++ npriv->regmap_mac = n5010_hssi_create_regmap(priv, port, regmap_mac); ++ if (!npriv->regmap_mac) ++ goto err_unreg_netdev; ++ ++ npriv->regmap_fec = n5010_hssi_create_regmap(priv, port, regmap_fec); ++ if (!npriv->regmap_fec) ++ goto err_unreg_netdev; ++ ++ npriv->regmap_phy = n5010_hssi_create_regmap(priv, port, regmap_phy); ++ if (!npriv->regmap_phy) ++ goto err_unreg_netdev; ++ ++ npriv->ops_params = &n5010_100g_params; ++ ++ SET_NETDEV_DEV(netdev, dev); ++ ++ flags = ETH_RESET_MGMT; ++ ++ npriv->link_status = FEC_RX_STATUS_LINK_NO; ++ ++ err = ethtool_reset(netdev, &flags); ++ if (err) { ++ dev_err(dev, "failed to reset MGMT %s: %d", netdev->name, err); ++ goto err_unreg_netdev; ++ } ++ ++ err = register_netdev(netdev); ++ if (err) { ++ dev_err(dev, "failed to register %s: %d", netdev->name, err); ++ goto err_unreg_netdev; ++ } ++ ++ err = n5010_phy_attach(phy, netdev, n5010_hssi_update_link, port); ++ if (err) ++ goto err_unreg_netdev; ++ ++ return 0; ++ ++err_unreg_netdev: ++ unregister_netdev(netdev); ++ ++ return err; ++} ++ ++static int n5010_match_phy_dev(struct device *dev, void *data) ++{ ++ return dev->driver && !strcmp(dev->driver->name, "n5010bmc-phy"); ++} ++ ++static int n5010_match_phy_master(struct device *dev, const void *data) ++{ ++ struct dfl_device *dfl_dev = (void *)data; ++ struct device *base_dev = dfl_dev_get_base_dev(dfl_dev); ++ ++ /* look trace device tree until a direct dfl-device is found */ ++ do { ++ if (!dev->bus) ++ continue; ++ ++ if (!strcmp(dev->bus->name, "dfl")) ++ break; ++ ++ if (!dev->parent) ++ return 0; ++ } while ((dev = dev->parent)); ++ ++ if (!dev) ++ return 0; ++ ++ /* compare the base (pci) device of the spi controller with the base ++ * (pci) device of the n5010-hssi device ++ */ ++ return dfl_dev_get_base_dev(to_dfl_dev(dev)) == base_dev; ++} ++ ++static int n5010_hssi_probe(struct dfl_device *dfl_dev) ++{ ++ struct device *phy_master, *phy_dev; ++ struct device *dev = &dfl_dev->dev; ++ struct n5010_hssi_drvdata *priv; ++ u64 val, port_cnt, port; ++ void __iomem *base; ++ u64 priv_size; ++ int ret = 0; ++ ++ /* find the spi controller from this pci device */ ++ phy_master = bus_find_device(&spi_bus_type, NULL, dfl_dev, ++ n5010_match_phy_master); ++ if (!phy_master) { ++ dev_info(dev, "phy master not found; deferring probe\n"); ++ return -EPROBE_DEFER; ++ } ++ ++ /* find the spi slave matching the n5010-phy driver */ ++ phy_dev = device_find_child(phy_master, dfl_dev, ++ n5010_match_phy_dev); ++ if (!phy_dev) { ++ dev_info(dev, "phy slave not found; deferring probe\n"); ++ ret = -EPROBE_DEFER; ++ goto err_phy_master; ++ } ++ ++ base = devm_ioremap_resource(dev, &dfl_dev->mmio_res); ++ if (IS_ERR(base)) { ++ ret = PTR_ERR(base); ++ goto err_phy_dev; ++ } ++ ++ val = readq(base + CAPABILITY_OFFSET); ++ port_cnt = FIELD_GET(CAP_PORT_CNT, val); ++ priv_size = sizeof(*priv) + port_cnt * sizeof(void *); ++ ++ priv = devm_kzalloc(dev, priv_size, GFP_KERNEL); ++ if (!priv) { ++ ret = -ENOMEM; ++ goto err_phy_dev; ++ } ++ ++ dev_set_drvdata(dev, priv); ++ ++ priv->dfl_dev = dfl_dev; ++ priv->port_cnt = port_cnt; ++ priv->base = base; ++ ++ for (port = 0; port < priv->port_cnt; port++) { ++ ret = n5010_hssi_create_netdev(priv, phy_dev, port); ++ if (ret) ++ goto err_phy_dev; ++ } ++ ++err_phy_dev: ++ put_device(phy_dev); ++err_phy_master: ++ put_device(phy_master); ++ ++ return ret; ++} ++ ++static void n5010_hssi_remove(struct dfl_device *dfl_dev) ++{ ++ struct n5010_hssi_drvdata *priv = dev_get_drvdata(&dfl_dev->dev); ++ u64 port; ++ ++ for (port = 0; port < priv->port_cnt; port++) { ++ n5010_phy_detach(priv->netdev[port]); ++ unregister_netdev(priv->netdev[port]); ++ } ++} ++ ++#define FME_FEATURE_ID_LL_100G_MAC_N5010 0x1f /* Silicom Lightning Creek */ ++ ++static const struct dfl_device_id n5010_hssi_mac_ids[] = { ++ { FME_ID, FME_FEATURE_ID_LL_100G_MAC_N5010 }, ++ { } ++}; ++ ++static struct dfl_driver n5010_hssi_driver = { ++ .drv = { ++ .name = "n5010_hssi", ++ }, ++ .id_table = n5010_hssi_mac_ids, ++ .probe = n5010_hssi_probe, ++ .remove = n5010_hssi_remove, ++}; ++ ++module_dfl_driver(n5010_hssi_driver); ++MODULE_DEVICE_TABLE(dfl, n5010_hssi_mac_ids); ++MODULE_DESCRIPTION("Network Device Driver for Silicom Lightning Creek"); ++MODULE_AUTHOR("Esa Leskinen "); ++MODULE_LICENSE("GPL v2"); diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0059-fpga-dfl-export-fme-and-port-error-DFH-revision-to-s.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0059-fpga-dfl-export-fme-and-port-error-DFH-revision-to-s.patch new file mode 100644 index 0000000..8aec579 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0059-fpga-dfl-export-fme-and-port-error-DFH-revision-to-s.patch @@ -0,0 +1,79 @@ +From 40644439b0be20dd7b0df78a7a53345eb5fc6dc3 Mon Sep 17 00:00:00 2001 +From: Matthew Gerlach +Date: Thu, 22 Oct 2020 14:25:27 -0400 +Subject: [PATCH] fpga: dfl: export fme and port error DFH revision to sysfs + +With Intel OFS, the definition of the port error bits have +changed to reflect the transition from CCI-P to AXI-S TLP. +Export the DFH revision to sysfs so that user space can +properly decode the port errors. + +Signed-off-by: Matthew Gerlach +--- + drivers/fpga/dfl-afu-error.c | 15 +++++++++++++++ + drivers/fpga/dfl-fme-error.c | 15 +++++++++++++++ + 2 files changed, 30 insertions(+) + +diff --git a/drivers/fpga/dfl-afu-error.c b/drivers/fpga/dfl-afu-error.c +index a36db24384f6..0f7ba59353e9 100644 +--- a/drivers/fpga/dfl-afu-error.c ++++ b/drivers/fpga/dfl-afu-error.c +@@ -178,10 +178,25 @@ static ssize_t first_malformed_req_show(struct device *dev, + } + static DEVICE_ATTR_RO(first_malformed_req); + ++static ssize_t revision_show(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); ++ void __iomem *base; ++ u64 dfh; ++ ++ base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_ERROR); ++ ++ dfh = readq(base); ++ ++ return sprintf(buf, "%lld\n", FIELD_GET(DFH_REVISION, dfh)); ++} ++static DEVICE_ATTR_RO(revision); ++ + static struct attribute *port_err_attrs[] = { + &dev_attr_errors.attr, + &dev_attr_first_error.attr, + &dev_attr_first_malformed_req.attr, ++ &dev_attr_revision.attr, + NULL, + }; + +diff --git a/drivers/fpga/dfl-fme-error.c b/drivers/fpga/dfl-fme-error.c +index 697718a0ceac..ee0fd3be5af9 100644 +--- a/drivers/fpga/dfl-fme-error.c ++++ b/drivers/fpga/dfl-fme-error.c +@@ -278,6 +278,20 @@ static ssize_t next_error_show(struct device *dev, + } + static DEVICE_ATTR_RO(next_error); + ++static ssize_t revision_show(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct dfl_feature_dev_data *fdata = to_dfl_feature_dev_data(dev); ++ void __iomem *base; ++ u64 dfh; ++ ++ base = dfl_get_feature_ioaddr_by_id(fdata, FME_FEATURE_ID_GLOBAL_ERR); ++ ++ dfh = readq(base); ++ ++ return sprintf(buf, "%lld\n", FIELD_GET(DFH_REVISION, dfh)); ++} ++static DEVICE_ATTR_RO(revision); ++ + static struct attribute *fme_global_err_attrs[] = { + &dev_attr_pcie0_errors.attr, + &dev_attr_pcie1_errors.attr, +@@ -287,6 +301,7 @@ static struct attribute *fme_global_err_attrs[] = { + &dev_attr_fme_errors.attr, + &dev_attr_first_error.attr, + &dev_attr_next_error.attr, ++ &dev_attr_revision.attr, + NULL, + }; + diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0060-uio-dfl-add-id-for-PCI-Subsystem.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0060-uio-dfl-add-id-for-PCI-Subsystem.patch new file mode 100644 index 0000000..f8cbe66 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0060-uio-dfl-add-id-for-PCI-Subsystem.patch @@ -0,0 +1,32 @@ +From ccbde7e3bb658723f026e40e3d61d0dc445f6f96 Mon Sep 17 00:00:00 2001 +From: Matthew Gerlach +Date: Thu, 29 Sep 2022 08:49:30 -0700 +Subject: [PATCH] uio: dfl: add id for PCI Subsystem + +Add id for device feature list (dfl) PCI subsystem feature +to table of ids supported by the uio_dfl driver. + +Signed-off-by: Matthew Gerlach +--- + drivers/uio/uio_dfl.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/uio/uio_dfl.c b/drivers/uio/uio_dfl.c +index 43e74194e013..517263f5b28b 100644 +--- a/drivers/uio/uio_dfl.c ++++ b/drivers/uio/uio_dfl.c +@@ -133,12 +133,14 @@ static int uio_dfl_probe(struct dfl_device *ddev) + + #define FME_FEATURE_ID_ETH_GROUP 0x10 + #define FME_FEATURE_ID_HSSI_SUBSYS 0x15 ++#define FME_FEATURE_ID_PCI_SUBSYS 0x20 + #define FME_FEATURE_ID_VENDOR_SPECIFIC 0x23 + #define PORT_FEATURE_ID_IOPLL_USRCLK 0x14 + + static const struct dfl_device_id uio_dfl_ids[] = { + { FME_ID, FME_FEATURE_ID_ETH_GROUP }, + { FME_ID, FME_FEATURE_ID_HSSI_SUBSYS }, ++ { FME_ID, FME_FEATURE_ID_PCI_SUBSYS }, + { FME_ID, FME_FEATURE_ID_VENDOR_SPECIFIC }, + { PORT_ID, PORT_FEATURE_ID_IOPLL_USRCLK }, + { } diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0061-fpga-dfl-add-support-for-switching-the-retimer-FEC-m.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0061-fpga-dfl-add-support-for-switching-the-retimer-FEC-m.patch new file mode 100644 index 0000000..aa28c2a --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0061-fpga-dfl-add-support-for-switching-the-retimer-FEC-m.patch @@ -0,0 +1,173 @@ +From 0dc10b42e5e6560ee0a2f3f876dbdabdbc9b953d Mon Sep 17 00:00:00 2001 +From: Xu Yilun +Date: Sat, 10 Oct 2020 10:38:27 +0800 +Subject: [PATCH] fpga: dfl: add support for switching the retimer FEC mode + +The N3000 Nios private feature provides the one-time configuration for +the retime FEC mode. The Nios firmware is responsible for the actual +hardware operation. It gives users a chance (only one chance) to set the +retimers to a different FEC mode. + +The Nios firmware has no nvmem to store the required FEC mode info, so it +needs the user input everytime on board power up. So this patch +introduced a module parameter for the user input. + +However, the community rejects this module parameter solution. Firstly +the module parameter can not support different configuration for +multiple boards. Secondly the maintainer thinks this configuration +should not be cared by linux user, the bootloader (thus the on board +firmware) should be changed to handle the configuration. + +Signed-off-by: Xu Yilun +--- + .../testing/sysfs-bus-dfl-devices-n3000-nios | 4 +- + Documentation/fpga/dfl-n3000-nios.rst | 73 +++++++++++++++++++ + Documentation/fpga/index.rst | 1 + + drivers/fpga/dfl-n3000-nios.c | 18 +++-- + 4 files changed, 90 insertions(+), 6 deletions(-) + create mode 100644 Documentation/fpga/dfl-n3000-nios.rst + +diff --git a/Documentation/ABI/testing/sysfs-bus-dfl-devices-n3000-nios b/Documentation/ABI/testing/sysfs-bus-dfl-devices-n3000-nios +index 5335d742bcaf..494eb1808094 100644 +--- a/Documentation/ABI/testing/sysfs-bus-dfl-devices-n3000-nios ++++ b/Documentation/ABI/testing/sysfs-bus-dfl-devices-n3000-nios +@@ -7,7 +7,9 @@ Description: Read-only. Returns the FEC mode of the 25G links of the + Solomon FEC, "kr" for Fire Code FEC, "no" for NO FEC. + "not supported" if the FEC mode setting is not supported, this + happens when the Nios firmware version major < 3, or no link is +- configured to 25G. ++ configured to 25G. The FEC mode could be set by module ++ parameters, but it could only be set once after the board ++ powers up. + Format: string + + What: /sys/bus/dfl/devices/dfl_dev.X/retimer_A_mode +diff --git a/Documentation/fpga/dfl-n3000-nios.rst b/Documentation/fpga/dfl-n3000-nios.rst +new file mode 100644 +index 000000000000..66bc09150aba +--- /dev/null ++++ b/Documentation/fpga/dfl-n3000-nios.rst +@@ -0,0 +1,73 @@ ++.. SPDX-License-Identifier: GPL-2.0 ++ ++================================= ++N3000 Nios Private Feature Driver ++================================= ++ ++The N3000 Nios driver supports for the Nios handshake private feature on Intel ++PAC (Programmable Acceleration Card) N3000. ++ ++The Nios is the embedded processor in the FPGA, it will configure the 2 onboard ++ethernet retimers on power up. This private feature provides a handshake ++interface to FPGA Nios firmware, which receives the ethernet retimer ++configuration command from host and does the configuration via an internal SPI ++master (spi-altera). When Nios finishes the configuration, host takes over the ++ownership of the SPI master to control an Intel MAX10 BMC (Board Management ++Controller) Chip on the SPI bus. ++ ++So the driver does 2 major tasks on probe, uses the Nios firmware to configure ++the ethernet retimer, and then creates a spi master platform device with the ++MAX10 device info in spi_board_info. ++ ++ ++Configuring the ethernet retimer ++================================ ++ ++The Intel PAC N3000 is a FPGA based SmartNIC platform which could be programmed ++to various configurations (with different link numbers and speeds, e.g. 8x10G, ++4x25G ...). And the retimer chips should also be configured correspondingly by ++Nios firmware. There are 2 retimer chips on the board, each of them supports 4 ++links. For example, in 8x10G configuration, the 2 retimer chips are both set to ++4x10G mode, while in 4x25G configuration, retimer A is set to 4x25G and retimer ++B is in reset. For now, the Nios firmware only supports 10G and 25G mode ++setting for the retimer chips. ++ ++For all 25G links, their FEC (Forward Error Correction) mode could be further ++configured by Nios firmware for user's requirement. For 10G links, they don't ++have the FEC mode at all, the firmware ignores the FEC mode setting for them. ++The FEC setting is not supported if the firmware version major < 3. ++ ++The retimer configuration can only be done once after the board powers up, the ++Nios firmware will not accept second configuration afterward. So it is not ++proper for the driver to create a RW sysfs node for the FEC mode. A better way ++is that the driver accepts a module parameter for the FEC mode, and does the ++retimer configuration on driver probe, it also creates a RO sysfs node for the ++FEC mode query. ++ ++Module Parameters ++================= ++ ++The N3000 Nios driver supports the following module parameters: ++ ++* fec_mode: string ++ Require the Nios firmware to set the FEC mode for all 25G links of the ++ ethernet retimers. The Nios firmware configures all these links with the same ++ FEC mode. The possible values of fec_mode could be: ++ ++ - "rs": Reed Solomon FEC (default) ++ - "kr": Fire Code FEC ++ - "no": No FEC ++ ++ Since the firmware doesn't accept second configuration, The FEC mode will not ++ be changed if the module is reloaded with a different parameter value. ++ ++ The parameter has no effect for 10G links. It has no effect to all the links ++ if firmware version major < 3. ++ ++ ++Sysfs Attributes ++================ ++ ++The driver creates some attributes in sysfs for users to query the retimer ++info. Please see Documentation/ABI/testing/sysfs-bus-dfl-devices-n3000-nios for ++more details. +diff --git a/Documentation/fpga/index.rst b/Documentation/fpga/index.rst +index 43c968871d99..37d519ce7c12 100644 +--- a/Documentation/fpga/index.rst ++++ b/Documentation/fpga/index.rst +@@ -8,6 +8,7 @@ FPGA + :maxdepth: 1 + + dfl ++ dfl-n3000-nios + + .. only:: subproject and html + +diff --git a/drivers/fpga/dfl-n3000-nios.c b/drivers/fpga/dfl-n3000-nios.c +index 9ddf1d1d392f..88e45d5e929c 100644 +--- a/drivers/fpga/dfl-n3000-nios.c ++++ b/drivers/fpga/dfl-n3000-nios.c +@@ -23,6 +23,10 @@ + #include + #include + ++static char *fec_mode = "rs"; ++module_param(fec_mode, charp, 0444); ++MODULE_PARM_DESC(fec_mode, "FEC mode of the ethernet retimer on Intel PAC N3000"); ++ + /* + * N3000 Nios private feature registers, named as NIOS_SPI_XX on spec. + * NS is the abbreviation of NIOS_SPI. +@@ -348,13 +352,17 @@ static int n3000_nios_init_done_check(struct n3000_nios *nn) + * mode field cause host could not get the retimer working mode + * until the Nios init is done. + * +- * For now the driver doesn't support the retimer FEC mode +- * switching per user's request. It is always set to Reed +- * Solomon FEC. +- * + * The driver will set the same FEC mode for all links. + */ +- val |= N3000_NIOS_INIT_REQ_FEC_MODE_RS_ALL; ++ ++ if (!strcmp(fec_mode, "no")) ++ val |= N3000_NIOS_INIT_REQ_FEC_MODE_NO_ALL; ++ else if (!strcmp(fec_mode, "kr")) ++ val |= N3000_NIOS_INIT_REQ_FEC_MODE_KR_ALL; ++ else if (!strcmp(fec_mode, "rs")) ++ val |= N3000_NIOS_INIT_REQ_FEC_MODE_RS_ALL; ++ else ++ return -EINVAL; + + ret = regmap_write(nn->regmap, N3000_NIOS_INIT, val); + if (ret) diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0062-fpga-dfl-add-debug-to-failed-partial-reconfiguration.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0062-fpga-dfl-add-debug-to-failed-partial-reconfiguration.patch new file mode 100644 index 0000000..0c611dd --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0062-fpga-dfl-add-debug-to-failed-partial-reconfiguration.patch @@ -0,0 +1,34 @@ +From 8c5aa007f458b8989dd289d934f80f7d8ab164cb Mon Sep 17 00:00:00 2001 +From: Matthew Gerlach +Date: Wed, 2 Jun 2021 11:55:07 -0700 +Subject: [PATCH] fpga: dfl: add debug to failed partial reconfiguration + +Add dev_err call printing number of bytes pushed out of total +attempted after a failed partial reconfigation. + +Signed-off-by: Matthew Gerlach +--- + drivers/fpga/dfl-fme-mgr.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/fpga/dfl-fme-mgr.c b/drivers/fpga/dfl-fme-mgr.c +index 13d4473147a4..3e6e4279276d 100644 +--- a/drivers/fpga/dfl-fme-mgr.c ++++ b/drivers/fpga/dfl-fme-mgr.c +@@ -180,6 +180,7 @@ static int fme_mgr_write(struct fpga_manager *mgr, + void __iomem *fme_pr = priv->ioaddr; + u64 pr_ctrl, pr_status, pr_data; + int delay = 0, pr_credit; ++ size_t full_cnt = count; + size_t chunk_size; + + dev_dbg(dev, "start request\n"); +@@ -203,6 +204,8 @@ static int fme_mgr_write(struct fpga_manager *mgr, + while (pr_credit <= 1) { + if (delay++ > PR_WAIT_TIMEOUT) { + dev_err(dev, "PR_CREDIT timeout\n"); ++ dev_err(dev, "wrote %zu bytes of %zu total\n", ++ full_cnt - count, full_cnt); + return -ETIMEDOUT; + } + udelay(1); diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0063-DEBUG-WARNING-enable-debugfs-writing-of-regmap-regis.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0063-DEBUG-WARNING-enable-debugfs-writing-of-regmap-regis.patch new file mode 100644 index 0000000..fddbcc1 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0063-DEBUG-WARNING-enable-debugfs-writing-of-regmap-regis.patch @@ -0,0 +1,29 @@ +From f6a2e7f37c608618fc9d03411398828c1921df06 Mon Sep 17 00:00:00 2001 +From: Matthew Gerlach +Date: Tue, 20 Oct 2020 13:59:26 -0400 +Subject: [PATCH] DEBUG WARNING enable debugfs writing of regmap registers + +Enable writing via debugfs to regmap registers by defining the necessary +macro. + +This change is potentially dangerous and is intended for development +only and not recommended for production deployment. + +Signed-off-by: Matthew Gerlach +--- + drivers/base/regmap/regmap-debugfs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c +index f36027591e1a..f09166787e84 100644 +--- a/drivers/base/regmap/regmap-debugfs.c ++++ b/drivers/base/regmap/regmap-debugfs.c +@@ -290,7 +290,7 @@ static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf, + count, ppos); + } + +-#undef REGMAP_ALLOW_WRITE_DEBUGFS ++#define REGMAP_ALLOW_WRITE_DEBUGFS + #ifdef REGMAP_ALLOW_WRITE_DEBUGFS + /* + * This can be dangerous especially when we have clients such as diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0064-fpga-dfl-Add-wildcard-sub-device-ID-for-intel-DFL-de.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0064-fpga-dfl-Add-wildcard-sub-device-ID-for-intel-DFL-de.patch new file mode 100644 index 0000000..17e798b --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0064-fpga-dfl-Add-wildcard-sub-device-ID-for-intel-DFL-de.patch @@ -0,0 +1,29 @@ +From 46ff90e9e47bb90f1d14bca5a521697504c82b23 Mon Sep 17 00:00:00 2001 +From: Russ Weight +Date: Tue, 16 Aug 2022 10:25:02 -0600 +Subject: [PATCH] fpga: dfl: Add wildcard sub-device ID for intel DFL devs + +The DFL device ID requires subdevice IDs. For intel devices, allow a +wildcard for the subdevice ID. This is intended for internal use only and +should not be upstreamed. + +Signed-off-by: Russ Weight +--- + drivers/fpga/dfl-pci.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/fpga/dfl-pci.c b/drivers/fpga/dfl-pci.c +index 02801e600bf2..7eb38a6a6bc1 100644 +--- a/drivers/fpga/dfl-pci.c ++++ b/drivers/fpga/dfl-pci.c +@@ -120,6 +120,10 @@ static struct pci_device_id cci_pcie_id_tbl[] = { + PCI_VENDOR_ID_INTEL, PCIE_SUBDEVICE_ID_INTEL_C6100),}, + {PCI_DEVICE_SUB(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_DFL_VF, + PCI_VENDOR_ID_INTEL, PCIE_SUBDEVICE_ID_INTEL_C6100),}, ++ {PCI_DEVICE_SUB(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_DFL, ++ PCI_VENDOR_ID_INTEL, PCI_ANY_ID),}, ++ {PCI_DEVICE_SUB(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_DFL_VF, ++ PCI_VENDOR_ID_INTEL, PCI_ANY_ID),}, + {PCI_DEVICE(PCI_VENDOR_ID_ALIBABA, PCIE_DEVICE_ID_ALIBABA_F5),}, + {0,} + }; diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0065-fpga-dfl-pci-sva-Add-support-for-binding-a-PASID-to-.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0065-fpga-dfl-pci-sva-Add-support-for-binding-a-PASID-to-.patch new file mode 100644 index 0000000..dbd5501 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0065-fpga-dfl-pci-sva-Add-support-for-binding-a-PASID-to-.patch @@ -0,0 +1,532 @@ +From 8828347bb9743fc750a14f3f73df8c384a43ebfe Mon Sep 17 00:00:00 2001 +From: Michael Adler +Date: Fri, 22 Sep 2023 12:55:57 -0400 +Subject: [PATCH] fpga: dfl-pci-sva: Add support for binding a PASID to an FPGA + port + +Expose a device interface for binding a PASID to FPGA PCIe ports. +PCIe devices with a DFL device ID are tracked independent of their +current driver, making it possible to configure IOMMU SVA with +either dfl-pci or vfio-pci drivers. The module uses bus notifier +hooks in order to catch device removal when vfio-pci is bound. + +Device files named /dev/dfl-pci-sva/ are managed +in this module (e.g. /dev/dfl-pci-sva/0000:ab:00.3). The +DFL_PCI_SVA_BIND_DEV ioctl ensures a PASID is allocated, binds +it to the device and returns the PASID. The PASID remains bound +until the file is closed or DFL_PCI_SVA_UNBIND_DEV. + +Signed-off-by: Michael Adler +--- + drivers/fpga/Kconfig | 7 + + drivers/fpga/Makefile | 1 + + drivers/fpga/dfl-pci-sva.c | 434 ++++++++++++++++++++++++++++++++++ + include/uapi/linux/fpga-dfl.h | 19 ++ + 4 files changed, 461 insertions(+) + create mode 100644 drivers/fpga/dfl-pci-sva.c + +diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig +index 5bcce59d3815..101b6ea2495b 100644 +--- a/drivers/fpga/Kconfig ++++ b/drivers/fpga/Kconfig +@@ -225,6 +225,13 @@ config FPGA_DFL_PCI + + To compile this as a module, choose M here. + ++config FPGA_DFL_PCI_SVA ++ tristate "FPGA DFL PCIe Shared Virtual Addressing Device Driver" ++ depends on PCI && FPGA_DFL ++ help ++ Select this option to enable PASID and IOMMU binding of DFL-based ++ devices that support shared virtual memory. ++ + config FPGA_DFL_HSSI + tristate "FPGA DFL HSSI Driver" + depends on FPGA_DFL +diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile +index 55ac2be413d7..29efc8f6fd3b 100644 +--- a/drivers/fpga/Makefile ++++ b/drivers/fpga/Makefile +@@ -55,6 +55,7 @@ obj-$(CONFIG_FPGA_DFL_NIOS_INTEL_PAC_N3000) += dfl-n3000-nios.o + + # Drivers for FPGAs which implement DFL + obj-$(CONFIG_FPGA_DFL_PCI) += dfl-pci.o ++obj-$(CONFIG_FPGA_DFL_PCI_SVA) += dfl-pci-sva.o + obj-$(CONFIG_FPGA_DFL_HSSI) += dfl-hssi.o + + # KUnit tests +diff --git a/drivers/fpga/dfl-pci-sva.c b/drivers/fpga/dfl-pci-sva.c +new file mode 100644 +index 000000000000..0c75f17c93eb +--- /dev/null ++++ b/drivers/fpga/dfl-pci-sva.c +@@ -0,0 +1,434 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Manage PASID and IOMMU binding for FPGA ports supporting shared ++ * virtual addressing. ++ * ++ * Copyright (C) 2023 Intel Corporation, Inc. ++ * ++ * Authors: ++ * Michael Adler ++ */ ++ ++/* ++ * Expose a device interface for binding a PASID to FPGA PCIe ports. ++ * PCIe devices with a DFL device ID are tracked independent of their ++ * current driver, making it possible to configure IOMMU SVA with ++ * either dfl-pci or vfio-pci drivers. The module uses bus notifier ++ * hooks in order to catch device removal when vfio-pci is bound. ++ * ++ * Device files named /dev/dfl-pci-sva/ are managed ++ * in this module (e.g. /dev/dfl-pci-sva/0000:ab:00.3). The ++ * DFL_PCI_SVA_BIND_DEV ioctl ensures a PASID is allocated, binds ++ * it to the device and returns the PASID. The PASID remains bound ++ * until the file is closed or DFL_PCI_SVA_UNBIND_DEV. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "dfl.h" ++ ++/* Device IDs of DFL-managed functions */ ++#define PCIE_DEVICE_ID_INTEL_DFL 0xbcce ++#define PCIE_DEVICE_ID_INTEL_DFL_VF 0xbccf ++ ++static struct notifier_block sva_nb; ++ ++static DEFINE_MUTEX(dfl_dev_list_mutex); ++static LIST_HEAD(dfl_dev_list); ++ ++struct dfl_sva_handle { ++ struct iommu_sva *sva_handle; /* Handle for process SVA binding with PASID */ ++ struct list_head sva_next; ++}; ++ ++struct dfl_sva_dev { ++ struct pci_dev *pdev; /* PCIe device to bind */ ++ struct miscdevice mdev; /* /dev/dfl-pci-sva/ device */ ++ char mdev_name[64]; /* dfl-pci-sva! */ ++ struct file_operations mdev_fops; /* dfl-pci-sva file ops */ ++ struct list_head sva_next; /* List of all SVA bindings, one per file descriptor */ ++ struct list_head pdev_next; /* List of all managed devices */ ++ struct mutex mutex; ++}; ++ ++/* ++ * Enable shared virtual addressing IOMMU support if the host and FPGA ++ * are configured to support it. PASID, ATS and PRS must all be enabled ++ * on the FPGA or the feature can not be enabled. ++ * ++ * If the function returns false, SVA is not available and the ++ * dfl-pci-sva device will not be created. ++ */ ++static int enable_iommu_sva_feature(struct pci_dev *pdev) ++{ ++ int ret; ++ ++ ret = iommu_dev_enable_feature(&pdev->dev, IOMMU_DEV_FEAT_IOPF); ++ if (ret) ++ return ret; ++ ++ ret = iommu_dev_enable_feature(&pdev->dev, IOMMU_DEV_FEAT_SVA); ++ if (ret) { ++ iommu_dev_disable_feature(&pdev->dev, IOMMU_DEV_FEAT_IOPF); ++ return ret; ++ } ++ ++ pci_info(pdev, "Enabled IOPF and SVA features\n"); ++ return 0; ++} ++ ++static void disable_iommu_sva_feature(struct pci_dev *pdev) ++{ ++ iommu_dev_disable_feature(&pdev->dev, IOMMU_DEV_FEAT_SVA); ++ iommu_dev_disable_feature(&pdev->dev, IOMMU_DEV_FEAT_IOPF); ++ pci_info(pdev, "Disabled IOPF and SVA features\n"); ++} ++ ++static int dfl_pci_sva_open(struct inode *inode, struct file *file) ++{ ++ struct dfl_sva_dev *dev = container_of(file->f_op, struct dfl_sva_dev, mdev_fops); ++ struct pci_dev *pdev; ++ struct dfl_sva_handle *sva; ++ int ret = 0; ++ ++ mutex_lock(&dev->mutex); ++ pdev = dev->pdev; ++ ++ if (!pdev) { ++ ret = -EBUSY; ++ goto out_unlock; ++ } ++ ++ sva = kzalloc(sizeof(struct dfl_sva_handle), GFP_KERNEL); ++ if (!sva) { ++ ret = -ENOMEM; ++ goto out_unlock; ++ } ++ ++ list_add(&sva->sva_next, &dev->sva_next); ++ file->private_data = sva; ++ ++ pci_dbg(pdev, "%s: pid %d\n", __func__, task_pid_nr(current)); ++ ++out_unlock: ++ mutex_unlock(&dev->mutex); ++ return ret; ++} ++ ++static int dfl_pci_sva_release(struct inode *inode, struct file *file) ++{ ++ struct dfl_sva_dev *dev = container_of(file->f_op, struct dfl_sva_dev, mdev_fops); ++ struct dfl_sva_handle *sva = file->private_data; ++ ++ mutex_lock(&dev->mutex); ++ ++ if (dev->pdev) { ++ pci_info(dev->pdev, "%s: pid %d, release sva_handle %p\n", __func__, ++ task_pid_nr(current), sva->sva_handle); ++ } ++ ++ /* Drop the IOMMU binding and release the sva_handle */ ++ if (sva->sva_handle) ++ iommu_sva_unbind_device(sva->sva_handle); ++ list_del(&sva->sva_next); ++ kfree(sva); ++ ++ if (!dev->pdev && list_empty(&dev->sva_next)) { ++ /* ++ * The device was deleted while the sva file handle was open. It has already ++ * been removed from the device dfl_dev_list but the memory needs to be ++ * released. dev->mutex can be ignored since it is in the memory being freed. ++ */ ++ kfree(dev); ++ pr_debug("%s: released device handle, pid %d\n", __func__, task_pid_nr(current)); ++ return 0; ++ } ++ ++ mutex_unlock(&dev->mutex); ++ return 0; ++} ++ ++static long ioctl_sva_bind_dev(struct dfl_sva_dev *dev, struct iommu_sva **sva_handle_p) ++{ ++ struct iommu_sva *handle; ++ ++ /* Was the device deleted while file handle is open? */ ++ if (!dev->pdev) ++ return -ENODEV; ++ ++ if (!current->mm) ++ return -EINVAL; ++ ++ if (*sva_handle_p) ++ return current->mm->pasid; ++ ++ handle = iommu_sva_bind_device(&dev->pdev->dev, current->mm); ++ pci_info(dev->pdev, "%s: pid %d, bind sva_handle %p, pasid = %d\n", ++ __func__, task_pid_nr(current), ++ handle, current->mm->pasid); ++ ++ if (!handle) ++ return -ENODEV; ++ if (IS_ERR(handle)) ++ return PTR_ERR(handle); ++ ++ *sva_handle_p = handle; ++ return current->mm->pasid; ++} ++ ++static long ioctl_sva_unbind_dev(struct dfl_sva_dev *dev, struct iommu_sva **sva_handle_p) ++{ ++ /* Was the device deleted while file handle is open? */ ++ if (!dev->pdev) ++ return -ENODEV; ++ ++ pci_info(dev->pdev, "%s: pid %d, unbind sva_handle %p\n", __func__, ++ task_pid_nr(current), *sva_handle_p); ++ ++ if (*sva_handle_p) { ++ iommu_sva_unbind_device(*sva_handle_p); ++ *sva_handle_p = NULL; ++ } ++ ++ return 0; ++} ++ ++static long dfl_pci_sva_ioctl(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ struct dfl_sva_dev *dev = container_of(file->f_op, struct dfl_sva_dev, mdev_fops); ++ struct dfl_sva_handle *sva = file->private_data; ++ long ret; ++ ++ mutex_lock(&dev->mutex); ++ ++ switch (cmd) { ++ case DFL_FPGA_GET_API_VERSION: ++ ret = DFL_FPGA_API_VERSION; ++ break; ++ case DFL_PCI_SVA_BIND_DEV: ++ ret = ioctl_sva_bind_dev(dev, &sva->sva_handle); ++ break; ++ case DFL_PCI_SVA_UNBIND_DEV: ++ ret = ioctl_sva_unbind_dev(dev, &sva->sva_handle); ++ break; ++ default: ++ pci_info(dev->pdev, "0x%x cmd not handled", cmd); ++ ret = -EINVAL; ++ } ++ ++ mutex_unlock(&dev->mutex); ++ return ret; ++} ++ ++static const struct file_operations dfl_mdev_fops = { ++ .open = dfl_pci_sva_open, ++ .release = dfl_pci_sva_release, ++ .unlocked_ioctl = dfl_pci_sva_ioctl, ++ .owner = THIS_MODULE, ++}; ++ ++static int add_dfl_mdev(struct dfl_sva_dev *dev) ++{ ++ struct pci_dev *pdev = dev->pdev; ++ ++ snprintf(dev->mdev_name, sizeof(dev->mdev_name), ++ "dfl-pci-sva!%04x:%02x:%02x.%x", ++ pci_domain_nr(pdev->bus), ++ pdev->bus->number, ++ PCI_SLOT(pdev->devfn), ++ PCI_FUNC(pdev->devfn)); ++ ++ INIT_LIST_HEAD(&dev->sva_next); ++ dev->mdev_fops = dfl_mdev_fops; ++ ++ dev->mdev.minor = MISC_DYNAMIC_MINOR; ++ dev->mdev.name = dev->mdev_name; ++ dev->mdev.fops = &dev->mdev_fops; ++ dev->mdev.mode = 0400; ++ ++ mutex_init(&dev->mutex); ++ misc_register(&dev->mdev); ++ ++ return 0; ++} ++ ++static void del_dfl_mdev(struct dfl_sva_dev *dev) ++{ ++ struct dfl_sva_handle *sva; ++ ++ mutex_lock(&dev->mutex); ++ pci_info(dev->pdev, "dfl-sva delete device\n"); ++ misc_deregister(&dev->mdev); ++ ++ list_for_each_entry(sva, &dev->sva_next, sva_next) { ++ if (sva->sva_handle) { ++ pci_info(dev->pdev, "dfl-sva force unbind sva_handle %p\n", ++ sva->sva_handle); ++ iommu_sva_unbind_device(sva->sva_handle); ++ sva->sva_handle = NULL; ++ } ++ } ++ ++ disable_iommu_sva_feature(dev->pdev); ++ dev->pdev = NULL; ++ ++ /* ++ * If the miscdevice is not open then delete the dfl_sva_dev entry. ++ * The entry can be deleted even though dev->mutex is held. The mutex ++ * is inside the memory being freed. ++ * ++ * If there is an open handle to miscdevice, keep the dfl_sva_dev. ++ * It will be freed when the file is closed. ++ */ ++ if (list_empty(&dev->sva_next)) ++ kfree(dev); ++ else ++ mutex_unlock(&dev->mutex); ++} ++ ++static inline bool is_dfl_device(struct pci_dev *pdev) ++{ ++ return pdev->vendor == PCI_VENDOR_ID_INTEL && ++ (pdev->device == PCIE_DEVICE_ID_INTEL_DFL || ++ pdev->device == PCIE_DEVICE_ID_INTEL_DFL_VF); ++} ++ ++/* ++ * Consider adding a new device. This is called both by new dfl-pci probes ++ * and from the PCIe bus notifier. ++ */ ++static void dfl_pci_sva_add_dev(struct pci_dev *pdev) ++{ ++ int ret; ++ struct dfl_sva_dev *cur; ++ ++ /* ++ * Consider new DFL and DFL_VF devices, adding them to dfl_dev_list ++ * if they support shared virtual addressing. ++ */ ++ if (!is_dfl_device(pdev)) ++ return; ++ ++ mutex_lock(&dfl_dev_list_mutex); ++ /* Nothing to do if the device was already added */ ++ list_for_each_entry(cur, &dfl_dev_list, pdev_next) { ++ if (cur->pdev == pdev) ++ goto out_unlock; ++ } ++ ++ /* Manage only devices with SVA features (returns 0 here) */ ++ ret = enable_iommu_sva_feature(pdev); ++ if (ret) ++ goto out_unlock; ++ ++ cur = kzalloc(sizeof(struct dfl_sva_dev), GFP_KERNEL); ++ if (!cur) ++ goto out_disable; ++ ++ pci_info(pdev, "dfl-sva add device\n"); ++ cur->pdev = pdev; ++ ++ ret = add_dfl_mdev(cur); ++ if (ret) { ++ kfree(cur); ++ goto out_disable; ++ } ++ ++ list_add(&cur->pdev_next, &dfl_dev_list); ++ mutex_unlock(&dfl_dev_list_mutex); ++ ++ return; ++ ++out_disable: ++ disable_iommu_sva_feature(pdev); ++out_unlock: ++ mutex_unlock(&dfl_dev_list_mutex); ++} ++ ++static void dfl_pci_sva_del_dev(struct pci_dev *pdev) ++{ ++ struct dfl_sva_dev *cur; ++ ++ if (is_dfl_device(pdev)) { ++ mutex_lock(&dfl_dev_list_mutex); ++ list_for_each_entry(cur, &dfl_dev_list, pdev_next) { ++ if (cur->pdev == pdev) { ++ list_del(&cur->pdev_next); ++ del_dfl_mdev(cur); ++ break; ++ } ++ } ++ mutex_unlock(&dfl_dev_list_mutex); ++ } ++} ++ ++/* ++ * Monitor PCIe bus events so that DFL devices will be updated even if ++ * they are bound to vfio-pci instead of dfl-pci. ++ */ ++static int sva_bus_notifier(struct notifier_block *nb, ++ unsigned long action, void *data) ++{ ++ struct device *dev = data; ++ struct pci_dev *pdev = to_pci_dev(dev); ++ ++ if (action == BUS_NOTIFY_ADD_DEVICE || action == BUS_NOTIFY_BIND_DRIVER) ++ dfl_pci_sva_add_dev(pdev); ++ if (action == BUS_NOTIFY_DEL_DEVICE) ++ dfl_pci_sva_del_dev(pdev); ++ ++ return 0; ++} ++ ++static int sva_init_dev(struct device *dev, void *data) ++{ ++ dfl_pci_sva_add_dev(to_pci_dev(dev)); ++ return 0; ++} ++ ++static int __init dfl_pci_sva_init_module(void) ++{ ++ int ret; ++ ++ INIT_LIST_HEAD(&dfl_dev_list); ++ sva_nb.notifier_call = sva_bus_notifier; ++ ret = bus_register_notifier(&pci_bus_type, &sva_nb); ++ if (ret) ++ return ret; ++ ++ /* ++ * Discover devices already added. Devices added later will be detected ++ * by the notifier. ++ */ ++ return bus_for_each_dev(&pci_bus_type, NULL, NULL, sva_init_dev); ++} ++ ++static void __exit dfl_pci_sva_cleanup_module(void) ++{ ++ struct dfl_sva_dev *cur, *tmp; ++ ++ bus_unregister_notifier(&pci_bus_type, &sva_nb); ++ ++ mutex_lock(&dfl_dev_list_mutex); ++ list_for_each_entry_safe(cur, tmp, &dfl_dev_list, pdev_next) { ++ del_dfl_mdev(cur); ++ } ++ ++ INIT_LIST_HEAD(&dfl_dev_list); ++ mutex_unlock(&dfl_dev_list_mutex); ++} ++ ++module_init(dfl_pci_sva_init_module); ++module_exit(dfl_pci_sva_cleanup_module); ++ ++MODULE_DESCRIPTION("FPGA DFL PCIe Shared Virtual Addressing Device Driver"); ++MODULE_AUTHOR("Intel Corporation"); ++MODULE_LICENSE("GPL v2"); +diff --git a/include/uapi/linux/fpga-dfl.h b/include/uapi/linux/fpga-dfl.h +index 72d68e205eb9..868c81ff2cf7 100644 +--- a/include/uapi/linux/fpga-dfl.h ++++ b/include/uapi/linux/fpga-dfl.h +@@ -31,6 +31,7 @@ + #define DFL_FPGA_BASE 0 + #define DFL_PORT_BASE 0x40 + #define DFL_FME_BASE 0x80 ++#define DFL_PCI_SVA_BASE 0xf8 + + /* Common IOCTLs for both FME and AFU file descriptor */ + +@@ -284,4 +285,22 @@ struct dfl_fpga_fme_port_pr { + DFL_FME_BASE + 4, \ + struct dfl_fpga_irq_set) + ++/** ++ * DFL_PCI_SVA_BIND_DEV - _IO(DFL_FPGA_MAGIC, DFL_PCI_SVA_BASE + 0) ++ * ++ * Ensure that a PASID is present in the user process and enable the ++ * PASID on the IOMMU domain of the device associated with the file handle. ++ * Returns the PASID on success, -errno on failure. ++ */ ++#define DFL_PCI_SVA_BIND_DEV _IO(DFL_FPGA_MAGIC, \ ++ DFL_PCI_SVA_BASE + 0) ++ ++/** ++ * DFL_PCI_SVA_UNBIND_DEV - _IO(DFL_FPGA_MAGIC, DFL_PCI_SVA_BASE + 1) ++ * ++ * Unbind the current PASID from the device. ++ */ ++#define DFL_PCI_SVA_UNBIND_DEV _IO(DFL_FPGA_MAGIC, \ ++ DFL_PCI_SVA_BASE + 1) ++ + #endif /* _UAPI_LINUX_FPGA_DFL_H */ diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0066-fpga-dfl-cxl-cache-Add-Intel-CXL-cache-driver.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0066-fpga-dfl-cxl-cache-Add-Intel-CXL-cache-driver.patch new file mode 100644 index 0000000..f514af5 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0066-fpga-dfl-cxl-cache-Add-Intel-CXL-cache-driver.patch @@ -0,0 +1,795 @@ +From 22d90605689773ea2b3a04efcc31604d3778e818 Mon Sep 17 00:00:00 2001 +From: Tim Whisonant +Date: Wed, 18 Oct 2023 15:51:44 -0700 +Subject: [PATCH] fpga: dfl-cxl-cache: Add Intel CXL cache driver + +Provides a means of accessing the device MMIO and the +capability to pin buffers and program their physical +addresses into the HE-Cache registers. User interface +is exposed via /dev/dfl-cxl-cache.X as described in +include/uapi/linux/fpga-dfl.h. + +Co-developed-by: Ananda Ravuri +Signed-off-by: Ananda Ravuri +Co-developed-by: Matthew Gerlach +Signed-off-by: Matthew Gerlach +Signed-off-by: Tim Whisonant +--- + drivers/fpga/Kconfig | 7 + + drivers/fpga/Makefile | 1 + + drivers/fpga/dfl-cxl-cache.c | 613 ++++++++++++++++++++++++++++++++++ + include/uapi/linux/fpga-dfl.h | 99 ++++++ + 4 files changed, 720 insertions(+) + create mode 100644 drivers/fpga/dfl-cxl-cache.c + +diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig +index 101b6ea2495b..46a26b2c9d36 100644 +--- a/drivers/fpga/Kconfig ++++ b/drivers/fpga/Kconfig +@@ -272,6 +272,13 @@ config FPGA_M10_BMC_SEC_UPDATE + (BMC) and provides support for secure updates for the BMC image, + the FPGA image, the Root Entry Hashes, etc. + ++config FPGA_DFL_CXL_CACHE ++ tristate "Intel CXL cache driver" ++ depends on FPGA_DFL ++ help ++ This is the driver for CXL cache Accelerated Function Unit ++ (AFU) which provides interfaces to MMIO region and dma buffers. ++ + config FPGA_MGR_MICROCHIP_SPI + tristate "Microchip Polarfire SPI FPGA manager" + depends on SPI +diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile +index 29efc8f6fd3b..ff57d3cd034c 100644 +--- a/drivers/fpga/Makefile ++++ b/drivers/fpga/Makefile +@@ -57,6 +57,7 @@ obj-$(CONFIG_FPGA_DFL_NIOS_INTEL_PAC_N3000) += dfl-n3000-nios.o + obj-$(CONFIG_FPGA_DFL_PCI) += dfl-pci.o + obj-$(CONFIG_FPGA_DFL_PCI_SVA) += dfl-pci-sva.o + obj-$(CONFIG_FPGA_DFL_HSSI) += dfl-hssi.o ++obj-$(CONFIG_FPGA_DFL_CXL_CACHE) += dfl-cxl-cache.o + + # KUnit tests + obj-$(CONFIG_FPGA_KUNIT_TESTS) += tests/ +diff --git a/drivers/fpga/dfl-cxl-cache.c b/drivers/fpga/dfl-cxl-cache.c +new file mode 100644 +index 000000000000..1e6222e039b2 +--- /dev/null ++++ b/drivers/fpga/dfl-cxl-cache.c +@@ -0,0 +1,613 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * DFL device driver for Host Exerciser Cache private feature. ++ * ++ * Provides a means of accessing the device MMIO and the ++ * capability to pin buffers and program their physical ++ * addresses into the HE-Cache registers. User interface ++ * is exposed via /dev/dfl-cxl-cache.X as described in ++ * include/uapi/linux/fpga-dfl.h. ++ * ++ * Copyright (C) 2023 Intel Corporation, Inc. ++ * ++ * Authors: ++ * Tim Whisonant ++ * Ananda Ravuri ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DFL_CXL_CACHE_DRIVER_NAME "dfl-cxl-cache" ++#define FME_FEATURE_ID_CXL_CACHE 0x25 ++ ++struct dfl_cxl_cache_buffer_region { ++ u64 user_addr; ++ u64 length; ++ struct page **pages; ++ phys_addr_t phys; ++ __u64 offset[DFL_ARRAY_MAX_SIZE]; ++ struct rb_node node; ++}; ++ ++struct dfl_cxl_cache { ++ struct dfl_device *ddev; ++ int id; ++ struct device *dev; ++ struct cdev cdev; ++ atomic_t opened; ++ void __iomem *mmio_base; ++ int mmio_size; ++ struct dfl_cxl_cache_region_info rinfo; ++ struct rb_root dma_regions; ++}; ++ ++static DEFINE_MUTEX(dfl_cxl_cache_class_lock); ++static struct class *dfl_cxl_cache_class; ++static dev_t dfl_cxl_cache_devt; ++static int dfl_cxl_cache_devices; ++ ++static int dfl_cxl_cache_open(struct inode *inode, struct file *filp) ++{ ++ struct dfl_cxl_cache *cxl_cache = container_of(inode->i_cdev, struct dfl_cxl_cache, cdev); ++ ++ if (atomic_cmpxchg(&cxl_cache->opened, 0, 1)) ++ return -EBUSY; ++ ++ filp->private_data = cxl_cache; ++ ++ return 0; ++} ++ ++static long cxl_cache_ioctl_check_extension(struct dfl_cxl_cache *cxl_cache, unsigned long arg) ++{ ++ /* No extension support for now */ ++ return 0; ++} ++ ++static long cxl_cache_ioctl_get_region_info(struct dfl_cxl_cache *cxl_cache, void __user *arg) ++{ ++ struct dfl_cxl_cache_region_info rinfo; ++ unsigned long minsz; ++ ++ minsz = offsetofend(struct dfl_cxl_cache_region_info, offset); ++ ++ if (copy_from_user(&rinfo, arg, minsz)) ++ return -EFAULT; ++ ++ if (rinfo.argsz < minsz) ++ return -EINVAL; ++ ++ rinfo.flags = cxl_cache->rinfo.flags; ++ rinfo.size = cxl_cache->rinfo.size; ++ rinfo.offset = cxl_cache->rinfo.offset; ++ ++ if (copy_to_user(arg, &rinfo, sizeof(rinfo))) ++ return -EFAULT; ++ ++ return 0; ++} ++ ++static void cxl_cache_unpin_pages(struct device *dev, struct page ***pages, unsigned long length) ++{ ++ const long npages = PFN_DOWN(length); ++ ++ if (!*pages) ++ return; ++ ++ unpin_user_pages(*pages, npages); ++ kfree(*pages); ++ *pages = NULL; ++ account_locked_vm(current->mm, npages, false); ++ ++ dev_dbg(dev, "%ld pages unpinned\n", npages); ++} ++ ++/** ++ * cxl_cache_dsm_check_continuous_pages - check if pages are continuous ++ * @region: dma memory region ++ * ++ * Return true if pages of given dma memory region have continuous physical ++ * address, otherwise return false. ++ */ ++static bool cxl_cache_check_continuous_pages(struct page **pages, unsigned long length) ++{ ++ int i; ++ const int npages = PFN_DOWN(length); ++ ++ for (i = 0; i < npages - 1; i++) ++ if (page_to_pfn(pages[i]) + 1 != page_to_pfn(pages[i + 1])) ++ return false; ++ ++ return true; ++} ++ ++static int cxl_cache_dma_pin_pages(struct dfl_cxl_cache *cxl_cache, ++ struct dfl_cxl_cache_buffer_region *region) ++{ ++ int ret, pinned; ++ const unsigned int flags = FOLL_LONGTERM | FOLL_WRITE; ++ const int npages = PFN_DOWN(region->length); ++ ++ ret = account_locked_vm(current->mm, npages, true); ++ if (ret) ++ return ret; ++ ++ region->pages = kzalloc(npages * sizeof(struct page *), GFP_KERNEL); ++ if (!region->pages) { ++ ret = -ENOMEM; ++ goto unlock_vm; ++ } ++ ++ pinned = pin_user_pages_fast(region->user_addr, npages, flags, region->pages); ++ if (pinned < 0) { ++ ret = pinned; ++ goto free_pages; ++ } else if (pinned != npages) { ++ ret = -EFAULT; ++ goto unpin_pages; ++ } ++ dev_dbg(cxl_cache->dev, "%d pages pinned\n", pinned); ++ ++ return 0; ++ ++unpin_pages: ++ unpin_user_pages(region->pages, pinned); ++free_pages: ++ kfree(region->pages); ++unlock_vm: ++ account_locked_vm(current->mm, npages, false); ++ return ret; ++} ++ ++static void cxl_cache_dma_region_remove(struct dfl_cxl_cache *cxl_cache, ++ struct dfl_cxl_cache_buffer_region *region) ++{ ++ dev_dbg(cxl_cache->dev, "del region (user_addr = %llx)\n", region->user_addr); ++ rb_erase(®ion->node, &cxl_cache->dma_regions); ++} ++ ++static bool dma_region_check_user_addr(struct dfl_cxl_cache_buffer_region *region, u64 user_addr, ++ u64 size) ++{ ++ if (!size && region->user_addr != user_addr) ++ return false; ++ ++ return (region->user_addr <= user_addr) && ++ (region->length + region->user_addr >= user_addr + size); ++} ++ ++struct dfl_cxl_cache_buffer_region* ++ cxl_cache_dma_region_find(struct dfl_cxl_cache *cxl_cache, u64 user_addr, u64 size) ++{ ++ struct rb_node *node = cxl_cache->dma_regions.rb_node; ++ ++ while (node) { ++ struct dfl_cxl_cache_buffer_region *region; ++ ++ region = container_of(node, struct dfl_cxl_cache_buffer_region, node); ++ ++ if (dma_region_check_user_addr(region, user_addr, size)) { ++ dev_dbg(cxl_cache->dev, "find region (user_addr = %llx)\n", ++ region->user_addr); ++ return region; ++ } ++ ++ if (user_addr < region->user_addr) ++ node = node->rb_left; ++ else if (user_addr > region->user_addr) ++ node = node->rb_right; ++ else ++ break; ++ } ++ ++ dev_dbg(cxl_cache->dev, "region with user_addr %llx and size %llx is not found\n", ++ user_addr, size); ++ return NULL; ++} ++ ++static int cxl_cache_dma_region_add(struct dfl_cxl_cache *cxl_cache, ++ struct dfl_cxl_cache_buffer_region *region) ++{ ++ struct rb_node **new, *parent = NULL; ++ ++ dev_dbg(cxl_cache->dev, "add region (user_addr = %llx)\n", region->user_addr); ++ new = &cxl_cache->dma_regions.rb_node; ++ ++ while (*new) { ++ struct dfl_cxl_cache_buffer_region *this; ++ ++ this = container_of(*new, struct dfl_cxl_cache_buffer_region, node); ++ parent = *new; ++ ++ if (dma_region_check_user_addr(this, region->user_addr, region->length)) ++ return -EEXIST; ++ ++ if (region->user_addr < this->user_addr) ++ new = &((*new)->rb_left); ++ else if (region->user_addr > this->user_addr) ++ new = &((*new)->rb_right); ++ else ++ return -EEXIST; ++ } ++ ++ rb_link_node(®ion->node, parent, new); ++ rb_insert_color(®ion->node, &cxl_cache->dma_regions); ++ ++ return 0; ++} ++ ++static long cxl_cache_ioctl_numa_buffer_map(struct dfl_cxl_cache *cxl_cache, void __user *arg) ++{ ++ int i = 0; ++ unsigned long minsz = 0; ++ long ret = 0; ++ struct dfl_cxl_cache_buffer_map dma_map; ++ struct dfl_cxl_cache_buffer_region *region; ++ ++ minsz = offsetofend(struct dfl_cxl_cache_buffer_map, csr_array); ++ if (copy_from_user(&dma_map, arg, minsz)) { ++ dev_err(cxl_cache->dev, "fails to copy from user space buffer\n"); ++ return -EFAULT; ++ } ++ if (dma_map.argsz < minsz) { ++ dev_err(cxl_cache->dev, "invalid ioctl buffer size\n"); ++ return -EINVAL; ++ } ++ ++ /* Check Inputs, only accept page-aligned user memory region with valid length */ ++ if (!PAGE_ALIGNED(dma_map.user_addr) || !PAGE_ALIGNED(dma_map.length) || ++ !(dma_map.length)) { ++ dev_err(cxl_cache->dev, "length is not page-aligned or the length is zero\n"); ++ return -EINVAL; ++ } ++ ++ /* Check overflow */ ++ if (dma_map.user_addr + dma_map.length < dma_map.user_addr) { ++ dev_err(cxl_cache->dev, "dma buffer check overflow\n"); ++ return -EINVAL; ++ } ++ ++ region = kzalloc(sizeof(*region), GFP_KERNEL); ++ if (!region) ++ return -ENOMEM; ++ ++ region->user_addr = dma_map.user_addr; ++ region->length = dma_map.length; ++ ++ dev_dbg(cxl_cache->dev, "user_addr: %llx length: %lld\n", ++ region->user_addr, region->length); ++ ++ /* Pin the user memory region */ ++ ret = cxl_cache_dma_pin_pages(cxl_cache, region); ++ if (ret) { ++ dev_err(cxl_cache->dev, "failed to pin pages\n"); ++ goto free_region; ++ } ++ ++ /* Only accept continuous pages, return error else */ ++ if (!cxl_cache_check_continuous_pages(region->pages, region->length)) { ++ dev_err(cxl_cache->dev, "pages are not continuous\n"); ++ ret = -EINVAL; ++ goto out_unpin_pages; ++ } ++ ++ ret = cxl_cache_dma_region_add(cxl_cache, region); ++ ++ if (ret) { ++ dev_err(cxl_cache->dev, "failed to add dma region\n"); ++ goto out_unpin_pages; ++ } ++ ++ drm_clflush_virt_range(page_address(region->pages[0]), region->length); ++ ++ region->phys = page_to_phys(region->pages[0]); ++ ++ for (i = 0; i < DFL_ARRAY_MAX_SIZE; i++) { ++ if (dma_map.csr_array[i] != 0 && dma_map.csr_array[i] < cxl_cache->rinfo.size) ++ writeq(region->phys, cxl_cache->mmio_base + dma_map.csr_array[i]); ++ } ++ ++ dev_dbg(cxl_cache->dev, "phys address:%lld\n", region->phys); ++ return 0; ++ ++out_unpin_pages: ++ cxl_cache_unpin_pages(cxl_cache->dev, ®ion->pages, region->length); ++free_region: ++ kfree(region); ++ return ret; ++} ++ ++static long cxl_cache_ioctl_numa_buffer_unmap(struct dfl_cxl_cache *cxl_cache, void __user *arg) ++{ ++ unsigned long minsz = 0; ++ long ret = 0; ++ int i = 0; ++ struct dfl_cxl_cache_buffer_unmap dma_unmap; ++ struct dfl_cxl_cache_buffer_region *region; ++ ++ minsz = offsetofend(struct dfl_cxl_cache_buffer_unmap, csr_array); ++ if (copy_from_user(&dma_unmap, arg, minsz)) { ++ dev_err(cxl_cache->dev, "fails to copy from user space buffer\n"); ++ return -EFAULT; ++ } ++ if (dma_unmap.argsz < minsz) { ++ dev_err(cxl_cache->dev, "invalid ioctl buffer size\n"); ++ return -EINVAL; ++ } ++ ++ dev_dbg(cxl_cache->dev, "user_addr: %llx length: %lld", ++ dma_unmap.user_addr, dma_unmap.length); ++ ++ region = cxl_cache_dma_region_find(cxl_cache, dma_unmap.user_addr, dma_unmap.length); ++ if (!region) { ++ dev_err(cxl_cache->dev, "fails to find buffer\n"); ++ return -EINVAL; ++ } ++ ++ cxl_cache_dma_region_remove(cxl_cache, region); ++ cxl_cache_unpin_pages(cxl_cache->dev, ®ion->pages, region->length); ++ ++ for (i = 0; i < DFL_ARRAY_MAX_SIZE; i++) { ++ if (dma_unmap.csr_array[i] != 0 && dma_unmap.csr_array[i] < cxl_cache->rinfo.size) ++ writeq(0, cxl_cache->mmio_base + dma_unmap.csr_array[i]); ++ } ++ ++ kfree(region); ++ return ret; ++} ++ ++static long dfl_cxl_cache_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ struct dfl_cxl_cache *cxl_cache = filp->private_data; ++ ++ switch (cmd) { ++ case DFL_FPGA_GET_API_VERSION: ++ return DFL_FPGA_GET_API_VERSION; ++ case DFL_FPGA_CHECK_EXTENSION: ++ return cxl_cache_ioctl_check_extension(cxl_cache, arg); ++ case DFL_CXL_CACHE_GET_REGION_INFO: ++ return cxl_cache_ioctl_get_region_info(cxl_cache, (void __user *)arg); ++ case DFL_CXL_CACHE_NUMA_BUFFER_MAP: ++ return cxl_cache_ioctl_numa_buffer_map(cxl_cache, (void __user *)arg); ++ case DFL_CXL_CACHE_NUMA_BUFFER_UNMAP: ++ return cxl_cache_ioctl_numa_buffer_unmap(cxl_cache, (void __user *)arg); ++ } ++ ++ return -EINVAL; ++} ++ ++static const struct vm_operations_struct cxl_cache_vma_ops = { ++#ifdef CONFIG_HAVE_IOREMAP_PROT ++ .access = generic_access_phys, ++#endif ++}; ++ ++static int dfl_cxl_cache_mmap(struct file *filp, struct vm_area_struct *vma) ++{ ++ struct dfl_cxl_cache *cxl_cache = filp->private_data; ++ u64 size = vma->vm_end - vma->vm_start; ++ u64 offset; ++ ++ if (!(vma->vm_flags & VM_SHARED)) ++ return -EINVAL; ++ ++ if (!(cxl_cache->rinfo.flags & DFL_CXL_CACHE_REGION_MMAP)) ++ return -EINVAL; ++ ++ if ((vma->vm_flags & VM_READ) && !(cxl_cache->rinfo.flags & DFL_CXL_CACHE_REGION_READ)) ++ return -EPERM; ++ ++ if ((vma->vm_flags & VM_WRITE) && !(cxl_cache->rinfo.flags & DFL_CXL_CACHE_REGION_WRITE)) ++ return -EPERM; ++ ++ offset = PFN_PHYS(vma->vm_pgoff); ++ ++ /* Support debug access to the mapping */ ++ vma->vm_ops = &cxl_cache_vma_ops; ++ ++ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); ++ ++ return remap_pfn_range(vma, vma->vm_start, ++ PFN_DOWN(cxl_cache->ddev->mmio_res.start + ++ (offset - cxl_cache->rinfo.offset)), ++ size, vma->vm_page_prot); ++} ++ ++void cxl_cache_dma_region_destroy(struct dfl_cxl_cache *cxl_cache) ++{ ++ struct rb_node *node = rb_first(&cxl_cache->dma_regions); ++ struct dfl_cxl_cache_buffer_region *region; ++ ++ while (node) { ++ region = container_of(node, struct dfl_cxl_cache_buffer_region, node); ++ ++ dev_dbg(cxl_cache->dev, "del region (user_addr = %llx)\n", region->user_addr); ++ rb_erase(node, &cxl_cache->dma_regions); ++ ++ if (region->pages) ++ cxl_cache_unpin_pages(cxl_cache->dev, ®ion->pages, region->length); ++ ++ node = rb_next(node); ++ kfree(region); ++ } ++} ++ ++static int dfl_cxl_cache_release(struct inode *inode, struct file *filp) ++{ ++ struct dfl_cxl_cache *cxl_cache = filp->private_data; ++ ++ cxl_cache_dma_region_destroy(cxl_cache); ++ atomic_set(&cxl_cache->opened, 0); ++ return 0; ++} ++ ++static const struct file_operations dfl_cxl_cache_fops = { ++ .owner = THIS_MODULE, ++ .open = dfl_cxl_cache_open, ++ .release = dfl_cxl_cache_release, ++ .unlocked_ioctl = dfl_cxl_cache_ioctl, ++ .mmap = dfl_cxl_cache_mmap, ++}; ++ ++static void cxl_cache_dev_release(struct device *dev) ++{ ++ struct dfl_cxl_cache *cxl_cache = dev_get_drvdata(dev); ++ ++ cdev_del(&cxl_cache->cdev); ++} ++ ++static void cxl_cache_chardev_uinit(struct dfl_cxl_cache *cxl_cache) ++{ ++ dev_set_drvdata(&cxl_cache->ddev->dev, NULL); ++ device_destroy(dfl_cxl_cache_class, ++ MKDEV(MAJOR(dfl_cxl_cache_devt), cxl_cache->id)); ++} ++ ++static int cxl_cache_chardev_init(struct dfl_cxl_cache *cxl_cache, ++ struct dfl_device *ddev, ++ void __iomem *mmio_base) ++{ ++ int ret; ++ ++ dev_set_drvdata(&ddev->dev, cxl_cache); ++ cxl_cache->ddev = ddev; ++ cxl_cache->mmio_base = mmio_base; ++ cxl_cache->id = dfl_cxl_cache_devices++; ++ cxl_cache->dma_regions = RB_ROOT; ++ ++ cxl_cache->rinfo.argsz = sizeof(struct dfl_cxl_cache_region_info); ++ cxl_cache->rinfo.flags = DFL_CXL_CACHE_REGION_READ | DFL_CXL_CACHE_REGION_WRITE | ++ DFL_CXL_CACHE_REGION_MMAP; ++ cxl_cache->rinfo.size = resource_size(&ddev->mmio_res); ++ cxl_cache->rinfo.offset = 0; ++ ++ cxl_cache->dev = device_create(dfl_cxl_cache_class, &ddev->dev, ++ MKDEV(MAJOR(dfl_cxl_cache_devt), cxl_cache->id), ++ cxl_cache, DFL_CXL_CACHE_DRIVER_NAME ".%d", ++ cxl_cache->id); ++ ++ if (IS_ERR(cxl_cache->dev)) { ++ ret = PTR_ERR(cxl_cache->dev); ++ dev_err(&ddev->dev, "device_create failed: %d\n", ret); ++ cxl_cache->dev = NULL; ++ return ret; ++ } ++ cxl_cache->dev->release = cxl_cache_dev_release; ++ ++ dev_dbg(cxl_cache->dev, "added cxl_cache device: %s\n", dev_name(cxl_cache->dev)); ++ ++ cdev_init(&cxl_cache->cdev, &dfl_cxl_cache_fops); ++ cxl_cache->cdev.owner = THIS_MODULE; ++ cxl_cache->cdev.ops = &dfl_cxl_cache_fops; ++ ++ ret = cdev_add(&cxl_cache->cdev, cxl_cache->dev->devt, 1); ++ if (ret) ++ dev_err(cxl_cache->dev, "cdev_add failed: %d\n", ret); ++ ++ return ret; ++} ++ ++static int dfl_cxl_cache_probe(struct dfl_device *ddev) ++{ ++ int ret = 0; ++ void __iomem *mmio_base; ++ struct dfl_cxl_cache *cxl_cache; ++ ++ mutex_lock(&dfl_cxl_cache_class_lock); ++ ++ if (!dfl_cxl_cache_class) { ++ dfl_cxl_cache_class = class_create(DFL_CXL_CACHE_DRIVER_NAME); ++ if (IS_ERR(dfl_cxl_cache_class)) { ++ ret = PTR_ERR(dfl_cxl_cache_class); ++ dfl_cxl_cache_class = NULL; ++ dev_err_probe(&ddev->dev, ret, "class_create failed\n"); ++ goto out_unlock; ++ } ++ } ++ ++ if (!MAJOR(dfl_cxl_cache_devt)) { ++ ret = alloc_chrdev_region(&dfl_cxl_cache_devt, 0, ++ MINORMASK, ++ DFL_CXL_CACHE_DRIVER_NAME); ++ if (ret) { ++ dev_err_probe(&ddev->dev, ret, "alloc_chrdev_region failed\n"); ++ dfl_cxl_cache_devt = MKDEV(0, 0); ++ goto out_unlock; ++ } ++ } ++ ++ mmio_base = devm_ioremap_resource(&ddev->dev, &ddev->mmio_res); ++ if (IS_ERR(mmio_base)) { ++ ret = PTR_ERR(mmio_base); ++ dev_err_probe(&ddev->dev, ret, "devm_ioremap_resource failed\n"); ++ goto out_unlock; ++ } ++ ++ cxl_cache = devm_kzalloc(&ddev->dev, sizeof(*cxl_cache), GFP_KERNEL); ++ if (!cxl_cache) { ++ ret = -ENOMEM; ++ goto out_unlock; ++ } ++ ++ ret = cxl_cache_chardev_init(cxl_cache, ddev, mmio_base); ++ if (ret) ++ dev_err_probe(&ddev->dev, ret, "cxl_cache_chardev_init failed\n"); ++ ++out_unlock: ++ mutex_unlock(&dfl_cxl_cache_class_lock); ++ ++ return ret; ++} ++ ++static void dfl_cxl_cache_remove(struct dfl_device *ddev) ++{ ++ struct dfl_cxl_cache *cxl_cache = dev_get_drvdata(&ddev->dev); ++ ++ mutex_lock(&dfl_cxl_cache_class_lock); ++ cxl_cache_chardev_uinit(cxl_cache); ++ ++ if (--dfl_cxl_cache_devices <= 0) { ++ if (dfl_cxl_cache_class) { ++ class_destroy(dfl_cxl_cache_class); ++ dfl_cxl_cache_class = NULL; ++ } ++ ++ if (MAJOR(dfl_cxl_cache_devt)) { ++ unregister_chrdev_region(dfl_cxl_cache_devt, MINORMASK); ++ dfl_cxl_cache_devt = MKDEV(0, 0); ++ } ++ } ++ ++ mutex_unlock(&dfl_cxl_cache_class_lock); ++} ++ ++static const struct dfl_device_id dfl_cxl_cache_ids[] = { ++ { FME_ID, FME_FEATURE_ID_CXL_CACHE }, ++ { } ++}; ++MODULE_DEVICE_TABLE(dfl, dfl_cxl_cache_ids); ++ ++static struct dfl_driver dfl_cxl_cache_driver = { ++ .drv = { ++ .name = DFL_CXL_CACHE_DRIVER_NAME, ++ }, ++ .id_table = dfl_cxl_cache_ids, ++ .probe = dfl_cxl_cache_probe, ++ .remove = dfl_cxl_cache_remove, ++}; ++module_dfl_driver(dfl_cxl_cache_driver); ++ ++MODULE_DESCRIPTION("DFL CXL Cache driver"); ++MODULE_AUTHOR("Intel Corporation"); ++MODULE_LICENSE("GPL"); +diff --git a/include/uapi/linux/fpga-dfl.h b/include/uapi/linux/fpga-dfl.h +index 868c81ff2cf7..3784f893397c 100644 +--- a/include/uapi/linux/fpga-dfl.h ++++ b/include/uapi/linux/fpga-dfl.h +@@ -9,6 +9,8 @@ + * Zhang Yi + * Wu Hao + * Xiao Guangrong ++ * Tim Whisonant ++ * Ananda Ravuri + */ + + #ifndef _UAPI_LINUX_FPGA_DFL_H +@@ -31,6 +33,7 @@ + #define DFL_FPGA_BASE 0 + #define DFL_PORT_BASE 0x40 + #define DFL_FME_BASE 0x80 ++#define DFL_CXL_CACHE_BASE 0xA0 + #define DFL_PCI_SVA_BASE 0xf8 + + /* Common IOCTLs for both FME and AFU file descriptor */ +@@ -303,4 +306,100 @@ struct dfl_fpga_fme_port_pr { + #define DFL_PCI_SVA_UNBIND_DEV _IO(DFL_FPGA_MAGIC, \ + DFL_PCI_SVA_BASE + 1) + ++ /** ++ * DFL_CXL_CACHE_GET_REGION_INFO - _IOWR(DFL_FPGA_MAGIC, DFL_CXL_CACHE_BASE + 0, ++ * struct dfl_cxl_cache_region_info) ++ * ++ * Retrieve information about a device memory region. ++ * Caller provides struct dfl_cxl_cache_region_info with flags. ++ * Driver returns the region info in other fields. ++ * Return: 0 on success, -errno on failure. ++ */ ++ ++#define DFL_CXL_CACHE_GET_REGION_INFO _IO(DFL_FPGA_MAGIC, DFL_CXL_CACHE_BASE + 0) ++ ++ /** ++ * struct dfl_cxl_cache_region_info - CXL cache region information ++ * @argsz: structure length ++ * @flags: access permission ++ * @size: region size (bytes) ++ * @offset: region offset from start of device fd ++ * ++ * to retrieve information about a device memory region ++ */ ++struct dfl_cxl_cache_region_info { ++ __u32 argsz; ++ __u32 flags; ++#define DFL_CXL_CACHE_REGION_READ BIT(0) ++#define DFL_CXL_CACHE_REGION_WRITE BIT(1) ++#define DFL_CXL_CACHE_REGION_MMAP BIT(2) ++ __u64 size; ++ __u64 offset; ++}; ++ ++/** ++ * DFL_CXL_CACHE_NUMA_BUFFER_MAP - _IOWR(DFL_FPGA_MAGIC, DFL_CXL_CACHE_BASE + 1, ++ * struct dfl_cxl_cache_buffer_map) ++ * ++ * Map the user memory per user_addr, length and numa node which are ++ * provided by caller. The driver allocates memory on the numa node, ++ * converts the user's virtual addressto a continuous physical address, ++ * and writes the physical address to the cxl cache read/write address table CSR. ++ * ++ * This interface only accepts page-size aligned user memory for mapping. ++ * Return: 0 on success, -errno on failure. ++ */ ++ ++#define DFL_ARRAY_MAX_SIZE 0x10 ++ ++#define DFL_CXL_CACHE_NUMA_BUFFER_MAP _IO(DFL_FPGA_MAGIC, DFL_CXL_CACHE_BASE + 1) ++ ++/** ++ * struct dfl_cxl_cache_buffer_map - maps user address to physical address. ++ * @argsz: structure length ++ * @flags: flags ++ * @user_addr: user mmap virtual address ++ * @length: length of mapping (bytes) ++ * @csr_array: array of region address offset ++ * ++ * maps user allocated virtual address to physical address. ++ */ ++struct dfl_cxl_cache_buffer_map { ++ __u32 argsz; ++ __u32 flags; ++ __u64 user_addr; ++ __u64 length; ++ __u64 csr_array[DFL_ARRAY_MAX_SIZE]; ++}; ++ ++/** ++ * DFL_CXL_CACHE_NUMA_BUFFER_UNMAP - _IOWR(DFL_FPGA_MAGIC, DFL_CXL_CACHE_BASE + 1, ++ * struct dfl_cxl_cache_buffer_unmap) ++ * ++ * Unmaps the user memory per user_addr and length which are provided by caller ++ * The driver deletes the physical pages of the user address and writes a zero ++ * to the read/write address table CSR. ++ * Return: 0 on success, -errno on failure. ++ */ ++ ++#define DFL_CXL_CACHE_NUMA_BUFFER_UNMAP _IO(DFL_FPGA_MAGIC, DFL_CXL_CACHE_BASE + 2) ++ ++/** ++ * struct dfl_cxl_cache_buffer_unmap - unmaps user allocated memory. ++ * @argsz: structure length ++ * @flags: flags ++ * @user_addr: user mmap virtual address ++ * @length: length of mapping (bytes) ++ * @csr_array: array of region address offset ++ * ++ * unmaps user allocated memory. ++ */ ++struct dfl_cxl_cache_buffer_unmap { ++ __u32 argsz; ++ __u32 flags; ++ __u64 user_addr; ++ __u64 length; ++ __u64 csr_array[DFL_ARRAY_MAX_SIZE]; ++}; ++ + #endif /* _UAPI_LINUX_FPGA_DFL_H */ diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0067-dt-bindings-fpga-Add-Device-Feature-List-DFL.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0067-dt-bindings-fpga-Add-Device-Feature-List-DFL.patch new file mode 100644 index 0000000..be72002 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0067-dt-bindings-fpga-Add-Device-Feature-List-DFL.patch @@ -0,0 +1,88 @@ +From 38236098c809ecb9120ac22f2c7d91cc8c813138 Mon Sep 17 00:00:00 2001 +From: Basheer Ahmed Muddebihal +Date: Fri, 3 Nov 2023 01:36:41 -0700 +Subject: [PATCH] dt-bindings: fpga: Add Device Feature List (DFL) + +The Device Feature List (DFL) defines a linked list of feature headers +within the device MMIO space, offering an extensible method for adding +features. + +Signed-off-by: Basheer Ahmed Muddebihal +--- + .../bindings/soc/intel/intel,dfl-mmio.yaml | 67 +++++++++++++++++++ + 1 file changed, 67 insertions(+) + create mode 100644 Documentation/devicetree/bindings/soc/intel/intel,dfl-mmio.yaml + +diff --git a/Documentation/devicetree/bindings/soc/intel/intel,dfl-mmio.yaml b/Documentation/devicetree/bindings/soc/intel/intel,dfl-mmio.yaml +new file mode 100644 +index 000000000000..16f181d90728 +--- /dev/null ++++ b/Documentation/devicetree/bindings/soc/intel/intel,dfl-mmio.yaml +@@ -0,0 +1,67 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: "http://devicetree.org/schemas/soc/intel/intel,dfl-mmio.yaml#" ++$schema: "http://devicetree.org/meta-schemas/core.yaml#" ++title: Device Feature List (DFL) for MMIO ++ ++maintainers: ++ - Basheer Ahmed Muddebihal ++ ++description: | ++ Device Feature List defines a linked list of feature headers within the device ++ MMIO space to provide an extensible way of adding features. Please see the link ++ for more information https://docs.kernel.org/fpga/dfl.html. ++ ++properties: ++ compatible: ++ const: intel,dfl-mmio ++ ++ reg: ++ maxItems: 1 ++ description: ++ The 'reg' property within the node serves to define the memory-mapped ++ address range for the DFL. The first value in the 'reg' property specifies ++ the starting address of the DFL, and the second value represents the ++ length of the address range from start address of the DFL. ++ ++ interrupt-parent: ++ maxItems: 1 ++ description: ++ This property establishes a reference to the Interrupt Controller Node, ++ which manages interrupts for the device. ++ ++ interrupt-user-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: ++ maxItems: 1 ++ descritpion: ++ This property indicates the starting interrupt number within the GIC where ++ FPGA-specific interrupts are mapped. ++ ++ fpga-interrupt-lines: ++ maxItems: 1 ++ descritpions: ++ This property specifies the total count of Interrupt Requests (IRQs) ++ originating from the FPGA and routed to the GIC. ++ ++required: ++ - compatible ++ - reg ++ ++additionalProperties: false ++ ++examples: ++ - | ++ dfl0: dfl@F9000000 { ++ compatible = "intel,dfl-mmio"; ++ reg = <0xF9000000 0x00002000>; ++ interrupt-parent = <&intc>; ++ interrupt-user-start = <32>; ++ fpga-interrupt-start = <49>; ++ fpga-interrupt-lines = <64>; ++ }; diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0068-fpga-dfl-Add-platform-driver-for-DFL-device-tree.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0068-fpga-dfl-Add-platform-driver-for-DFL-device-tree.patch new file mode 100644 index 0000000..89da7ff --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0068-fpga-dfl-Add-platform-driver-for-DFL-device-tree.patch @@ -0,0 +1,250 @@ +From fd15da1cf8ac3dcb84cdbb4c9677e0202dc426fe Mon Sep 17 00:00:00 2001 +From: Basheer Ahmed Muddebihal +Date: Thu, 13 Apr 2023 00:04:27 -0700 +Subject: [PATCH] fpga: dfl: Add platform driver for DFL device tree + +In order to support the integration of the Device Feature List (DFL) into +non-PCIe FPGA System-on-Chip (SoC) solutions, the Device Tree Node is used +to define the DFL location within the Memory-Mapped I/O (MMIO) space. +To process the device tree node, a driver module has been implemented and +utilizes the information within the Linux DFL framework's (dfl.ko) module +for the purpose of enumerating and managing the FPGA Features. + +Signed-off-by: Basheer Ahmed Muddebihal +--- + drivers/fpga/Kconfig | 12 +++ + drivers/fpga/Makefile | 1 + + drivers/fpga/dfl-platform.c | 189 ++++++++++++++++++++++++++++++++++++ + 3 files changed, 202 insertions(+) + create mode 100644 drivers/fpga/dfl-platform.c + +diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig +index 46a26b2c9d36..ee3ffedf5503 100644 +--- a/drivers/fpga/Kconfig ++++ b/drivers/fpga/Kconfig +@@ -232,6 +232,18 @@ config FPGA_DFL_PCI_SVA + Select this option to enable PASID and IOMMU binding of DFL-based + devices that support shared virtual memory. + ++config FPGA_DFL_PLATFORM ++ tristate "FPGA DFL Platform Driver" ++ depends on FPGA_DFL ++ depends on OF || COMPILE_TEST ++ help ++ Select this option to enable the Device Feature List (DFL) platform driver. ++ For more detailed information about DFL, please refer to the Linux DFL ++ documentation available at: . ++ ++ To compile this driver as a module, choose M here: the module will be ++ called dfl_platform. ++ + config FPGA_DFL_HSSI + tristate "FPGA DFL HSSI Driver" + depends on FPGA_DFL +diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile +index ff57d3cd034c..664ac7f6ca47 100644 +--- a/drivers/fpga/Makefile ++++ b/drivers/fpga/Makefile +@@ -56,6 +56,7 @@ obj-$(CONFIG_FPGA_DFL_NIOS_INTEL_PAC_N3000) += dfl-n3000-nios.o + # Drivers for FPGAs which implement DFL + obj-$(CONFIG_FPGA_DFL_PCI) += dfl-pci.o + obj-$(CONFIG_FPGA_DFL_PCI_SVA) += dfl-pci-sva.o ++obj-$(CONFIG_FPGA_DFL_PLATFORM) += dfl-platform.o + obj-$(CONFIG_FPGA_DFL_HSSI) += dfl-hssi.o + obj-$(CONFIG_FPGA_DFL_CXL_CACHE) += dfl-cxl-cache.o + +diff --git a/drivers/fpga/dfl-platform.c b/drivers/fpga/dfl-platform.c +new file mode 100644 +index 000000000000..28b4f25b32e2 +--- /dev/null ++++ b/drivers/fpga/dfl-platform.c +@@ -0,0 +1,189 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Driver for FPGA Device Feature List(DFL) device entry. ++ * ++ * Copyright (C) 2023 Intel Corp. ++ * ++ * Authors: ++ * Basheer Ahmed Muddebihal ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "dfl.h" ++ ++#define DRV_NAME "dfl-platform" ++ ++struct dfl_platform_drvdata { ++ struct dfl_fpga_cdev *cdev; /* container device */ ++}; ++ ++static int dfl_platform_init_drvdata(struct platform_device *pdev) ++{ ++ struct dfl_platform_drvdata *drvdata; ++ ++ drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); ++ if (!drvdata) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, drvdata); ++ ++ return 0; ++} ++ ++static void dfl_platform_remove_feature_devs(struct platform_device *pdev) ++{ ++ struct dfl_platform_drvdata *drvdata = platform_get_drvdata(pdev); ++ ++ /* remove all children feature devices */ ++ dfl_fpga_feature_devs_remove(drvdata->cdev); ++} ++ ++static int dfl_platform_process_dfl_node(struct platform_device *pdev, ++ struct dfl_fpga_enum_info *info, ++ struct resource dfl_location) ++{ ++ resource_size_t start, len; ++ void __iomem *base; ++ int ret = 0; ++ ++ start = dfl_location.start; ++ len = resource_size(&dfl_location); ++ ++ if (!request_mem_region(start, len, DRV_NAME)) { ++ dev_err(&pdev->dev, "cannot claim memory\n"); ++ return -EINVAL; ++ } ++ ++ base = of_iomap(pdev->dev.of_node, 0); ++ if (!base) { ++ dev_err(&pdev->dev, "cannot map memory\n"); ++ ret = -ENOMEM; ++ goto err_map; ++ } ++ ++ dfl_fpga_enum_info_add_dfl(info, start, len); ++ ++ /* release I/O mappings for next step enumeration */ ++ iounmap(base); ++err_map: ++ release_mem_region(start, len); ++ ++ return ret; ++} ++ ++/* enumerate feature devices under device */ ++static int dfl_platform_enumerate_feature_devs(struct platform_device *pdev, ++ struct resource dfl_location) ++{ ++ struct dfl_platform_drvdata *drvdata = platform_get_drvdata(pdev); ++ struct dfl_fpga_enum_info *info; ++ struct dfl_fpga_cdev *cdev; ++ int ret = 0; ++ ++ /* allocate enumeration info */ ++ info = dfl_fpga_enum_info_alloc(&pdev->dev); ++ if (!info) ++ return -ENOMEM; ++ ++ /* process the device tree node */ ++ ret = dfl_platform_process_dfl_node(pdev, info, dfl_location); ++ if (ret) ++ goto info_free_exit; ++ ++ /* start enumeration with prepared enumeration information */ ++ cdev = dfl_fpga_feature_devs_enumerate(info); ++ if (IS_ERR(cdev)) { ++ dev_err(&pdev->dev, "Enumeration failure\n"); ++ ret = PTR_ERR(cdev); ++ goto info_free_exit; ++ } ++ ++ drvdata->cdev = cdev; ++ ++info_free_exit: ++ dfl_fpga_enum_info_free(info); ++ ++ return ret; ++} ++ ++static int dfl_platform_probe(struct platform_device *pdev) ++{ ++ struct resource dfl_location; ++ int ret = 0; ++ ++ dev_info(&pdev->dev, "DFL Platform probe\n"); ++ ++ ret = of_address_to_resource(pdev->dev.of_node, 0, &dfl_location); ++ if (ret) { ++ dev_err_probe(&pdev->dev, ret, "Failed to get DFL location\n"); ++ return -EINVAL; ++ } ++ ++ if (dfl_location.start == 0 || dfl_location.end == 0 || ++ dfl_location.end <= dfl_location.start) ++ return -EINVAL; ++ ++ ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64)); ++ if (ret) { ++ dev_warn(&pdev->dev, "Couldn't set 64 bit DMA mask, attempting 32\n"); ++ ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); ++ if (ret) { ++ dev_err_probe(&pdev->dev, ret, "Couldn't set 32 bit DMA mask\n"); ++ return ret; ++ } ++ } ++ ++ ret = dfl_platform_init_drvdata(pdev); ++ if (ret) { ++ dev_err_probe(&pdev->dev, ret, "Failed to init drvdata %d.\n", ret); ++ return ret; ++ } ++ ++ ret = dfl_platform_enumerate_feature_devs(pdev, dfl_location); ++ if (!ret) ++ return ret; ++ ++ dev_err_probe(&pdev->dev, ret, "enumeration failure %d.\n", ret); ++ ++ return ret; ++} ++ ++static int dfl_platform_remove(struct platform_device *pdev) ++{ ++ dfl_platform_remove_feature_devs(pdev); ++ return 0; ++} ++ ++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); ++ ++static struct platform_driver dfl_platform_driver = { ++ .probe = dfl_platform_probe, ++ .remove = dfl_platform_remove, ++ .driver = { ++ .name = DRV_NAME, ++ .of_match_table = of_match_ptr(dfl_platform_match), ++ }, ++ .id_table = dfl_platform_ids, ++}; ++module_platform_driver(dfl_platform_driver); ++ ++MODULE_DESCRIPTION("FPGA DFL Platform Device Driver"); ++MODULE_AUTHOR("Intel Corporation"); ++MODULE_LICENSE("GPL"); diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0069-fpga-dfl-Introduce-new-FIU-for-enhanced-initiation-f.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0069-fpga-dfl-Introduce-new-FIU-for-enhanced-initiation-f.patch new file mode 100644 index 0000000..1ef8c5b --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0069-fpga-dfl-Introduce-new-FIU-for-enhanced-initiation-f.patch @@ -0,0 +1,359 @@ +From 03fef4875c8093c9c5ecb71250d225ea4fc180bd Mon Sep 17 00:00:00 2001 +From: Basheer Ahmed Muddebihal +Date: Wed, 19 Apr 2023 12:37:11 -0700 +Subject: [PATCH] fpga: dfl: Introduce new FIU for enhanced initiation + flexibility + +The current initiation of the Device Feature List (DFL) is limited to +FME FIU or PORT FIU. To improve flexibility, a new FPGA Interface Unit +(FIU) has been added. This FIU initiates the DFL with any Feature +serving as the Start Node in the list. + +Signed-off-by: Basheer Ahmed Muddebihal +--- + drivers/fpga/Kconfig | 10 +++ + drivers/fpga/Makefile | 3 + + drivers/fpga/dfl-priv-feat-main.c | 120 ++++++++++++++++++++++++++++++ + drivers/fpga/dfl-priv-feat.h | 27 +++++++ + drivers/fpga/dfl.c | 29 +++++++- + drivers/fpga/dfl.h | 3 + + include/linux/dfl.h | 1 + + 7 files changed, 192 insertions(+), 1 deletion(-) + create mode 100644 drivers/fpga/dfl-priv-feat-main.c + create mode 100644 drivers/fpga/dfl-priv-feat.h + +diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig +index ee3ffedf5503..f6b9499225e9 100644 +--- a/drivers/fpga/Kconfig ++++ b/drivers/fpga/Kconfig +@@ -199,6 +199,16 @@ config FPGA_DFL_AFU + to the FPGA infrastructure via a Port. There may be more than one + Port/AFU per DFL based FPGA device. + ++config FPGA_DFL_PRIV_FEAT ++ tristate "FPGA DFL PRIV FEAT Driver" ++ depends on FPGA_DFL ++ help ++ This is the driver for FPGA Private Features which will implement ++ FIU feature start. ++ ++ To compile this driver as a module, choose M here: the module will ++ be called dfl_priv_feat. ++ + 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 664ac7f6ca47..69e3b12f9c8d 100644 +--- a/drivers/fpga/Makefile ++++ b/drivers/fpga/Makefile +@@ -41,6 +41,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_FME) += dfl-fme.o ++obj-$(CONFIG_FPGA_DFL_PRIV_FEAT) += dfl-priv-feat.o + obj-$(CONFIG_FPGA_DFL_FME_MGR) += dfl-fme-mgr.o + obj-$(CONFIG_FPGA_DFL_FME_BRIDGE) += dfl-fme-br.o + obj-$(CONFIG_FPGA_DFL_FME_REGION) += dfl-fme-region.o +@@ -51,6 +52,8 @@ dfl-fme-objs += dfl-fme-perf.o + dfl-afu-objs := dfl-afu-main.o dfl-afu-region.o dfl-afu-dma-region.o + dfl-afu-objs += dfl-afu-error.o + ++dfl-priv-feat-objs := dfl-priv-feat-main.o ++ + obj-$(CONFIG_FPGA_DFL_NIOS_INTEL_PAC_N3000) += dfl-n3000-nios.o + + # Drivers for FPGAs which implement DFL +diff --git a/drivers/fpga/dfl-priv-feat-main.c b/drivers/fpga/dfl-priv-feat-main.c +new file mode 100644 +index 000000000000..25ee7e34a022 +--- /dev/null ++++ b/drivers/fpga/dfl-priv-feat-main.c +@@ -0,0 +1,120 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Driver for FPGA Private Features ++ * ++ * Copyright (C) 2023 Intel Corp. ++ * ++ * Authors: ++ * Basheer Ahmed Muddebihal ++ */ ++ ++#include ++#include ++ ++#include "dfl.h" ++#include "dfl-priv-feat.h" ++ ++static ssize_t ++guid_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); ++} ++static DEVICE_ATTR_RO(guid); ++ ++static struct attribute *dfl_priv_feat_attrs[] = { ++ &dev_attr_guid.attr, ++ NULL, ++}; ++ ++static const struct attribute_group dfl_priv_feat_group = { ++ .attrs = dfl_priv_feat_attrs, ++}; ++ ++static struct dfl_feature_driver dfl_priv_feat_drvs[] = { ++ { ++ .id_table = NULL, ++ .ops = NULL, ++ }, ++}; ++ ++static int dfl_priv_feat_dev_init(struct platform_device *pdev) ++{ ++ struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); ++ struct dfl_feature_dev_data *fdata = pdata->fdata; ++ struct dfl_priv_feat *pfeat; ++ ++ pfeat = devm_kzalloc(&pdev->dev, sizeof(*pfeat), GFP_KERNEL); ++ if (!pfeat) ++ return -ENOMEM; ++ ++ pfeat->pdata = pdata; ++ ++ mutex_lock(&fdata->lock); ++ dfl_fpga_fdata_set_private(fdata, pfeat); ++ mutex_unlock(&fdata->lock); ++ ++ return 0; ++} ++ ++static void dfl_priv_feat_dev_destroy(struct platform_device *pdev) ++{ ++ struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); ++ struct dfl_feature_dev_data *fdata = pdata->fdata; ++ ++ mutex_lock(&fdata->lock); ++ dfl_fpga_fdata_set_private(fdata, NULL); ++ mutex_unlock(&fdata->lock); ++} ++ ++static int dfl_priv_feat_probe(struct platform_device *pdev) ++{ ++ int ret; ++ ++ ret = dfl_priv_feat_dev_init(pdev); ++ if (ret) ++ goto exit; ++ ++ ret = dfl_fpga_dev_feature_init(pdev, dfl_priv_feat_drvs); ++ if (ret) ++ goto dev_destroy; ++ ++ return 0; ++ ++dev_destroy: ++ dfl_priv_feat_dev_destroy(pdev); ++exit: ++ return ret; ++} ++ ++static int dfl_priv_feat_remove(struct platform_device *pdev) ++{ ++ dfl_fpga_dev_feature_uinit(pdev); ++ dfl_priv_feat_dev_destroy(pdev); ++ ++ return 0; ++} ++ ++static const struct attribute_group *dfl_priv_feat_dev_groups[] = { ++ &dfl_priv_feat_group, ++ NULL ++}; ++ ++static struct platform_driver dfl_priv_feat_driver = { ++ .driver = { ++ .name = DFL_FPGA_FEATURE_DEV_PRIV_FEAT, ++ .dev_groups = dfl_priv_feat_dev_groups, ++ }, ++ .probe = dfl_priv_feat_probe, ++ .remove = dfl_priv_feat_remove, ++}; ++ ++module_platform_driver(dfl_priv_feat_driver); ++ ++MODULE_DESCRIPTION("FPGA Privare Feature driver"); ++MODULE_AUTHOR("Intel Corporation"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/fpga/dfl-priv-feat.h b/drivers/fpga/dfl-priv-feat.h +new file mode 100644 +index 000000000000..6dc665e5dd15 +--- /dev/null ++++ b/drivers/fpga/dfl-priv-feat.h +@@ -0,0 +1,27 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * Header file for FPGA Feature Driver ++ * ++ * Copyright (C) 2023 Intel Corp. ++ * ++ */ ++ ++#ifndef __DFL_PRIV_FEAT_H ++#define __DFL_PRIV_FEAT_H ++ ++/** ++ * struct dfl_priv_feat - dfl feature private data ++ * ++ * @mgr: FPGA Feature platform device. ++ * @region_list: linked list of FME's FPGA regions. ++ * @bridge_list: linked list of FME's FPGA bridges. ++ * @pdata: feature platform device's pdata. ++ */ ++struct dfl_priv_feat { ++ struct platform_device *mgr; ++ struct list_head region_list; ++ struct list_head bridge_list; ++ struct dfl_feature_platform_data *pdata; ++}; ++ ++#endif /* __DFL_PRIV_FEAT_H */ +diff --git a/drivers/fpga/dfl.c b/drivers/fpga/dfl.c +index 3a27bdeeff17..5ce4c6c16ede 100644 +--- a/drivers/fpga/dfl.c ++++ b/drivers/fpga/dfl.c +@@ -35,6 +35,7 @@ static DEFINE_MUTEX(dfl_id_mutex); + enum dfl_fpga_devt_type { + DFL_FPGA_DEVT_FME, + DFL_FPGA_DEVT_PORT, ++ DFL_FPGA_DEVT_PRIV_FEAT, + DFL_FPGA_DEVT_MAX, + }; + +@@ -43,6 +44,7 @@ static struct lock_class_key dfl_pdata_keys[DFL_ID_MAX]; + static const char *dfl_pdata_key_strings[DFL_ID_MAX] = { + "dfl-fme-pdata", + "dfl-port-pdata", ++ "dfl-priv-feat-pdata" + }; + + /** +@@ -65,6 +67,8 @@ static struct dfl_dev_info dfl_devs[] = { + .devt_type = DFL_FPGA_DEVT_FME}, + {.name = DFL_FPGA_FEATURE_DEV_PORT, .dfh_id = DFH_ID_FIU_PORT, + .devt_type = DFL_FPGA_DEVT_PORT}, ++ {.name = DFL_FPGA_FEATURE_DEV_PRIV_FEAT, .dfh_id = DFH_ID_FIU_PRIV_FEAT, ++ .devt_type = DFL_FPGA_DEVT_PORT}, + }; + + /** +@@ -81,6 +85,7 @@ struct dfl_chardev_info { + static struct dfl_chardev_info dfl_chrdevs[] = { + {.name = DFL_FPGA_FEATURE_DEV_FME}, + {.name = DFL_FPGA_FEATURE_DEV_PORT}, ++ {.name = DFL_FPGA_FEATURE_DEV_PRIV_FEAT}, + }; + + static void dfl_ids_init(void) +@@ -779,6 +784,15 @@ static void dfl_fpga_cdev_add_port_data(struct dfl_fpga_cdev *cdev, + mutex_unlock(&cdev->lock); + } + ++static void dfl_fpga_cdev_add_priv_feat_data(struct dfl_fpga_cdev *cdev, ++ struct dfl_feature_dev_data *fdata) ++ ++{ ++ mutex_lock(&cdev->lock); ++ list_add(&fdata->node, &cdev->priv_feat_dev_list); ++ mutex_unlock(&cdev->lock); ++} ++ + static struct dfl_feature_dev_data * + binfo_create_feature_dev_data(struct build_feature_devs_info *binfo) + { +@@ -967,6 +981,8 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo) + + if (binfo->type == PORT_ID) + dfl_fpga_cdev_add_port_data(binfo->cdev, fdata); ++ else if (binfo->type == PRIV_FEAT_ID) ++ dfl_fpga_cdev_add_priv_feat_data(binfo->cdev, fdata); + else + binfo->cdev->fme_dev = get_device(&fdata->dev->dev); + +@@ -1448,12 +1464,21 @@ static int parse_feature_fiu(struct build_feature_devs_info *binfo, + static int parse_feature_private(struct build_feature_devs_info *binfo, + resource_size_t ofst) + { +- if (!is_feature_dev_detected(binfo)) { ++ u8 dfh_ver; ++ u64 v; ++ ++ v = readq(binfo->ioaddr + DFH); ++ dfh_ver = FIELD_GET(DFH_VERSION, v); ++ ++ if (dfh_ver == 0 && !is_feature_dev_detected(binfo)) { + dev_err(binfo->dev, "the private feature 0x%x does not belong to any AFU.\n", + feature_id(readq(binfo->ioaddr + ofst))); + return -EINVAL; + } + ++ if (dfh_ver == 1) ++ binfo->type = PRIV_FEAT_ID; ++ + return create_feature_instance(binfo, ofst, 0, 0); + } + +@@ -1687,6 +1712,8 @@ dfl_fpga_feature_devs_enumerate(struct dfl_fpga_enum_info *info) + mutex_init(&cdev->lock); + INIT_LIST_HEAD(&cdev->port_dev_list); + ++ INIT_LIST_HEAD(&cdev->priv_feat_dev_list); ++ + cdev->region = fpga_region_register(info->dev, NULL, NULL); + if (IS_ERR(cdev->region)) { + ret = PTR_ERR(cdev->region); +diff --git a/drivers/fpga/dfl.h b/drivers/fpga/dfl.h +index f79ba69f170b..ac6ed3b410fd 100644 +--- a/drivers/fpga/dfl.h ++++ b/drivers/fpga/dfl.h +@@ -72,6 +72,7 @@ + #define DFH_ID GENMASK_ULL(11, 0) /* Feature ID */ + #define DFH_ID_FIU_FME 0 + #define DFH_ID_FIU_PORT 1 ++#define DFH_ID_FIU_PRIV_FEAT 2 + #define DFH_REVISION GENMASK_ULL(15, 12) /* Feature revision */ + #define DFH_NEXT_HDR_OFST GENMASK_ULL(39, 16) /* Offset to next DFH */ + #define DFH_EOL BIT_ULL(40) /* End of list */ +@@ -416,6 +417,7 @@ struct dfl_feature_ops { + + #define DFL_FPGA_FEATURE_DEV_FME "dfl-fme" + #define DFL_FPGA_FEATURE_DEV_PORT "dfl-port" ++#define DFL_FPGA_FEATURE_DEV_PRIV_FEAT "dfl-priv-feat" + + void dfl_fpga_dev_feature_uinit(struct platform_device *pdev); + int dfl_fpga_dev_feature_init(struct platform_device *pdev, +@@ -579,6 +581,7 @@ struct dfl_fpga_cdev { + struct device *fme_dev; + struct mutex lock; + struct list_head port_dev_list; ++ struct list_head priv_feat_dev_list; + int released_port_num; + }; + +diff --git a/include/linux/dfl.h b/include/linux/dfl.h +index f230befc9efe..6d66aa4ad302 100644 +--- a/include/linux/dfl.h ++++ b/include/linux/dfl.h +@@ -17,6 +17,7 @@ + enum dfl_id_type { + FME_ID = 0, + PORT_ID = 1, ++ PRIV_FEAT_ID = 2, + DFL_ID_MAX, + }; + diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0070-fpga-dfl-Add-support-for-DFH-Private-feature-type.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0070-fpga-dfl-Add-support-for-DFH-Private-feature-type.patch new file mode 100644 index 0000000..5890bc8 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0070-fpga-dfl-Add-support-for-DFH-Private-feature-type.patch @@ -0,0 +1,49 @@ +From 890357f66e44f36474415148daf7eaa3532093cf Mon Sep 17 00:00:00 2001 +From: Basheer Ahmed Muddebihal +Date: Fri, 27 Oct 2023 17:21:53 -0700 +Subject: [PATCH] fpga: dfl: Add support for DFH Private feature type + +Allow a Device Feature List (DFL) to start with a Device Feature Header +(DFH) of type Private feature in addition to the currently supported +type, Feature Management Entity (FME) or Port. + +Signed-off-by: Basheer Ahmed Muddebihal +--- + drivers/fpga/dfl-pci.c | 5 +++++ + drivers/fpga/dfl.h | 7 +++++++ + 2 files changed, 12 insertions(+) + +diff --git a/drivers/fpga/dfl-pci.c b/drivers/fpga/dfl-pci.c +index 7eb38a6a6bc1..347b00273604 100644 +--- a/drivers/fpga/dfl-pci.c ++++ b/drivers/fpga/dfl-pci.c +@@ -313,6 +313,11 @@ static int find_dfls_by_default(struct pci_dev *pcidev, + start = pci_resource_start(pcidev, 0); + len = pci_resource_len(pcidev, 0); + ++ dfl_fpga_enum_info_add_dfl(info, start, len); ++ } else if (dfl_feature_is_private(base)) { ++ start = pci_resource_start(pcidev, 0); ++ len = pci_resource_len(pcidev, 0); ++ + dfl_fpga_enum_info_add_dfl(info, start, len); + } else { + v = readq(base + DFH); +diff --git a/drivers/fpga/dfl.h b/drivers/fpga/dfl.h +index ac6ed3b410fd..21f3c6736c35 100644 +--- a/drivers/fpga/dfl.h ++++ b/drivers/fpga/dfl.h +@@ -496,6 +496,13 @@ static inline bool dfl_feature_is_port(void __iomem *base) + (FIELD_GET(DFH_ID, v) == DFH_ID_FIU_PORT); + } + ++static inline bool dfl_feature_is_private(void __iomem *base) ++{ ++ u64 v = readq(base + DFH); ++ ++ return (FIELD_GET(DFH_TYPE, v) == DFH_TYPE_PRIVATE); ++} ++ + static inline u8 dfl_feature_revision(void __iomem *base) + { + return (u8)FIELD_GET(DFH_REVISION, readq(base + DFH)); diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0071-security-Add-intel-security-policy-file.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0071-security-Add-intel-security-policy-file.patch new file mode 100644 index 0000000..a260d0f --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0071-security-Add-intel-security-policy-file.patch @@ -0,0 +1,25 @@ +From 7dd4db4ed78348935f7b44aa8962dc6a2e42d25d Mon Sep 17 00:00:00 2001 +From: Russ Weight +Date: Tue, 15 Aug 2023 09:54:18 -0700 +Subject: [PATCH] security: Add intel security policy file + +Add Intel standard SECURITY.md file to communicate Intel's Security +Policy. + +Signed-off-by: Russ Weight +--- + SECURITY.md | 5 +++++ + 1 file changed, 5 insertions(+) + create mode 100644 SECURITY.md + +diff --git a/SECURITY.md b/SECURITY.md +new file mode 100644 +index 000000000000..4988e77be87d +--- /dev/null ++++ b/SECURITY.md +@@ -0,0 +1,5 @@ ++# Security Policy # ++Intel is committed to rapidly addressing security vulnerabilities affecting our customers and providing clear guidance on the solution, impact, severity and mitigation. ++ ++## Reporting a Vulnerability ## ++Please report any security vulnerabilities in this project **[utilizing the guidelines here](https://www.intel.com/content/www/us/en/security-center/vulnerability-handling-guidelines.html)**. diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0072-configs-DFL-driver-config-options.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0072-configs-DFL-driver-config-options.patch new file mode 100644 index 0000000..ff3c948 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0072-configs-DFL-driver-config-options.patch @@ -0,0 +1,117 @@ +From b140ea1d2f18fbea0fb18bc8d47eff5a914c4e6b Mon Sep 17 00:00:00 2001 +From: Russ Weight +Date: Mon, 5 Apr 2021 11:13:31 -0700 +Subject: [PATCH] configs: DFL driver config options + +Having separate config files means having a lot of duplicate options +listed in both files. It also means that both config files need to be +used in order to build all of the DFL support into a single kernel. + +This change merges the configs into a single list of config options and +renames the readme.txt file to README. + +The n3000_d5005_defconfig and n5010_defconfig files are now deprecated +and will be removed soon. + +Signed-off-by: Russ Weight +--- + configs/README | 13 +++++++++ + configs/dfl-config | 69 ++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 82 insertions(+) + create mode 100644 configs/README + create mode 100644 configs/dfl-config + +diff --git a/configs/README b/configs/README +new file mode 100644 +index 000000000000..d100a073056b +--- /dev/null ++++ b/configs/README +@@ -0,0 +1,13 @@ ++This directory contains the dfl-config file which includes the config ++options required to enable the Device Feature List (DFL) driver support. ++By design the DFL driver collection is extendable and it is anticipated ++that new drivers will be added to the collection. ++ ++The dfl related config options are intended to be appended to a base kernel ++configuration. For example the following commands would modify an existing ++kernel configuration to enable support DFL cards. ++ ++ # cd kernel_source_directory ++ # cp /boot/config-`uname -r` .config ++ # cat configs/dfl-config >> .config ++ # make olddefconfig +diff --git a/configs/dfl-config b/configs/dfl-config +new file mode 100644 +index 000000000000..b5d7b1c4e249 +--- /dev/null ++++ b/configs/dfl-config +@@ -0,0 +1,69 @@ ++# Core FPGA support ++ ++CONFIG_FPGA=m ++CONFIG_FPGA_BRIDGE=m ++CONFIG_FPGA_REGION=m ++ ++# Core DFL support ++ ++CONFIG_FPGA_DFL=m ++CONFIG_FPGA_DFL_PCI=m ++CONFIG_FPGA_DFL_PCI_SVA=m ++CONFIG_FPGA_DFL_PLATFORM=m ++CONFIG_FPGA_DFL_AFU=m ++CONFIG_FPGA_DFL_FME=m ++CONFIG_FPGA_DFL_PRIV_FEAT=m ++CONFIG_FPGA_DFL_FME_MGR=m ++CONFIG_FPGA_DFL_FME_BRIDGE=m ++CONFIG_FPGA_DFL_FME_REGION=m ++ ++CONFIG_SPI_ALTERA=m ++CONFIG_SPI_ALTERA_DFL=m ++CONFIG_SERIAL_8250_DFL=m ++CONFIG_FPGA_M10_BMC_SEC_UPDATE=m ++ ++CONFIG_MFD_INTEL_M10_BMC_SPI=m ++CONFIG_SENSORS_INTEL_M10_BMC_HWMON=m ++ ++CONFIG_FW_UPLOAD=y ++ ++CONFIG_UIO_DFL=m ++ ++# N3000 / D5005 Support ++ ++CONFIG_MEMORY=y ++CONFIG_IIO_INTERRUPT_TRIGGER=m ++ ++CONFIG_FPGA_DFL_EMIF=m ++CONFIG_FPGA_DFL_NIOS_INTEL_PAC_N3000=m ++CONFIG_FPGA_DFL_HSSI=m ++CONFIG_S10HSSI=m ++CONFIG_INTEL_S10_PHY=m ++ ++# N5010 Support ++ ++CONFIG_FIXED_PHY=y ++CONFIG_N5010_HSSI=m ++CONFIG_N5010_PHY=m ++CONFIG_NET_VENDOR_SILICOM=y ++ ++# PMCI device support ++ ++CONFIG_MFD_INTEL_M10_BMC_LOG=m ++CONFIG_MFD_INTEL_M10_BMC_PMCI=m ++CONFIG_QSFP_MEM=m ++CONFIG_QSFP_MEM_DFL=m ++ ++# ToD device support ++ ++CONFIG_PTP_DFL_TOD=m ++ ++# CXL cache support ++ ++CONFIG_FPGA_DFL_CXL_CACHE=m ++ ++# Test configs - not required for production environments ++ ++CONFIG_IKCONFIG=y ++CONFIG_IKCONFIG_PROC=y ++CONFIG_TEST_FIRMWARE=m diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0073-fpga-dfl-pci-sva-depend-on-CONFIG_IOMMU_SVA.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0073-fpga-dfl-pci-sva-depend-on-CONFIG_IOMMU_SVA.patch new file mode 100644 index 0000000..9b7ec09 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0073-fpga-dfl-pci-sva-depend-on-CONFIG_IOMMU_SVA.patch @@ -0,0 +1,26 @@ +From f94046db2243ae6bc89df9b8d98ff2dbab3423b2 Mon Sep 17 00:00:00 2001 +From: Peter Colberg +Date: Wed, 6 Dec 2023 16:40:27 -0500 +Subject: [PATCH] fpga: dfl-pci-sva: depend on CONFIG_IOMMU_SVA + +struct mm_struct only defines the member pasid when CONFIG_IOMMU_SVA +is enabled, e.g., by enabling CONFIG_INTEL_IOMMU_SVM. + +Signed-off-by: Peter Colberg +--- + drivers/fpga/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig +index f6b9499225e9..7031cb5485fb 100644 +--- a/drivers/fpga/Kconfig ++++ b/drivers/fpga/Kconfig +@@ -237,7 +237,7 @@ config FPGA_DFL_PCI + + config FPGA_DFL_PCI_SVA + tristate "FPGA DFL PCIe Shared Virtual Addressing Device Driver" +- depends on PCI && FPGA_DFL ++ depends on PCI && FPGA_DFL && IOMMU_SVA + help + Select this option to enable PASID and IOMMU binding of DFL-based + devices that support shared virtual memory. diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0074-configs-enable-CONFIG_INTEL_IOMMU_SVM.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0074-configs-enable-CONFIG_INTEL_IOMMU_SVM.patch new file mode 100644 index 0000000..34459dc --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0074-configs-enable-CONFIG_INTEL_IOMMU_SVM.patch @@ -0,0 +1,26 @@ +From dd48ce5e8af867858c11f815a198c96e4b0d55ad Mon Sep 17 00:00:00 2001 +From: Peter Colberg +Date: Wed, 6 Dec 2023 16:51:45 -0500 +Subject: [PATCH] configs: enable CONFIG_INTEL_IOMMU_SVM + +This implicitly enables CONFIG_IOMMU_SVA which is a prerequisite of +CONFIG_FPGA_DFL_PCI_SVA. The option CONFIG_INTEL_IOMMU_SVM is enabled +in current RHEL 8 and Ubuntu 22.04 kernels. + +Signed-off-by: Peter Colberg +--- + configs/dfl-config | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/configs/dfl-config b/configs/dfl-config +index b5d7b1c4e249..a7a5e93fb918 100644 +--- a/configs/dfl-config ++++ b/configs/dfl-config +@@ -8,6 +8,7 @@ CONFIG_FPGA_REGION=m + + CONFIG_FPGA_DFL=m + CONFIG_FPGA_DFL_PCI=m ++CONFIG_INTEL_IOMMU_SVM=y + CONFIG_FPGA_DFL_PCI_SVA=m + CONFIG_FPGA_DFL_PLATFORM=m + CONFIG_FPGA_DFL_AFU=m diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0075-fpga-dfl-afu-update-initialization-of-port_hdr-drive.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0075-fpga-dfl-afu-update-initialization-of-port_hdr-drive.patch new file mode 100644 index 0000000..cf983aa --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0075-fpga-dfl-afu-update-initialization-of-port_hdr-drive.patch @@ -0,0 +1,44 @@ +From 9d43fdcfb5374f5428dbd0023230b8f7e703f2d7 Mon Sep 17 00:00:00 2001 +From: Matthew Gerlach +Date: Thu, 7 Dec 2023 14:44:05 -0800 +Subject: [PATCH] fpga: dfl: afu: update initialization of port_hdr driver + +Revision 2 of the Device Feature List (DFL) Port feature has +slightly different requirements than revision 1. Revision 2 +does not need the port to reset at driver startup. In fact, +performing a port reset during driver initialization can cause +driver race conditions when the port is connected to a different +PCIe Physical Function (PF) than the management PF performing +the actual port reset. + +Signed-off-by: Matthew Gerlach +--- + drivers/fpga/dfl-afu-main.c | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +diff --git a/drivers/fpga/dfl-afu-main.c b/drivers/fpga/dfl-afu-main.c +index 2f54cbb78a06..c3d034202131 100644 +--- a/drivers/fpga/dfl-afu-main.c ++++ b/drivers/fpga/dfl-afu-main.c +@@ -422,7 +422,20 @@ static const struct attribute_group port_hdr_group = { + static int port_hdr_init(struct platform_device *pdev, + struct dfl_feature *feature) + { +- port_reset(pdev); ++ struct dfl_feature_dev_data *fdata; ++ void __iomem *base; ++ u8 rev; ++ ++ fdata = to_dfl_feature_dev_data(&pdev->dev); ++ ++ base = dfl_get_feature_ioaddr_by_id(fdata, PORT_FEATURE_ID_HEADER); ++ ++ rev = dfl_feature_revision(base); ++ ++ if (rev < 2) ++ port_reset(pdev); ++ else if (rev > 2) ++ dev_info(&pdev->dev, "unexpected port feature revision, %u\n", rev); + + return 0; + } diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0076-fpga-dfl-cxl-cache-include-linux-slab.h.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0076-fpga-dfl-cxl-cache-include-linux-slab.h.patch new file mode 100644 index 0000000..49409bf --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0076-fpga-dfl-cxl-cache-include-linux-slab.h.patch @@ -0,0 +1,24 @@ +From 46eafb15fc3dab19812a4ca134555afa3ebd39ef Mon Sep 17 00:00:00 2001 +From: Peter Colberg +Date: Thu, 7 Dec 2023 14:55:17 -0500 +Subject: [PATCH] fpga: dfl-cxl-cache: include linux/slab.h + +linux/slab.h is needed for kzalloc() and kfree(). + +Signed-off-by: Peter Colberg +--- + drivers/fpga/dfl-cxl-cache.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/fpga/dfl-cxl-cache.c b/drivers/fpga/dfl-cxl-cache.c +index 1e6222e039b2..13d07ba01512 100644 +--- a/drivers/fpga/dfl-cxl-cache.c ++++ b/drivers/fpga/dfl-cxl-cache.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + #include + #include + diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0077-fpga-dfl-pci-sva-include-linux-module.h.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0077-fpga-dfl-pci-sva-include-linux-module.h.patch new file mode 100644 index 0000000..104c9d1 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0077-fpga-dfl-pci-sva-include-linux-module.h.patch @@ -0,0 +1,24 @@ +From 147ee2330347758525ef069b9c524994fa09538a Mon Sep 17 00:00:00 2001 +From: Peter Colberg +Date: Thu, 7 Dec 2023 14:55:50 -0500 +Subject: [PATCH] fpga: dfl-pci-sva: include linux/module.h + +linux/module.h is needed for module_*() and MODULE_*(). + +Signed-off-by: Peter Colberg +--- + drivers/fpga/dfl-pci-sva.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/fpga/dfl-pci-sva.c b/drivers/fpga/dfl-pci-sva.c +index 0c75f17c93eb..d9aaffd60975 100644 +--- a/drivers/fpga/dfl-pci-sva.c ++++ b/drivers/fpga/dfl-pci-sva.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + #include + #include + #include diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0078-fpga-dfl-Fix-the-dfl-dev-type-to-Privare-Feature.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0078-fpga-dfl-Fix-the-dfl-dev-type-to-Privare-Feature.patch new file mode 100644 index 0000000..aecf2c7 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0078-fpga-dfl-Fix-the-dfl-dev-type-to-Privare-Feature.patch @@ -0,0 +1,26 @@ +From 7afb79a21a9245b47b01886e56385fd2a19d6f50 Mon Sep 17 00:00:00 2001 +From: Basheer Ahmed Muddebihal +Date: Wed, 13 Dec 2023 12:34:23 -0800 +Subject: [PATCH] fpga: dfl: Fix the dfl dev type to Privare Feature + +The device type was set to Port Type and changed to Private to reflect the correct +device type. + +Signed-off-by: Basheer Ahmed Muddebihal +--- + drivers/fpga/dfl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/fpga/dfl.c b/drivers/fpga/dfl.c +index 5ce4c6c16ede..97cbac8e1b30 100644 +--- a/drivers/fpga/dfl.c ++++ b/drivers/fpga/dfl.c +@@ -68,7 +68,7 @@ static struct dfl_dev_info dfl_devs[] = { + {.name = DFL_FPGA_FEATURE_DEV_PORT, .dfh_id = DFH_ID_FIU_PORT, + .devt_type = DFL_FPGA_DEVT_PORT}, + {.name = DFL_FPGA_FEATURE_DEV_PRIV_FEAT, .dfh_id = DFH_ID_FIU_PRIV_FEAT, +- .devt_type = DFL_FPGA_DEVT_PORT}, ++ .devt_type = DFL_FPGA_DEVT_PRIV_FEAT}, + }; + + /** diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0079-mfd-intel-m10-bmc-Removing-support-for-SDM-with-PMCI.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0079-mfd-intel-m10-bmc-Removing-support-for-SDM-with-PMCI.patch new file mode 100644 index 0000000..b811acf --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0079-mfd-intel-m10-bmc-Removing-support-for-SDM-with-PMCI.patch @@ -0,0 +1,57 @@ +From 99d72aa195a3317abab409c41402124fc17212f0 Mon Sep 17 00:00:00 2001 +From: KrishnaSimmadhari <91877513+KrishnaSimmadhari@users.noreply.github.com> +Date: Thu, 14 Dec 2023 21:36:17 +0530 +Subject: [PATCH] mfd: intel-m10-bmc: Removing support for SDM with PMCI for + CMC (#352) + +Removing support for secure data manager for CMC as CMC does not support secure +updates using root key hashes. + +Signed-off-by: Krishna Kumar S R +--- + drivers/fpga/intel-m10-bmc-sec-update.c | 11 +++++++++++ + drivers/mfd/intel-m10-bmc-pmci.c | 2 +- + 2 files changed, 12 insertions(+), 1 deletion(-) + +diff --git a/drivers/fpga/intel-m10-bmc-sec-update.c b/drivers/fpga/intel-m10-bmc-sec-update.c +index 605574796617..bc67f642bfda 100644 +--- a/drivers/fpga/intel-m10-bmc-sec-update.c ++++ b/drivers/fpga/intel-m10-bmc-sec-update.c +@@ -1590,6 +1590,13 @@ static const struct m10bmc_sec_ops m10sec_n6000_ops = { + .sec_visible = true, + }; + ++static const struct m10bmc_sec_ops m10sec_cmc_ops = { ++ .rsu_status = m10bmc_sec_n6000_rsu_status, ++ .image_load = n6000_image_load_hndlrs, ++ .poc = &pmci_power_on_image, ++ .sec_visible = false, ++}; ++ + #define SEC_UPDATE_LEN_MAX 32 + static int m10bmc_sec_probe(struct platform_device *pdev) + { +@@ -1675,6 +1682,10 @@ static const struct platform_device_id intel_m10bmc_sec_ids[] = { + .name = "n6000bmc-sec-update", + .driver_data = (kernel_ulong_t)&m10sec_n6000_ops, + }, ++ { ++ .name = "cmcbmc-sec-update", ++ .driver_data = (kernel_ulong_t)&m10sec_cmc_ops, ++ }, + { } + }; + MODULE_DEVICE_TABLE(platform, intel_m10bmc_sec_ids); +diff --git a/drivers/mfd/intel-m10-bmc-pmci.c b/drivers/mfd/intel-m10-bmc-pmci.c +index 7272d35ef74b..f6df2bdc85c8 100644 +--- a/drivers/mfd/intel-m10-bmc-pmci.c ++++ b/drivers/mfd/intel-m10-bmc-pmci.c +@@ -263,7 +263,7 @@ static struct mfd_cell m10bmc_pmci_c6100_bmc_subdevs[] = { + + static struct mfd_cell m10bmc_pmci_cmc_bmc_subdevs[] = { + { .name = "cmcbmc-hwmon" }, +- { .name = "n6000bmc-sec-update" }, ++ { .name = "cmcbmc-sec-update" }, + { .name = "cmcbmc-log" }, + }; + diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0080-Documentation-fpga-dfl-add-AFU-feature-list-details.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0080-Documentation-fpga-dfl-add-AFU-feature-list-details.patch new file mode 100644 index 0000000..54e0d0d --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0080-Documentation-fpga-dfl-add-AFU-feature-list-details.patch @@ -0,0 +1,66 @@ +From 493dc5c660b0ce2e0b4a2d3a18e2f63f2df91456 Mon Sep 17 00:00:00 2001 +From: Michael Adler +Date: Fri, 15 Dec 2023 12:13:05 -0500 +Subject: [PATCH] Documentation: fpga: dfl: add AFU feature list details + +Describe parent/child AFU port relationship. + +Signed-off-by: Michael Adler +--- + Documentation/fpga/dfl.rst | 36 +++++++++++++++++++++++++++++++++++- + 1 file changed, 35 insertions(+), 1 deletion(-) + +diff --git a/Documentation/fpga/dfl.rst b/Documentation/fpga/dfl.rst +index bd69d16c1de4..1d1f66dfc986 100644 +--- a/Documentation/fpga/dfl.rst ++++ b/Documentation/fpga/dfl.rst +@@ -280,6 +280,40 @@ used for accelerator-specific control registers. + User-space applications can acquire exclusive access to an AFU attached to a + port by using open() on the port device node and release it using close(). + ++AFU MMIO space must begin with a feature list, either version 0 or 1. The GUID ++at the head of an AFU feature list defines the GUID with which the AFU is ++discovered. Within the first DFH: ++ ++- The feature type is 1 (AFU) ++- Revision may be an AFU-private version number ++- ID is normally 0 ++ ++AFUs that require connections through multiple PCIe functions define a ++parent/child relationship. A parent AFU must use a version 1 feature at ++the head of its feature list. Children are enumerated by their GUIDs as ++parameters in the parent's version 1 header: ++ ++- The parameter ID is 2, version 0 (see ++ https://github.com/OFS/dfl-feature-id/blob/main/dfl-param-ids.rst) ++- The parameter's payload is a list of child GUID_L and GUID_H pairs ++- The parameter's next field (payload size in 8 byte words) indicates ++ the number of children: two 8 byte words for each child ++ ++Child AFUs may have either version 0 or version 1 headers: ++ ++- The feature type is 1 (AFU) ++- ID is normally 1 ++- The GUID must match a GUID from the parent's child list parameter ++ ++Unlike normal AFUs, which may be replicated in hardware and expose the ++same GUID multiple times, child GUIDs must typically be unique. A given ++parent AFU normally depends on a specific instance of an associated child. ++While an AFU's children are often located on the same FPGA, it is not ++a requirement. With multiple FPGAs in a system, children will be ++discovered with normal AFU GUID searches and may be found anywhere. ++Attempting to open a parent AFU will fail if the children can not be ++found. ++ + The following functions are exposed through ioctls: + + - Get driver API version (DFL_FPGA_GET_API_VERSION) +@@ -641,7 +675,7 @@ could be a reference. + + Please refer to below link to existing feature id table and guide for new feature + ids application. +-https://github.com/OPAE/dfl-feature-id ++https://github.com/OFS/dfl-feature-id + + + Location of DFLs on a PCI Device diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0081-fpga-dfl-cxl-cache-make-pages-readonly-when-biased-t.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0081-fpga-dfl-cxl-cache-make-pages-readonly-when-biased-t.patch new file mode 100644 index 0000000..967f217 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0081-fpga-dfl-cxl-cache-make-pages-readonly-when-biased-t.patch @@ -0,0 +1,199 @@ +From 5c79827e5c720ad5c8fa50f937a122641b23bee8 Mon Sep 17 00:00:00 2001 +From: Tim Whisonant +Date: Tue, 5 Dec 2023 17:28:29 +0000 +Subject: [PATCH] fpga: dfl-cxl-cache: make pages readonly when biased toward + device + +When the device owns the memory, make the pages read only by the +host in order to cause a segmentation fault, instead of a machine +hang, when host writes to the device memory. + +Signed-off-by: Matthew Gerlach +--- + drivers/fpga/dfl-cxl-cache.c | 98 ++++++++++++++++++++++++++++++++--- + include/uapi/linux/fpga-dfl.h | 1 + + 2 files changed, 92 insertions(+), 7 deletions(-) + +diff --git a/drivers/fpga/dfl-cxl-cache.c b/drivers/fpga/dfl-cxl-cache.c +index 13d07ba01512..632444a447c3 100644 +--- a/drivers/fpga/dfl-cxl-cache.c ++++ b/drivers/fpga/dfl-cxl-cache.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -33,6 +34,7 @@ + #define FME_FEATURE_ID_CXL_CACHE 0x25 + + struct dfl_cxl_cache_buffer_region { ++ u32 flags; + u64 user_addr; + u64 length; + struct page **pages; +@@ -137,12 +139,14 @@ static int cxl_cache_dma_pin_pages(struct dfl_cxl_cache *cxl_cache, + struct dfl_cxl_cache_buffer_region *region) + { + int ret, pinned; +- const unsigned int flags = FOLL_LONGTERM | FOLL_WRITE; ++ unsigned int flags = FOLL_LONGTERM; + const int npages = PFN_DOWN(region->length); + + ret = account_locked_vm(current->mm, npages, true); +- if (ret) ++ if (ret) { ++ dev_err(cxl_cache->dev, "account_locked_vm() failed: %d\n", ret); + return ret; ++ } + + region->pages = kzalloc(npages * sizeof(struct page *), GFP_KERNEL); + if (!region->pages) { +@@ -150,12 +154,17 @@ static int cxl_cache_dma_pin_pages(struct dfl_cxl_cache *cxl_cache, + goto unlock_vm; + } + ++ if (region->flags & DFL_CXL_BUFFER_MAP_WRITABLE) ++ flags |= FOLL_WRITE; ++ + pinned = pin_user_pages_fast(region->user_addr, npages, flags, region->pages); + if (pinned < 0) { + ret = pinned; ++ dev_err(cxl_cache->dev, "pin_user_pages_fast() failed: %d\n", ret); + goto free_pages; + } else if (pinned != npages) { + ret = -EFAULT; ++ dev_err(cxl_cache->dev, "pin_user_pages_fast() failed: %d\n", pinned); + goto unpin_pages; + } + dev_dbg(cxl_cache->dev, "%d pages pinned\n", pinned); +@@ -248,6 +257,77 @@ static int cxl_cache_dma_region_add(struct dfl_cxl_cache *cxl_cache, + return 0; + } + ++static void fixup_ptes(struct mm_struct *mm, unsigned long start, unsigned long end) ++{ ++ unsigned long addr = start; ++ pgd_t *pgd; ++ p4d_t *p4d; ++ pud_t *pud; ++ pmd_t *pmd; ++ pte_t *pte; ++ ++ while (addr < end) { ++ pgd = pgd_offset(mm, addr); ++ if (pgd_bad(*pgd) || pgd_none(*pgd)) { ++ addr += PAGE_SIZE; ++ continue; ++ } ++ ++ p4d = p4d_offset(pgd, addr); ++ if (p4d_bad(*p4d) || p4d_none(*p4d)) { ++ addr += PAGE_SIZE; ++ continue; ++ } ++ ++ pud = pud_offset(p4d, addr); ++ if (pud_bad(*pud) || pud_none(*pud)) { ++ addr += PAGE_SIZE; ++ continue; ++ } ++ ++ pmd = pmd_offset(pud, addr); ++ if (pmd_bad(*pmd) || pmd_none(*pmd)) { ++ addr += PAGE_SIZE; ++ continue; ++ } ++ ++ pte = pte_offset_kernel(pmd, addr); ++ if (!pte_none(*pte) && pte_present(*pte)) ++ *pte = pte_wrprotect(*pte); ++ ++ addr += PAGE_SIZE; ++ } ++} ++ ++static long cxl_cache_set_region_read_only(struct dfl_cxl_cache *cxl_cache, ++ struct dfl_cxl_cache_buffer_region *region) ++{ ++ struct vm_area_struct *vma; ++ long ret = 0; ++ ++ vma = vma_lookup(current->mm, region->user_addr); ++ if (IS_ERR(vma)) { ++ ret = PTR_ERR(vma); ++ dev_err(cxl_cache->dev, "vma_lookup() failed: %ld\n", ret); ++ return ret; ++ } ++ ++ mmap_write_lock(current->mm); ++ ++ /* Mark the pages as non-cached and write-protected. */ ++ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); ++ vm_flags_clear(vma, VM_WRITE); ++ ++ fixup_ptes(current->mm, vma->vm_start, vma->vm_end); ++ ++ mmap_write_unlock(current->mm); ++ ++ /* Flush all remaining cache entries. */ ++ drm_clflush_virt_range(page_address(region->pages[0]), region->length); ++ ++ return ret; ++} ++ + static long cxl_cache_ioctl_numa_buffer_map(struct dfl_cxl_cache *cxl_cache, void __user *arg) + { + int i = 0; +@@ -283,11 +363,12 @@ static long cxl_cache_ioctl_numa_buffer_map(struct dfl_cxl_cache *cxl_cache, voi + if (!region) + return -ENOMEM; + ++ region->flags = dma_map.flags; + region->user_addr = dma_map.user_addr; + region->length = dma_map.length; + +- dev_dbg(cxl_cache->dev, "user_addr: %llx length: %lld\n", +- region->user_addr, region->length); ++ dev_dbg(cxl_cache->dev, "flags: %u user_addr: %llx length: %lld\n", ++ region->flags, region->user_addr, region->length); + + /* Pin the user memory region */ + ret = cxl_cache_dma_pin_pages(cxl_cache, region); +@@ -303,15 +384,18 @@ static long cxl_cache_ioctl_numa_buffer_map(struct dfl_cxl_cache *cxl_cache, voi + goto out_unpin_pages; + } + +- ret = cxl_cache_dma_region_add(cxl_cache, region); ++ if (!(region->flags & DFL_CXL_BUFFER_MAP_WRITABLE)) { ++ ret = cxl_cache_set_region_read_only(cxl_cache, region); ++ if (ret) ++ goto out_unpin_pages; ++ } + ++ ret = cxl_cache_dma_region_add(cxl_cache, region); + if (ret) { + dev_err(cxl_cache->dev, "failed to add dma region\n"); + goto out_unpin_pages; + } + +- drm_clflush_virt_range(page_address(region->pages[0]), region->length); +- + region->phys = page_to_phys(region->pages[0]); + + for (i = 0; i < DFL_ARRAY_MAX_SIZE; i++) { +diff --git a/include/uapi/linux/fpga-dfl.h b/include/uapi/linux/fpga-dfl.h +index 3784f893397c..bf4c3223ce61 100644 +--- a/include/uapi/linux/fpga-dfl.h ++++ b/include/uapi/linux/fpga-dfl.h +@@ -366,6 +366,7 @@ struct dfl_cxl_cache_region_info { + */ + struct dfl_cxl_cache_buffer_map { + __u32 argsz; ++#define DFL_CXL_BUFFER_MAP_WRITABLE BIT(0) + __u32 flags; + __u64 user_addr; + __u64 length; diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0082-fpga-update-cxl-cache-buffer-map-flags.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0082-fpga-update-cxl-cache-buffer-map-flags.patch new file mode 100644 index 0000000..71b44e3 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0082-fpga-update-cxl-cache-buffer-map-flags.patch @@ -0,0 +1,23 @@ +From ca3b6ec045153f7feb3584f3b9152c13c3ea1569 Mon Sep 17 00:00:00 2001 +From: anandaravuri +Date: Tue, 12 Dec 2023 11:05:57 -0800 +Subject: [PATCH] fpga:update cxl cache buffer map flags + +Signed-off-by: anandaravuri +--- + include/uapi/linux/fpga-dfl.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/uapi/linux/fpga-dfl.h b/include/uapi/linux/fpga-dfl.h +index bf4c3223ce61..412c3c9e6c76 100644 +--- a/include/uapi/linux/fpga-dfl.h ++++ b/include/uapi/linux/fpga-dfl.h +@@ -366,7 +366,7 @@ struct dfl_cxl_cache_region_info { + */ + struct dfl_cxl_cache_buffer_map { + __u32 argsz; +-#define DFL_CXL_BUFFER_MAP_WRITABLE BIT(0) ++#define DFL_CXL_BUFFER_MAP_WRITABLE 1 + __u32 flags; + __u64 user_addr; + __u64 length; diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0083-fpga-dfl-cxl-cache-clean-up-based-on-preliminary-rev.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0083-fpga-dfl-cxl-cache-clean-up-based-on-preliminary-rev.patch new file mode 100644 index 0000000..147dc36 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0083-fpga-dfl-cxl-cache-clean-up-based-on-preliminary-rev.patch @@ -0,0 +1,327 @@ +From b2177aa751ef1365de98cd6d4151556d72b53a0c Mon Sep 17 00:00:00 2001 +From: Matthew Gerlach +Date: Wed, 3 Jan 2024 23:59:21 +0530 +Subject: [PATCH] fpga: dfl-cxl-cache: clean up based on preliminary review + +First round of clean up based on feedback from andriy.shevchenko@intel.com: +- Clean up header files. Include what is explicity used. +- Make container_of a noop. +- Change while loop to a for loop. +- Remove reduncant else. + +Signed-off-by: Matthew Gerlach +--- + drivers/fpga/dfl-cxl-cache.c | 102 ++++++++++------------------------- + 1 file changed, 29 insertions(+), 73 deletions(-) + +diff --git a/drivers/fpga/dfl-cxl-cache.c b/drivers/fpga/dfl-cxl-cache.c +index 632444a447c3..1964df9562d3 100644 +--- a/drivers/fpga/dfl-cxl-cache.c ++++ b/drivers/fpga/dfl-cxl-cache.c +@@ -15,39 +15,42 @@ + * Ananda Ravuri + */ + +-#include + #include + #include ++#include + #include + #include + #include + #include + #include +-#include + #include + #include ++#include ++#include + #include + #include + #include + ++#include ++ + #define DFL_CXL_CACHE_DRIVER_NAME "dfl-cxl-cache" + #define FME_FEATURE_ID_CXL_CACHE 0x25 + + struct dfl_cxl_cache_buffer_region { ++ struct rb_node node; + u32 flags; + u64 user_addr; + u64 length; + struct page **pages; + phys_addr_t phys; +- __u64 offset[DFL_ARRAY_MAX_SIZE]; +- struct rb_node node; ++ u64 offset[DFL_ARRAY_MAX_SIZE]; + }; + + struct dfl_cxl_cache { ++ struct cdev cdev; + struct dfl_device *ddev; + int id; + struct device *dev; +- struct cdev cdev; + atomic_t opened; + void __iomem *mmio_base; + int mmio_size; +@@ -84,7 +87,6 @@ static long cxl_cache_ioctl_get_region_info(struct dfl_cxl_cache *cxl_cache, voi + unsigned long minsz; + + minsz = offsetofend(struct dfl_cxl_cache_region_info, offset); +- + if (copy_from_user(&rinfo, arg, minsz)) + return -EFAULT; + +@@ -112,17 +114,8 @@ static void cxl_cache_unpin_pages(struct device *dev, struct page ***pages, unsi + kfree(*pages); + *pages = NULL; + account_locked_vm(current->mm, npages, false); +- +- dev_dbg(dev, "%ld pages unpinned\n", npages); + } + +-/** +- * cxl_cache_dsm_check_continuous_pages - check if pages are continuous +- * @region: dma memory region +- * +- * Return true if pages of given dma memory region have continuous physical +- * address, otherwise return false. +- */ + static bool cxl_cache_check_continuous_pages(struct page **pages, unsigned long length) + { + int i; +@@ -148,7 +141,7 @@ static int cxl_cache_dma_pin_pages(struct dfl_cxl_cache *cxl_cache, + return ret; + } + +- region->pages = kzalloc(npages * sizeof(struct page *), GFP_KERNEL); ++ region->pages = kcalloc(npages, sizeof(struct page *), GFP_KERNEL); + if (!region->pages) { + ret = -ENOMEM; + goto unlock_vm; +@@ -158,22 +151,13 @@ static int cxl_cache_dma_pin_pages(struct dfl_cxl_cache *cxl_cache, + flags |= FOLL_WRITE; + + pinned = pin_user_pages_fast(region->user_addr, npages, flags, region->pages); +- if (pinned < 0) { +- ret = pinned; +- dev_err(cxl_cache->dev, "pin_user_pages_fast() failed: %d\n", ret); +- goto free_pages; +- } else if (pinned != npages) { +- ret = -EFAULT; +- dev_err(cxl_cache->dev, "pin_user_pages_fast() failed: %d\n", pinned); +- goto unpin_pages; +- } +- dev_dbg(cxl_cache->dev, "%d pages pinned\n", pinned); ++ if (pinned == npages) ++ return 0; + +- return 0; ++ ret = -EFAULT; ++ if (pinned > 0) ++ unpin_user_pages(region->pages, pinned); + +-unpin_pages: +- unpin_user_pages(region->pages, pinned); +-free_pages: + kfree(region->pages); + unlock_vm: + account_locked_vm(current->mm, npages, false); +@@ -183,7 +167,6 @@ static int cxl_cache_dma_pin_pages(struct dfl_cxl_cache *cxl_cache, + static void cxl_cache_dma_region_remove(struct dfl_cxl_cache *cxl_cache, + struct dfl_cxl_cache_buffer_region *region) + { +- dev_dbg(cxl_cache->dev, "del region (user_addr = %llx)\n", region->user_addr); + rb_erase(®ion->node, &cxl_cache->dma_regions); + } + +@@ -197,8 +180,8 @@ static bool dma_region_check_user_addr(struct dfl_cxl_cache_buffer_region *regio + (region->length + region->user_addr >= user_addr + size); + } + +-struct dfl_cxl_cache_buffer_region* +- cxl_cache_dma_region_find(struct dfl_cxl_cache *cxl_cache, u64 user_addr, u64 size) ++static struct dfl_cxl_cache_buffer_region* ++cxl_cache_dma_region_find(struct dfl_cxl_cache *cxl_cache, u64 user_addr, u64 size) + { + struct rb_node *node = cxl_cache->dma_regions.rb_node; + +@@ -207,11 +190,8 @@ struct dfl_cxl_cache_buffer_region* + + region = container_of(node, struct dfl_cxl_cache_buffer_region, node); + +- if (dma_region_check_user_addr(region, user_addr, size)) { +- dev_dbg(cxl_cache->dev, "find region (user_addr = %llx)\n", +- region->user_addr); ++ if (dma_region_check_user_addr(region, user_addr, size)) + return region; +- } + + if (user_addr < region->user_addr) + node = node->rb_left; +@@ -221,8 +201,6 @@ struct dfl_cxl_cache_buffer_region* + break; + } + +- dev_dbg(cxl_cache->dev, "region with user_addr %llx and size %llx is not found\n", +- user_addr, size); + return NULL; + } + +@@ -231,7 +209,6 @@ static int cxl_cache_dma_region_add(struct dfl_cxl_cache *cxl_cache, + { + struct rb_node **new, *parent = NULL; + +- dev_dbg(cxl_cache->dev, "add region (user_addr = %llx)\n", region->user_addr); + new = &cxl_cache->dma_regions.rb_node; + + while (*new) { +@@ -259,43 +236,33 @@ static int cxl_cache_dma_region_add(struct dfl_cxl_cache *cxl_cache, + + static void fixup_ptes(struct mm_struct *mm, unsigned long start, unsigned long end) + { +- unsigned long addr = start; ++ unsigned long addr; + pgd_t *pgd; + p4d_t *p4d; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; + +- while (addr < end) { ++ for (addr = start; addr < end; addr += PAGE_SIZE) { + pgd = pgd_offset(mm, addr); +- if (pgd_bad(*pgd) || pgd_none(*pgd)) { +- addr += PAGE_SIZE; ++ if (pgd_bad(*pgd) || pgd_none(*pgd)) + continue; +- } + + p4d = p4d_offset(pgd, addr); +- if (p4d_bad(*p4d) || p4d_none(*p4d)) { +- addr += PAGE_SIZE; ++ if (p4d_bad(*p4d) || p4d_none(*p4d)) + continue; +- } + + pud = pud_offset(p4d, addr); +- if (pud_bad(*pud) || pud_none(*pud)) { +- addr += PAGE_SIZE; ++ if (pud_bad(*pud) || pud_none(*pud)) + continue; +- } + + pmd = pmd_offset(pud, addr); +- if (pmd_bad(*pmd) || pmd_none(*pmd)) { +- addr += PAGE_SIZE; ++ if (pmd_bad(*pmd) || pmd_none(*pmd)) + continue; +- } + + pte = pte_offset_kernel(pmd, addr); + if (!pte_none(*pte) && pte_present(*pte)) + *pte = pte_wrprotect(*pte); +- +- addr += PAGE_SIZE; + } + } + +@@ -367,9 +334,6 @@ static long cxl_cache_ioctl_numa_buffer_map(struct dfl_cxl_cache *cxl_cache, voi + region->user_addr = dma_map.user_addr; + region->length = dma_map.length; + +- dev_dbg(cxl_cache->dev, "flags: %u user_addr: %llx length: %lld\n", +- region->flags, region->user_addr, region->length); +- + /* Pin the user memory region */ + ret = cxl_cache_dma_pin_pages(cxl_cache, region); + if (ret) { +@@ -399,11 +363,10 @@ static long cxl_cache_ioctl_numa_buffer_map(struct dfl_cxl_cache *cxl_cache, voi + region->phys = page_to_phys(region->pages[0]); + + for (i = 0; i < DFL_ARRAY_MAX_SIZE; i++) { +- if (dma_map.csr_array[i] != 0 && dma_map.csr_array[i] < cxl_cache->rinfo.size) ++ if (dma_map.csr_array[i] && dma_map.csr_array[i] < cxl_cache->rinfo.size) + writeq(region->phys, cxl_cache->mmio_base + dma_map.csr_array[i]); + } + +- dev_dbg(cxl_cache->dev, "phys address:%lld\n", region->phys); + return 0; + + out_unpin_pages: +@@ -431,9 +394,6 @@ static long cxl_cache_ioctl_numa_buffer_unmap(struct dfl_cxl_cache *cxl_cache, v + return -EINVAL; + } + +- dev_dbg(cxl_cache->dev, "user_addr: %llx length: %lld", +- dma_unmap.user_addr, dma_unmap.length); +- + region = cxl_cache_dma_region_find(cxl_cache, dma_unmap.user_addr, dma_unmap.length); + if (!region) { + dev_err(cxl_cache->dev, "fails to find buffer\n"); +@@ -444,7 +404,7 @@ static long cxl_cache_ioctl_numa_buffer_unmap(struct dfl_cxl_cache *cxl_cache, v + cxl_cache_unpin_pages(cxl_cache->dev, ®ion->pages, region->length); + + for (i = 0; i < DFL_ARRAY_MAX_SIZE; i++) { +- if (dma_unmap.csr_array[i] != 0 && dma_unmap.csr_array[i] < cxl_cache->rinfo.size) ++ if (dma_unmap.csr_array[i] && dma_unmap.csr_array[i] < cxl_cache->rinfo.size) + writeq(0, cxl_cache->mmio_base + dma_unmap.csr_array[i]); + } + +@@ -467,9 +427,9 @@ static long dfl_cxl_cache_ioctl(struct file *filp, unsigned int cmd, unsigned lo + return cxl_cache_ioctl_numa_buffer_map(cxl_cache, (void __user *)arg); + case DFL_CXL_CACHE_NUMA_BUFFER_UNMAP: + return cxl_cache_ioctl_numa_buffer_unmap(cxl_cache, (void __user *)arg); ++ default: ++ return -EINVAL; + } +- +- return -EINVAL; + } + + static const struct vm_operations_struct cxl_cache_vma_ops = { +@@ -509,7 +469,7 @@ static int dfl_cxl_cache_mmap(struct file *filp, struct vm_area_struct *vma) + size, vma->vm_page_prot); + } + +-void cxl_cache_dma_region_destroy(struct dfl_cxl_cache *cxl_cache) ++static void cxl_cache_dma_region_destroy(struct dfl_cxl_cache *cxl_cache) + { + struct rb_node *node = rb_first(&cxl_cache->dma_regions); + struct dfl_cxl_cache_buffer_region *region; +@@ -517,7 +477,6 @@ void cxl_cache_dma_region_destroy(struct dfl_cxl_cache *cxl_cache) + while (node) { + region = container_of(node, struct dfl_cxl_cache_buffer_region, node); + +- dev_dbg(cxl_cache->dev, "del region (user_addr = %llx)\n", region->user_addr); + rb_erase(node, &cxl_cache->dma_regions); + + if (region->pages) +@@ -590,8 +549,6 @@ static int cxl_cache_chardev_init(struct dfl_cxl_cache *cxl_cache, + } + cxl_cache->dev->release = cxl_cache_dev_release; + +- dev_dbg(cxl_cache->dev, "added cxl_cache device: %s\n", dev_name(cxl_cache->dev)); +- + cdev_init(&cxl_cache->cdev, &dfl_cxl_cache_fops); + cxl_cache->cdev.owner = THIS_MODULE; + cxl_cache->cdev.ops = &dfl_cxl_cache_fops; +@@ -635,7 +592,6 @@ static int dfl_cxl_cache_probe(struct dfl_device *ddev) + mmio_base = devm_ioremap_resource(&ddev->dev, &ddev->mmio_res); + if (IS_ERR(mmio_base)) { + ret = PTR_ERR(mmio_base); +- dev_err_probe(&ddev->dev, ret, "devm_ioremap_resource failed\n"); + goto out_unlock; + } + +@@ -662,7 +618,7 @@ static void dfl_cxl_cache_remove(struct dfl_device *ddev) + mutex_lock(&dfl_cxl_cache_class_lock); + cxl_cache_chardev_uinit(cxl_cache); + +- if (--dfl_cxl_cache_devices <= 0) { ++ if (dfl_cxl_cache_devices-- == 0) { + if (dfl_cxl_cache_class) { + class_destroy(dfl_cxl_cache_class); + dfl_cxl_cache_class = NULL; diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0084-fpga-dfl-cxl-cache-switch-to-using-mutex-guards.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0084-fpga-dfl-cxl-cache-switch-to-using-mutex-guards.patch new file mode 100644 index 0000000..dde328b --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0084-fpga-dfl-cxl-cache-switch-to-using-mutex-guards.patch @@ -0,0 +1,96 @@ +From 1813ad32e4a2300a5625837ab63094785f7ca32a Mon Sep 17 00:00:00 2001 +From: Matthew Gerlach +Date: Thu, 4 Jan 2024 00:43:01 +0530 +Subject: [PATCH] fpga: dfl-cxl-cache: switch to using mutex guards + +Mutex guards were introduced in the 6.4 kernel. Change code +to make use of the new feature. + +Signed-off-by: Matthew Gerlach +--- + drivers/fpga/dfl-cxl-cache.c | 26 +++++++++----------------- + 1 file changed, 9 insertions(+), 17 deletions(-) + +diff --git a/drivers/fpga/dfl-cxl-cache.c b/drivers/fpga/dfl-cxl-cache.c +index 1964df9562d3..c9d8064ca064 100644 +--- a/drivers/fpga/dfl-cxl-cache.c ++++ b/drivers/fpga/dfl-cxl-cache.c +@@ -17,6 +17,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -566,7 +567,7 @@ static int dfl_cxl_cache_probe(struct dfl_device *ddev) + void __iomem *mmio_base; + struct dfl_cxl_cache *cxl_cache; + +- mutex_lock(&dfl_cxl_cache_class_lock); ++ guard(mutex)(&dfl_cxl_cache_class_lock); + + if (!dfl_cxl_cache_class) { + dfl_cxl_cache_class = class_create(DFL_CXL_CACHE_DRIVER_NAME); +@@ -574,7 +575,7 @@ static int dfl_cxl_cache_probe(struct dfl_device *ddev) + ret = PTR_ERR(dfl_cxl_cache_class); + dfl_cxl_cache_class = NULL; + dev_err_probe(&ddev->dev, ret, "class_create failed\n"); +- goto out_unlock; ++ return ret; + } + } + +@@ -585,29 +586,22 @@ static int dfl_cxl_cache_probe(struct dfl_device *ddev) + if (ret) { + dev_err_probe(&ddev->dev, ret, "alloc_chrdev_region failed\n"); + dfl_cxl_cache_devt = MKDEV(0, 0); +- goto out_unlock; ++ return ret; + } + } + + mmio_base = devm_ioremap_resource(&ddev->dev, &ddev->mmio_res); +- if (IS_ERR(mmio_base)) { +- ret = PTR_ERR(mmio_base); +- goto out_unlock; +- } ++ if (IS_ERR(mmio_base)) ++ return PTR_ERR(mmio_base); + + cxl_cache = devm_kzalloc(&ddev->dev, sizeof(*cxl_cache), GFP_KERNEL); +- if (!cxl_cache) { +- ret = -ENOMEM; +- goto out_unlock; +- } ++ if (!cxl_cache) ++ return -ENOMEM; + + ret = cxl_cache_chardev_init(cxl_cache, ddev, mmio_base); + if (ret) + dev_err_probe(&ddev->dev, ret, "cxl_cache_chardev_init failed\n"); + +-out_unlock: +- mutex_unlock(&dfl_cxl_cache_class_lock); +- + return ret; + } + +@@ -615,7 +609,7 @@ static void dfl_cxl_cache_remove(struct dfl_device *ddev) + { + struct dfl_cxl_cache *cxl_cache = dev_get_drvdata(&ddev->dev); + +- mutex_lock(&dfl_cxl_cache_class_lock); ++ guard(mutex)(&dfl_cxl_cache_class_lock); + cxl_cache_chardev_uinit(cxl_cache); + + if (dfl_cxl_cache_devices-- == 0) { +@@ -629,8 +623,6 @@ static void dfl_cxl_cache_remove(struct dfl_device *ddev) + dfl_cxl_cache_devt = MKDEV(0, 0); + } + } +- +- mutex_unlock(&dfl_cxl_cache_class_lock); + } + + static const struct dfl_device_id dfl_cxl_cache_ids[] = { diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0085-fpga-dfl-cxl-cache-fix-check-of-return-of-vma_lookup.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0085-fpga-dfl-cxl-cache-fix-check-of-return-of-vma_lookup.patch new file mode 100644 index 0000000..37b36d2 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0085-fpga-dfl-cxl-cache-fix-check-of-return-of-vma_lookup.patch @@ -0,0 +1,44 @@ +From 0eec35cdda2b20991bbd7fa032f9cd12a0de6f5b Mon Sep 17 00:00:00 2001 +From: Matthew Gerlach +Date: Fri, 5 Jan 2024 11:05:06 -0800 +Subject: [PATCH] fpga: dfl-cxl-cache: fix check of return of vma_lookup() + +The function, vma_lookup, return NULL on error, not PTR_ERR. +Fix the error handling accordingly. This problem was reported +by Coverity. + +Signed-off-by: Matthew Gerlach mm, region->user_addr); +- if (IS_ERR(vma)) { +- ret = PTR_ERR(vma); +- dev_err(cxl_cache->dev, "vma_lookup() failed: %ld\n", ret); +- return ret; ++ if (!vma) { ++ dev_err(cxl_cache->dev, "vma_lookup() failed\n"); ++ return -EINVAL; + } + + mmap_write_lock(current->mm); +@@ -293,7 +291,7 @@ static long cxl_cache_set_region_read_only(struct dfl_cxl_cache *cxl_cache, + /* Flush all remaining cache entries. */ + drm_clflush_virt_range(page_address(region->pages[0]), region->length); + +- return ret; ++ return 0; + } + + static long cxl_cache_ioctl_numa_buffer_map(struct dfl_cxl_cache *cxl_cache, void __user *arg) diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0086-.github-workflows-build-kernel-packages.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0086-.github-workflows-build-kernel-packages.patch new file mode 100644 index 0000000..9d51f45 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0086-.github-workflows-build-kernel-packages.patch @@ -0,0 +1,44 @@ +From f1a8bc4bdca58d4cfea254da17d406fbfca2bc16 Mon Sep 17 00:00:00 2001 +From: Peter Colberg +Date: Wed, 24 Jan 2024 17:51:36 -0500 +Subject: [PATCH] .github: workflows: build kernel packages + +Signed-off-by: Peter Colberg +--- + .github/workflows/build.yml | 27 +++++++++++++++++++++++++++ + 1 file changed, 27 insertions(+) + create mode 100644 .github/workflows/build.yml + +diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml +new file mode 100644 +index 000000000000..2a95bbb3e273 +--- /dev/null ++++ b/.github/workflows/build.yml +@@ -0,0 +1,27 @@ ++name: Build kernel packages ++ ++on: ++ push: ++ branches: ++ - 'fpga-ofs-dev' ++ - 'fpga-ofs-dev-*-lts' ++ paths: ++ - '**' ++ - '!.github/**' ++ - '.github/workflows/build.yml' ++ ++ pull_request: ++ branches: ++ - 'fpga-ofs-dev' ++ - 'fpga-ofs-dev-*-lts' ++ paths: ++ - '**' ++ - '!.github/**' ++ - '.github/workflows/build.yml' ++ ++ workflow_dispatch: ++ ++jobs: ++ build: ++ # https://docs.github.com/en/actions/using-workflows/reusing-workflows ++ uses: intel-innersource/applications.fpga.opae.linux-dfl/.github/workflows/build.yml@main diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0087-.github-workflows-scan-kernel-with-Coverity.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0087-.github-workflows-scan-kernel-with-Coverity.patch new file mode 100644 index 0000000..52b70c1 --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0087-.github-workflows-scan-kernel-with-Coverity.patch @@ -0,0 +1,43 @@ +From b8b8b9187bc5bc3a715d56277a9c155d9196e26c Mon Sep 17 00:00:00 2001 +From: Peter Colberg +Date: Mon, 29 Jan 2024 17:07:33 -0500 +Subject: [PATCH] .github: workflows: scan kernel with Coverity + +Signed-off-by: Peter Colberg +--- + .github/workflows/coverity.yml | 26 ++++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + create mode 100644 .github/workflows/coverity.yml + +diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml +new file mode 100644 +index 000000000000..a87d6c0b0fcc +--- /dev/null ++++ b/.github/workflows/coverity.yml +@@ -0,0 +1,26 @@ ++name: Scan kernel with Coverity ++ ++on: ++ push: ++ branches: ++ - 'fpga-ofs-dev' ++ - 'fpga-ofs-dev-*-lts' ++ paths: ++ - '**' ++ - '!.github/**' ++ - '.github/workflows/coverity.yml' ++ ++ pull_request: ++ branches: ++ - 'fpga-ofs-dev' ++ - 'fpga-ofs-dev-*-lts' ++ paths: ++ - '.github/workflows/coverity.yml' ++ ++ workflow_dispatch: ++ ++jobs: ++ build: ++ # https://docs.github.com/en/actions/using-workflows/reusing-workflows ++ uses: intel-innersource/applications.fpga.opae.linux-dfl/.github/workflows/coverity.yml@main ++ secrets: inherit diff --git a/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0088-fpga-dfl-cxl-cache-depend-on-DRM.patch b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0088-fpga-dfl-cxl-cache-depend-on-DRM.patch new file mode 100644 index 0000000..d109daf --- /dev/null +++ b/upstream_patches/fpga-ofs-dev-6.6-lts-patches/0088-fpga-dfl-cxl-cache-depend-on-DRM.patch @@ -0,0 +1,39 @@ +From ac3ff19483556fea4ec5ce4c486493f24de375f2 Mon Sep 17 00:00:00 2001 +From: Peter Colberg +Date: Wed, 31 Jan 2024 18:27:28 -0500 +Subject: [PATCH] fpga: dfl-cxl-cache: depend on DRM + +This resolves an undefined reference to drm_clflush_virt_range() +when building a kernel without modules and minimal configuration. + +Signed-off-by: Peter Colberg +--- + configs/dfl-config | 1 + + drivers/fpga/Kconfig | 2 +- + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/configs/dfl-config b/configs/dfl-config +index a7a5e93fb918..09565b1f4f2b 100644 +--- a/configs/dfl-config ++++ b/configs/dfl-config +@@ -61,6 +61,7 @@ CONFIG_PTP_DFL_TOD=m + + # CXL cache support + ++CONFIG_DRM=m + CONFIG_FPGA_DFL_CXL_CACHE=m + + # Test configs - not required for production environments +diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig +index 7031cb5485fb..a35eb285fde3 100644 +--- a/drivers/fpga/Kconfig ++++ b/drivers/fpga/Kconfig +@@ -296,7 +296,7 @@ config FPGA_M10_BMC_SEC_UPDATE + + config FPGA_DFL_CXL_CACHE + tristate "Intel CXL cache driver" +- depends on FPGA_DFL ++ depends on DRM && FPGA_DFL + help + This is the driver for CXL cache Accelerated Function Unit + (AFU) which provides interfaces to MMIO region and dma buffers. diff --git a/upstream_patches/intel-dfl-fixes/001-fix-config-dependency-intel-s10hssi.patch b/upstream_patches/intel-dfl-fixes/001-fix-config-dependency-intel-s10hssi.patch new file mode 100644 index 0000000..491726d --- /dev/null +++ b/upstream_patches/intel-dfl-fixes/001-fix-config-dependency-intel-s10hssi.patch @@ -0,0 +1,11 @@ +--- a/drivers/net/ethernet/intel/Kconfig 2023-02-28 14:27:47.919630051 +0100 ++++ b/drivers/net/ethernet/intel/Kconfig 2023-02-28 14:28:23.847564543 +0100 +@@ -375,6 +375,7 @@ + config S10HSSI + tristate "Control Plane Driver for Stratix 10 HSSI" + select REGMAP_INDIRECT_REGISTER ++ depends on FPGA_DFL + help + This driver provides control plane support for an Stratix 10 + High Speed Serial Interface. + diff --git a/upstream_patches/series b/upstream_patches/series new file mode 100644 index 0000000..418cea2 --- /dev/null +++ b/upstream_patches/series @@ -0,0 +1,89 @@ +fpga-ofs-dev-6.6-lts-patches/0001-fpga-dfl-afu-use-PFN_DOWN-and-PFN_PHYS-helper-macros.patch +fpga-ofs-dev-6.6-lts-patches/0002-fpga-dfl-use-sysfs_emit-to-format-sysfs-values.patch +fpga-ofs-dev-6.6-lts-patches/0003-fpga-dfl-omit-unneeded-casts-of-u64-values-for-dev_d.patch +fpga-ofs-dev-6.6-lts-patches/0004-fpga-dfl-afu-remove-unused-member-pdata-from-struct-.patch +fpga-ofs-dev-6.6-lts-patches/0005-mfd-intel-m10-bmc-Change-staging-size-to-a-variable.patch +fpga-ofs-dev-6.6-lts-patches/0006-fpga-dfl-Fix-handling-of-CSR-relative-addresses.patch +fpga-ofs-dev-6.6-lts-patches/0007-fpga-m10bmc-sec-add-sysfs-to-load-bmc-images.patch +fpga-ofs-dev-6.6-lts-patches/0008-fpga-m10bmc-sec-m10bmc_sec_retimer_load-callback.patch +fpga-ofs-dev-6.6-lts-patches/0009-fpga-dfl-Add-GUID-support-in-mod-device-table.patch +fpga-ofs-dev-6.6-lts-patches/0010-fpga-dfl-Add-feature-device-driver-match-by-GUID.patch +fpga-ofs-dev-6.6-lts-patches/0011-tty-serial-8250-Add-the-GUID-definition-for-UART.patch +fpga-ofs-dev-6.6-lts-patches/0012-fpga-dfl-fix-the-kernel-warning-when-release-assign-.patch +fpga-ofs-dev-6.6-lts-patches/0013-mfd-intel-m10-bmc-Create-BMC-log-sub-driver.patch +fpga-ofs-dev-6.6-lts-patches/0014-fpga-dfl-Validate-length-field-in-DFHv1-header.patch +fpga-ofs-dev-6.6-lts-patches/0015-fpga-dfl-afu-add-read-only-write-only-dma-mapping-su.patch +fpga-ofs-dev-6.6-lts-patches/0016-fpga-dfl-afu-add-FOLL_LONGTERM-flag-when-pin-user-pa.patch +fpga-ofs-dev-6.6-lts-patches/0017-uio-uio_dfl-add-interrupt-support.patch +fpga-ofs-dev-6.6-lts-patches/0018-fpga-dfl-pci-gracefully-handle-misconfigured-port-en.patch +fpga-ofs-dev-6.6-lts-patches/0019-fpga-dfl-fme-mgr-fix-potential-endian-issue.patch +fpga-ofs-dev-6.6-lts-patches/0020-fpga-dfl-move-the-handling-of-unaligned-image-size-i.patch +fpga-ofs-dev-6.6-lts-patches/0021-fpga-dfl-fme-fix-kernel-doc-comments-for-some-functi.patch +fpga-ofs-dev-6.6-lts-patches/0022-fpga-dfl-fix-VF-creation-when-ports-have-no-local-BA.patch +fpga-ofs-dev-6.6-lts-patches/0023-fpga-dfl-handle-empty-port-list.patch +fpga-ofs-dev-6.6-lts-patches/0024-fpga-dfl-Handle-dfl-s-starting-with-AFU.patch +fpga-ofs-dev-6.6-lts-patches/0025-fpga-dfl-add-an-API-to-get-the-base-device-for-dfl-d.patch +fpga-ofs-dev-6.6-lts-patches/0026-fpga-m10bmc-sec-add-n5010-device-id.patch +fpga-ofs-dev-6.6-lts-patches/0027-fpga-dfl-Add-PCI-IDs-for-new-N5013-and-N5014-cards.patch +fpga-ofs-dev-6.6-lts-patches/0028-hwmon-intel-m10-bmc-Add-support-N5013-and-N5014.patch +fpga-ofs-dev-6.6-lts-patches/0029-spi-spi-altera-dfl-Add-support-for-N5013-and-N5014.patch +fpga-ofs-dev-6.6-lts-patches/0030-mfd-intel-m10-bmc-Extend-BMC-for-N5013-and-N5014.patch +fpga-ofs-dev-6.6-lts-patches/0031-fpga-m10bmc-sec-support-power-on-image.patch +fpga-ofs-dev-6.6-lts-patches/0032-net-phy-add-memory-based-QSFP-controller.patch +fpga-ofs-dev-6.6-lts-patches/0033-net-phy-add-qsfp-plugin-status-checking.patch +fpga-ofs-dev-6.6-lts-patches/0034-net-phy-QSFP-controller-subsystem-driver-for-Intel-F.patch +fpga-ofs-dev-6.6-lts-patches/0035-fpga-m10bmc-sec-add-fpga_boot_image.patch +fpga-ofs-dev-6.6-lts-patches/0036-fpga-m10bmc-sec-Support-for-SDM-key-provisioning.patch +fpga-ofs-dev-6.6-lts-patches/0037-fpga-m10bmc-sec-Expose-SDM-SR-provisioning-status.patch +fpga-ofs-dev-6.6-lts-patches/0038-fpga-m10bmc-sec-Expose-SDM-PR-provisioning-status.patch +fpga-ofs-dev-6.6-lts-patches/0039-fpga-m10bmc-sec-Support-SDM-SR-PR-cancellation.patch +fpga-ofs-dev-6.6-lts-patches/0040-fpga-m10bmc-sec-PR-SR-root-key-hash-support-for-VAB.patch +fpga-ofs-dev-6.6-lts-patches/0041-fpga-m10bmc-sec-Add-trigger-to-read-SDM-key-hashes.patch +fpga-ofs-dev-6.6-lts-patches/0042-hwmon-Add-sensor-support-for-the-C6100-card.patch +fpga-ofs-dev-6.6-lts-patches/0043-mfd-intel-m10-bmc-Add-C6100-support.patch +fpga-ofs-dev-6.6-lts-patches/0044-Documentation-fpga-dfl-add-documentation-for-Interfa.patch +fpga-ofs-dev-6.6-lts-patches/0045-fpga-dfl-add-support-for-Interface-type-of-DFH.patch +fpga-ofs-dev-6.6-lts-patches/0046-fpga-dfl-Add-support-for-CMC-card.patch +fpga-ofs-dev-6.6-lts-patches/0047-hwmon-intel-m10-bmc-Add-support-for-CMC-card.patch +fpga-ofs-dev-6.6-lts-patches/0048-mfd-intel-m10-bmc-Add-support-for-CMC-card.patch +fpga-ofs-dev-6.6-lts-patches/0049-mfd-intel-m10-bmc-PMCI-and-log-changes-for-CMC.patch +fpga-ofs-dev-6.6-lts-patches/0050-fpga-dfl-add-vendor-IDs-and-device-IDs-for-ALIBABA-F.patch +fpga-ofs-dev-6.6-lts-patches/0051-dfl-add-generic-indirect-regmap-support.patch +fpga-ofs-dev-6.6-lts-patches/0052-mfd-intel-m10-bmc-Use-the-generic-regmap-indirect.patch +fpga-ofs-dev-6.6-lts-patches/0053-fpga-dfl-hssi-driver.patch +fpga-ofs-dev-6.6-lts-patches/0054-net-phy-intel-driver-for-stratix10-phy.patch +fpga-ofs-dev-6.6-lts-patches/0055-net-ethernet-intel-add-s10hssi-driver.patch +fpga-ofs-dev-6.6-lts-patches/0056-net-ethernet-intel-add-polling-of-link-status.patch +fpga-ofs-dev-6.6-lts-patches/0057-net-ethernet-silicom-add-n5010-phy-driver.patch +fpga-ofs-dev-6.6-lts-patches/0058-net-ethernet-silicom-add-n5010-hssi-driver.patch +fpga-ofs-dev-6.6-lts-patches/0059-fpga-dfl-export-fme-and-port-error-DFH-revision-to-s.patch +fpga-ofs-dev-6.6-lts-patches/0060-uio-dfl-add-id-for-PCI-Subsystem.patch +fpga-ofs-dev-6.6-lts-patches/0061-fpga-dfl-add-support-for-switching-the-retimer-FEC-m.patch +fpga-ofs-dev-6.6-lts-patches/0062-fpga-dfl-add-debug-to-failed-partial-reconfiguration.patch +fpga-ofs-dev-6.6-lts-patches/0063-DEBUG-WARNING-enable-debugfs-writing-of-regmap-regis.patch +fpga-ofs-dev-6.6-lts-patches/0064-fpga-dfl-Add-wildcard-sub-device-ID-for-intel-DFL-de.patch +fpga-ofs-dev-6.6-lts-patches/0065-fpga-dfl-pci-sva-Add-support-for-binding-a-PASID-to-.patch +fpga-ofs-dev-6.6-lts-patches/0066-fpga-dfl-cxl-cache-Add-Intel-CXL-cache-driver.patch +fpga-ofs-dev-6.6-lts-patches/0067-dt-bindings-fpga-Add-Device-Feature-List-DFL.patch +fpga-ofs-dev-6.6-lts-patches/0068-fpga-dfl-Add-platform-driver-for-DFL-device-tree.patch +fpga-ofs-dev-6.6-lts-patches/0069-fpga-dfl-Introduce-new-FIU-for-enhanced-initiation-f.patch +fpga-ofs-dev-6.6-lts-patches/0070-fpga-dfl-Add-support-for-DFH-Private-feature-type.patch +fpga-ofs-dev-6.6-lts-patches/0071-security-Add-intel-security-policy-file.patch +fpga-ofs-dev-6.6-lts-patches/0072-configs-DFL-driver-config-options.patch +fpga-ofs-dev-6.6-lts-patches/0073-fpga-dfl-pci-sva-depend-on-CONFIG_IOMMU_SVA.patch +fpga-ofs-dev-6.6-lts-patches/0074-configs-enable-CONFIG_INTEL_IOMMU_SVM.patch +fpga-ofs-dev-6.6-lts-patches/0075-fpga-dfl-afu-update-initialization-of-port_hdr-drive.patch +fpga-ofs-dev-6.6-lts-patches/0076-fpga-dfl-cxl-cache-include-linux-slab.h.patch +fpga-ofs-dev-6.6-lts-patches/0077-fpga-dfl-pci-sva-include-linux-module.h.patch +fpga-ofs-dev-6.6-lts-patches/0078-fpga-dfl-Fix-the-dfl-dev-type-to-Privare-Feature.patch +fpga-ofs-dev-6.6-lts-patches/0079-mfd-intel-m10-bmc-Removing-support-for-SDM-with-PMCI.patch +fpga-ofs-dev-6.6-lts-patches/0080-Documentation-fpga-dfl-add-AFU-feature-list-details.patch +fpga-ofs-dev-6.6-lts-patches/0081-fpga-dfl-cxl-cache-make-pages-readonly-when-biased-t.patch +fpga-ofs-dev-6.6-lts-patches/0082-fpga-update-cxl-cache-buffer-map-flags.patch +fpga-ofs-dev-6.6-lts-patches/0083-fpga-dfl-cxl-cache-clean-up-based-on-preliminary-rev.patch +fpga-ofs-dev-6.6-lts-patches/0084-fpga-dfl-cxl-cache-switch-to-using-mutex-guards.patch +fpga-ofs-dev-6.6-lts-patches/0085-fpga-dfl-cxl-cache-fix-check-of-return-of-vma_lookup.patch +fpga-ofs-dev-6.6-lts-patches/0086-.github-workflows-build-kernel-packages.patch +fpga-ofs-dev-6.6-lts-patches/0087-.github-workflows-scan-kernel-with-Coverity.patch +fpga-ofs-dev-6.6-lts-patches/0088-fpga-dfl-cxl-cache-depend-on-DRM.patch +intel-dfl-fixes/001-fix-config-dependency-intel-s10hssi.patch