qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: "Philippe Mathieu-Daudé" <f4bug@amsat.org>
To: Alistair Francis <alistair.francis@xilinx.com>,
	Peter Maydell <peter.maydell@linaro.org>,
	Igor Mitsyanko <i.mitsyanko@gmail.com>,
	Andrew Baumann <Andrew.Baumann@microsoft.com>,
	Olbrich <m.olbrich@pengutronix.de>,
	Andrzej Zaborowski <balrogg@gmail.com>
Cc: "Philippe Mathieu-Daudé" <f4bug@amsat.org>,
	qemu-devel@nongnu.org,
	"Edgar E . Iglesias" <edgar.iglesias@xilinx.com>,
	"Prasad J Pandit" <pjp@fedoraproject.org>,
	"Peter Crosthwaite" <crosthwaite.peter@gmail.com>,
	"Paul Brook" <paul@codesourcery.com>,
	"Marc-André Lureau" <marcandre.lureau@redhat.com>
Subject: [Qemu-devel] [PATCH v2 25/25] sdcard: introduce Spec v4.51 & v5.1 MMC commands
Date: Wed,  3 Jan 2018 18:24:36 -0300	[thread overview]
Message-ID: <20180103212436.15762-26-f4bug@amsat.org> (raw)
In-Reply-To: <20180103212436.15762-1-f4bug@amsat.org>

Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
---
 include/hw/sd/sd.h |   1 +
 hw/sd/sd.c         | 181 ++++++++++++++++++++++++++++++++---------------------
 2 files changed, 112 insertions(+), 70 deletions(-)

diff --git a/include/hw/sd/sd.h b/include/hw/sd/sd.h
index 6874696ff7..1f1ec2a042 100644
--- a/include/hw/sd/sd.h
+++ b/include/hw/sd/sd.h
@@ -58,6 +58,7 @@
 typedef enum {
     PROTO_SD =  0,
     PROTO_SPI = 1 << 1,
+    PROTO_MMC = 1 << 2,
 } sd_bus_protocol_t;
 
 typedef enum {
diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index 6fbc640d2e..c4701f9c7c 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -63,6 +63,13 @@ typedef enum {
     SD_PHY_SPEC_VER_3_01 = 301, /* not yet supported */
 } sd_phy_spec_ver_t;
 
+typedef enum {
+    MMC_SPEC_VER_2_2    = 202,  /* not well supported */
+    /* e.MMC */
+    MMC_SPEC_VER_4_51   = 451,
+    MMC_SPEC_VER_5_1    = 501,  /* not supported */
+} mmc_phy_spec_ver_t;
+
 typedef enum {
     sd_capacity_unknown,
     sd_capacity_sdsc,           /* not well supported */
@@ -157,6 +164,8 @@ static const char *sd_protocol_name(sd_bus_protocol_t protocol)
         return "SD";
     case PROTO_SPI:
         return "SPI";
+    case PROTO_MMC:
+        return "MMC";
     default:
         g_assert_not_reached();
     }
@@ -299,78 +308,90 @@ typedef struct {
     struct {
         uint16_t version;
         uint32_t ccc_mask;
-    } sd, spi;
+    } sd, spi, mmc;
 } sd_cmd_supported_t;
 
 static const sd_cmd_supported_t cmd_supported[SDCARD_CMD_MAX] = {
-     /*           SD                  SPI          */
-     [0] = {{200, BIT(0)},      {200, BIT(0)},      },
-     [1] = {{301, BIT(0)},      {200, BIT(0)},      },
-     [2] = {{200, BIT(0)},      {},                 },
-     [3] = {{200, BIT(0)},      {},                 },
-     [4] = {{200, BIT(0)},      {},                 },
-     [5] = {{200, BIT(9)},      {200, BIT(9)},      },
-     [6] = {{200, BIT(10)},     {200, BIT(10)},     },
-     [7] = {{200, BIT(0)},      {},                 },
-     [8] = {{200, BIT(0)},      {200, BIT(0)},      },
-     [9] = {{200, BIT(0)},      {200, BIT(0)},      },
-    [10] = {{200, BIT(0)},      {200, BIT(0)},      },
-    [12] = {{200, BIT(0)},      {200, BIT(0)},      },
-    [13] = {{200, BIT(0)},      {200, BIT(0)},      },
-    [14] = {{200, BIT(0)},      {},                 },
-    [15] = {{200, BIT(0)},      {},                 },
-    [16] = {{200, BIT_2_4_7},   {200, BIT_2_4_7},   },
-    [17] = {{200, BIT(2)},      {200, BIT(2)},      },
-    [18] = {{200, BIT(2)},      {200, BIT(2)},      },
-    [23] = {{301, BIT_2_4},     {},                 },
-    [24] = {{200, BIT(4)},      {200, BIT(4)},      },
-    [25] = {{200, BIT(4)},      {200, BIT(4)},      },
-    [26] = {{200, BIT_MANUF},   {/*?*/},            },
-    [27] = {{200, BIT(4)},      {200, BIT(4)},      },
-    [28] = {{200, BIT(6)},      {200, BIT(6)},      },
-    [29] = {{200, BIT(6)},      {200, BIT(6)},      },
-    [30] = {{200, BIT(6)},      {200, BIT(6)},      },
-    [32] = {{200, BIT(5)},      {200, BIT(5)},      },
-    [33] = {{200, BIT(5)},      {200, BIT(5)},      },
-    [34] = {{200, BIT(10)},     {200, BIT(10)},     },
-    [35] = {{200, BIT(10)},     {200, BIT(10)},     },
-    [36] = {{200, BIT(10)},     {200, BIT(10)},     },
-    [37] = {{200, BIT(10)},     {200, BIT(10)},     },
-    [38] = {{200, BIT(5)},      {200, BIT(5)},      },
-    [42] = {{200, BIT(7)},      {200, BIT(7)},      },
-    [50] = {{200, BIT(10)},     {200, BIT(10)},     },
-    [52] = {{200, BIT(9)},      {200, BIT(9)},      },
-    [53] = {{200, BIT(9)},      {200, BIT(9)},      },
-    [54] = {{/* 2.00 SDIO */},  {/* 2.00 SDIO */},  },
-    [55] = {{200, BIT(8)},      {200, BIT(8)},      },
-    [56] = {{200, BIT(8)},      {200, BIT(8)},      },
-    [57] = {{200, BIT(10)},     {200, BIT(10)},     },
-    [58] = {{301, BIT(0)},      {200, BIT(0)},      },
-    [59] = {{301, BIT(0)},      {200, BIT(0)},      },
-    [60] = {{200, BIT_MANUF},   {/*?*/},            },
-    [61] = {{200, BIT_MANUF},   {/*?*/},            },
-    [62] = {{200, BIT_MANUF},   {/*?*/},            },
-    [63] = {{200, BIT_MANUF},   {/*?*/},            },
+     /*           SD                  SPI                 eMMC         */
+     [0] = {{200, BIT(0)},      {200, BIT(0)},      {451, BIT(0)}       },
+     [1] = {{301, BIT(0)},      {200, BIT(0)},      {451, BIT(0)}       },
+     [2] = {{200, BIT(0)},      {},                 {451, BIT(0)}       },
+     [3] = {{200, BIT(0)},      {},                 {451, BIT(0)}       },
+     [4] = {{200, BIT(0)},      {},                 {451, BIT(0)}       },
+     [5] = {{200, BIT(9)},      {200, BIT(9)},      {451, BIT(0)}       },
+     [6] = {{200, BIT(10)},     {200, BIT(10)},     {451, BIT(0)}       },
+     [7] = {{200, BIT(0)},      {},                 {451, BIT(0)}       },
+     [8] = {{200, BIT(0)},      {200, BIT(0)},      {451, BIT(0)}       },
+     [9] = {{200, BIT(0)},      {200, BIT(0)},      {451, BIT(0)}       },
+    [10] = {{200, BIT(0)},      {200, BIT(0)},      {451, BIT(0)}       },
+    [12] = {{200, BIT(0)},      {200, BIT(0)},      {451, BIT(0)}       },
+    [13] = {{200, BIT(0)},      {200, BIT(0)},      {451, BIT(0)}       },
+    [14] = {{200, BIT(0)},      {},                 {451, BIT(0)}       },
+    [15] = {{200, BIT(0)},      {},                 {451, BIT(0)}       },
+    [16] = {{200, BIT_2_4_7},   {200, BIT_2_4_7},   {451, BIT_2_4_7}    },
+    [17] = {{200, BIT(2)},      {200, BIT(2)},      {451, BIT(2)}       },
+    [18] = {{200, BIT(2)},      {200, BIT(2)},      {451, BIT(2)}       },
+    [19] = {{},                 {},                 {451, BIT(0)}       },
+    [21] = {{},                 {},                 {/* HS200 */}       },
+    [23] = {{301, BIT_2_4},     {},                 {/*BIT_2_4 ?*/}     },
+    [24] = {{200, BIT(4)},      {200, BIT(4)},      {451, BIT(4)}       },
+    [25] = {{200, BIT(4)},      {200, BIT(4)},      {451, BIT(4)}       },
+    [26] = {{200, BIT_MANUF},   {/*?*/},            {/*?*/}             },
+    [27] = {{200, BIT(4)},      {200, BIT(4)},      {451, BIT(4)}       },
+    [28] = {{200, BIT(6)},      {200, BIT(6)},      {451, BIT(6)}       },
+    [29] = {{200, BIT(6)},      {200, BIT(6)},      {451, BIT(6)}       },
+    [30] = {{200, BIT(6)},      {200, BIT(6)},      {451, BIT(6)}       },
+    [31] = {{},                 {},                 {451, BIT(6)}       },
+    [32] = {{200, BIT(5)},      {200, BIT(5)},      {}                  },
+    [33] = {{200, BIT(5)},      {200, BIT(5)},      {}                  },
+    [34] = {{200, BIT(10)},     {200, BIT(10)},     {}                  },
+    [35] = {{200, BIT(10)},     {200, BIT(10)},     {451, BIT(5)}       },
+    [36] = {{200, BIT(10)},     {200, BIT(10)},     {451, BIT(5)}       },
+    [37] = {{200, BIT(10)},     {200, BIT(10)},     {},                 },
+    [38] = {{200, BIT(5)},      {200, BIT(5)},      {451, BIT(5)}       },
+    [39] = {{},                 {},                 {451, BIT(9)}       },
+    [40] = {{},                 {},                 {451, BIT(9)}       },
+    [41] = {{},                 {},                 {/*451, BIT(7)*/}   },
+    [42] = {{200, BIT(7)},      {200, BIT(7)},      {451, BIT(4)}       },
+    [44] = {{},                 {},                 {501, BIT(10)}      },
+    [45] = {{},                 {},                 {501, BIT(10)}      },
+    [46] = {{},                 {},                 {501, BIT(10)}      },
+    [47] = {{},                 {},                 {501, BIT(10)}      },
+    [48] = {{},                 {},                 {501, BIT(10)}      },
+    [49] = {{},                 {},                 {451, BIT(4)}       },
+    [50] = {{200, BIT(10)},     {200, BIT(10)},     {}                  },
+    [52] = {{200, BIT(9)},      {200, BIT(9)},      {}                  },
+    [53] = {{200, BIT(9)},      {200, BIT(9)},      {451, BIT(10)}      },
+    [54] = {{/* 2.00 SDIO */},  {/* 2.00 SDIO */},  {451, BIT(10)}      },
+    [55] = {{200, BIT(8)},      {200, BIT(8)},      {451, BIT(8)}       },
+    [56] = {{200, BIT(8)},      {200, BIT(8)},      {451, BIT(8)}       },
+    [57] = {{200, BIT(10)},     {200, BIT(10)},     {}                  },
+    [58] = {{301, BIT(0)},      {200, BIT(0)},      {}                  },
+    [59] = {{301, BIT(0)},      {200, BIT(0)},      {}                  },
+    [60] = {{200, BIT_MANUF},   {/*?*/},            {/*?*/}             },
+    [61] = {{200, BIT_MANUF},   {/*?*/},            {/*?*/}             },
+    [62] = {{200, BIT_MANUF},   {/*?*/},            {/*?*/}             },
+    [63] = {{200, BIT_MANUF},   {/*?*/},            {/*?*/}             },
 }, acmd_supported[SDCARD_CMD_MAX] = {
-     /*           SD                  SPI          */
-     [6] = {{200, BIT(8)},      {},                 },
-    [13] = {{200, BIT(8)},      {200, BIT(8)},      },
-    [18] = {{200, BIT_SECU},    {200, BIT_SECU},    },
-    [22] = {{200, BIT(8)},      {200, BIT(8)},      },
-    [23] = {{200, BIT(8)},      {200, BIT(8)},      },
-    [25] = {{200, BIT_SECU},    {200, BIT_SECU},    },
-    [26] = {{200, BIT_SECU},    {200, BIT_SECU},    },
-    [38] = {{200, BIT_SECU},    {200, BIT_SECU},    },
-    [41] = {{200, BIT(8)},      {200, BIT(8)},      },
-    [42] = {{200, BIT(8)},      {200, BIT(8)},      },
-    [43] = {{200, BIT_SECU},    {200, BIT_SECU},    },
-    [44] = {{200, BIT_SECU},    {200, BIT_SECU},    },
-    [45] = {{200, BIT_SECU},    {200, BIT_SECU},    },
-    [46] = {{200, BIT_SECU},    {200, BIT_SECU},    },
-    [47] = {{200, BIT_SECU},    {200, BIT_SECU},    },
-    [48] = {{200, BIT_SECU},    {200, BIT_SECU},    },
-    [49] = {{200, BIT_SECU},    {200, BIT_SECU},    },
-    [51] = {{200, BIT(8)},      {200, BIT(8)},      },
+     /*           SD                  SPI                 eMMC         */
+     [6] = {{200, BIT(8)},      {},                 {451, BIT(0)}       },
+    [13] = {{200, BIT(8)},      {200, BIT(8)},      {451, BIT(0)}       },
+    [18] = {{200, BIT_SECU},    {200, BIT_SECU},    {451, BIT(0)}       },
+    [22] = {{200, BIT(8)},      {200, BIT(8)},      {451, BIT(4)}       },
+    [23] = {{200, BIT(8)},      {200, BIT(8)},      {451, BIT(4)}       },
+    [25] = {{200, BIT_SECU},    {200, BIT_SECU},    {451, BIT(0)}       },
+    [26] = {{200, BIT_SECU},    {200, BIT_SECU},    {451, BIT(0)}       },
+    [38] = {{200, BIT_SECU},    {200, BIT_SECU},    {451, BIT(0)}       },
+    [41] = {{200, BIT(8)},      {200, BIT(8)},      {451, BIT(8)}       },
+    [42] = {{200, BIT(8)},      {200, BIT(8)},      {451, BIT(0)}       },
+    [43] = {{200, BIT_SECU},    {200, BIT_SECU},    {451, BIT(0)}       },
+    [44] = {{200, BIT_SECU},    {200, BIT_SECU},    {451, BIT(0)}       },
+    [45] = {{200, BIT_SECU},    {200, BIT_SECU},    {451, BIT(0)}       },
+    [46] = {{200, BIT_SECU},    {200, BIT_SECU},    {451, BIT(0)}       },
+    [47] = {{200, BIT_SECU},    {200, BIT_SECU},    {451, BIT(0)}       },
+    [48] = {{200, BIT_SECU},    {200, BIT_SECU},    {451, BIT(0)}       },
+    [49] = {{200, BIT_SECU},    {200, BIT_SECU},    {451, BIT(0)}       },
+    [51] = {{200, BIT(8)},      {200, BIT(8)},      {451, BIT(8)}       },
 };
 
 static const char *spec_version_name(uint16_t spec_version)
@@ -378,8 +399,14 @@ static const char *spec_version_name(uint16_t spec_version)
     switch (spec_version) {
     case SD_PHY_SPEC_VER_2_00:
         return "v2.00";
+    case MMC_SPEC_VER_2_2:
+        return "v2.2";
     case SD_PHY_SPEC_VER_3_01:
         return "v3.01";
+    case MMC_SPEC_VER_4_51:
+        return "v4.51";
+    case MMC_SPEC_VER_5_1:
+        return "v5.1";
     default:
         g_assert_not_reached();
     }
@@ -397,6 +424,9 @@ static bool cmd_version_supported(SDState *sd, uint8_t cmd, bool is_acmd)
     case PROTO_SPI:
         cmd_version = cmdset[cmd].spi.version;
         break;
+    case PROTO_MMC:
+        cmd_version = cmdset[cmd].mmc.version;
+        break;
     default:
         g_assert_not_reached();
     }
@@ -424,6 +454,9 @@ static bool cmd_class_supported(SDState *sd, uint8_t cmd, uint8_t class,
         /* class 1, 3 and 9 are not supported in SPI mode */
         cmd_ccc_mask = cmdset[cmd].spi.ccc_mask;
         break;
+    case PROTO_MMC:
+        cmd_ccc_mask = cmdset[cmd].mmc.ccc_mask;
+        break;
     default:
         g_assert_not_reached();
     }
@@ -602,7 +635,7 @@ static void sd_reset_csd(SDState *sd, uint64_t size)
 
 static void sd_reset_rca(SDState *sd)
 {
-    sd->rca = 0;
+    sd->rca = sd->bus_protocol == PROTO_MMC;
 }
 
 static void sd_set_rca(SDState *sd)
@@ -907,6 +940,9 @@ static SDState *sdcard_init(BlockBackend *blk, sd_bus_protocol_t bus_protocol)
     case PROTO_SPI:
         qdev_prop_set_bit(dev, "spi", true);
         break;
+    case PROTO_MMC:
+        qdev_prop_set_bit(dev, "mmc", true);
+        break;
     default:
         break;
     }
@@ -2163,7 +2199,11 @@ static void sd_realize(DeviceState *dev, Error **errp)
     int ret;
 
     sd->proto_name = sd_protocol_name(sd->bus_protocol);
-    sd->spec_version = SD_PHY_SPEC_VER_2_00;
+    if (sd->bus_protocol == PROTO_MMC) {
+        sd->spec_version = MMC_SPEC_VER_4_51;
+    } else {
+        sd->spec_version = SD_PHY_SPEC_VER_2_00;
+    }
 
     if (sd->blk && blk_is_read_only(sd->blk)) {
         error_setg(errp, "Cannot use read-only drive as SD card");
@@ -2209,6 +2249,7 @@ static Property sd_properties[] = {
      * board to ensure that ssi transfers only occur when the chip select
      * is asserted.  */
     DEFINE_PROP_BIT("spi", SDState, bus_protocol, 1, false),
+    DEFINE_PROP_BIT("mmc", SDState, bus_protocol, 2, false),
     DEFINE_PROP_END_OF_LIST()
 };
 
-- 
2.15.1

      parent reply	other threads:[~2018-01-03 21:26 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-01-03 21:24 [Qemu-devel] [PATCH v2 00/25] SDCard: housekeeping, improve SPI, introduce new Specs Philippe Mathieu-Daudé
2018-01-03 21:24 ` [Qemu-devel] [PATCH v2 01/25] sdcard: reorder SDState struct members Philippe Mathieu-Daudé
2018-01-08 21:46   ` Alistair Francis
2018-01-03 21:24 ` [Qemu-devel] [PATCH v2 02/25] sdcard: replace DPRINTF() by trace events Philippe Mathieu-Daudé
2018-01-03 21:24 ` [Qemu-devel] [PATCH v2 03/25] sdcard: add more " Philippe Mathieu-Daudé
2018-01-03 21:24 ` [Qemu-devel] [PATCH v2 04/25] sdcard: define SDCARD_CMD_MAX instead of using the magic '64' Philippe Mathieu-Daudé
2018-01-08 21:47   ` Alistair Francis
2018-01-03 21:24 ` [Qemu-devel] [PATCH v2 05/25] sdcard: display command name when tracing CMD/ACMD Philippe Mathieu-Daudé
2018-01-03 21:24 ` [Qemu-devel] [PATCH v2 06/25] sdcard: let cmd_valid_while_locked() returns a bool Philippe Mathieu-Daudé
2018-01-03 21:24 ` [Qemu-devel] [PATCH v2 07/25] sdcard: rename sd_set_$REG() functions called once as sd_reset_$REG() Philippe Mathieu-Daudé
2018-01-03 21:24 ` [Qemu-devel] [PATCH v2 08/25] sdcard: use the registerfields API to access the OCR register Philippe Mathieu-Daudé
2018-01-03 21:24 ` [Qemu-devel] [PATCH v2 09/25] sdcard: use G_BYTE from cutils Philippe Mathieu-Daudé
2018-01-08 21:45   ` Alistair Francis
2018-01-03 21:24 ` [Qemu-devel] [PATCH v2 10/25] sdcard: remove unreachable code Philippe Mathieu-Daudé
2018-01-03 21:24 ` [Qemu-devel] [PATCH v2 11/25] sdcard: replace switch(unique case) statements -> if(case) Philippe Mathieu-Daudé
2018-01-03 21:24 ` [Qemu-devel] [PATCH v2 12/25] sdcard: use a 16-bit integer for the 16-bit RCA register Philippe Mathieu-Daudé
2018-01-08 21:49   ` Alistair Francis
2018-01-03 21:24 ` [Qemu-devel] [PATCH v2 13/25] sdcard: let function handling response codes returns the response size Philippe Mathieu-Daudé
2018-01-03 21:24 ` [Qemu-devel] [PATCH v2 14/25] sdcard: add missing command CMD55 Philippe Mathieu-Daudé
2018-01-03 21:24 ` [Qemu-devel] [PATCH v2 15/25] sdcard: add missing CMD54 SDIO command Philippe Mathieu-Daudé
2018-01-03 21:24 ` [Qemu-devel] [RFC PATCH v2 16/25] sdcard: add missing SPI legal commands Philippe Mathieu-Daudé
2018-01-03 21:24 ` [Qemu-devel] [RFC PATCH v2 17/25] sdcard: fix SPI response length Philippe Mathieu-Daudé
2018-01-03 21:24 ` [Qemu-devel] [PATCH v2 18/25] sdcard: add an enum for the SD PHY Spec version Philippe Mathieu-Daudé
2018-01-03 21:24 ` [Qemu-devel] [PATCH v2 19/25] sdcard: check if the card capacity is supported Philippe Mathieu-Daudé
2018-01-03 21:24 ` [Qemu-devel] [PATCH v2 20/25] sdcard: Don't always set the high capacity bit Philippe Mathieu-Daudé
2018-01-03 21:24 ` [Qemu-devel] [PATCH v2 21/25] sdcard: add cmd_version_supported(), improve cmd_class_supported() Philippe Mathieu-Daudé
2018-01-03 21:24 ` [Qemu-devel] [PATCH v2 22/25] sdcard: remove unreachable SPI commands Philippe Mathieu-Daudé
2018-01-03 21:24 ` [Qemu-devel] [RFC PATCH v2 23/25] sdcard: store the bus protocol in an enum Philippe Mathieu-Daudé
2018-01-03 21:24 ` [Qemu-devel] [PATCH v2 24/25] sdcard: introduce Spec v3.01 SD commands Philippe Mathieu-Daudé
2018-01-03 21:24 ` Philippe Mathieu-Daudé [this message]

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=20180103212436.15762-26-f4bug@amsat.org \
    --to=f4bug@amsat.org \
    --cc=Andrew.Baumann@microsoft.com \
    --cc=alistair.francis@xilinx.com \
    --cc=balrogg@gmail.com \
    --cc=crosthwaite.peter@gmail.com \
    --cc=edgar.iglesias@xilinx.com \
    --cc=i.mitsyanko@gmail.com \
    --cc=m.olbrich@pengutronix.de \
    --cc=marcandre.lureau@redhat.com \
    --cc=paul@codesourcery.com \
    --cc=peter.maydell@linaro.org \
    --cc=pjp@fedoraproject.org \
    --cc=qemu-devel@nongnu.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: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).