All of lore.kernel.org
 help / color / mirror / Atom feed
* hardcoded maximum number of CFI chips - continued
@ 2003-07-21 13:04 andrzej.mialkowski
  2003-07-21 16:04 ` Jörn Engel
  0 siblings, 1 reply; 6+ messages in thread
From: andrzej.mialkowski @ 2003-07-21 13:04 UTC (permalink / raw)
  To: Jörn Engel; +Cc: linux-mtd


Due to e-mail configuration problems I'm not able to continue on previous 
thread.

Jörn,
  You of course right that limit proposed in patch too high. With current 
typical stack size (8K) and structure size (36 bytes - on ARM) it is safe to 
handle this way about 160 chips. This is much more what can be expected in 
resonable designs (and what I need). On the other hand placing kmalloc for 
chips structure effectively leeds to solution with realloc. Drawback of this 
will be creation of heap fragment, it also still has problem with the constant 
limit.
For me attractive are two solutions:
1) Cleaned previous proposal, becuse it is simple and solves problem probably 
fits for all designs.
2) Rewrite genprobe_ident_chips to use realloc emulation to allow expansion 
structure and handling any number of chips.

Andrzej

diff -Nru --minimal prev/drivers/mtd/chips/Config.in 
linux/drivers/mtd/chips/Config.in
--- prev/drivers/mtd/chips/Config.in	Fri Mar 14 17:21:15 2003
+++ linux/drivers/mtd/chips/Config.in	Mon Jul 21 14:23:49 2003
@@ -40,6 +40,7 @@
        bool '    Support 4-chip flash interleave' CONFIG_MTD_CFI_I4
        bool '    Support 8-chip flash interleave' CONFIG_MTD_CFI_I8
      fi
+     int '  Maximum number of flash chips' CONFIG_MTD_CFI_MAX_CHIPS 8 1 32
   fi
 fi
 dep_tristate '  Support for Intel/Sharp flash chips' CONFIG_MTD_CFI_INTELEXT 
$CONFIG_MTD_GEN_PROBE
diff -Nru --minimal prev/include/linux/mtd/cfi.h linux/include/linux/mtd/cfi.h
--- prev/include/linux/mtd/cfi.h	Fri Mar 14 17:05:39 2003
+++ linux/include/linux/mtd/cfi.h	Mon Jul 21 14:22:38 2003
@@ -306,7 +306,11 @@
 	struct flchip chips[0];  /* per-chip data structure for each chip */
 };
 
+#ifndef CONFIG_MTD_CFI_MAX_CHIPS
 #define MAX_CFI_CHIPS 8 /* Entirely arbitrary to avoid realloc() */
+#else
+#define MAX_CFI_CHIPS CONFIG_MTD_CFI_MAX_CHIPS
+#endif
 
 /*
  * Returns the command address according to the given geometry. 

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: hardcoded maximum number of CFI chips - continued
  2003-07-21 13:04 hardcoded maximum number of CFI chips - continued andrzej.mialkowski
@ 2003-07-21 16:04 ` Jörn Engel
  2003-07-21 21:34   ` andrzej.mialkowski
  0 siblings, 1 reply; 6+ messages in thread
From: Jörn Engel @ 2003-07-21 16:04 UTC (permalink / raw)
  To: andrzej.mialkowski; +Cc: linux-mtd

On Mon, 21 July 2003 15:04:51 +0200, andrzej.mialkowski@inetia.pl wrote:
> 
> Jörn,
>   You of course right that limit proposed in patch too high. With current 
> typical stack size (8K) and structure size (36 bytes - on ARM) it is safe to 
> handle this way about 160 chips. This is much more what can be expected in 
> resonable designs (and what I need). On the other hand placing kmalloc for 
> chips structure effectively leeds to solution with realloc. Drawback of this 
> will be creation of heap fragment, it also still has problem with the constant 
> limit.

Heap fragmentation should not be a problem in kernel space, but you
have to copy the array around each time you "realloc".

> For me attractive are two solutions:
> 1) Cleaned previous proposal, becuse it is simple and solves problem probably 
> fits for all designs.
> 2) Rewrite genprobe_ident_chips to use realloc emulation to allow expansion 
> structure and handling any number of chips.
3) Rewrite genprobe_ident_chips to use a linked list with struct
list_head.

Usually 3) is a little awkward at first, but when you are done, the
code looks a lot nicer than before.  I'm not sure if it would work
here as well.  It should, but you never know before you actually try
it.

> diff -Nru --minimal prev/drivers/mtd/chips/Config.in 
> linux/drivers/mtd/chips/Config.in
> --- prev/drivers/mtd/chips/Config.in	Fri Mar 14 17:21:15 2003
> +++ linux/drivers/mtd/chips/Config.in	Mon Jul 21 14:23:49 2003
> @@ -40,6 +40,7 @@
>         bool '    Support 4-chip flash interleave' CONFIG_MTD_CFI_I4
>         bool '    Support 8-chip flash interleave' CONFIG_MTD_CFI_I8
>       fi
> +     int '  Maximum number of flash chips' CONFIG_MTD_CFI_MAX_CHIPS 8 1 32
>    fi
>  fi

This should with 4k kernel stack, but it is still an ugly solution,
imo.  The complexety for the problem is all over the place, Makefile
Kconfig, header, source file.  If I only had more time to do a proper
fix myself...

Jörn

-- 
The cost of changing business rules is much more expensive for software
than for a secretaty.
-- unknown

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: hardcoded maximum number of CFI chips - continued
  2003-07-21 16:04 ` Jörn Engel
@ 2003-07-21 21:34   ` andrzej.mialkowski
  2003-07-22 10:21     ` Jörn Engel
  0 siblings, 1 reply; 6+ messages in thread
From: andrzej.mialkowski @ 2003-07-21 21:34 UTC (permalink / raw)
  To: Jörn Engel; +Cc: linux-mtd

Yes, linked list is nice solution; I would also prefer it while writing a new 
module. 
Problem is that module exist and works pretty well. My priorities are time to 
solution and risk of bug avoidance. You must agree that this is big difference 
between changing number 8 to 10 and rewriting even only module initialization 
to linked lists. 
Compromise solution may be leave runtime structures as they are, and change 
chips table to be 'reallocated' for instance in 4-16 chip increments. This 
solution reduces to reasonable amount of copying and memory allocations (still 
not critical during initialization), supports 'unlimited' number of chips and 
may be implemented and tested in period of few hours. I can do this tomorrow.

Andrzej

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: hardcoded maximum number of CFI chips - continued
  2003-07-21 21:34   ` andrzej.mialkowski
@ 2003-07-22 10:21     ` Jörn Engel
  2003-07-24 16:28       ` andrzej.mialkowski
  0 siblings, 1 reply; 6+ messages in thread
From: Jörn Engel @ 2003-07-22 10:21 UTC (permalink / raw)
  To: andrzej.mialkowski; +Cc: linux-mtd

On Mon, 21 July 2003 23:34:05 +0200, andrzej.mialkowski@inetia.pl wrote:
> 
> Yes, linked list is nice solution; I would also prefer it while writing a new 
> module. 
> Problem is that module exist and works pretty well. My priorities are time to 
> solution and risk of bug avoidance. You must agree that this is big difference 
> between changing number 8 to 10 and rewriting even only module initialization 
> to linked lists. 
> Compromise solution may be leave runtime structures as they are, and change 
> chips table to be 'reallocated' for instance in 4-16 chip increments. This 
> solution reduces to reasonable amount of copying and memory allocations (still 
> not critical during initialization), supports 'unlimited' number of chips and 
> may be implemented and tested in period of few hours. I can do this tomorrow.

In that case, why don't you just crank up the number from 8 to 16?  It
is the simpler solution to your problem at hand.

Jörn

-- 
Correctness comes second.
Features come third.
Performance comes last.
Maintainability is needed for all of them.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: hardcoded maximum number of CFI chips - continued
  2003-07-22 10:21     ` Jörn Engel
@ 2003-07-24 16:28       ` andrzej.mialkowski
  2003-08-01 16:55         ` Jörn Engel
  0 siblings, 1 reply; 6+ messages in thread
From: andrzej.mialkowski @ 2003-07-24 16:28 UTC (permalink / raw)
  To: Jörn Engel; +Cc: linux-mtd

Cytowanie Jörn Engel <joern@wohnheim.fh-wedel.de>:
> In that case, why don't you just crank up the number from 8 to 16?  It
> is the simpler solution to your problem at hand.
> 
> Jörn

Jörn,

Answer is very simple: It is not first my Linux port. In period last two years 
i had to port Linux to about 9 different ARM based systems. In all cases I 
meet several hardcoded limitations. This means so it is also my personal 
business to make Linux easier to port. I'm trying to balace between complexity 
of change an effect. As far as I know friedns from my hadware team, next time 
they will mount me 27.5 chips :).

I looked once again on generic probe code and found following conclusion:
Chips table is used only for alias detection and for building runtime retcfi 
structure. In both cases only information used is chip address. This means 
that table of flchip structures may be replaced by any data structure that is 
able to return this information. Thought about lists, tables and finally 
decided to use bitmap. Bitmap of valid chips can be used effectively if 
assumption that number of possible chips (locations to check!) in map is 
reasonable in comparison to number of chips. Algorithm is not effective only 
if map driver reports millions of unoccupied possible chip locations (if we 
have a lot of chips we must have much more memory for runtime structures).
In my case map driver detects number of writable bits in banking hardware so 
in result of calculations I have 16 possible chip locations.

Below is patch for my work tree 2.4.19-rmk7-ds3, tried to do not affect 
algorithms and large parts of code. Not tested JEDEC part but changes are 
almost identical like for CFI.

Andrzej

diff -Nru --minimal --ignore-all-space prev/drivers/mtd/chips/cfi_probe.c 
linux/drivers/mtd/chips/cfi_probe.c
--- prev/drivers/mtd/chips/cfi_probe.c	Tue Apr 29 13:57:43 2003
+++ linux/drivers/mtd/chips/cfi_probe.c	Thu Jul 24 14:45:06 2003
@@ -25,7 +25,7 @@
 #endif
 
 static int cfi_probe_chip(struct map_info *map, __u32 base,
-			  struct flchip *chips, struct cfi_private *cfi);
+			  struct probe_info *probe, struct cfi_private *cfi);
 static int cfi_chip_setup(struct map_info *map, struct cfi_private *cfi);
 
 struct mtd_info *cfi_probe(struct map_info *map);
@@ -48,7 +48,7 @@
 }
 
 static int cfi_probe_chip(struct map_info *map, __u32 base,
-			  struct flchip *chips, struct cfi_private *cfi)
+			  struct probe_info *probe, struct cfi_private *cfi)
 {
 	int i;
 	
@@ -80,21 +80,26 @@
 		return cfi_chip_setup(map, cfi);
 	}
 
-	/* Check each previous chip to see if it's an alias */
-	for (i=0; i<cfi->numchips; i++) {
+	/* Check each previous chip locations to see if it's an alias */
+	for (i=0; i < (base >> cfi->chipshift); i++) {
+		unsigned long start;
+		if(!test_bit(i, probe->chip_map)) {
+			continue; /* Skip location; no valid chip at this 
address */
+		}
+		start = i << cfi->chipshift;
 		/* This chip should be in read mode if it's one
 		   we've already touched. */
-		if (qry_present(map,chips[i].start,cfi)) {
+		if (qry_present(map, start, cfi)) {
 			/* Eep. This chip also had the QRY marker. 
 			 * Is it an alias for the new one? */
-			cfi_send_gen_cmd(0xF0, 0, chips[i].start, map, cfi, 
cfi->device_type, NULL);
+			cfi_send_gen_cmd(0xF0, 0, start, map, cfi, cfi-
>device_type, NULL);
 			/* some devices don't respond to 0xF0, so send 0xFF to 
be sure */
-			cfi_send_gen_cmd(0xFF, 0, chips[i].start, map, cfi, 
cfi->device_type, NULL);
+			cfi_send_gen_cmd(0xFF, 0, start, map, cfi, cfi-
>device_type, NULL);
 
 			/* If the QRY marker goes away, it's an alias */
-			if (!qry_present(map, chips[i].start, cfi)) {
+			if (!qry_present(map, start, cfi)) {
 				printk(KERN_DEBUG "%s: Found an alias at 0x%x 
for the chip at 0x%lx\n",
-				       map->name, base, chips[i].start);
+				       map->name, base, start);
 				return 0;
 			}
 			/* Yes, it's actually got QRY for data. Most 
@@ -106,7 +111,7 @@
 			cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi-
>device_type, NULL);
 			if (qry_present(map, base, cfi)) {
 				printk(KERN_DEBUG "%s: Found an alias at 0x%x 
for the chip at 0x%lx\n",
-				       map->name, base, chips[i].start);
+				       map->name, base, start);
 				return 0;
 			}
 		}
@@ -114,13 +119,7 @@
 	
 	/* OK, if we got to here, then none of the previous chips appear to
 	   be aliases for the current one. */
-	if (cfi->numchips == MAX_CFI_CHIPS) {
-		printk(KERN_WARNING"%s: Too many flash chips detected. 
Increase MAX_CFI_CHIPS from %d.\n", map->name, MAX_CFI_CHIPS);
-		/* Doesn't matter about resetting it to Read Mode - we're not 
going to talk to it anyway */
-		return -1;
-	}
-	chips[cfi->numchips].start = base;
-	chips[cfi->numchips].state = FL_READY;
+	set_bit((base >> cfi->chipshift), probe->chip_map); /* Update chip map 
*/
 	cfi->numchips++;
 	
 	/* Put it back into Read Mode */
diff -Nru --minimal --ignore-all-space prev/drivers/mtd/chips/gen_probe.c 
linux/drivers/mtd/chips/gen_probe.c
--- prev/drivers/mtd/chips/gen_probe.c	Fri Mar 14 17:21:18 2003
+++ linux/drivers/mtd/chips/gen_probe.c	Thu Jul 24 15:47:20 2003
@@ -50,11 +50,11 @@
 
 struct cfi_private *genprobe_ident_chips(struct map_info *map, struct 
chip_probe *cp)
 {
-	unsigned long base=0;
 	struct cfi_private cfi;
 	struct cfi_private *retcfi;
-	struct flchip chip[MAX_CFI_CHIPS];
-	int i;
+	struct probe_info probe;
+	int i, j;
+	int max_chips;
 
 	memset(&cfi, 0, sizeof(cfi));
 
@@ -77,8 +77,6 @@
 		return NULL;
 	}
 #endif
-	chip[0].start = 0;
-	chip[0].state = FL_READY;
 	cfi.chipshift = cfi.cfiq->DevSize;
 
 	switch(cfi.interleave) {
@@ -102,45 +100,57 @@
 		
 	cfi.numchips = 1;
 
+	/* Allocate memory for bitmap of valid chips. Align bitmap storage 
size to full byte. */
+	max_chips = map->size >> cfi.chipshift;
+	probe.chip_map = kmalloc((max_chips + 7) / 8, GFP_KERNEL);
+	if (!probe.chip_map) {
+		printk(KERN_WARNING "%s: kmalloc failed for CFI chip map\n", 
map->name);
+		kfree(cfi.cfiq);
+		return NULL;
+	}
+
+	set_bit(0, probe.chip_map); /* Mark first chip valid */
+
 	/*
 	 * Now probe for other chips, checking sensibly for aliases while
 	 * we're at it. The new_chip probe above should have let the first
 	 * chip in read mode.
-	 *
-	 * NOTE: Here, we're checking if there is room for another chip
-	 *       the same size within the mapping. Therefore, 
-	 *       base + chipsize <= map->size is the correct thing to do, 
-	 *       because, base + chipsize would be the  _first_ byte of the
-	 *       next chip, not the one we're currently pondering.
 	 */
 
-	for (base = (1<<cfi.chipshift); base + (1<<cfi.chipshift) <= map->size;
-	     base += (1<<cfi.chipshift))
-		cp->probe_chip(map, base, &chip[0], &cfi);
+	for (i = 1; i < max_chips; i++) {
+		cp->probe_chip(map, i << cfi.chipshift, &probe, &cfi);
+	}
 
 	/*
 	 * Now allocate the space for the structures we need to return to 
 	 * our caller, and copy the appropriate data into them.
 	 */
 
-	retcfi = kmalloc(sizeof(struct cfi_private) + cfi.numchips * sizeof
(struct flchip), GFP_KERNEL);
+	retcfi = kmalloc(sizeof(struct cfi_private) + (cfi.numchips - 1) * 
sizeof(struct flchip), GFP_KERNEL);
 
 	if (!retcfi) {
 		printk(KERN_WARNING "%s: kmalloc failed for CFI private 
structure\n", map->name);
 		kfree(cfi.cfiq);
+		kfree(probe.chip_map);
 		return NULL;
 	}
 
 	memcpy(retcfi, &cfi, sizeof(cfi));
-	memcpy(&retcfi->chips[0], chip, sizeof(struct flchip) * cfi.numchips);
+	memset(&retcfi->chips[0], 0, sizeof(struct flchip) * cfi.numchips);
 
-	/* Fix up the stuff that breaks when you move it */
-	for (i=0; i< retcfi->numchips; i++) {
-		init_waitqueue_head(&retcfi->chips[i].wq);
-		spin_lock_init(&retcfi->chips[i]._spinlock);
-		retcfi->chips[i].mutex = &retcfi->chips[i]._spinlock;
+	for (i = 0, j = 0; (j < cfi.numchips) && (i < max_chips); i++) {
+		if(test_bit(i, probe.chip_map)) {
+			struct flchip *pchip = &retcfi->chips[j++];
+
+			pchip->start = (i << cfi.chipshift);
+			pchip->state = FL_READY;
+			init_waitqueue_head(&pchip->wq);
+			spin_lock_init(&pchip->_spinlock);
+			pchip->mutex = &pchip->_spinlock;
+		}
 	}
 
+	kfree(probe.chip_map);
 	return retcfi;
 }
 
diff -Nru --minimal --ignore-all-space prev/drivers/mtd/chips/jedec_probe.c 
linux/drivers/mtd/chips/jedec_probe.c
--- prev/drivers/mtd/chips/jedec_probe.c	Fri Mar 14 17:21:19 2003
+++ linux/drivers/mtd/chips/jedec_probe.c	Thu Jul 24 15:11:10 2003
@@ -803,7 +803,7 @@
 static int cfi_jedec_setup(struct cfi_private *p_cfi, int index);
 
 static int jedec_probe_chip(struct map_info *map, __u32 base,
-			    struct flchip *chips, struct cfi_private *cfi);
+			    struct probe_info *probe, struct cfi_private *cfi);
 
 struct mtd_info *jedec_probe(struct map_info *map);
 
@@ -871,7 +871,7 @@
 }
 
 static int jedec_probe_chip(struct map_info *map, __u32 base,
-			      struct flchip *chips, struct cfi_private *cfi)
+			    struct probe_info *probe, struct cfi_private *cfi)
 {
 	int i;
 	int unlockpass = 0;
@@ -977,21 +977,24 @@
 		}
 	}
 	
-	/* Check each previous chip to see if it's an alias */
-	for (i=0; i<cfi->numchips; i++) {
-		/* This chip should be in read mode if it's one
-		   we've already touched. */
-		if (jedec_read_mfr(map, chips[i].start, cfi) == cfi->mfr &&
-		    jedec_read_id(map, chips[i].start, cfi) == cfi->id) {
+	/* Check each previous chip locations to see if it's an alias */
+	for (i=0; i < (base >> cfi->chipshift); i++) {
+		unsigned long start;
+		if(!test_bit(i, probe->chip_map)) {
+			continue; /* Skip location; no valid chip at this 
address */
+		}
+		start = i << cfi->chipshift;
+		if (jedec_read_mfr(map, start, cfi) == cfi->mfr &&
+		    jedec_read_id(map, start, cfi) == cfi->id) {
 			/* Eep. This chip also looks like it's in autoselect 
mode.
 			   Is it an alias for the new one? */
-			jedec_reset(chips[i].start, map, cfi);
+			jedec_reset(start, map, cfi);
 
 			/* If the device IDs go away, it's an alias */
 			if (jedec_read_mfr(map, base, cfi) != cfi->mfr ||
 			    jedec_read_id(map, base, cfi) != cfi->id) {
 				printk(KERN_DEBUG "%s: Found an alias at 0x%x 
for the chip at 0x%lx\n",
-				       map->name, base, chips[i].start);
+				       map->name, base, start);
 				return 0;
 			}
 			
@@ -1003,7 +1006,7 @@
 			if (jedec_read_mfr(map, base, cfi) == cfi->mfr &&
 			    jedec_read_id(map, base, cfi) == cfi->id) {
 				printk(KERN_DEBUG "%s: Found an alias at 0x%x 
for the chip at 0x%lx\n",
-				       map->name, base, chips[i].start);
+				       map->name, base, start);
 				return 0;
 			}
 		}
@@ -1011,13 +1014,7 @@
 		
 	/* OK, if we got to here, then none of the previous chips appear to
 	   be aliases for the current one. */
-	if (cfi->numchips == MAX_CFI_CHIPS) {
-		printk(KERN_WARNING"%s: Too many flash chips detected. 
Increase MAX_CFI_CHIPS from %d.\n", map->name, MAX_CFI_CHIPS);
-		/* Doesn't matter about resetting it to Read Mode - we're not 
going to talk to it anyway */
-		return -1;
-	}
-	chips[cfi->numchips].start = base;
-	chips[cfi->numchips].state = FL_READY;
+	set_bit((base >> cfi->chipshift), probe->chip_map); /* Update chip map 
*/
 	cfi->numchips++;
 		
 ok_out:
diff -Nru --minimal --ignore-all-space prev/include/linux/mtd/cfi.h 
linux/include/linux/mtd/cfi.h
--- prev/include/linux/mtd/cfi.h	Fri Mar 14 17:05:39 2003
+++ linux/include/linux/mtd/cfi.h	Thu Jul 24 13:32:18 2003
@@ -306,8 +306,6 @@
 	struct flchip chips[0];  /* per-chip data structure for each chip */
 };
 
-#define MAX_CFI_CHIPS 8 /* Entirely arbitrary to avoid realloc() */
-
 /*
  * Returns the command address according to the given geometry.
  */
diff -Nru --minimal --ignore-all-space prev/include/linux/mtd/gen_probe.h 
linux/include/linux/mtd/gen_probe.h
--- prev/include/linux/mtd/gen_probe.h	Fri Mar 14 15:49:56 2003
+++ linux/include/linux/mtd/gen_probe.h	Thu Jul 24 14:42:46 2003
@@ -10,12 +10,16 @@
 #include <linux/mtd/flashchip.h>
 #include <linux/mtd/map.h> 
 #include <linux/mtd/cfi.h>
+#include <asm/bitops.h>
+
+struct probe_info {
+	long *chip_map;	/* bitmap of valid chips in mtd map */
+};
 
 struct chip_probe {
 	char *name;
 	int (*probe_chip)(struct map_info *map, __u32 base,
-			  struct flchip *chips, struct cfi_private *cfi);
-
+			  struct probe_info *probe, struct cfi_private *cfi);
 };
 
 struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe 
*cp); 

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: hardcoded maximum number of CFI chips - continued
  2003-07-24 16:28       ` andrzej.mialkowski
@ 2003-08-01 16:55         ` Jörn Engel
  0 siblings, 0 replies; 6+ messages in thread
From: Jörn Engel @ 2003-08-01 16:55 UTC (permalink / raw)
  To: andrzej.mialkowski; +Cc: linux-mtd

On Thu, 24 July 2003 18:28:31 +0200, andrzej.mialkowski@inetia.pl wrote:
> 
> [a lot of code and explanations]

Sorry for the long lag.  Exam period has come up again, the most
irrational timeof the year for me.  But I'm finally reading your code.

Thanks! :)

Jörn

-- 
Premature optimization is the root of all evil.
-- Donald Knuth

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2003-08-01 16:56 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-07-21 13:04 hardcoded maximum number of CFI chips - continued andrzej.mialkowski
2003-07-21 16:04 ` Jörn Engel
2003-07-21 21:34   ` andrzej.mialkowski
2003-07-22 10:21     ` Jörn Engel
2003-07-24 16:28       ` andrzej.mialkowski
2003-08-01 16:55         ` Jörn Engel

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.