vfio_platform_bcmflexrm.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. /*
  2. * Copyright (C) 2017 Broadcom
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License as
  6. * published by the Free Software Foundation version 2.
  7. *
  8. * This program is distributed "as is" WITHOUT ANY WARRANTY of any
  9. * kind, whether express or implied; without even the implied warranty
  10. * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. */
  13. /*
  14. * This driver provides reset support for Broadcom FlexRM ring manager
  15. * to VFIO platform.
  16. */
  17. #include <linux/delay.h>
  18. #include <linux/device.h>
  19. #include <linux/init.h>
  20. #include <linux/io.h>
  21. #include <linux/kernel.h>
  22. #include <linux/module.h>
  23. #include "vfio_platform_private.h"
  24. /* FlexRM configuration */
  25. #define RING_REGS_SIZE 0x10000
  26. #define RING_VER_MAGIC 0x76303031
  27. /* Per-Ring register offsets */
  28. #define RING_VER 0x000
  29. #define RING_CONTROL 0x034
  30. #define RING_FLUSH_DONE 0x038
  31. /* Register RING_CONTROL fields */
  32. #define CONTROL_FLUSH_SHIFT 5
  33. /* Register RING_FLUSH_DONE fields */
  34. #define FLUSH_DONE_MASK 0x1
  35. static int vfio_platform_bcmflexrm_shutdown(void __iomem *ring)
  36. {
  37. unsigned int timeout;
  38. /* Disable/inactivate ring */
  39. writel_relaxed(0x0, ring + RING_CONTROL);
  40. /* Set ring flush state */
  41. timeout = 1000; /* timeout of 1s */
  42. writel_relaxed(BIT(CONTROL_FLUSH_SHIFT), ring + RING_CONTROL);
  43. do {
  44. if (readl_relaxed(ring + RING_FLUSH_DONE) &
  45. FLUSH_DONE_MASK)
  46. break;
  47. mdelay(1);
  48. } while (--timeout);
  49. if (!timeout)
  50. return -ETIMEDOUT;
  51. /* Clear ring flush state */
  52. timeout = 1000; /* timeout of 1s */
  53. writel_relaxed(0x0, ring + RING_CONTROL);
  54. do {
  55. if (!(readl_relaxed(ring + RING_FLUSH_DONE) &
  56. FLUSH_DONE_MASK))
  57. break;
  58. mdelay(1);
  59. } while (--timeout);
  60. if (!timeout)
  61. return -ETIMEDOUT;
  62. return 0;
  63. }
  64. static int vfio_platform_bcmflexrm_reset(struct vfio_platform_device *vdev)
  65. {
  66. void __iomem *ring;
  67. int rc = 0, ret = 0, ring_num = 0;
  68. struct vfio_platform_region *reg = &vdev->regions[0];
  69. /* Map FlexRM ring registers if not mapped */
  70. if (!reg->ioaddr) {
  71. reg->ioaddr = ioremap_nocache(reg->addr, reg->size);
  72. if (!reg->ioaddr)
  73. return -ENOMEM;
  74. }
  75. /* Discover and shutdown each FlexRM ring */
  76. for (ring = reg->ioaddr;
  77. ring < (reg->ioaddr + reg->size); ring += RING_REGS_SIZE) {
  78. if (readl_relaxed(ring + RING_VER) == RING_VER_MAGIC) {
  79. rc = vfio_platform_bcmflexrm_shutdown(ring);
  80. if (rc) {
  81. dev_warn(vdev->device,
  82. "FlexRM ring%d shutdown error %d\n",
  83. ring_num, rc);
  84. ret |= rc;
  85. }
  86. ring_num++;
  87. }
  88. }
  89. return ret;
  90. }
  91. module_vfio_reset_handler("brcm,iproc-flexrm-mbox",
  92. vfio_platform_bcmflexrm_reset);
  93. MODULE_LICENSE("GPL v2");
  94. MODULE_AUTHOR("Anup Patel <anup.patel@broadcom.com>");
  95. MODULE_DESCRIPTION("Reset support for Broadcom FlexRM VFIO platform device");