All of lore.kernel.org
 help / color / mirror / Atom feed
From: Yi Sun <yi.y.sun@linux.intel.com>
To: xen-devel@lists.xenproject.org
Cc: kevin.tian@intel.com, wei.liu2@citrix.com,
	andrew.cooper3@citrix.com, dario.faggioli@citrix.com,
	he.chen@linux.intel.com, ian.jackson@eu.citrix.com,
	Yi Sun <yi.y.sun@linux.intel.com>,
	mengxu@cis.upenn.edu, jbeulich@suse.com,
	chao.p.peng@linux.intel.com, roger.pau@citrix.com
Subject: [PATCH v9 05/25] x86: refactor psr: L3 CAT: implement CPU init and free flow.
Date: Thu, 16 Mar 2017 19:07:55 +0800	[thread overview]
Message-ID: <1489662495-5375-6-git-send-email-yi.y.sun@linux.intel.com> (raw)
In-Reply-To: <1489662495-5375-1-git-send-email-yi.y.sun@linux.intel.com>

This patch implements the CPU init and free flow including L3 CAT
initialization and feature array free. It includes below flows:
1. presmp init:
    - parse command line parameter.
    - allocate socket info for every socket.
    - allocate feature resource.
    - initialize socket info, get feature info and add feature into feature
      array per cpuid result.
    - free resources allocated if error happens.
    - register cpu notifier to handle cpu events.
2. cpu notifier:
    - handle cpu online events, if initialization work has been done before,
      do nothing.
    - handle cpu offline events, if it is the last cpu offline, free feature
      resources.

Signed-off-by: Yi Sun <yi.y.sun@linux.intel.com>
---
v9:
    - add commit message to explain the flows.
    - handle cpu offline and online again case to read MSRs registers values
      back and save them into cos array to make user can get real data.
    - create a new patch about moving 'cpuid_count_leaf'.
      (suggested by Wei Liu)
    - modify comment to explain why not free some resource in 'free_feature'.
      (suggested by Wei Liu)
    - implement 'psr_alloc_feat_enabled' to check if allocation feature is
      enabled in cmdline and some initialization work done.
      (suggested by Wei Liu)
    - implement 'cat_default_val' to set default value for CAT features.
      (suggested by Wei Liu)
    - replace feature list handling to feature array handling.
      (suggested by Roger Pau)
    - implement a common 'cat_init_feature' to replace L3 CAT/L2 CAT specific
      init functions.
      (suggested by Roger Pau)
    - modify comments for global feature node.
      (suggested by Jan Beulich)
    - remove unnecessary comments.
      (suggested by Jan Beulich)
    - remove unnecessary 'else'.
      (suggested by Jan Beulich)
    - remove 'nr_feat'.
      (suggested by Jan Beulich)
    - modify patch title to indicate 'L3 CAT'.
      (suggested by Jan Beulich)
    - check global flag with boot cpu operations.
      (suggested by Jan Beulich)
    - remove 'cpu_init_work' and move codes into 'psr_cpu_init'.
      (suggested by Jan Beulich)
    - remove 'cpu_fini_work' and move codes into 'psr_cpu_fini'.
      (suggested by Jan Beulich)
    - assign value for 'cos_num'.
      (suggested by Jan Beulich)
    - change about 'uint64_t' to 'uint32_t'.
      (suggested by Jan Beulich)
v8:
    - fix format issue.
      (suggested by Konrad Rzeszutek Wilk)
    - add comments to explain why we care about cpumask_empty when the last
      cpu on socket is offline.
      (suggested by Konrad Rzeszutek Wilk)
v7:
    - initialize structure objects for avoiding surprise.
      (suggested by Konrad Rzeszutek Wilk)
    - fix typo.
      (suggested by Konrad Rzeszutek Wilk)
    - fix a logical mistake when handling the last cpu offline event.
      (suggested by Konrad Rzeszutek Wilk)
v6:
    - use 'struct cpuid_leaf' introduced in Andrew's patch.
      (suggested by Konrad Rzeszutek Wilk)
    - add comments about cpu_add_remove_lock.
      (suggested by Konrad Rzeszutek Wilk)
    - change 'clear_bit' to '__clear_bit'.
      (suggested by Konrad Rzeszutek Wilk)
    - add 'ASSERT' check when setting 'feat_mask'.
      (suggested by Konrad Rzeszutek Wilk)
    - adjust 'printk' position to avoid odd spacing.
      (suggested by Konrad Rzeszutek Wilk)
    - add comment to explain usage of 'feat_l3_cat'.
      (suggested by Konrad Rzeszutek Wilk)
    - fix wording.
      (suggested by Konrad Rzeszutek Wilk)
    - move 'cpuid_count_leaf' helper function to 'asm-x86/processor.h'.
      It cannot be moved to 'cpuid.h' which causes compilation error because
      of header file loop reference.
      (suggested by Andrew Cooper)
v5:
    - add comment to explain the reason to define 'feat_l3_cat'.
      (suggested by Jan Beulich)
    - use 'list_for_each_entry_safe'.
      (suggested by Jan Beulich)
    - remove codes to free 'feat_l3_cat' in 'free_feature' to avoid the need
      for an allocation the next time a CPU comes online.
      (suggested by Jan Beulich)
    - define 'struct cpuid_leaf_regs' to encapsulate eax~edx.
      (suggested by Jan Beulich)
    - print feature info on a socket only when 'opt_cpu_info' is true.
      (suggested by Jan Beulich)
    - declare global variable 'l3_cat_ops' to 'static const'.
      (suggested by Jan Beulich)
    - use 'current_cpu_data'.
      (suggested by Jan Beulich)
    - rename 'feat_tmp' to 'feat'.
      (suggested by Jan Beulich)
    - clear PQE feature bit when the maximum CPUID level is too low.
      (suggested by Jan Beulich)
    - directly call 'l3_cat_init_feature'. No need to make it a callback
      function.
      (suggested by Jan Beulich)
    - remove local variable 'info'.
      (suggested by Jan Beulich)
    - move 'INIT_LIST_HEAD' into 'cpu_init_work' to be together with
      spin_lock_init().
      (suggested by Jan Beulich)
    - remove 'cpu_prepare_work' and move its content into 'psr_cpu_prepare'.
      (suggested by Jan Beulich)
v4:
    - create this patch because of removing all CAT/CDP old codes to make
      implementation be more easily understood.
      (suggested by Jan Beulich)
---
 xen/arch/x86/psr.c | 202 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 197 insertions(+), 5 deletions(-)

diff --git a/xen/arch/x86/psr.c b/xen/arch/x86/psr.c
index 822f1c0..66a9ce8 100644
--- a/xen/arch/x86/psr.c
+++ b/xen/arch/x86/psr.c
@@ -18,6 +18,7 @@
 #include <xen/init.h>
 #include <xen/sched.h>
 #include <asm/psr.h>
+#include <asm/x86_emulate.h>
 
 /*
  * Terminology:
@@ -34,6 +35,9 @@
 #define PSR_CAT        (1<<1)
 #define PSR_CDP        (1<<2)
 
+#define CAT_CBM_LEN_MASK 0x1f
+#define CAT_COS_MAX_MASK 0xffff
+
 /*
  * Per SDM chapter 'Cache Allocation Technology: Cache Mask Configuration',
  * the MSRs ranging from 0C90H through 0D0FH (inclusive), enables support for
@@ -46,6 +50,9 @@
  */
 #define MAX_COS_REG_CNT  128
 
+/* CAT features use 1 COS register in one access. */
+#define CAT_COS_NUM      1
+
 enum psr_feat_type {
     PSR_SOCKET_L3_CAT = 0,
     PSR_SOCKET_L3_CDP,
@@ -126,11 +133,110 @@ struct psr_assoc {
 
 struct psr_cmt *__read_mostly psr_cmt;
 
+static struct psr_socket_info *__read_mostly socket_info;
+
 static unsigned int opt_psr;
 static unsigned int __initdata opt_rmid_max = 255;
+static unsigned int __read_mostly opt_cos_max = MAX_COS_REG_CNT;
 static uint64_t rmid_mask;
 static DEFINE_PER_CPU(struct psr_assoc, psr_assoc);
 
+/*
+ * Declare global feature node for every feature to facilitate the feature
+ * array creation. It is used to transiently store a spare node.
+ */
+static struct feat_node *feat_l3_cat;
+
+/* Common functions */
+#define cat_default_val(len)                 \
+            ( (uint32_t)((1ul << len) - 1) )
+
+/*
+ * Use this function to check if any allocation feature has been enabled
+ * in cmdline.
+ */
+static bool psr_alloc_feat_enabled(void)
+{
+    return ((!socket_info) ? false : true );
+}
+
+static void free_feature(struct psr_socket_info *info)
+{
+    unsigned int i;
+
+    if ( !info )
+        return;
+
+    /*
+     * Free resources of features. The global feature object, e.g. feat_l3_cat,
+     * may not be freed here if it is not added into array. It is simply being
+     * kept until the next CPU online attempt.
+     */
+    for ( i = 0; i < PSR_SOCKET_MAX_FEAT; i++ )
+    {
+        if ( !info->features[i] )
+            continue;
+
+        xfree(info->features[i]);
+        info->features[i] = NULL;
+        __clear_bit(i, &info->feat_mask);
+    }
+}
+
+/* CAT common functions implementation. */
+static void cat_init_feature(struct cpuid_leaf regs,
+                             struct feat_node *feat,
+                             struct psr_socket_info *info,
+                             enum psr_feat_type type)
+{
+    unsigned int socket, i;
+    struct psr_cat_hw_info cat = { };
+    uint64_t val;
+
+    /* No valid value so do not enable feature. */
+    if ( !regs.a || !regs.d )
+        return;
+
+    cat.cbm_len = (regs.a & CAT_CBM_LEN_MASK) + 1;
+    cat.cos_max = min(opt_cos_max, regs.d & CAT_COS_MAX_MASK);
+
+    /* cos=0 is reserved as default cbm(all bits within cbm_len are 1). */
+    feat->cos_reg_val[0] = cat_default_val(cat.cbm_len);
+    /*
+     * To handle cpu offline and then online case, we need read MSRs back to
+     * save values into cos_reg_val array.
+     */
+    for ( i = 1; i <= cat.cos_max; i++ )
+    {
+        rdmsrl(MSR_IA32_PSR_L3_MASK(i), val);
+        feat->cos_reg_val[i] = (uint32_t)val;
+    }
+
+    feat->info.cat_info = cat;
+    feat->cos_num = CAT_COS_NUM;
+
+    /* Add this feature into array. */
+    info->features[type] = feat;
+
+    ASSERT(!test_bit(type, &info->feat_mask));
+    __set_bit(type, &info->feat_mask);
+
+    socket = cpu_to_socket(smp_processor_id());
+    if ( !opt_cpu_info )
+        return;
+
+    printk(XENLOG_INFO "%s CAT: enabled on socket %u, cos_max:%u, cbm_len:%u\n",
+           ((type == PSR_SOCKET_L3_CAT) ? "L3" : "L2"),
+           socket, feat->info.cat_info.cos_max,
+           feat->info.cat_info.cbm_len);
+
+    return;
+}
+
+/* L3 CAT ops */
+static const struct feat_ops l3_cat_ops = {
+};
+
 static void __init parse_psr_bool(char *s, char *value, char *feature,
                                   unsigned int mask)
 {
@@ -170,6 +276,9 @@ static void __init parse_psr_param(char *s)
         if ( val_str && !strcmp(s, "rmid_max") )
             opt_rmid_max = simple_strtoul(val_str, NULL, 0);
 
+        if ( val_str && !strcmp(s, "cos_max") )
+            opt_cos_max = simple_strtoul(val_str, NULL, 0);
+
         s = ss + 1;
     } while ( ss );
 }
@@ -325,19 +434,98 @@ void psr_domain_free(struct domain *d)
     psr_free_rmid(d);
 }
 
-static int psr_cpu_prepare(unsigned int cpu)
+static void __init init_psr(void)
 {
+    if ( opt_cos_max < 1 )
+    {
+        printk(XENLOG_INFO "CAT: disabled, cos_max is too small\n");
+        return;
+    }
+
+    socket_info = xzalloc_array(struct psr_socket_info, nr_sockets);
+
+    if ( !socket_info )
+    {
+        printk(XENLOG_INFO "Failed to alloc socket_info!\n");
+        return;
+    }
+}
+
+static void __init psr_free(void)
+{
+    xfree(socket_info);
+    socket_info = NULL;
+}
+
+static int psr_cpu_prepare(void)
+{
+    if ( !psr_alloc_feat_enabled() )
+        return 0;
+
+    /* Malloc memory for the global feature head here. */
+    if ( feat_l3_cat == NULL &&
+         (feat_l3_cat = xzalloc(struct feat_node)) == NULL )
+        return -ENOMEM;
+
     return 0;
 }
 
 static void psr_cpu_init(void)
 {
+    struct psr_socket_info *info;
+    unsigned int socket, i;
+    unsigned int cpu = smp_processor_id();
+    struct feat_node *feat;
+    struct cpuid_leaf regs;
+
+    if ( !psr_alloc_feat_enabled() || !boot_cpu_has(X86_FEATURE_PQE) )
+        goto assoc_init;
+
+    if ( boot_cpu_data.cpuid_level < PSR_CPUID_LEVEL_CAT )
+    {
+        setup_clear_cpu_cap(X86_FEATURE_PQE);
+        goto assoc_init;
+    }
+
+    socket = cpu_to_socket(cpu);
+    info = socket_info + socket;
+    if ( info->feat_mask )
+        goto assoc_init;
+
+    for ( i = 0; i < PSR_SOCKET_MAX_FEAT; i++ )
+        info->features[i] = NULL;
+
+    spin_lock_init(&info->ref_lock);
+
+    cpuid_count_leaf(PSR_CPUID_LEVEL_CAT, 0, &regs);
+    if ( regs.b & PSR_RESOURCE_TYPE_L3 )
+    {
+        cpuid_count_leaf(PSR_CPUID_LEVEL_CAT, 1, &regs);
+
+        feat = feat_l3_cat;
+        feat_l3_cat = NULL;
+        feat->ops = l3_cat_ops;
+
+        cat_init_feature(regs, feat, info, PSR_SOCKET_L3_CAT);
+    }
+
+assoc_init:
     psr_assoc_init();
 }
 
 static void psr_cpu_fini(unsigned int cpu)
 {
-    return;
+    unsigned int socket = cpu_to_socket(cpu);
+
+    if ( !psr_alloc_feat_enabled() )
+        return;
+
+    /*
+     * We only free when we are the last CPU in the socket. The socket_cpumask
+     * is cleared prior to this notification code by remove_siblinginfo().
+     */
+    if ( socket_cpumask[socket] && cpumask_empty(socket_cpumask[socket]) )
+        free_feature(socket_info + socket);
 }
 
 static int cpu_callback(
@@ -349,7 +537,7 @@ static int cpu_callback(
     switch ( action )
     {
     case CPU_UP_PREPARE:
-        rc = psr_cpu_prepare(cpu);
+        rc = psr_cpu_prepare();
         break;
     case CPU_STARTING:
         psr_cpu_init();
@@ -378,10 +566,14 @@ static int __init psr_presmp_init(void)
     if ( (opt_psr & PSR_CMT) && opt_rmid_max )
         init_psr_cmt(opt_rmid_max);
 
-    psr_cpu_prepare(0);
+    if ( opt_psr & PSR_CAT )
+        init_psr();
+
+    if ( psr_cpu_prepare() )
+        psr_free();
 
     psr_cpu_init();
-    if ( psr_cmt_enabled() )
+    if ( psr_cmt_enabled() || psr_alloc_feat_enabled() )
         register_cpu_notifier(&cpu_nfb);
 
     return 0;
-- 
1.9.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

  parent reply	other threads:[~2017-03-16 11:13 UTC|newest]

Thread overview: 105+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-03-16 11:07 [PATCH v9 00/25] Enable L2 Cache Allocation Technology & Refactor psr.c Yi Sun
2017-03-16 11:07 ` [PATCH v9 01/25] docs: create Cache Allocation Technology (CAT) and Code and Data Prioritization (CDP) feature document Yi Sun
2017-03-16 11:07 ` [PATCH v9 02/25] x86: refactor psr: remove L3 CAT/CDP codes Yi Sun
2017-03-16 11:07 ` [PATCH v9 03/25] x86: refactor psr: implement main data structures Yi Sun
2017-03-24 16:19   ` Jan Beulich
2017-03-27  2:38     ` Yi Sun
2017-03-27  6:20       ` Jan Beulich
2017-03-27  7:12         ` Yi Sun
2017-03-27  7:37           ` Jan Beulich
2017-03-16 11:07 ` [PATCH v9 04/25] x86: move cpuid_count_leaf from cpuid.c to processor.h Yi Sun
2017-03-24 16:22   ` Jan Beulich
2017-03-16 11:07 ` Yi Sun [this message]
2017-03-24 16:52   ` [PATCH v9 05/25] x86: refactor psr: L3 CAT: implement CPU init and free flow Jan Beulich
2017-03-27  4:41     ` Yi Sun
2017-03-27  6:34       ` Jan Beulich
2017-03-27  8:16         ` Yi Sun
2017-03-27  8:43           ` Jan Beulich
2017-03-16 11:07 ` [PATCH v9 06/25] x86: refactor psr: L3 CAT: implement Domain init/free and schedule flows Yi Sun
2017-03-16 11:07 ` [PATCH v9 07/25] x86: refactor psr: L3 CAT: implement get hw info flow Yi Sun
2017-03-27  9:07   ` Jan Beulich
2017-03-27 12:24     ` Yi Sun
2017-03-27 12:51       ` Jan Beulich
2017-03-27 13:19         ` Yi Sun
2017-03-27 13:32           ` Jan Beulich
2017-03-16 11:07 ` [PATCH v9 08/25] x86: refactor psr: L3 CAT: implement get value flow Yi Sun
2017-03-27  9:23   ` Jan Beulich
2017-03-27 12:59     ` Yi Sun
2017-03-27 13:34       ` Jan Beulich
2017-03-28  2:13         ` Yi Sun
2017-03-28  8:10           ` Jan Beulich
2017-03-16 11:07 ` [PATCH v9 09/25] x86: refactor psr: L3 CAT: set value: implement framework Yi Sun
2017-03-27  9:59   ` Jan Beulich
2017-03-28  1:21     ` Yi Sun
2017-03-28  8:21       ` Jan Beulich
2017-03-16 11:08 ` [PATCH v9 10/25] x86: refactor psr: L3 CAT: set value: assemble features value array Yi Sun
2017-03-27 10:17   ` Jan Beulich
2017-03-28  3:12     ` Yi Sun
2017-03-28  8:05       ` Yi Sun
2017-03-28  8:36         ` Jan Beulich
2017-03-28  9:11           ` Yi Sun
2017-03-28  9:20             ` Jan Beulich
2017-03-28 10:18               ` Yi Sun
2017-03-28 10:39                 ` Jan Beulich
2017-03-28  8:34       ` Jan Beulich
2017-03-28 10:12         ` Yi Sun
2017-03-28 10:36           ` Jan Beulich
2017-03-16 11:08 ` [PATCH v9 11/25] x86: refactor psr: L3 CAT: set value: implement cos finding flow Yi Sun
2017-03-27 10:28   ` Jan Beulich
2017-03-28  3:26     ` Yi Sun
2017-03-28  8:41       ` Jan Beulich
2017-03-16 11:08 ` [PATCH v9 12/25] x86: refactor psr: L3 CAT: set value: implement cos id picking flow Yi Sun
2017-03-27 10:37   ` Jan Beulich
2017-03-28  4:58     ` Yi Sun
2017-03-28  8:45       ` Jan Beulich
2017-03-28 10:31         ` Yi Sun
2017-03-28 10:40           ` Jan Beulich
2017-03-28 11:59             ` Yi Sun
2017-03-28 12:20               ` Jan Beulich
2017-03-29  1:20                 ` Yi Sun
2017-03-29  1:36                   ` Yi Sun
2017-03-29  9:57                     ` Jan Beulich
2017-03-30  1:37                       ` Yi Sun
2017-03-30  1:39                         ` Yi Sun
2017-03-30 11:55                         ` Jan Beulich
2017-03-30 12:10                           ` Yi Sun
2017-03-31  8:47                             ` Jan Beulich
2017-03-31  9:12                               ` Yi Sun
2017-03-31  9:18                                 ` Yi Sun
2017-03-31 10:19                                 ` Jan Beulich
2017-03-31 12:40                                   ` Yi Sun
2017-03-31 12:51                                     ` Jan Beulich
2017-03-31 13:22                                       ` Yi Sun
2017-03-31 14:35                                         ` Jan Beulich
2017-03-31 14:46                                           ` Yi Sun
2017-03-16 11:08 ` [PATCH v9 13/25] x86: refactor psr: L3 CAT: set value: implement write msr flow Yi Sun
2017-03-27 10:46   ` Jan Beulich
2017-03-28  5:06     ` Yi Sun
2017-03-28  8:48       ` Jan Beulich
2017-03-28 10:20         ` Yi Sun
2017-03-16 11:08 ` [PATCH v9 14/25] x86: refactor psr: CDP: implement CPU init and free flow Yi Sun
2017-03-27 13:58   ` Jan Beulich
2017-03-16 11:08 ` [PATCH v9 15/25] x86: refactor psr: CDP: implement get hw info flow Yi Sun
2017-03-27 14:08   ` Jan Beulich
2017-03-28  5:13     ` Yi Sun
2017-03-16 11:08 ` [PATCH v9 16/25] x86: refactor psr: CDP: implement get value flow Yi Sun
2017-03-16 11:08 ` [PATCH v9 17/25] x86: refactor psr: CDP: implement set value callback functions Yi Sun
2017-03-27 14:17   ` Jan Beulich
2017-03-28  5:14     ` Yi Sun
2017-03-16 11:08 ` [PATCH v9 18/25] x86: L2 CAT: implement CPU init and free flow Yi Sun
2017-03-16 11:08 ` [PATCH v9 19/25] x86: L2 CAT: implement get hw info flow Yi Sun
2017-03-27 14:38   ` Jan Beulich
2017-03-28  5:16     ` Yi Sun
2017-03-16 11:08 ` [PATCH v9 20/25] x86: L2 CAT: implement get value flow Yi Sun
2017-03-27 14:39   ` Jan Beulich
2017-03-16 11:08 ` [PATCH v9 21/25] x86: L2 CAT: implement set " Yi Sun
2017-03-27 14:40   ` Jan Beulich
2017-03-16 11:08 ` [PATCH v9 22/25] tools: L2 CAT: support get HW info for L2 CAT Yi Sun
2017-03-16 11:08 ` [PATCH v9 23/25] tools: L2 CAT: support show cbm " Yi Sun
2017-03-16 11:08 ` [PATCH v9 24/25] tools: L2 CAT: support set " Yi Sun
2017-03-28 14:04   ` Wei Liu
2017-03-29  1:21     ` Yi Sun
2017-03-16 11:08 ` [PATCH v9 25/25] docs: add L2 CAT description in docs Yi Sun
2017-03-16 11:20 ` [PATCH v9 00/25] Enable L2 Cache Allocation Technology & Refactor psr.c Jan Beulich
2017-03-17  1:29   ` Yi Sun
2017-03-17  7:25     ` Jan Beulich

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=1489662495-5375-6-git-send-email-yi.y.sun@linux.intel.com \
    --to=yi.y.sun@linux.intel.com \
    --cc=andrew.cooper3@citrix.com \
    --cc=chao.p.peng@linux.intel.com \
    --cc=dario.faggioli@citrix.com \
    --cc=he.chen@linux.intel.com \
    --cc=ian.jackson@eu.citrix.com \
    --cc=jbeulich@suse.com \
    --cc=kevin.tian@intel.com \
    --cc=mengxu@cis.upenn.edu \
    --cc=roger.pau@citrix.com \
    --cc=wei.liu2@citrix.com \
    --cc=xen-devel@lists.xenproject.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 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.