.. | .. |
---|
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, |
---|