Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc/powernv: Fix indirect XSCOM unmangling

We need to unmangle the full address, not just the register
number, and we also need to support the real indirect bit
being set for in-kernel uses.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
CC: <stable@vger.kernel.org> [v3.13]

+12 -9
+12 -9
arch/powerpc/platforms/powernv/opal-xscom.c
··· 71 71 } 72 72 } 73 73 74 - static u64 opal_scom_unmangle(u64 reg) 74 + static u64 opal_scom_unmangle(u64 addr) 75 75 { 76 76 /* 77 77 * XSCOM indirect addresses have the top bit set. Additionally 78 - * the reset of the top 3 nibbles is always 0. 78 + * the rest of the top 3 nibbles is always 0. 79 79 * 80 80 * Because the debugfs interface uses signed offsets and shifts 81 81 * the address left by 3, we basically cannot use the top 4 bits ··· 86 86 * conversion here. To leave room for further xscom address 87 87 * expansion, we only clear out the top byte 88 88 * 89 + * For in-kernel use, we also support the real indirect bit, so 90 + * we test for any of the top 5 bits 91 + * 89 92 */ 90 - if (reg & (1ull << 59)) 91 - reg = (reg & ~(0xffull << 56)) | (1ull << 63); 92 - return reg; 93 + if (addr & (0x1full << 59)) 94 + addr = (addr & ~(0xffull << 56)) | (1ull << 63); 95 + return addr; 93 96 } 94 97 95 98 static int opal_scom_read(scom_map_t map, u64 reg, u64 *value) ··· 101 98 int64_t rc; 102 99 __be64 v; 103 100 104 - reg = opal_scom_unmangle(reg); 105 - rc = opal_xscom_read(m->chip, m->addr + reg, (__be64 *)__pa(&v)); 101 + reg = opal_scom_unmangle(m->addr + reg); 102 + rc = opal_xscom_read(m->chip, reg, (__be64 *)__pa(&v)); 106 103 *value = be64_to_cpu(v); 107 104 return opal_xscom_err_xlate(rc); 108 105 } ··· 112 109 struct opal_scom_map *m = map; 113 110 int64_t rc; 114 111 115 - reg = opal_scom_unmangle(reg); 116 - rc = opal_xscom_write(m->chip, m->addr + reg, value); 112 + reg = opal_scom_unmangle(m->addr + reg); 113 + rc = opal_xscom_write(m->chip, reg, value); 117 114 return opal_xscom_err_xlate(rc); 118 115 } 119 116