aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/platforms/powernv/opal-lpc.c59
1 files changed, 59 insertions, 0 deletions
diff --git a/arch/powerpc/platforms/powernv/opal-lpc.c b/arch/powerpc/platforms/powernv/opal-lpc.c
index ad4b31df779a..e4169d68cb32 100644
--- a/arch/powerpc/platforms/powernv/opal-lpc.c
+++ b/arch/powerpc/platforms/powernv/opal-lpc.c
@@ -216,14 +216,54 @@ static ssize_t lpc_debug_read(struct file *filp, char __user *ubuf,
216 &data, len); 216 &data, len);
217 if (rc) 217 if (rc)
218 return -ENXIO; 218 return -ENXIO;
219
220 /*
221 * Now there is some trickery with the data returned by OPAL
222 * as it's the desired data right justified in a 32-bit BE
223 * word.
224 *
225 * This is a very bad interface and I'm to blame for it :-(
226 *
227 * So we can't just apply a 32-bit swap to what comes from OPAL,
228 * because user space expects the *bytes* to be in their proper
229 * respective positions (ie, LPC position).
230 *
231 * So what we really want to do here is to shift data right
232 * appropriately on a LE kernel.
233 *
234 * IE. If the LPC transaction has bytes B0, B1, B2 and B3 in that
235 * order, we have in memory written to by OPAL at the "data"
236 * pointer:
237 *
238 * Bytes: OPAL "data" LE "data"
239 * 32-bit: B0 B1 B2 B3 B0B1B2B3 B3B2B1B0
240 * 16-bit: B0 B1 0000B0B1 B1B00000
241 * 8-bit: B0 000000B0 B0000000
242 *
243 * So a BE kernel will have the leftmost of the above in the MSB
244 * and rightmost in the LSB and can just then "cast" the u32 "data"
245 * down to the appropriate quantity and write it.
246 *
247 * However, an LE kernel can't. It doesn't need to swap because a
248 * load from data followed by a store to user are going to preserve
249 * the byte ordering which is the wire byte order which is what the
250 * user wants, but in order to "crop" to the right size, we need to
251 * shift right first.
252 */
219 switch(len) { 253 switch(len) {
220 case 4: 254 case 4:
221 rc = __put_user((u32)data, (u32 __user *)ubuf); 255 rc = __put_user((u32)data, (u32 __user *)ubuf);
222 break; 256 break;
223 case 2: 257 case 2:
258#ifdef __LITTLE_ENDIAN__
259 data >>= 16;
260#endif
224 rc = __put_user((u16)data, (u16 __user *)ubuf); 261 rc = __put_user((u16)data, (u16 __user *)ubuf);
225 break; 262 break;
226 default: 263 default:
264#ifdef __LITTLE_ENDIAN__
265 data >>= 24;
266#endif
227 rc = __put_user((u8)data, (u8 __user *)ubuf); 267 rc = __put_user((u8)data, (u8 __user *)ubuf);
228 break; 268 break;
229 } 269 }
@@ -263,12 +303,31 @@ static ssize_t lpc_debug_write(struct file *filp, const char __user *ubuf,
263 else if (todo > 1 && (pos & 1) == 0) 303 else if (todo > 1 && (pos & 1) == 0)
264 len = 2; 304 len = 2;
265 } 305 }
306
307 /*
308 * Similarly to the read case, we have some trickery here but
309 * it's different to handle. We need to pass the value to OPAL in
310 * a register whose layout depends on the access size. We want
311 * to reproduce the memory layout of the user, however we aren't
312 * doing a load from user and a store to another memory location
313 * which would achieve that. Here we pass the value to OPAL via
314 * a register which is expected to contain the "BE" interpretation
315 * of the byte sequence. IE: for a 32-bit access, byte 0 should be
316 * in the MSB. So here we *do* need to byteswap on LE.
317 *
318 * User bytes: LE "data" OPAL "data"
319 * 32-bit: B0 B1 B2 B3 B3B2B1B0 B0B1B2B3
320 * 16-bit: B0 B1 0000B1B0 0000B0B1
321 * 8-bit: B0 000000B0 000000B0
322 */
266 switch(len) { 323 switch(len) {
267 case 4: 324 case 4:
268 rc = __get_user(data, (u32 __user *)ubuf); 325 rc = __get_user(data, (u32 __user *)ubuf);
326 data = cpu_to_be32(data);
269 break; 327 break;
270 case 2: 328 case 2:
271 rc = __get_user(data, (u16 __user *)ubuf); 329 rc = __get_user(data, (u16 __user *)ubuf);
330 data = cpu_to_be16(data);
272 break; 331 break;
273 default: 332 default:
274 rc = __get_user(data, (u8 __user *)ubuf); 333 rc = __get_user(data, (u8 __user *)ubuf);