From: Fangzhi Zuo <jerry.zuo@amd.com>
To: <amd-gfx@lists.freedesktop.org>
Cc: Harry Wentland <harry.wentland@amd.com>,
Leo Li <sunpeng.li@amd.com>,
Aurabindo Pillai <aurabindo.pillai@amd.com>,
Roman Li <roman.li@amd.com>, Wayne Lin <wayne.lin@amd.com>,
Tom Chung <chiahsuan.chung@amd.com>,
"Fangzhi Zuo" <jerry.zuo@amd.com>,
Dan Wheeler <daniel.wheeler@amd.com>, Ray Wu <Ray.Wu@amd.com>,
Ivan Lipski <ivan.lipski@amd.com>, Alex Hung <alex.hung@amd.com>,
James Lin <PingLei.Lin@amd.com>,
Chenyu Chen <Chen-Yu.Chen@amd.com>,
Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Subject: [PATCH 05/49] drm/amd/display: Add KUnit tests for HDCP display helpers
Date: Thu, 23 Jul 2026 16:13:13 -0400 [thread overview]
Message-ID: <20260723201908.373300-6-jerry.zuo@amd.com> (raw)
In-Reply-To: <20260723201908.373300-1-jerry.zuo@amd.com>
From: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Cover the HDCP display lifecycle helpers:
- hdcp_update_display() registers the connector and, on the
disable path, resets the per-link encryption status to
HDCP_OFF.
- hdcp_remove_display() reverts an ENABLED connector back to
DESIRED and clears the per-link entry, including the NULL
connector-state path.
- hdcp_reset_display() clears the encryption status and the
connector for every link.
Reviewed-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Fangzhi Zuo <jerry.zuo@amd.com>
Tested-by: Dan Wheeler <daniel.wheeler@amd.com>
---
.../amd/display/amdgpu_dm/amdgpu_dm_hdcp.c | 6 +-
.../amd/display/amdgpu_dm/amdgpu_dm_hdcp.h | 2 +
.../amdgpu_dm/tests/amdgpu_dm_hdcp_test.c | 207 ++++++++++++++++++
3 files changed, 214 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
index 3b5e0e64adde..f786c0a85425 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
@@ -317,8 +317,10 @@ void hdcp_update_display(struct hdcp_workqueue *hdcp_work,
process_output(hdcp_w);
}
+EXPORT_IF_KUNIT(hdcp_update_display);
-static void hdcp_remove_display(struct hdcp_workqueue *hdcp_work,
+STATIC_IFN_KUNIT
+void hdcp_remove_display(struct hdcp_workqueue *hdcp_work,
unsigned int link_index,
struct amdgpu_dm_connector *aconnector)
{
@@ -348,6 +350,7 @@ static void hdcp_remove_display(struct hdcp_workqueue *hdcp_work,
}
process_output(hdcp_w);
}
+EXPORT_IF_KUNIT(hdcp_remove_display);
void hdcp_reset_display(struct hdcp_workqueue *hdcp_work, unsigned int link_index)
{
@@ -371,6 +374,7 @@ void hdcp_reset_display(struct hdcp_workqueue *hdcp_work, unsigned int link_inde
process_output(hdcp_w);
}
+EXPORT_IF_KUNIT(hdcp_reset_display);
void hdcp_handle_cpirq(struct hdcp_workqueue *hdcp_work, unsigned int link_index)
{
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h
index fb66f48d7297..69a50e081c56 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h
@@ -115,6 +115,8 @@ void hdcp_update_display_encryption_control(struct hdcp_workqueue *hdcp_work,
bool enable_encryption);
void event_property_update(struct work_struct *work);
void link_lock(struct hdcp_workqueue *work, bool lock);
+void hdcp_remove_display(struct hdcp_workqueue *hdcp_work, unsigned int link_index,
+ struct amdgpu_dm_connector *aconnector);
uint8_t *psp_get_srm(struct psp_context *psp, uint32_t *srm_version, uint32_t *srm_size);
int psp_set_srm(struct psp_context *psp, u8 *srm, uint32_t srm_size, uint32_t *srm_version);
#endif
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_hdcp_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_hdcp_test.c
index 43c7efcdd22c..e6d03199187b 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_hdcp_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_hdcp_test.c
@@ -9,6 +9,7 @@
#include <linux/workqueue.h>
#include "amdgpu.h"
+#include "amdgpu_dm.h"
#include "amdgpu_dm_hdcp.h"
static void dummy_work_fn(struct work_struct *work) {}
@@ -753,6 +754,206 @@ static void dm_test_psp_set_srm_uninitialized_returns_einval(struct kunit *test)
/* End of tests for psp_get_srm() and psp_set_srm() */
+/*
+ * Tests for hdcp_update_display() / hdcp_remove_display() /
+ * hdcp_reset_display().
+ */
+
+/**
+ * alloc_test_workqueue_locked - workqueue with dworks and mutex initialised
+ * @test: KUnit test context for managed allocation
+ *
+ * Allocates a minimal hdcp_workqueue with its mutex and the three delayed
+ * works initialised, as required by the guard(mutex) and process_output()
+ * usage in the display update/remove/reset helpers.
+ */
+static struct hdcp_workqueue *alloc_test_workqueue_locked(struct kunit *test)
+{
+ struct hdcp_workqueue *work;
+
+ work = kunit_kzalloc(test, sizeof(*work), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, work);
+
+ mutex_init(&work->mutex);
+ INIT_DELAYED_WORK(&work->callback_dwork, dummy_work_fn);
+ INIT_DELAYED_WORK(&work->watchdog_timer_dwork, dummy_work_fn);
+ INIT_DELAYED_WORK(&work->property_validate_dwork, dummy_work_fn);
+
+ return work;
+}
+
+/**
+ * alloc_test_connector - minimal amdgpu_dm_connector for display tests
+ * @test: KUnit test context for managed allocation
+ * @index: drm connector index to assign
+ *
+ * Allocates an amdgpu_dm_connector with an initialised connector refcount
+ * (so drm_connector_get() is valid) and a dc_link/dc pair. The connector's
+ * free_cb is left NULL so drm_connector_put() is a safe no-op that never
+ * releases the object.
+ */
+static struct amdgpu_dm_connector *alloc_test_connector(struct kunit *test,
+ unsigned int index)
+{
+ struct amdgpu_dm_connector *aconnector;
+ struct dc_link *dc_link;
+ struct dc *dc;
+
+ aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, aconnector);
+ dc_link = kunit_kzalloc(test, sizeof(*dc_link), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, dc_link);
+ dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, dc);
+
+ kref_init(&aconnector->base.base.refcount);
+ aconnector->base.index = index;
+ dc_link->dc = dc;
+ aconnector->dc_link = dc_link;
+
+ return aconnector;
+}
+
+/**
+ * dm_test_hdcp_update_display_enable_registers_connector - enable stores the connector
+ * @test: KUnit test context
+ *
+ * hdcp_update_display() with enable_encryption=true should register the
+ * connector in the per-link aconnector array at its connector index. The
+ * hdcp has no active display, so mod_hdcp_update_display() is effectively a
+ * no-op and the call must not touch encryption_status.
+ */
+static void dm_test_hdcp_update_display_enable_registers_connector(struct kunit *test)
+{
+ struct hdcp_workqueue *work = alloc_test_workqueue_locked(test);
+ struct amdgpu_dm_connector *aconnector = alloc_test_connector(test, 0);
+
+ work->srm_size = 0;
+
+ hdcp_update_display(work, 0, aconnector, DRM_MODE_HDCP_CONTENT_TYPE0, true);
+
+ KUNIT_EXPECT_PTR_EQ(test, work->aconnector[0], aconnector);
+ KUNIT_EXPECT_EQ(test, work->encryption_status[0],
+ MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF);
+
+ cancel_delayed_work_sync(&work->property_validate_dwork);
+ cancel_delayed_work_sync(&work->callback_dwork);
+ cancel_delayed_work_sync(&work->watchdog_timer_dwork);
+}
+
+/**
+ * dm_test_hdcp_update_display_disable_sets_status_off - disable clears status
+ * @test: KUnit test context
+ *
+ * hdcp_update_display() with enable_encryption=false should register the
+ * connector and reset the connector's encryption_status entry to HDCP_OFF
+ * via hdcp_update_display_encryption_control().
+ */
+static void dm_test_hdcp_update_display_disable_sets_status_off(struct kunit *test)
+{
+ struct hdcp_workqueue *work = alloc_test_workqueue_locked(test);
+ struct amdgpu_dm_connector *aconnector = alloc_test_connector(test, 2);
+
+ work->encryption_status[2] = MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE1_ON;
+
+ hdcp_update_display(work, 0, aconnector, DRM_MODE_HDCP_CONTENT_TYPE0, false);
+
+ KUNIT_EXPECT_PTR_EQ(test, work->aconnector[2], aconnector);
+ KUNIT_EXPECT_EQ(test, work->encryption_status[2],
+ MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF);
+
+ cancel_delayed_work_sync(&work->property_validate_dwork);
+ cancel_delayed_work_sync(&work->callback_dwork);
+ cancel_delayed_work_sync(&work->watchdog_timer_dwork);
+}
+
+/**
+ * dm_test_hdcp_remove_display_enabled_resets_cp - ENABLED CP reverts to DESIRED
+ * @test: KUnit test context
+ *
+ * hdcp_remove_display() must revert a connector whose content_protection is
+ * ENABLED back to DESIRED and clear the per-link aconnector entry.
+ */
+static void dm_test_hdcp_remove_display_enabled_resets_cp(struct kunit *test)
+{
+ struct hdcp_workqueue *work = alloc_test_workqueue_locked(test);
+ struct amdgpu_dm_connector *aconnector = alloc_test_connector(test, 1);
+ struct drm_connector_state *conn_state;
+
+ conn_state = kunit_kzalloc(test, sizeof(*conn_state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, conn_state);
+
+ conn_state->content_protection = DRM_MODE_CONTENT_PROTECTION_ENABLED;
+ aconnector->base.state = conn_state;
+ work->aconnector[1] = aconnector;
+
+ hdcp_remove_display(work, 0, aconnector);
+
+ KUNIT_EXPECT_EQ(test, conn_state->content_protection,
+ DRM_MODE_CONTENT_PROTECTION_DESIRED);
+ KUNIT_EXPECT_PTR_EQ(test, work->aconnector[1], NULL);
+
+ cancel_delayed_work_sync(&work->property_validate_dwork);
+ cancel_delayed_work_sync(&work->callback_dwork);
+ cancel_delayed_work_sync(&work->watchdog_timer_dwork);
+}
+
+/**
+ * dm_test_hdcp_remove_display_null_state_clears_connector - NULL state skips CP change
+ * @test: KUnit test context
+ *
+ * When the connector has no drm_connector_state, hdcp_remove_display() must
+ * skip the content_protection update path and still clear the per-link
+ * aconnector entry.
+ */
+static void dm_test_hdcp_remove_display_null_state_clears_connector(struct kunit *test)
+{
+ struct hdcp_workqueue *work = alloc_test_workqueue_locked(test);
+ struct amdgpu_dm_connector *aconnector = alloc_test_connector(test, 0);
+
+ aconnector->base.state = NULL;
+ work->aconnector[0] = aconnector;
+
+ hdcp_remove_display(work, 0, aconnector);
+
+ KUNIT_EXPECT_PTR_EQ(test, work->aconnector[0], NULL);
+
+ cancel_delayed_work_sync(&work->property_validate_dwork);
+ cancel_delayed_work_sync(&work->callback_dwork);
+ cancel_delayed_work_sync(&work->watchdog_timer_dwork);
+}
+
+/**
+ * dm_test_hdcp_reset_display_clears_all_state - reset clears status and connectors
+ * @test: KUnit test context
+ *
+ * hdcp_reset_display() must reset every connector's encryption_status to
+ * HDCP_OFF and clear all per-link aconnector entries.
+ */
+static void dm_test_hdcp_reset_display_clears_all_state(struct kunit *test)
+{
+ struct hdcp_workqueue *work = alloc_test_workqueue_locked(test);
+ struct amdgpu_dm_connector *aconnector = alloc_test_connector(test, 4);
+
+ work->encryption_status[4] = MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE1_ON;
+ work->aconnector[4] = aconnector;
+
+ hdcp_reset_display(work, 0);
+
+ KUNIT_EXPECT_EQ(test, work->encryption_status[4],
+ MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF);
+ KUNIT_EXPECT_PTR_EQ(test, work->aconnector[4], NULL);
+
+ cancel_delayed_work_sync(&work->property_validate_dwork);
+ cancel_delayed_work_sync(&work->callback_dwork);
+ cancel_delayed_work_sync(&work->watchdog_timer_dwork);
+}
+
+/*
+ * End of tests for hdcp_update_display() / hdcp_remove_display() /
+ * hdcp_reset_display().
+ */
+
static struct kunit_case dm_hdcp_test_cases[] = {
/* hdcp_get_content_protection_from_status() */
KUNIT_CASE(dm_test_hdcp_get_cp_disabled_returns_desired),
@@ -790,6 +991,12 @@ static struct kunit_case dm_hdcp_test_cases[] = {
/* psp_get_srm() / psp_set_srm() */
KUNIT_CASE(dm_test_psp_get_srm_uninitialized_returns_null),
KUNIT_CASE(dm_test_psp_set_srm_uninitialized_returns_einval),
+ /* hdcp_update_display() / hdcp_remove_display() / hdcp_reset_display() */
+ KUNIT_CASE(dm_test_hdcp_update_display_enable_registers_connector),
+ KUNIT_CASE(dm_test_hdcp_update_display_disable_sets_status_off),
+ KUNIT_CASE(dm_test_hdcp_remove_display_enabled_resets_cp),
+ KUNIT_CASE(dm_test_hdcp_remove_display_null_state_clears_connector),
+ KUNIT_CASE(dm_test_hdcp_reset_display_clears_all_state),
{}
};
--
2.53.0
next prev parent reply other threads:[~2026-07-23 20:19 UTC|newest]
Thread overview: 51+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-23 20:13 [PATCH 00/49] DC Patches July 20th, 2026 Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 01/49] drm/amd/display: share common DM KUnit helpers Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 02/49] drm/amd/display: Port DCN4+ MCIF ARB programming to new format Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 03/49] drm/amd/display: Fix force FRL rate debug setting Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 04/49] drm/amd/display: Add KUnit tests for link_lock and psp SRM helpers Fangzhi Zuo
2026-07-23 20:13 ` Fangzhi Zuo [this message]
2026-07-23 20:13 ` [PATCH 06/49] drm/amd/display: Add KUnit tests for event_callback Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 07/49] drm/amd/display: Add KUnit tests for event_property_validate Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 08/49] drm/amd/display: Add KUnit tests for watchdog and cpirq events Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 09/49] drm/amd/display: Add KUnit tests for hdcp_destroy Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 10/49] drm/amd/display: Add AV mute wait frames to dce110_set_avmute Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 11/49] drm/amd/display: revert "convert dcn42 GPIO translation to lookup tables" Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 12/49] drm/amd/display: move scaling helper to connector Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 13/49] drm/amd/display: move stutter quirk to quirks file Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 14/49] drm/amd/display: move watermarks table to pp_smu Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 15/49] drm/amd/display: move GPU mem helpers to services Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 16/49] drm/amd/display: add FreeSync/VRR module Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 17/49] drm/amd/display: add cursor module Fangzhi Zuo
2026-08-03 12:48 ` Timur Kristóf
2026-07-23 20:13 ` [PATCH 18/49] drm/amd/display: add KUnit tests for audio component get_eld Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 19/49] drm/amd/display: add KUnit tests for audio commit path Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 20/49] drm/amd/display: Use current mpc pipe in set output transfer func Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 21/49] drm/amd/display: Correct vblank_end calc for fams cmd packet Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 22/49] drm/amd/display: Add KUnit test for native backlight registration Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 23/49] drm/amd/display: Add color transfer-function tests Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 24/49] drm/amd/display: Add atomic " Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 25/49] drm/amd/display: Add CRTC and plane degamma tests Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 26/49] drm/amd/display: Add legacy plane LUT tests Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 27/49] drm/amd/display: Add truncated colorop tests Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 28/49] drm/amd/display: Add colorop LUT programming tests Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 29/49] drm/amd/display: Add KUnit tests for enable_assr Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 30/49] drm/amd/display: Add KUnit tests for update_config Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 31/49] drm/amd/display: Add KUnit tests for hdcp_create_workqueue Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 32/49] drm/amd/display: Add KUnit tests for srm_data_write and srm_data_read Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 33/49] drm/amd/display: Add KUnit tests for HDCP DDC link adapters Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 34/49] drm/amd/display: Add initialized-branch test for psp_set_srm Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 35/49] drm/amd/display: Add deeper event_property_update tests Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 36/49] drm/amd/display: adjust floating point format for gamut remap when needed Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 37/49] drm/amd/display: Reintroduce "convert dcn42 GPIO translation to lookup tables" Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 38/49] drm/amd/display: Prune per-tile Timing from Apple Studio Display Primary Tile Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 39/49] drm/amd/display: Add get replay residency function Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 40/49] drm/amd/display: Fix divide-by-zero in calculate_mcache_setting on zero viewport Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 41/49] drm/amd/display: check if dml21_add_phantom_plane() is successful Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 42/49] drm/amd/display: change dcc_rate from 1 to 2 for log use only Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 43/49] drm/amd/display: enforce UCLK pstate support in mode_support Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 44/49] drm/amd/display: add DalForceMaxDisplayClock debug option to DML2 Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 45/49] drm/amd/display: Fixes for dcn42b_soc_bb.h Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 46/49] drm/amd/display: Fix rounding errors in CalculatePrefetchSchedule Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 47/49] drm/amd/display: plumb PMO per-plane pstate methods into mode_support Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 48/49] drm/amd/display: dispatch compressed FRL cap check inside dml1_frl_cap_chk_inter Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 49/49] drm/amd/display: Promote DC to 3.2.391 Fangzhi Zuo
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=20260723201908.373300-6-jerry.zuo@amd.com \
--to=jerry.zuo@amd.com \
--cc=Chen-Yu.Chen@amd.com \
--cc=PingLei.Lin@amd.com \
--cc=Ray.Wu@amd.com \
--cc=alex.hung@amd.com \
--cc=amd-gfx@lists.freedesktop.org \
--cc=aurabindo.pillai@amd.com \
--cc=bhawanpreet.lakha@amd.com \
--cc=chiahsuan.chung@amd.com \
--cc=daniel.wheeler@amd.com \
--cc=harry.wentland@amd.com \
--cc=ivan.lipski@amd.com \
--cc=roman.li@amd.com \
--cc=sunpeng.li@amd.com \
--cc=wayne.lin@amd.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.