qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: "Andreas Färber" <afaerber@suse.de>
To: Vasilis Liaskovitis <vasilis.liaskovitis@profitbricks.com>
Cc: pingfank@linux.vnet.ibm.com, gleb@redhat.com,
	Hu Tao <hutao@cn.fujitsu.com>,
	jbaron@redhat.com, seabios@seabios.org, qemu-devel@nongnu.org,
	blauwirbel@gmail.com, kevin@koconnor.net, kraxel@redhat.com,
	anthony@codemonkey.ws, stefanha@gmail.com
Subject: Re: [Qemu-devel] [RFC PATCH v4 13/30] piix_pci and pc_piix: refactor
Date: Wed, 16 Jan 2013 12:17:05 +0100	[thread overview]
Message-ID: <50F68C31.70006@suse.de> (raw)
In-Reply-To: <20130116093638.GA6141@dhcp-192-168-178-175.profitbricks.localdomain>

Hi,

Am 16.01.2013 10:36, schrieb Vasilis Liaskovitis:
> On Wed, Jan 16, 2013 at 03:20:40PM +0800, Hu Tao wrote:
>> On Tue, Dec 18, 2012 at 01:41:41PM +0100, Vasilis Liaskovitis wrote:
>>> Refactor code so that chipset initialization is similar to q35. This will
>>> allow memory map initialization at chipset qdev init time for both
>>> machines, as well as more similar code structure overall.
>>>
>>> Signed-off-by: Vasilis Liaskovitis <vasilis.liaskovitis@profitbricks.com>
>>> ---
>>>  hw/pc_piix.c  |   57 ++++++++++++---
>>>  hw/piix_pci.c |  225 ++++++++++++++-------------------------------------------
>>>  2 files changed, 100 insertions(+), 182 deletions(-)
>>>
>>> diff --git a/hw/pc_piix.c b/hw/pc_piix.c
>>> index 19e342a..6a9b508 100644
>>> --- a/hw/pc_piix.c
>>> +++ b/hw/pc_piix.c
>>> @@ -47,6 +47,7 @@
>>>  #ifdef CONFIG_XEN
>>>  #  include <xen/hvm/hvm_info_table.h>
>>>  #endif
>>> +#include "piix_pci.h"
>>
>> Can't find this file. Did you forget to add this file to git?
> 
> sorry, you are right. Below is the corrected patch with the missing header

Please take review comments on other similar series into account. You
can also check if the QOM Vadis slides from KVM Forum are online somewhere.

You are aware that there were two people previously working on
QOM'ifying i440fx?

> Refactor code so that chipset initialization is similar to q35. This will
> allow memory map initialization at chipset qdev init time for both
> machines, as well as more similar code structure overall.
> 
> Signed-off-by: Vasilis Liaskovitis <vasilis.liaskovitis@profitbricks.com>
> ---
>  hw/pc_piix.c  |   57 ++++++++++++---
>  hw/piix_pci.c |  225 ++++++++++++++-------------------------------------------
>  hw/piix_pci.h |  116 +++++++++++++++++++++++++++++
>  3 files changed, 216 insertions(+), 182 deletions(-)
>  create mode 100644 hw/piix_pci.h
> 
> diff --git a/hw/pc_piix.c b/hw/pc_piix.c
> index 19e342a..6a9b508 100644
> --- a/hw/pc_piix.c
> +++ b/hw/pc_piix.c
[...]
> @@ -127,21 +130,53 @@ static void pc_init1(MemoryRegion *system_memory,
>      }
>  
>      if (pci_enabled) {
> -        pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, &isa_bus, gsi,
> -                              system_memory, system_io, ram_size,
> -                              below_4g_mem_size,
> -                              0x100000000ULL - below_4g_mem_size,
> -                              0x100000000ULL + above_4g_mem_size,
> -                              (sizeof(hwaddr) == 4
> -                               ? 0
> -                               : ((uint64_t)1 << 62)),
> -                              pci_memory, ram_memory);
> +        i440fx_host = I440FX_HOST_DEVICE(qdev_create(NULL,
> +                    TYPE_I440FX_HOST_DEVICE));

Elsewhere it was requested to use _HOST_BRIDGE wording.

> +        i440fx_host->mch.ram_memory = ram_memory;
> +        i440fx_host->mch.pci_address_space = pci_memory;
> +        i440fx_host->mch.system_memory = get_system_memory();
> +        i440fx_host->mch.address_space_io = get_system_io();;
> +        i440fx_host->mch.below_4g_mem_size = below_4g_mem_size;
> +        i440fx_host->mch.above_4g_mem_size = above_4g_mem_size;
> +
> +        qdev_init_nofail(DEVICE(i440fx_host));
> +        i440fx_state = &i440fx_host->mch;
> +        pci_bus = i440fx_host->parent_obj.bus;

Please don't access the parent field, in particular not "parent_obj". It
was specifically renamed after checking that no more users exist.

PCIHostState *phb = PCI_HOST_BRIDGE(i440fx_host);
...
pci_bus = phb->bus;

> +        /* Xen supports additional interrupt routes from the PCI devices to
> +         * the IOAPIC: the four pins of each PCI device on the bus are also
> +         * connected to the IOAPIC directly.
> +         * These additional routes can be discovered through ACPI. */
> +        if (xen_enabled()) {
> +            piix3 = DO_UPCAST(PIIX3State, dev,
> +                    pci_create_simple_multifunction(pci_bus, -1, true,
> +                        "PIIX3-xen"));

Please don't introduce new usages of DO_UPCAST() with QOM types. Instead
add QOM cast macros where needed and use them.

> +            pci_bus_irqs(pci_bus, xen_piix3_set_irq, xen_pci_slot_get_pirq,
> +                    piix3, XEN_PIIX_NUM_PIRQS);
> +        } else {
> +            piix3 = DO_UPCAST(PIIX3State, dev,
> +                    pci_create_simple_multifunction(pci_bus, -1, true,
> +                        "PIIX3"));
> +            pci_bus_irqs(pci_bus, piix3_set_irq, pci_slot_get_pirq, piix3,
> +                    PIIX_NUM_PIRQS);
> +            pci_bus_set_route_irq_fn(pci_bus, piix3_route_intx_pin_to_irq);
> +        }
> +        piix3->pic = gsi;
> +        isa_bus = DO_UPCAST(ISABus, qbus,
> +                qdev_get_child_bus(&piix3->dev.qdev, "isa.0"));

isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(piix3), ...));

> +
> +        piix3_devfn = piix3->dev.devfn;
> +
> +        ram_size = ram_size / 8 / 1024 / 1024;
> +        if (ram_size > 255) {
> +            ram_size = 255;
> +        }
> +        i440fx_state->dev.config[0x57] = ram_size;
>      } else {
>          pci_bus = NULL;
> -        i440fx_state = NULL;
>          isa_bus = isa_bus_new(NULL, system_io);
>          no_hpet = 1;
>      }
> +
>      isa_bus_irqs(isa_bus, gsi);
>  
>      if (kvm_irqchip_in_kernel()) {
> @@ -157,7 +192,7 @@ static void pc_init1(MemoryRegion *system_memory,
>          gsi_state->i8259_irq[i] = i8259[i];
>      }
>      if (pci_enabled) {
> -        ioapic_init_gsi(gsi_state, "i440fx");
> +        ioapic_init_gsi(gsi_state, NULL);

Unrelated? Why?

>      }
>  
>      pc_register_ferr_irq(gsi[13]);
> diff --git a/hw/piix_pci.c b/hw/piix_pci.c
> index ba1b3de..7ca3c73 100644
> --- a/hw/piix_pci.c
> +++ b/hw/piix_pci.c
> @@ -31,70 +31,15 @@
>  #include "range.h"
>  #include "xen.h"
>  #include "pam.h"
> +#include "piix_pci.h"
>  
> -/*
> - * I440FX chipset data sheet.
> - * http://download.intel.com/design/chipsets/datashts/29054901.pdf
> - */
> -
> -typedef struct I440FXState {
> -    PCIHostState parent_obj;
> -} I440FXState;
> -
> -#define PIIX_NUM_PIC_IRQS       16      /* i8259 * 2 */
> -#define PIIX_NUM_PIRQS          4ULL    /* PIRQ[A-D] */
> -#define XEN_PIIX_NUM_PIRQS      128ULL
> -#define PIIX_PIRQC              0x60
> -
> -typedef struct PIIX3State {
> -    PCIDevice dev;
> -
> -    /*
> -     * bitmap to track pic levels.
> -     * The pic level is the logical OR of all the PCI irqs mapped to it
> -     * So one PIC level is tracked by PIIX_NUM_PIRQS bits.
> -     *
> -     * PIRQ is mapped to PIC pins, we track it by
> -     * PIIX_NUM_PIRQS * PIIX_NUM_PIC_IRQS = 64 bits with
> -     * pic_irq * PIIX_NUM_PIRQS + pirq
> -     */
> -#if PIIX_NUM_PIC_IRQS * PIIX_NUM_PIRQS > 64
> -#error "unable to encode pic state in 64bit in pic_levels."
> -#endif
> -    uint64_t pic_levels;
> -
> -    qemu_irq *pic;
> -
> -    /* This member isn't used. Just for save/load compatibility */
> -    int32_t pci_irq_levels_vmstate[PIIX_NUM_PIRQS];
> -} PIIX3State;
> -
> -struct PCII440FXState {
> -    PCIDevice dev;
> -    MemoryRegion *system_memory;
> -    MemoryRegion *pci_address_space;
> -    MemoryRegion *ram_memory;
> -    MemoryRegion pci_hole;
> -    MemoryRegion pci_hole_64bit;
> -    PAMMemoryRegion pam_regions[13];
> -    MemoryRegion smram_region;
> -    uint8_t smm_enabled;
> -};
> -
> -
> -#define I440FX_PAM      0x59
> -#define I440FX_PAM_SIZE 7
> -#define I440FX_SMRAM    0x72
> -
> -static void piix3_set_irq(void *opaque, int pirq, int level);
> -static PCIINTxRoute piix3_route_intx_pin_to_irq(void *opaque, int pci_intx);
>  static void piix3_write_config_xen(PCIDevice *dev,
>                                 uint32_t address, uint32_t val, int len);
>  
>  /* return the global irq number corresponding to a given device irq
>     pin. We could also use the bus number to have a more precise
>     mapping. */
> -static int pci_slot_get_pirq(PCIDevice *pci_dev, int pci_intx)
> +int pci_slot_get_pirq(PCIDevice *pci_dev, int pci_intx)
>  {
>      int slot_addend;
>      slot_addend = (pci_dev->devfn >> 3) - 1;
> @@ -180,149 +125,86 @@ static const VMStateDescription vmstate_i440fx = {
>      }
>  };
>  
> -static int i440fx_pcihost_initfn(SysBusDevice *dev)
> +static void i440fx_pcihost_initfn(Object *obj)
>  {
> -    PCIHostState *s = PCI_HOST_BRIDGE(dev);
> +    I440FXState *s = I440FX_HOST_DEVICE(obj);
> +    object_initialize(&s->mch, TYPE_I440FX_PCI_DEVICE);
> +    object_property_add_child(OBJECT(s), "mch", OBJECT(&s->mch), NULL);

Is there maybe a more readable property name?

> +}
>  
> -    memory_region_init_io(&s->conf_mem, &pci_host_conf_le_ops, s,
> -                          "pci-conf-idx", 4);
> -    sysbus_add_io(dev, 0xcf8, &s->conf_mem);
> -    sysbus_init_ioports(&s->busdev, 0xcf8, 4);
> +static int i440fx_pcihost_init(SysBusDevice *dev)
> +{
> +    PCIHostState *pci = FROM_SYSBUS(PCIHostState, dev);

Don't use FROM_SYSBUS() either:

PCIHostState *phb = PCI_HOST_BRIDGE(dev);

> +    I440FXState *s = I440FX_HOST_DEVICE(&dev->qdev);

No need to access ->qdev, just use I440FX_...(dev);

> +    PCIBus *b;
> +
> +    memory_region_init_io(&pci->conf_mem, &pci_host_conf_le_ops, pci,
> +                           "pci-conf-idx", 4);
> +    sysbus_add_io(dev, 0xcf8, &pci->conf_mem);
> +    sysbus_init_ioports(&pci->busdev, 0xcf8, 4);
> +    memory_region_init_io(&pci->data_mem, &pci_host_data_le_ops, pci,
> +                           "pci-conf-data", 4);
>  
> -    memory_region_init_io(&s->data_mem, &pci_host_data_le_ops, s,
> -                          "pci-conf-data", 4);
> -    sysbus_add_io(dev, 0xcfc, &s->data_mem);
> -    sysbus_init_ioports(&s->busdev, 0xcfc, 4);
> +    sysbus_add_io(dev, 0xcfc, &pci->data_mem);
> +    sysbus_init_ioports(&pci->busdev, 0xcfc, 4);
> +
> +    b = pci_bus_new(&s->parent_obj.busdev.qdev, NULL, s->mch.pci_address_space,

DEVICE(dev)

> +                    s->mch.address_space_io, 0);

Initializing the bus in-place would be preferred.

> +    s->parent_obj.bus = b;
> +    qdev_set_parent_bus(DEVICE(&s->mch), BUS(b));
> +    qdev_init_nofail(DEVICE(&s->mch));

When casts other than OBJECT() are used multiple times, a variable is
preferred.

>  
>      return 0;
>  }
>  
>  static int i440fx_initfn(PCIDevice *dev)
>  {
> -    PCII440FXState *d = DO_UPCAST(PCII440FXState, dev, dev);
> +    int i;
> +    PCII440FXState *f = DO_UPCAST(PCII440FXState, dev, dev);
> +    hwaddr pci_hole64_size;
>  
> -    d->dev.config[I440FX_SMRAM] = 0x02;
> +    f->dev.config[I440FX_SMRAM] = 0x02;
>  
> -    cpu_smm_register(&i440fx_set_smm, d);
> -    return 0;
> -}
> +    cpu_smm_register(&i440fx_set_smm, f);

Is all this d -> f variable renaming really necessary? I can understand
the s -> pci (or for less ambiguity: phb) renaming above (I believe I
left it s to keep my patch small ;)), but here no new variable is
introduced so it just seems to enlarge the patch.

[...]
> @@ -550,7 +432,7 @@ static void i440fx_class_init(ObjectClass *klass, void *data)
>  }
>  
>  static const TypeInfo i440fx_info = {
> -    .name          = "i440FX",
> +    .name          = TYPE_I440FX_PCI_DEVICE,
>      .parent        = TYPE_PCI_DEVICE,

This matches the _PCI_DEVICE naming in earlier series including prep_pci

>      .instance_size = sizeof(PCII440FXState),
>      .class_init    = i440fx_class_init,
> @@ -561,15 +443,16 @@ static void i440fx_pcihost_class_init(ObjectClass *klass, void *data)
>      DeviceClass *dc = DEVICE_CLASS(klass);
>      SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
>  
> -    k->init = i440fx_pcihost_initfn;
> +    k->init = i440fx_pcihost_init;
>      dc->fw_name = "pci";
>      dc->no_user = 1;
>  }
>  
>  static const TypeInfo i440fx_pcihost_info = {
> -    .name          = "i440FX-pcihost",
> +    .name          = TYPE_I440FX_HOST_DEVICE,
>      .parent        = TYPE_PCI_HOST_BRIDGE,

whereas here you see the mentioned _HOST_DEVICE vs. _HOST_BRIDGE.

>      .instance_size = sizeof(I440FXState),
> +    .instance_init = i440fx_pcihost_initfn,
>      .class_init    = i440fx_pcihost_class_init,
>  };
>  
[snip]

Regards,
Andreas

-- 
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer; HRB 16746 AG Nürnberg

  reply	other threads:[~2013-01-16 11:17 UTC|newest]

Thread overview: 72+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-12-18 12:41 [Qemu-devel] [RFC PATCH v4 00/30] ACPI memory hotplug Vasilis Liaskovitis
2012-12-18 12:41 ` [Qemu-devel] [RFC PATCH v4 01/30] [SeaBIOS] Add ACPI_EXTRACT_DEVICE* macros Vasilis Liaskovitis
2013-03-20  3:28   ` li guang
2012-12-18 12:41 ` [Qemu-devel] [RFC PATCH v4 02/30] [SeaBIOS] Add SSDT memory device support Vasilis Liaskovitis
2012-12-18 12:41 ` [Qemu-devel] [RFC PATCH v4 03/30] [SeaBIOS] acpi-dsdt: Implement functions for memory hotplug Vasilis Liaskovitis
2012-12-18 12:41 ` [Qemu-devel] [RFC PATCH v4 04/30] [SeaBIOS] acpi: generate hotplug memory devices Vasilis Liaskovitis
2012-12-18 12:41 ` [Qemu-devel] [RFC PATCH v4 05/30] [SeaBIOS] q35: Add memory hotplug handler Vasilis Liaskovitis
2012-12-18 12:41 ` [Qemu-devel] [RFC PATCH v4 06/30] qapi: make visit_type_size fallback to type_int Vasilis Liaskovitis
2013-01-09  0:18   ` Andreas Färber
2013-01-09 16:00     ` mdroth
2012-12-18 12:41 ` [Qemu-devel] [RFC PATCH v4 07/30] Add SIZE type to qdev properties Vasilis Liaskovitis
2013-03-20  6:06   ` li guang
2013-03-20 14:24     ` Eric Blake
2013-03-21  0:39       ` li guang
2012-12-18 12:41 ` [Qemu-devel] [RFC PATCH v4 08/30] qemu-option: export parse_option_number Vasilis Liaskovitis
2012-12-18 12:41 ` [Qemu-devel] [RFC PATCH v4 09/30] Implement dimm device abstraction Vasilis Liaskovitis
2013-03-26  3:51   ` li guang
2012-12-18 12:41 ` [Qemu-devel] [RFC PATCH v4 10/30] vl: handle "-device dimm" Vasilis Liaskovitis
2012-12-18 12:41 ` [Qemu-devel] [RFC PATCH v4 11/30] acpi_piix4 : Implement memory device hotplug registers Vasilis Liaskovitis
2012-12-18 12:41 ` [Qemu-devel] [RFC PATCH v4 12/30] acpi_ich9 " Vasilis Liaskovitis
2012-12-18 12:41 ` [Qemu-devel] [RFC PATCH v4 13/30] piix_pci and pc_piix: refactor Vasilis Liaskovitis
2013-01-16  7:20   ` Hu Tao
2013-01-16  9:36     ` Vasilis Liaskovitis
2013-01-16 11:17       ` Andreas Färber [this message]
2013-01-16 17:10         ` Vasilis Liaskovitis
2012-12-18 12:41 ` [Qemu-devel] [RFC PATCH v4 14/30] piix_pci: Add i440fx dram controller initialization Vasilis Liaskovitis
2012-12-18 12:41 ` [Qemu-devel] [RFC PATCH v4 15/30] q35: " Vasilis Liaskovitis
2012-12-18 12:41 ` [Qemu-devel] [RFC PATCH v4 16/30] pc: Add dimm paravirt SRAT info Vasilis Liaskovitis
2012-12-18 12:41 ` [Qemu-devel] [RFC PATCH v4 17/30] [SeaBIOS] pci: Use paravirt interface for pcimem_start and pcimem64_start Vasilis Liaskovitis
2012-12-18 12:41 ` [Qemu-devel] [RFC PATCH v4 18/30] Introduce paravirt interface QEMU_CFG_PCI_WINDOW Vasilis Liaskovitis
2012-12-18 12:41 ` [Qemu-devel] [RFC PATCH v4 19/30] Implement "info memory-total" and "query-memory-total" Vasilis Liaskovitis
2012-12-19 19:47   ` Blue Swirl
2013-01-04 16:21   ` Eric Blake
2013-01-10 17:42     ` Vasilis Liaskovitis
2012-12-18 12:41 ` [Qemu-devel] [RFC PATCH v4 20/30] balloon: update with hotplugged memory Vasilis Liaskovitis
2012-12-18 12:41 ` [Qemu-devel] [RFC PATCH v4 21/30] Implement dimm-info Vasilis Liaskovitis
2013-01-08 23:20   ` Eric Blake
2013-01-10 17:45     ` Vasilis Liaskovitis
2012-12-18 12:41 ` [Qemu-devel] [RFC PATCH v4 22/30] [SeaBIOS] acpi: add _EJ0 operation and eject port for memory devices Vasilis Liaskovitis
2012-12-18 12:41 ` [Qemu-devel] [RFC PATCH v4 23/30] dimm: add hot-remove capability Vasilis Liaskovitis
2012-12-18 12:41 ` [Qemu-devel] [RFC PATCH v4 24/30] acpi_piix4: " Vasilis Liaskovitis
2012-12-18 12:41 ` [Qemu-devel] [RFC PATCH v4 25/30] acpi_ich9: " Vasilis Liaskovitis
2012-12-19 19:48   ` Blue Swirl
2012-12-18 12:41 ` [Qemu-devel] [RFC PATCH v4 26/30] Implement qmp and hmp commands for notification lists Vasilis Liaskovitis
2013-01-09  0:23   ` Eric Blake
2012-12-18 12:41 ` [Qemu-devel] [RFC PATCH v4 27/30] [SeaBIOS] Add _OST dimm method Vasilis Liaskovitis
2012-12-18 12:41 ` [Qemu-devel] [RFC PATCH v4 28/30] Add _OST dimm support Vasilis Liaskovitis
2012-12-18 12:41 ` [Qemu-devel] [RFC PATCH v4 29/30] [SeaBIOS] Implement _PS3 method for memory device Vasilis Liaskovitis
2012-12-18 12:41 ` [Qemu-devel] [RFC PATCH v4 30/30] Implement _PS3 for dimm Vasilis Liaskovitis
2012-12-18 16:45 ` [Qemu-devel] [RFC PATCH v4 00/30] ACPI memory hotplug Zhi Yong Wu
2012-12-19 11:40   ` Vasilis Liaskovitis
2012-12-19  7:27 ` Gerd Hoffmann
2012-12-19 11:35   ` Vasilis Liaskovitis
2012-12-19 13:56     ` Gerd Hoffmann
2013-01-10 18:57     ` Vasilis Liaskovitis
2013-03-19  6:30       ` li guang
2013-03-26 16:58         ` Vasilis Liaskovitis
2013-03-27  2:42           ` li guang
2013-04-02  9:15       ` liu ping fan
2013-01-09  0:08 ` Andreas Färber
2013-01-10 17:36   ` Vasilis Liaskovitis
2013-01-10 17:55     ` Andreas Färber
2013-03-20  6:18   ` li guang
2013-03-26 14:20     ` Eduardo Habkost
2013-03-27  7:39       ` li guang
     [not found] ` <CAF+CadtnTcOnUt7jp1bARJgioxR5KzLG0QSQuDbiqhiKxiCqFA@mail.gmail.com>
     [not found]   ` <20130228101819.GA4370@dhcp-192-168-178-175.profitbricks.localdomain>
2013-03-19  7:28     ` li guang
2013-03-26 16:43       ` Vasilis Liaskovitis
2013-03-27  2:54         ` li guang
2013-03-28  9:29           ` Vasilis Liaskovitis
2013-03-28  9:49             ` liu ping fan
2013-03-26 14:47 ` Luiz Capitulino
2013-03-26 16:59   ` Vasilis Liaskovitis

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=50F68C31.70006@suse.de \
    --to=afaerber@suse.de \
    --cc=anthony@codemonkey.ws \
    --cc=blauwirbel@gmail.com \
    --cc=gleb@redhat.com \
    --cc=hutao@cn.fujitsu.com \
    --cc=jbaron@redhat.com \
    --cc=kevin@koconnor.net \
    --cc=kraxel@redhat.com \
    --cc=pingfank@linux.vnet.ibm.com \
    --cc=qemu-devel@nongnu.org \
    --cc=seabios@seabios.org \
    --cc=stefanha@gmail.com \
    --cc=vasilis.liaskovitis@profitbricks.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).