Fix error branches and config pending races in firewire init.

This way, if anything fails, it just fails; you don't panic.  This can
happen if suspending and resuming of firewire is broken (e.g., as I
encountered in PR kern/44581).
This commit is contained in:
riastradh 2012-08-04 03:55:43 +00:00
parent 3a4a1ac26a
commit 934b1cc688
6 changed files with 106 additions and 81 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: fwohci_cardbus.c,v 1.34 2011/08/01 11:20:27 drochner Exp $ */
/* $NetBSD: fwohci_cardbus.c,v 1.35 2012/08/04 03:55:43 riastradh Exp $ */
/*-
* Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: fwohci_cardbus.c,v 1.34 2011/08/01 11:20:27 drochner Exp $");
__KERNEL_RCSID(0, "$NetBSD: fwohci_cardbus.c,v 1.35 2012/08/04 03:55:43 riastradh Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -98,6 +98,8 @@ fwohci_cardbus_attach(device_t parent, device_t self, void *aux)
PCI_REVISION(ca->ca_class));
aprint_naive("\n");
fwohci_init(&sc->sc_sc);
/* Map I/O registers */
if (Cardbus_mapreg_map(ct, PCI_OHCI_MAP_REGISTER,
PCI_MAPREG_TYPE_MEM, 0,
@ -128,7 +130,7 @@ fwohci_cardbus_attach(device_t parent, device_t self, void *aux)
}
/* XXX NULL should be replaced by some call to Cardbus coed */
if (fwohci_init(&sc->sc_sc) != 0) {
if (fwohci_attach(&sc->sc_sc) != 0) {
Cardbus_intr_disestablish(ct, sc->sc_ih);
sc->sc_ih = NULL;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: firewire.c,v 1.39 2012/04/29 18:31:40 dsl Exp $ */
/* $NetBSD: firewire.c,v 1.40 2012/08/04 03:55:43 riastradh Exp $ */
/*-
* Copyright (c) 2003 Hidetoshi Shimokawa
* Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: firewire.c,v 1.39 2012/04/29 18:31:40 dsl Exp $");
__KERNEL_RCSID(0, "$NetBSD: firewire.c,v 1.40 2012/08/04 03:55:43 riastradh Exp $");
#include <sys/param.h>
#include <sys/bus.h>
@ -259,7 +259,6 @@ firewireattach(device_t parent, device_t self, void *aux)
if (kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL, fw_bus_probe_thread,
fc, &fc->probe_thread, "fw%dprobe", device_unit(fc->bdev)))
aprint_error_dev(self, "kthread_create failed\n");
config_pending_incr();
devlist = malloc(sizeof(struct firewire_dev_list), M_DEVBUF, M_NOWAIT);
if (devlist == NULL) {
@ -679,6 +678,15 @@ fw_init(struct firewire_comm *fc)
fc->crom_src_buf = NULL;
}
void
fw_destroy(struct firewire_comm *fc)
{
mutex_destroy(&fc->arq->q_mtx);
mutex_destroy(&fc->ars->q_mtx);
mutex_destroy(&fc->atq->q_mtx);
mutex_destroy(&fc->ats->q_mtx);
}
#define BIND_CMP(addr, fwb) \
(((addr) < (fwb)->start) ? -1 : ((fwb)->end < (addr)) ? 1 : 0)
@ -1935,8 +1943,6 @@ fw_bus_probe_thread(void *arg)
{
struct firewire_comm *fc = (struct firewire_comm *)arg;
config_pending_decr();
mutex_enter(&fc->wait_lock);
while (fc->status != FWBUSDETACH) {
if (fc->status == FWBUSEXPLORE) {

View File

@ -1,4 +1,4 @@
/* $NetBSD: firewirereg.h,v 1.17 2012/04/29 18:31:40 dsl Exp $ */
/* $NetBSD: firewirereg.h,v 1.18 2012/08/04 03:55:43 riastradh Exp $ */
/*-
* Copyright (c) 2003 Hidetoshi Shimokawa
* Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
@ -283,6 +283,7 @@ int fw_xferwait(struct fw_xfer *);
void fw_drain_txq(struct firewire_comm *);
void fw_busreset(struct firewire_comm *, uint32_t);
void fw_init(struct firewire_comm *);
void fw_destroy(struct firewire_comm *);
struct fw_bind *fw_bindlookup(struct firewire_comm *, uint16_t, uint32_t);
int fw_bindadd(struct firewire_comm *, struct fw_bind *);
int fw_bindremove(struct firewire_comm *, struct fw_bind *);

View File

@ -1,4 +1,4 @@
/* $NetBSD: fwohci.c,v 1.132 2011/07/31 13:51:53 uebayasi Exp $ */
/* $NetBSD: fwohci.c,v 1.133 2012/08/04 03:55:43 riastradh Exp $ */
/*-
* Copyright (c) 2003 Hidetoshi Shimokawa
@ -37,7 +37,7 @@
*
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: fwohci.c,v 1.132 2011/07/31 13:51:53 uebayasi Exp $");
__KERNEL_RCSID(0, "$NetBSD: fwohci.c,v 1.133 2012/08/04 03:55:43 riastradh Exp $");
#include <sys/param.h>
#include <sys/atomic.h>
@ -323,38 +323,15 @@ static void fwohci_arcv(struct fwohci_softc *, struct fwohci_dbch *);
#define IRX_CH 36
int
/*
* Call fwohci_init before fwohci_attach to initialize the kernel's
* data structures well enough that fwohci_detach won't crash, even if
* fwohci_attach fails.
*/
void
fwohci_init(struct fwohci_softc *sc)
{
uint32_t reg;
uint8_t ui[8];
int i, mver;
/* OHCI version */
reg = OREAD(sc, OHCI_VERSION);
mver = (reg >> 16) & 0xff;
aprint_normal_dev(sc->fc.dev, "OHCI version %x.%x (ROM=%d)\n",
mver, reg & 0xff, (reg >> 24) & 1);
if (mver < 1 || mver > 9) {
aprint_error_dev(sc->fc.dev, "invalid OHCI version\n");
return ENXIO;
}
/* Available Isochronous DMA channel probe */
OWRITE(sc, OHCI_IT_MASK, 0xffffffff);
OWRITE(sc, OHCI_IR_MASK, 0xffffffff);
reg = OREAD(sc, OHCI_IT_MASK) & OREAD(sc, OHCI_IR_MASK);
OWRITE(sc, OHCI_IT_MASKCLR, 0xffffffff);
OWRITE(sc, OHCI_IR_MASKCLR, 0xffffffff);
for (i = 0; i < 0x20; i++)
if ((reg & (1 << i)) == 0)
break;
sc->fc.nisodma = i;
aprint_normal_dev(sc->fc.dev, "No. of Isochronous channels is %d.\n",
i);
if (i == 0)
return ENXIO;
sc->fc.arq = &sc->arrq.xferq;
sc->fc.ars = &sc->arrs.xferq;
sc->fc.atq = &sc->atrq.xferq;
@ -395,6 +372,68 @@ fwohci_init(struct fwohci_softc *sc)
sc->atrq.off = OHCI_ATQOFF;
sc->atrs.off = OHCI_ATSOFF;
sc->fc.tcode = tinfo;
sc->fc.cyctimer = fwohci_cyctimer;
sc->fc.ibr = fwohci_ibr;
sc->fc.set_bmr = fwohci_set_bus_manager;
sc->fc.ioctl = fwohci_ioctl;
sc->fc.irx_enable = fwohci_irx_enable;
sc->fc.irx_disable = fwohci_irx_disable;
sc->fc.itx_enable = fwohci_itxbuf_enable;
sc->fc.itx_disable = fwohci_itx_disable;
sc->fc.timeout = fwohci_timeout;
sc->fc.set_intr = fwohci_set_intr;
#if BYTE_ORDER == BIG_ENDIAN
sc->fc.irx_post = fwohci_irx_post;
#else
sc->fc.irx_post = NULL;
#endif
sc->fc.itx_post = NULL;
sc->intmask = sc->irstat = sc->itstat = 0;
fw_init(&sc->fc);
}
/*
* Call fwohci_attach after fwohci_init to initialize the hardware and
* attach children.
*/
int
fwohci_attach(struct fwohci_softc *sc)
{
uint32_t reg;
uint8_t ui[8];
int i, mver;
/* OHCI version */
reg = OREAD(sc, OHCI_VERSION);
mver = (reg >> 16) & 0xff;
aprint_normal_dev(sc->fc.dev, "OHCI version %x.%x (ROM=%d)\n",
mver, reg & 0xff, (reg >> 24) & 1);
if (mver < 1 || mver > 9) {
aprint_error_dev(sc->fc.dev, "invalid OHCI version\n");
return ENXIO;
}
/* Available Isochronous DMA channel probe */
OWRITE(sc, OHCI_IT_MASK, 0xffffffff);
OWRITE(sc, OHCI_IR_MASK, 0xffffffff);
reg = OREAD(sc, OHCI_IT_MASK) & OREAD(sc, OHCI_IR_MASK);
OWRITE(sc, OHCI_IT_MASKCLR, 0xffffffff);
OWRITE(sc, OHCI_IR_MASKCLR, 0xffffffff);
for (i = 0; i < 0x20; i++)
if ((reg & (1 << i)) == 0)
break;
sc->fc.nisodma = i;
aprint_normal_dev(sc->fc.dev, "No. of Isochronous channels is %d.\n",
i);
if (i == 0)
return ENXIO;
for (i = 0; i < sc->fc.nisodma; i++) {
sc->fc.it[i] = &sc->it[i].xferq;
sc->fc.ir[i] = &sc->ir[i].xferq;
@ -406,8 +445,6 @@ fwohci_init(struct fwohci_softc *sc)
sc->ir[i].off = OHCI_IROFF(i);
}
sc->fc.tcode = tinfo;
sc->fc.config_rom = fwdma_alloc_setup(sc->fc.dev, sc->fc.dmat,
CROMSIZE, &sc->crom_dma, CROMSIZE, BUS_DMA_NOWAIT);
if (sc->fc.config_rom == NULL) {
@ -467,27 +504,6 @@ fwohci_init(struct fwohci_softc *sc)
"EUI64 %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
ui[0], ui[1], ui[2], ui[3], ui[4], ui[5], ui[6], ui[7]);
sc->fc.cyctimer = fwohci_cyctimer;
sc->fc.ibr = fwohci_ibr;
sc->fc.set_bmr = fwohci_set_bus_manager;
sc->fc.ioctl = fwohci_ioctl;
sc->fc.irx_enable = fwohci_irx_enable;
sc->fc.irx_disable = fwohci_irx_disable;
sc->fc.itx_enable = fwohci_itxbuf_enable;
sc->fc.itx_disable = fwohci_itx_disable;
sc->fc.timeout = fwohci_timeout;
sc->fc.set_intr = fwohci_set_intr;
#if BYTE_ORDER == BIG_ENDIAN
sc->fc.irx_post = fwohci_irx_post;
#else
sc->fc.irx_post = NULL;
#endif
sc->fc.itx_post = NULL;
sc->intmask = sc->irstat = sc->itstat = 0;
fw_init(&sc->fc);
fwohci_reset(sc);
sc->fc.bdev =
@ -499,10 +515,13 @@ fwohci_init(struct fwohci_softc *sc)
int
fwohci_detach(struct fwohci_softc *sc, int flags)
{
int i;
int i, rv;
if (sc->fc.bdev != NULL)
config_detach(sc->fc.bdev, flags);
if (sc->fc.bdev != NULL) {
rv = config_detach(sc->fc.bdev, flags);
if (rv)
return rv;
}
if (sc->sid_buf != NULL)
fwdma_free(sc->sid_dma.dma_tag, sc->sid_dma.dma_map,
sc->sid_dma.v_addr);
@ -519,10 +538,7 @@ fwohci_detach(struct fwohci_softc *sc, int flags)
fwohci_db_free(sc, &sc->ir[i]);
}
mutex_destroy(&sc->arrq.xferq.q_mtx);
mutex_destroy(&sc->arrs.xferq.q_mtx);
mutex_destroy(&sc->atrq.xferq.q_mtx);
mutex_destroy(&sc->atrs.xferq.q_mtx);
fw_destroy(&sc->fc);
return 0;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: fwohcivar.h,v 1.33 2012/04/29 18:31:40 dsl Exp $ */
/* $NetBSD: fwohcivar.h,v 1.34 2012/08/04 03:55:43 riastradh Exp $ */
/*-
* Copyright (c) 2003 Hidetoshi SHimokawa
@ -77,7 +77,8 @@ struct fwohci_softc {
#define OWRITE(sc, r, x) bus_space_write_4((sc)->bst, (sc)->bsh, (r), (x))
#define OREAD(sc, r) bus_space_read_4((sc)->bst, (sc)->bsh, (r))
int fwohci_init(struct fwohci_softc *);
void fwohci_init(struct fwohci_softc *);
int fwohci_attach(struct fwohci_softc *);
int fwohci_detach(struct fwohci_softc *, int);
int fwohci_intr(void *arg);
int fwohci_resume(struct fwohci_softc *);

View File

@ -1,4 +1,4 @@
/* $NetBSD: fwohci_pci.c,v 1.40 2012/01/30 19:41:19 drochner Exp $ */
/* $NetBSD: fwohci_pci.c,v 1.41 2012/08/04 03:55:44 riastradh Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: fwohci_pci.c,v 1.40 2012/01/30 19:41:19 drochner Exp $");
__KERNEL_RCSID(0, "$NetBSD: fwohci_pci.c,v 1.41 2012/08/04 03:55:44 riastradh Exp $");
#include <sys/param.h>
#include <sys/bus.h>
@ -102,6 +102,8 @@ fwohci_pci_attach(device_t parent, device_t self, void *aux)
pci_aprint_devinfo(pa, "IEEE 1394 Controller");
fwohci_init(&psc->psc_sc);
psc->psc_sc.fc.dev = self;
psc->psc_sc.fc.dmat = pa->pa_dmat;
psc->psc_pc = pa->pa_pc;
@ -149,15 +151,12 @@ fwohci_pci_attach(device_t parent, device_t self, void *aux)
}
aprint_normal_dev(self, "interrupting at %s\n", intrstr);
if (fwohci_attach(&psc->psc_sc) != 0)
goto fail;
if (!pmf_device_register(self, fwohci_pci_suspend, fwohci_pci_resume))
aprint_error_dev(self, "couldn't establish power handler\n");
if (fwohci_init(&psc->psc_sc) != 0) {
pci_intr_disestablish(pa->pa_pc, psc->psc_ih);
bus_space_unmap(psc->psc_sc.bst, psc->psc_sc.bsh,
psc->psc_sc.bssize);
}
return;
fail: