[PATCH] fsl-rio: add support for mapping inbound windows

Subsystems: linux for powerpc (32-bit and 64-bit), the rest

STALE4346d

5 messages, 3 authors, 2014-09-17 · open the first message on its own page

[PATCH] fsl-rio: add support for mapping inbound windows

From: Martijn de Gouw <hidden>
Date: 2014-08-05 14:16:10

Add support for mapping and unmapping of inbound rapidio windows.

Signed-off-by: Martijn de Gouw <redacted>
---
 arch/powerpc/sysdev/fsl_rio.c |  104 +++++++++++++++++++++++++++++++++++++++++
 arch/powerpc/sysdev/fsl_rio.h |   13 ++++++
 2 files changed, 117 insertions(+)
diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c
index c04b718..08d60f1 100644
--- a/arch/powerpc/sysdev/fsl_rio.c
+++ b/arch/powerpc/sysdev/fsl_rio.c
@@ -58,6 +58,19 @@
 #define RIO_ISR_AACR		0x10120
 #define RIO_ISR_AACR_AA		0x1	/* Accept All ID */
 
+#define RIWTAR_TRAD_VAL_SHIFT	12
+#define RIWTAR_TRAD_MASK	0x00FFFFFF
+#define RIWBAR_BADD_VAL_SHIFT	12
+#define RIWBAR_BADD_MASK	0x003FFFFF
+#define RIWAR_ENABLE		0x80000000
+#define RIWAR_TGINT_LOCAL	0x00F00000
+#define RIWAR_RDTYP_NO_SNOOP	0x00040000
+#define RIWAR_RDTYP_SNOOP	0x00050000
+#define RIWAR_WRTYP_NO_SNOOP	0x00004000
+#define RIWAR_WRTYP_SNOOP	0x00005000
+#define RIWAR_WRTYP_ALLOC	0x00006000
+#define RIWAR_SIZE_MASK		0x0000003F
+
 #define __fsl_read_rio_config(x, addr, err, op)		\
 	__asm__ __volatile__(				\
 		"1:	"op" %1,0(%2)\n"		\
@@ -266,6 +279,89 @@ fsl_rio_config_write(struct rio_mport *mport, int index, u16 destid,
 	return 0;
 }
 
+static void fsl_rio_inbound_mem_init(struct rio_priv *priv)
+{
+	int i;
+
+	/* close inbound windows */
+	for (i = 0; i < RIO_INB_ATMU_COUNT; i++)
+		out_be32(&priv->inb_atmu_regs[i].riwar, 0);
+}
+
+int fsl_map_inb_mem(struct rio_mport *mport, dma_addr_t lstart,
+	u64 rstart, u32 size, u32 flags)
+{
+	struct rio_priv *priv = mport->priv;
+	u32 base_size;
+	unsigned int base_size_log;
+	u64 win_start, win_end;
+	u32 riwar;
+	int i;
+
+	if ((size & (size - 1)) != 0)
+		return -EINVAL;
+
+	base_size_log = ilog2(size);
+	base_size = 1 << base_size_log;
+
+	/* check if addresses are aligned with the window size */
+	if (lstart & (base_size - 1))
+		return -EINVAL;
+	if (rstart & (base_size - 1))
+		return -EINVAL;
+
+	/* check for conflicting ranges */
+	for (i = 0; i < RIO_INB_ATMU_COUNT; i++) {
+		riwar = in_be32(&priv->inb_atmu_regs[i].riwar);
+		if ((riwar & RIWAR_ENABLE) == 0)
+			continue;
+		win_start = ((u64)(in_be32(&priv->inb_atmu_regs[i].riwbar) & RIWBAR_BADD_MASK))
+			<< RIWBAR_BADD_VAL_SHIFT;
+		win_end = win_start + ((1 << ((riwar & RIWAR_SIZE_MASK) + 1)) - 1);
+		if (rstart < win_end && (rstart + size) > win_start)
+			return -EINVAL;
+	}
+
+	/* find unused atmu */
+	for (i = 0; i < RIO_INB_ATMU_COUNT; i++) {
+		riwar = in_be32(&priv->inb_atmu_regs[i].riwar);
+		if ((riwar & RIWAR_ENABLE) == 0)
+			break;
+	}
+	if (i >= RIO_INB_ATMU_COUNT)
+		return -ENOMEM;
+
+	out_be32(&priv->inb_atmu_regs[i].riwtar, lstart >> RIWTAR_TRAD_VAL_SHIFT);
+	out_be32(&priv->inb_atmu_regs[i].riwbar, rstart >> RIWBAR_BADD_VAL_SHIFT);
+	out_be32(&priv->inb_atmu_regs[i].riwar, RIWAR_ENABLE | RIWAR_TGINT_LOCAL |
+		RIWAR_RDTYP_SNOOP | RIWAR_WRTYP_SNOOP | (base_size_log - 1));
+
+	return 0;
+}
+
+void fsl_unmap_inb_mem(struct rio_mport *mport, dma_addr_t lstart)
+{
+	u32 win_start_shift, base_start_shift;
+	struct rio_priv *priv = mport->priv;
+	u32 riwar, riwtar;
+	int i;
+
+	/* skip default window */
+	base_start_shift = lstart >> RIWTAR_TRAD_VAL_SHIFT;
+	for (i = 0; i < RIO_INB_ATMU_COUNT; i++) {
+		riwar = in_be32(&priv->inb_atmu_regs[i].riwar);
+		if ((riwar & RIWAR_ENABLE) == 0)
+			continue;
+
+		riwtar = in_be32(&priv->inb_atmu_regs[i].riwtar);
+		win_start_shift = riwtar & RIWTAR_TRAD_MASK;
+		if (win_start_shift == base_start_shift) {
+			out_be32(&priv->inb_atmu_regs[i].riwar, riwar & ~RIWAR_ENABLE);
+			return;
+		}
+	}
+}
+
 void fsl_rio_port_error_handler(int offset)
 {
 	/*XXX: Error recovery is not implemented, we just clear errors */
@@ -389,6 +485,8 @@ int fsl_rio_setup(struct platform_device *dev)
 	ops->add_outb_message = fsl_add_outb_message;
 	ops->add_inb_buffer = fsl_add_inb_buffer;
 	ops->get_inb_message = fsl_get_inb_message;
+	ops->map_inb = fsl_map_inb_mem;
+	ops->unmap_inb = fsl_unmap_inb_mem;
 
 	rmu_node = of_parse_phandle(dev->dev.of_node, "fsl,srio-rmu-handle", 0);
 	if (!rmu_node) {
@@ -602,6 +700,11 @@ int fsl_rio_setup(struct platform_device *dev)
 			RIO_ATMU_REGS_PORT2_OFFSET));
 
 		priv->maint_atmu_regs = priv->atmu_regs + 1;
+		priv->inb_atmu_regs = (struct rio_inb_atmu_regs __iomem *)
+			(priv->regs_win +
+			((i == 0) ? RIO_INB_ATMU_REGS_PORT1_OFFSET :
+			RIO_INB_ATMU_REGS_PORT2_OFFSET));
+
 
 		/* Set to receive any dist ID for serial RapidIO controller. */
 		if (port->phy_type == RIO_PHY_SERIAL)
@@ -620,6 +723,7 @@ int fsl_rio_setup(struct platform_device *dev)
 		rio_law_start = range_start;
 
 		fsl_rio_setup_rmu(port, rmu_np[i]);
+		fsl_rio_inbound_mem_init(priv);
 
 		dbell->mport[i] = port;
 
diff --git a/arch/powerpc/sysdev/fsl_rio.h b/arch/powerpc/sysdev/fsl_rio.h
index ae8e274..d53407a 100644
--- a/arch/powerpc/sysdev/fsl_rio.h
+++ b/arch/powerpc/sysdev/fsl_rio.h
@@ -50,9 +50,12 @@
 #define RIO_S_DBELL_REGS_OFFSET	0x13400
 #define RIO_S_PW_REGS_OFFSET	0x134e0
 #define RIO_ATMU_REGS_DBELL_OFFSET	0x10C40
+#define RIO_INB_ATMU_REGS_PORT1_OFFSET 0x10d60
+#define RIO_INB_ATMU_REGS_PORT2_OFFSET 0x10f60
 
 #define MAX_MSG_UNIT_NUM	2
 #define MAX_PORT_NUM		4
+#define RIO_INB_ATMU_COUNT	4
 
 struct rio_atmu_regs {
 	 u32 rowtar;
@@ -63,6 +66,15 @@ struct rio_atmu_regs {
 	 u32 pad2[3];
 };
 
+struct rio_inb_atmu_regs {
+	u32 riwtar;
+	u32 pad1;
+	u32 riwbar;
+	u32 pad2;
+	u32 riwar;
+	u32 pad3[3];
+};
+
 struct rio_dbell_ring {
 	void *virt;
 	dma_addr_t phys;
@@ -99,6 +111,7 @@ struct rio_priv {
 	void __iomem *regs_win;
 	struct rio_atmu_regs __iomem *atmu_regs;
 	struct rio_atmu_regs __iomem *maint_atmu_regs;
+	struct rio_inb_atmu_regs __iomem *inb_atmu_regs;
 	void __iomem *maint_win;
 	void *rmm_handle; /* RapidIO message manager(unit) Handle */
 };
-- 
1.7.10.4

Re: [PATCH] fsl-rio: add support for mapping inbound windows

From: Scott Wood <hidden>
Date: 2014-08-05 21:38:03

On Tue, 2014-08-05 at 15:52 +0200, Martijn de Gouw wrote:
Add support for mapping and unmapping of inbound rapidio windows.

Signed-off-by: Martijn de Gouw <redacted>
Could you elaborate in the changelog on what this fixes or makes
possible?  E.g. did the driver previously not support inbound
transactions at all, or did it assume the window was set up by a
bootloader?

Liu Gang, could you review this?

-Scott
quoted hunk
---
 arch/powerpc/sysdev/fsl_rio.c |  104 +++++++++++++++++++++++++++++++++++++++++
 arch/powerpc/sysdev/fsl_rio.h |   13 ++++++
 2 files changed, 117 insertions(+)
diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c
index c04b718..08d60f1 100644
--- a/arch/powerpc/sysdev/fsl_rio.c
+++ b/arch/powerpc/sysdev/fsl_rio.c
@@ -58,6 +58,19 @@
 #define RIO_ISR_AACR		0x10120
 #define RIO_ISR_AACR_AA		0x1	/* Accept All ID */
 
+#define RIWTAR_TRAD_VAL_SHIFT	12
+#define RIWTAR_TRAD_MASK	0x00FFFFFF
+#define RIWBAR_BADD_VAL_SHIFT	12
+#define RIWBAR_BADD_MASK	0x003FFFFF
+#define RIWAR_ENABLE		0x80000000
+#define RIWAR_TGINT_LOCAL	0x00F00000
+#define RIWAR_RDTYP_NO_SNOOP	0x00040000
+#define RIWAR_RDTYP_SNOOP	0x00050000
+#define RIWAR_WRTYP_NO_SNOOP	0x00004000
+#define RIWAR_WRTYP_SNOOP	0x00005000
+#define RIWAR_WRTYP_ALLOC	0x00006000
+#define RIWAR_SIZE_MASK		0x0000003F
+
 #define __fsl_read_rio_config(x, addr, err, op)		\
 	__asm__ __volatile__(				\
 		"1:	"op" %1,0(%2)\n"		\
@@ -266,6 +279,89 @@ fsl_rio_config_write(struct rio_mport *mport, int index, u16 destid,
 	return 0;
 }
 
+static void fsl_rio_inbound_mem_init(struct rio_priv *priv)
+{
+	int i;
+
+	/* close inbound windows */
+	for (i = 0; i < RIO_INB_ATMU_COUNT; i++)
+		out_be32(&priv->inb_atmu_regs[i].riwar, 0);
+}
+
+int fsl_map_inb_mem(struct rio_mport *mport, dma_addr_t lstart,
+	u64 rstart, u32 size, u32 flags)
+{
+	struct rio_priv *priv = mport->priv;
+	u32 base_size;
+	unsigned int base_size_log;
+	u64 win_start, win_end;
+	u32 riwar;
+	int i;
+
+	if ((size & (size - 1)) != 0)
+		return -EINVAL;
+
+	base_size_log = ilog2(size);
+	base_size = 1 << base_size_log;
+
+	/* check if addresses are aligned with the window size */
+	if (lstart & (base_size - 1))
+		return -EINVAL;
+	if (rstart & (base_size - 1))
+		return -EINVAL;
+
+	/* check for conflicting ranges */
+	for (i = 0; i < RIO_INB_ATMU_COUNT; i++) {
+		riwar = in_be32(&priv->inb_atmu_regs[i].riwar);
+		if ((riwar & RIWAR_ENABLE) == 0)
+			continue;
+		win_start = ((u64)(in_be32(&priv->inb_atmu_regs[i].riwbar) & RIWBAR_BADD_MASK))
+			<< RIWBAR_BADD_VAL_SHIFT;
+		win_end = win_start + ((1 << ((riwar & RIWAR_SIZE_MASK) + 1)) - 1);
+		if (rstart < win_end && (rstart + size) > win_start)
+			return -EINVAL;
+	}
+
+	/* find unused atmu */
+	for (i = 0; i < RIO_INB_ATMU_COUNT; i++) {
+		riwar = in_be32(&priv->inb_atmu_regs[i].riwar);
+		if ((riwar & RIWAR_ENABLE) == 0)
+			break;
+	}
+	if (i >= RIO_INB_ATMU_COUNT)
+		return -ENOMEM;
+
+	out_be32(&priv->inb_atmu_regs[i].riwtar, lstart >> RIWTAR_TRAD_VAL_SHIFT);
+	out_be32(&priv->inb_atmu_regs[i].riwbar, rstart >> RIWBAR_BADD_VAL_SHIFT);
+	out_be32(&priv->inb_atmu_regs[i].riwar, RIWAR_ENABLE | RIWAR_TGINT_LOCAL |
+		RIWAR_RDTYP_SNOOP | RIWAR_WRTYP_SNOOP | (base_size_log - 1));
+
+	return 0;
+}
+
+void fsl_unmap_inb_mem(struct rio_mport *mport, dma_addr_t lstart)
+{
+	u32 win_start_shift, base_start_shift;
+	struct rio_priv *priv = mport->priv;
+	u32 riwar, riwtar;
+	int i;
+
+	/* skip default window */
+	base_start_shift = lstart >> RIWTAR_TRAD_VAL_SHIFT;
+	for (i = 0; i < RIO_INB_ATMU_COUNT; i++) {
+		riwar = in_be32(&priv->inb_atmu_regs[i].riwar);
+		if ((riwar & RIWAR_ENABLE) == 0)
+			continue;
+
+		riwtar = in_be32(&priv->inb_atmu_regs[i].riwtar);
+		win_start_shift = riwtar & RIWTAR_TRAD_MASK;
+		if (win_start_shift == base_start_shift) {
+			out_be32(&priv->inb_atmu_regs[i].riwar, riwar & ~RIWAR_ENABLE);
+			return;
+		}
+	}
+}
+
 void fsl_rio_port_error_handler(int offset)
 {
 	/*XXX: Error recovery is not implemented, we just clear errors */
@@ -389,6 +485,8 @@ int fsl_rio_setup(struct platform_device *dev)
 	ops->add_outb_message = fsl_add_outb_message;
 	ops->add_inb_buffer = fsl_add_inb_buffer;
 	ops->get_inb_message = fsl_get_inb_message;
+	ops->map_inb = fsl_map_inb_mem;
+	ops->unmap_inb = fsl_unmap_inb_mem;
 
 	rmu_node = of_parse_phandle(dev->dev.of_node, "fsl,srio-rmu-handle", 0);
 	if (!rmu_node) {
@@ -602,6 +700,11 @@ int fsl_rio_setup(struct platform_device *dev)
 			RIO_ATMU_REGS_PORT2_OFFSET));
 
 		priv->maint_atmu_regs = priv->atmu_regs + 1;
+		priv->inb_atmu_regs = (struct rio_inb_atmu_regs __iomem *)
+			(priv->regs_win +
+			((i == 0) ? RIO_INB_ATMU_REGS_PORT1_OFFSET :
+			RIO_INB_ATMU_REGS_PORT2_OFFSET));
+
 
 		/* Set to receive any dist ID for serial RapidIO controller. */
 		if (port->phy_type == RIO_PHY_SERIAL)
@@ -620,6 +723,7 @@ int fsl_rio_setup(struct platform_device *dev)
 		rio_law_start = range_start;
 
 		fsl_rio_setup_rmu(port, rmu_np[i]);
+		fsl_rio_inbound_mem_init(priv);
 
 		dbell->mport[i] = port;
 
diff --git a/arch/powerpc/sysdev/fsl_rio.h b/arch/powerpc/sysdev/fsl_rio.h
index ae8e274..d53407a 100644
--- a/arch/powerpc/sysdev/fsl_rio.h
+++ b/arch/powerpc/sysdev/fsl_rio.h
@@ -50,9 +50,12 @@
 #define RIO_S_DBELL_REGS_OFFSET	0x13400
 #define RIO_S_PW_REGS_OFFSET	0x134e0
 #define RIO_ATMU_REGS_DBELL_OFFSET	0x10C40
+#define RIO_INB_ATMU_REGS_PORT1_OFFSET 0x10d60
+#define RIO_INB_ATMU_REGS_PORT2_OFFSET 0x10f60
 
 #define MAX_MSG_UNIT_NUM	2
 #define MAX_PORT_NUM		4
+#define RIO_INB_ATMU_COUNT	4
 
 struct rio_atmu_regs {
 	 u32 rowtar;
@@ -63,6 +66,15 @@ struct rio_atmu_regs {
 	 u32 pad2[3];
 };
 
+struct rio_inb_atmu_regs {
+	u32 riwtar;
+	u32 pad1;
+	u32 riwbar;
+	u32 pad2;
+	u32 riwar;
+	u32 pad3[3];
+};
+
 struct rio_dbell_ring {
 	void *virt;
 	dma_addr_t phys;
@@ -99,6 +111,7 @@ struct rio_priv {
 	void __iomem *regs_win;
 	struct rio_atmu_regs __iomem *atmu_regs;
 	struct rio_atmu_regs __iomem *maint_atmu_regs;
+	struct rio_inb_atmu_regs __iomem *inb_atmu_regs;
 	void __iomem *maint_win;
 	void *rmm_handle; /* RapidIO message manager(unit) Handle */
 };

Re: [PATCH] fsl-rio: add support for mapping inbound windows

From: Martijn de Gouw <hidden>
Date: 2014-08-12 08:48:04

On 08/05/2014 11:37 PM, Scott Wood wrote:
On Tue, 2014-08-05 at 15:52 +0200, Martijn de Gouw wrote:
quoted
Add support for mapping and unmapping of inbound rapidio windows.

Signed-off-by: Martijn de Gouw <redacted>
Could you elaborate in the changelog on what this fixes or makes
possible?  E.g. did the driver previously not support inbound
transactions at all, or did it assume the window was set up by a
bootloader?
Something like:

fsl-rio: add support for mapping inbound windows

     Add support for mapping and unmapping of inbound rapidio windows.
     This allows for drivers to open up a part of local memory on the
     rapidio network. Also applications can use this and tranfer blocks
     of data over the network.
Liu Gang, could you review this?
I'll wait for the review before I post a new version.

Gr, Martijn


-- 
Martijn de Gouw
Engineer
Prodrive Technologies B.V.
Mobile: +31 63 17 76 161
Phone:  +31 40 26 76 200

Re: [PATCH] fsl-rio: add support for mapping inbound windows

From: Scott Wood <hidden>
Date: 2014-09-03 22:42:54

On Tue, 2014-08-05 at 16:37 -0500, Scott Wood wrote:
On Tue, 2014-08-05 at 15:52 +0200, Martijn de Gouw wrote:
quoted
Add support for mapping and unmapping of inbound rapidio windows.

Signed-off-by: Martijn de Gouw <redacted>
Could you elaborate in the changelog on what this fixes or makes
possible?  E.g. did the driver previously not support inbound
transactions at all, or did it assume the window was set up by a
bootloader?

Liu Gang, could you review this?
Liu Gang, ping?

-Scott

RE: [PATCH] fsl-rio: add support for mapping inbound windows

From: Gang.Liu@freescale.com <hidden>
Date: 2014-09-17 03:52:54

SXQgbG9va3MgZ29vZCBmb3IgbWUuDQoNCkxpdSBHYW5nDQoNCj4gLS0tLS1PcmlnaW5hbCBNZXNz
YWdlLS0tLS0NCj4gRnJvbTogTWFydGlqbiBkZSBHb3V3IFttYWlsdG86bWFydGlqbi5kZS5nb3V3
QHByb2RyaXZlLXRlY2hub2xvZ2llcy5jb21dDQo+IFNlbnQ6IFR1ZXNkYXksIEF1Z3VzdCAxMiwg
MjAxNCA0OjQ4IFBNDQo+IFRvOiBXb29kIFNjb3R0LUIwNzQyMQ0KPiBDYzogbGludXhwcGMtZGV2
QGxpc3RzLm96bGFicy5vcmc7IEFsZXhhbmRyZS5Cb3VuaW5lQGlkdC5jb207DQo+IHN0ZWYudmFu
Lm9zQHByb2RyaXZlLXRlY2hub2xvZ2llcy5jb207IEJhcnJ5Lldvb2RAaWR0LmNvbTsgTGl1IEdh
bmctDQo+IEIzNDE4Mg0KPiBTdWJqZWN0OiBSZTogW1BBVENIXSBmc2wtcmlvOiBhZGQgc3VwcG9y
dCBmb3IgbWFwcGluZyBpbmJvdW5kIHdpbmRvd3MNCj4gDQo+IE9uIDA4LzA1LzIwMTQgMTE6Mzcg
UE0sIFNjb3R0IFdvb2Qgd3JvdGU6DQo+ID4gT24gVHVlLCAyMDE0LTA4LTA1IGF0IDE1OjUyICsw
MjAwLCBNYXJ0aWpuIGRlIEdvdXcgd3JvdGU6DQo+ID4+IEFkZCBzdXBwb3J0IGZvciBtYXBwaW5n
IGFuZCB1bm1hcHBpbmcgb2YgaW5ib3VuZCByYXBpZGlvIHdpbmRvd3MuDQo+ID4+DQo+ID4+IFNp
Z25lZC1vZmYtYnk6IE1hcnRpam4gZGUgR291dw0KPiA+PiA8bWFydGlqbi5kZS5nb3V3QHByb2Ry
aXZlLXRlY2hub2xvZ2llcy5jb20+DQo+ID4NCj4gPiBDb3VsZCB5b3UgZWxhYm9yYXRlIGluIHRo
ZSBjaGFuZ2Vsb2cgb24gd2hhdCB0aGlzIGZpeGVzIG9yIG1ha2VzDQo+ID4gcG9zc2libGU/ICBF
LmcuIGRpZCB0aGUgZHJpdmVyIHByZXZpb3VzbHkgbm90IHN1cHBvcnQgaW5ib3VuZA0KPiA+IHRy
YW5zYWN0aW9ucyBhdCBhbGwsIG9yIGRpZCBpdCBhc3N1bWUgdGhlIHdpbmRvdyB3YXMgc2V0IHVw
IGJ5IGENCj4gPiBib290bG9hZGVyPw0KPiANCj4gU29tZXRoaW5nIGxpa2U6DQo+IA0KPiBmc2wt
cmlvOiBhZGQgc3VwcG9ydCBmb3IgbWFwcGluZyBpbmJvdW5kIHdpbmRvd3MNCj4gDQo+ICAgICAg
QWRkIHN1cHBvcnQgZm9yIG1hcHBpbmcgYW5kIHVubWFwcGluZyBvZiBpbmJvdW5kIHJhcGlkaW8g
d2luZG93cy4NCj4gICAgICBUaGlzIGFsbG93cyBmb3IgZHJpdmVycyB0byBvcGVuIHVwIGEgcGFy
dCBvZiBsb2NhbCBtZW1vcnkgb24gdGhlDQo+ICAgICAgcmFwaWRpbyBuZXR3b3JrLiBBbHNvIGFw
cGxpY2F0aW9ucyBjYW4gdXNlIHRoaXMgYW5kIHRyYW5mZXIgYmxvY2tzDQo+ICAgICAgb2YgZGF0
YSBvdmVyIHRoZSBuZXR3b3JrLg0KPiANCj4gPg0KPiA+IExpdSBHYW5nLCBjb3VsZCB5b3UgcmV2
aWV3IHRoaXM/DQo+IA0KPiBJJ2xsIHdhaXQgZm9yIHRoZSByZXZpZXcgYmVmb3JlIEkgcG9zdCBh
IG5ldyB2ZXJzaW9uLg0KPiANCj4gR3IsIE1hcnRpam4NCj4gDQo+IA0KPiAtLQ0KPiBNYXJ0aWpu
IGRlIEdvdXcNCj4gRW5naW5lZXINCj4gUHJvZHJpdmUgVGVjaG5vbG9naWVzIEIuVi4NCj4gTW9i
aWxlOiArMzEgNjMgMTcgNzYgMTYxDQo+IFBob25lOiAgKzMxIDQwIDI2IDc2IDIwMA0K
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help