From: "Ilpo Järvinen" <ilpo.jarvinen@linux.intel.com>
To: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
Cc: Hans de Goede <hansg@kernel.org>,
platform-driver-x86@vger.kernel.org, mario.limonciello@amd.com,
Sanket.Goswami@amd.com
Subject: Re: [PATCH v2 1/2] platform/x86/amd/pmc: Use per-SoC cpu_info struct for SMU mailbox and IP info
Date: Mon, 8 Jun 2026 12:08:55 +0300 (EEST) [thread overview]
Message-ID: <d18cbafc-fd11-c3f9-db5f-4976ba26e711@linux.intel.com> (raw)
In-Reply-To: <20260601112103.1690951-2-Shyam-sundar.S-k@amd.com>
On Mon, 1 Jun 2026, Shyam Sundar S K wrote:
> Replace the scattered per-field assignments in amd_pmc_get_ip_info() and
> amd_pmc_get_os_hint() with a single amd_pmc_cpu_info struct capturing all
> SoC-specific parameters such as SMU offsets, IP block table, and OS hint.
>
> Define static const instances per SoC variant and embed them as
> driver_data in the PCI ID table via PCI_DEVICE_DATA(), avoiding runtime
> switch statements. Store a pointer in amd_pmc_dev replacing the individual
> smu_msg, num_ips, and ips_ptr fields, SMU send/receive paths and debugfs
> iterator dereference through it. For the 1Ah M70 variant requiring
> boot_cpu_data.x86_model detection, fallback to amd_pmc_set_cpu_info().
>
> Also, rename AMD_CPU_ID_* to PCI_DEVICE_ID_AMD_CPU_ID_* with compatibility
> aliases.
>
> Co-developed-by: Sanket Goswami <Sanket.Goswami@amd.com>
> Signed-off-by: Sanket Goswami <Sanket.Goswami@amd.com>
> Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
> ---
> drivers/platform/x86/amd/pmc/pmc.c | 161 +++++++++++++++++++----------
> drivers/platform/x86/amd/pmc/pmc.h | 69 +++++++++----
> 2 files changed, 156 insertions(+), 74 deletions(-)
>
> diff --git a/drivers/platform/x86/amd/pmc/pmc.c b/drivers/platform/x86/amd/pmc/pmc.c
> index cae3fcafd4d7..6c7fa80c7f09 100644
> --- a/drivers/platform/x86/amd/pmc/pmc.c
> +++ b/drivers/platform/x86/amd/pmc/pmc.c
> @@ -85,6 +85,52 @@ static const struct amd_pmc_bit_map soc15_ip_blk[] = {
> {"VPE", BIT(21)},
> };
>
> +/* CPU info structures for different SoC variants */
> +static const struct amd_pmc_cpu_info amd_pco_cpu_info = {
> + .smu_msg = AMD_PMC_REGISTER_MESSAGE,
> + .smu_arg = AMD_PMC_REGISTER_ARGUMENT,
> + .smu_rsp = AMD_PMC_REGISTER_RESPONSE,
> + .num_ips = 12,
> + .ips_ptr = soc15_ip_blk,
> + .os_hint = MSG_OS_HINT_PCO,
> +};
> +
> +static const struct amd_pmc_cpu_info amd_rn_cpu_info = {
> + .smu_msg = AMD_PMC_REGISTER_MESSAGE,
> + .smu_arg = AMD_PMC_REGISTER_ARGUMENT,
> + .smu_rsp = AMD_PMC_REGISTER_RESPONSE,
> + .num_ips = 12,
> + .ips_ptr = soc15_ip_blk,
> + .os_hint = MSG_OS_HINT_RN,
> +};
> +
> +static const struct amd_pmc_cpu_info amd_ps_cpu_info = {
> + .smu_msg = AMD_PMC_REGISTER_MESSAGE,
> + .smu_arg = AMD_PMC_REGISTER_ARGUMENT,
> + .smu_rsp = AMD_PMC_REGISTER_RESPONSE,
> + .num_ips = 21,
> + .ips_ptr = soc15_ip_blk,
> + .os_hint = MSG_OS_HINT_RN,
> +};
> +
> +static const struct amd_pmc_cpu_info amd_1ah_cpu_info = {
> + .smu_msg = AMD_PMC_REGISTER_MSG_1AH_20H,
> + .smu_arg = AMD_PMC_REGISTER_ARGUMENT,
> + .smu_rsp = AMD_PMC_REGISTER_RESPONSE,
> + .num_ips = ARRAY_SIZE(soc15_ip_blk),
> + .ips_ptr = soc15_ip_blk,
> + .os_hint = MSG_OS_HINT_RN,
> +};
> +
> +static const struct amd_pmc_cpu_info amd_1ah_m70_cpu_info = {
> + .smu_msg = AMD_PMC_REGISTER_MSG_1AH_20H,
> + .smu_arg = AMD_PMC_REGISTER_ARGUMENT,
> + .smu_rsp = AMD_PMC_REGISTER_RESPONSE,
> + .num_ips = ARRAY_SIZE(soc15_ip_blk_v2),
> + .ips_ptr = soc15_ip_blk_v2,
> + .os_hint = MSG_OS_HINT_RN,
> +};
> +
> static bool disable_workarounds;
> module_param(disable_workarounds, bool, 0644);
> MODULE_PARM_DESC(disable_workarounds, "Disable workarounds for platform bugs");
> @@ -101,35 +147,37 @@ static inline void amd_pmc_reg_write(struct amd_pmc_dev *dev, int reg_offset, u3
> iowrite32(val, dev->regbase + reg_offset);
> }
>
> -static void amd_pmc_get_ip_info(struct amd_pmc_dev *dev)
> +static void amd_pmc_set_cpu_info(struct amd_pmc_dev *dev)
> {
> + const struct amd_pmc_cpu_info *info = NULL;
> +
> switch (dev->cpu_id) {
> case AMD_CPU_ID_PCO:
> + info = &amd_pco_cpu_info;
> + break;
> case AMD_CPU_ID_RN:
> case AMD_CPU_ID_VG:
> case AMD_CPU_ID_YC:
> case AMD_CPU_ID_CB:
> - dev->num_ips = 12;
> - dev->ips_ptr = soc15_ip_blk;
> - dev->smu_msg = 0x538;
> + info = &amd_rn_cpu_info;
> break;
> case AMD_CPU_ID_PS:
> - dev->num_ips = 21;
> - dev->ips_ptr = soc15_ip_blk;
> - dev->smu_msg = 0x538;
> + info = &amd_ps_cpu_info;
Are these actually needed, can't the code be reorganized so here we do
only:
id = pci_match_id(pmc_pci_ids, rdev);
if (!id)
return -ENODEV;
if (id->driver_data) {
dev->cpu_info = id->driver_data;
return 0;
}
switch (...) {
> case PCI_DEVICE_ID_AMD_1AH_M20H_ROOT:
> case PCI_DEVICE_ID_AMD_1AH_M60H_ROOT:
> - if (boot_cpu_data.x86_model == 0x70) {
> - dev->num_ips = ARRAY_SIZE(soc15_ip_blk_v2);
> - dev->ips_ptr = soc15_ip_blk_v2;
> - } else {
> - dev->num_ips = ARRAY_SIZE(soc15_ip_blk);
> - dev->ips_ptr = soc15_ip_blk;
> - }
> - dev->smu_msg = 0x938;
> + /* Special case: check x86_model for M70 variant */
> + if (boot_cpu_data.x86_model == 0x70)
> + info = &amd_1ah_m70_cpu_info;
> + else
> + info = &amd_1ah_cpu_info;
Just assign directly to dev->cpu_info.
> break;
> + default:
> + dev_err(dev->dev, "Unknown CPU ID: 0x%x\n", dev->cpu_id);
> + return;
> }
> +
> + dev->cpu_info = info;
> }
>
> static int amd_pmc_setup_smu_logging(struct amd_pmc_dev *dev)
> @@ -296,9 +344,9 @@ static int smu_fw_info_show(struct seq_file *s, void *unused)
> table.timeto_resume_to_os_lastcapture);
>
> seq_puts(s, "\n=== Active time (in us) ===\n");
> - for (idx = 0 ; idx < dev->num_ips ; idx++) {
> - if (dev->ips_ptr[idx].bit_mask & dev->active_ips)
> - seq_printf(s, "%-8s : %lld\n", dev->ips_ptr[idx].name,
> + for (idx = 0 ; idx < dev->cpu_info->num_ips ; idx++) {
> + if (dev->cpu_info->ips_ptr[idx].bit_mask & dev->active_ips)
> + seq_printf(s, "%-8s : %lld\n", dev->cpu_info->ips_ptr[idx].name,
> table.timecondition_notmet_lastcapture[idx]);
> }
>
> @@ -425,9 +473,9 @@ static void amd_pmc_dump_registers(struct amd_pmc_dev *dev)
> argument = dev->stb_arg.arg;
> response = dev->stb_arg.resp;
> } else {
> - message = dev->smu_msg;
> - argument = AMD_PMC_REGISTER_ARGUMENT;
> - response = AMD_PMC_REGISTER_RESPONSE;
> + message = dev->cpu_info->smu_msg;
> + argument = dev->cpu_info->smu_arg;
> + response = dev->cpu_info->smu_rsp;
> }
>
> value = amd_pmc_reg_read(dev, response);
> @@ -452,9 +500,9 @@ int amd_pmc_send_cmd(struct amd_pmc_dev *dev, u32 arg, u32 *data, u8 msg, bool r
> argument = dev->stb_arg.arg;
> response = dev->stb_arg.resp;
> } else {
> - message = dev->smu_msg;
> - argument = AMD_PMC_REGISTER_ARGUMENT;
> - response = AMD_PMC_REGISTER_RESPONSE;
> + message = dev->cpu_info->smu_msg;
> + argument = dev->cpu_info->smu_arg;
> + response = dev->cpu_info->smu_rsp;
> }
>
> /* Wait until we get a valid response */
> @@ -514,19 +562,12 @@ int amd_pmc_send_cmd(struct amd_pmc_dev *dev, u32 arg, u32 *data, u8 msg, bool r
>
> static int amd_pmc_get_os_hint(struct amd_pmc_dev *dev)
> {
> - switch (dev->cpu_id) {
> - case AMD_CPU_ID_PCO:
> - return MSG_OS_HINT_PCO;
> - case AMD_CPU_ID_RN:
> - case AMD_CPU_ID_VG:
> - case AMD_CPU_ID_YC:
> - case AMD_CPU_ID_CB:
> - case AMD_CPU_ID_PS:
> - case PCI_DEVICE_ID_AMD_1AH_M20H_ROOT:
> - case PCI_DEVICE_ID_AMD_1AH_M60H_ROOT:
> - return MSG_OS_HINT_RN;
> + if (!dev->cpu_info) {
> + dev_err(dev->dev, "CPU info not initialized\n");
> + return -EINVAL;
> }
> - return -EINVAL;
> +
> + return dev->cpu_info->os_hint;
If there's always a cpu_info struct (see below), the whole function can be
removed and the caller just uses the ->cpu_info->os_hint directly.
> }
>
> static int amd_pmc_wa_irq1(struct amd_pmc_dev *pdev)
> @@ -710,18 +751,18 @@ static const struct dev_pm_ops amd_pmc_pm = {
> };
>
> static const struct pci_device_id pmc_pci_ids[] = {
> - { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_PS) },
> - { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_CB) },
> - { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_YC) },
> - { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_CZN) },
> - { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_RN) },
> - { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_PCO) },
> - { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_RV) },
> - { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_SP) },
> - { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_SHP) },
> - { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_VG) },
> - { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M20H_ROOT) },
> - { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M60H_ROOT) },
> + { PCI_DEVICE_DATA(AMD, CPU_ID_PCO, &amd_pco_cpu_info) },
> + { PCI_DEVICE_DATA(AMD, CPU_ID_RV, &amd_pco_cpu_info) },
> + { PCI_DEVICE_DATA(AMD, CPU_ID_RN, &amd_rn_cpu_info) },
> + { PCI_DEVICE_DATA(AMD, CPU_ID_CZN, &amd_rn_cpu_info) },
> + { PCI_DEVICE_DATA(AMD, CPU_ID_VG, &amd_rn_cpu_info) },
> + { PCI_DEVICE_DATA(AMD, CPU_ID_YC, &amd_rn_cpu_info) },
> + { PCI_DEVICE_DATA(AMD, CPU_ID_CB, &amd_rn_cpu_info) },
> + { PCI_DEVICE_DATA(AMD, CPU_ID_PS, &amd_ps_cpu_info) },
> + { PCI_DEVICE_DATA(AMD, CPU_ID_SP, NULL) },
> + { PCI_DEVICE_DATA(AMD, CPU_ID_SHP, NULL) },
I suggest you add a dummy entry for these two as well so we'll always
have a valid cpu_info struct.
> + { PCI_DEVICE_DATA(AMD, 1AH_M20H_ROOT, NULL) },
> + { PCI_DEVICE_DATA(AMD, 1AH_M60H_ROOT, NULL) },
> { }
> };
>
> @@ -729,6 +770,7 @@ static int amd_pmc_probe(struct platform_device *pdev)
> {
> struct amd_pmc_dev *dev = &pmc;
> struct pci_dev *rdev;
> + const struct pci_device_id *id;
> u32 base_addr_lo, base_addr_hi;
> u64 base_addr;
> int err;
> @@ -736,7 +778,13 @@ static int amd_pmc_probe(struct platform_device *pdev)
>
> dev->dev = &pdev->dev;
> rdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0));
> - if (!rdev || !pci_match_id(pmc_pci_ids, rdev)) {
> + if (!rdev) {
> + err = -ENODEV;
> + goto err_pci_dev_put;
FYI, there's also __free(pci_dev_put) but then you'll need to handle
no_free_ptr() on the success path which will require some reorganization
so my suggestion is to look at it after this series is done.
> + }
> +
> + id = pci_match_id(pmc_pci_ids, rdev);
> + if (!id) {
> err = -ENODEV;
> goto err_pci_dev_put;
> }
> @@ -749,6 +797,18 @@ static int amd_pmc_probe(struct platform_device *pdev)
> }
>
> dev->rdev = rdev;
> +
> + if (id->driver_data)
> + dev->cpu_info = (const struct amd_pmc_cpu_info *)id->driver_data;
IMO, this would be more logical to do inside amd_pmc_set_cpu_info().
> + else
> + amd_pmc_set_cpu_info(dev);
Perhaps this call can be moved earlier, so that pci_match_id() has to be
done only once inside it?
> + if (!dev->cpu_info) {
> + dev_err(dev->dev, "Failed to set CPU info\n");
> + err = -ENODEV;
> + goto err_pci_dev_put;
> + }
> +
> err = amd_smn_read(0, AMD_PMC_BASE_ADDR_LO, &val);
> if (err) {
> dev_err(dev->dev, "error reading 0x%x\n", AMD_PMC_BASE_ADDR_LO);
> @@ -778,9 +838,6 @@ static int amd_pmc_probe(struct platform_device *pdev)
> if (err)
> goto err_pci_dev_put;
>
> - /* Get num of IP blocks within the SoC */
> - amd_pmc_get_ip_info(dev);
> -
> platform_set_drvdata(pdev, dev);
> if (IS_ENABLED(CONFIG_SUSPEND)) {
> err = acpi_register_lps0_dev(&amd_pmc_s2idle_dev_ops);
> diff --git a/drivers/platform/x86/amd/pmc/pmc.h b/drivers/platform/x86/amd/pmc/pmc.h
> index fe3f53eb5955..0fd0ced21831 100644
> --- a/drivers/platform/x86/amd/pmc/pmc.h
> +++ b/drivers/platform/x86/amd/pmc/pmc.h
> @@ -17,6 +17,10 @@
> /* SMU communication registers */
> #define AMD_PMC_REGISTER_RESPONSE 0x980
> #define AMD_PMC_REGISTER_ARGUMENT 0x9BC
> +#define AMD_PMC_REGISTER_MESSAGE 0x538
> +
> +/* SMU communication registers for 1Ah 20h SoC */
> +#define AMD_PMC_REGISTER_MSG_1AH_20H 0x938
>
> /* PMC Scratch Registers */
> #define AMD_PMC_SCRATCH_REG_CZN 0x94
> @@ -90,6 +94,21 @@ struct stb_arg {
> u32 resp;
> };
>
> +struct amd_pmc_bit_map {
> + const char *name;
> + u32 bit_mask;
> +};
> +
> +/* SoC-specific information */
> +struct amd_pmc_cpu_info {
> + u32 smu_msg;
> + u32 smu_arg;
> + u32 smu_rsp;
> + u32 num_ips;
> + const struct amd_pmc_bit_map *ips_ptr;
> + int os_hint;
> +};
> +
> struct amd_pmc_dev {
> void __iomem *regbase;
> void __iomem *smu_virt_addr;
> @@ -99,9 +118,6 @@ struct amd_pmc_dev {
> u32 cpu_id;
> u32 dram_size;
> u32 active_ips;
> - const struct amd_pmc_bit_map *ips_ptr;
> - u32 num_ips;
> - u32 smu_msg;
> /* SMU version information */
> u8 smu_program;
> u8 major;
> @@ -116,11 +132,7 @@ struct amd_pmc_dev {
> bool disable_8042_wakeup;
> struct amd_mp2_dev *mp2;
> struct stb_arg stb_arg;
> -};
> -
> -struct amd_pmc_bit_map {
> - const char *name;
> - u32 bit_mask;
> + const struct amd_pmc_cpu_info *cpu_info;
> };
>
> struct smu_metrics {
> @@ -151,20 +163,33 @@ void amd_pmc_quirks_init(struct amd_pmc_dev *dev);
> void amd_mp2_stb_init(struct amd_pmc_dev *dev);
> void amd_mp2_stb_deinit(struct amd_pmc_dev *dev);
>
> -/* List of supported CPU ids */
> -#define AMD_CPU_ID_RV 0x15D0
> -#define AMD_CPU_ID_RN 0x1630
> -#define AMD_CPU_ID_PCO AMD_CPU_ID_RV
> -#define AMD_CPU_ID_CZN AMD_CPU_ID_RN
> -#define AMD_CPU_ID_VG 0x1645
> -#define AMD_CPU_ID_YC 0x14B5
> -#define AMD_CPU_ID_CB 0x14D8
> -#define AMD_CPU_ID_PS 0x14E8
> -#define AMD_CPU_ID_SP 0x14A4
> -#define AMD_CPU_ID_SHP 0x153A
> -#define PCI_DEVICE_ID_AMD_1AH_M20H_ROOT 0x1507
> -#define PCI_DEVICE_ID_AMD_1AH_M60H_ROOT 0x1122
> -#define PCI_DEVICE_ID_AMD_MP2_STB 0x172c
> +/* List of supported CPU/device IDs */
> +#define PCI_DEVICE_ID_AMD_CPU_ID_RV 0x15D0
> +#define PCI_DEVICE_ID_AMD_CPU_ID_RN 0x1630
> +#define PCI_DEVICE_ID_AMD_CPU_ID_PCO PCI_DEVICE_ID_AMD_CPU_ID_RV
> +#define PCI_DEVICE_ID_AMD_CPU_ID_CZN PCI_DEVICE_ID_AMD_CPU_ID_RN
> +#define PCI_DEVICE_ID_AMD_CPU_ID_VG 0x1645
> +#define PCI_DEVICE_ID_AMD_CPU_ID_YC 0x14B5
> +#define PCI_DEVICE_ID_AMD_CPU_ID_CB 0x14D8
> +#define PCI_DEVICE_ID_AMD_CPU_ID_PS 0x14E8
> +#define PCI_DEVICE_ID_AMD_CPU_ID_SP 0x14A4
> +#define PCI_DEVICE_ID_AMD_CPU_ID_SHP 0x153A
> +
> +/* Backward compatibility aliases */
> +#define AMD_CPU_ID_RV PCI_DEVICE_ID_AMD_CPU_ID_RV
> +#define AMD_CPU_ID_RN PCI_DEVICE_ID_AMD_CPU_ID_RN
> +#define AMD_CPU_ID_PCO PCI_DEVICE_ID_AMD_CPU_ID_PCO
> +#define AMD_CPU_ID_CZN PCI_DEVICE_ID_AMD_CPU_ID_CZN
> +#define AMD_CPU_ID_VG PCI_DEVICE_ID_AMD_CPU_ID_VG
> +#define AMD_CPU_ID_YC PCI_DEVICE_ID_AMD_CPU_ID_YC
> +#define AMD_CPU_ID_CB PCI_DEVICE_ID_AMD_CPU_ID_CB
> +#define AMD_CPU_ID_PS PCI_DEVICE_ID_AMD_CPU_ID_PS
> +#define AMD_CPU_ID_SP PCI_DEVICE_ID_AMD_CPU_ID_SP
> +#define AMD_CPU_ID_SHP PCI_DEVICE_ID_AMD_CPU_ID_SHP
> +
> +#define PCI_DEVICE_ID_AMD_1AH_M20H_ROOT 0x1507
> +#define PCI_DEVICE_ID_AMD_1AH_M60H_ROOT 0x1122
> +#define PCI_DEVICE_ID_AMD_MP2_STB 0x172c
>
> int amd_stb_s2d_init(struct amd_pmc_dev *dev);
> int amd_stb_read(struct amd_pmc_dev *dev, u32 *buf);
>
--
i.
next prev parent reply other threads:[~2026-06-08 9:09 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-01 11:21 [PATCH v2 0/2] platform/x86/amd/pmc: Add support for AMD 1Ah Family 80h SoC Shyam Sundar S K
2026-06-01 11:21 ` [PATCH v2 1/2] platform/x86/amd/pmc: Use per-SoC cpu_info struct for SMU mailbox and IP info Shyam Sundar S K
2026-06-08 9:08 ` Ilpo Järvinen [this message]
2026-06-09 5:54 ` Shyam Sundar S K
2026-06-09 8:13 ` Ilpo Järvinen
2026-06-01 11:21 ` [PATCH v2 2/2] platform/x86/amd/pmc: Add PMC driver support for AMD 1Ah M80H SoC Shyam Sundar S K
2026-06-08 9:18 ` Ilpo Järvinen
2026-06-09 7:23 ` Shyam Sundar S K
2026-06-02 13:58 ` [PATCH v2 0/2] platform/x86/amd/pmc: Add support for AMD 1Ah Family 80h SoC Mario Limonciello
2026-06-09 7:38 ` Shyam Sundar S K
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=d18cbafc-fd11-c3f9-db5f-4976ba26e711@linux.intel.com \
--to=ilpo.jarvinen@linux.intel.com \
--cc=Sanket.Goswami@amd.com \
--cc=Shyam-sundar.S-k@amd.com \
--cc=hansg@kernel.org \
--cc=mario.limonciello@amd.com \
--cc=platform-driver-x86@vger.kernel.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).