All of lore.kernel.org
 help / color / mirror / Atom feed
From: Michael Hanselmann <linux-kernel@hansmi.ch>
To: akpm@osdl.org
Cc: benh@kernel.crashing.org, johannes@sipsolutions.net,
	aris@valeta.org, linux-fbdev-devel@lists.sourceforge.net,
	linux-kernel@killerfox.forkbomb.ch
Subject: Locking fixes for powermac backlight infrastructure
Date: Sat, 8 Jul 2006 14:06:37 +0200	[thread overview]
Message-ID: <20060708120637.GA23909@hansmi.ch> (raw)

This patch fixes locking issues in the new powermac backlight
infrastructure as reported by Aristeu S. Rozanski F. <aris@valeta.org>.
It also fixes the wrong calculation of backlight values in some of the
drivers.

Signed-off-by: Michael Hanselmann <linux-kernel@hansmi.ch>
Acked-by: René Nussbaumer <linux-kernel@killerfox.forkbomb.ch>

---
diff -Nrup --exclude-from linux-exclude-from linux-2.6.18-rc1.orig/drivers/video/aty/aty128fb.c linux-2.6.18-rc1/drivers/video/aty/aty128fb.c
--- linux-2.6.18-rc1.orig/drivers/video/aty/aty128fb.c	2006-07-08 12:27:09.000000000 +0200
+++ linux-2.6.18-rc1/drivers/video/aty/aty128fb.c	2006-07-08 12:28:32.000000000 +0200
@@ -456,6 +456,7 @@ static void do_wait_for_fifo(u16 entries
 static void wait_for_fifo(u16 entries, struct aty128fb_par *par);
 static void wait_for_idle(struct aty128fb_par *par);
 static u32 depth_to_dst(u32 depth);
+static void aty128_bl_set_power(struct fb_info *info, int power);
 
 #define BIOS_IN8(v)  	(readb(bios + (v)))
 #define BIOS_IN16(v) 	(readb(bios + (v)) | \
@@ -1258,25 +1259,11 @@ static void aty128_set_lcd_enable(struct
 		reg &= ~LVDS_DISPLAY_DIS;
 		aty_st_le32(LVDS_GEN_CNTL, reg);
 #ifdef CONFIG_FB_ATY128_BACKLIGHT
-		mutex_lock(&info->bl_mutex);
-		if (info->bl_dev) {
-			down(&info->bl_dev->sem);
-			info->bl_dev->props->update_status(info->bl_dev);
-			up(&info->bl_dev->sem);
-		}
-		mutex_unlock(&info->bl_mutex);
+		aty128_bl_set_power(info, FB_BLANK_UNBLANK);
 #endif	
 	} else {
 #ifdef CONFIG_FB_ATY128_BACKLIGHT
-		mutex_lock(&info->bl_mutex);
-		if (info->bl_dev) {
-			down(&info->bl_dev->sem);
-			info->bl_dev->props->brightness = 0;
-			info->bl_dev->props->power = FB_BLANK_POWERDOWN;
-			info->bl_dev->props->update_status(info->bl_dev);
-			up(&info->bl_dev->sem);
-		}
-		mutex_unlock(&info->bl_mutex);
+		aty128_bl_set_power(info, FB_BLANK_POWERDOWN);
 #endif	
 		reg = aty_ld_le32(LVDS_GEN_CNTL);
 		reg |= LVDS_DISPLAY_DIS;
@@ -1703,6 +1690,7 @@ static int __devinit aty128fb_setup(char
 
 static struct backlight_properties aty128_bl_data;
 
+/* Call with fb_info->bl_mutex held */
 static int aty128_bl_get_level_brightness(struct aty128fb_par *par,
 		int level)
 {
@@ -1710,10 +1698,8 @@ static int aty128_bl_get_level_brightnes
 	int atylevel;
 
 	/* Get and convert the value */
-	mutex_lock(&info->bl_mutex);
 	atylevel = MAX_LEVEL -
 		(info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL);
-	mutex_unlock(&info->bl_mutex);
 
 	if (atylevel < 0)
 		atylevel = 0;
@@ -1731,7 +1717,8 @@ static int aty128_bl_get_level_brightnes
 /* That one prevents proper CRT output with LCD off */
 #undef BACKLIGHT_DAC_OFF
 
-static int aty128_bl_update_status(struct backlight_device *bd)
+/* Call with fb_info->bl_mutex held */
+static int __aty128_bl_update_status(struct backlight_device *bd)
 {
 	struct aty128fb_par *par = class_get_devdata(&bd->class_dev);
 	unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL);
@@ -1784,6 +1771,19 @@ static int aty128_bl_update_status(struc
 	return 0;
 }
 
+static int aty128_bl_update_status(struct backlight_device *bd)
+{
+	struct aty128fb_par *par = class_get_devdata(&bd->class_dev);
+	struct fb_info *info = pci_get_drvdata(par->pdev);
+	int ret;
+
+	mutex_lock(&info->bl_mutex);
+	ret = __aty128_bl_update_status(bd);
+	mutex_unlock(&info->bl_mutex);
+
+	return ret;
+}
+
 static int aty128_bl_get_brightness(struct backlight_device *bd)
 {
 	return bd->props->brightness;
@@ -1796,6 +1796,16 @@ static struct backlight_properties aty12
 	.max_brightness	= (FB_BACKLIGHT_LEVELS - 1),
 };
 
+static void aty128_bl_set_power(struct fb_info *info, int power)
+{
+	mutex_lock(&info->bl_mutex);
+	up(&info->bl_dev->sem);
+	info->bl_dev->props->power = power;
+	__aty128_bl_update_status(info->bl_dev);
+	down(&info->bl_dev->sem);
+	mutex_unlock(&info->bl_mutex);
+}
+
 static void aty128_bl_init(struct aty128fb_par *par)
 {
 	struct fb_info *info = pci_get_drvdata(par->pdev);
@@ -2198,12 +2208,8 @@ static int aty128fb_blank(int blank, str
 		return 0;
 
 #ifdef CONFIG_FB_ATY128_BACKLIGHT
-	if (machine_is(powermac) && blank) {
-		down(&fb->bl_dev->sem);
-		fb->bl_dev->props->power = FB_BLANK_POWERDOWN;
-		fb->bl_dev->props->update_status(fb->bl_dev);
-		up(&fb->bl_dev->sem);
-	}
+	if (machine_is(powermac) && blank)
+		aty128_bl_set_power(fb, FB_BLANK_POWERDOWN);
 #endif
 
 	if (blank & FB_BLANK_VSYNC_SUSPEND)
@@ -2219,14 +2225,12 @@ static int aty128fb_blank(int blank, str
 		aty128_set_crt_enable(par, par->crt_on && !blank);
 		aty128_set_lcd_enable(par, par->lcd_on && !blank);
 	}
+
 #ifdef CONFIG_FB_ATY128_BACKLIGHT
-	if (machine_is(powermac) && !blank) {
-		down(&fb->bl_dev->sem);
-		fb->bl_dev->props->power = FB_BLANK_UNBLANK;
-		fb->bl_dev->props->update_status(fb->bl_dev);
-		up(&fb->bl_dev->sem);
-	}
+	if (machine_is(powermac) && !blank)
+		aty128_bl_set_power(fb, FB_BLANK_UNBLANK);
 #endif
+
 	return 0;
 }
 
diff -Nrup --exclude-from linux-exclude-from linux-2.6.18-rc1.orig/drivers/video/aty/atyfb_base.c linux-2.6.18-rc1/drivers/video/aty/atyfb_base.c
--- linux-2.6.18-rc1.orig/drivers/video/aty/atyfb_base.c	2006-07-08 12:27:09.000000000 +0200
+++ linux-2.6.18-rc1/drivers/video/aty/atyfb_base.c	2006-07-08 12:28:32.000000000 +0200
@@ -2129,15 +2129,14 @@ static int atyfb_pci_resume(struct pci_d
 
 static struct backlight_properties aty_bl_data;
 
+/* Call with fb_info->bl_mutex held */
 static int aty_bl_get_level_brightness(struct atyfb_par *par, int level)
 {
 	struct fb_info *info = pci_get_drvdata(par->pdev);
 	int atylevel;
 
 	/* Get and convert the value */
-	mutex_lock(&info->bl_mutex);
 	atylevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL;
-	mutex_unlock(&info->bl_mutex);
 
 	if (atylevel < 0)
 		atylevel = 0;
@@ -2147,7 +2146,8 @@ static int aty_bl_get_level_brightness(s
 	return atylevel;
 }
 
-static int aty_bl_update_status(struct backlight_device *bd)
+/* Call with fb_info->bl_mutex held */
+static int __aty_bl_update_status(struct backlight_device *bd)
 {
 	struct atyfb_par *par = class_get_devdata(&bd->class_dev);
 	unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, par);
@@ -2172,6 +2172,19 @@ static int aty_bl_update_status(struct b
 	return 0;
 }
 
+static int aty_bl_update_status(struct backlight_device *bd)
+{
+	struct atyfb_par *par = class_get_devdata(&bd->class_dev);
+	struct fb_info *info = pci_get_drvdata(par->pdev);
+	int ret;
+
+	mutex_lock(&info->bl_mutex);
+	ret = __aty_bl_update_status(bd);
+	mutex_unlock(&info->bl_mutex);
+
+	return ret;
+}
+
 static int aty_bl_get_brightness(struct backlight_device *bd)
 {
 	return bd->props->brightness;
@@ -2184,6 +2197,16 @@ static struct backlight_properties aty_b
 	.max_brightness = (FB_BACKLIGHT_LEVELS - 1),
 };
 
+static void aty_bl_set_power(struct fb_info *info, int power)
+{
+	mutex_lock(&info->bl_mutex);
+	up(&info->bl_dev->sem);
+	info->bl_dev->props->power = power;
+	__aty_bl_update_status(info->bl_dev);
+	down(&info->bl_dev->sem);
+	mutex_unlock(&info->bl_mutex);
+}
+
 static void aty_bl_init(struct atyfb_par *par)
 {
 	struct fb_info *info = pci_get_drvdata(par->pdev);
@@ -2790,16 +2813,8 @@ static int atyfb_blank(int blank, struct
 		return 0;
 
 #ifdef CONFIG_PMAC_BACKLIGHT
-	if (machine_is(powermac) && blank > FB_BLANK_NORMAL) {
-		mutex_lock(&info->bl_mutex);
-		if (info->bl_dev) {
-			down(&info->bl_dev->sem);
-			info->bl_dev->props->power = FB_BLANK_POWERDOWN;
-			info->bl_dev->props->update_status(info->bl_dev);
-			up(&info->bl_dev->sem);
-		}
-		mutex_unlock(&info->bl_mutex);
-	}
+	if (machine_is(powermac) && blank > FB_BLANK_NORMAL)
+		aty_bl_set_power(info, FB_BLANK_POWERDOWN);
 #elif defined(CONFIG_FB_ATY_GENERIC_LCD)
 	if (par->lcd_table && blank > FB_BLANK_NORMAL &&
 	    (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {
@@ -2830,16 +2845,8 @@ static int atyfb_blank(int blank, struct
 	aty_st_le32(CRTC_GEN_CNTL, gen_cntl, par);
 
 #ifdef CONFIG_PMAC_BACKLIGHT
-	if (machine_is(powermac) && blank <= FB_BLANK_NORMAL) {
-		mutex_lock(&info->bl_mutex);
-		if (info->bl_dev) {
-			down(&info->bl_dev->sem);
-			info->bl_dev->props->power = FB_BLANK_UNBLANK;
-			info->bl_dev->props->update_status(info->bl_dev);
-			up(&info->bl_dev->sem);
-		}
-		mutex_unlock(&info->bl_mutex);
-	}
+	if (machine_is(powermac) && blank <= FB_BLANK_NORMAL)
+		aty_bl_set_power(info, FB_BLANK_UNBLANK);
 #elif defined(CONFIG_FB_ATY_GENERIC_LCD)
 	if (par->lcd_table && blank <= FB_BLANK_NORMAL &&
 	    (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {
diff -Nrup --exclude-from linux-exclude-from linux-2.6.18-rc1.orig/drivers/video/chipsfb.c linux-2.6.18-rc1/drivers/video/chipsfb.c
--- linux-2.6.18-rc1.orig/drivers/video/chipsfb.c	2006-07-08 12:27:08.000000000 +0200
+++ linux-2.6.18-rc1/drivers/video/chipsfb.c	2006-07-08 12:28:32.000000000 +0200
@@ -150,12 +150,11 @@ static int chipsfb_blank(int blank, stru
 	mutex_lock(&pmac_backlight_mutex);
 
 	if (pmac_backlight) {
-		down(&pmac_backlight->sem);
-
 		/* used to disable backlight only for blank > 1, but it seems
 		 * useful at blank = 1 too (saves battery, extends backlight
 		 * life)
 	 	 */
+		down(&pmac_backlight->sem);
 		if (blank)
 			pmac_backlight->props->power = FB_BLANK_POWERDOWN;
 		else
diff -Nrup --exclude-from linux-exclude-from linux-2.6.18-rc1.orig/drivers/video/nvidia/nv_backlight.c linux-2.6.18-rc1/drivers/video/nvidia/nv_backlight.c
--- linux-2.6.18-rc1.orig/drivers/video/nvidia/nv_backlight.c	2006-07-08 12:27:09.000000000 +0200
+++ linux-2.6.18-rc1/drivers/video/nvidia/nv_backlight.c	2006-07-08 12:28:32.000000000 +0200
@@ -26,9 +26,11 @@
  */
 #define MIN_LEVEL 0x158
 #define MAX_LEVEL 0x534
+#define LEVEL_STEP ((MAX_LEVEL - MIN_LEVEL) / FB_BACKLIGHT_MAX)
 
 static struct backlight_properties nvidia_bl_data;
 
+/* Call with fb_info->bl_mutex held */
 static int nvidia_bl_get_level_brightness(struct nvidia_par *par,
 		int level)
 {
@@ -36,9 +38,7 @@ static int nvidia_bl_get_level_brightnes
 	int nlevel;
 
 	/* Get and convert the value */
-	mutex_lock(&info->bl_mutex);
-	nlevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL;
-	mutex_unlock(&info->bl_mutex);
+	nlevel = MIN_LEVEL + info->bl_curve[level] * LEVEL_STEP;
 
 	if (nlevel < 0)
 		nlevel = 0;
@@ -50,7 +50,8 @@ static int nvidia_bl_get_level_brightnes
 	return nlevel;
 }
 
-static int nvidia_bl_update_status(struct backlight_device *bd)
+/* Call with fb_info->bl_mutex held */
+static int __nvidia_bl_update_status(struct backlight_device *bd)
 {
 	struct nvidia_par *par = class_get_devdata(&bd->class_dev);
 	u32 tmp_pcrt, tmp_pmc, fpcontrol;
@@ -84,6 +85,19 @@ static int nvidia_bl_update_status(struc
 	return 0;
 }
 
+static int nvidia_bl_update_status(struct backlight_device *bd)
+{
+	struct nvidia_par *par = class_get_devdata(&bd->class_dev);
+	struct fb_info *info = pci_get_drvdata(par->pci_dev);
+	int ret;
+
+	mutex_lock(&info->bl_mutex);
+	ret = __nvidia_bl_update_status(bd);
+	mutex_unlock(&info->bl_mutex);
+
+	return ret;
+}
+
 static int nvidia_bl_get_brightness(struct backlight_device *bd)
 {
 	return bd->props->brightness;
@@ -96,6 +110,16 @@ static struct backlight_properties nvidi
 	.max_brightness = (FB_BACKLIGHT_LEVELS - 1),
 };
 
+void nvidia_bl_set_power(struct fb_info *info, int power)
+{
+	mutex_lock(&info->bl_mutex);
+	up(&info->bl_dev->sem);
+	info->bl_dev->props->power = power;
+	__nvidia_bl_update_status(info->bl_dev);
+	down(&info->bl_dev->sem);
+	mutex_unlock(&info->bl_mutex);
+}
+
 void nvidia_bl_init(struct nvidia_par *par)
 {
 	struct fb_info *info = pci_get_drvdata(par->pci_dev);
diff -Nrup --exclude-from linux-exclude-from linux-2.6.18-rc1.orig/drivers/video/nvidia/nvidia.c linux-2.6.18-rc1/drivers/video/nvidia/nvidia.c
--- linux-2.6.18-rc1.orig/drivers/video/nvidia/nvidia.c	2006-07-08 12:27:09.000000000 +0200
+++ linux-2.6.18-rc1/drivers/video/nvidia/nvidia.c	2006-07-08 12:28:32.000000000 +0200
@@ -933,16 +933,7 @@ static int nvidiafb_blank(int blank, str
 	NVWriteSeq(par, 0x01, tmp);
 	NVWriteCrtc(par, 0x1a, vesa);
 
-#ifdef CONFIG_FB_NVIDIA_BACKLIGHT
-	mutex_lock(&info->bl_mutex);
-	if (info->bl_dev) {
-		down(&info->bl_dev->sem);
-		info->bl_dev->props->power = blank;
-		info->bl_dev->props->update_status(info->bl_dev);
-		up(&info->bl_dev->sem);
-	}
-	mutex_unlock(&info->bl_mutex);
-#endif
+	nvidia_bl_set_power(info, blank);
 
 	NVTRACE_LEAVE();
 
diff -Nrup --exclude-from linux-exclude-from linux-2.6.18-rc1.orig/drivers/video/nvidia/nv_proto.h linux-2.6.18-rc1/drivers/video/nvidia/nv_proto.h
--- linux-2.6.18-rc1.orig/drivers/video/nvidia/nv_proto.h	2006-07-08 12:27:09.000000000 +0200
+++ linux-2.6.18-rc1/drivers/video/nvidia/nv_proto.h	2006-07-08 12:28:32.000000000 +0200
@@ -68,9 +68,11 @@ extern u8 byte_rev[256];
 #ifdef CONFIG_FB_NVIDIA_BACKLIGHT
 extern void nvidia_bl_init(struct nvidia_par *par);
 extern void nvidia_bl_exit(struct nvidia_par *par);
+extern void nvidia_bl_set_power(struct fb_info *info, int power);
 #else
 static inline void nvidia_bl_init(struct nvidia_par *par) {}
 static inline void nvidia_bl_exit(struct nvidia_par *par) {}
+static inline void nvidia_bl_set_power(struct fb_info *info, int power) {}
 #endif
 
 #endif				/* __NV_PROTO_H__ */
diff -Nrup --exclude-from linux-exclude-from linux-2.6.18-rc1.orig/drivers/video/riva/fbdev.c linux-2.6.18-rc1/drivers/video/riva/fbdev.c
--- linux-2.6.18-rc1.orig/drivers/video/riva/fbdev.c	2006-07-08 12:27:08.000000000 +0200
+++ linux-2.6.18-rc1/drivers/video/riva/fbdev.c	2006-07-08 12:28:32.000000000 +0200
@@ -278,9 +278,11 @@ static const struct riva_regs reg_templa
  */
 #define MIN_LEVEL 0x158
 #define MAX_LEVEL 0x534
+#define LEVEL_STEP ((MAX_LEVEL - MIN_LEVEL) / FB_BACKLIGHT_MAX)
 
 static struct backlight_properties riva_bl_data;
 
+/* Call with fb_info->bl_mutex held */
 static int riva_bl_get_level_brightness(struct riva_par *par,
 		int level)
 {
@@ -288,9 +290,7 @@ static int riva_bl_get_level_brightness(
 	int nlevel;
 
 	/* Get and convert the value */
-	mutex_lock(&info->bl_mutex);
-	nlevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL;
-	mutex_unlock(&info->bl_mutex);
+	nlevel = MIN_LEVEL + info->bl_curve[level] * LEVEL_STEP;
 
 	if (nlevel < 0)
 		nlevel = 0;
@@ -302,7 +302,8 @@ static int riva_bl_get_level_brightness(
 	return nlevel;
 }
 
-static int riva_bl_update_status(struct backlight_device *bd)
+/* Call with fb_info->bl_mutex held */
+static int __riva_bl_update_status(struct backlight_device *bd)
 {
 	struct riva_par *par = class_get_devdata(&bd->class_dev);
 	U032 tmp_pcrt, tmp_pmc;
@@ -327,6 +328,19 @@ static int riva_bl_update_status(struct 
 	return 0;
 }
 
+static int riva_bl_update_status(struct backlight_device *bd)
+{
+	struct riva_par *par = class_get_devdata(&bd->class_dev);
+	struct fb_info *info = pci_get_drvdata(par->pdev);
+	int ret;
+
+	mutex_lock(&info->bl_mutex);
+	ret = __riva_bl_update_status(bd);
+	mutex_unlock(&info->bl_mutex);
+
+	return ret;
+}
+
 static int riva_bl_get_brightness(struct backlight_device *bd)
 {
 	return bd->props->brightness;
@@ -339,6 +353,16 @@ static struct backlight_properties riva_
 	.max_brightness = (FB_BACKLIGHT_LEVELS - 1),
 };
 
+static void riva_bl_set_power(struct fb_info *info, int power)
+{
+	mutex_lock(&info->bl_mutex);
+	up(&info->bl_dev->sem);
+	info->bl_dev->props->power = power;
+	__riva_bl_update_status(info->bl_dev);
+	down(&info->bl_dev->sem);
+	mutex_unlock(&info->bl_mutex);
+}
+
 static void riva_bl_init(struct riva_par *par)
 {
 	struct fb_info *info = pci_get_drvdata(par->pdev);
@@ -419,6 +443,7 @@ static void riva_bl_exit(struct riva_par
 #else
 static inline void riva_bl_init(struct riva_par *par) {}
 static inline void riva_bl_exit(struct riva_par *par) {}
+static inline void riva_bl_set_power(struct fb_info *info, int power) {}
 #endif /* CONFIG_FB_RIVA_BACKLIGHT */
 
 /* ------------------------------------------------------------------------- *
@@ -1337,16 +1362,7 @@ static int rivafb_blank(int blank, struc
 	SEQout(par, 0x01, tmp);
 	CRTCout(par, 0x1a, vesa);
 
-#ifdef CONFIG_FB_RIVA_BACKLIGHT
-	mutex_lock(&info->bl_mutex);
-	if (info->bl_dev) {
-		down(&info->bl_dev->sem);
-		info->bl_dev->props->power = blank;
-		info->bl_dev->props->update_status(info->bl_dev);
-		up(&info->bl_dev->sem);
-	}
-	mutex_unlock(&info->bl_mutex);
-#endif
+	riva_bl_set_power(info, blank);
 
 	NVTRACE_LEAVE();
 

Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
Linux-fbdev-devel mailing list
Linux-fbdev-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-fbdev-devel

                 reply	other threads:[~2006-07-08 12:06 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

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=20060708120637.GA23909@hansmi.ch \
    --to=linux-kernel@hansmi.ch \
    --cc=akpm@osdl.org \
    --cc=aris@valeta.org \
    --cc=benh@kernel.crashing.org \
    --cc=johannes@sipsolutions.net \
    --cc=linux-fbdev-devel@lists.sourceforge.net \
    --cc=linux-kernel@killerfox.forkbomb.ch \
    /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.