[PATCH] yenta: irq-routing for TI bridges...again

Daniel Ritz daniel.ritz at gmx.ch
Thu Mar 11 00:53:41 GMT 2004


On Wednesday 10 March 2004 09:16, Pavel Roskin wrote:
> On Tue, 9 Mar 2004, Daniel Ritz wrote:
> 
> > On Tuesday 09 March 2004 23:01, David Hinds wrote:
> > > The pcmcia-cs drivers have always tested the PCI interrupt as well as
> > > the ISA ones; this caught a not-insignificant number of BIOS problems
> > > related to incorrect interrupt routing tables, in addition to bridge
> > > configuration issues.  The testing itself never caused any problems,
> > > as far as I know.
> >
> > thanks for acknowledge. btw guess where the idea (and code parts)
> > comes from :)
> 
> OK, good to know that probing is not an issue.  Sorry for making you so
> angry, but some questions just had to be asked.
> 
> I have tested the patch and it's working for me (TI PCI1410).

fine. thanks.

> 
> It would be nice to clean it up and integrate it better into the
> surrounding code.  I believe patches to the PCI ID database should be
> submitted separately to different people.  Be prepared that the PCI ID
> database may be patches after the PCMCIA part.  Many drivers provide
> replacement definitions, e.g.
> 
> #ifndef PCI_VENDOR_ID_APPLICOM
> #define PCI_VENDOR_ID_APPLICOM                0x1389
> #endif

that just looks damn ugly IMHO...i already removed that from topic.h and
moved the IDs into pci_ids.h...it was merged a long time ago. so i see no
problem there.

> 
> Kernel addresses should not be printed unless you expect the
> subsequent stack dump and panic.  There are better ideas for the prefix,

i know. it was more for debugging where more the uniqueness was relevant.
the address is the easiest thing....

> such as the source file name, function name and pci_name().

done.

> 
> All hex numbers should be preceded by "0x" unless it's impractical.  It

done.

> may be better to use words rather than numbers - not everyone knows
> meaning of bits in mfunc.

done.

> 
> Please make a single patch (except the PCI ID changes), look at it, think

attached the new patch. if you have other cleanups in mind: please as patch
ontop as i'm lazy :)

> what can be done better, then post it.  I'll be glad to test it on more
> systems.

thanx. you don't have a non-working dual-slot chip around, have you?
i'd like to test if the INTB/INTRTIE stuff is working/necessary..

rgds
-daniel


--- 1.143/include/linux/pci_ids.h	Fri Mar  5 18:51:03 2004
+++ edited/include/linux/pci_ids.h	Sat Mar  6 18:06:15 2004
@@ -704,6 +704,7 @@
 #define PCI_VENDOR_ID_TI		0x104c
 #define PCI_DEVICE_ID_TI_TVP4010	0x3d04
 #define PCI_DEVICE_ID_TI_TVP4020	0x3d07
+#define PCI_DEVICE_ID_TI_4450		0x8011
 #define PCI_DEVICE_ID_TI_1130		0xac12
 #define PCI_DEVICE_ID_TI_1031		0xac13
 #define PCI_DEVICE_ID_TI_1131		0xac15
@@ -720,6 +721,7 @@
 #define PCI_DEVICE_ID_TI_4451		0xac42
 #define PCI_DEVICE_ID_TI_1410		0xac50
 #define PCI_DEVICE_ID_TI_1420		0xac51
+#define PCI_DEVICE_ID_TI_1451A		0xac52
 #define PCI_DEVICE_ID_TI_1520		0xac55
 #define PCI_DEVICE_ID_TI_1510		0xac56
 
--- 1.51/drivers/pcmcia/yenta_socket.c	Wed Dec 31 01:35:29 2003
+++ edited/drivers/pcmcia/yenta_socket.c	Tue Mar  2 23:19:05 2004
@@ -662,6 +662,118 @@
 };
 
 
+/*
+ * Only probe "regular" interrupts, don't
+ * touch dangerous spots like the mouse irq,
+ * because there are mice that apparently
+ * get really confused if they get fondled
+ * too intimately.
+ *
+ * Default to 11, 10, 9, 7, 6, 5, 4, 3.
+ */
+static u32 isa_interrupts = 0x0ef8;
+
+static unsigned int yenta_probe_irq(struct yenta_socket *socket, u32 isa_irq_mask)
+{
+	int i;
+	unsigned long val;
+	u16 bridge_ctrl;
+	u32 mask;
+
+	/* Set up ISA irq routing to probe the ISA irqs.. */
+	bridge_ctrl = config_readw(socket, CB_BRIDGE_CONTROL);
+	if (!(bridge_ctrl & CB_BRIDGE_INTR)) {
+		bridge_ctrl |= CB_BRIDGE_INTR;
+		config_writew(socket, CB_BRIDGE_CONTROL, bridge_ctrl);
+	}
+
+	/*
+	 * Probe for usable interrupts using the force
+	 * register to generate bogus card status events.
+	 */
+	cb_writel(socket, CB_SOCKET_EVENT, -1);
+	cb_writel(socket, CB_SOCKET_MASK, CB_CSTSMASK);
+	exca_writeb(socket, I365_CSCINT, 0);
+	val = probe_irq_on() & isa_irq_mask;
+	for (i = 1; i < 16; i++) {
+		if (!((val >> i) & 1))
+			continue;
+		exca_writeb(socket, I365_CSCINT, I365_CSC_STSCHG | (i << 4));
+		cb_writel(socket, CB_SOCKET_FORCE, CB_FCARDSTS);
+		udelay(100);
+		cb_writel(socket, CB_SOCKET_EVENT, -1);
+	}
+	cb_writel(socket, CB_SOCKET_MASK, 0);
+	exca_writeb(socket, I365_CSCINT, 0);
+
+	mask = probe_irq_mask(val) & 0xffff;
+
+	bridge_ctrl &= ~CB_BRIDGE_INTR;
+	config_writew(socket, CB_BRIDGE_CONTROL, bridge_ctrl);
+
+	return mask;
+}
+
+
+/* interrupt handler, only used during probing */
+static irqreturn_t yenta_probe_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct yenta_socket *socket = (struct yenta_socket *) dev_id;
+	u8 csc;
+        u32 cb_event;
+
+	/* Clear interrupt status for the event */
+	cb_event = cb_readl(socket, CB_SOCKET_EVENT);
+	cb_writel(socket, CB_SOCKET_EVENT, -1);
+	csc = exca_readb(socket, I365_CSC);
+
+	if (cb_event || csc) {
+		socket->private[7] = 1;
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_NONE;
+}
+
+/* probes the PCI interrupt, use only on override functions */
+static int yenta_probe_cb_irq(struct yenta_socket *socket)
+{
+	u16 bridge_ctrl;
+
+	if (!socket->cb_irq)
+		return -1;
+
+	socket->private[7] = 0;
+
+	/* disable ISA interrupts */
+	bridge_ctrl = config_readw(socket, CB_BRIDGE_CONTROL);
+	bridge_ctrl &= ~CB_BRIDGE_INTR;
+	config_writew(socket, CB_BRIDGE_CONTROL, bridge_ctrl);
+
+	if (request_irq(socket->cb_irq, yenta_probe_handler, SA_SHIRQ, "yenta", socket))
+		return -1;
+
+	/* generate interrupt, wait */
+	exca_writeb(socket, I365_CSCINT, I365_CSC_STSCHG);
+	cb_writel(socket, CB_SOCKET_EVENT, -1);
+	cb_writel(socket, CB_SOCKET_MASK, CB_CSTSMASK);
+	cb_writel(socket, CB_SOCKET_FORCE, CB_FCARDSTS);
+	
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(HZ/10);
+
+	/* disable interrupts */
+	cb_writel(socket, CB_SOCKET_MASK, 0);
+	exca_writeb(socket, I365_CSCINT, 0);
+	cb_writel(socket, CB_SOCKET_EVENT, -1);
+	exca_readb(socket, I365_CSC);
+
+	free_irq(socket->cb_irq, socket);
+
+	return socket->private[7];
+}
+
+
 #include "ti113x.h"
 #include "ricoh.h"
 #include "topic.h"
@@ -717,58 +829,6 @@
 
 
 /*
- * Only probe "regular" interrupts, don't
- * touch dangerous spots like the mouse irq,
- * because there are mice that apparently
- * get really confused if they get fondled
- * too intimately.
- *
- * Default to 11, 10, 9, 7, 6, 5, 4, 3.
- */
-static u32 isa_interrupts = 0x0ef8;
-
-static unsigned int yenta_probe_irq(struct yenta_socket *socket, u32 isa_irq_mask)
-{
-	int i;
-	unsigned long val;
-	u16 bridge_ctrl;
-	u32 mask;
-
-	/* Set up ISA irq routing to probe the ISA irqs.. */
-	bridge_ctrl = config_readw(socket, CB_BRIDGE_CONTROL);
-	if (!(bridge_ctrl & CB_BRIDGE_INTR)) {
-		bridge_ctrl |= CB_BRIDGE_INTR;
-		config_writew(socket, CB_BRIDGE_CONTROL, bridge_ctrl);
-	}
-
-	/*
-	 * Probe for usable interrupts using the force
-	 * register to generate bogus card status events.
-	 */
-	cb_writel(socket, CB_SOCKET_EVENT, -1);
-	cb_writel(socket, CB_SOCKET_MASK, CB_CSTSMASK);
-	exca_writeb(socket, I365_CSCINT, 0);
-	val = probe_irq_on() & isa_irq_mask;
-	for (i = 1; i < 16; i++) {
-		if (!((val >> i) & 1))
-			continue;
-		exca_writeb(socket, I365_CSCINT, I365_CSC_STSCHG | (i << 4));
-		cb_writel(socket, CB_SOCKET_FORCE, CB_FCARDSTS);
-		udelay(100);
-		cb_writel(socket, CB_SOCKET_EVENT, -1);
-	}
-	cb_writel(socket, CB_SOCKET_MASK, 0);
-	exca_writeb(socket, I365_CSCINT, 0);
-
-	mask = probe_irq_mask(val) & 0xffff;
-
-	bridge_ctrl &= ~CB_BRIDGE_INTR;
-	config_writew(socket, CB_BRIDGE_CONTROL, bridge_ctrl);
-
-	return mask;
-}
-
-/*
  * Set static data that doesn't need re-initializing..
  */
 static void yenta_get_socket_capabilities(struct yenta_socket *socket, u32 isa_irq_mask)
@@ -904,6 +964,13 @@
 
 	/* We must finish initialization here */
 
+#if 0
+	if (socket->cb_irq && (yenta_probe_cb_irq(socket) < 1)) {
+		socket->cb_irq = 0;
+		printk(KERN_INFO "Yenta: probing of PCI interrupt failed. Poll.\n");
+	}
+#endif
+
 	if (!socket->cb_irq || request_irq(socket->cb_irq, yenta_interrupt, SA_SHIRQ, "yenta", socket)) {
 		/* No IRQ or request_irq failed. Poll */
 		socket->cb_irq = 0; /* But zero is a valid IRQ number. */
@@ -997,7 +1064,6 @@
 	 * data sheets for these devices. --rmk)
 	 */
 	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1210, TI),
-	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1251B, TI),
 
 	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1130, TI113X),
 	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1131, TI113X),
@@ -1007,11 +1073,14 @@
 	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1221, TI12XX),
 	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1225, TI12XX),
 	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1251A, TI12XX),
+	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1251B, TI12XX),
 	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1420, TI12XX),
 	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1450, TI12XX),
+	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1451A, TI12XX),
+	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1510, TI12XX),
 	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1520, TI12XX),
 	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4410, TI12XX),
-//	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4450, TI12XX),
+	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4450, TI12XX),
 	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4451, TI12XX),
 
 	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1250, TI1250),
--- 1.18/drivers/pcmcia/ti113x.h	Wed Aug 27 21:58:54 2003
+++ edited/drivers/pcmcia/ti113x.h	Wed Mar 10 23:54:52 2004
@@ -252,7 +252,7 @@
  * INTCTL register that sets the PCI CSC interrupt.
  * Make sure we set it correctly at open and init
  * time
- * - open: disable the PCI CSC interrupt. This makes
+ * - override: disable the PCI CSC interrupt. This makes
  *   it possible to use the CSC interrupt to probe the
  *   ISA interrupts.
  * - init: set the interrupt to match our PCI state.
@@ -281,33 +281,6 @@
 
 	ti_set_zv(socket);
 
-#if 0
-	/*
-	 * If ISA interrupts don't work, then fall back to routing card
-	 * interrupts to the PCI interrupt of the socket.
-	 *
-	 * Tweaking this when we are using serial PCI IRQs causes hangs
-	 *   --rmk
-	 */
-	if (!socket->socket.irq_mask) {
-		u8 irqmux, devctl;
-
-		devctl = config_readb(socket, TI113X_DEVICE_CONTROL);
-		if ((devctl & TI113X_DCR_IMODE_MASK) != TI12XX_DCR_IMODE_ALL_SERIAL) {
-			printk (KERN_INFO "ti113x: Routing card interrupts to PCI\n");
-
-			devctl &= ~TI113X_DCR_IMODE_MASK;
-
-			irqmux = config_readl(socket, TI122X_IRQMUX);
-			irqmux = (irqmux & ~0x0f) | 0x02; /* route INTA */
-			irqmux = (irqmux & ~0xf0) | 0x20; /* route INTB */
-
-			config_writel(socket, TI122X_IRQMUX, irqmux);
-			config_writeb(socket, TI113X_DEVICE_CONTROL, devctl);
-		}
-	}
-#endif
-
 	return 0;
 }
 
@@ -325,9 +298,12 @@
 }
 
 
+
 static int ti12xx_override(struct yenta_socket *socket)
 {
-	u32 val;
+	u32 val, mfunc, mfunc_old, devctl;
+	unsigned probe_mask;
+	int ret, pci;
 
 	/* make sure that memory burst is active */
 	val = config_readl(socket, TI113X_SYSTEM_CONTROL);
@@ -347,7 +323,194 @@
 	printk(KERN_INFO "Yenta: Routing CardBus interrupts to %s\n",
 		(val & TI1250_DIAG_PCI_IREQ) ? "PCI" : "ISA");
 
-	return ti_override(socket);
+	/*********************************************************************/
+
+	mfunc = mfunc_old = config_readl(socket, TI122X_IRQMUX);
+	devctl = config_readb(socket, TI113X_DEVICE_CONTROL);
+	printk(KERN_INFO "Yenta TI: socket %s, mfunc 0x%08x, devctl 0x%02x\n",
+	       pci_name(socket->dev), mfunc, devctl);
+
+	/* test PCI interrupts first */
+	pci = yenta_probe_cb_irq(socket);
+	if (pci)
+		goto probe_isa;
+
+	/*
+	 * We're here which means PCI interrupts are _not_ delivered. try to
+	 * find the right setting (all serial or parallel)
+	 */
+	printk(KERN_INFO "Yenta TI: socket %s probing PCI interrupt failed, trying to fix\n",
+	       pci_name(socket->dev));
+
+	/* for serial PCI make sure MFUNC3 is set to IRQSER */
+	if ((devctl & TI113X_DCR_IMODE_MASK) == TI12XX_DCR_IMODE_ALL_SERIAL) {
+		switch (socket->dev->device) {
+			case PCI_DEVICE_ID_TI_1250:
+			case PCI_DEVICE_ID_TI_1251A:
+			case PCI_DEVICE_ID_TI_1251B:
+			case PCI_DEVICE_ID_TI_1450:
+			case PCI_DEVICE_ID_TI_1451A:
+			case PCI_DEVICE_ID_TI_4450:
+			case PCI_DEVICE_ID_TI_4451:
+				/* these chips have no IRQSER setting in MFUNC3  */
+				break;
+
+			default:
+				mfunc = (mfunc & ~0xf000) | 0x1000;
+
+				/* write down if changed, probe */
+				if (mfunc != mfunc_old) {
+					config_writel(socket, TI122X_IRQMUX, mfunc);
+
+					pci = yenta_probe_cb_irq(socket);
+					if (pci) {
+						printk(KERN_INFO "Yenta TI: socket %s all-serial interrupts ok\n",
+						       pci_name(socket->dev));
+						mfunc_old = mfunc;
+						goto probe_isa;
+					}
+
+					/* not working, back to old value */
+					mfunc = mfunc_old;
+					config_writel(socket, TI122X_IRQMUX, mfunc);
+				}
+		}
+
+		/* serial PCI interrupts not working fall back to parallel */
+		printk(KERN_INFO "Yenta TI: socket %s falling back to parallel PCI interrupts\n",
+		       pci_name(socket->dev));
+		devctl &= ~TI113X_DCR_IMODE_MASK;
+		devctl |= TI113X_DCR_IMODE_SERIAL; /* serial ISA could be right */
+		config_writeb(socket, TI113X_DEVICE_CONTROL, devctl);
+	}
+
+	/* parallel PCI interrupts: MFUNC0 -> INTA. not for 125x/145x */
+	switch (socket->dev->device) {
+		case PCI_DEVICE_ID_TI_1250:
+		case PCI_DEVICE_ID_TI_1251A:
+		case PCI_DEVICE_ID_TI_1251B:
+		case PCI_DEVICE_ID_TI_1450:
+			/* nada */
+			break;
+
+		default:
+			mfunc = (mfunc_old & ~0x0f) | 0x02;
+	}
+
+#if 0
+	/* 
+	 * dual slot chips: routing of INTB depending on INTRTIE
+	 * we could also do the opposite and just set INTRTIE.
+	 * manual says we then also have to set mfunc3 to IRQSER prior to
+	 * setting the INTRTIE bit!?
+	 */
+	switch (socket->dev->device) {
+		case PCI_DEVICE_ID_TI_1251A:
+		case PCI_DEVICE_ID_TI_1251B:
+		case PCI_DEVICE_ID_TI_1450:
+			sysctl = config_readl(socket, TI113X_SYSTEM_CONTROL);
+			if (!(sysctl & TI122X_SCR_INTRTIE))
+				mfunc = (mfunc & ~0x0f) | 0x01;
+			break;
+		case PCI_DEVICE_ID_TI_1220:
+		case PCI_DEVICE_ID_TI_1221:
+		case PCI_DEVICE_ID_TI_1225:
+		case PCI_DEVICE_ID_TI_1420:
+		case PCI_DEVICE_ID_TI_1451:
+		case PCI_DEVICE_ID_TI_1520:
+			sysctl = config_readl(socket, TI113X_SYSTEM_CONTROL);
+			if (!(sysctl & TI122X_SCR_INTRTIE))
+				mfunc = (mfunc & ~0xf0) | 0x20;
+
+		default:
+			break;
+	}
+#endif
+
+	if (mfunc != mfunc_old)
+		config_writel(socket, TI122X_IRQMUX, mfunc);
+
+	/* time to probe again */
+	pci = yenta_probe_cb_irq(socket);
+	if (pci == 1) {
+		mfunc_old = mfunc;
+		printk(KERN_INFO "Yenta TI: socket %s parallel PCI interrupts ok\n",
+		       pci_name(socket->dev));
+	} else {
+		/* not working, back to old value */
+		mfunc = mfunc_old;
+		config_writel(socket, TI122X_IRQMUX, mfunc);
+		printk(KERN_INFO "Yenta TI: socket %s no PCI interrupts. Fish. Please report.\n",
+		       pci_name(socket->dev));
+	}
+
+probe_isa:
+	if (pci < 1)
+		socket->cb_irq = 0;
+
+	/* need to call ti_override() before testing ISA interrupts */
+	ret = ti_override(socket);
+	if (ret)
+		goto out;
+
+	/* if all serial: setting is right (PCI interrutps are delivered) */
+	if ((devctl & TI113X_DCR_IMODE_MASK) == TI12XX_DCR_IMODE_ALL_SERIAL)
+		goto out;
+
+	/* probe interrupts before any 'fixup' */
+	probe_mask = yenta_probe_irq(socket, isa_interrupts);
+	if (probe_mask)
+		goto out;
+
+
+	/*
+	 * we're here which means ISA interrupts are not delivered. try to fix it
+	 */
+	printk(KERN_INFO "Yenta TI: socket %s probing ISA interrupts failed, trying to fix\n",
+	       pci_name(socket->dev));
+
+	/* serialized interrupts: MFUNC3 should be IRQSER */
+	if (devctl & TI113X_DCR_IMODE_SERIAL) {
+		switch (socket->dev->device) {
+			case PCI_DEVICE_ID_TI_1250:
+			case PCI_DEVICE_ID_TI_1251A:
+			case PCI_DEVICE_ID_TI_1251B:
+			case PCI_DEVICE_ID_TI_1450:
+			case PCI_DEVICE_ID_TI_1451A:
+			case PCI_DEVICE_ID_TI_4450:
+			case PCI_DEVICE_ID_TI_4451:
+				/* these chips have no IRQSER setting in MFUNC3  */
+				break;
+
+			default:
+				mfunc = (mfunc & ~0xf000) | 0x1000;
+
+				/* write down if changed, probe */
+				if (mfunc != mfunc_old) {
+					config_writel(socket, TI122X_IRQMUX, mfunc);
+
+					probe_mask = yenta_probe_irq(socket, isa_interrupts);
+					if (probe_mask) {
+						printk(KERN_INFO "Yenta TI: socket %s serial ISA interrupts ok\n",
+						       pci_name(socket->dev));
+						goto out;
+					}
+
+					/* not working, back to old value */
+					mfunc = mfunc_old;
+					config_writel(socket, TI122X_IRQMUX, mfunc);
+				}
+		}
+
+		/* serial ISA not working: fall back to PCI */
+		printk(KERN_INFO "Yenta TI: socket %s routing card interrupts to PCI\n",
+		       pci_name(socket->dev));
+		devctl &= ~TI113X_DCR_IMODE_MASK;
+		config_writeb(socket, TI113X_DEVICE_CONTROL, devctl);
+	}
+
+out:
+	return ret;
 }
 
 
@@ -365,26 +528,6 @@
 			old, diag);
 		config_writeb(socket, TI1250_DIAGNOSTIC, diag);
 	}
-
-#if 0
-	/*
-	 * This is highly machine specific, and we should NOT touch
-	 * this register - we have no knowledge how the hardware
-	 * is actually wired.
-	 *
-	 * If we're going to do this, we should probably look into
-	 * using the subsystem IDs.
-	 *
-	 * On ThinkPad 380XD, this changes MFUNC0 from the ISA IRQ3
-	 * output (which it is) to IRQ2.  We also change MFUNC1
-	 * from ISA IRQ4 to IRQ6.
-	 */
-	irqmux = config_readl(socket, TI122X_IRQMUX);
-	irqmux = (irqmux & ~0x0f) | 0x02; /* route INTA */
-	if (!(ti_sysctl(socket) & TI122X_SCR_INTRTIE))
-		irqmux = (irqmux & ~0xf0) | 0x20; /* route INTB */
-	config_writel(socket, TI122X_IRQMUX, irqmux);
-#endif
 
 	return ti12xx_override(socket);
 }

 




More information about the linux-pcmcia mailing list