Subject: Old World interrupts again
To: netbsd-macppc macppc <port-macppc@netbsd.org>
From: Michael Lorenz <macallan@netbsd.org>
List: port-macppc
Date: 09/24/2006 18:45:16
--Apple-Mail-3-442090206
Content-Type: multipart/mixed; boundary=Apple-Mail-2-442090171


--Apple-Mail-2-442090171
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
	charset=US-ASCII;
	format=flowed

Hello,

since I'm hacking the PB3400c I ran into various issues, one of them 
was that the built-in tlp didn't work, apparently because the interrupt 
handler was never called.
Turned out the issue is a lot deeper than it looks like:
- OF lies about the IRQ pin used - claims 27 but uses 60
- the PB3400c has two interrupt controllers, our current code finds 
only one and guess which one the tlp is hooked up to.

So what I did is to frob the tlp's IRQ line to 60 in pci_machdep.c when 
finding a 2nd ohare interrupt controller and rewrite half of extintr.c 
to support the following configurations:
- single PIC with 32 lines - Grand Central, ohare etc.
- single PIC with 64 lines - Heathrow
- two PICs with 32 lines each, cascaded - 2x ohare
other configurations can be easily added.
The patch is still a bit rough but it worked well for a couple days on 
a beige G3 ( which has a Heathrow PIC ) and said PB3400c.

If nobody finds something wrong with the principle I'm going to commit.

have fun
Michael



--Apple-Mail-2-442090171
Content-Transfer-Encoding: 7bit
Content-Type: application/octet-stream;
	x-unix-mode=0644;
	name="macpps_irqs.patch"
Content-Disposition: attachment;
	filename=macpps_irqs.patch

Index: pci/pci_machdep.c
===================================================================
RCS file: /cvsroot/src/sys/arch/macppc/pci/pci_machdep.c,v
retrieving revision 1.31
diff -u -w -r1.31 pci_machdep.c
--- pci/pci_machdep.c	24 Sep 2006 19:17:56 -0000	1.31
+++ pci/pci_machdep.c	24 Sep 2006 22:43:32 -0000
@@ -381,6 +381,19 @@
 			if (len <= 0)
 				continue;
 		}
+
+		/* 
+		 * check if we're on a PowerBook 3400, if so we need to frob
+		 * the built-in ethernet controller's IRQ to 60
+		 */
+		if (tag == 0x80006800) {			
+			
+			if (OF_finddevice("/bandit/pci106b,7") > 0) {
+				irqs[0] = 60;
+				printf("\nohare: frobbing tlp IRQ to 60");
+			}
+		}
+
 		intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
 		intr &= ~PCI_INTERRUPT_LINE_MASK;
 		intr |= irqs[0] & PCI_INTERRUPT_LINE_MASK;
Index: macppc/extintr.c
===================================================================
RCS file: /cvsroot/src/sys/arch/macppc/macppc/extintr.c,v
retrieving revision 1.58
diff -u -w -r1.58 extintr.c
--- macppc/extintr.c	14 Aug 2006 11:17:59 -0000	1.58
+++ macppc/extintr.c	24 Sep 2006 22:43:33 -0000
@@ -101,18 +101,28 @@
 #define HWIRQ_MAX (NIRQ - 4 - 1)
 #define HWIRQ_MASK 0x0fffffff
 
-void intr_calculatemasks __P((void));
-int fakeintr __P((void *));
+//#define LPIC_DEBUG
 
-static inline uint32_t gc_read_irq __P((void));
-static inline int mapirq __P((int));
-static void gc_enable_irq __P((int));
-static void gc_reenable_irq __P((int));
-static void gc_disable_irq __P((int));
-
-static void do_pending_int __P((void));
-static void ext_intr_openpic __P((void));
-static void legacy_int_init __P((void));
+void intr_calculatemasks(void);
+int fakeintr(void *);
+
+static inline uint32_t gc_read_irq(void);
+static inline int mapirq(uint32_t);
+static void gc_enable_irq(uint32_t);
+static void gc_reenable_irq(uint32_t);
+static void gc_disable_irq(uint32_t);
+
+static int	lpic_add(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t);
+static uint32_t	lpic_read_events(int);
+static void	lpic_enable_irq(int, uint32_t);
+static void	lpic_disable_irq(int, uint32_t);
+static void	lpic_disable_all(void);
+static void	lpic_clear_all(void);
+static void	lpic_dump(int);
+
+static void do_pending_int(void);
+static void ext_intr_openpic(void);
+static void legacy_int_init(void);
 
 int imask[NIPL];
 
@@ -125,42 +135,158 @@
 	struct evcnt is_ev;
 	char is_source[16];
 };
-
 static struct intrsource intrsources[NIRQ];
 
 static u_char virq[ICU_LEN];
 static int virq_max = 0;
 
-static u_char *obio_base;
-
 extern u_int *heathrow_FCR;
 
-#define IPI_VECTOR 64
+typedef struct __lpic_regs {
+	uint32_t	lpic_state;
+	uint32_t	lpic_enable;
+	uint32_t	lpic_clear;
+	uint32_t	lpic_level;
+	uint32_t	lpic_level_mask;
+	uint32_t	lpic_enable_mask;
+	uint32_t	lpic_cascade_mask;
+} lpic_regs;
 
-#define interrupt_reg	(obio_base + 0x10)
+static lpic_regs lpics[4]; 
 
-#define INT_STATE_REG_H  (interrupt_reg + 0x00)
-#define INT_ENABLE_REG_H (interrupt_reg + 0x04)
-#define INT_CLEAR_REG_H  (interrupt_reg + 0x08)
-#define INT_LEVEL_REG_H  (interrupt_reg + 0x0c)
-#define INT_STATE_REG_L  (interrupt_reg + 0x10)
-#define INT_ENABLE_REG_L (interrupt_reg + 0x14)
-#define INT_CLEAR_REG_L  (interrupt_reg + 0x18)
-#define INT_LEVEL_REG_L  (interrupt_reg + 0x1c)
+#define IPI_VECTOR 64
+
+#define INT_STATE_REG_H		0x10
+#define INT_ENABLE_REG_H	0x14
+#define INT_CLEAR_REG_H		0x18
+#define INT_LEVEL_REG_H		0x1c
+#define INT_STATE_REG_L		0x20
+#define INT_ENABLE_REG_L	0x24
+#define INT_CLEAR_REG_L		0x28
+#define INT_LEVEL_REG_L		0x2c
 
 #define have_openpic	(openpic_base != NULL)
 
-static uint32_t		intr_level_mask;
+static uint32_t		num_hw_irqs = 0;
+static uint32_t		num_lpics = 0;
 
 #define INT_LEVEL_MASK_GC	0x3ff00000
-#define INT_LEVEL_MASK_OHARE	0x1ff00000
+#define INT_LEVEL_MASK_OHARE	0x1ff00000	/* also for Heathrow */
+
+static int
+lpic_add(uint32_t state, uint32_t enable, uint32_t clear, uint32_t level, 
+    uint32_t mask)
+{
+	lpic_regs *this;
+	
+	if (num_lpics >= 4)
+		return -1;
+	this = &lpics[num_lpics];
+	this->lpic_state = state;
+	this->lpic_enable = enable;
+	this->lpic_clear = clear;
+	this->lpic_level = level;
+	this->lpic_level_mask = mask;
+	this->lpic_cascade_mask = 0;
+	this->lpic_enable_mask = 0;
+	num_lpics++;
+	num_hw_irqs += 32;
+	return 0;
+}
+
+static inline uint32_t
+lpic_read_events(int num)
+{
+	lpic_regs *this = &lpics[num];
+	uint32_t irqs, levels, events;
+	
+	irqs = in32rb(this->lpic_state);
+	events = irqs & ~this->lpic_level_mask;
+
+	levels = in32rb(this->lpic_level) & this->lpic_enable_mask;
+	events |= levels & this->lpic_level_mask;
+	
+	/* Clear any interrupts that we've read and all level ones */
+	out32rb(this->lpic_clear, events | this->lpic_level_mask);
+
+	/* don't return cascade interrupts */
+	events &= ~this->lpic_cascade_mask;
+#ifdef LPIC_DEBUG
+	printf("lpic %d: %08x %08x %08x ", num, irqs, levels, events);
+#endif
+	return events;
+}
+
+static inline void
+lpic_enable_irq(int num, uint32_t irq)
+{
+	lpic_regs *this = &lpics[num];
+
+#ifdef DIAGNOSTIC	
+	if (irq > 31)
+		printf("bogus irq %d\n", irq);
+#endif
+	this->lpic_enable_mask |= (1 << irq) | this->lpic_cascade_mask;
+	out32rb(this->lpic_enable, this->lpic_enable_mask);	/* unmask */
+#ifdef LPIC_DEBUG
+	printf("enabling %d %d %08x ", num, irq, mask);
+#endif
+}
+
+static void
+lpic_disable_irq(int num, uint32_t irq)
+{
+	lpic_regs *this = &lpics[num];
+
+#ifdef DIAGNOSTIC
+	if (irq > 31)
+		printf("bogus irq %d\n", irq);
+#endif
+	this->lpic_enable_mask &= ~(1 << irq);
+	out32rb(this->lpic_enable, this->lpic_enable_mask);	/* unmask */
+}
+
+#ifdef DIAGNOSTIC
+static void
+lpic_dump(int num)
+{
+	lpic_regs *this = &lpics[num];
+
+	printf("lpic %d:\n", num);
+	printf("state:      %08x\n", in32rb(this->lpic_state));
+	printf("enable:     %08x\n", in32rb(this->lpic_enable));
+	printf("clear:      %08x\n", in32rb(this->lpic_clear));
+	printf("level:      %08x\n", in32rb(this->lpic_level));
+	printf("level_mask: %08x\n", this->lpic_level_mask);
+	printf("cascade:    %08x\n", this->lpic_cascade_mask);
+}
+#endif
+
+static void
+lpic_disable_all()
+{
+	int i;
+	
+	for (i = 0; i < num_lpics; i++) {
+		lpics[i].lpic_enable_mask = 0;
+		out32rb(lpics[i].lpic_enable, 0);
+	}
+}
+
+static void
+lpic_clear_all()
+{
+	int i;
+	
+	for (i = 0; i < num_lpics; i++)
+		out32rb(lpics[i].lpic_clear, 0xffffffff);
+}
 
 /*
  * Map 64 irqs into 32 (bits).
  */
 int
-mapirq(irq)
-	int irq;
+mapirq(uint32_t irq)
 {
 	int v;
 
@@ -177,7 +303,9 @@
 
 	intrsources[v].is_hwirq = irq;
 	virq[irq] = v;
-
+#ifdef LPIC_DEBUG
+	printf("mapping irq %d to virq %d\n", irq, v);
+#endif
 	return v;
 }
 
@@ -185,123 +313,70 @@
 gc_read_irq()
 {
 	uint32_t rv = 0;
-	uint32_t int_state;
-	uint32_t events, e;
-	uint32_t levels;
-
-	/* Get the internal interrupts */
-	int_state = in32rb(INT_STATE_REG_L);
-	events = int_state & ~intr_level_mask;
-
-	/* Get the enabled external interrupts */
-	levels = in32rb(INT_LEVEL_REG_L) & in32rb(INT_ENABLE_REG_L);
-	events = events | (levels & intr_level_mask);
-
-	/* Clear any interrupts that we've read */
-	out32rb(INT_CLEAR_REG_L, events | int_state);
-	while (events) {
-		e = 31 - cntlzw(events);
-		rv |= 1 << virq[e];
-		events &= ~(1 << e);
-	}
-
-	/* If we're on Heathrow, repeat for the secondary */
-	if (heathrow_FCR) {
-		events = in32rb(INT_STATE_REG_H);
-
-		if (events)
-			out32rb(INT_CLEAR_REG_H, events);
+	uint32_t e;
+	uint32_t events;
+	int i;
 
+	for (i = 0; i < num_lpics; i++) {
+		events = lpic_read_events(i);
 		while (events) {
 			e = 31 - cntlzw(events);
-			rv |= 1 << virq[e + 32];
+			rv |= 1 << virq[e + (i << 5)];
 			events &= ~(1 << e);
 		}
 	}
 
+#ifdef LPIC_DEBUG
+	printf("rv: %08x ", rv);
+#endif	
 	/* 1 << 0 is invalid because virq will always be at least 1. */
 	return rv & ~1;
 }
 
 void
-gc_reenable_irq(irq)
-	int irq;
+gc_reenable_irq(uint32_t irq)
 {
+	lpic_regs *this;
 	struct cpu_info *ci = curcpu();
-	u_int levels, vi;
-	u_int mask, irqbit;
+	uint32_t levels, irqbit, vi;
+	uint32_t pic;
 
-	if (irq < 32) {
-		mask = in32rb(INT_ENABLE_REG_L);
-		irqbit = 1 << irq;
-
-		/* Already enabled? */
-		if (mask & irqbit)
-			return;
+	pic = irq >> 5;
+	this = &lpics[pic];
 
-		mask |= irqbit;
-		out32rb(INT_ENABLE_REG_L, mask);	/* unmask */
-
-		/* look for lost level interrupts */
-		levels = in32rb(INT_LEVEL_REG_L);
-		if (levels & irqbit) {
-			vi = virq[irq];		/* map to virtual irq */
-			ci->ci_ipending |= (1<<vi);	
-			out32rb(INT_CLEAR_REG_L, irqbit);
-		}
-	} else {
-		mask = in32rb(INT_ENABLE_REG_H);
-		irqbit = 1 << (irq - 32);
+	irqbit = 1 << (irq & 0x1f);
 
 		/* Already enabled? */
-		if (mask & irqbit)
+	if (this->lpic_enable_mask & irqbit)
 			return;
 
-		mask |= irqbit;
-		out32rb(INT_ENABLE_REG_H, mask);	/* unmask */
+	lpic_enable_irq(pic, irq & 0x1f);
 
 		/* look for lost level interrupts */
-		levels = in32rb(INT_LEVEL_REG_H);
+	levels = in32rb(this->lpic_level);
 		if (levels & irqbit) {
 			vi = virq[irq];		/* map to virtual irq */
 			ci->ci_ipending |= (1<<vi);	
-			out32rb(INT_CLEAR_REG_H, irqbit);
-		}
+		out32rb(this->lpic_clear, irqbit);
 	}
 }
 
 void
-gc_enable_irq(irq)
-	int irq;
+gc_enable_irq(uint32_t irq)
 {
-	u_int mask;
+	uint32_t pic;
 
-	if (irq < 32) {
-		mask = in32rb(INT_ENABLE_REG_L);
-		mask |= 1 << irq;
-		out32rb(INT_ENABLE_REG_L, mask);	/* unmask */
-	} else {
-		mask = in32rb(INT_ENABLE_REG_H);
-		mask |= 1 << (irq - 32);
-		out32rb(INT_ENABLE_REG_H, mask);	/* unmask */
-	}
+	pic = (irq >> 5);
+	lpic_enable_irq(pic, irq & 0x1f);
 }
 
 void
-gc_disable_irq(irq)
-	int irq;
+gc_disable_irq(uint32_t irq)
 {
-	u_int x;
+	uint32_t pic;
 
-	if (irq < 32) {
-		x = in32rb(INT_ENABLE_REG_L);
-		x &= ~(1 << irq);
-		out32rb(INT_ENABLE_REG_L, x);
-	} else {
-		x = in32rb(INT_ENABLE_REG_H);
-		x &= ~(1 << (irq - 32));
-		out32rb(INT_ENABLE_REG_H, x);
-	}
+	pic = (irq >> 5);
+	lpic_disable_irq(pic, irq & 0x1f);
 }
 
 /*
@@ -406,9 +481,7 @@
 				openpic_enable_irq(is->is_hwirq, is->is_type);
 		}
 	} else {
-		out32rb(INT_ENABLE_REG_L, 0);
-		if (heathrow_FCR)
-			out32rb(INT_ENABLE_REG_H, 0);
+		lpic_disable_all();
 		for (irq = 0, is = intrsources; irq < NIRQ; irq++, is++) {
 			if (is->is_hand)
 				gc_enable_irq(is->is_hwirq);
@@ -584,9 +657,8 @@
 	struct intrsource *is;
 	struct intrhand *ih;
 	uint32_t int_state;
-#if DIAGNOSTIC
-	uint32_t oint_state;
-	int spincount=0;
+#ifdef DIAGNOSTIC
+	int intr_spin = 0;
 #endif
 
 #ifdef MULTIPROCESSOR
@@ -601,38 +673,18 @@
 	pcpl = ci->ci_cpl;
 	msr = mfmsr();
 
-#if DIAGNOSTIC
-	oint_state = 0;
-#endif
 	while ((int_state = gc_read_irq()) != 0) {
 
-#if DIAGNOSTIC
-		/*
-		 * Paranoia....
-		 */
-		if (int_state == oint_state) {
-			if (spincount++ > 0x80) {
-				uint32_t	stuck;
-				const char	*comma="";
-
-				stuck = int_state;
-				printf("Disabling stuck interrupt(s): ");
-				while (stuck) {
-					irq = 31 - cntlzw(int_state);
-					r_imen = 1 << irq;
-					is = &intrsources[irq];
-					printf("%s%d", comma, is->is_hwirq);
-					gc_disable_irq(is->is_hwirq);
-					ci->ci_ipending &= ~r_imen;
-					stuck &= ~r_imen;
-					comma = ", ";
+#ifdef DIAGNOSTIC
+		if (intr_spin > 100) {
+			int i;
+			printf("spinning in ext_intr! %08x\n", int_state);
+			for (i = 0; i < num_lpics; i++) {
+				lpic_dump(i);
 				}
-				printf("\n");
-				spincount = 0;
+			panic("stuck interrupt");
 				continue;
 			}
-		}
-		oint_state = int_state;
 #endif
 
 #ifdef MULTIPROCESSOR
@@ -688,6 +740,7 @@
 			uvmexp.intrs++;
 			is->is_ev.ev_count++;
 		}
+		intr_spin++;
 	}
 
 	mtmsr(msr | PSL_EE);
@@ -1010,33 +1063,72 @@
 	oea_install_extint(ext_intr_openpic);
 }
 
+#define GC_OBIO_BASE		0xf3000000
+
 void
 legacy_int_init()
 {
-	int	ohare;
+	uint32_t reg[5];
+	uint32_t obio_base;
+	int	ohare, ohare2;
 
-	out32rb(INT_ENABLE_REG_L, 0);		/* disable all intr. */
-	out32rb(INT_CLEAR_REG_L, 0xffffffff);	/* clear pending intr. */
-	intr_level_mask = INT_LEVEL_MASK_GC;
-	if (heathrow_FCR) {
-		out32rb(INT_ENABLE_REG_H, 0);
-		out32rb(INT_CLEAR_REG_H, 0xffffffff);
-		intr_level_mask = INT_LEVEL_MASK_OHARE;
-	}
 	ohare = OF_finddevice("/bandit/ohare");
 	if (ohare != -1) {
-		intr_level_mask = INT_LEVEL_MASK_OHARE;
+		if (OF_getprop(ohare, "assigned-addresses", reg, sizeof(reg))
+		    == 20) {
+			obio_base = reg[2];
+			printf("found OHare at 0x%08x\n", obio_base);
+			lpic_add(obio_base + INT_STATE_REG_L,
+			    obio_base + INT_ENABLE_REG_L,
+			    obio_base + INT_CLEAR_REG_L,
+			    obio_base + INT_LEVEL_REG_L,
+			    INT_LEVEL_MASK_OHARE);
 	}
+	} else {
+		/* must be Grand Central */
+		printf("found Grand Central at 0x%08x\n", GC_OBIO_BASE);
+		lpic_add(GC_OBIO_BASE + INT_STATE_REG_L,
+		    GC_OBIO_BASE + INT_ENABLE_REG_L,
+		    GC_OBIO_BASE + INT_CLEAR_REG_L,
+		    GC_OBIO_BASE + INT_LEVEL_REG_L,
+		    INT_LEVEL_MASK_GC);
+		return;
+	}
+
+	ohare2 = OF_finddevice("/bandit/pci106b,7");
+	if (ohare2 != -1) {
+		uint32_t irq;
+		
+		if (OF_getprop(ohare2, "assigned-addresses", reg, sizeof(reg))
+		    < 20)
+		    	goto next;
+		if (OF_getprop(ohare2, "AAPL,interrupts", &irq, sizeof(irq))
+		    < 4)
+		    	goto next;
+		obio_base = reg[2];			
+		printf("found OHare2 at 0x%08x, irq %d\n", obio_base, irq);
+		lpic_add(obio_base + INT_STATE_REG_L,
+		    obio_base + INT_ENABLE_REG_L,
+		    obio_base + INT_CLEAR_REG_L,
+		    obio_base + INT_LEVEL_REG_L,
+		    INT_LEVEL_MASK_OHARE);
+		lpics[0].lpic_cascade_mask = 1 << irq;
+	}
+next:	
+	lpic_disable_all();
+	lpic_clear_all();
+	
+	printf("Handling %d interrupts\n", num_hw_irqs);
 
 	oea_install_extint(ext_intr);
 }
 
 #define HEATHROW_FCR_OFFSET	0x38		/* XXX should not here */
-#define GC_OBIO_BASE		0xf3000000
 
 void
 init_interrupt()
 {
+	uint32_t obio_base;
 	int chosen __attribute__((unused));
 	int mac_io, reg[5];
 	int32_t ictlr;
@@ -1054,7 +1146,6 @@
 		/*
 		 * No mac-io.  Assume Grand-Central or OHare.
 		 */
-		obio_base = (void *)GC_OBIO_BASE;
 		legacy_int_init();
 		return;
 	}
@@ -1062,8 +1153,7 @@
 	if (OF_getprop(mac_io, "assigned-addresses", reg, sizeof(reg)) < 20)
 		goto failed;
 
-	obio_base = (void *)reg[2];
-	printf("obio_base: %p\n", obio_base);
+	obio_base = reg[2];
 
 	heathrow_FCR = (void *)(obio_base + HEATHROW_FCR_OFFSET);
 
@@ -1096,7 +1186,24 @@
 		/*
 		 * Not an open-pic.  Must be a Heathrow (compatible).
 		 */
-		legacy_int_init();
+		printf("Found Heathrow at 0x%08x\n", obio_base);
+		lpic_add(obio_base + INT_STATE_REG_L,
+			obio_base + INT_ENABLE_REG_L,
+			obio_base + INT_CLEAR_REG_L,
+			obio_base + INT_LEVEL_REG_L,
+			INT_LEVEL_MASK_OHARE);
+
+		lpic_add(obio_base + INT_STATE_REG_H,
+			obio_base + INT_ENABLE_REG_H,
+			obio_base + INT_CLEAR_REG_H,
+			obio_base + INT_LEVEL_REG_H,
+			0);
+
+		lpic_disable_all();
+		lpic_clear_all();
+		oea_install_extint(ext_intr);
+		printf("Handling %d interrupts\n", num_hw_irqs);
+
 		return;
 	} else {
 		/*
@@ -1113,8 +1220,8 @@
 		openpic_base = (void *)(obio_base + reg[0]);
 #elif defined (PPC_OEA64_BRIDGE)
 		/* There is no BAT mapping the OBIO region, use PTEs */
-		openpic_base = (void *)mapiodev((u_int32_t)obio_base + (u_int32_t)reg[0],
-							0x40000);
+		openpic_base = (void *)mapiodev((u_int32_t)obio_base + 
+		    (u_int32_t)reg[0], 0x40000);
 #endif
 		printf("%s: found OpenPIC @ pa 0x%08x, %p\n", __FUNCTION__, 
 				(u_int32_t)obio_base + (u_int32_t)reg[0], openpic_base);

--Apple-Mail-2-442090171--

--Apple-Mail-3-442090206
content-type: application/pgp-signature; x-mac-type=70674453;
	name=PGP.sig
content-description: This is a digitally signed message part
content-disposition: inline; filename=PGP.sig
content-transfer-encoding: 7bit

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (Darwin)

iQEVAwUBRRcKfMpnzkX8Yg2nAQKl9QgAtc3u2sB3Uj7Gzw5dEn4PE1+I+8hSInXP
MlZB5mUZqDj3dS952PoVKGAdP5DpmTnr+KsqqjIz5+mnEtj57raAkNPRl1ITPOlq
pU9VskSBsi/j3F3VrLRcPD5t+5cZZ1xAi5bOhYugEhe592zl+btIfNvrWbOgwI3g
cDwaeQr0e+fN6OAvzraxaVgyejuaz6Q/v1wnKYHP3fMMhTQcgAqyTqwoKOSyo6KC
2w43TCoLmydDZ8xEhU1WIZkFl1pgKeInUkKPM181RKa0AzoFK9QxgVKi6nQpmfip
v3B2XJVC/57ntLBL9dce/wgo1aBtOHk7NO7QB4+smqpnBqDo8cpuUQ==
=mYlT
-----END PGP SIGNATURE-----

--Apple-Mail-3-442090206--