From owner-freebsd-arch@FreeBSD.ORG Sat Apr 28 17:16:03 2007 Return-Path: X-Original-To: freebsd-arch@freebsd.org Delivered-To: freebsd-arch@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 836C616A400 for ; Sat, 28 Apr 2007 17:16:03 +0000 (UTC) (envelope-from takeharu1219@ybb.ne.jp) Received: from ybbsmtp12.mail.ogk.yahoo.co.jp (ybbsmtp12.mail.ogk.yahoo.co.jp [124.83.153.132]) by mx1.freebsd.org (Postfix) with SMTP id 17D9413C458 for ; Sat, 28 Apr 2007 17:16:02 +0000 (UTC) (envelope-from takeharu1219@ybb.ne.jp) Received: (qmail 825 invoked by alias); 28 Apr 2007 16:49:21 -0000 DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=ybb20050223; d=ybb.ne.jp; b=P4OdQ8zH1aKPb5xQRd3+EXd5dThHC1egiTbvHyk8zU29L0V2m9+kihTtUilB1AnUHEyCduR0LlIe5WYTuG+2HX8qA0z1WmtEc0kPoX7qcql+LHPdt6LJMqAhkoRmTW+J ; Received: from unknown (HELO ?127.0.0.1?) (takeharu1219@219.35.170.86 with plain) by ybbsmtp12.mail.ogk.yahoo.co.jp with SMTP; 28 Apr 2007 16:49:21 -0000 X-Apparently-From: Message-ID: <46337B06.9080102@ybb.ne.jp> Date: Sun, 29 Apr 2007 01:49:10 +0900 From: Takeharu KATO User-Agent: Thunderbird 1.5.0.9 (Windows/20061207) MIME-Version: 1.0 To: freebsd-arch@freebsd.org Content-Type: text/plain; charset=ISO-2022-JP Content-Transfer-Encoding: 7bit Subject: ichwd for ICH8 X-BeenThere: freebsd-arch@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Discussion related to FreeBSD architecture List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 28 Apr 2007 17:16:03 -0000 Hi, I am trying to port ichwd to ICH6 and later. I have a box which has ICH8 compliant mother board(GIGA BYTE GA-965P-DS3). As far as I refer the manual(Intel I/O Controller Hub 8 (ICH8) Family) , this driver can setup counter properly and then enable watchdog facility. But the driver can not make the system reboot when watchdog fire the interrupt. I can not figure out the reason of this problem is caused by my patch or current ichwd part. Because I do not have the box which have ICH5 or before. Does anyone use ichwd? diff -Nupr ichwd.orig/ichwd.c ichwd/ichwd.c --- ichwd.orig/ichwd.c Wed Apr 25 22:03:16 2007 +++ ichwd/ichwd.c Fri Apr 27 00:59:16 2007 @@ -71,20 +71,27 @@ __FBSDID("$FreeBSD: src/sys/dev/ichwd/ic #include static struct ichwd_device ichwd_devices[] = { - { VENDORID_INTEL, DEVICEID_82801AA, "Intel 82801AA watchdog timer" }, - { VENDORID_INTEL, DEVICEID_82801AB, "Intel 82801AB watchdog timer" }, - { VENDORID_INTEL, DEVICEID_82801BA, "Intel 82801BA watchdog timer" }, - { VENDORID_INTEL, DEVICEID_82801BAM, "Intel 82801BAM watchdog timer" }, - { VENDORID_INTEL, DEVICEID_82801CA, "Intel 82801CA watchdog timer" }, - { VENDORID_INTEL, DEVICEID_82801CAM, "Intel 82801CAM watchdog timer" }, - { VENDORID_INTEL, DEVICEID_82801DB, "Intel 82801DB watchdog timer" }, - { VENDORID_INTEL, DEVICEID_82801DBM, "Intel 82801DBM watchdog timer" }, - { VENDORID_INTEL, DEVICEID_82801E, "Intel 82801E watchdog timer" }, - { VENDORID_INTEL, DEVICEID_82801EBR, "Intel 82801EB/ER watchdog timer" }, - { VENDORID_INTEL, DEVICEID_82801FBR, "Intel 82801FB/FR watchdog timer" }, - { VENDORID_INTEL, DEVICEID_ICH5, "Intel ICH5 watchdog timer"}, - { VENDORID_INTEL, DEVICEID_6300ESB, "Intel 6300ESB watchdog timer"}, - { 0, 0, NULL }, + { VENDORID_INTEL, DEVICEID_82801AA, "Intel 82801AA watchdog timer", 1} , + { VENDORID_INTEL, DEVICEID_82801AB, "Intel 82801AB watchdog timer", 1} , + { VENDORID_INTEL, DEVICEID_82801BA, "Intel 82801BA watchdog timer", 1} , + { VENDORID_INTEL, DEVICEID_82801BAM, "Intel 82801BAM watchdog timer", 1} , + { VENDORID_INTEL, DEVICEID_82801CA, "Intel 82801CA watchdog timer", 1} , + { VENDORID_INTEL, DEVICEID_82801CAM, "Intel 82801CAM watchdog timer", 1} , + { VENDORID_INTEL, DEVICEID_82801DB, "Intel 82801DB watchdog timer", 1} , + { VENDORID_INTEL, DEVICEID_82801DBM, "Intel 82801DBM watchdog timer", 1} , + { VENDORID_INTEL, DEVICEID_82801E, "Intel 82801E watchdog timer", 1} , + { VENDORID_INTEL, DEVICEID_82801EBR, "Intel 82801EB/ER watchdog timer", 1} , + { VENDORID_INTEL, DEVICEID_82801FBR, "Intel 82801FB/FR watchdog timer", 2} , + { VENDORID_INTEL, DEVICEID_ICH5, "Intel ICH5 watchdog timer", 2} , + { VENDORID_INTEL, DEVICEID_6300ESB, "Intel 6300ESB watchdog timer", 2} , + { VENDORID_INTEL, DEVICEID_ICH6M, "Intel ICH6M watchdog timer", 2} , + { VENDORID_INTEL, DEVICEID_ICH6W, "Intel ICH6W watchdog timer", 2} , + { VENDORID_INTEL, DEVICEID_ICH7M, "Intel ICH7M watchdog timer", 2} , + { VENDORID_INTEL, DEVICEID_ICH7MDH, "Intel ICH7MDH watchdog timer", 2} , + { VENDORID_INTEL, DEVICEID_ICH8, "Intel ICH8 watchdog timer", 2} , + { VENDORID_INTEL, DEVICEID_ICH8DH, "Intel ICH8DH watchdog timer", 2} , + { VENDORID_INTEL, DEVICEID_ICH8DO, "Intel ICH8DO watchdog timer", 2} , + { 0, 0, NULL, 0 } , }; static devclass_t ichwd_devclass; @@ -103,11 +110,21 @@ static devclass_t ichwd_devclass; #define ichwd_write_tco_4(sc, off, val) \ bus_space_write_4((sc)->tco_bst, (sc)->tco_bsh, (off), (val)) -#define ichwd_read_smi_4(sc, off) \ +#define ichwd_read_smi_4(sc, off) \ bus_space_read_4((sc)->smi_bst, (sc)->smi_bsh, (off)) #define ichwd_write_smi_4(sc, off, val) \ bus_space_write_4((sc)->smi_bst, (sc)->smi_bsh, (off), (val)) +#define ichwd_read_gcs_4(sc, off) \ + bus_read_4((sc)->gcs_res, (off)) +#define ichwd_write_gcs_4(sc, off, val) \ + bus_write_4((sc)->gcs_res, (off), (val)) + +#define ichwd_verbose_printf(dev,fmt,arg...) do { \ + if (bootverbose) \ + device_printf(dev, fmt, ##arg); \ + } while (0) + static __inline void ichwd_intr_enable(struct ichwd_softc *sc) { @@ -136,8 +153,7 @@ ichwd_tmr_enable(struct ichwd_softc *sc) cnt = ichwd_read_tco_2(sc, TCO1_CNT) & TCO_CNT_PRESERVE; ichwd_write_tco_2(sc, TCO1_CNT, cnt & ~TCO_TMR_HALT); sc->active = 1; - if (bootverbose) - device_printf(sc->device, "timer enabled\n"); + ichwd_verbose_printf(sc->device, "timer enabled\n"); } static __inline void @@ -148,25 +164,67 @@ ichwd_tmr_disable(struct ichwd_softc *sc cnt = ichwd_read_tco_2(sc, TCO1_CNT) & TCO_CNT_PRESERVE; ichwd_write_tco_2(sc, TCO1_CNT, cnt | TCO_TMR_HALT); sc->active = 0; - if (bootverbose) - device_printf(sc->device, "timer disabled\n"); + ichwd_verbose_printf(sc->device, "timer disabled\n"); } static __inline void ichwd_tmr_reload(struct ichwd_softc *sc) { - ichwd_write_tco_1(sc, TCO_RLD, 1); - if (bootverbose) - device_printf(sc->device, "timer reloaded\n"); + if (sc->tco_version == 1) + ichwd_write_tco_1(sc, TCO_RLD, 1); + else + ichwd_write_tco_2(sc, TCO_RLD, 1); + + ichwd_verbose_printf(sc->device, "timer reloaded\n"); } static __inline void ichwd_tmr_set(struct ichwd_softc *sc, uint8_t timeout) { - ichwd_write_tco_1(sc, TCO_TMR, timeout); + + if (sc->tco_version == 1) { + ichwd_write_tco_1(sc, TCO_TMR, timeout); + } else { + uint16_t tmr_val = ichwd_read_tco_2(sc, TCO_V2_TMR); + + tmr_val &= 0xfc00; + tmr_val |= timeout; + ichwd_write_tco_2(sc, TCO_V2_TMR, tmr_val); + } + sc->timeout = timeout; - if (bootverbose) - device_printf(sc->device, "timeout set to %u ticks\n", timeout); + + ichwd_verbose_printf(sc->device, "timeout set to %u ticks\n", timeout); +} + +static __inline int +ichwd_clear_noreboot(struct ichwd_softc *sc) +{ + uint32_t status; + int rc = 0; + + /* try to clear the NO_REBOOT bit */ + if (sc->tco_version == 1) { + pci_write_config(sc->ich, ICH_GEN_STA, 0x00, 1); + status = pci_read_config(sc->ich, ICH_GEN_STA, 1); + if (status & ICH_GEN_STA_NO_REBOOT) + rc = EIO; + } else { + status = ichwd_read_gcs_4(sc, 0); + status &= ~(GCS_NOREBOOT); + ichwd_write_gcs_4(sc, 0, status); + + status = ichwd_read_gcs_4(sc, 0); + if (status & GCS_NOREBOOT) + rc = EIO; + } + + if (rc) + ichwd_verbose_printf(sc->device, + "%s(): ICH WDT present but disabled\n", + __func__); + + return rc; } /* @@ -197,7 +255,24 @@ ichwd_event(void *arg, unsigned int cmd, } } -static unsigned int pmbase = 0; +static device_t +ichwd_find_ich_lpc_bridge(struct ichwd_device **id_p) { + struct ichwd_device *id; + device_t ich = NULL; + + /* look for an ICH LPC interface bridge */ + for (id = ichwd_devices; id->desc != NULL; ++id) + if ((ich = pci_find_device(id->vendor, id->device)) != NULL) + break; + + if ( (bootverbose) && (ich) ) + printf("%s(): found ICH chipset: %s TCO version:%d\n", __func__, id->desc, id->version); + + if (id_p) + *id_p = id; + + return ich; +} /* * Look for an ICH LPC interface bridge. If one is found, register an @@ -206,44 +281,33 @@ static unsigned int pmbase = 0; static void ichwd_identify(driver_t *driver, device_t parent) { - struct ichwd_device *id; + struct ichwd_device *id_p; device_t ich = NULL; device_t dev; + uint32_t rcba; + int rc; - /* look for an ICH LPC interface bridge */ - for (id = ichwd_devices; id->desc != NULL; ++id) - if ((ich = pci_find_device(id->vendor, id->device)) != NULL) - break; + ich = ichwd_find_ich_lpc_bridge(&id_p); if (ich == NULL) return; - if (bootverbose) - printf("%s(): found ICH chipset: %s\n", __func__, id->desc); - - /* get for ACPI base address */ - pmbase = pci_read_config(ich, ICH_PMBASE, 2) & ICH_PMBASE_MASK; - if (pmbase == 0) { - if (bootverbose) - printf("%s(): ICH PMBASE register is empty\n", - __func__); - return; - } - - /* try to clear the NO_REBOOT bit */ - pci_write_config(ich, ICH_GEN_STA, 0x00, 1); - if (pci_read_config(ich, ICH_GEN_STA, 1) & ICH_GEN_STA_NO_REBOOT) { - if (bootverbose) - printf("%s(): ICH WDT present but disabled\n", - __func__); - return; - } - /* good, add child to bus */ if ((dev = device_find_child(parent, driver->name, 0)) == NULL) dev = BUS_ADD_CHILD(parent, 0, driver->name, 0); - if (dev != NULL) - device_set_desc_copy(dev, id->desc); + if (dev != NULL) { + device_set_desc_copy(dev, id_p->desc); + + if (id_p->version == 2) { + /* set rcba */ + rcba = (pci_read_config(ich, ICH_RCBA, 4) & (0xffffc000)); + rc = bus_set_resource(ich, SYS_RES_MEMORY, 0, rcba, ICH_GCS_SIZE); + if (rc) + ichwd_verbose_printf(dev, "%s(): Can not set memory resource:0x%x\n", __func__, rcba); + else + ichwd_verbose_printf(dev, "%s(): This machine has TCO Version 2 wdt.\n", __func__); + } + } } static int @@ -257,12 +321,27 @@ static int ichwd_attach(device_t dev) { struct ichwd_softc *sc; + struct ichwd_device *id_p; + device_t ich; + unsigned int pmbase = 0; sc = device_get_softc(dev); sc->device = dev; + ich = ichwd_find_ich_lpc_bridge(&id_p); + if (ich == NULL) { + device_printf(sc->device, "Can not find ICH device.\n"); + goto fail; + } + sc->ich = ich; + sc->tco_version = id_p->version; + + /* get for ACPI base address */ + pmbase = pci_read_config(ich, ICH_PMBASE, 2) & ICH_PMBASE_MASK; if (pmbase == 0) { - printf("Not found\n"); + ichwd_verbose_printf(sc->device, "%s(): ICH PMBASE register is empty\n", + __func__); + goto fail; } /* allocate I/O register space */ @@ -287,6 +366,21 @@ ichwd_attach(device_t dev) } sc->tco_bst = rman_get_bustag(sc->tco_res); sc->tco_bsh = rman_get_bushandle(sc->tco_res); + + sc->gcs_rid = 0; + sc->gcs_res = bus_alloc_resource_any(ich, SYS_RES_MEMORY, &sc->gcs_rid, + RF_ACTIVE|RF_SHAREABLE); + if ( (sc->gcs_res == NULL) && (sc->tco_version != 1) ) { + device_printf(dev, "unable to reserve GCS registers\n"); + goto fail; + } + + if (ichwd_clear_noreboot(sc)) + goto fail; + + device_printf(dev, "%s (TCO version %d)\n", + device_get_desc(dev), sc->tco_version); + /* reset the watchdog status registers */ ichwd_sts_reset(sc); @@ -309,6 +403,10 @@ ichwd_attach(device_t dev) if (sc->smi_res != NULL) bus_release_resource(dev, SYS_RES_IOPORT, sc->smi_rid, sc->smi_res); + if (sc->gcs_res != NULL) + bus_release_resource(ich, SYS_RES_MEMORY, + sc->gcs_rid, sc->gcs_res); + return (ENXIO); } @@ -316,6 +414,7 @@ static int ichwd_detach(device_t dev) { struct ichwd_softc *sc; + device_t ich = NULL; sc = device_get_softc(dev); @@ -338,6 +437,10 @@ ichwd_detach(device_t dev) bus_release_resource(dev, SYS_RES_IOPORT, sc->tco_rid, sc->tco_res); bus_release_resource(dev, SYS_RES_IOPORT, sc->smi_rid, sc->smi_res); + /* deallocate memory resource */ + ich = ichwd_find_ich_lpc_bridge(NULL); + if ( (sc->gcs_res) && (ich) ) + bus_release_resource(ich, SYS_RES_MEMORY, sc->gcs_rid, sc->gcs_res); return (0); } diff -Nupr ichwd.orig/ichwd.h ichwd/ichwd.h --- ichwd.orig/ichwd.h Wed Apr 25 22:03:16 2007 +++ ichwd/ichwd.h Fri Apr 27 01:03:54 2007 @@ -35,11 +35,12 @@ struct ichwd_device { uint16_t vendor; uint16_t device; char *desc; + unsigned int version; }; struct ichwd_softc { device_t device; - + device_t ich; int active; unsigned int timeout; @@ -53,6 +54,11 @@ struct ichwd_softc { bus_space_tag_t tco_bst; bus_space_handle_t tco_bsh; + int gcs_rid; + struct resource *gcs_res; + + int tco_version; + eventhandler_tag ev_tag; }; @@ -70,6 +76,13 @@ struct ichwd_softc { #define DEVICEID_6300ESB 0x25a1 #define DEVICEID_82801FBR 0x2640 #define DEVICEID_ICH5 0x27b8 +#define DEVICEID_ICH6M 0x2641 +#define DEVICEID_ICH6W 0x2642 +#define DEVICEID_ICH7M 0x27b9 +#define DEVICEID_ICH7MDH 0x27bd +#define DEVICEID_ICH8 0x2810 +#define DEVICEID_ICH8DH 0x2812 +#define DEVICEID_ICH8DO 0x2814 /* ICH LPC Interface Bridge Registers */ #define ICH_GEN_STA 0xd4 @@ -111,6 +124,12 @@ struct ichwd_softc { /* control bits for TCO1_CNT */ #define TCO_TMR_HALT 0x0800 /* clear to enable WDT */ #define TCO_CNT_PRESERVE 0x0200 /* preserve these bits */ + +#define ICH_RCBA 0xf0 +#define ICH_GCS_OFFSET 0x3410 +#define ICH_GCS_SIZE 0x4 +#define GCS_NOREBOOT 0x00000020 +#define TCO_V2_TMR 0x12 /* TCO Timer Initial Value for V2 */ /* approximate length in nanoseconds of one WDT tick */ #define ICHWD_TICK 1800000000