qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
To: Xiao Guangrong <guangrong.xiao@linux.intel.com>,
	pbonzini@redhat.com, imammedo@redhat.com
Cc: ehabkost@redhat.com, kvm@vger.kernel.org, mst@redhat.com,
	gleb@kernel.org, mtosatti@redhat.com, qemu-devel@nongnu.org,
	stefanha@redhat.com, dan.j.williams@intel.com, rth@twiddle.net
Subject: Re: [Qemu-devel] [PATCH v7 23/35] nvdimm: implement NVDIMM device abstract
Date: Fri, 13 Nov 2015 19:53:44 +0300	[thread overview]
Message-ID: <56461598.2050109@virtuozzo.com> (raw)
In-Reply-To: <1446455617-129562-24-git-send-email-guangrong.xiao@linux.intel.com>

On 02.11.2015 12:13, Xiao Guangrong wrote:
> Introduce "nvdimm" device which is based on dimm device type
>
> 128K memory region which is the minimum namespace label size
> required by NVDIMM Namespace Spec locates at the end of
> backend memory device is reserved for label data
>
> We can use "-m 1G,maxmem=100G,slots=10 -object memory-backend-file,
> id=mem1,size=1G,mem-path=/dev/pmem0 -device nvdimm,memdev=mem1" to
> create NVDIMM device for guest
>
> Signed-off-by: Xiao Guangrong <guangrong.xiao@linux.intel.com>
> ---
>   default-configs/i386-softmmu.mak   |   1 +
>   default-configs/x86_64-softmmu.mak |   1 +
>   hw/acpi/memory_hotplug.c           |   6 ++
>   hw/mem/Makefile.objs               |   1 +
>   hw/mem/nvdimm.c                    | 116 +++++++++++++++++++++++++++++++++++++
>   include/hw/mem/nvdimm.h            |  83 ++++++++++++++++++++++++++
>   6 files changed, 208 insertions(+)
>   create mode 100644 hw/mem/nvdimm.c
>   create mode 100644 include/hw/mem/nvdimm.h
>
> diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak
> index 3ece8bb..4e84a1c 100644
> --- a/default-configs/i386-softmmu.mak
> +++ b/default-configs/i386-softmmu.mak
> @@ -47,6 +47,7 @@ CONFIG_APIC=y
>   CONFIG_IOAPIC=y
>   CONFIG_PVPANIC=y
>   CONFIG_MEM_HOTPLUG=y
> +CONFIG_NVDIMM=y
>   CONFIG_XIO3130=y
>   CONFIG_IOH3420=y
>   CONFIG_I82801B11=y
> diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak
> index 92ea7c1..e877a86 100644
> --- a/default-configs/x86_64-softmmu.mak
> +++ b/default-configs/x86_64-softmmu.mak
> @@ -47,6 +47,7 @@ CONFIG_APIC=y
>   CONFIG_IOAPIC=y
>   CONFIG_PVPANIC=y
>   CONFIG_MEM_HOTPLUG=y
> +CONFIG_NVDIMM=y
>   CONFIG_XIO3130=y
>   CONFIG_IOH3420=y
>   CONFIG_I82801B11=y
> diff --git a/hw/acpi/memory_hotplug.c b/hw/acpi/memory_hotplug.c
> index 20d3093..bb5a29f 100644
> --- a/hw/acpi/memory_hotplug.c
> +++ b/hw/acpi/memory_hotplug.c
> @@ -1,6 +1,7 @@
>   #include "hw/acpi/memory_hotplug.h"
>   #include "hw/acpi/pc-hotplug.h"
>   #include "hw/mem/dimm.h"
> +#include "hw/mem/nvdimm.h"
>   #include "hw/boards.h"
>   #include "hw/qdev-core.h"
>   #include "trace.h"
> @@ -231,6 +232,11 @@ void acpi_memory_plug_cb(ACPIREGS *ar, qemu_irq irq, MemHotplugState *mem_st,
>   {
>       MemStatus *mdev;
>   
> +    /* Currently, NVDIMM hotplug has not been supported yet. */
> +    if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) {
> +        return;
> +    }
> +

hmm, should not check for DIMM_GET_CLASS(dev)->hotpluggable be used here 
instead for more common case covering?

>       mdev = acpi_memory_slot_status(mem_st, dev, errp);
>       if (!mdev) {
>           return;
> diff --git a/hw/mem/Makefile.objs b/hw/mem/Makefile.objs
> index cebb4b1..12d9b72 100644
> --- a/hw/mem/Makefile.objs
> +++ b/hw/mem/Makefile.objs
> @@ -1,2 +1,3 @@
>   common-obj-$(CONFIG_DIMM) += dimm.o
>   common-obj-$(CONFIG_MEM_HOTPLUG) += pc-dimm.o
> +common-obj-$(CONFIG_NVDIMM) += nvdimm.o
> diff --git a/hw/mem/nvdimm.c b/hw/mem/nvdimm.c
> new file mode 100644
> index 0000000..c310887
> --- /dev/null
> +++ b/hw/mem/nvdimm.c
> @@ -0,0 +1,116 @@
> +/*
> + * Non-Volatile Dual In-line Memory Module Virtualization Implementation
> + *
> + * Copyright(C) 2015 Intel Corporation.
> + *
> + * Author:
> + *  Xiao Guangrong <guangrong.xiao@linux.intel.com>
> + *
> + * Currently, it only supports PMEM Virtualization.
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see <http://www.gnu.org/licenses/>
> + */
> +
> +#include "qapi/visitor.h"
> +#include "hw/mem/nvdimm.h"
> +
> +static MemoryRegion *nvdimm_get_memory_region(DIMMDevice *dimm)
> +{
> +    NVDIMMDevice *nvdimm = NVDIMM(dimm);
> +
> +    /* plug a NVDIMM device which is not properly realized? */
> +    assert(memory_region_size(&nvdimm->nvdimm_mr));
> +
> +    return &nvdimm->nvdimm_mr;
> +}
> +
> +static void nvdimm_realize(DIMMDevice *dimm, Error **errp)
> +{
> +    MemoryRegion *mr;
> +    NVDIMMDevice *nvdimm = NVDIMM(dimm);
> +    uint64_t size;
> +
> +    nvdimm->label_size = MIN_NAMESPACE_LABEL_SIZE;
> +
> +    mr = host_memory_backend_get_memory(dimm->hostmem, errp);
> +    size = memory_region_size(mr);
> +
> +    if (size <= nvdimm->label_size) {
> +        char *path = object_get_canonical_path_component(OBJECT(dimm->hostmem));
> +        error_setg(errp, "the size of memdev %s (0x%" PRIx64 ") is too small"
> +                   " to contain nvdimm namespace label (0x%" PRIx64 ")", path,
> +                   memory_region_size(mr), nvdimm->label_size);
> +        return;
> +    }
> +
> +    memory_region_init_alias(&nvdimm->nvdimm_mr, OBJECT(dimm), "nvdimm-memory",
> +                             mr, 0, size - nvdimm->label_size);
> +    nvdimm->label_data = memory_region_get_ram_ptr(mr) +
> +                         memory_region_size(&nvdimm->nvdimm_mr);
> +}
> +
> +static void nvdimm_read_label_data(NVDIMMDevice *nvdimm, void *buf,
> +                                   uint64_t size, uint64_t offset)
> +{
> +    assert((nvdimm->label_size >= size + offset) && (offset + size > offset));
> +
> +    memcpy(buf, nvdimm->label_data + offset, size);
> +}
> +
> +static void nvdimm_write_label_data(NVDIMMDevice *nvdimm, const void *buf,
> +                                    uint64_t size, uint64_t offset)
> +{
> +    MemoryRegion *mr;
> +    DIMMDevice *dimm = DIMM(nvdimm);
> +    uint64_t backend_offset;
> +
> +    assert((nvdimm->label_size >= size + offset) && (offset + size > offset));
> +
> +    memcpy(nvdimm->label_data + offset, buf, size);
> +
> +    mr = host_memory_backend_get_memory(dimm->hostmem, &error_abort);
> +    backend_offset = memory_region_size(mr) - nvdimm->label_size + offset;
> +    memory_region_set_dirty(mr, backend_offset, size);
> +}
> +
> +static void nvdimm_class_init(ObjectClass *oc, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(oc);
> +    DIMMDeviceClass *ddc = DIMM_CLASS(oc);
> +    NVDIMMClass *nvc = NVDIMM_CLASS(oc);
> +
> +    /* nvdimm hotplug has not been supported yet. */
> +    dc->hotpluggable = false;
> +
> +    ddc->realize = nvdimm_realize;
> +    ddc->get_memory_region = nvdimm_get_memory_region;
> +
> +    nvc->read_label_data = nvdimm_read_label_data;
> +    nvc->write_label_data = nvdimm_write_label_data;
> +}
> +
> +static TypeInfo nvdimm_info = {
> +    .name          = TYPE_NVDIMM,
> +    .parent        = TYPE_DIMM,
> +    .instance_size = sizeof(NVDIMMDevice),
> +    .class_init    = nvdimm_class_init,
> +    .class_size    = sizeof(NVDIMMClass),
> +};
> +
> +static void nvdimm_register_types(void)
> +{
> +    type_register_static(&nvdimm_info);
> +}
> +
> +type_init(nvdimm_register_types)
> diff --git a/include/hw/mem/nvdimm.h b/include/hw/mem/nvdimm.h
> new file mode 100644
> index 0000000..cd90957
> --- /dev/null
> +++ b/include/hw/mem/nvdimm.h
> @@ -0,0 +1,83 @@
> +/*
> + * Non-Volatile Dual In-line Memory Module Virtualization Implementation
> + *
> + * Copyright(C) 2015 Intel Corporation.
> + *
> + * Author:
> + *  Xiao Guangrong <guangrong.xiao@linux.intel.com>
> + *
> + * NVDIMM specifications and some documents can be found at:
> + * NVDIMM ACPI device and NFIT are introduced in ACPI 6:
> + *      http://www.uefi.org/sites/default/files/resources/ACPI_6.0.pdf
> + * NVDIMM Namespace specification:
> + *      http://pmem.io/documents/NVDIMM_Namespace_Spec.pdf
> + * DSM Interface Example:
> + *      http://pmem.io/documents/NVDIMM_DSM_Interface_Example.pdf
> + * Driver Writer's Guide:
> + *      http://pmem.io/documents/NVDIMM_Driver_Writers_Guide.pdf
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +#ifndef QEMU_NVDIMM_H
> +#define QEMU_NVDIMM_H
> +
> +#include "hw/mem/dimm.h"
> +
> +/*
> + * The minimum label data size is required by NVDIMM Namespace
> + * specification, please refer to chapter 2 Namespaces:
> + *   "NVDIMMs following the NVDIMM Block Mode Specification use an area
> + *    at least 128KB in size, which holds around 1000 labels."
> + */
> +#define MIN_NAMESPACE_LABEL_SIZE      (128UL << 10)
> +
> +#define TYPE_NVDIMM      "nvdimm"
> +#define NVDIMM(obj)      OBJECT_CHECK(NVDIMMDevice, (obj), TYPE_NVDIMM)
> +#define NVDIMM_CLASS(oc) OBJECT_CLASS_CHECK(NVDIMMClass, (oc), TYPE_NVDIMM)
> +#define NVDIMM_GET_CLASS(obj) OBJECT_GET_CLASS(NVDIMMClass, (obj), \
> +                                               TYPE_NVDIMM)
> +
> +struct NVDIMMDevice {
> +    /* private */
> +    DIMMDevice parent_obj;
> +
> +    /* public */
> +
> +    /*
> +     * the size of label data in NVDIMM device which is presented to
> +     * guest via __DSM "Get Namespace Label Size" command.
> +     */
> +    uint64_t label_size;
> +
> +    /*
> +     * the address of label data which is read by __DSM "Get Namespace
> +     * Label Data" command and written by __DSM "Set Namespace Label
> +     * Data" command.
> +     */
> +    void *label_data;
> +
> +    /*
> +     * it's the PMEM region in NVDIMM device, which is presented to
> +     * guest via ACPI NFIT and _FIT method if NVDIMM hotplug is supported.
> +     */
> +    MemoryRegion nvdimm_mr;
> +};
> +typedef struct NVDIMMDevice NVDIMMDevice;
> +
> +struct NVDIMMClass {
> +    /* private */
> +    DIMMDeviceClass parent_class;
> +
> +    /* public */
> +    /* read @size bytes from NVDIMM label data at @offset into @buf. */
> +    void (*read_label_data)(NVDIMMDevice *nvdimm, void *buf,
> +                            uint64_t size, uint64_t offset);
> +    /* write @size bytes from @buf to NVDIMM label data at @offset. */
> +    void (*write_label_data)(NVDIMMDevice *nvdimm, const void *buf,
> +                             uint64_t size, uint64_t offset);
> +};
> +typedef struct NVDIMMClass NVDIMMClass;
> +
> +#endif


-- 
Best regards,
Vladimir
* now, @virtuozzo.com instead of @parallels.com. Sorry for this inconvenience.

  reply	other threads:[~2015-11-13 16:54 UTC|newest]

Thread overview: 101+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-11-02  9:13 [Qemu-devel] [PATCH v7 00/35] implement vNVDIMM Xiao Guangrong
2015-11-02  9:13 ` [Qemu-devel] [PATCH v7 01/35] acpi: add aml_derefof Xiao Guangrong
2015-11-02  9:13 ` [Qemu-devel] [PATCH v7 02/35] acpi: add aml_sizeof Xiao Guangrong
2015-11-02  9:13 ` [Qemu-devel] [PATCH v7 03/35] acpi: add aml_create_field Xiao Guangrong
2015-11-03  6:14   ` Shannon Zhao
2015-11-03 14:52     ` Xiao Guangrong
2015-11-02  9:13 ` [Qemu-devel] [PATCH v7 04/35] acpi: add aml_concatenate Xiao Guangrong
2015-11-02  9:13 ` [Qemu-devel] [PATCH v7 05/35] acpi: add aml_object_type Xiao Guangrong
2015-11-02  9:13 ` [Qemu-devel] [PATCH v7 06/35] acpi: add aml_method_serialized Xiao Guangrong
2015-11-03 12:30   ` Igor Mammedov
2015-11-03 13:27     ` Xiao Guangrong
2015-11-02  9:13 ` [Qemu-devel] [PATCH v7 07/35] util: introduce qemu_file_get_page_size() Xiao Guangrong
2015-11-02 13:56   ` Vladimir Sementsov-Ogievskiy
2015-11-06 15:36   ` Eduardo Habkost
2015-11-09  4:36     ` Xiao Guangrong
2015-11-09 18:34       ` Eduardo Habkost
2015-11-02  9:13 ` [Qemu-devel] [PATCH v7 08/35] exec: allow memory to be allocated from any kind of path Xiao Guangrong
2015-11-02 14:51   ` Vladimir Sementsov-Ogievskiy
2015-11-02 15:22     ` Xiao Guangrong
2015-11-02 15:52       ` Vladimir Sementsov-Ogievskiy
2015-11-03 23:00   ` Eduardo Habkost
2015-11-04  3:12     ` Xiao Guangrong
2015-11-04 12:40       ` Eduardo Habkost
2015-11-04 14:22         ` Xiao Guangrong
2015-11-02  9:13 ` [Qemu-devel] [PATCH v7 09/35] exec: allow file_ram_alloc to work on file Xiao Guangrong
2015-11-02 15:12   ` Vladimir Sementsov-Ogievskiy
2015-11-02 15:25     ` Xiao Guangrong
2015-11-02 15:58       ` Vladimir Sementsov-Ogievskiy
2015-11-02 21:12   ` Paolo Bonzini
2015-11-03  3:56     ` Xiao Guangrong
2015-11-03 13:55       ` Paolo Bonzini
2015-11-03 14:26         ` Xiao Guangrong
2015-11-03 12:34   ` Igor Mammedov
2015-11-03 13:32     ` Xiao Guangrong
2015-11-02  9:13 ` [Qemu-devel] [PATCH v7 10/35] hostmem-file: clean up memory allocation Xiao Guangrong
2015-11-02  9:13 ` [Qemu-devel] [PATCH v7 11/35] util: introduce qemu_file_getlength() Xiao Guangrong
2015-11-02 15:26   ` Vladimir Sementsov-Ogievskiy
2015-11-03 23:21   ` Eduardo Habkost
2015-11-04  3:17     ` Xiao Guangrong
2015-11-04 14:44       ` Eduardo Habkost
2015-11-04 14:44         ` Xiao Guangrong
2015-11-06 15:50   ` Eduardo Habkost
2015-11-09  4:44     ` Xiao Guangrong
2015-11-09 19:21       ` Eduardo Habkost
2015-11-02  9:13 ` [Qemu-devel] [PATCH v7 12/35] util: let qemu_fd_getlength support block device Xiao Guangrong
2015-11-02 16:11   ` Vladimir Sementsov-Ogievskiy
2015-11-02 16:21     ` Xiao Guangrong
2015-11-06 15:44       ` Eduardo Habkost
2015-11-06 15:48   ` Eduardo Habkost
2015-11-06 15:54   ` Eduardo Habkost
2015-11-09  5:58     ` Xiao Guangrong
2015-11-09 18:43       ` Eduardo Habkost
2015-11-02  9:13 ` [Qemu-devel] [PATCH v7 13/35] hostmem-file: use whole file size if possible Xiao Guangrong
2015-11-02 17:09   ` Vladimir Sementsov-Ogievskiy
2015-11-03 14:51     ` Xiao Guangrong
2015-11-02  9:13 ` [Qemu-devel] [PATCH v7 14/35] pc-dimm: remove DEFAULT_PC_DIMMSIZE Xiao Guangrong
2015-11-02  9:13 ` [Qemu-devel] [PATCH v7 15/35] pc-dimm: make pc_existing_dimms_capacity static and rename it Xiao Guangrong
2015-11-02  9:13 ` [Qemu-devel] [PATCH v7 16/35] pc-dimm: drop the prefix of pc-dimm Xiao Guangrong
2015-11-02  9:13 ` [Qemu-devel] [PATCH v7 17/35] stubs: rename qmp_pc_dimm_device_list.c Xiao Guangrong
2015-11-02  9:13 ` [Qemu-devel] [PATCH v7 18/35] pc-dimm: rename pc-dimm.c and pc-dimm.h Xiao Guangrong
2015-11-02  9:13 ` [Qemu-devel] [PATCH v7 19/35] dimm: abstract dimm device from pc-dimm Xiao Guangrong
2015-11-02  9:13 ` [Qemu-devel] [PATCH v7 20/35] dimm: get mapped memory region from DIMMDeviceClass->get_memory_region Xiao Guangrong
2015-11-02 12:19   ` Vladimir Sementsov-Ogievskiy
2015-11-02 13:08     ` Xiao Guangrong
2015-11-02 14:26       ` Vladimir Sementsov-Ogievskiy
2015-11-02 15:06         ` Xiao Guangrong
2015-11-02 16:16           ` Vladimir Sementsov-Ogievskiy
2015-11-03 14:47             ` Xiao Guangrong
2015-11-05  8:53               ` Vladimir Sementsov-Ogievskiy
2015-11-05 17:29   ` Eduardo Habkost
2015-11-06  2:50     ` Xiao Guangrong
2015-11-02  9:13 ` [Qemu-devel] [PATCH v7 21/35] dimm: keep the state of the whole backend memory Xiao Guangrong
2015-11-02  9:13 ` [Qemu-devel] [PATCH v7 22/35] dimm: introduce realize callback Xiao Guangrong
2015-11-02  9:13 ` [Qemu-devel] [PATCH v7 23/35] nvdimm: implement NVDIMM device abstract Xiao Guangrong
2015-11-13 16:53   ` Vladimir Sementsov-Ogievskiy [this message]
2015-11-02  9:13 ` [Qemu-devel] [PATCH v7 24/35] docs: add NVDIMM ACPI documentation Xiao Guangrong
2015-11-02  9:13 ` [Qemu-devel] [PATCH v7 25/35] nvdimm acpi: init the resource used by NVDIMM ACPI Xiao Guangrong
2015-11-05  9:58   ` Igor Mammedov
2015-11-05 10:15     ` Xiao Guangrong
2015-11-05 13:03       ` Igor Mammedov
2015-11-05 13:33         ` Xiao Guangrong
2015-11-05 14:49           ` Igor Mammedov
2015-11-06  8:31             ` Xiao Guangrong
2015-11-06  8:56               ` Xiao Guangrong
2015-11-09 11:13               ` Igor Mammedov
2015-11-11  3:01                 ` [Qemu-devel] Ask for ACK (was Re: [PATCH v7 25/35] nvdimm acpi: init the resource used by NVDIMM ACPI) Xiao Guangrong
2015-11-02  9:13 ` [Qemu-devel] [PATCH v7 26/35] nvdimm acpi: build ACPI NFIT table Xiao Guangrong
2015-11-02  9:13 ` [Qemu-devel] [PATCH v7 27/35] nvdimm acpi: build ACPI nvdimm devices Xiao Guangrong
2015-11-03 13:13   ` Igor Mammedov
2015-11-03 14:22     ` Xiao Guangrong
2015-11-04  8:56       ` Igor Mammedov
2015-11-04 14:11         ` Xiao Guangrong
2015-11-02  9:13 ` [Qemu-devel] [PATCH v7 28/35] nvdimm acpi: save arg3 for NVDIMM device _DSM method Xiao Guangrong
2015-11-02  9:13 ` [Qemu-devel] [PATCH v7 29/35] nvdimm acpi: support function 0 Xiao Guangrong
2015-11-02  9:13 ` [Qemu-devel] [PATCH v7 30/35] nvdimm acpi: support Get Namespace Label Size function Xiao Guangrong
2015-11-02  9:13 ` [Qemu-devel] [PATCH v7 31/35] nvdimm acpi: support Get Namespace Label Data function Xiao Guangrong
2015-11-02  9:13 ` [Qemu-devel] [PATCH v7 32/35] nvdimm acpi: support Set " Xiao Guangrong
2015-11-02  9:13 ` [Qemu-devel] [PATCH v7 33/35] nvdimm: allow using whole backend memory as pmem Xiao Guangrong
2015-11-02  9:13 ` [Qemu-devel] [PATCH v7 34/35] nvdimm acpi: support _FIT method Xiao Guangrong
2015-11-02  9:13 ` [Qemu-devel] [PATCH v7 35/35] nvdimm: add maintain info Xiao Guangrong
2015-11-02 11:51 ` [Qemu-devel] [PATCH v7 00/35] implement vNVDIMM Stefan Hajnoczi

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=56461598.2050109@virtuozzo.com \
    --to=vsementsov@virtuozzo.com \
    --cc=dan.j.williams@intel.com \
    --cc=ehabkost@redhat.com \
    --cc=gleb@kernel.org \
    --cc=guangrong.xiao@linux.intel.com \
    --cc=imammedo@redhat.com \
    --cc=kvm@vger.kernel.org \
    --cc=mst@redhat.com \
    --cc=mtosatti@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=rth@twiddle.net \
    --cc=stefanha@redhat.com \
    /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).