All of lore.kernel.org
 help / color / mirror / Atom feed
From: Wei Wang <wei.wang2@amd.com>
To: "qemu-devel@nongnu.org" <qemu-devel@nongnu.org>
Cc: "xen-devel@lists.xensource.com" <xen-devel@lists.xensource.com>
Subject: [Qemu-devel] [PATCH] Add amd iommu emulation for Xen.
Date: Wed, 26 Sep 2012 16:45:55 +0200	[thread overview]
Message-ID: <50631523.3060602@amd.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 88 bytes --]

HI,
Attached patch adds amd iommu emulation for Xen. Please review it.
Thanks,
Wei






[-- Attachment #2: 0001-Add-amd-iommu-emulation-for-Xen.patch --]
[-- Type: text/plain, Size: 8114 bytes --]

From 122517435641384e4f5e36eaad8302ff273648e8 Mon Sep 17 00:00:00 2001
From: Wei Wang <wei.wang2@amd.com>
Date: Wed, 26 Sep 2012 16:43:40 +0200
Subject: [PATCH] Add amd iommu emulation for Xen.

To passthrough amd southern islands series gpu to guest, a virtual iommu device must
be registered on qemu pci bus. It uses a new hypercall xc_domain_update_iommu_msi
to notify xen the msi vector of iommu.

Signed-off-by: Wei Wang <wei.wang2@amd.com>
---
 hw/i386/Makefile.objs |    2 +-
 hw/pc_piix.c          |    6 ++
 hw/xen_iommu.c        |  191 +++++++++++++++++++++++++++++++++++++++++++++++++
 hw/xen_pt.h           |    1 +
 4 files changed, 199 insertions(+), 1 deletions(-)
 create mode 100644 hw/xen_iommu.c

diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs
index 8c764bb..8b231ab 100644
--- a/hw/i386/Makefile.objs
+++ b/hw/i386/Makefile.objs
@@ -8,7 +8,7 @@ obj-y += pc_piix.o
 obj-y += pc_sysfw.o
 obj-$(CONFIG_XEN) += xen_platform.o xen_apic.o
 obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o
-obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_msi.o
+obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_msi.o xen_iommu.o
 obj-y += kvm/
 obj-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
 
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index fd5898f..0b5d034 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -46,6 +46,9 @@
 #ifdef CONFIG_XEN
 #  include <xen/hvm/hvm_info_table.h>
 #endif
+#ifdef CONFIG_XEN_PCI_PASSTHROUGH
+#  include "xen_pt.h"
+#endif
 
 #define MAX_IDE_BUS 2
 
@@ -228,6 +231,9 @@ static void pc_init1(MemoryRegion *system_memory,
     pc_vga_init(isa_bus, pci_enabled ? pci_bus : NULL);
     if (xen_enabled()) {
         pci_create_simple(pci_bus, -1, "xen-platform");
+#ifdef CONFIG_XEN_PCI_PASSTHROUGH
+        xen_pt_iommu_create(pci_bus);
+#endif
     }
 
     /* init basic PC hardware */
diff --git a/hw/xen_iommu.c b/hw/xen_iommu.c
new file mode 100644
index 0000000..9a9ede4
--- /dev/null
+++ b/hw/xen_iommu.c
@@ -0,0 +1,191 @@
+/*
+ * amd iommu support
+ *
+ * Copyright (C) 2012 Advanced Micro Devices, Inc.
+ * Author: Wei Wang <wei.wang2@amd.com> 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "xen_pt.h"
+#include "xen_backend.h"
+
+#pragma pack(1)
+
+typedef struct iommu_capability_block {
+    uint8_t     id;
+    uint8_t     next_ptr;
+    uint8_t     cap_info;
+    uint8_t     flags;
+    uint32_t    base_low;
+    uint32_t    base_high;
+    uint32_t    range;
+    uint32_t    misc;
+} iommu_capability_t;
+
+typedef struct msi_capability_block {
+    uint8_t     id;
+    uint8_t     next_ptr;
+    uint16_t    msg_ctrl;
+    uint32_t    addr_low;
+    uint32_t    addr_high;
+    uint32_t    msi_data;
+} msi_capability_t;
+
+struct amd_iommu_config {
+    uint16_t    vendor_id;
+    uint16_t    device_id;
+    uint16_t    command;
+    uint16_t    status;
+    uint8_t     revision;
+    uint8_t     api;
+    uint8_t     subclass;
+    uint8_t     class;
+    uint8_t     cache_line_size;
+    uint8_t     latency_timer;
+    uint8_t     header_type;
+    uint8_t     bist;
+    uint32_t    base_address_regs[6];
+    uint32_t    reserved1;
+    uint16_t    subsystem_vendor_id;
+    uint16_t    subsystem_id;
+    uint32_t    rom_addr;
+    uint8_t     cap_ptr;
+    uint8_t     reserved3[3];
+    uint32_t    reserved4;
+    uint8_t     interrupt_line;
+    uint8_t     interrupt_pin;
+    uint8_t     min_gnt;
+    uint8_t     max_lat;
+    iommu_capability_t cap;
+    msi_capability_t   msi;
+};
+#pragma pack()
+
+#ifndef PCI_CAP_ID_SEC
+#define PCI_CAP_ID_SEC                  0x0F
+#endif
+#define PCI_CLASS_SYSTEM_AMD_IOMMU      0x0806
+#define PCI_DEVICE_AMD_IOMMU_V2         0xFFFF
+#define IOMMU_CAP_FLAGS_IOTLB           0
+#define IOMMU_CAP_FLAGS_EFRSUP          3
+#define IOMMU_CAP_TYPE                  0x3
+#define IOMMU_CAP_REV                   0x1
+
+#define MSI_DATA_VECTOR_SHIFT          0
+#define MSI_DATA_DELIVERY_SHIFT        8
+#define MSI_DATA_LEVEL_SHIFT           14
+#define MSI_DATA_TRIGGER_SHIFT         15
+#define MSI_ADDR_DESTID_MASK           0xfff0000f
+#define MSI_ADDR_DESTMODE_SHIFT        2
+#define MSI_ADDR_REDIRECTION_SHIFT     3
+#define MSI_TARGET_CPU_SHIFT           12
+#define PCI_STATUS_CAPABILITIES        0x010
+
+static void amd_iommu_pci_write_config(PCIDevice *d, uint32_t address,
+                                       uint32_t val, int len)
+{
+    struct amd_iommu_config *iommu_config;
+    uint64_t msi_addr;
+    uint32_t msi_data;
+    uint8_t offset_msi_data, vector, en;
+    uint8_t dest_mode, dest, delivery_mode, trig_mode;
+
+    pci_default_write_config(d, address, val, len);
+
+    iommu_config = (struct amd_iommu_config *)d->config;
+
+    offset_msi_data = iommu_config->cap.next_ptr + sizeof(uint32_t) +
+                      sizeof(uint64_t);
+
+    if ( address == offset_msi_data )
+    {
+        msi_addr = (uint64_t)iommu_config->msi.addr_high << 32 | 
+                   iommu_config->msi.addr_low;
+        msi_data = val;
+        vector = msi_data & 0xFF;
+        en = iommu_config->msi.msg_ctrl & 0x1;
+        
+        if ( !en )
+            return;
+
+        dest_mode = (msi_addr >> MSI_ADDR_DESTMODE_SHIFT) & 0x1;
+        dest = (msi_addr >> MSI_TARGET_CPU_SHIFT) & 0xff;
+        delivery_mode = (msi_data >> MSI_DATA_DELIVERY_SHIFT) & 0x7;
+        trig_mode = (msi_data >> MSI_DATA_TRIGGER_SHIFT) & 0x1;
+
+        xc_domain_update_iommu_msi(xen_xc, xen_domid, vector, dest, 
+                                   dest_mode, delivery_mode, trig_mode);
+    }
+}
+
+static int amd_iommu_initfn(PCIDevice *d)
+{
+    struct amd_iommu_config *cfg;
+
+    cfg = (struct amd_iommu_config *)d->config;
+
+    cfg->status       =   PCI_STATUS_CAPABILITIES;
+    cfg->cap_ptr      =   sizeof(struct amd_iommu_config) - 
+                          sizeof(iommu_capability_t)- sizeof(msi_capability_t);
+
+    cfg->cap.id       = PCI_CAP_ID_SEC;
+    cfg->cap.cap_info = IOMMU_CAP_REV << 3 | IOMMU_CAP_TYPE;
+
+    cfg->cap.flags   |= 1 << IOMMU_CAP_FLAGS_IOTLB;
+    cfg->cap.flags   |= 1 << IOMMU_CAP_FLAGS_EFRSUP;
+
+    cfg->cap.next_ptr = cfg->cap_ptr + sizeof(iommu_capability_t);
+    cfg->msi.id       = PCI_CAP_ID_MSI;
+    cfg->msi.msg_ctrl = PCI_MSI_FLAGS_64BIT;
+
+    return 0;
+}
+
+static void xen_iommu_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = amd_iommu_initfn;
+    k->vendor_id = PCI_VENDOR_ID_AMD;
+    k->device_id = PCI_DEVICE_AMD_IOMMU_V2;
+    k->class_id = PCI_CLASS_SYSTEM_AMD_IOMMU;
+    k->subsystem_vendor_id = PCI_VENDOR_ID_AMD;
+    k->subsystem_id = PCI_DEVICE_AMD_IOMMU_V2;
+    k->config_write = amd_iommu_pci_write_config;
+};
+
+typedef struct XenIommuState {
+    PCIDevice dev;
+} XenIommuState;
+
+static TypeInfo xen_iommu_info = {
+    .name = "xen-iommu",
+    .parent = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(XenIommuState),
+    .class_init = xen_iommu_class_init,
+};
+
+static void xen_iommu_register_types(void)
+{
+    type_register_static(&xen_iommu_info);
+}
+
+type_init(xen_iommu_register_types)
+
+void xen_pt_iommu_create(PCIBus *pci_bus)
+{
+    char *path;
+    char *iommu;
+    struct xs_handle *xs = xs_open(0);
+            
+    path = xs_get_domain_path(xs, xen_domid);
+    iommu = xenstore_read_str(path, "guest_iommu");
+    
+    if ( !strcmp(iommu, "1") )
+        pci_create_simple(pci_bus, -1, "xen-iommu");
+    
+    free(path);
+    xs_close(xs);
+}
diff --git a/hw/xen_pt.h b/hw/xen_pt.h
index 112477a..b54a0fb 100644
--- a/hw/xen_pt.h
+++ b/hw/xen_pt.h
@@ -291,6 +291,7 @@ void xen_pt_msix_delete(XenPCIPassthroughState *s);
 int xen_pt_msix_update(XenPCIPassthroughState *s);
 int xen_pt_msix_update_remap(XenPCIPassthroughState *s, int bar_index);
 void xen_pt_msix_disable(XenPCIPassthroughState *s);
+void xen_pt_iommu_create(PCIBus *pci_bus);
 
 static inline bool xen_pt_has_msix_mapping(XenPCIPassthroughState *s, int bar)
 {
-- 
1.7.4


WARNING: multiple messages have this Message-ID (diff)
From: Wei Wang <wei.wang2@amd.com>
To: "qemu-devel@nongnu.org" <qemu-devel@nongnu.org>
Cc: "xen-devel@lists.xensource.com" <xen-devel@lists.xensource.com>
Subject: [PATCH] Add amd iommu emulation for Xen.
Date: Wed, 26 Sep 2012 16:45:55 +0200	[thread overview]
Message-ID: <50631523.3060602@amd.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 88 bytes --]

HI,
Attached patch adds amd iommu emulation for Xen. Please review it.
Thanks,
Wei






[-- Attachment #2: 0001-Add-amd-iommu-emulation-for-Xen.patch --]
[-- Type: text/plain, Size: 8114 bytes --]

From 122517435641384e4f5e36eaad8302ff273648e8 Mon Sep 17 00:00:00 2001
From: Wei Wang <wei.wang2@amd.com>
Date: Wed, 26 Sep 2012 16:43:40 +0200
Subject: [PATCH] Add amd iommu emulation for Xen.

To passthrough amd southern islands series gpu to guest, a virtual iommu device must
be registered on qemu pci bus. It uses a new hypercall xc_domain_update_iommu_msi
to notify xen the msi vector of iommu.

Signed-off-by: Wei Wang <wei.wang2@amd.com>
---
 hw/i386/Makefile.objs |    2 +-
 hw/pc_piix.c          |    6 ++
 hw/xen_iommu.c        |  191 +++++++++++++++++++++++++++++++++++++++++++++++++
 hw/xen_pt.h           |    1 +
 4 files changed, 199 insertions(+), 1 deletions(-)
 create mode 100644 hw/xen_iommu.c

diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs
index 8c764bb..8b231ab 100644
--- a/hw/i386/Makefile.objs
+++ b/hw/i386/Makefile.objs
@@ -8,7 +8,7 @@ obj-y += pc_piix.o
 obj-y += pc_sysfw.o
 obj-$(CONFIG_XEN) += xen_platform.o xen_apic.o
 obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o
-obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_msi.o
+obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_msi.o xen_iommu.o
 obj-y += kvm/
 obj-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
 
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index fd5898f..0b5d034 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -46,6 +46,9 @@
 #ifdef CONFIG_XEN
 #  include <xen/hvm/hvm_info_table.h>
 #endif
+#ifdef CONFIG_XEN_PCI_PASSTHROUGH
+#  include "xen_pt.h"
+#endif
 
 #define MAX_IDE_BUS 2
 
@@ -228,6 +231,9 @@ static void pc_init1(MemoryRegion *system_memory,
     pc_vga_init(isa_bus, pci_enabled ? pci_bus : NULL);
     if (xen_enabled()) {
         pci_create_simple(pci_bus, -1, "xen-platform");
+#ifdef CONFIG_XEN_PCI_PASSTHROUGH
+        xen_pt_iommu_create(pci_bus);
+#endif
     }
 
     /* init basic PC hardware */
diff --git a/hw/xen_iommu.c b/hw/xen_iommu.c
new file mode 100644
index 0000000..9a9ede4
--- /dev/null
+++ b/hw/xen_iommu.c
@@ -0,0 +1,191 @@
+/*
+ * amd iommu support
+ *
+ * Copyright (C) 2012 Advanced Micro Devices, Inc.
+ * Author: Wei Wang <wei.wang2@amd.com> 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "xen_pt.h"
+#include "xen_backend.h"
+
+#pragma pack(1)
+
+typedef struct iommu_capability_block {
+    uint8_t     id;
+    uint8_t     next_ptr;
+    uint8_t     cap_info;
+    uint8_t     flags;
+    uint32_t    base_low;
+    uint32_t    base_high;
+    uint32_t    range;
+    uint32_t    misc;
+} iommu_capability_t;
+
+typedef struct msi_capability_block {
+    uint8_t     id;
+    uint8_t     next_ptr;
+    uint16_t    msg_ctrl;
+    uint32_t    addr_low;
+    uint32_t    addr_high;
+    uint32_t    msi_data;
+} msi_capability_t;
+
+struct amd_iommu_config {
+    uint16_t    vendor_id;
+    uint16_t    device_id;
+    uint16_t    command;
+    uint16_t    status;
+    uint8_t     revision;
+    uint8_t     api;
+    uint8_t     subclass;
+    uint8_t     class;
+    uint8_t     cache_line_size;
+    uint8_t     latency_timer;
+    uint8_t     header_type;
+    uint8_t     bist;
+    uint32_t    base_address_regs[6];
+    uint32_t    reserved1;
+    uint16_t    subsystem_vendor_id;
+    uint16_t    subsystem_id;
+    uint32_t    rom_addr;
+    uint8_t     cap_ptr;
+    uint8_t     reserved3[3];
+    uint32_t    reserved4;
+    uint8_t     interrupt_line;
+    uint8_t     interrupt_pin;
+    uint8_t     min_gnt;
+    uint8_t     max_lat;
+    iommu_capability_t cap;
+    msi_capability_t   msi;
+};
+#pragma pack()
+
+#ifndef PCI_CAP_ID_SEC
+#define PCI_CAP_ID_SEC                  0x0F
+#endif
+#define PCI_CLASS_SYSTEM_AMD_IOMMU      0x0806
+#define PCI_DEVICE_AMD_IOMMU_V2         0xFFFF
+#define IOMMU_CAP_FLAGS_IOTLB           0
+#define IOMMU_CAP_FLAGS_EFRSUP          3
+#define IOMMU_CAP_TYPE                  0x3
+#define IOMMU_CAP_REV                   0x1
+
+#define MSI_DATA_VECTOR_SHIFT          0
+#define MSI_DATA_DELIVERY_SHIFT        8
+#define MSI_DATA_LEVEL_SHIFT           14
+#define MSI_DATA_TRIGGER_SHIFT         15
+#define MSI_ADDR_DESTID_MASK           0xfff0000f
+#define MSI_ADDR_DESTMODE_SHIFT        2
+#define MSI_ADDR_REDIRECTION_SHIFT     3
+#define MSI_TARGET_CPU_SHIFT           12
+#define PCI_STATUS_CAPABILITIES        0x010
+
+static void amd_iommu_pci_write_config(PCIDevice *d, uint32_t address,
+                                       uint32_t val, int len)
+{
+    struct amd_iommu_config *iommu_config;
+    uint64_t msi_addr;
+    uint32_t msi_data;
+    uint8_t offset_msi_data, vector, en;
+    uint8_t dest_mode, dest, delivery_mode, trig_mode;
+
+    pci_default_write_config(d, address, val, len);
+
+    iommu_config = (struct amd_iommu_config *)d->config;
+
+    offset_msi_data = iommu_config->cap.next_ptr + sizeof(uint32_t) +
+                      sizeof(uint64_t);
+
+    if ( address == offset_msi_data )
+    {
+        msi_addr = (uint64_t)iommu_config->msi.addr_high << 32 | 
+                   iommu_config->msi.addr_low;
+        msi_data = val;
+        vector = msi_data & 0xFF;
+        en = iommu_config->msi.msg_ctrl & 0x1;
+        
+        if ( !en )
+            return;
+
+        dest_mode = (msi_addr >> MSI_ADDR_DESTMODE_SHIFT) & 0x1;
+        dest = (msi_addr >> MSI_TARGET_CPU_SHIFT) & 0xff;
+        delivery_mode = (msi_data >> MSI_DATA_DELIVERY_SHIFT) & 0x7;
+        trig_mode = (msi_data >> MSI_DATA_TRIGGER_SHIFT) & 0x1;
+
+        xc_domain_update_iommu_msi(xen_xc, xen_domid, vector, dest, 
+                                   dest_mode, delivery_mode, trig_mode);
+    }
+}
+
+static int amd_iommu_initfn(PCIDevice *d)
+{
+    struct amd_iommu_config *cfg;
+
+    cfg = (struct amd_iommu_config *)d->config;
+
+    cfg->status       =   PCI_STATUS_CAPABILITIES;
+    cfg->cap_ptr      =   sizeof(struct amd_iommu_config) - 
+                          sizeof(iommu_capability_t)- sizeof(msi_capability_t);
+
+    cfg->cap.id       = PCI_CAP_ID_SEC;
+    cfg->cap.cap_info = IOMMU_CAP_REV << 3 | IOMMU_CAP_TYPE;
+
+    cfg->cap.flags   |= 1 << IOMMU_CAP_FLAGS_IOTLB;
+    cfg->cap.flags   |= 1 << IOMMU_CAP_FLAGS_EFRSUP;
+
+    cfg->cap.next_ptr = cfg->cap_ptr + sizeof(iommu_capability_t);
+    cfg->msi.id       = PCI_CAP_ID_MSI;
+    cfg->msi.msg_ctrl = PCI_MSI_FLAGS_64BIT;
+
+    return 0;
+}
+
+static void xen_iommu_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = amd_iommu_initfn;
+    k->vendor_id = PCI_VENDOR_ID_AMD;
+    k->device_id = PCI_DEVICE_AMD_IOMMU_V2;
+    k->class_id = PCI_CLASS_SYSTEM_AMD_IOMMU;
+    k->subsystem_vendor_id = PCI_VENDOR_ID_AMD;
+    k->subsystem_id = PCI_DEVICE_AMD_IOMMU_V2;
+    k->config_write = amd_iommu_pci_write_config;
+};
+
+typedef struct XenIommuState {
+    PCIDevice dev;
+} XenIommuState;
+
+static TypeInfo xen_iommu_info = {
+    .name = "xen-iommu",
+    .parent = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(XenIommuState),
+    .class_init = xen_iommu_class_init,
+};
+
+static void xen_iommu_register_types(void)
+{
+    type_register_static(&xen_iommu_info);
+}
+
+type_init(xen_iommu_register_types)
+
+void xen_pt_iommu_create(PCIBus *pci_bus)
+{
+    char *path;
+    char *iommu;
+    struct xs_handle *xs = xs_open(0);
+            
+    path = xs_get_domain_path(xs, xen_domid);
+    iommu = xenstore_read_str(path, "guest_iommu");
+    
+    if ( !strcmp(iommu, "1") )
+        pci_create_simple(pci_bus, -1, "xen-iommu");
+    
+    free(path);
+    xs_close(xs);
+}
diff --git a/hw/xen_pt.h b/hw/xen_pt.h
index 112477a..b54a0fb 100644
--- a/hw/xen_pt.h
+++ b/hw/xen_pt.h
@@ -291,6 +291,7 @@ void xen_pt_msix_delete(XenPCIPassthroughState *s);
 int xen_pt_msix_update(XenPCIPassthroughState *s);
 int xen_pt_msix_update_remap(XenPCIPassthroughState *s, int bar_index);
 void xen_pt_msix_disable(XenPCIPassthroughState *s);
+void xen_pt_iommu_create(PCIBus *pci_bus);
 
 static inline bool xen_pt_has_msix_mapping(XenPCIPassthroughState *s, int bar)
 {
-- 
1.7.4


             reply	other threads:[~2012-09-26 14:44 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-09-26 14:45 Wei Wang [this message]
2012-09-26 14:45 ` [PATCH] Add amd iommu emulation for Xen Wei Wang

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=50631523.3060602@amd.com \
    --to=wei.wang2@amd.com \
    --cc=qemu-devel@nongnu.org \
    --cc=xen-devel@lists.xensource.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 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.