linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Elliot Berman <eberman@codeaurora.org>
To: bjorn.andersson@linaro.org, saiprakash.ranjan@codeaurora.org,
	agross@kernel.org, swboyd@chromium.org
Cc: Elliot Berman <eberman@codeaurora.org>,
	tsoni@codeaurora.org, sidgup@codeaurora.org,
	psodagud@codeaurora.org, linux-arm-msm@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: [PATCH v2 17/18] firmware: qcom_scm: Dynamically support SMCCC and legacy conventions
Date: Tue, 12 Nov 2019 13:22:53 -0800	[thread overview]
Message-ID: <1573593774-12539-18-git-send-email-eberman@codeaurora.org> (raw)
In-Reply-To: <1573593774-12539-1-git-send-email-eberman@codeaurora.org>

Dynamically support SMCCCC and legacy conventions by detecting which
convention to use at runtime. qcom_scm_call_atomic and qcom_scm_call can
then be moved in qcom_scm.c and use underlying convention backend as
appropriate. Thus, rename qcom_scm-64,-32 to reflect that they are
backends for -smccc and -legacy, respectively.

Signed-off-by: Elliot Berman <eberman@codeaurora.org>
---
 drivers/firmware/Kconfig                           |   8 --
 drivers/firmware/Makefile                          |   4 +-
 .../firmware/{qcom_scm-32.c => qcom_scm-legacy.c}  |  24 +----
 .../firmware/{qcom_scm-64.c => qcom_scm-smccc.c}   |  77 +-------------
 drivers/firmware/qcom_scm.c                        | 113 ++++++++++++++++++++-
 drivers/firmware/qcom_scm.h                        |  23 +++--
 6 files changed, 137 insertions(+), 112 deletions(-)
 rename drivers/firmware/{qcom_scm-32.c => qcom_scm-legacy.c} (92%)
 rename drivers/firmware/{qcom_scm-64.c => qcom_scm-smccc.c} (60%)

diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index e40a77b..ea869ad 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -239,14 +239,6 @@ config QCOM_SCM
 	depends on ARM || ARM64
 	select RESET_CONTROLLER
 
-config QCOM_SCM_32
-	def_bool y
-	depends on QCOM_SCM && ARM
-
-config QCOM_SCM_64
-	def_bool y
-	depends on QCOM_SCM && ARM64
-
 config QCOM_SCM_DOWNLOAD_MODE_DEFAULT
 	bool "Qualcomm download mode enabled by default"
 	depends on QCOM_SCM
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index 747fb73..4ae2f55 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -17,9 +17,7 @@ obj-$(CONFIG_ISCSI_IBFT)	+= iscsi_ibft.o
 obj-$(CONFIG_FIRMWARE_MEMMAP)	+= memmap.o
 obj-$(CONFIG_RASPBERRYPI_FIRMWARE) += raspberrypi.o
 obj-$(CONFIG_FW_CFG_SYSFS)	+= qemu_fw_cfg.o
-obj-$(CONFIG_QCOM_SCM)		+= qcom_scm.o
-obj-$(CONFIG_QCOM_SCM_64)	+= qcom_scm-64.o
-obj-$(CONFIG_QCOM_SCM_32)	+= qcom_scm-32.o
+obj-$(CONFIG_QCOM_SCM)		+= qcom_scm.o qcom_scm-smccc.o qcom_scm-legacy.o
 obj-$(CONFIG_TI_SCI_PROTOCOL)	+= ti_sci.o
 obj-$(CONFIG_TRUSTED_FOUNDATIONS) += trusted_foundations.o
 obj-$(CONFIG_TURRIS_MOX_RWTM)	+= turris-mox-rwtm.o
diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-legacy.c
similarity index 92%
rename from drivers/firmware/qcom_scm-32.c
rename to drivers/firmware/qcom_scm-legacy.c
index 9e3789d..8d7ce69 100644
--- a/drivers/firmware/qcom_scm-32.c
+++ b/drivers/firmware/qcom_scm-legacy.c
@@ -21,7 +21,6 @@ struct arm_smccc_args {
 	unsigned long a[8];
 };
 
-#define LEGACY_FUNCNUM(s, c)	(((s) << 10) | ((c) & 0x3ff))
 
 /**
  * struct qcom_scm_legacy_command - one SCM command buffer
@@ -124,7 +123,7 @@ static void __qcom_scm_call_do(const struct arm_smccc_args *smc,
  * and response buffers is taken care of by qcom_scm_call; however, callers are
  * responsible for any other cached buffers passed over to the secure world.
  */
-int qcom_scm_call(struct device *dev, struct qcom_scm_desc *desc)
+int qcom_scm_call_legacy(struct device *dev, struct qcom_scm_desc *desc)
 {
 	int arglen = desc->arginfo & 0xf;
 	int ret = 0, context_id;
@@ -208,7 +207,7 @@ int qcom_scm_call(struct device *dev, struct qcom_scm_desc *desc)
  * This shall only be used with commands that are guaranteed to be
  * uninterruptable, atomic and SMP safe.
  */
-int qcom_scm_call_atomic(struct device *dev, struct qcom_scm_desc *desc)
+int qcom_scm_call_legacy_atomic(struct device *dev, struct qcom_scm_desc *desc)
 {
 	int context_id;
 	struct arm_smccc_args smc = {0};
@@ -232,22 +231,3 @@ int qcom_scm_call_atomic(struct device *dev, struct qcom_scm_desc *desc)
 
 	return res.a0;
 }
-
-int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id)
-{
-	int ret;
-	struct qcom_scm_desc desc = {
-		.svc = QCOM_SCM_SVC_INFO,
-		.cmd = QCOM_SCM_INFO_IS_CALL_AVAIL,
-		.args[0] = LEGACY_FUNCNUM(svc_id, cmd_id),
-		.arginfo = QCOM_SCM_ARGS(1),
-	};
-
-	ret = qcom_scm_call(dev, &desc);
-
-	return ret ? : desc.result[0];
-}
-
-void __qcom_scm_init(void)
-{
-}
diff --git a/drivers/firmware/qcom_scm-64.c b/drivers/firmware/qcom_scm-smccc.c
similarity index 60%
rename from drivers/firmware/qcom_scm-64.c
rename to drivers/firmware/qcom_scm-smccc.c
index 1e81b89..f398f09 100644
--- a/drivers/firmware/qcom_scm-64.c
+++ b/drivers/firmware/qcom_scm-smccc.c
@@ -18,13 +18,11 @@ struct arm_smccc_args {
 	unsigned long a[8];
 };
 
-static u64 qcom_smccc_convention = -1;
 static DEFINE_MUTEX(qcom_scm_lock);
 
 #define QCOM_SCM_EBUSY_WAIT_MS 30
 #define QCOM_SCM_EBUSY_MAX_RETRY 20
 
-#define SMCCC_FUNCNUM(s, c)	((((s) & 0xFF) << 8) | ((c) & 0xFF))
 #define SMCCC_N_REG_ARGS	4
 #define SMCCC_FIRST_EXT_IDX	(SMCCC_N_REG_ARGS - 1)
 #define SMCCC_N_EXT_ARGS	(MAX_QCOM_SCM_ARGS - SMCCC_N_REG_ARGS + 1)
@@ -50,8 +48,8 @@ static void __qcom_scm_call_do_quirk(const struct arm_smccc_args *smc,
 	} while (res->a0 == QCOM_SCM_INTERRUPTED);
 }
 
-static int ___qcom_scm_call_smccc(struct device *dev,
-				  struct qcom_scm_desc *desc, bool atomic)
+int qcom_scm_call_smccc(struct device *dev, struct qcom_scm_desc *desc,
+			bool atomic)
 {
 	int arglen = desc->arginfo & 0xf;
 	int i;
@@ -60,6 +58,9 @@ static int ___qcom_scm_call_smccc(struct device *dev,
 	size_t alloc_len;
 	gfp_t flag = atomic ? GFP_ATOMIC : GFP_KERNEL;
 	u32 smccc_call_type = atomic ? ARM_SMCCC_FAST_CALL : ARM_SMCCC_STD_CALL;
+	u32 qcom_smccc_convention =
+			(qcom_scm_convention == SMC_CONVENTION_ARM_32) ?
+			ARM_SMCCC_SMC_32 : ARM_SMCCC_SMC_64;
 	struct arm_smccc_res res;
 	struct arm_smccc_args smc = {0};
 
@@ -138,71 +139,3 @@ static int ___qcom_scm_call_smccc(struct device *dev,
 
 	return 0;
 }
-
-/**
- * qcom_scm_call() - Invoke a syscall in the secure world
- * @dev:	device
- * @svc_id:	service identifier
- * @cmd_id:	command identifier
- * @desc:	Descriptor structure containing arguments and return values
- *
- * Sends a command to the SCM and waits for the command to finish processing.
- * This should *only* be called in pre-emptible context.
- */
-int qcom_scm_call(struct device *dev, struct qcom_scm_desc *desc)
-{
-	might_sleep();
-	return ___qcom_scm_call_smccc(dev, desc, false);
-}
-
-/**
- * qcom_scm_call_atomic() - atomic variation of qcom_scm_call()
- * @dev:	device
- * @svc_id:	service identifier
- * @cmd_id:	command identifier
- * @desc:	Descriptor structure containing arguments and return values
- * @res:	Structure containing results from SMC/HVC call
- *
- * Sends a command to the SCM and waits for the command to finish processing.
- * This can be called in atomic context.
- */
-int qcom_scm_call_atomic(struct device *dev, struct qcom_scm_desc *desc)
-{
-	return ___qcom_scm_call_smccc(dev, desc, true);
-}
-
-int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id)
-{
-	int ret;
-	struct qcom_scm_desc desc = {
-		.svc = QCOM_SCM_SVC_INFO,
-		.cmd = QCOM_SCM_INFO_IS_CALL_AVAIL,
-		.owner = ARM_SMCCC_OWNER_SIP,
-	};
-
-	desc.arginfo = QCOM_SCM_ARGS(1);
-	desc.args[0] = SMCCC_FUNCNUM(svc_id, cmd_id) |
-			(ARM_SMCCC_OWNER_SIP << ARM_SMCCC_OWNER_SHIFT);
-
-	ret = qcom_scm_call(dev, &desc);
-
-	return ret ? : desc.result[0];
-}
-
-void __qcom_scm_init(void)
-{
-	qcom_smccc_convention = ARM_SMCCC_SMC_64;
-	if (__qcom_scm_is_call_available(NULL, QCOM_SCM_SVC_INFO,
-			QCOM_SCM_INFO_IS_CALL_AVAIL) == 1)
-		goto out;
-
-	qcom_smccc_convention = ARM_SMCCC_SMC_32;
-	if (__qcom_scm_is_call_available(NULL, QCOM_SCM_SVC_INFO,
-			QCOM_SCM_INFO_IS_CALL_AVAIL) == 1)
-		goto out;
-
-	qcom_smccc_convention = -1;
-	BUG();
-out:
-	pr_debug("QCOM SCM SMC Convention: %llu\n", qcom_smccc_convention);
-}
diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c
index 2dc9ca6..b122fa7 100644
--- a/drivers/firmware/qcom_scm.c
+++ b/drivers/firmware/qcom_scm.c
@@ -85,6 +85,117 @@ static void qcom_scm_clk_disable(void)
 	clk_disable_unprepare(__scm->bus_clk);
 }
 
+static int __qcom_scm_is_call_available(struct device *dev, u32 svc_id,
+					u32 cmd_id);
+
+enum qcom_scm_convention qcom_scm_convention;
+static enum qcom_scm_convention __get_convention(void)
+{
+	if (likely(qcom_scm_convention != SMC_CONVENTION_UNKNOWN))
+		return qcom_scm_convention;
+
+	qcom_scm_convention = SMC_CONVENTION_LEGACY;
+	if (__qcom_scm_is_call_available(NULL, QCOM_SCM_SVC_INFO,
+			QCOM_SCM_INFO_IS_CALL_AVAIL) == 1)
+		goto out;
+
+	qcom_scm_convention = SMC_CONVENTION_ARM_64;
+	if (__qcom_scm_is_call_available(NULL, QCOM_SCM_SVC_INFO,
+			QCOM_SCM_INFO_IS_CALL_AVAIL) == 1)
+		goto out;
+
+	qcom_scm_convention = SMC_CONVENTION_ARM_32;
+	if (__qcom_scm_is_call_available(NULL, QCOM_SCM_SVC_INFO,
+			QCOM_SCM_INFO_IS_CALL_AVAIL) == 1)
+		goto out;
+
+	qcom_scm_convention = SMC_CONVENTION_UNKNOWN;
+	BUG();
+out:
+	pr_debug("QCOM SCM SMC Convention: %d\n", qcom_scm_convention);
+	return qcom_scm_convention;
+}
+
+/**
+ * qcom_scm_call() - Invoke a syscall in the secure world
+ * @dev:	device
+ * @svc_id:	service identifier
+ * @cmd_id:	command identifier
+ * @desc:	Descriptor structure containing arguments and return values
+ *
+ * Sends a command to the SCM and waits for the command to finish processing.
+ * This should *only* be called in pre-emptible context.
+ */
+static int qcom_scm_call(struct device *dev, struct qcom_scm_desc *desc)
+{
+	might_sleep();
+	switch (__get_convention()) {
+	case SMC_CONVENTION_ARM_32:
+	case SMC_CONVENTION_ARM_64:
+		return qcom_scm_call_smccc(dev, desc, false);
+	case SMC_CONVENTION_LEGACY:
+		return qcom_scm_call_legacy(dev, desc);
+	default:
+		pr_err("Unknown current SCM calling convention.\n");
+		return -EINVAL;
+	}
+}
+
+/**
+ * qcom_scm_call_atomic() - atomic variation of qcom_scm_call()
+ * @dev:	device
+ * @svc_id:	service identifier
+ * @cmd_id:	command identifier
+ * @desc:	Descriptor structure containing arguments and return values
+ * @res:	Structure containing results from SMC/HVC call
+ *
+ * Sends a command to the SCM and waits for the command to finish processing.
+ * This can be called in atomic context.
+ */
+static int qcom_scm_call_atomic(struct device *dev, struct qcom_scm_desc *desc)
+{
+	switch (__get_convention()) {
+	case SMC_CONVENTION_ARM_32:
+	case SMC_CONVENTION_ARM_64:
+		return qcom_scm_call_smccc(dev, desc, true);
+	case SMC_CONVENTION_LEGACY:
+		return qcom_scm_call_legacy_atomic(dev, desc);
+	default:
+		pr_err("Unknown current SCM calling convention.\n");
+		return -EINVAL;
+	}
+}
+
+static int __qcom_scm_is_call_available(struct device *dev, u32 svc_id,
+					u32 cmd_id)
+{
+	int ret;
+	struct qcom_scm_desc desc = {
+		.svc = QCOM_SCM_SVC_INFO,
+		.cmd = QCOM_SCM_INFO_IS_CALL_AVAIL,
+		.owner = ARM_SMCCC_OWNER_SIP,
+	};
+
+	desc.arginfo = QCOM_SCM_ARGS(1);
+	switch (__get_convention()) {
+	case SMC_CONVENTION_ARM_32:
+	case SMC_CONVENTION_ARM_64:
+		desc.args[0] = SMCCC_FUNCNUM(svc_id, cmd_id) |
+				(ARM_SMCCC_OWNER_SIP << ARM_SMCCC_OWNER_SHIFT);
+		break;
+	case SMC_CONVENTION_LEGACY:
+		desc.args[0] = LEGACY_FUNCNUM(svc_id, cmd_id);
+		break;
+	default:
+		pr_err("Unknown SMC convention being used\n");
+		return -EINVAL;
+	}
+
+	ret = qcom_scm_call(dev, &desc);
+
+	return ret ? : desc.result[0];
+}
+
 #define QCOM_SCM_FLAG_COLDBOOT_CPU0	0x00
 #define QCOM_SCM_FLAG_COLDBOOT_CPU1	0x01
 #define QCOM_SCM_FLAG_COLDBOOT_CPU2	0x08
@@ -887,7 +998,7 @@ static int qcom_scm_probe(struct platform_device *pdev)
 	__scm = scm;
 	__scm->dev = &pdev->dev;
 
-	__qcom_scm_init();
+	__get_convention();
 
 	/*
 	 * If requested enable "download mode", from this point on warmboot
diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h
index efbd31b..9252498 100644
--- a/drivers/firmware/qcom_scm.h
+++ b/drivers/firmware/qcom_scm.h
@@ -4,6 +4,15 @@
 #ifndef __QCOM_SCM_INT_H
 #define __QCOM_SCM_INT_H
 
+enum qcom_scm_convention {
+	SMC_CONVENTION_UNKNOWN,
+	SMC_CONVENTION_LEGACY,
+	SMC_CONVENTION_ARM_32,
+	SMC_CONVENTION_ARM_64,
+};
+
+extern enum qcom_scm_convention qcom_scm_convention;
+
 #define MAX_QCOM_SCM_ARGS 10
 #define MAX_QCOM_SCM_RETS 3
 
@@ -44,8 +53,14 @@ struct qcom_scm_desc {
 	u32 owner;
 };
 
-extern int qcom_scm_call(struct device *dev, struct qcom_scm_desc *desc);
-extern int qcom_scm_call_atomic(struct device *dev, struct qcom_scm_desc *desc);
+#define SMCCC_FUNCNUM(s, c)	((((s) & 0xFF) << 8) | ((c) & 0xFF))
+extern int qcom_scm_call_smccc(struct device *dev, struct qcom_scm_desc *desc,
+			       bool atomic);
+
+#define LEGACY_FUNCNUM(s, c)	(((s) << 10) | ((c) & 0x3ff))
+extern int qcom_scm_call_legacy_atomic(struct device *dev,
+				       struct qcom_scm_desc *desc);
+extern int qcom_scm_call_legacy(struct device *dev, struct qcom_scm_desc *desc);
 
 #define QCOM_SCM_SVC_BOOT		0x1
 #define QCOM_SCM_BOOT_SET_ADDR		0x1
@@ -61,14 +76,10 @@ extern int qcom_scm_call_atomic(struct device *dev, struct qcom_scm_desc *desc);
 
 #define QCOM_SCM_SVC_INFO		0x6
 #define QCOM_SCM_INFO_IS_CALL_AVAIL	0x1
-extern int __qcom_scm_is_call_available(struct device *dev, u32 svc_id,
-		u32 cmd_id);
 
 #define QCOM_SCM_SVC_HDCP		0x11
 #define QCOM_SCM_HDCP_INVOKE		0x01
 
-extern void __qcom_scm_init(void);
-
 #define QCOM_SCM_SVC_PIL		0x2
 #define QCOM_SCM_PIL_PAS_INIT_IMAGE	0x1
 #define QCOM_SCM_PIL_PAS_MEM_SETUP	0x2
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


  parent reply	other threads:[~2019-11-12 21:23 UTC|newest]

Thread overview: 39+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-11-12 21:22 [PATCH v2 00/18] Restructure, improve target support for qcom_scm driver Elliot Berman
2019-11-12 21:22 ` [PATCH v2 01/18] firmware: qcom_scm: Rename macros and structures Elliot Berman
2019-11-15 23:27   ` Stephen Boyd
2019-11-16  1:19     ` eberman
2019-11-19 21:47       ` Stephen Boyd
2019-11-12 21:22 ` [PATCH v2 02/18] firmware: qcom_scm: Add funcnum IDs Elliot Berman
2019-11-15 23:30   ` Stephen Boyd
2019-11-12 21:22 ` [PATCH v2 03/18] firmware: qcom_scm-64: Make SMCCC macros less magical Elliot Berman
2019-11-15 22:43   ` Stephen Boyd
2019-11-12 21:22 ` [PATCH v2 04/18] firmware: qcom_scm: Apply consistent naming scheme to command IDs Elliot Berman
2019-11-15 22:45   ` Stephen Boyd
2019-11-12 21:22 ` [PATCH v2 05/18] firmware: qcom_scm: Remove unused qcom_scm_get_version Elliot Berman
2019-11-15 22:45   ` Stephen Boyd
2019-11-12 21:22 ` [PATCH v2 06/18] firmware: qcom_scm-64: Move svc/cmd/owner into qcom_scm_desc Elliot Berman
2019-11-15 23:40   ` Stephen Boyd
2019-11-12 21:22 ` [PATCH v2 07/18] firmware: qcom_scm-64: Add SCM results to descriptor Elliot Berman
2019-11-15 23:42   ` Stephen Boyd
2019-11-12 21:22 ` [PATCH v2 08/18] firmware: qcom_scm-64: Remove qcom_scm_call_do_smccc Elliot Berman
2019-11-15 23:45   ` Stephen Boyd
2019-11-12 21:22 ` [PATCH v2 09/18] firmware: qcom_scm-64: Move SMC register filling to qcom_scm_call_smccc Elliot Berman
2019-11-15 23:57   ` Stephen Boyd
2019-11-12 21:22 ` [PATCH v2 10/18] firmware: qcom_scm-64: Improve SMC convention detection Elliot Berman
2019-11-16  0:21   ` Stephen Boyd
2019-11-16  1:29     ` eberman
2019-11-19 21:49       ` Stephen Boyd
2019-11-12 21:22 ` [PATCH v2 11/18] firmware: qcom_scm-32: Use SMC arch wrappers Elliot Berman
2019-11-16  0:41   ` Stephen Boyd
2019-12-12 19:45     ` Elliot Berman
2019-11-12 21:22 ` [PATCH v2 12/18] firmware: qcom_scm-32: Use qcom_scm_desc in non-atomic calls Elliot Berman
2019-11-19 22:03   ` Stephen Boyd
2019-11-12 21:22 ` [PATCH v2 13/18] firmware: qcom_scm-32: Move SMCCC register filling to qcom_scm_call Elliot Berman
2019-11-19 22:05   ` Stephen Boyd
2019-11-12 21:22 ` [PATCH v2 14/18] firmware: qcom_scm-32: Create common legacy atomic call Elliot Berman
2019-11-19 22:11   ` Stephen Boyd
2019-11-12 21:22 ` [PATCH v2 15/18] firmware: qcom_scm-32: Add device argument to atomic calls Elliot Berman
2019-11-19 22:13   ` Stephen Boyd
2019-11-12 21:22 ` [PATCH v2 16/18] firmware: qcom_scm: Remove thin wrappers Elliot Berman
2019-11-12 21:22 ` Elliot Berman [this message]
2019-11-12 21:22 ` [PATCH v2 18/18] firmware: qcom_scm: Order functions, definitions by service/command Elliot Berman

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=1573593774-12539-18-git-send-email-eberman@codeaurora.org \
    --to=eberman@codeaurora.org \
    --cc=agross@kernel.org \
    --cc=bjorn.andersson@linaro.org \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=psodagud@codeaurora.org \
    --cc=saiprakash.ranjan@codeaurora.org \
    --cc=sidgup@codeaurora.org \
    --cc=swboyd@chromium.org \
    --cc=tsoni@codeaurora.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 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).