fpga: dfl: afu: add AFU state related sysfs interfaces
authorWu Hao <hao.wu@intel.com>
Sun, 4 Aug 2019 10:20:13 +0000 (18:20 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 5 Aug 2019 15:56:47 +0000 (17:56 +0200)
This patch introduces more sysfs interfaces for Accelerated
Function Unit (AFU). These interfaces allow users to read
current AFU Power State (APx), read / clear AFU Power (APx)
events which are sticky to identify transient APx state,
and manage AFU's LTR (latency tolerance reporting).

Signed-off-by: Ananda Ravuri <ananda.ravuri@intel.com>
Signed-off-by: Xu Yilun <yilun.xu@intel.com>
Signed-off-by: Wu Hao <hao.wu@intel.com>
Acked-by: Alan Tull <atull@kernel.org>
Signed-off-by: Moritz Fischer <mdf@kernel.org>
Link: https://lore.kernel.org/r/1564914022-3710-4-git-send-email-hao.wu@intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Documentation/ABI/testing/sysfs-platform-dfl-port
drivers/fpga/dfl-afu-main.c
drivers/fpga/dfl.h

index 6a92dda517b05120b0447629743d81372ecd1662..1ab3e6f6154a91f74d2c58e1747a4318d89cd951 100644 (file)
@@ -14,3 +14,35 @@ Description: Read-only. User can program different PR bitstreams to FPGA
                Accelerator Function Unit (AFU) for different functions. It
                returns uuid which could be used to identify which PR bitstream
                is programmed in this AFU.
+
+What:          /sys/bus/platform/devices/dfl-port.0/power_state
+Date:          August 2019
+KernelVersion: 5.4
+Contact:       Wu Hao <hao.wu@intel.com>
+Description:   Read-only. It reports the APx (AFU Power) state, different APx
+               means different throttling level. When reading this file, it
+               returns "0" - Normal / "1" - AP1 / "2" - AP2 / "6" - AP6.
+
+What:          /sys/bus/platform/devices/dfl-port.0/ap1_event
+Date:          August 2019
+KernelVersion: 5.4
+Contact:       Wu Hao <hao.wu@intel.com>
+Description:   Read-write. Read this file for AP1 (AFU Power State 1) event.
+               It's used to indicate transient AP1 state. Write 1 to this
+               file to clear AP1 event.
+
+What:          /sys/bus/platform/devices/dfl-port.0/ap2_event
+Date:          August 2019
+KernelVersion: 5.4
+Contact:       Wu Hao <hao.wu@intel.com>
+Description:   Read-write. Read this file for AP2 (AFU Power State 2) event.
+               It's used to indicate transient AP2 state. Write 1 to this
+               file to clear AP2 event.
+
+What:          /sys/bus/platform/devices/dfl-port.0/ltr
+Date:          August 2019
+KernelVersion: 5.4
+Contact:       Wu Hao <hao.wu@intel.com>
+Description:   Read-write. Read or set AFU latency tolerance reporting value.
+               Set ltr to 1 if the AFU can tolerate latency >= 40us or set it
+               to 0 if it is latency sensitive.
index 68b4d0874b931ddca7457a2fd400802a2415d601..12175bbd90c17dc892beedb2cfa7c149e5365511 100644 (file)
@@ -141,8 +141,145 @@ id_show(struct device *dev, struct device_attribute *attr, char *buf)
 }
 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);
+       void __iomem *base;
+       u64 v;
+
+       base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
+
+       mutex_lock(&pdata->lock);
+       v = readq(base + PORT_HDR_CTRL);
+       mutex_unlock(&pdata->lock);
+
+       return sprintf(buf, "%x\n", (u8)FIELD_GET(PORT_CTRL_LATENCY, v));
+}
+
+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);
+       void __iomem *base;
+       bool ltr;
+       u64 v;
+
+       if (kstrtobool(buf, &ltr))
+               return -EINVAL;
+
+       base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
+
+       mutex_lock(&pdata->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);
+
+       return count;
+}
+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);
+       void __iomem *base;
+       u64 v;
+
+       base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
+
+       mutex_lock(&pdata->lock);
+       v = readq(base + PORT_HDR_STS);
+       mutex_unlock(&pdata->lock);
+
+       return sprintf(buf, "%x\n", (u8)FIELD_GET(PORT_STS_AP1_EVT, v));
+}
+
+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);
+       void __iomem *base;
+       bool clear;
+
+       if (kstrtobool(buf, &clear) || !clear)
+               return -EINVAL;
+
+       base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
+
+       mutex_lock(&pdata->lock);
+       writeq(PORT_STS_AP1_EVT, base + PORT_HDR_STS);
+       mutex_unlock(&pdata->lock);
+
+       return count;
+}
+static DEVICE_ATTR_RW(ap1_event);
+
+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);
+       void __iomem *base;
+       u64 v;
+
+       base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
+
+       mutex_lock(&pdata->lock);
+       v = readq(base + PORT_HDR_STS);
+       mutex_unlock(&pdata->lock);
+
+       return sprintf(buf, "%x\n", (u8)FIELD_GET(PORT_STS_AP2_EVT, v));
+}
+
+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);
+       void __iomem *base;
+       bool clear;
+
+       if (kstrtobool(buf, &clear) || !clear)
+               return -EINVAL;
+
+       base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
+
+       mutex_lock(&pdata->lock);
+       writeq(PORT_STS_AP2_EVT, base + PORT_HDR_STS);
+       mutex_unlock(&pdata->lock);
+
+       return count;
+}
+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);
+       void __iomem *base;
+       u64 v;
+
+       base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
+
+       mutex_lock(&pdata->lock);
+       v = readq(base + PORT_HDR_STS);
+       mutex_unlock(&pdata->lock);
+
+       return sprintf(buf, "0x%x\n", (u8)FIELD_GET(PORT_STS_PWR_STATE, v));
+}
+static DEVICE_ATTR_RO(power_state);
+
 static struct attribute *port_hdr_attrs[] = {
        &dev_attr_id.attr,
+       &dev_attr_ltr.attr,
+       &dev_attr_ap1_event.attr,
+       &dev_attr_ap2_event.attr,
+       &dev_attr_power_state.attr,
        NULL,
 };
 ATTRIBUTE_GROUPS(port_hdr);
index b3f2f53a75d39020a3035a7073603758f6e7a2ed..6625d73bade8189d394cee3a252c060cde153f4c 100644 (file)
 #define PORT_HDR_NEXT_AFU      NEXT_AFU
 #define PORT_HDR_CAP           0x30
 #define PORT_HDR_CTRL          0x38
+#define PORT_HDR_STS           0x40
 
 /* Port Capability Register Bitfield */
 #define PORT_CAP_PORT_NUM      GENMASK_ULL(1, 0)       /* ID of this port */
 /* Latency tolerance reporting. '1' >= 40us, '0' < 40us.*/
 #define PORT_CTRL_LATENCY      BIT_ULL(2)
 #define PORT_CTRL_SFTRST_ACK   BIT_ULL(4)              /* HW ack for reset */
+
+/* Port Status Register Bitfield */
+#define PORT_STS_AP2_EVT       BIT_ULL(13)             /* AP2 event detected */
+#define PORT_STS_AP1_EVT       BIT_ULL(12)             /* AP1 event detected */
+#define PORT_STS_PWR_STATE     GENMASK_ULL(11, 8)      /* AFU power states */
+#define PORT_STS_PWR_STATE_NORM 0
+#define PORT_STS_PWR_STATE_AP1 1                       /* 50% throttling */
+#define PORT_STS_PWR_STATE_AP2 2                       /* 90% throttling */
+#define PORT_STS_PWR_STATE_AP6 6                       /* 100% throttling */
+
 /**
  * struct dfl_fpga_port_ops - port ops
  *