From: Dave Airlie <airlied@gmail.com> To: Nick Bowler <nbowler@elliptictech.com> Cc: Maarten Maathuis <madman2003@gmail.com>, Martin Peres <martin.peres@labri.fr>, Dmitry Torokhov <dmitry.torokhov@gmail.com>, Linux Kernel Mailing List <linux-kernel@vger.kernel.org>, dri-devel@lists.freedesktop.org, Ben Skeggs <bskeggs@redhat.com>, Linus Torvalds <torvalds@linux-foundation.org> Subject: Re: Linux 3.4-rc4 Date: Fri, 4 May 2012 10:20:56 +0100 [thread overview] Message-ID: <CAPM=9tynyGoV6ppRZe+y5WGUbQRSPc+ih9RL2HZQu951AoZiog@mail.gmail.com> (raw) In-Reply-To: <20120502012029.GA24097@elliptictech.com> [-- Attachment #1: Type: text/plain, Size: 839 bytes --] >> >> FWIW, for me EDID failure on new kernels is 100% reproducible, and there >> are no such checksum errors in the log. It's just missing. >> >> > Just a crazy thought, but didn't we change some timings related to >> > EDID retrieval? To make it faster. >> >> OK, this time bisecting started off relatively smoothly (doing the same >> "backwards" bisect on the branch-o-reverts as last time), but then my >> disk died halfway through... > [...] > > OK, system is back online and I finished the bisection. The commit that > broke it for me is the following, and reverting it on top of 3.3.4 + the > "make VGA work at all" patch fixes this particular issue for me. > Can you test with the attached patch? its a revert mostly of Ben's patch, and he says with the i2c core change stuff is working for him again. Dave. [-- Attachment #2: 0001-drm-nouveau-i2c-resume-use-of-i2c-algo-bit-rather-th.patch --] [-- Type: application/octet-stream, Size: 6615 bytes --] From 281a02ece2245254f415172306a8577dca96eda3 Mon Sep 17 00:00:00 2001 From: Ben Skeggs <bskeggs@redhat.com> Date: Fri, 4 May 2012 14:38:49 +1000 Subject: [PATCH] drm/nouveau/i2c: resume use of i2c-algo-bit, rather than custom stack Previous issues with i2c-algo-bit have now been resolved. Signed-off-by: Ben Skeggs <bskeggs@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/nouveau/nouveau_i2c.c | 199 ++++----------------------------- drivers/gpu/drm/nouveau/nouveau_i2c.h | 1 + 2 files changed, 22 insertions(+), 178 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.c b/drivers/gpu/drm/nouveau/nouveau_i2c.c index e2be95a..77e5646 100644 --- a/drivers/gpu/drm/nouveau/nouveau_i2c.c +++ b/drivers/gpu/drm/nouveau/nouveau_i2c.c @@ -29,10 +29,6 @@ #include "nouveau_i2c.h" #include "nouveau_hw.h" -#define T_TIMEOUT 2200000 -#define T_RISEFALL 1000 -#define T_HOLD 5000 - static void i2c_drive_scl(void *data, int state) { @@ -113,175 +109,6 @@ i2c_sense_sda(void *data) return 0; } -static void -i2c_delay(struct nouveau_i2c_chan *port, u32 nsec) -{ - udelay((nsec + 500) / 1000); -} - -static bool -i2c_raise_scl(struct nouveau_i2c_chan *port) -{ - u32 timeout = T_TIMEOUT / T_RISEFALL; - - i2c_drive_scl(port, 1); - do { - i2c_delay(port, T_RISEFALL); - } while (!i2c_sense_scl(port) && --timeout); - - return timeout != 0; -} - -static int -i2c_start(struct nouveau_i2c_chan *port) -{ - int ret = 0; - - port->state = i2c_sense_scl(port); - port->state |= i2c_sense_sda(port) << 1; - if (port->state != 3) { - i2c_drive_scl(port, 0); - i2c_drive_sda(port, 1); - if (!i2c_raise_scl(port)) - ret = -EBUSY; - } - - i2c_drive_sda(port, 0); - i2c_delay(port, T_HOLD); - i2c_drive_scl(port, 0); - i2c_delay(port, T_HOLD); - return ret; -} - -static void -i2c_stop(struct nouveau_i2c_chan *port) -{ - i2c_drive_scl(port, 0); - i2c_drive_sda(port, 0); - i2c_delay(port, T_RISEFALL); - - i2c_drive_scl(port, 1); - i2c_delay(port, T_HOLD); - i2c_drive_sda(port, 1); - i2c_delay(port, T_HOLD); -} - -static int -i2c_bitw(struct nouveau_i2c_chan *port, int sda) -{ - i2c_drive_sda(port, sda); - i2c_delay(port, T_RISEFALL); - - if (!i2c_raise_scl(port)) - return -ETIMEDOUT; - i2c_delay(port, T_HOLD); - - i2c_drive_scl(port, 0); - i2c_delay(port, T_HOLD); - return 0; -} - -static int -i2c_bitr(struct nouveau_i2c_chan *port) -{ - int sda; - - i2c_drive_sda(port, 1); - i2c_delay(port, T_RISEFALL); - - if (!i2c_raise_scl(port)) - return -ETIMEDOUT; - i2c_delay(port, T_HOLD); - - sda = i2c_sense_sda(port); - - i2c_drive_scl(port, 0); - i2c_delay(port, T_HOLD); - return sda; -} - -static int -i2c_get_byte(struct nouveau_i2c_chan *port, u8 *byte, bool last) -{ - int i, bit; - - *byte = 0; - for (i = 7; i >= 0; i--) { - bit = i2c_bitr(port); - if (bit < 0) - return bit; - *byte |= bit << i; - } - - return i2c_bitw(port, last ? 1 : 0); -} - -static int -i2c_put_byte(struct nouveau_i2c_chan *port, u8 byte) -{ - int i, ret; - for (i = 7; i >= 0; i--) { - ret = i2c_bitw(port, !!(byte & (1 << i))); - if (ret < 0) - return ret; - } - - ret = i2c_bitr(port); - if (ret == 1) /* nack */ - ret = -EIO; - return ret; -} - -static int -i2c_addr(struct nouveau_i2c_chan *port, struct i2c_msg *msg) -{ - u32 addr = msg->addr << 1; - if (msg->flags & I2C_M_RD) - addr |= 1; - return i2c_put_byte(port, addr); -} - -static int -i2c_bit_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) -{ - struct nouveau_i2c_chan *port = (struct nouveau_i2c_chan *)adap; - struct i2c_msg *msg = msgs; - int ret = 0, mcnt = num; - - while (!ret && mcnt--) { - u8 remaining = msg->len; - u8 *ptr = msg->buf; - - ret = i2c_start(port); - if (ret == 0) - ret = i2c_addr(port, msg); - - if (msg->flags & I2C_M_RD) { - while (!ret && remaining--) - ret = i2c_get_byte(port, ptr++, !remaining); - } else { - while (!ret && remaining--) - ret = i2c_put_byte(port, *ptr++); - } - - msg++; - } - - i2c_stop(port); - return (ret < 0) ? ret : num; -} - -static u32 -i2c_bit_func(struct i2c_adapter *adap) -{ - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; -} - -const struct i2c_algorithm nouveau_i2c_bit_algo = { - .master_xfer = i2c_bit_xfer, - .functionality = i2c_bit_func -}; - static const uint32_t nv50_i2c_port[] = { 0x00e138, 0x00e150, 0x00e168, 0x00e180, 0x00e254, 0x00e274, 0x00e764, 0x00e780, @@ -384,12 +211,10 @@ nouveau_i2c_init(struct drm_device *dev) case 0: /* NV04:NV50 */ port->drive = entry[0]; port->sense = entry[1]; - port->adapter.algo = &nouveau_i2c_bit_algo; break; case 4: /* NV4E */ port->drive = 0x600800 + entry[1]; port->sense = port->drive; - port->adapter.algo = &nouveau_i2c_bit_algo; break; case 5: /* NV50- */ port->drive = entry[0] & 0x0f; @@ -402,7 +227,6 @@ nouveau_i2c_init(struct drm_device *dev) port->drive = 0x00d014 + (port->drive * 0x20); port->sense = port->drive; } - port->adapter.algo = &nouveau_i2c_bit_algo; break; case 6: /* NV50- DP AUX */ port->drive = entry[0]; @@ -413,7 +237,7 @@ nouveau_i2c_init(struct drm_device *dev) break; } - if (!port->adapter.algo) { + if (!port->adapter.algo && !port->drive) { NV_ERROR(dev, "I2C%d: type %d index %x/%x unknown\n", i, port->type, port->drive, port->sense); kfree(port); @@ -429,7 +253,26 @@ nouveau_i2c_init(struct drm_device *dev) port->dcb = ROM32(entry[0]); i2c_set_adapdata(&port->adapter, i2c); - ret = i2c_add_adapter(&port->adapter); + if (port->adapter.algo != &nouveau_dp_i2c_algo) { + port->adapter.algo_data = &port->bit; + port->bit.udelay = 10; + port->bit.timeout = usecs_to_jiffies(2200); + port->bit.data = port; + port->bit.setsda = i2c_drive_sda; + port->bit.setscl = i2c_drive_scl; + port->bit.getsda = i2c_sense_sda; + port->bit.getscl = i2c_sense_scl; + + i2c_drive_scl(port, 0); + i2c_drive_sda(port, 1); + i2c_drive_scl(port, 1); + + ret = i2c_bit_add_bus(&port->adapter); + } else { + port->adapter.algo = &nouveau_dp_i2c_algo; + ret = i2c_add_adapter(&port->adapter); + } + if (ret) { NV_ERROR(dev, "I2C%d: failed register: %d\n", i, ret); kfree(port); diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.h b/drivers/gpu/drm/nouveau/nouveau_i2c.h index 4d2e4e9..1d08389 100644 --- a/drivers/gpu/drm/nouveau/nouveau_i2c.h +++ b/drivers/gpu/drm/nouveau/nouveau_i2c.h @@ -34,6 +34,7 @@ struct nouveau_i2c_chan { struct i2c_adapter adapter; struct drm_device *dev; + struct i2c_algo_bit_data bit; struct list_head head; u8 index; u8 type; -- 1.7.7.6
WARNING: multiple messages have this Message-ID (diff)
From: Dave Airlie <airlied@gmail.com> To: Nick Bowler <nbowler@elliptictech.com> Cc: Martin Peres <martin.peres@labri.fr>, Dmitry Torokhov <dmitry.torokhov@gmail.com>, Linux Kernel Mailing List <linux-kernel@vger.kernel.org>, dri-devel@lists.freedesktop.org, Ben Skeggs <bskeggs@redhat.com>, Linus Torvalds <torvalds@linux-foundation.org> Subject: Re: Linux 3.4-rc4 Date: Fri, 4 May 2012 10:20:56 +0100 [thread overview] Message-ID: <CAPM=9tynyGoV6ppRZe+y5WGUbQRSPc+ih9RL2HZQu951AoZiog@mail.gmail.com> (raw) In-Reply-To: <20120502012029.GA24097@elliptictech.com> [-- Attachment #1: Type: text/plain, Size: 839 bytes --] >> >> FWIW, for me EDID failure on new kernels is 100% reproducible, and there >> are no such checksum errors in the log. It's just missing. >> >> > Just a crazy thought, but didn't we change some timings related to >> > EDID retrieval? To make it faster. >> >> OK, this time bisecting started off relatively smoothly (doing the same >> "backwards" bisect on the branch-o-reverts as last time), but then my >> disk died halfway through... > [...] > > OK, system is back online and I finished the bisection. The commit that > broke it for me is the following, and reverting it on top of 3.3.4 + the > "make VGA work at all" patch fixes this particular issue for me. > Can you test with the attached patch? its a revert mostly of Ben's patch, and he says with the i2c core change stuff is working for him again. Dave. [-- Attachment #2: 0001-drm-nouveau-i2c-resume-use-of-i2c-algo-bit-rather-th.patch --] [-- Type: application/octet-stream, Size: 6615 bytes --] From 281a02ece2245254f415172306a8577dca96eda3 Mon Sep 17 00:00:00 2001 From: Ben Skeggs <bskeggs@redhat.com> Date: Fri, 4 May 2012 14:38:49 +1000 Subject: [PATCH] drm/nouveau/i2c: resume use of i2c-algo-bit, rather than custom stack Previous issues with i2c-algo-bit have now been resolved. Signed-off-by: Ben Skeggs <bskeggs@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/nouveau/nouveau_i2c.c | 199 ++++----------------------------- drivers/gpu/drm/nouveau/nouveau_i2c.h | 1 + 2 files changed, 22 insertions(+), 178 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.c b/drivers/gpu/drm/nouveau/nouveau_i2c.c index e2be95a..77e5646 100644 --- a/drivers/gpu/drm/nouveau/nouveau_i2c.c +++ b/drivers/gpu/drm/nouveau/nouveau_i2c.c @@ -29,10 +29,6 @@ #include "nouveau_i2c.h" #include "nouveau_hw.h" -#define T_TIMEOUT 2200000 -#define T_RISEFALL 1000 -#define T_HOLD 5000 - static void i2c_drive_scl(void *data, int state) { @@ -113,175 +109,6 @@ i2c_sense_sda(void *data) return 0; } -static void -i2c_delay(struct nouveau_i2c_chan *port, u32 nsec) -{ - udelay((nsec + 500) / 1000); -} - -static bool -i2c_raise_scl(struct nouveau_i2c_chan *port) -{ - u32 timeout = T_TIMEOUT / T_RISEFALL; - - i2c_drive_scl(port, 1); - do { - i2c_delay(port, T_RISEFALL); - } while (!i2c_sense_scl(port) && --timeout); - - return timeout != 0; -} - -static int -i2c_start(struct nouveau_i2c_chan *port) -{ - int ret = 0; - - port->state = i2c_sense_scl(port); - port->state |= i2c_sense_sda(port) << 1; - if (port->state != 3) { - i2c_drive_scl(port, 0); - i2c_drive_sda(port, 1); - if (!i2c_raise_scl(port)) - ret = -EBUSY; - } - - i2c_drive_sda(port, 0); - i2c_delay(port, T_HOLD); - i2c_drive_scl(port, 0); - i2c_delay(port, T_HOLD); - return ret; -} - -static void -i2c_stop(struct nouveau_i2c_chan *port) -{ - i2c_drive_scl(port, 0); - i2c_drive_sda(port, 0); - i2c_delay(port, T_RISEFALL); - - i2c_drive_scl(port, 1); - i2c_delay(port, T_HOLD); - i2c_drive_sda(port, 1); - i2c_delay(port, T_HOLD); -} - -static int -i2c_bitw(struct nouveau_i2c_chan *port, int sda) -{ - i2c_drive_sda(port, sda); - i2c_delay(port, T_RISEFALL); - - if (!i2c_raise_scl(port)) - return -ETIMEDOUT; - i2c_delay(port, T_HOLD); - - i2c_drive_scl(port, 0); - i2c_delay(port, T_HOLD); - return 0; -} - -static int -i2c_bitr(struct nouveau_i2c_chan *port) -{ - int sda; - - i2c_drive_sda(port, 1); - i2c_delay(port, T_RISEFALL); - - if (!i2c_raise_scl(port)) - return -ETIMEDOUT; - i2c_delay(port, T_HOLD); - - sda = i2c_sense_sda(port); - - i2c_drive_scl(port, 0); - i2c_delay(port, T_HOLD); - return sda; -} - -static int -i2c_get_byte(struct nouveau_i2c_chan *port, u8 *byte, bool last) -{ - int i, bit; - - *byte = 0; - for (i = 7; i >= 0; i--) { - bit = i2c_bitr(port); - if (bit < 0) - return bit; - *byte |= bit << i; - } - - return i2c_bitw(port, last ? 1 : 0); -} - -static int -i2c_put_byte(struct nouveau_i2c_chan *port, u8 byte) -{ - int i, ret; - for (i = 7; i >= 0; i--) { - ret = i2c_bitw(port, !!(byte & (1 << i))); - if (ret < 0) - return ret; - } - - ret = i2c_bitr(port); - if (ret == 1) /* nack */ - ret = -EIO; - return ret; -} - -static int -i2c_addr(struct nouveau_i2c_chan *port, struct i2c_msg *msg) -{ - u32 addr = msg->addr << 1; - if (msg->flags & I2C_M_RD) - addr |= 1; - return i2c_put_byte(port, addr); -} - -static int -i2c_bit_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) -{ - struct nouveau_i2c_chan *port = (struct nouveau_i2c_chan *)adap; - struct i2c_msg *msg = msgs; - int ret = 0, mcnt = num; - - while (!ret && mcnt--) { - u8 remaining = msg->len; - u8 *ptr = msg->buf; - - ret = i2c_start(port); - if (ret == 0) - ret = i2c_addr(port, msg); - - if (msg->flags & I2C_M_RD) { - while (!ret && remaining--) - ret = i2c_get_byte(port, ptr++, !remaining); - } else { - while (!ret && remaining--) - ret = i2c_put_byte(port, *ptr++); - } - - msg++; - } - - i2c_stop(port); - return (ret < 0) ? ret : num; -} - -static u32 -i2c_bit_func(struct i2c_adapter *adap) -{ - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; -} - -const struct i2c_algorithm nouveau_i2c_bit_algo = { - .master_xfer = i2c_bit_xfer, - .functionality = i2c_bit_func -}; - static const uint32_t nv50_i2c_port[] = { 0x00e138, 0x00e150, 0x00e168, 0x00e180, 0x00e254, 0x00e274, 0x00e764, 0x00e780, @@ -384,12 +211,10 @@ nouveau_i2c_init(struct drm_device *dev) case 0: /* NV04:NV50 */ port->drive = entry[0]; port->sense = entry[1]; - port->adapter.algo = &nouveau_i2c_bit_algo; break; case 4: /* NV4E */ port->drive = 0x600800 + entry[1]; port->sense = port->drive; - port->adapter.algo = &nouveau_i2c_bit_algo; break; case 5: /* NV50- */ port->drive = entry[0] & 0x0f; @@ -402,7 +227,6 @@ nouveau_i2c_init(struct drm_device *dev) port->drive = 0x00d014 + (port->drive * 0x20); port->sense = port->drive; } - port->adapter.algo = &nouveau_i2c_bit_algo; break; case 6: /* NV50- DP AUX */ port->drive = entry[0]; @@ -413,7 +237,7 @@ nouveau_i2c_init(struct drm_device *dev) break; } - if (!port->adapter.algo) { + if (!port->adapter.algo && !port->drive) { NV_ERROR(dev, "I2C%d: type %d index %x/%x unknown\n", i, port->type, port->drive, port->sense); kfree(port); @@ -429,7 +253,26 @@ nouveau_i2c_init(struct drm_device *dev) port->dcb = ROM32(entry[0]); i2c_set_adapdata(&port->adapter, i2c); - ret = i2c_add_adapter(&port->adapter); + if (port->adapter.algo != &nouveau_dp_i2c_algo) { + port->adapter.algo_data = &port->bit; + port->bit.udelay = 10; + port->bit.timeout = usecs_to_jiffies(2200); + port->bit.data = port; + port->bit.setsda = i2c_drive_sda; + port->bit.setscl = i2c_drive_scl; + port->bit.getsda = i2c_sense_sda; + port->bit.getscl = i2c_sense_scl; + + i2c_drive_scl(port, 0); + i2c_drive_sda(port, 1); + i2c_drive_scl(port, 1); + + ret = i2c_bit_add_bus(&port->adapter); + } else { + port->adapter.algo = &nouveau_dp_i2c_algo; + ret = i2c_add_adapter(&port->adapter); + } + if (ret) { NV_ERROR(dev, "I2C%d: failed register: %d\n", i, ret); kfree(port); diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.h b/drivers/gpu/drm/nouveau/nouveau_i2c.h index 4d2e4e9..1d08389 100644 --- a/drivers/gpu/drm/nouveau/nouveau_i2c.h +++ b/drivers/gpu/drm/nouveau/nouveau_i2c.h @@ -34,6 +34,7 @@ struct nouveau_i2c_chan { struct i2c_adapter adapter; struct drm_device *dev; + struct i2c_algo_bit_data bit; struct list_head head; u8 index; u8 type; -- 1.7.7.6 [-- Attachment #3: Type: text/plain, Size: 159 bytes --] _______________________________________________ dri-devel mailing list dri-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/dri-devel
next prev parent reply other threads:[~2012-05-04 9:20 UTC|newest] Thread overview: 44+ messages / expand[flat|nested] mbox.gz Atom feed top 2012-04-21 22:43 Linux 3.4-rc4 Linus Torvalds 2012-04-22 4:07 ` Nick Bowler 2012-04-22 4:51 ` Linus Torvalds 2012-04-22 4:51 ` Linus Torvalds 2012-04-22 7:26 ` Dave Airlie 2012-04-22 7:26 ` Dave Airlie 2012-04-22 16:42 ` Nick Bowler 2012-04-23 3:16 ` Ben Skeggs 2012-04-22 16:40 ` Nick Bowler 2012-04-22 18:20 ` Geert Uytterhoeven 2012-04-23 0:05 ` Nick Bowler 2012-04-23 2:45 ` Konrad Rzeszutek Wilk 2012-04-23 2:45 ` Konrad Rzeszutek Wilk 2012-04-24 1:03 ` Nick Bowler 2012-04-24 15:11 ` Konrad Rzeszutek Wilk 2012-04-25 1:35 ` Nick Bowler 2012-04-25 2:56 ` Ben Skeggs 2012-04-25 2:56 ` Ben Skeggs 2012-04-27 5:20 ` Ben Skeggs 2012-04-28 0:39 ` Nick Bowler 2012-04-28 6:19 ` Alex Deucher 2012-04-28 15:33 ` Nick Bowler 2012-04-28 15:33 ` Nick Bowler 2012-04-29 22:37 ` Dmitry Torokhov 2012-04-30 9:07 ` Maarten Maathuis 2012-04-30 11:01 ` Luca Tettamanti 2012-04-30 11:01 ` Luca Tettamanti 2012-05-02 7:54 ` Jean Delvare 2012-05-02 11:31 ` Ben Skeggs 2012-05-04 5:08 ` Ben Skeggs 2012-05-04 5:08 ` Ben Skeggs 2012-05-04 14:12 ` Jean Delvare 2012-05-01 13:23 ` Nick Bowler 2012-05-01 15:09 ` Alan Cox 2012-05-01 15:09 ` Alan Cox 2012-05-01 15:31 ` Nick Bowler 2012-05-01 15:31 ` Nick Bowler 2012-05-01 15:45 ` Alan Cox 2012-05-02 1:20 ` Nick Bowler 2012-05-02 1:20 ` Nick Bowler 2012-05-04 9:20 ` Dave Airlie [this message] 2012-05-04 9:20 ` Dave Airlie 2012-05-05 15:39 ` Nick Bowler 2012-04-22 8:38 ` Bjarke Istrup Pedersen
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to='CAPM=9tynyGoV6ppRZe+y5WGUbQRSPc+ih9RL2HZQu951AoZiog@mail.gmail.com' \ --to=airlied@gmail.com \ --cc=bskeggs@redhat.com \ --cc=dmitry.torokhov@gmail.com \ --cc=dri-devel@lists.freedesktop.org \ --cc=linux-kernel@vger.kernel.org \ --cc=madman2003@gmail.com \ --cc=martin.peres@labri.fr \ --cc=nbowler@elliptictech.com \ --cc=torvalds@linux-foundation.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.