[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