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 /* 15 * This driver provides reset support for Broadcom FlexRM ring manager 16 * to VFIO platform. 17 */ 18 19 #include <linux/delay.h> 20 #include <linux/device.h> 21 #include <linux/init.h> 22 #include <linux/io.h> 23 #include <linux/kernel.h> 24 #include <linux/module.h> 25 26 #include "vfio_platform_private.h" 27 28 /* FlexRM configuration */ 29 #define RING_REGS_SIZE 0x10000 30 #define RING_VER_MAGIC 0x76303031 31 32 /* Per-Ring register offsets */ 33 #define RING_VER 0x000 34 #define RING_CONTROL 0x034 35 #define RING_FLUSH_DONE 0x038 36 37 /* Register RING_CONTROL fields */ 38 #define CONTROL_FLUSH_SHIFT 5 39 40 /* Register RING_FLUSH_DONE fields */ 41 #define FLUSH_DONE_MASK 0x1 42 43 static int vfio_platform_bcmflexrm_shutdown(void __iomem *ring) 44 { 45 unsigned int timeout; 46 47 /* Disable/inactivate ring */ 48 writel_relaxed(0x0, ring + RING_CONTROL); 49 50 /* Set ring flush state */ 51 timeout = 1000; /* timeout of 1s */ 52 writel_relaxed(BIT(CONTROL_FLUSH_SHIFT), ring + RING_CONTROL); 53 do { 54 if (readl_relaxed(ring + RING_FLUSH_DONE) & 55 FLUSH_DONE_MASK) 56 break; 57 mdelay(1); 58 } while (--timeout); 59 if (!timeout) 60 return -ETIMEDOUT; 61 62 /* Clear ring flush state */ 63 timeout = 1000; /* timeout of 1s */ 64 writel_relaxed(0x0, ring + RING_CONTROL); 65 do { 66 if (!(readl_relaxed(ring + RING_FLUSH_DONE) & 67 FLUSH_DONE_MASK)) 68 break; 69 mdelay(1); 70 } while (--timeout); 71 if (!timeout) 72 return -ETIMEDOUT; 73 74 return 0; 75 } 76 77 static int vfio_platform_bcmflexrm_reset(struct vfio_platform_device *vdev) 78 { 79 void __iomem *ring; 80 int rc = 0, ret = 0, ring_num = 0; 81 struct vfio_platform_region *reg = &vdev->regions[0]; 82 83 /* Map FlexRM ring registers if not mapped */ 84 if (!reg->ioaddr) { 85 reg->ioaddr = ioremap_nocache(reg->addr, reg->size); 86 if (!reg->ioaddr) 87 return -ENOMEM; 88 } 89 90 /* Discover and shutdown each FlexRM ring */ 91 for (ring = reg->ioaddr; 92 ring < (reg->ioaddr + reg->size); ring += RING_REGS_SIZE) { 93 if (readl_relaxed(ring + RING_VER) == RING_VER_MAGIC) { 94 rc = vfio_platform_bcmflexrm_shutdown(ring); 95 if (rc) { 96 dev_warn(vdev->device, 97 "FlexRM ring%d shutdown error %d\n", 98 ring_num, rc); 99 ret |= rc; 100 } 101 ring_num++; 102 } 103 } 104 105 return ret; 106 } 107 108 module_vfio_reset_handler("brcm,iproc-flexrm-mbox", 109 vfio_platform_bcmflexrm_reset); 110 111 MODULE_LICENSE("GPL v2"); 112 MODULE_AUTHOR("Anup Patel <anup.patel@broadcom.com>"); 113 MODULE_DESCRIPTION("Reset support for Broadcom FlexRM VFIO platform device"); 114