root/drivers/fpga/dfl-afu-error.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. __afu_port_err_mask
  2. afu_port_err_mask
  3. afu_port_err_clear
  4. errors_show
  5. errors_store
  6. first_error_show
  7. first_malformed_req_show
  8. port_err_attrs_visible
  9. port_err_init
  10. port_err_uinit

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Driver for FPGA Accelerated Function Unit (AFU) Error Reporting
   4  *
   5  * Copyright 2019 Intel Corporation, Inc.
   6  *
   7  * Authors:
   8  *   Wu Hao <hao.wu@linux.intel.com>
   9  *   Xiao Guangrong <guangrong.xiao@linux.intel.com>
  10  *   Joseph Grecco <joe.grecco@intel.com>
  11  *   Enno Luebbers <enno.luebbers@intel.com>
  12  *   Tim Whisonant <tim.whisonant@intel.com>
  13  *   Ananda Ravuri <ananda.ravuri@intel.com>
  14  *   Mitchel Henry <henry.mitchel@intel.com>
  15  */
  16 
  17 #include <linux/uaccess.h>
  18 
  19 #include "dfl-afu.h"
  20 
  21 #define PORT_ERROR_MASK         0x8
  22 #define PORT_ERROR              0x10
  23 #define PORT_FIRST_ERROR        0x18
  24 #define PORT_MALFORMED_REQ0     0x20
  25 #define PORT_MALFORMED_REQ1     0x28
  26 
  27 #define ERROR_MASK              GENMASK_ULL(63, 0)
  28 
  29 /* mask or unmask port errors by the error mask register. */
  30 static void __afu_port_err_mask(struct device *dev, bool mask)
  31 {
  32         void __iomem *base;
  33 
  34         base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_ERROR);
  35 
  36         writeq(mask ? ERROR_MASK : 0, base + PORT_ERROR_MASK);
  37 }
  38 
  39 static void afu_port_err_mask(struct device *dev, bool mask)
  40 {
  41         struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
  42 
  43         mutex_lock(&pdata->lock);
  44         __afu_port_err_mask(dev, mask);
  45         mutex_unlock(&pdata->lock);
  46 }
  47 
  48 /* clear port errors. */
  49 static int afu_port_err_clear(struct device *dev, u64 err)
  50 {
  51         struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
  52         struct platform_device *pdev = to_platform_device(dev);
  53         void __iomem *base_err, *base_hdr;
  54         int ret = -EBUSY;
  55         u64 v;
  56 
  57         base_err = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_ERROR);
  58         base_hdr = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
  59 
  60         mutex_lock(&pdata->lock);
  61 
  62         /*
  63          * clear Port Errors
  64          *
  65          * - Check for AP6 State
  66          * - Halt Port by keeping Port in reset
  67          * - Set PORT Error mask to all 1 to mask errors
  68          * - Clear all errors
  69          * - Set Port mask to all 0 to enable errors
  70          * - All errors start capturing new errors
  71          * - Enable Port by pulling the port out of reset
  72          */
  73 
  74         /* if device is still in AP6 power state, can not clear any error. */
  75         v = readq(base_hdr + PORT_HDR_STS);
  76         if (FIELD_GET(PORT_STS_PWR_STATE, v) == PORT_STS_PWR_STATE_AP6) {
  77                 dev_err(dev, "Could not clear errors, device in AP6 state.\n");
  78                 goto done;
  79         }
  80 
  81         /* Halt Port by keeping Port in reset */
  82         ret = __afu_port_disable(pdev);
  83         if (ret)
  84                 goto done;
  85 
  86         /* Mask all errors */
  87         __afu_port_err_mask(dev, true);
  88 
  89         /* Clear errors if err input matches with current port errors.*/
  90         v = readq(base_err + PORT_ERROR);
  91 
  92         if (v == err) {
  93                 writeq(v, base_err + PORT_ERROR);
  94 
  95                 v = readq(base_err + PORT_FIRST_ERROR);
  96                 writeq(v, base_err + PORT_FIRST_ERROR);
  97         } else {
  98                 ret = -EINVAL;
  99         }
 100 
 101         /* Clear mask */
 102         __afu_port_err_mask(dev, false);
 103 
 104         /* Enable the Port by clear the reset */
 105         __afu_port_enable(pdev);
 106 
 107 done:
 108         mutex_unlock(&pdata->lock);
 109         return ret;
 110 }
 111 
 112 static ssize_t errors_show(struct device *dev, struct device_attribute *attr,
 113                            char *buf)
 114 {
 115         struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
 116         void __iomem *base;
 117         u64 error;
 118 
 119         base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_ERROR);
 120 
 121         mutex_lock(&pdata->lock);
 122         error = readq(base + PORT_ERROR);
 123         mutex_unlock(&pdata->lock);
 124 
 125         return sprintf(buf, "0x%llx\n", (unsigned long long)error);
 126 }
 127 
 128 static ssize_t errors_store(struct device *dev, struct device_attribute *attr,
 129                             const char *buff, size_t count)
 130 {
 131         u64 value;
 132         int ret;
 133 
 134         if (kstrtou64(buff, 0, &value))
 135                 return -EINVAL;
 136 
 137         ret = afu_port_err_clear(dev, value);
 138 
 139         return ret ? ret : count;
 140 }
 141 static DEVICE_ATTR_RW(errors);
 142 
 143 static ssize_t first_error_show(struct device *dev,
 144                                 struct device_attribute *attr, char *buf)
 145 {
 146         struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
 147         void __iomem *base;
 148         u64 error;
 149 
 150         base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_ERROR);
 151 
 152         mutex_lock(&pdata->lock);
 153         error = readq(base + PORT_FIRST_ERROR);
 154         mutex_unlock(&pdata->lock);
 155 
 156         return sprintf(buf, "0x%llx\n", (unsigned long long)error);
 157 }
 158 static DEVICE_ATTR_RO(first_error);
 159 
 160 static ssize_t first_malformed_req_show(struct device *dev,
 161                                         struct device_attribute *attr,
 162                                         char *buf)
 163 {
 164         struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
 165         void __iomem *base;
 166         u64 req0, req1;
 167 
 168         base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_ERROR);
 169 
 170         mutex_lock(&pdata->lock);
 171         req0 = readq(base + PORT_MALFORMED_REQ0);
 172         req1 = readq(base + PORT_MALFORMED_REQ1);
 173         mutex_unlock(&pdata->lock);
 174 
 175         return sprintf(buf, "0x%016llx%016llx\n",
 176                        (unsigned long long)req1, (unsigned long long)req0);
 177 }
 178 static DEVICE_ATTR_RO(first_malformed_req);
 179 
 180 static struct attribute *port_err_attrs[] = {
 181         &dev_attr_errors.attr,
 182         &dev_attr_first_error.attr,
 183         &dev_attr_first_malformed_req.attr,
 184         NULL,
 185 };
 186 
 187 static umode_t port_err_attrs_visible(struct kobject *kobj,
 188                                       struct attribute *attr, int n)
 189 {
 190         struct device *dev = kobj_to_dev(kobj);
 191 
 192         /*
 193          * sysfs entries are visible only if related private feature is
 194          * enumerated.
 195          */
 196         if (!dfl_get_feature_by_id(dev, PORT_FEATURE_ID_ERROR))
 197                 return 0;
 198 
 199         return attr->mode;
 200 }
 201 
 202 const struct attribute_group port_err_group = {
 203         .name       = "errors",
 204         .attrs      = port_err_attrs,
 205         .is_visible = port_err_attrs_visible,
 206 };
 207 
 208 static int port_err_init(struct platform_device *pdev,
 209                          struct dfl_feature *feature)
 210 {
 211         afu_port_err_mask(&pdev->dev, false);
 212 
 213         return 0;
 214 }
 215 
 216 static void port_err_uinit(struct platform_device *pdev,
 217                            struct dfl_feature *feature)
 218 {
 219         afu_port_err_mask(&pdev->dev, true);
 220 }
 221 
 222 const struct dfl_feature_id port_err_id_table[] = {
 223         {.id = PORT_FEATURE_ID_ERROR,},
 224         {0,}
 225 };
 226 
 227 const struct dfl_feature_ops port_err_ops = {
 228         .init = port_err_init,
 229         .uinit = port_err_uinit,
 230 };

/* [<][>][^][v][top][bottom][index][help] */