Stephen Warren was concerned that the rmb() present in the new mailbox driver was unnecessary, and after seeing the docs, that it was just so surprising that somebody would come along and remove it later. The explanation for the need for the rmb() is long enough that we won't want to place it at every callsite. Make a wrapper with the whole explanation in it, so that anyone wondering what's going on sees the docs right there. Signed-off-by: Eric Anholt <eric@xxxxxxxxxx> --- include/soc/bcm2835/peripheral-workaround.h | 75 +++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 include/soc/bcm2835/peripheral-workaround.h diff --git a/include/soc/bcm2835/peripheral-workaround.h b/include/soc/bcm2835/peripheral-workaround.h new file mode 100644 index 0000000..4541a13 --- /dev/null +++ b/include/soc/bcm2835/peripheral-workaround.h @@ -0,0 +1,75 @@ +/* + * Copyright © 2015 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +static inline void bcm2835_peripheral_read_workaround(void) +{ +#ifdef CONFIG_ARCH_BCM2835 + /* + * The BCM2835 bus is unusual in that it doesn't guarantee + * ordering between reads from different peripherals (where + * peripherals roughly correspond to Linux devices). From + * BCM2835 ARM Peripherals.pdf, page 7: + * + * "In order to keep the system complexity low and data + * throughput high, the BCM2835 AXI system does not + * always return read data in-order. The GPU has special + * logic to cope with data arriving out-of-order; however + * the ARM core does not contain such logic. Therefore + * some precautions must be taken when using the ARM to + * access peripherals. + * + * Accesses to the same peripheral will always arrive and + * return in-order. It is only when switching from one + * peripheral to another that data can arrive + * out-of-order. The simplest way to make sure that data + * is processed in-order is to place a memory barrier + * instruction at critical positions in the code. You + * should place: + * + * • A memory write barrier before the first write to a + * peripheral. + * • A memory read barrier after the last read of a + * peripheral." + * + * The footnote explicitly says that: + * + * "For example: + * + * a_status = *pointer_to_peripheral_a; + * b_status = *pointer_to_peripheral_b; + * + * Without precuations the values ending up in the + * variables a_status and b_status can be swapped + * around." + * + * However, it also notes that, somewhat contrary to the first + * bullet point: + * + * "It is theoretical possible for writes to go ‘wrong’ + * but that is far more difficult to achieve. The AXI + * system makes sure the data always arrives in-order at + * its intended destination. So: + * + * *pointer_to_peripheral_a = value_a; + * *pointer_to_peripheral_b = value_b; + * + * will always give the expected result. The only time + * write data can arrive out-of-order is if two different + * peripherals are connected to the same external + * equipment" + * + * Since we aren't interacting with multiple peripherals + * connected to the same external equipment as far as we know, + * that means that we only need to handle the read workaround + * case. We do so by placing an rmb() at the first device + * read acceess in a given driver path, including the + * interrupt handlers. + */ + rmb(); +#endif +} -- 2.1.4 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html