Date: Wed, 24 Sep 1997 14:47:44 +0200 From: Stefan Esser <se@FreeBSD.ORG> To: Nate Williams <nate@mt.sri.com> Cc: mobile@FreeBSD.ORG, current@FreeBSD.ORG Subject: Re: PCCARD in -current broken Message-ID: <19970924144744.47293@mi.uni-koeln.de> In-Reply-To: <199709232246.QAA09189@rocky.mt.sri.com>; from Nate Williams on Tue, Sep 23, 1997 at 04:46:56PM -0600 References: <199709231929.NAA08312@rocky.mt.sri.com> <19970923230018.00034@mi.uni-koeln.de> <199709232246.QAA09189@rocky.mt.sri.com>
next in thread | previous in thread | raw e-mail | index | archive | help
On Sep 23, Nate Williams <nate@mt.sri.com> wrote:
> > There should not be a problem. ISA does not
> > (should not, I didn't check the sources
> > recently) register the handler as shared,
> > and this will prevent another handler (both
> > shared or exclusive) to be registered.
>
> register_intr() sets the INTR_EXCL flag just before it calls
> intr_create() (so far so good), but in intr_connect(), the code to check
> for that flag is ifdef's out:
Well, I have implemented experimental resource
registration and check code, but come to the
conclusion, that it should be done quite
differently ...
> int
> intr_connect(intrec *idesc)
> {
> ....
> #ifdef RESOURCE_CHECK
> resflag = (idesc->flags & INTR_EXCL) ? RESF_NONE : RESF_SHARED;
> if (resource_claim(idesc->devdata, REST_INT, resflag, irq, irq) == 0)
> #endif /* RESOURCE_CHECK */
> {
>
> So, we don't even check to see if INTR_EXCL is used.
Well, you don't. I do, but I don't rely on that
check :)
> How does the new code realize that the interrupt is exclusive then?
I have implemented a very simple set of functions
to claim and check resource usage, and you see the
resource_claim() call above. (The code does know
resource types (e.g. REST_INT is interrupt), the
minimum and maximum value (both passed as "irq"
in the example), and a flag that currently only
takes the value RESF_SHARED, if a resource may
be shared with other uses, as long as all of them
have RESF_SHARED set.
> > Well, ISA interrupts should be registered in
> > a way that guarantees they are not shared.
>
> How?
But the code in -current does not use this function,
and to make sure, that no other interrupt is added
in combination with an exclusive interrupt, there is
the test in add_intrdesc(), which I outlined in my
previous reply.
> So, can I rely on register_intr() return a negative # for failure?
Well, if it fails for you, then there definitely is
a bug in the check I added to add_intrdesc(), which
is there to avoid just this situation.
I assume you are sure that the PCCARD code is only
called after the ISA devices are attached ?
> (Here's the code in question.)
> static u_int
> build_freelist(u_int pcic_mask)
> {
> inthand2_t *nullfunc;
> int irq;
> u_int mask, freemask;
>
> /* No free IRQs (yet). */
> freemask = 0;
>
> /* Walk through all of the IRQ's and find any that aren't allocated. */
> for (irq = 0; irq < ICU_LEN; irq++) {
> /*
> * If the PCIC controller can't generate it, don't
> * bother checking to see if it it's free.
> */
> mask = 1 << irq;
> if (!(mask & pcic_mask)) continue;
>
> /* See if the IRQ is free. */
> if (register_intr(irq, 0, 0, nullfunc, NULL, irq) == 0) {
> /* Give it back, but add it to the mask */
> INTRMASK(freemask, mask);
> unregister_intr(irq, nullfunc);
> }
> }
> #ifdef PCIC_DEBUG
> printf("Freelist of IRQ's <0x%x>\n", freemask);
> #endif
> return freemask;
> }
Looks fine to me. Lets see what happens after you call
register_intr():
[ Much simplified extract from /sys/kern/kern_intr.c ! ]
/** INTR_EXCL is added to flags and passed to intr_create(). **/
int
register_intr(int intr, int device_id, u_int flags,
inthand2_t handler, u_int *maskptr, int unit)
{
flags |= INTR_EXCL;
idesc = intr_create((void *)device_id, intr, handler,
(void*)unit, maskptr, flags);
return (intr_connect(idesc));
}
/** The flags parameter is put into the idesc structure. **/
intrec *
intr_create(void *dev_instance, int irq, inthand2_t handler, void *arg,
intrmask_t *maskptr, int flags)
{
idesc = malloc(sizeof *idesc, M_DEVBUF, M_WAITOK);
if (idesc) {
idesc->flags = flags;
}
return (idesc);
}
/** Return the error code from add_intrdesc (rest of code not shown). **/
int
intr_connect(intrec *idesc)
{
errcode = add_intrdesc(idesc);
return (errcode);
}
/** If this is the first handler for this irq, just register it. **/
/** If another handler has been registered before, then make sure, **/
/** that both the old and new handler are for a device that supports **/
/** shared interrupts (does not have INTR_EXCL set). Only the first **/
/** handler can have INTR_EXCL set, since no second one could have **/
/** been added ... **/
static int
add_intrdesc(intrec *idesc)
{
if (head == NULL) {
/* first handler for this irq, just install it */
if (icu_setup(irq, idesc->handler, idesc->argument,
idesc->maskptr, idesc->flags) != 0)
return (-1);
} else {
if ((idesc->flags & INTR_EXCL) != 0
|| (head->flags & INTR_EXCL) != 0) {
/*
* can't append new handler, if either list head or
* new handler do not allow interrupts to be shared
*/
printf("\tdevice combination doesn't support shared irq%d\n",
irq);
return (-1);
}
/* DO REAL WORK */
}
return (0);
}
Well, in fact you should see the "device combination doesn't support ..."
message printed, when you call register_intr() to check for the interrupt
to be available. If you don't then there is a good chance, that you perform
this test, before the ISA devices are attached, and there is no collision
reported until the PCCARD attach tries to register a handler for an assumed
free IRQ, which has been claimed by an ISA driver in between ...
Regards, Stefan
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?19970924144744.47293>
