From: Serge Semin <Sergey.Semin@baikalelectronics.ru> To: Michal Simek <michal.simek@xilinx.com>, Borislav Petkov <bp@alien8.de>, Mauro Carvalho Chehab <mchehab@kernel.org>, Tony Luck <tony.luck@intel.com>, James Morse <james.morse@arm.com>, Robert Richter <rric@kernel.org> Cc: Serge Semin <Sergey.Semin@baikalelectronics.ru>, Serge Semin <fancer.lancer@gmail.com>, Alexey Malahov <Alexey.Malahov@baikalelectronics.ru>, Michail Ivanov <Michail.Ivanov@baikalelectronics.ru>, Pavel Parkhomenko <Pavel.Parkhomenko@baikalelectronics.ru>, Punnaiah Choudary Kalluri <punnaiah.choudary.kalluri@xilinx.com>, Manish Narani <manish.narani@xilinx.com>, Dinh Nguyen <dinguyen@kernel.org>, Rob Herring <robh+dt@kernel.org>, Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>, Rob Herring <robh@kernel.org>, Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>, <devicetree@vger.kernel.org>, <linux-arm-kernel@lists.infradead.org>, <linux-edac@vger.kernel.org>, <linux-kernel@vger.kernel.org> Subject: [PATCH RESEND v3 13/17] EDAC/mc: Add MC unique index allocation procedure Date: Fri, 30 Sep 2022 02:27:08 +0300 [thread overview] Message-ID: <20220929232712.12202-14-Sergey.Semin@baikalelectronics.ru> (raw) In-Reply-To: <20220929232712.12202-1-Sergey.Semin@baikalelectronics.ru> In case of the unique index allocation it's not that optimal to always rely on the low-level device drivers (platform drivers), because they get to start to implement either the same design pattern (for instance global static MC counter) or may end-up with having non-unique index eventually at runtime. Needless to say that having a generic unique index allocation/tracking procedure will make code more readable and safer. The suggested implementation is based on the kernel IDA infrastructure exposed by the lib/idr.c driver with API described in linux/idr.h header file. It's used to create an ID resource descriptor "mc_idr", which then is utilized either to track the custom MC idx specified by EDAC LLDDs or to allocate the next-free MC idx. A new special MC index is introduced here. It's defined by the EDAC_AUTO_MC_NUM macro with a value specifically chosen as the least probable value used for the real MC index. In case if the EDAC_AUTO_MC_NUM index is specified by the EDAC LLDD, the MC index will be either retrieved from the MC device OF-node alias index ("mc[:number:]") or automatically generated as the next-free MC index found by the ID allocation procedure. Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru> --- Note the approach implemented here has been partly ported from the SPI core driver using IDA to track/allocate SPI bus numbers. Link: https://elixir.bootlin.com/linux/latest/source/drivers/spi/spi.c#L2957 --- drivers/edac/edac_mc.c | 89 +++++++++++++++++++++++++++++++++++++++--- drivers/edac/edac_mc.h | 4 ++ 2 files changed, 87 insertions(+), 6 deletions(-) diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 24814839d885..634c41ea7804 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -29,6 +29,9 @@ #include <linux/edac.h> #include <linux/bitops.h> #include <linux/uaccess.h> +#include <linux/idr.h> +#include <linux/of.h> + #include <asm/page.h> #include "edac_mc.h" #include "edac_module.h" @@ -46,6 +49,7 @@ EXPORT_SYMBOL_GPL(edac_op_state); /* lock to memory controller's control array */ static DEFINE_MUTEX(mem_ctls_mutex); static LIST_HEAD(mc_devices); +static DEFINE_IDR(mc_idr); /* * Used to lock EDAC MC to just one module, avoiding two drivers e. g. @@ -493,7 +497,64 @@ void edac_mc_reset_delay_period(unsigned long value) mutex_unlock(&mem_ctls_mutex); } +/** + * edac_mc_alloc_id() - Allocate unique Memory Controller identifier + * + * @mci: pointer to the mci structure to allocate ID for + * + * Use edac_mc_free_id() to coherently free the MC identifier. + * + * .. note:: + * locking model: must be called with the mem_ctls_mutex lock held + * + * Returns: + * 0 on Success, or an error code on failure + */ +static int edac_mc_alloc_id(struct mem_ctl_info *mci) +{ + struct device_node *np = dev_of_node(mci->pdev); + int ret, min, max; + + if (mci->mc_idx == EDAC_AUTO_MC_NUM) { + ret = of_alias_get_id(np, "mc"); + if (ret >= 0) { + min = ret; + max = ret + 1; + } else { + min = of_alias_get_highest_id("mc"); + if (min >= 0) + min++; + else + min = 0; + + max = 0; + } + } else { + min = mci->mc_idx; + max = mci->mc_idx + 1; + } + + ret = idr_alloc(&mc_idr, mci, min, max, GFP_KERNEL); + if (ret < 0) + return ret == -ENOSPC ? -EBUSY : ret; + + mci->mc_idx = ret; + + return 0; +} +/** + * edac_mc_free_id() - Free Memory Controller identifier + * + * @mci: pointer to the mci structure to free ID from + * + * .. note:: + * locking model: must be called with the mem_ctls_mutex lock held + */ +static void edac_mc_free_id(struct mem_ctl_info *mci) +{ + idr_remove(&mc_idr, mci->mc_idx); +} /** * edac_mc_init_labels() - Initialize DIMM labels @@ -612,7 +673,8 @@ EXPORT_SYMBOL_GPL(edac_get_owner); int edac_mc_add_mc_with_groups(struct mem_ctl_info *mci, const struct attribute_group **groups) { - int ret = -EINVAL; + int ret; + edac_dbg(0, "\n"); #ifdef CONFIG_EDAC_DEBUG @@ -649,20 +711,30 @@ int edac_mc_add_mc_with_groups(struct mem_ctl_info *mci, goto fail0; } + ret = edac_mc_alloc_id(mci); + if (ret) { + edac_printk(KERN_ERR, EDAC_MC, "failed to allocate MC idx %u\n", + mci->mc_idx); + goto fail0; + } + edac_mc_init_labels(mci); - if (add_mc_to_global_list(mci)) - goto fail0; + if (add_mc_to_global_list(mci)) { + ret = -EINVAL; + goto fail1; + } /* set load time so that error rate can be tracked */ mci->start_time = jiffies; mci->bus = edac_get_sysfs_subsys(); - if (edac_create_sysfs_mci_device(mci, groups)) { + ret = edac_create_sysfs_mci_device(mci, groups); + if (ret) { edac_mc_printk(mci, KERN_WARNING, "failed to create sysfs device\n"); - goto fail1; + goto fail2; } if (mci->edac_check) { @@ -686,9 +758,12 @@ int edac_mc_add_mc_with_groups(struct mem_ctl_info *mci, mutex_unlock(&mem_ctls_mutex); return 0; -fail1: +fail2: del_mc_from_global_list(mci); +fail1: + edac_mc_free_id(mci); + fail0: mutex_unlock(&mem_ctls_mutex); return ret; @@ -716,6 +791,8 @@ struct mem_ctl_info *edac_mc_del_mc(struct device *dev) if (del_mc_from_global_list(mci)) edac_mc_owner = NULL; + edac_mc_free_id(mci); + mutex_unlock(&mem_ctls_mutex); if (mci->edac_check) diff --git a/drivers/edac/edac_mc.h b/drivers/edac/edac_mc.h index 881b00eadf7a..4b6676235b1b 100644 --- a/drivers/edac/edac_mc.h +++ b/drivers/edac/edac_mc.h @@ -23,6 +23,7 @@ #define _EDAC_MC_H_ #include <linux/kernel.h> +#include <linux/limits.h> #include <linux/types.h> #include <linux/module.h> #include <linux/spinlock.h> @@ -37,6 +38,9 @@ #include <linux/workqueue.h> #include <linux/edac.h> +/* Generate MC identifier automatically */ +#define EDAC_AUTO_MC_NUM UINT_MAX + #if PAGE_SHIFT < 20 #define PAGES_TO_MiB(pages) ((pages) >> (20 - PAGE_SHIFT)) #define MiB_TO_PAGES(mb) ((mb) << (20 - PAGE_SHIFT)) -- 2.37.3 _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
WARNING: multiple messages have this Message-ID (diff)
From: Serge Semin <Sergey.Semin@baikalelectronics.ru> To: Michal Simek <michal.simek@xilinx.com>, Borislav Petkov <bp@alien8.de>, Mauro Carvalho Chehab <mchehab@kernel.org>, Tony Luck <tony.luck@intel.com>, James Morse <james.morse@arm.com>, Robert Richter <rric@kernel.org> Cc: Serge Semin <Sergey.Semin@baikalelectronics.ru>, Serge Semin <fancer.lancer@gmail.com>, Alexey Malahov <Alexey.Malahov@baikalelectronics.ru>, Michail Ivanov <Michail.Ivanov@baikalelectronics.ru>, Pavel Parkhomenko <Pavel.Parkhomenko@baikalelectronics.ru>, Punnaiah Choudary Kalluri <punnaiah.choudary.kalluri@xilinx.com>, Manish Narani <manish.narani@xilinx.com>, Dinh Nguyen <dinguyen@kernel.org>, Rob Herring <robh+dt@kernel.org>, Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>, Rob Herring <robh@kernel.org>, Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>, <devicetree@vger.kernel.org>, <linux-arm-kernel@lists.infradead.org>, <linux-edac@vger.kernel.org>, <linux-kernel@vger.kernel.org> Subject: [PATCH RESEND v3 13/17] EDAC/mc: Add MC unique index allocation procedure Date: Fri, 30 Sep 2022 02:27:08 +0300 [thread overview] Message-ID: <20220929232712.12202-14-Sergey.Semin@baikalelectronics.ru> (raw) In-Reply-To: <20220929232712.12202-1-Sergey.Semin@baikalelectronics.ru> In case of the unique index allocation it's not that optimal to always rely on the low-level device drivers (platform drivers), because they get to start to implement either the same design pattern (for instance global static MC counter) or may end-up with having non-unique index eventually at runtime. Needless to say that having a generic unique index allocation/tracking procedure will make code more readable and safer. The suggested implementation is based on the kernel IDA infrastructure exposed by the lib/idr.c driver with API described in linux/idr.h header file. It's used to create an ID resource descriptor "mc_idr", which then is utilized either to track the custom MC idx specified by EDAC LLDDs or to allocate the next-free MC idx. A new special MC index is introduced here. It's defined by the EDAC_AUTO_MC_NUM macro with a value specifically chosen as the least probable value used for the real MC index. In case if the EDAC_AUTO_MC_NUM index is specified by the EDAC LLDD, the MC index will be either retrieved from the MC device OF-node alias index ("mc[:number:]") or automatically generated as the next-free MC index found by the ID allocation procedure. Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru> --- Note the approach implemented here has been partly ported from the SPI core driver using IDA to track/allocate SPI bus numbers. Link: https://elixir.bootlin.com/linux/latest/source/drivers/spi/spi.c#L2957 --- drivers/edac/edac_mc.c | 89 +++++++++++++++++++++++++++++++++++++++--- drivers/edac/edac_mc.h | 4 ++ 2 files changed, 87 insertions(+), 6 deletions(-) diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 24814839d885..634c41ea7804 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -29,6 +29,9 @@ #include <linux/edac.h> #include <linux/bitops.h> #include <linux/uaccess.h> +#include <linux/idr.h> +#include <linux/of.h> + #include <asm/page.h> #include "edac_mc.h" #include "edac_module.h" @@ -46,6 +49,7 @@ EXPORT_SYMBOL_GPL(edac_op_state); /* lock to memory controller's control array */ static DEFINE_MUTEX(mem_ctls_mutex); static LIST_HEAD(mc_devices); +static DEFINE_IDR(mc_idr); /* * Used to lock EDAC MC to just one module, avoiding two drivers e. g. @@ -493,7 +497,64 @@ void edac_mc_reset_delay_period(unsigned long value) mutex_unlock(&mem_ctls_mutex); } +/** + * edac_mc_alloc_id() - Allocate unique Memory Controller identifier + * + * @mci: pointer to the mci structure to allocate ID for + * + * Use edac_mc_free_id() to coherently free the MC identifier. + * + * .. note:: + * locking model: must be called with the mem_ctls_mutex lock held + * + * Returns: + * 0 on Success, or an error code on failure + */ +static int edac_mc_alloc_id(struct mem_ctl_info *mci) +{ + struct device_node *np = dev_of_node(mci->pdev); + int ret, min, max; + + if (mci->mc_idx == EDAC_AUTO_MC_NUM) { + ret = of_alias_get_id(np, "mc"); + if (ret >= 0) { + min = ret; + max = ret + 1; + } else { + min = of_alias_get_highest_id("mc"); + if (min >= 0) + min++; + else + min = 0; + + max = 0; + } + } else { + min = mci->mc_idx; + max = mci->mc_idx + 1; + } + + ret = idr_alloc(&mc_idr, mci, min, max, GFP_KERNEL); + if (ret < 0) + return ret == -ENOSPC ? -EBUSY : ret; + + mci->mc_idx = ret; + + return 0; +} +/** + * edac_mc_free_id() - Free Memory Controller identifier + * + * @mci: pointer to the mci structure to free ID from + * + * .. note:: + * locking model: must be called with the mem_ctls_mutex lock held + */ +static void edac_mc_free_id(struct mem_ctl_info *mci) +{ + idr_remove(&mc_idr, mci->mc_idx); +} /** * edac_mc_init_labels() - Initialize DIMM labels @@ -612,7 +673,8 @@ EXPORT_SYMBOL_GPL(edac_get_owner); int edac_mc_add_mc_with_groups(struct mem_ctl_info *mci, const struct attribute_group **groups) { - int ret = -EINVAL; + int ret; + edac_dbg(0, "\n"); #ifdef CONFIG_EDAC_DEBUG @@ -649,20 +711,30 @@ int edac_mc_add_mc_with_groups(struct mem_ctl_info *mci, goto fail0; } + ret = edac_mc_alloc_id(mci); + if (ret) { + edac_printk(KERN_ERR, EDAC_MC, "failed to allocate MC idx %u\n", + mci->mc_idx); + goto fail0; + } + edac_mc_init_labels(mci); - if (add_mc_to_global_list(mci)) - goto fail0; + if (add_mc_to_global_list(mci)) { + ret = -EINVAL; + goto fail1; + } /* set load time so that error rate can be tracked */ mci->start_time = jiffies; mci->bus = edac_get_sysfs_subsys(); - if (edac_create_sysfs_mci_device(mci, groups)) { + ret = edac_create_sysfs_mci_device(mci, groups); + if (ret) { edac_mc_printk(mci, KERN_WARNING, "failed to create sysfs device\n"); - goto fail1; + goto fail2; } if (mci->edac_check) { @@ -686,9 +758,12 @@ int edac_mc_add_mc_with_groups(struct mem_ctl_info *mci, mutex_unlock(&mem_ctls_mutex); return 0; -fail1: +fail2: del_mc_from_global_list(mci); +fail1: + edac_mc_free_id(mci); + fail0: mutex_unlock(&mem_ctls_mutex); return ret; @@ -716,6 +791,8 @@ struct mem_ctl_info *edac_mc_del_mc(struct device *dev) if (del_mc_from_global_list(mci)) edac_mc_owner = NULL; + edac_mc_free_id(mci); + mutex_unlock(&mem_ctls_mutex); if (mci->edac_check) diff --git a/drivers/edac/edac_mc.h b/drivers/edac/edac_mc.h index 881b00eadf7a..4b6676235b1b 100644 --- a/drivers/edac/edac_mc.h +++ b/drivers/edac/edac_mc.h @@ -23,6 +23,7 @@ #define _EDAC_MC_H_ #include <linux/kernel.h> +#include <linux/limits.h> #include <linux/types.h> #include <linux/module.h> #include <linux/spinlock.h> @@ -37,6 +38,9 @@ #include <linux/workqueue.h> #include <linux/edac.h> +/* Generate MC identifier automatically */ +#define EDAC_AUTO_MC_NUM UINT_MAX + #if PAGE_SHIFT < 20 #define PAGES_TO_MiB(pages) ((pages) >> (20 - PAGE_SHIFT)) #define MiB_TO_PAGES(mb) ((mb) << (20 - PAGE_SHIFT)) -- 2.37.3
next prev parent reply other threads:[~2022-09-29 23:33 UTC|newest] Thread overview: 76+ messages / expand[flat|nested] mbox.gz Atom feed top 2022-09-29 23:26 [PATCH RESEND v3 00/17] EDAC/mc/synopsys: Various fixes and cleanups Serge Semin 2022-09-29 23:26 ` Serge Semin 2022-09-29 23:26 ` [PATCH RESEND v3 01/17] EDAC/synopsys: Fix native uMCTL2 IRQs handling procedure Serge Semin 2022-09-29 23:26 ` Serge Semin 2022-10-31 17:24 ` Borislav Petkov 2022-10-31 17:24 ` Borislav Petkov 2023-09-01 11:24 ` Serge Semin 2023-09-01 11:24 ` Serge Semin 2022-09-29 23:26 ` [PATCH RESEND v3 02/17] EDAC/synopsys: Fix generic device type detection procedure Serge Semin 2022-09-29 23:26 ` Serge Semin 2022-09-29 23:26 ` [PATCH RESEND v3 03/17] EDAC/synopsys: Fix mci->scrub_cap field setting Serge Semin 2022-09-29 23:26 ` Serge Semin 2022-09-29 23:26 ` [PATCH RESEND v3 04/17] EDAC/synopsys: Drop erroneous ADDRMAP4.addrmap_col_b10 parse Serge Semin 2022-09-29 23:26 ` Serge Semin 2022-09-29 23:27 ` [PATCH RESEND v3 05/17] EDAC/synopsys: Fix reading errors count before ECC status Serge Semin 2022-09-29 23:27 ` Serge Semin 2022-09-29 23:27 ` [PATCH RESEND v3 06/17] EDAC/synopsys: Use platform device devm ioremap method Serge Semin 2022-09-29 23:27 ` Serge Semin 2022-09-29 23:27 ` [PATCH RESEND v3 07/17] EDAC/synopsys: Drop internal CE and UE counters Serge Semin 2022-09-29 23:27 ` Serge Semin 2022-09-29 23:27 ` [PATCH RESEND v3 08/17] EDAC/synopsys: Drop local to_mci macro implementation Serge Semin 2022-09-29 23:27 ` Serge Semin 2022-09-29 23:27 ` [PATCH RESEND v3 09/17] EDAC/synopsys: Drop struct ecc_error_info.blknr field Serge Semin 2022-09-29 23:27 ` Serge Semin 2022-09-29 23:27 ` [PATCH RESEND v3 10/17] EDAC/synopsys: Shorten out struct ecc_error_info.bankgrpnr field name Serge Semin 2022-09-29 23:27 ` Serge Semin 2022-09-29 23:27 ` [PATCH RESEND v3 11/17] EDAC/synopsys: Drop redundant info from error message Serge Semin 2022-09-29 23:27 ` Serge Semin 2022-09-29 23:27 ` [PATCH RESEND v3 12/17] EDAC/mc: Init DIMM labels in MC registration method Serge Semin 2022-09-29 23:27 ` Serge Semin 2022-09-29 23:27 ` Serge Semin [this message] 2022-09-29 23:27 ` [PATCH RESEND v3 13/17] EDAC/mc: Add MC unique index allocation procedure Serge Semin 2022-10-12 17:29 ` Borislav Petkov 2022-10-12 17:29 ` Borislav Petkov 2022-10-12 20:01 ` Serge Semin 2022-10-12 20:01 ` Serge Semin 2022-10-12 20:33 ` Borislav Petkov 2022-10-12 20:33 ` Borislav Petkov 2022-10-12 20:44 ` Tony Luck 2022-10-12 20:44 ` Tony Luck 2022-10-12 21:31 ` Serge Semin 2022-10-12 21:31 ` Serge Semin 2022-10-12 22:30 ` Serge Semin 2022-10-12 22:30 ` Serge Semin 2022-10-13 9:38 ` Borislav Petkov 2022-10-13 9:38 ` Borislav Petkov 2022-09-29 23:27 ` [PATCH RESEND v3 14/17] EDAC/synopsys: Detach Zynq DDRC controller support Serge Semin 2022-09-29 23:27 ` Serge Semin 2022-09-30 14:42 ` Borislav Petkov 2022-09-30 14:42 ` Borislav Petkov 2022-10-06 12:17 ` Serge Semin 2022-10-06 12:17 ` Serge Semin 2022-10-06 13:25 ` Borislav Petkov 2022-10-06 13:25 ` Borislav Petkov 2022-10-08 0:42 ` Serge Semin 2022-10-08 0:42 ` Serge Semin 2022-10-12 17:28 ` Borislav Petkov 2022-10-12 17:28 ` Borislav Petkov 2022-10-12 19:27 ` Serge Semin 2022-10-12 19:27 ` Serge Semin 2022-10-12 19:44 ` Borislav Petkov 2022-10-12 19:44 ` Borislav Petkov 2022-10-12 20:55 ` Serge Semin 2022-10-12 20:55 ` Serge Semin 2022-09-29 23:27 ` [PATCH RESEND v3 15/17] EDAC/synopsys: Drop unused platform-specific setup API Serge Semin 2022-09-29 23:27 ` Serge Semin 2022-09-29 23:27 ` [PATCH RESEND v3 16/17] EDAC/synopsys: Unify the driver entities naming Serge Semin 2022-09-29 23:27 ` Serge Semin 2022-09-29 23:27 ` [PATCH RESEND v3 17/17] EDAC/synopsys: Convert to using BIT/GENMASK/FIELD_x macros Serge Semin 2022-09-29 23:27 ` Serge Semin 2022-09-30 14:29 ` [PATCH RESEND v3 00/17] EDAC/mc/synopsys: Various fixes and cleanups Borislav Petkov 2022-09-30 14:29 ` Borislav Petkov 2022-10-06 7:13 ` Michal Simek 2022-10-06 7:13 ` Michal Simek 2023-08-18 23:06 ` Serge Semin 2023-08-18 23:06 ` Serge Semin
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=20220929232712.12202-14-Sergey.Semin@baikalelectronics.ru \ --to=sergey.semin@baikalelectronics.ru \ --cc=Alexey.Malahov@baikalelectronics.ru \ --cc=Michail.Ivanov@baikalelectronics.ru \ --cc=Pavel.Parkhomenko@baikalelectronics.ru \ --cc=bp@alien8.de \ --cc=devicetree@vger.kernel.org \ --cc=dinguyen@kernel.org \ --cc=fancer.lancer@gmail.com \ --cc=james.morse@arm.com \ --cc=krzysztof.kozlowski+dt@linaro.org \ --cc=krzysztof.kozlowski@linaro.org \ --cc=linux-arm-kernel@lists.infradead.org \ --cc=linux-edac@vger.kernel.org \ --cc=linux-kernel@vger.kernel.org \ --cc=manish.narani@xilinx.com \ --cc=mchehab@kernel.org \ --cc=michal.simek@xilinx.com \ --cc=punnaiah.choudary.kalluri@xilinx.com \ --cc=robh+dt@kernel.org \ --cc=robh@kernel.org \ --cc=rric@kernel.org \ --cc=tony.luck@intel.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: linkBe 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.