| .. | .. |
|---|
| 22 | 22 | #include "dfl-afu.h" |
|---|
| 23 | 23 | |
|---|
| 24 | 24 | /** |
|---|
| 25 | | - * port_enable - enable a port |
|---|
| 25 | + * __afu_port_enable - enable a port by clear reset |
|---|
| 26 | 26 | * @pdev: port platform device. |
|---|
| 27 | 27 | * |
|---|
| 28 | 28 | * Enable Port by clear the port soft reset bit, which is set by default. |
|---|
| 29 | 29 | * The AFU is unable to respond to any MMIO access while in reset. |
|---|
| 30 | | - * port_enable function should only be used after port_disable function. |
|---|
| 30 | + * __afu_port_enable function should only be used after __afu_port_disable |
|---|
| 31 | + * function. |
|---|
| 32 | + * |
|---|
| 33 | + * The caller needs to hold lock for protection. |
|---|
| 31 | 34 | */ |
|---|
| 32 | | -static void port_enable(struct platform_device *pdev) |
|---|
| 35 | +void __afu_port_enable(struct platform_device *pdev) |
|---|
| 33 | 36 | { |
|---|
| 34 | 37 | struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); |
|---|
| 35 | 38 | void __iomem *base; |
|---|
| .. | .. |
|---|
| 52 | 55 | #define RST_POLL_TIMEOUT 1000 /* us */ |
|---|
| 53 | 56 | |
|---|
| 54 | 57 | /** |
|---|
| 55 | | - * port_disable - disable a port |
|---|
| 58 | + * __afu_port_disable - disable a port by hold reset |
|---|
| 56 | 59 | * @pdev: port platform device. |
|---|
| 57 | 60 | * |
|---|
| 58 | | - * Disable Port by setting the port soft reset bit, it puts the port into |
|---|
| 59 | | - * reset. |
|---|
| 61 | + * Disable Port by setting the port soft reset bit, it puts the port into reset. |
|---|
| 62 | + * |
|---|
| 63 | + * The caller needs to hold lock for protection. |
|---|
| 60 | 64 | */ |
|---|
| 61 | | -static int port_disable(struct platform_device *pdev) |
|---|
| 65 | +int __afu_port_disable(struct platform_device *pdev) |
|---|
| 62 | 66 | { |
|---|
| 63 | 67 | struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); |
|---|
| 64 | 68 | void __iomem *base; |
|---|
| .. | .. |
|---|
| 105 | 109 | { |
|---|
| 106 | 110 | int ret; |
|---|
| 107 | 111 | |
|---|
| 108 | | - ret = port_disable(pdev); |
|---|
| 112 | + ret = __afu_port_disable(pdev); |
|---|
| 109 | 113 | if (!ret) |
|---|
| 110 | | - port_enable(pdev); |
|---|
| 114 | + __afu_port_enable(pdev); |
|---|
| 111 | 115 | |
|---|
| 112 | 116 | return ret; |
|---|
| 113 | 117 | } |
|---|
| .. | .. |
|---|
| 142 | 146 | } |
|---|
| 143 | 147 | static DEVICE_ATTR_RO(id); |
|---|
| 144 | 148 | |
|---|
| 145 | | -static const struct attribute *port_hdr_attrs[] = { |
|---|
| 149 | +static ssize_t |
|---|
| 150 | +ltr_show(struct device *dev, struct device_attribute *attr, char *buf) |
|---|
| 151 | +{ |
|---|
| 152 | + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); |
|---|
| 153 | + void __iomem *base; |
|---|
| 154 | + u64 v; |
|---|
| 155 | + |
|---|
| 156 | + base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); |
|---|
| 157 | + |
|---|
| 158 | + mutex_lock(&pdata->lock); |
|---|
| 159 | + v = readq(base + PORT_HDR_CTRL); |
|---|
| 160 | + mutex_unlock(&pdata->lock); |
|---|
| 161 | + |
|---|
| 162 | + return sprintf(buf, "%x\n", (u8)FIELD_GET(PORT_CTRL_LATENCY, v)); |
|---|
| 163 | +} |
|---|
| 164 | + |
|---|
| 165 | +static ssize_t |
|---|
| 166 | +ltr_store(struct device *dev, struct device_attribute *attr, |
|---|
| 167 | + const char *buf, size_t count) |
|---|
| 168 | +{ |
|---|
| 169 | + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); |
|---|
| 170 | + void __iomem *base; |
|---|
| 171 | + bool ltr; |
|---|
| 172 | + u64 v; |
|---|
| 173 | + |
|---|
| 174 | + if (kstrtobool(buf, <r)) |
|---|
| 175 | + return -EINVAL; |
|---|
| 176 | + |
|---|
| 177 | + base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); |
|---|
| 178 | + |
|---|
| 179 | + mutex_lock(&pdata->lock); |
|---|
| 180 | + v = readq(base + PORT_HDR_CTRL); |
|---|
| 181 | + v &= ~PORT_CTRL_LATENCY; |
|---|
| 182 | + v |= FIELD_PREP(PORT_CTRL_LATENCY, ltr ? 1 : 0); |
|---|
| 183 | + writeq(v, base + PORT_HDR_CTRL); |
|---|
| 184 | + mutex_unlock(&pdata->lock); |
|---|
| 185 | + |
|---|
| 186 | + return count; |
|---|
| 187 | +} |
|---|
| 188 | +static DEVICE_ATTR_RW(ltr); |
|---|
| 189 | + |
|---|
| 190 | +static ssize_t |
|---|
| 191 | +ap1_event_show(struct device *dev, struct device_attribute *attr, char *buf) |
|---|
| 192 | +{ |
|---|
| 193 | + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); |
|---|
| 194 | + void __iomem *base; |
|---|
| 195 | + u64 v; |
|---|
| 196 | + |
|---|
| 197 | + base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); |
|---|
| 198 | + |
|---|
| 199 | + mutex_lock(&pdata->lock); |
|---|
| 200 | + v = readq(base + PORT_HDR_STS); |
|---|
| 201 | + mutex_unlock(&pdata->lock); |
|---|
| 202 | + |
|---|
| 203 | + return sprintf(buf, "%x\n", (u8)FIELD_GET(PORT_STS_AP1_EVT, v)); |
|---|
| 204 | +} |
|---|
| 205 | + |
|---|
| 206 | +static ssize_t |
|---|
| 207 | +ap1_event_store(struct device *dev, struct device_attribute *attr, |
|---|
| 208 | + const char *buf, size_t count) |
|---|
| 209 | +{ |
|---|
| 210 | + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); |
|---|
| 211 | + void __iomem *base; |
|---|
| 212 | + bool clear; |
|---|
| 213 | + |
|---|
| 214 | + if (kstrtobool(buf, &clear) || !clear) |
|---|
| 215 | + return -EINVAL; |
|---|
| 216 | + |
|---|
| 217 | + base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); |
|---|
| 218 | + |
|---|
| 219 | + mutex_lock(&pdata->lock); |
|---|
| 220 | + writeq(PORT_STS_AP1_EVT, base + PORT_HDR_STS); |
|---|
| 221 | + mutex_unlock(&pdata->lock); |
|---|
| 222 | + |
|---|
| 223 | + return count; |
|---|
| 224 | +} |
|---|
| 225 | +static DEVICE_ATTR_RW(ap1_event); |
|---|
| 226 | + |
|---|
| 227 | +static ssize_t |
|---|
| 228 | +ap2_event_show(struct device *dev, struct device_attribute *attr, |
|---|
| 229 | + char *buf) |
|---|
| 230 | +{ |
|---|
| 231 | + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); |
|---|
| 232 | + void __iomem *base; |
|---|
| 233 | + u64 v; |
|---|
| 234 | + |
|---|
| 235 | + base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); |
|---|
| 236 | + |
|---|
| 237 | + mutex_lock(&pdata->lock); |
|---|
| 238 | + v = readq(base + PORT_HDR_STS); |
|---|
| 239 | + mutex_unlock(&pdata->lock); |
|---|
| 240 | + |
|---|
| 241 | + return sprintf(buf, "%x\n", (u8)FIELD_GET(PORT_STS_AP2_EVT, v)); |
|---|
| 242 | +} |
|---|
| 243 | + |
|---|
| 244 | +static ssize_t |
|---|
| 245 | +ap2_event_store(struct device *dev, struct device_attribute *attr, |
|---|
| 246 | + const char *buf, size_t count) |
|---|
| 247 | +{ |
|---|
| 248 | + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); |
|---|
| 249 | + void __iomem *base; |
|---|
| 250 | + bool clear; |
|---|
| 251 | + |
|---|
| 252 | + if (kstrtobool(buf, &clear) || !clear) |
|---|
| 253 | + return -EINVAL; |
|---|
| 254 | + |
|---|
| 255 | + base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); |
|---|
| 256 | + |
|---|
| 257 | + mutex_lock(&pdata->lock); |
|---|
| 258 | + writeq(PORT_STS_AP2_EVT, base + PORT_HDR_STS); |
|---|
| 259 | + mutex_unlock(&pdata->lock); |
|---|
| 260 | + |
|---|
| 261 | + return count; |
|---|
| 262 | +} |
|---|
| 263 | +static DEVICE_ATTR_RW(ap2_event); |
|---|
| 264 | + |
|---|
| 265 | +static ssize_t |
|---|
| 266 | +power_state_show(struct device *dev, struct device_attribute *attr, char *buf) |
|---|
| 267 | +{ |
|---|
| 268 | + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); |
|---|
| 269 | + void __iomem *base; |
|---|
| 270 | + u64 v; |
|---|
| 271 | + |
|---|
| 272 | + base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); |
|---|
| 273 | + |
|---|
| 274 | + mutex_lock(&pdata->lock); |
|---|
| 275 | + v = readq(base + PORT_HDR_STS); |
|---|
| 276 | + mutex_unlock(&pdata->lock); |
|---|
| 277 | + |
|---|
| 278 | + return sprintf(buf, "0x%x\n", (u8)FIELD_GET(PORT_STS_PWR_STATE, v)); |
|---|
| 279 | +} |
|---|
| 280 | +static DEVICE_ATTR_RO(power_state); |
|---|
| 281 | + |
|---|
| 282 | +static ssize_t |
|---|
| 283 | +userclk_freqcmd_store(struct device *dev, struct device_attribute *attr, |
|---|
| 284 | + const char *buf, size_t count) |
|---|
| 285 | +{ |
|---|
| 286 | + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); |
|---|
| 287 | + u64 userclk_freq_cmd; |
|---|
| 288 | + void __iomem *base; |
|---|
| 289 | + |
|---|
| 290 | + if (kstrtou64(buf, 0, &userclk_freq_cmd)) |
|---|
| 291 | + return -EINVAL; |
|---|
| 292 | + |
|---|
| 293 | + base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); |
|---|
| 294 | + |
|---|
| 295 | + mutex_lock(&pdata->lock); |
|---|
| 296 | + writeq(userclk_freq_cmd, base + PORT_HDR_USRCLK_CMD0); |
|---|
| 297 | + mutex_unlock(&pdata->lock); |
|---|
| 298 | + |
|---|
| 299 | + return count; |
|---|
| 300 | +} |
|---|
| 301 | +static DEVICE_ATTR_WO(userclk_freqcmd); |
|---|
| 302 | + |
|---|
| 303 | +static ssize_t |
|---|
| 304 | +userclk_freqcntrcmd_store(struct device *dev, struct device_attribute *attr, |
|---|
| 305 | + const char *buf, size_t count) |
|---|
| 306 | +{ |
|---|
| 307 | + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); |
|---|
| 308 | + u64 userclk_freqcntr_cmd; |
|---|
| 309 | + void __iomem *base; |
|---|
| 310 | + |
|---|
| 311 | + if (kstrtou64(buf, 0, &userclk_freqcntr_cmd)) |
|---|
| 312 | + return -EINVAL; |
|---|
| 313 | + |
|---|
| 314 | + base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); |
|---|
| 315 | + |
|---|
| 316 | + mutex_lock(&pdata->lock); |
|---|
| 317 | + writeq(userclk_freqcntr_cmd, base + PORT_HDR_USRCLK_CMD1); |
|---|
| 318 | + mutex_unlock(&pdata->lock); |
|---|
| 319 | + |
|---|
| 320 | + return count; |
|---|
| 321 | +} |
|---|
| 322 | +static DEVICE_ATTR_WO(userclk_freqcntrcmd); |
|---|
| 323 | + |
|---|
| 324 | +static ssize_t |
|---|
| 325 | +userclk_freqsts_show(struct device *dev, struct device_attribute *attr, |
|---|
| 326 | + char *buf) |
|---|
| 327 | +{ |
|---|
| 328 | + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); |
|---|
| 329 | + u64 userclk_freqsts; |
|---|
| 330 | + void __iomem *base; |
|---|
| 331 | + |
|---|
| 332 | + base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); |
|---|
| 333 | + |
|---|
| 334 | + mutex_lock(&pdata->lock); |
|---|
| 335 | + userclk_freqsts = readq(base + PORT_HDR_USRCLK_STS0); |
|---|
| 336 | + mutex_unlock(&pdata->lock); |
|---|
| 337 | + |
|---|
| 338 | + return sprintf(buf, "0x%llx\n", (unsigned long long)userclk_freqsts); |
|---|
| 339 | +} |
|---|
| 340 | +static DEVICE_ATTR_RO(userclk_freqsts); |
|---|
| 341 | + |
|---|
| 342 | +static ssize_t |
|---|
| 343 | +userclk_freqcntrsts_show(struct device *dev, struct device_attribute *attr, |
|---|
| 344 | + char *buf) |
|---|
| 345 | +{ |
|---|
| 346 | + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); |
|---|
| 347 | + u64 userclk_freqcntrsts; |
|---|
| 348 | + void __iomem *base; |
|---|
| 349 | + |
|---|
| 350 | + base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); |
|---|
| 351 | + |
|---|
| 352 | + mutex_lock(&pdata->lock); |
|---|
| 353 | + userclk_freqcntrsts = readq(base + PORT_HDR_USRCLK_STS1); |
|---|
| 354 | + mutex_unlock(&pdata->lock); |
|---|
| 355 | + |
|---|
| 356 | + return sprintf(buf, "0x%llx\n", |
|---|
| 357 | + (unsigned long long)userclk_freqcntrsts); |
|---|
| 358 | +} |
|---|
| 359 | +static DEVICE_ATTR_RO(userclk_freqcntrsts); |
|---|
| 360 | + |
|---|
| 361 | +static struct attribute *port_hdr_attrs[] = { |
|---|
| 146 | 362 | &dev_attr_id.attr, |
|---|
| 363 | + &dev_attr_ltr.attr, |
|---|
| 364 | + &dev_attr_ap1_event.attr, |
|---|
| 365 | + &dev_attr_ap2_event.attr, |
|---|
| 366 | + &dev_attr_power_state.attr, |
|---|
| 367 | + &dev_attr_userclk_freqcmd.attr, |
|---|
| 368 | + &dev_attr_userclk_freqcntrcmd.attr, |
|---|
| 369 | + &dev_attr_userclk_freqsts.attr, |
|---|
| 370 | + &dev_attr_userclk_freqcntrsts.attr, |
|---|
| 147 | 371 | NULL, |
|---|
| 372 | +}; |
|---|
| 373 | + |
|---|
| 374 | +static umode_t port_hdr_attrs_visible(struct kobject *kobj, |
|---|
| 375 | + struct attribute *attr, int n) |
|---|
| 376 | +{ |
|---|
| 377 | + struct device *dev = kobj_to_dev(kobj); |
|---|
| 378 | + umode_t mode = attr->mode; |
|---|
| 379 | + void __iomem *base; |
|---|
| 380 | + |
|---|
| 381 | + base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); |
|---|
| 382 | + |
|---|
| 383 | + if (dfl_feature_revision(base) > 0) { |
|---|
| 384 | + /* |
|---|
| 385 | + * userclk sysfs interfaces are only visible in case port |
|---|
| 386 | + * revision is 0, as hardware with revision >0 doesn't |
|---|
| 387 | + * support this. |
|---|
| 388 | + */ |
|---|
| 389 | + if (attr == &dev_attr_userclk_freqcmd.attr || |
|---|
| 390 | + attr == &dev_attr_userclk_freqcntrcmd.attr || |
|---|
| 391 | + attr == &dev_attr_userclk_freqsts.attr || |
|---|
| 392 | + attr == &dev_attr_userclk_freqcntrsts.attr) |
|---|
| 393 | + mode = 0; |
|---|
| 394 | + } |
|---|
| 395 | + |
|---|
| 396 | + return mode; |
|---|
| 397 | +} |
|---|
| 398 | + |
|---|
| 399 | +static const struct attribute_group port_hdr_group = { |
|---|
| 400 | + .attrs = port_hdr_attrs, |
|---|
| 401 | + .is_visible = port_hdr_attrs_visible, |
|---|
| 148 | 402 | }; |
|---|
| 149 | 403 | |
|---|
| 150 | 404 | static int port_hdr_init(struct platform_device *pdev, |
|---|
| 151 | 405 | struct dfl_feature *feature) |
|---|
| 152 | 406 | { |
|---|
| 153 | | - dev_dbg(&pdev->dev, "PORT HDR Init.\n"); |
|---|
| 154 | | - |
|---|
| 155 | 407 | port_reset(pdev); |
|---|
| 156 | 408 | |
|---|
| 157 | | - return sysfs_create_files(&pdev->dev.kobj, port_hdr_attrs); |
|---|
| 158 | | -} |
|---|
| 159 | | - |
|---|
| 160 | | -static void port_hdr_uinit(struct platform_device *pdev, |
|---|
| 161 | | - struct dfl_feature *feature) |
|---|
| 162 | | -{ |
|---|
| 163 | | - dev_dbg(&pdev->dev, "PORT HDR UInit.\n"); |
|---|
| 164 | | - |
|---|
| 165 | | - sysfs_remove_files(&pdev->dev.kobj, port_hdr_attrs); |
|---|
| 409 | + return 0; |
|---|
| 166 | 410 | } |
|---|
| 167 | 411 | |
|---|
| 168 | 412 | static long |
|---|
| .. | .. |
|---|
| 186 | 430 | return ret; |
|---|
| 187 | 431 | } |
|---|
| 188 | 432 | |
|---|
| 433 | +static const struct dfl_feature_id port_hdr_id_table[] = { |
|---|
| 434 | + {.id = PORT_FEATURE_ID_HEADER,}, |
|---|
| 435 | + {0,} |
|---|
| 436 | +}; |
|---|
| 437 | + |
|---|
| 189 | 438 | static const struct dfl_feature_ops port_hdr_ops = { |
|---|
| 190 | 439 | .init = port_hdr_init, |
|---|
| 191 | | - .uinit = port_hdr_uinit, |
|---|
| 192 | 440 | .ioctl = port_hdr_ioctl, |
|---|
| 193 | 441 | }; |
|---|
| 194 | 442 | |
|---|
| .. | .. |
|---|
| 215 | 463 | } |
|---|
| 216 | 464 | static DEVICE_ATTR_RO(afu_id); |
|---|
| 217 | 465 | |
|---|
| 218 | | -static const struct attribute *port_afu_attrs[] = { |
|---|
| 466 | +static struct attribute *port_afu_attrs[] = { |
|---|
| 219 | 467 | &dev_attr_afu_id.attr, |
|---|
| 220 | 468 | NULL |
|---|
| 469 | +}; |
|---|
| 470 | + |
|---|
| 471 | +static umode_t port_afu_attrs_visible(struct kobject *kobj, |
|---|
| 472 | + struct attribute *attr, int n) |
|---|
| 473 | +{ |
|---|
| 474 | + struct device *dev = kobj_to_dev(kobj); |
|---|
| 475 | + |
|---|
| 476 | + /* |
|---|
| 477 | + * sysfs entries are visible only if related private feature is |
|---|
| 478 | + * enumerated. |
|---|
| 479 | + */ |
|---|
| 480 | + if (!dfl_get_feature_by_id(dev, PORT_FEATURE_ID_AFU)) |
|---|
| 481 | + return 0; |
|---|
| 482 | + |
|---|
| 483 | + return attr->mode; |
|---|
| 484 | +} |
|---|
| 485 | + |
|---|
| 486 | +static const struct attribute_group port_afu_group = { |
|---|
| 487 | + .attrs = port_afu_attrs, |
|---|
| 488 | + .is_visible = port_afu_attrs_visible, |
|---|
| 221 | 489 | }; |
|---|
| 222 | 490 | |
|---|
| 223 | 491 | static int port_afu_init(struct platform_device *pdev, |
|---|
| 224 | 492 | struct dfl_feature *feature) |
|---|
| 225 | 493 | { |
|---|
| 226 | 494 | struct resource *res = &pdev->resource[feature->resource_index]; |
|---|
| 227 | | - int ret; |
|---|
| 228 | 495 | |
|---|
| 229 | | - dev_dbg(&pdev->dev, "PORT AFU Init.\n"); |
|---|
| 230 | | - |
|---|
| 231 | | - ret = afu_mmio_region_add(dev_get_platdata(&pdev->dev), |
|---|
| 232 | | - DFL_PORT_REGION_INDEX_AFU, resource_size(res), |
|---|
| 233 | | - res->start, DFL_PORT_REGION_READ | |
|---|
| 234 | | - DFL_PORT_REGION_WRITE | DFL_PORT_REGION_MMAP); |
|---|
| 235 | | - if (ret) |
|---|
| 236 | | - return ret; |
|---|
| 237 | | - |
|---|
| 238 | | - return sysfs_create_files(&pdev->dev.kobj, port_afu_attrs); |
|---|
| 496 | + return afu_mmio_region_add(dev_get_platdata(&pdev->dev), |
|---|
| 497 | + DFL_PORT_REGION_INDEX_AFU, |
|---|
| 498 | + resource_size(res), res->start, |
|---|
| 499 | + DFL_PORT_REGION_MMAP | DFL_PORT_REGION_READ | |
|---|
| 500 | + DFL_PORT_REGION_WRITE); |
|---|
| 239 | 501 | } |
|---|
| 240 | 502 | |
|---|
| 241 | | -static void port_afu_uinit(struct platform_device *pdev, |
|---|
| 242 | | - struct dfl_feature *feature) |
|---|
| 243 | | -{ |
|---|
| 244 | | - dev_dbg(&pdev->dev, "PORT AFU UInit.\n"); |
|---|
| 245 | | - |
|---|
| 246 | | - sysfs_remove_files(&pdev->dev.kobj, port_afu_attrs); |
|---|
| 247 | | -} |
|---|
| 503 | +static const struct dfl_feature_id port_afu_id_table[] = { |
|---|
| 504 | + {.id = PORT_FEATURE_ID_AFU,}, |
|---|
| 505 | + {0,} |
|---|
| 506 | +}; |
|---|
| 248 | 507 | |
|---|
| 249 | 508 | static const struct dfl_feature_ops port_afu_ops = { |
|---|
| 250 | 509 | .init = port_afu_init, |
|---|
| 251 | | - .uinit = port_afu_uinit, |
|---|
| 510 | +}; |
|---|
| 511 | + |
|---|
| 512 | +static int port_stp_init(struct platform_device *pdev, |
|---|
| 513 | + struct dfl_feature *feature) |
|---|
| 514 | +{ |
|---|
| 515 | + struct resource *res = &pdev->resource[feature->resource_index]; |
|---|
| 516 | + |
|---|
| 517 | + return afu_mmio_region_add(dev_get_platdata(&pdev->dev), |
|---|
| 518 | + DFL_PORT_REGION_INDEX_STP, |
|---|
| 519 | + resource_size(res), res->start, |
|---|
| 520 | + DFL_PORT_REGION_MMAP | DFL_PORT_REGION_READ | |
|---|
| 521 | + DFL_PORT_REGION_WRITE); |
|---|
| 522 | +} |
|---|
| 523 | + |
|---|
| 524 | +static const struct dfl_feature_id port_stp_id_table[] = { |
|---|
| 525 | + {.id = PORT_FEATURE_ID_STP,}, |
|---|
| 526 | + {0,} |
|---|
| 527 | +}; |
|---|
| 528 | + |
|---|
| 529 | +static const struct dfl_feature_ops port_stp_ops = { |
|---|
| 530 | + .init = port_stp_init, |
|---|
| 531 | +}; |
|---|
| 532 | + |
|---|
| 533 | +static long |
|---|
| 534 | +port_uint_ioctl(struct platform_device *pdev, struct dfl_feature *feature, |
|---|
| 535 | + unsigned int cmd, unsigned long arg) |
|---|
| 536 | +{ |
|---|
| 537 | + switch (cmd) { |
|---|
| 538 | + case DFL_FPGA_PORT_UINT_GET_IRQ_NUM: |
|---|
| 539 | + return dfl_feature_ioctl_get_num_irqs(pdev, feature, arg); |
|---|
| 540 | + case DFL_FPGA_PORT_UINT_SET_IRQ: |
|---|
| 541 | + return dfl_feature_ioctl_set_irq(pdev, feature, arg); |
|---|
| 542 | + default: |
|---|
| 543 | + dev_dbg(&pdev->dev, "%x cmd not handled", cmd); |
|---|
| 544 | + return -ENODEV; |
|---|
| 545 | + } |
|---|
| 546 | +} |
|---|
| 547 | + |
|---|
| 548 | +static const struct dfl_feature_id port_uint_id_table[] = { |
|---|
| 549 | + {.id = PORT_FEATURE_ID_UINT,}, |
|---|
| 550 | + {0,} |
|---|
| 551 | +}; |
|---|
| 552 | + |
|---|
| 553 | +static const struct dfl_feature_ops port_uint_ops = { |
|---|
| 554 | + .ioctl = port_uint_ioctl, |
|---|
| 252 | 555 | }; |
|---|
| 253 | 556 | |
|---|
| 254 | 557 | static struct dfl_feature_driver port_feature_drvs[] = { |
|---|
| 255 | 558 | { |
|---|
| 256 | | - .id = PORT_FEATURE_ID_HEADER, |
|---|
| 559 | + .id_table = port_hdr_id_table, |
|---|
| 257 | 560 | .ops = &port_hdr_ops, |
|---|
| 258 | 561 | }, |
|---|
| 259 | 562 | { |
|---|
| 260 | | - .id = PORT_FEATURE_ID_AFU, |
|---|
| 563 | + .id_table = port_afu_id_table, |
|---|
| 261 | 564 | .ops = &port_afu_ops, |
|---|
| 565 | + }, |
|---|
| 566 | + { |
|---|
| 567 | + .id_table = port_err_id_table, |
|---|
| 568 | + .ops = &port_err_ops, |
|---|
| 569 | + }, |
|---|
| 570 | + { |
|---|
| 571 | + .id_table = port_stp_id_table, |
|---|
| 572 | + .ops = &port_stp_ops, |
|---|
| 573 | + }, |
|---|
| 574 | + { |
|---|
| 575 | + .id_table = port_uint_id_table, |
|---|
| 576 | + .ops = &port_uint_ops, |
|---|
| 262 | 577 | }, |
|---|
| 263 | 578 | { |
|---|
| 264 | 579 | .ops = NULL, |
|---|
| .. | .. |
|---|
| 275 | 590 | if (WARN_ON(!pdata)) |
|---|
| 276 | 591 | return -ENODEV; |
|---|
| 277 | 592 | |
|---|
| 278 | | - ret = dfl_feature_dev_use_begin(pdata); |
|---|
| 279 | | - if (ret) |
|---|
| 280 | | - return ret; |
|---|
| 593 | + mutex_lock(&pdata->lock); |
|---|
| 594 | + ret = dfl_feature_dev_use_begin(pdata, filp->f_flags & O_EXCL); |
|---|
| 595 | + if (!ret) { |
|---|
| 596 | + dev_dbg(&fdev->dev, "Device File Opened %d Times\n", |
|---|
| 597 | + dfl_feature_dev_use_count(pdata)); |
|---|
| 598 | + filp->private_data = fdev; |
|---|
| 599 | + } |
|---|
| 600 | + mutex_unlock(&pdata->lock); |
|---|
| 281 | 601 | |
|---|
| 282 | | - dev_dbg(&fdev->dev, "Device File Open\n"); |
|---|
| 283 | | - filp->private_data = fdev; |
|---|
| 284 | | - |
|---|
| 285 | | - return 0; |
|---|
| 602 | + return ret; |
|---|
| 286 | 603 | } |
|---|
| 287 | 604 | |
|---|
| 288 | 605 | static int afu_release(struct inode *inode, struct file *filp) |
|---|
| 289 | 606 | { |
|---|
| 290 | 607 | struct platform_device *pdev = filp->private_data; |
|---|
| 291 | 608 | struct dfl_feature_platform_data *pdata; |
|---|
| 609 | + struct dfl_feature *feature; |
|---|
| 292 | 610 | |
|---|
| 293 | 611 | dev_dbg(&pdev->dev, "Device File Release\n"); |
|---|
| 294 | 612 | |
|---|
| 295 | 613 | pdata = dev_get_platdata(&pdev->dev); |
|---|
| 296 | 614 | |
|---|
| 297 | 615 | mutex_lock(&pdata->lock); |
|---|
| 298 | | - __port_reset(pdev); |
|---|
| 299 | | - afu_dma_region_destroy(pdata); |
|---|
| 300 | | - mutex_unlock(&pdata->lock); |
|---|
| 301 | | - |
|---|
| 302 | 616 | dfl_feature_dev_use_end(pdata); |
|---|
| 617 | + |
|---|
| 618 | + if (!dfl_feature_dev_use_count(pdata)) { |
|---|
| 619 | + dfl_fpga_dev_for_each_feature(pdata, feature) |
|---|
| 620 | + dfl_fpga_set_irq_triggers(feature, 0, |
|---|
| 621 | + feature->nr_irqs, NULL); |
|---|
| 622 | + __port_reset(pdev); |
|---|
| 623 | + afu_dma_region_destroy(pdata); |
|---|
| 624 | + } |
|---|
| 625 | + mutex_unlock(&pdata->lock); |
|---|
| 303 | 626 | |
|---|
| 304 | 627 | return 0; |
|---|
| 305 | 628 | } |
|---|
| .. | .. |
|---|
| 460 | 783 | return -EINVAL; |
|---|
| 461 | 784 | } |
|---|
| 462 | 785 | |
|---|
| 786 | +static const struct vm_operations_struct afu_vma_ops = { |
|---|
| 787 | +#ifdef CONFIG_HAVE_IOREMAP_PROT |
|---|
| 788 | + .access = generic_access_phys, |
|---|
| 789 | +#endif |
|---|
| 790 | +}; |
|---|
| 791 | + |
|---|
| 463 | 792 | static int afu_mmap(struct file *filp, struct vm_area_struct *vma) |
|---|
| 464 | 793 | { |
|---|
| 465 | 794 | struct platform_device *pdev = filp->private_data; |
|---|
| .. | .. |
|---|
| 488 | 817 | if ((vma->vm_flags & VM_WRITE) && |
|---|
| 489 | 818 | !(region.flags & DFL_PORT_REGION_WRITE)) |
|---|
| 490 | 819 | return -EPERM; |
|---|
| 820 | + |
|---|
| 821 | + /* Support debug access to the mapping */ |
|---|
| 822 | + vma->vm_ops = &afu_vma_ops; |
|---|
| 491 | 823 | |
|---|
| 492 | 824 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); |
|---|
| 493 | 825 | |
|---|
| .. | .. |
|---|
| 527 | 859 | static int afu_dev_destroy(struct platform_device *pdev) |
|---|
| 528 | 860 | { |
|---|
| 529 | 861 | struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); |
|---|
| 530 | | - struct dfl_afu *afu; |
|---|
| 531 | 862 | |
|---|
| 532 | 863 | mutex_lock(&pdata->lock); |
|---|
| 533 | | - afu = dfl_fpga_pdata_get_private(pdata); |
|---|
| 534 | 864 | afu_mmio_region_destroy(pdata); |
|---|
| 535 | 865 | afu_dma_region_destroy(pdata); |
|---|
| 536 | 866 | dfl_fpga_pdata_set_private(pdata, NULL); |
|---|
| .. | .. |
|---|
| 546 | 876 | |
|---|
| 547 | 877 | mutex_lock(&pdata->lock); |
|---|
| 548 | 878 | if (enable) |
|---|
| 549 | | - port_enable(pdev); |
|---|
| 879 | + __afu_port_enable(pdev); |
|---|
| 550 | 880 | else |
|---|
| 551 | | - ret = port_disable(pdev); |
|---|
| 881 | + ret = __afu_port_disable(pdev); |
|---|
| 552 | 882 | mutex_unlock(&pdata->lock); |
|---|
| 553 | 883 | |
|---|
| 554 | 884 | return ret; |
|---|
| .. | .. |
|---|
| 600 | 930 | return 0; |
|---|
| 601 | 931 | } |
|---|
| 602 | 932 | |
|---|
| 933 | +static const struct attribute_group *afu_dev_groups[] = { |
|---|
| 934 | + &port_hdr_group, |
|---|
| 935 | + &port_afu_group, |
|---|
| 936 | + &port_err_group, |
|---|
| 937 | + NULL |
|---|
| 938 | +}; |
|---|
| 939 | + |
|---|
| 603 | 940 | static struct platform_driver afu_driver = { |
|---|
| 604 | 941 | .driver = { |
|---|
| 605 | | - .name = DFL_FPGA_FEATURE_DEV_PORT, |
|---|
| 942 | + .name = DFL_FPGA_FEATURE_DEV_PORT, |
|---|
| 943 | + .dev_groups = afu_dev_groups, |
|---|
| 606 | 944 | }, |
|---|
| 607 | 945 | .probe = afu_probe, |
|---|
| 608 | 946 | .remove = afu_remove, |
|---|