Improve interlocking for card removal. We now can remove the card in
the ISR. We keep track of the card state and don't call the IRS when the card isn't inserted. This helps quite a bit with card ejection problems that Ian was seeing. Submitted by: Ian Dowse MFC upon: re approvel.
This commit is contained in:
parent
aad8d98833
commit
6ac061b532
@ -438,25 +438,36 @@ pcic_pci_cardtype(u_int32_t stat)
|
||||
return ("none (can't happen)");
|
||||
}
|
||||
|
||||
/*
|
||||
* Card insertion and removal code. The insertion events need to be
|
||||
* debounced so that the noisy insertion/removal events don't result
|
||||
* in the hardware being initialized many times, only to be torn down
|
||||
* as well. This may also cause races with pccardd. Instead, we wait
|
||||
* for the insertion signal to be stable for 0.5 seconds before we declare
|
||||
* it to be a real insertion event. Removal is done right away.
|
||||
*
|
||||
* Note: We only handle the card detect change events. We don't handle
|
||||
* power events and status change events.
|
||||
*/
|
||||
static void
|
||||
pcic_cd_event(void *arg)
|
||||
pcic_cd_insert(void *arg)
|
||||
{
|
||||
struct pcic_softc *sc = (struct pcic_softc *) arg;
|
||||
struct pcic_slot *sp = &sc->slots[0];
|
||||
u_int32_t stat;
|
||||
|
||||
|
||||
sc->cd_pending = 0;
|
||||
stat = bus_space_read_4(sp->bst, sp->bsh, CB_SOCKET_STATE);
|
||||
device_printf(sc->dev, "debounced state is 0x%x\n", stat);
|
||||
if ((stat & CB_SS_CD) == 0) {
|
||||
if ((stat & CB_SS_16BIT) == 0)
|
||||
device_printf(sp->sc->dev, "Unsupported card: %s\n",
|
||||
pcic_pci_cardtype(stat));
|
||||
else
|
||||
pccard_event(sp->slt, card_inserted);
|
||||
} else {
|
||||
pccard_event(sp->slt, card_removed);
|
||||
}
|
||||
sc->cd_pending = 0;
|
||||
|
||||
/* Just return if the interrupt handler missed a remove transition. */
|
||||
if ((stat & CB_SS_CD) != 0)
|
||||
return;
|
||||
sc->cd_present = 1;
|
||||
if ((stat & CB_SS_16BIT) == 0)
|
||||
device_printf(sp->sc->dev, "Card type %s is unsupported\n",
|
||||
pcic_pci_cardtype(stat));
|
||||
else
|
||||
pccard_event(sp->slt, card_inserted);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -466,20 +477,37 @@ pcic_pci_intr(void *arg)
|
||||
struct pcic_slot *sp = &sc->slots[0];
|
||||
u_int32_t event;
|
||||
u_int32_t stat;
|
||||
int present;
|
||||
|
||||
event = bus_space_read_4(sp->bst, sp->bsh, CB_SOCKET_EVENT);
|
||||
if (event != 0) {
|
||||
device_printf(sc->dev, "Event mask 0x%x\n", event);
|
||||
if ((event & CB_SE_CD) != 0 && !sc->cd_pending) {
|
||||
sc->cd_pending = 1;
|
||||
timeout(pcic_cd_event, arg, hz/2);
|
||||
stat = bus_space_read_4(sp->bst, sp->bsh, CB_SOCKET_STATE);
|
||||
if (bootverbose)
|
||||
device_printf(sc->dev, "Event mask 0x%x stat 0x%x\n",
|
||||
event, stat);
|
||||
|
||||
present = (stat & CB_SS_CD) == 0;
|
||||
if (present != sc->cd_present) {
|
||||
if (sc->cd_pending) {
|
||||
untimeout(pcic_cd_insert, arg, sc->cd_ch);
|
||||
sc->cd_pending = 0;
|
||||
}
|
||||
/* Delay insert events to debounce noisy signals. */
|
||||
if (present) {
|
||||
sc->cd_ch = timeout(pcic_cd_insert, arg, hz/2);
|
||||
sc->cd_pending = 1;
|
||||
} else {
|
||||
sc->cd_present = 0;
|
||||
sp->intr = NULL;
|
||||
pccard_event(sp->slt, card_removed);
|
||||
}
|
||||
}
|
||||
/* Ack the interrupt, all of them to be safe */
|
||||
bus_space_write_4(sp->bst, sp->bsh, 0, 0xffffffff);
|
||||
/* Ack the interrupt */
|
||||
bus_space_write_4(sp->bst, sp->bsh, 0, event);
|
||||
}
|
||||
|
||||
/*
|
||||
* TI chips also require us to read the old ExCA register for
|
||||
* Some TI chips also require us to read the old ExCA register for
|
||||
* card status change when we route CSC via PCI! So, we go ahead
|
||||
* and read it to clear the bits. Maybe we should check the status
|
||||
* ala the ISA interrupt handler, but those changes should be caught
|
||||
@ -487,12 +515,14 @@ pcic_pci_intr(void *arg)
|
||||
*/
|
||||
sp->getb(sp, PCIC_STAT_CHG);
|
||||
|
||||
/* Now call children interrupts if any */
|
||||
stat = bus_space_read_4(sp->bst, sp->bsh, CB_SOCKET_STATE);
|
||||
if ((stat & CB_SS_CD) == 0) {
|
||||
if (sp->intr != NULL)
|
||||
sp->intr(sp->argp);
|
||||
}
|
||||
/*
|
||||
* If we have a card in the slot with an interrupt handler, then
|
||||
* call it. Note: This means that each card can have at most one
|
||||
* interrupt handler for it. Since multifunction cards aren't
|
||||
* supported, this shouldn't cause a problem in practice.
|
||||
*/
|
||||
if (sc->cd_present && sp->intr != NULL)
|
||||
sp->intr(sp->argp);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -144,8 +144,8 @@
|
||||
#define CB_SOCKET_POWER 0x14
|
||||
#define CB_EXCA_OFFSET 0x800 /* Offset for ExCA registers */
|
||||
|
||||
#define CB_SM_CD 0x6 /* Socket MASK Card detect */
|
||||
#define CB_SE_CD 0x6 /* Socket Event Card detect */
|
||||
#define CB_SM_CD 0x6 /* Socket MASK Card detect */
|
||||
|
||||
#define CB_SS_CARDSTS 0x00000001 /* Card Status Change */
|
||||
#define CB_SS_CD1 0x00000002 /* Card Detect 1 */
|
||||
|
@ -67,7 +67,9 @@ struct pcic_softc
|
||||
void (*slot_poll)(void *);
|
||||
struct callout_handle timeout_ch;
|
||||
struct pcic_slot slots[PCIC_MAX_SLOTS];
|
||||
int cd_pending;
|
||||
int cd_pending; /* debounce timeout active */
|
||||
int cd_present; /* debounced card-present state */
|
||||
struct callout_handle cd_ch; /* handle for pcic_cd_insert */
|
||||
};
|
||||
|
||||
extern devclass_t pcic_devclass;
|
||||
|
Loading…
Reference in New Issue
Block a user