During shutdown, detach devices in an orderly fashion.

Call the detach routine for every device in the device tree, starting
with the leaves and moving toward the root, expecting that each
(pseudo-)device driver will use the opportunity to gracefully commit
outstandings transactions to the underlying (pseudo-)device and to
relinquish control of the hardware to the system BIOS.

Detaching devices is not suitable for every shutdown: in an emergency,
or if the system state is inconsistent, we should resort to a fast,
simple shutdown that uses only the pmf(9) shutdown hooks and the
(deprecated) shutdownhooks.  For now, if the flag RB_NOSYNC is set in
boothowto, opt for the fast, simple shutdown.

Add a device flag, DVF_DETACH_SHUTDOWN, that indicates by its presence
that it is safe to detach a device during shutdown.  Introduce macros
CFATTACH_DECL3() and CFATTACH_DECL3_NEW() for creating autoconf
attachments with default device flags.  Add DVF_DETACH_SHUTDOWN
to configuration attachments for atabus(4), atw(4) at cardbus(4),
cardbus(4), cardslot(4), com(4) at isa(4), elanpar(4), elanpex(4),
elansc(4), gpio(4), npx(4) at isa(4), nsphyter(4), pci(4), pcib(4),
pcmcia(4), ppb(4), sip(4), wd(4), and wdc(4) at isa(4).

Add a device-detachment "reason" flag, DETACH_SHUTDOWN, that tells the
autoconf code and a device driver that the reason for detachment is
system shutdown.

Add a sysctl, kern.detachall, that tells the system to try to detach
every device at shutdown, regardless of any device's DVF_DETACH_SHUTDOWN
flag.  The default for kern.detachall is 0.  SET IT TO 1, PLEASE, TO
HELP TEST AND DEBUG DEVICE DETACHMENT AT SHUTDOWN.

This is a work in progress.  In future work, I aim to treat
pseudo-devices more thoroughly, and to gracefully tear down a stack of
(pseudo-)disk drivers and filesystems, including cgd(4), vnd(4), and
raid(4) instances at shutdown.

Also commit some changes that are not easily untangled from the rest:

(1) begin to simplify device_t locking: rename struct pmf_private to
device_lock, and incorporate device_lock into struct device.

(2) #include <sys/device.h> in sys/pmf.h in order to get some
definitions that it needs.  Stop unnecessarily #including <sys/device.h>
in sys/arch/x86/include/pic.h to keep the amd64, xen, and i386 releases
building.
This commit is contained in:
dyoung 2009-04-02 00:09:32 +00:00
parent 49d3640ae0
commit 0d1ba3e899
22 changed files with 208 additions and 153 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: npx_isa.c,v 1.19 2008/04/11 20:42:34 cegger Exp $ */
/* $NetBSD: npx_isa.c,v 1.20 2009/04/02 00:09:32 dyoung Exp $ */
/*-
* Copyright (c) 1991 The Regents of the University of California.
@ -67,7 +67,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: npx_isa.c,v 1.19 2008/04/11 20:42:34 cegger Exp $");
__KERNEL_RCSID(0, "$NetBSD: npx_isa.c,v 1.20 2009/04/02 00:09:32 dyoung Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -86,8 +86,9 @@ __KERNEL_RCSID(0, "$NetBSD: npx_isa.c,v 1.19 2008/04/11 20:42:34 cegger Exp $");
int npx_isa_probe(device_t, struct cfdata *, void *);
void npx_isa_attach(device_t, device_t, void *);
CFATTACH_DECL_NEW(npx_isa, sizeof(struct npx_softc),
npx_isa_probe, npx_isa_attach, npxdetach, NULL);
CFATTACH_DECL3_NEW(npx_isa, sizeof(struct npx_softc),
npx_isa_probe, npx_isa_attach, npxdetach, NULL, NULL, NULL,
DVF_DETACH_SHUTDOWN);
int
npx_isa_probe(device_t parent, struct cfdata *match, void *aux)

View File

@ -1,4 +1,4 @@
/* $NetBSD: elan520.c,v 1.38 2009/02/24 06:03:54 yamt Exp $ */
/* $NetBSD: elan520.c,v 1.39 2009/04/02 00:09:32 dyoung Exp $ */
/*-
* Copyright (c) 2002 The NetBSD Foundation, Inc.
@ -40,7 +40,7 @@
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: elan520.c,v 1.38 2009/02/24 06:03:54 yamt Exp $");
__KERNEL_RCSID(0, "$NetBSD: elan520.c,v 1.39 2009/04/02 00:09:32 dyoung Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -1464,15 +1464,17 @@ elansc_rescan(device_t self, const char *ifattr, const int *locators)
return 0;
}
CFATTACH_DECL_NEW(elanpar, 0,
elanpar_match, elanpar_attach, elanpar_detach, NULL);
CFATTACH_DECL3_NEW(elanpar, 0,
elanpar_match, elanpar_attach, elanpar_detach, NULL, NULL, NULL,
DVF_DETACH_SHUTDOWN);
CFATTACH_DECL_NEW(elanpex, 0,
elanpex_match, elanpex_attach, elanpex_detach, NULL);
CFATTACH_DECL3_NEW(elanpex, 0,
elanpex_match, elanpex_attach, elanpex_detach, NULL, NULL, NULL,
DVF_DETACH_SHUTDOWN);
CFATTACH_DECL2_NEW(elansc, sizeof(struct elansc_softc),
CFATTACH_DECL3_NEW(elansc, sizeof(struct elansc_softc),
elansc_match, elansc_attach, elansc_detach, NULL, elansc_rescan,
elansc_childdetached);
elansc_childdetached, DVF_DETACH_SHUTDOWN);
#if NGPIO > 0
static int

View File

@ -1,10 +1,8 @@
/* $NetBSD: pic.h,v 1.5 2008/07/03 14:02:25 drochner Exp $ */
/* $NetBSD: pic.h,v 1.6 2009/04/02 00:09:32 dyoung Exp $ */
#ifndef _X86_PIC_H
#define _X86_PIC_H
#include <sys/device.h>
struct cpu_info;
/*

View File

@ -1,4 +1,4 @@
/* $NetBSD: pcib.c,v 1.7 2008/08/04 06:01:18 cegger Exp $ */
/* $NetBSD: pcib.c,v 1.8 2009/04/02 00:09:32 dyoung Exp $ */
/*-
* Copyright (c) 1996, 1998 The NetBSD Foundation, Inc.
@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: pcib.c,v 1.7 2008/08/04 06:01:18 cegger Exp $");
__KERNEL_RCSID(0, "$NetBSD: pcib.c,v 1.8 2009/04/02 00:09:32 dyoung Exp $");
#include <sys/types.h>
#include <sys/param.h>
@ -54,8 +54,9 @@ void pcibattach(device_t, device_t, void *);
int pcibdetach(device_t, int);
void pcibchilddet(device_t, device_t);
CFATTACH_DECL2_NEW(pcib, sizeof(struct pcib_softc),
pcibmatch, pcibattach, pcibdetach, NULL, NULL, pcibchilddet);
CFATTACH_DECL3_NEW(pcib, sizeof(struct pcib_softc),
pcibmatch, pcibattach, pcibdetach, NULL, NULL, pcibchilddet,
DVF_DETACH_SHUTDOWN);
void pcib_callback(device_t);

View File

@ -1,4 +1,4 @@
/* $NetBSD: ata.c,v 1.102 2008/11/16 19:31:21 bouyer Exp $ */
/* $NetBSD: ata.c,v 1.103 2009/04/02 00:09:32 dyoung Exp $ */
/*
* Copyright (c) 1998, 2001 Manuel Bouyer. All rights reserved.
@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.102 2008/11/16 19:31:21 bouyer Exp $");
__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.103 2009/04/02 00:09:32 dyoung Exp $");
#include "opt_ata.h"
@ -617,9 +617,9 @@ atabus_childdetached(device_t self, device_t child)
aprint_error_dev(self, "unknown child %p", (const void *)child);
}
CFATTACH_DECL2_NEW(atabus, sizeof(struct atabus_softc),
CFATTACH_DECL3_NEW(atabus, sizeof(struct atabus_softc),
atabus_match, atabus_attach, atabus_detach, atabus_activate, NULL,
atabus_childdetached);
atabus_childdetached, DVF_DETACH_SHUTDOWN);
/*****************************************************************************
* Common ATA bus operations.

View File

@ -1,4 +1,4 @@
/* $NetBSD: wd.c,v 1.370 2009/02/10 19:45:22 tron Exp $ */
/* $NetBSD: wd.c,v 1.371 2009/04/02 00:09:32 dyoung Exp $ */
/*
* Copyright (c) 1998, 2001 Manuel Bouyer. All rights reserved.
@ -59,7 +59,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.370 2009/02/10 19:45:22 tron Exp $");
__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.371 2009/04/02 00:09:32 dyoung Exp $");
#include "opt_ata.h"
@ -136,8 +136,8 @@ void wdperror(const struct wd_softc *);
static bool wd_suspend(device_t PMF_FN_PROTO);
static int wd_standby(struct wd_softc *, int);
CFATTACH_DECL_NEW(wd, sizeof(struct wd_softc),
wdprobe, wdattach, wddetach, wdactivate);
CFATTACH_DECL3_NEW(wd, sizeof(struct wd_softc),
wdprobe, wdattach, wddetach, wdactivate, NULL, NULL, DVF_DETACH_SHUTDOWN);
extern struct cfdriver wd_cd;

View File

@ -1,4 +1,4 @@
/* $NetBSD: cardbus.c,v 1.95 2008/06/25 11:42:32 drochner Exp $ */
/* $NetBSD: cardbus.c,v 1.96 2009/04/02 00:09:33 dyoung Exp $ */
/*
* Copyright (c) 1997, 1998, 1999 and 2000
@ -33,7 +33,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: cardbus.c,v 1.95 2008/06/25 11:42:32 drochner Exp $");
__KERNEL_RCSID(0, "$NetBSD: cardbus.c,v 1.96 2009/04/02 00:09:33 dyoung Exp $");
#include "opt_cardbus.h"
@ -91,9 +91,9 @@ static void disable_function(struct cardbus_softc *, int);
static bool cardbus_child_register(device_t);
CFATTACH_DECL2_NEW(cardbus, sizeof(struct cardbus_softc),
CFATTACH_DECL3_NEW(cardbus, sizeof(struct cardbus_softc),
cardbusmatch, cardbusattach, cardbusdetach, NULL,
cardbus_rescan, cardbus_childdetached);
cardbus_rescan, cardbus_childdetached, DVF_DETACH_SHUTDOWN);
#ifndef __NetBSD_Version__
struct cfdriver cardbus_cd = {

View File

@ -1,4 +1,4 @@
/* $NetBSD: cardslot.c,v 1.46 2009/03/14 15:36:16 dsl Exp $ */
/* $NetBSD: cardslot.c,v 1.47 2009/04/02 00:09:33 dyoung Exp $ */
/*
* Copyright (c) 1999 and 2000
@ -33,7 +33,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: cardslot.c,v 1.46 2009/03/14 15:36:16 dsl Exp $");
__KERNEL_RCSID(0, "$NetBSD: cardslot.c,v 1.47 2009/04/02 00:09:33 dyoung Exp $");
#include "opt_cardslot.h"
@ -75,8 +75,9 @@ static int cardslot_16_print(void *, const char *);
static int cardslot_16_submatch(struct device *, struct cfdata *,
const int *, void *);
CFATTACH_DECL_NEW(cardslot, sizeof(struct cardslot_softc),
cardslotmatch, cardslotattach, cardslotdetach, NULL);
CFATTACH_DECL3_NEW(cardslot, sizeof(struct cardslot_softc),
cardslotmatch, cardslotattach, cardslotdetach, NULL, NULL, NULL,
DVF_DETACH_SHUTDOWN);
STATIC int
cardslotmatch(struct device *parent, struct cfdata *cf,

View File

@ -1,4 +1,4 @@
/* $NetBSD: if_atw_cardbus.c,v 1.25 2009/02/06 02:00:50 dyoung Exp $ */
/* $NetBSD: if_atw_cardbus.c,v 1.26 2009/04/02 00:09:33 dyoung Exp $ */
/*-
* Copyright (c) 1999, 2000, 2003 The NetBSD Foundation, Inc.
@ -36,7 +36,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: if_atw_cardbus.c,v 1.25 2009/02/06 02:00:50 dyoung Exp $");
__KERNEL_RCSID(0, "$NetBSD: if_atw_cardbus.c,v 1.26 2009/04/02 00:09:33 dyoung Exp $");
#include "opt_inet.h"
#include "bpfilter.h"
@ -116,8 +116,9 @@ static int atw_cardbus_match(device_t, cfdata_t, void *);
static void atw_cardbus_attach(device_t, device_t, void *);
static int atw_cardbus_detach(device_t, int);
CFATTACH_DECL_NEW(atw_cardbus, sizeof(struct atw_cardbus_softc),
atw_cardbus_match, atw_cardbus_attach, atw_cardbus_detach, atw_activate);
CFATTACH_DECL3_NEW(atw_cardbus, sizeof(struct atw_cardbus_softc),
atw_cardbus_match, atw_cardbus_attach, atw_cardbus_detach, atw_activate,
NULL, NULL, DVF_DETACH_SHUTDOWN);
static void atw_cardbus_setup(struct atw_cardbus_softc *);

View File

@ -1,4 +1,4 @@
/* $NetBSD: gpio.c,v 1.17 2008/05/01 22:00:44 cegger Exp $ */
/* $NetBSD: gpio.c,v 1.18 2009/04/02 00:09:33 dyoung Exp $ */
/* $OpenBSD: gpio.c,v 1.6 2006/01/14 12:33:49 grange Exp $ */
/*
@ -18,7 +18,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: gpio.c,v 1.17 2008/05/01 22:00:44 cegger Exp $");
__KERNEL_RCSID(0, "$NetBSD: gpio.c,v 1.18 2009/04/02 00:09:33 dyoung Exp $");
/*
* General Purpose Input/Output framework.
@ -55,8 +55,9 @@ int gpio_activate(device_t, enum devact);
int gpio_search(device_t, cfdata_t, const int *, void *);
int gpio_print(void *, const char *);
CFATTACH_DECL_NEW(gpio, sizeof(struct gpio_softc),
gpio_match, gpio_attach, gpio_detach, gpio_activate);
CFATTACH_DECL3_NEW(gpio, sizeof(struct gpio_softc),
gpio_match, gpio_attach, gpio_detach, gpio_activate, NULL, NULL,
DVF_DETACH_SHUTDOWN);
dev_type_open(gpioopen);
dev_type_close(gpioclose);

View File

@ -1,4 +1,4 @@
/* $NetBSD: com_isa.c,v 1.34 2008/04/28 20:23:52 martin Exp $ */
/* $NetBSD: com_isa.c,v 1.35 2009/04/02 00:09:33 dyoung Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -61,7 +61,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: com_isa.c,v 1.34 2008/04/28 20:23:52 martin Exp $");
__KERNEL_RCSID(0, "$NetBSD: com_isa.c,v 1.35 2009/04/02 00:09:33 dyoung Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -107,8 +107,9 @@ int com_isa_isHAYESP(bus_space_handle_t, struct com_softc *);
#endif
CFATTACH_DECL_NEW(com_isa, sizeof(struct com_isa_softc),
com_isa_probe, com_isa_attach, com_isa_detach, com_activate);
CFATTACH_DECL3_NEW(com_isa, sizeof(struct com_isa_softc),
com_isa_probe, com_isa_attach, com_isa_detach, com_activate,
NULL, NULL, DVF_DETACH_SHUTDOWN);
int
com_isa_probe(device_t parent, cfdata_t match, void *aux)

View File

@ -1,4 +1,4 @@
/* $NetBSD: wdc_isa.c,v 1.55 2008/04/28 20:23:52 martin Exp $ */
/* $NetBSD: wdc_isa.c,v 1.56 2009/04/02 00:09:33 dyoung Exp $ */
/*-
* Copyright (c) 1998, 2003 The NetBSD Foundation, Inc.
@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: wdc_isa.c,v 1.55 2008/04/28 20:23:52 martin Exp $");
__KERNEL_RCSID(0, "$NetBSD: wdc_isa.c,v 1.56 2009/04/02 00:09:33 dyoung Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -71,9 +71,9 @@ static int wdc_isa_probe(device_t , cfdata_t, void *);
static void wdc_isa_attach(device_t, device_t, void *);
static int wdc_isa_detach(device_t, int);
CFATTACH_DECL2_NEW(wdc_isa, sizeof(struct wdc_isa_softc),
CFATTACH_DECL3_NEW(wdc_isa, sizeof(struct wdc_isa_softc),
wdc_isa_probe, wdc_isa_attach, wdc_isa_detach, NULL, NULL,
wdc_childdetached);
wdc_childdetached, DVF_DETACH_SHUTDOWN);
#if 0
static void wdc_isa_dma_setup(struct wdc_isa_softc *);

View File

@ -1,4 +1,4 @@
/* $NetBSD: nsphyter.c,v 1.33 2008/11/17 03:04:27 dyoung Exp $ */
/* $NetBSD: nsphyter.c,v 1.34 2009/04/02 00:09:33 dyoung Exp $ */
/*-
* Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc.
@ -68,7 +68,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: nsphyter.c,v 1.33 2008/11/17 03:04:27 dyoung Exp $");
__KERNEL_RCSID(0, "$NetBSD: nsphyter.c,v 1.34 2009/04/02 00:09:33 dyoung Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -89,8 +89,9 @@ __KERNEL_RCSID(0, "$NetBSD: nsphyter.c,v 1.33 2008/11/17 03:04:27 dyoung Exp $")
static int nsphytermatch(device_t, cfdata_t, void *);
static void nsphyterattach(device_t, device_t, void *);
CFATTACH_DECL_NEW(nsphyter, sizeof(struct mii_softc),
nsphytermatch, nsphyterattach, mii_phy_detach, mii_phy_activate);
CFATTACH_DECL3_NEW(nsphyter, sizeof(struct mii_softc),
nsphytermatch, nsphyterattach, mii_phy_detach, mii_phy_activate, NULL,
NULL, DVF_DETACH_SHUTDOWN);
static int nsphyter_service(struct mii_softc *, struct mii_data *, int);
static void nsphyter_status(struct mii_softc *);

View File

@ -1,4 +1,4 @@
/* $NetBSD: if_sip.c,v 1.137 2009/03/27 16:45:53 dyoung Exp $ */
/* $NetBSD: if_sip.c,v 1.138 2009/04/02 00:09:33 dyoung Exp $ */
/*-
* Copyright (c) 2001, 2002 The NetBSD Foundation, Inc.
@ -73,7 +73,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: if_sip.c,v 1.137 2009/03/27 16:45:53 dyoung Exp $");
__KERNEL_RCSID(0, "$NetBSD: if_sip.c,v 1.138 2009/04/02 00:09:33 dyoung Exp $");
#include "bpfilter.h"
#include "rnd.h"
@ -613,10 +613,12 @@ static bool sipcom_suspend(device_t PMF_FN_PROTO);
int gsip_copy_small = 0;
int sip_copy_small = 0;
CFATTACH_DECL(gsip, sizeof(struct sip_softc),
sipcom_match, sipcom_attach, sipcom_detach, NULL);
CFATTACH_DECL(sip, sizeof(struct sip_softc),
sipcom_match, sipcom_attach, sipcom_detach, NULL);
CFATTACH_DECL3(gsip, sizeof(struct sip_softc),
sipcom_match, sipcom_attach, sipcom_detach, NULL, NULL, NULL,
DVF_DETACH_SHUTDOWN);
CFATTACH_DECL3(sip, sizeof(struct sip_softc),
sipcom_match, sipcom_attach, sipcom_detach, NULL, NULL, NULL,
DVF_DETACH_SHUTDOWN);
/*
* Descriptions of the variants of the SiS900.

View File

@ -1,4 +1,4 @@
/* $NetBSD: pccbb.c,v 1.184 2009/03/05 01:38:12 msaitoh Exp $ */
/* $NetBSD: pccbb.c,v 1.185 2009/04/02 00:09:33 dyoung Exp $ */
/*
* Copyright (c) 1998, 1999 and 2000
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: pccbb.c,v 1.184 2009/03/05 01:38:12 msaitoh Exp $");
__KERNEL_RCSID(0, "$NetBSD: pccbb.c,v 1.185 2009/04/02 00:09:33 dyoung Exp $");
/*
#define CBB_DEBUG
@ -211,8 +211,9 @@ static void cb_show_regs(pci_chipset_tag_t pc, pcitag_t tag,
bus_space_tag_t memt, bus_space_handle_t memh);
#endif
CFATTACH_DECL_NEW(cbb_pci, sizeof(struct pccbb_softc),
pcicbbmatch, pccbbattach, pccbbdetach, NULL);
CFATTACH_DECL3_NEW(cbb_pci, sizeof(struct pccbb_softc),
pcicbbmatch, pccbbattach, pccbbdetach, NULL, NULL, NULL,
DVF_DETACH_SHUTDOWN);
static const struct pcmcia_chip_functions pccbb_pcmcia_funcs = {
pccbb_pcmcia_mem_alloc,

View File

@ -1,4 +1,4 @@
/* $NetBSD: pci.c,v 1.121 2008/12/16 22:35:33 christos Exp $ */
/* $NetBSD: pci.c,v 1.122 2009/04/02 00:09:33 dyoung Exp $ */
/*
* Copyright (c) 1995, 1996, 1997, 1998
@ -36,7 +36,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: pci.c,v 1.121 2008/12/16 22:35:33 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: pci.c,v 1.122 2009/04/02 00:09:33 dyoung Exp $");
#include "opt_pci.h"
@ -401,8 +401,9 @@ pcidevdetached(device_t self, device_t child)
c->c_dev = NULL;
}
CFATTACH_DECL2_NEW(pci, sizeof(struct pci_softc),
pcimatch, pciattach, pcidetach, NULL, pcirescan, pcidevdetached);
CFATTACH_DECL3_NEW(pci, sizeof(struct pci_softc),
pcimatch, pciattach, pcidetach, NULL, pcirescan, pcidevdetached,
DVF_DETACH_SHUTDOWN);
int
pci_get_capability(pci_chipset_tag_t pc, pcitag_t tag, int capid,

View File

@ -1,4 +1,4 @@
/* $NetBSD: ppb.c,v 1.39 2008/05/03 05:44:06 cegger Exp $ */
/* $NetBSD: ppb.c,v 1.40 2009/04/02 00:09:33 dyoung Exp $ */
/*
* Copyright (c) 1996, 1998 Christopher G. Demetriou. All rights reserved.
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ppb.c,v 1.39 2008/05/03 05:44:06 cegger Exp $");
__KERNEL_RCSID(0, "$NetBSD: ppb.c,v 1.40 2009/04/02 00:09:33 dyoung Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -206,5 +206,6 @@ ppbchilddet(device_t self, device_t child)
/* we keep no references to child devices, so do nothing */
}
CFATTACH_DECL2_NEW(ppb, sizeof(struct ppb_softc),
ppbmatch, ppbattach, ppbdetach, NULL, NULL, ppbchilddet);
CFATTACH_DECL3_NEW(ppb, sizeof(struct ppb_softc),
ppbmatch, ppbattach, ppbdetach, NULL, NULL, ppbchilddet,
DVF_DETACH_SHUTDOWN);

View File

@ -1,4 +1,4 @@
/* $NetBSD: pcmcia.c,v 1.90 2009/03/15 20:30:57 cegger Exp $ */
/* $NetBSD: pcmcia.c,v 1.91 2009/04/02 00:09:34 dyoung Exp $ */
/*
* Copyright (c) 2004 Charles M. Hannum. All rights reserved.
@ -48,7 +48,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: pcmcia.c,v 1.90 2009/03/15 20:30:57 cegger Exp $");
__KERNEL_RCSID(0, "$NetBSD: pcmcia.c,v 1.91 2009/04/02 00:09:34 dyoung Exp $");
#include "opt_pcmciaverbose.h"
@ -87,9 +87,9 @@ int pcmcia_rescan(struct device *, const char *, const int *);
void pcmcia_childdetached(struct device *, struct device *);
int pcmcia_print(void *, const char *);
CFATTACH_DECL2_NEW(pcmcia, sizeof(struct pcmcia_softc),
CFATTACH_DECL3_NEW(pcmcia, sizeof(struct pcmcia_softc),
pcmcia_match, pcmcia_attach, pcmcia_detach, NULL,
pcmcia_rescan, pcmcia_childdetached);
pcmcia_rescan, pcmcia_childdetached, DVF_DETACH_SHUTDOWN);
int
pcmcia_ccr_read(struct pcmcia_function *pf, int ccr)

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_pmf.c,v 1.21 2009/02/06 01:19:33 dyoung Exp $ */
/* $NetBSD: kern_pmf.c,v 1.22 2009/04/02 00:09:34 dyoung Exp $ */
/*-
* Copyright (c) 2007 Jared D. McNeill <jmcneill@invisible.ca>
@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_pmf.c,v 1.21 2009/02/06 01:19:33 dyoung Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_pmf.c,v 1.22 2009/04/02 00:09:34 dyoung Exp $");
#include <sys/types.h>
#include <sys/param.h>
@ -297,13 +297,19 @@ pmf_system_shutdown(int how)
static struct shutdown_state s;
device_t curdev;
(void)pmf_check_system_drivers();
aprint_debug("Shutting down devices:");
suspendsched();
for (curdev = shutdown_first(&s); curdev != NULL;
curdev = shutdown_next(&s)) {
aprint_debug(" attempting %s shutdown",
device_xname(curdev));
if (!device_pmf_is_registered(curdev))
if ((boothowto & RB_NOSYNC) == 0 &&
config_detach(curdev, DETACH_SHUTDOWN) == 0)
aprint_debug("(detached)");
else if (!device_pmf_is_registered(curdev))
aprint_debug("(skipped)");
#if 0 /* needed? */
else if (!device_pmf_class_shutdown(curdev, how))

View File

@ -1,4 +1,4 @@
/* $NetBSD: subr_autoconf.c,v 1.173 2009/03/28 18:43:20 christos Exp $ */
/* $NetBSD: subr_autoconf.c,v 1.174 2009/04/02 00:09:34 dyoung Exp $ */
/*
* Copyright (c) 1996, 2000 Christopher G. Demetriou
@ -77,7 +77,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: subr_autoconf.c,v 1.173 2009/03/28 18:43:20 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: subr_autoconf.c,v 1.174 2009/04/02 00:09:34 dyoung Exp $");
#include "opt_ddb.h"
#include "drvctl.h"
@ -104,10 +104,9 @@ __KERNEL_RCSID(0, "$NetBSD: subr_autoconf.c,v 1.173 2009/03/28 18:43:20 christos
#include <sys/fcntl.h>
#include <sys/lockf.h>
#include <sys/callout.h>
#include <sys/mutex.h>
#include <sys/condvar.h>
#include <sys/devmon.h>
#include <sys/cpu.h>
#include <sys/sysctl.h>
#include <sys/disk.h>
@ -130,14 +129,6 @@ extern struct splash_progress *splash_progress_state;
* Autoconfiguration subroutines.
*/
typedef struct pmf_private {
int pp_nwait;
int pp_nlock;
lwp_t *pp_holder;
kmutex_t pp_mtx;
kcondvar_t pp_cv;
} pmf_private_t;
/*
* ioconf.c exports exactly two names: cfdata and cfroots. All system
* devices and drivers are found via these tables.
@ -227,6 +218,8 @@ static int config_pending; /* semaphore for mountroot */
static kmutex_t config_misc_lock;
static kcondvar_t config_misc_cv;
static int detachall = 0;
#define STREQ(s1, s2) \
(*(s1) == *(s2) && strcmp((s1), (s2)) == 0)
@ -1185,6 +1178,7 @@ config_devalloc(const device_t parent, const cfdata_t cf, const int *locs)
device_t dev;
void *dev_private;
const struct cfiattrdata *ia;
device_lock_t dvl;
cd = config_cfdriver_lookup(cf->cf_name);
if (cd == NULL)
@ -1242,6 +1236,11 @@ config_devalloc(const device_t parent, const cfdata_t cf, const int *locs)
if (dev == NULL)
panic("config_devalloc: memory allocation for device_t failed");
dvl = device_getlock(dev);
mutex_init(&dvl->dvl_mtx, MUTEX_DEFAULT, IPL_NONE);
cv_init(&dvl->dvl_cv, "pmfsusp");
dev->dv_class = cd->cd_class;
dev->dv_cfdata = cf;
dev->dv_cfdriver = cd;
@ -1282,8 +1281,12 @@ config_devalloc(const device_t parent, const cfdata_t cf, const int *locs)
static void
config_devdealloc(device_t dev)
{
device_lock_t dvl = device_getlock(dev);
int priv = (dev->dv_flags & DVF_PRIV_ALLOC);
cv_destroy(&dvl->dvl_cv);
mutex_destroy(&dvl->dvl_mtx);
KASSERT(dev->dv_properties != NULL);
prop_object_release(dev->dv_properties);
@ -1493,7 +1496,11 @@ config_detach(device_t dev, int flags)
* remain set. Otherwise, if DVF_ACTIVE is still set, the
* device is busy, and the detach fails.
*/
if (ca->ca_activate != NULL)
if (!detachall &&
(flags & (DETACH_SHUTDOWN|DETACH_FORCE)) == DETACH_SHUTDOWN &&
(dev->dv_flags & DVF_DETACH_SHUTDOWN) == 0) {
rv = EBUSY; /* XXX EOPNOTSUPP? */
} else if (ca->ca_activate != NULL)
rv = config_deactivate(dev);
/*
@ -2093,14 +2100,6 @@ device_pmf_driver_register(device_t dev,
bool (*resume)(device_t PMF_FN_PROTO),
bool (*shutdown)(device_t, int))
{
pmf_private_t *pp;
if ((pp = kmem_zalloc(sizeof(*pp), KM_SLEEP)) == NULL)
return false;
mutex_init(&pp->pp_mtx, MUTEX_DEFAULT, IPL_NONE);
cv_init(&pp->pp_cv, "pmfsusp");
dev->dv_pmf_private = pp;
dev->dv_driver_suspend = suspend;
dev->dv_driver_resume = resume;
dev->dv_driver_shutdown = shutdown;
@ -2120,34 +2119,25 @@ curlwp_name(void)
void
device_pmf_driver_deregister(device_t dev)
{
pmf_private_t *pp = dev->dv_pmf_private;
/* XXX avoid crash in case we are not initialized */
if (!pp)
return;
device_lock_t dvl = device_getlock(dev);
dev->dv_driver_suspend = NULL;
dev->dv_driver_resume = NULL;
mutex_enter(&pp->pp_mtx);
mutex_enter(&dvl->dvl_mtx);
dev->dv_flags &= ~DVF_POWER_HANDLERS;
while (pp->pp_nlock > 0 || pp->pp_nwait > 0) {
while (dvl->dvl_nlock > 0 || dvl->dvl_nwait > 0) {
/* Wake a thread that waits for the lock. That
* thread will fail to acquire the lock, and then
* it will wake the next thread that waits for the
* lock, or else it will wake us.
*/
cv_signal(&pp->pp_cv);
cv_signal(&dvl->dvl_cv);
pmflock_debug(dev, __func__, __LINE__);
cv_wait(&pp->pp_cv, &pp->pp_mtx);
cv_wait(&dvl->dvl_cv, &dvl->dvl_mtx);
pmflock_debug(dev, __func__, __LINE__);
}
dev->dv_pmf_private = NULL;
mutex_exit(&pp->pp_mtx);
cv_destroy(&pp->pp_cv);
mutex_destroy(&pp->pp_mtx);
kmem_free(pp, sizeof(*pp));
mutex_exit(&dvl->dvl_mtx);
}
bool
@ -2200,46 +2190,46 @@ device_pmf_self_suspend(device_t dev PMF_FN_ARGS)
static void
pmflock_debug(device_t dev, const char *func, int line)
{
pmf_private_t *pp = device_pmf_private(dev);
device_lock_t dvl = device_getlock(dev);
aprint_debug_dev(dev, "%s.%d, %s pp_nlock %d pp_nwait %d dv_flags %x\n",
func, line, curlwp_name(), pp->pp_nlock, pp->pp_nwait,
aprint_debug_dev(dev, "%s.%d, %s dvl_nlock %d dvl_nwait %d dv_flags %x\n",
func, line, curlwp_name(), dvl->dvl_nlock, dvl->dvl_nwait,
dev->dv_flags);
}
static void
pmflock_debug_with_flags(device_t dev, const char *func, int line PMF_FN_ARGS)
{
pmf_private_t *pp = device_pmf_private(dev);
device_lock_t dvl = device_getlock(dev);
aprint_debug_dev(dev, "%s.%d, %s pp_nlock %d pp_nwait %d dv_flags %x "
aprint_debug_dev(dev, "%s.%d, %s dvl_nlock %d dvl_nwait %d dv_flags %x "
"flags " PMF_FLAGS_FMT "\n", func, line, curlwp_name(),
pp->pp_nlock, pp->pp_nwait, dev->dv_flags PMF_FN_CALL);
dvl->dvl_nlock, dvl->dvl_nwait, dev->dv_flags PMF_FN_CALL);
}
static bool
device_pmf_lock1(device_t dev PMF_FN_ARGS)
{
pmf_private_t *pp = device_pmf_private(dev);
device_lock_t dvl = device_getlock(dev);
while (device_pmf_is_registered(dev) &&
pp->pp_nlock > 0 && pp->pp_holder != curlwp) {
pp->pp_nwait++;
dvl->dvl_nlock > 0 && dvl->dvl_holder != curlwp) {
dvl->dvl_nwait++;
pmflock_debug_with_flags(dev, __func__, __LINE__ PMF_FN_CALL);
cv_wait(&pp->pp_cv, &pp->pp_mtx);
cv_wait(&dvl->dvl_cv, &dvl->dvl_mtx);
pmflock_debug_with_flags(dev, __func__, __LINE__ PMF_FN_CALL);
pp->pp_nwait--;
dvl->dvl_nwait--;
}
if (!device_pmf_is_registered(dev)) {
pmflock_debug_with_flags(dev, __func__, __LINE__ PMF_FN_CALL);
/* We could not acquire the lock, but some other thread may
* wait for it, also. Wake that thread.
*/
cv_signal(&pp->pp_cv);
cv_signal(&dvl->dvl_cv);
return false;
}
pp->pp_nlock++;
pp->pp_holder = curlwp;
dvl->dvl_nlock++;
dvl->dvl_holder = curlwp;
pmflock_debug_with_flags(dev, __func__, __LINE__ PMF_FN_CALL);
return true;
}
@ -2248,11 +2238,11 @@ bool
device_pmf_lock(device_t dev PMF_FN_ARGS)
{
bool rc;
pmf_private_t *pp = device_pmf_private(dev);
device_lock_t dvl = device_getlock(dev);
mutex_enter(&pp->pp_mtx);
mutex_enter(&dvl->dvl_mtx);
rc = device_pmf_lock1(dev PMF_FN_CALL);
mutex_exit(&pp->pp_mtx);
mutex_exit(&dvl->dvl_mtx);
return rc;
}
@ -2260,21 +2250,21 @@ device_pmf_lock(device_t dev PMF_FN_ARGS)
void
device_pmf_unlock(device_t dev PMF_FN_ARGS)
{
pmf_private_t *pp = device_pmf_private(dev);
device_lock_t dvl = device_getlock(dev);
KASSERT(pp->pp_nlock > 0);
mutex_enter(&pp->pp_mtx);
if (--pp->pp_nlock == 0)
pp->pp_holder = NULL;
cv_signal(&pp->pp_cv);
KASSERT(dvl->dvl_nlock > 0);
mutex_enter(&dvl->dvl_mtx);
if (--dvl->dvl_nlock == 0)
dvl->dvl_holder = NULL;
cv_signal(&dvl->dvl_cv);
pmflock_debug_with_flags(dev, __func__, __LINE__ PMF_FN_CALL);
mutex_exit(&pp->pp_mtx);
mutex_exit(&dvl->dvl_mtx);
}
void *
device_pmf_private(device_t dev)
device_lock_t
device_getlock(device_t dev)
{
return dev->dv_pmf_private;
return &dev->dv_lock;
}
void *
@ -2688,3 +2678,24 @@ deviter_release(deviter_t *di)
}
mutex_exit(&alldevs_mtx);
}
SYSCTL_SETUP(sysctl_detach_setup, "sysctl detach setup")
{
const struct sysctlnode *node = NULL;
sysctl_createv(clog, 0, NULL, &node,
CTLFLAG_PERMANENT,
CTLTYPE_NODE, "kern", NULL,
NULL, 0, NULL, 0,
CTL_KERN, CTL_EOL);
if (node == NULL)
return;
sysctl_createv(clog, 0, &node, NULL,
CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
CTLTYPE_INT, "detachall",
SYSCTL_DESCR("Detach all devices at shutdown"),
NULL, 0, &detachall, 0,
CTL_CREATE, CTL_EOL);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: device.h,v 1.116 2009/02/12 18:24:18 christos Exp $ */
/* $NetBSD: device.h,v 1.117 2009/04/02 00:09:34 dyoung Exp $ */
/*
* Copyright (c) 1996, 2000 Christopher G. Demetriou
@ -82,6 +82,8 @@
typedef struct device *device_t;
#ifdef _KERNEL
#include <sys/mutex.h>
#include <sys/condvar.h>
#include <sys/pmf.h>
#endif
@ -121,6 +123,16 @@ typedef struct cfdriver *cfdriver_t;
typedef struct cfattach *cfattach_t;
#ifdef _KERNEL
struct device_lock {
int dvl_nwait;
int dvl_nlock;
lwp_t *dvl_holder;
kmutex_t dvl_mtx;
kcondvar_t dvl_cv;
};
typedef struct device_lock *device_lock_t;
struct device {
devclass_t dv_class; /* this device's classification */
TAILQ_ENTRY(device) dv_list; /* entry on list of all devices */
@ -157,7 +169,7 @@ struct device {
bool (*dv_class_resume)(device_t PMF_FN_PROTO);
void (*dv_class_deregister)(device_t);
void *dv_pmf_private;
struct device_lock dv_lock;
};
/* dv_flags */
@ -168,6 +180,7 @@ struct device {
#define DVF_DRIVER_SUSPENDED 0x0010 /* device driver suspend was called */
#define DVF_BUS_SUSPENDED 0x0020 /* device bus suspend was called */
#define DVF_SELF_SUSPENDED 0x0040 /* device suspended itself */
#define DVF_DETACH_SHUTDOWN 0x0080 /* device detaches safely at shutdown */
TAILQ_HEAD(devicelist, device);
@ -287,11 +300,12 @@ struct cfattach {
};
LIST_HEAD(cfattachlist, cfattach);
#define CFATTACH_DECL2(name, ddsize, matfn, attfn, detfn, actfn, \
rescanfn, chdetfn) \
#define CFATTACH_DECL3(name, ddsize, matfn, attfn, detfn, actfn, \
rescanfn, chdetfn, __flags) \
struct cfattach __CONCAT(name,_ca) = { \
.ca_name = ___STRING(name), \
.ca_devsize = ddsize, \
.ca_flags = (__flags), \
.ca_match = matfn, \
.ca_attach = attfn, \
.ca_detach = detfn, \
@ -300,15 +314,20 @@ struct cfattach __CONCAT(name,_ca) = { \
.ca_childdetached = chdetfn, \
}
#define CFATTACH_DECL2(name, ddsize, matfn, attfn, detfn, actfn, \
rescanfn, chdetfn) \
CFATTACH_DECL3(name, ddsize, matfn, attfn, detfn, actfn, \
rescanfn, chdetfn, 0)
#define CFATTACH_DECL(name, ddsize, matfn, attfn, detfn, actfn) \
CFATTACH_DECL2(name, ddsize, matfn, attfn, detfn, actfn, NULL, NULL)
#define CFATTACH_DECL2_NEW(name, ddsize, matfn, attfn, detfn, actfn, \
rescanfn, chdetfn) \
#define CFATTACH_DECL3_NEW(name, ddsize, matfn, attfn, detfn, actfn, \
rescanfn, chdetfn, __flags) \
struct cfattach __CONCAT(name,_ca) = { \
.ca_name = ___STRING(name), \
.ca_devsize = ddsize, \
.ca_flags = DVF_PRIV_ALLOC, \
.ca_flags = (__flags) | DVF_PRIV_ALLOC, \
.ca_match = matfn, \
.ca_attach = attfn, \
.ca_detach = detfn, \
@ -317,12 +336,18 @@ struct cfattach __CONCAT(name,_ca) = { \
.ca_childdetached = chdetfn, \
}
#define CFATTACH_DECL_NEW(name, ddsize, matfn, attfn, detfn, actfn) \
#define CFATTACH_DECL2_NEW(name, ddsize, matfn, attfn, detfn, actfn, \
rescanfn, chdetfn) \
CFATTACH_DECL3_NEW(name, ddsize, matfn, attfn, detfn, actfn, \
rescanfn, chdetfn, 0)
#define CFATTACH_DECL_NEW(name, ddsize, matfn, attfn, detfn, actfn) \
CFATTACH_DECL2_NEW(name, ddsize, matfn, attfn, detfn, actfn, NULL, NULL)
/* Flags given to config_detach(), and the ca_detach function. */
#define DETACH_FORCE 0x01 /* force detachment; hardware gone */
#define DETACH_QUIET 0x02 /* don't print a notice */
#define DETACH_SHUTDOWN 0x04 /* detach because of system shutdown */
struct cfdriver {
LIST_ENTRY(cfdriver) cd_list; /* link on allcfdrivers */
@ -498,7 +523,7 @@ bool device_pmf_bus_suspend(device_t PMF_FN_PROTO);
bool device_pmf_bus_resume(device_t PMF_FN_PROTO);
bool device_pmf_bus_shutdown(device_t, int);
void *device_pmf_private(device_t);
device_lock_t device_getlock(device_t);
void device_pmf_unlock(device_t PMF_FN_PROTO);
bool device_pmf_lock(device_t PMF_FN_PROTO);

View File

@ -1,4 +1,4 @@
/* $NetBSD: pmf.h,v 1.14 2009/02/06 01:19:33 dyoung Exp $ */
/* $NetBSD: pmf.h,v 1.15 2009/04/02 00:09:34 dyoung Exp $ */
/*-
* Copyright (c) 2007 Jared D. McNeill <jmcneill@invisible.ca>
@ -32,6 +32,7 @@
#ifdef _KERNEL
#include <sys/types.h>
#include <sys/device.h>
typedef enum {
PMFE_DISPLAY_ON,