Do not explicitly set PCIM_CMD_SERRESPEN or PCIM_CMD_PERRESPEN. This was
[dragonfly.git] / sys / bus / firewire / fwohci_pci.c
index a7a16c1..61ee30c 100644 (file)
@@ -31,7 +31,8 @@
  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  * 
- * $FreeBSD: src/sys/dev/firewire/fwohci_pci.c,v 1.3.2.11 2003/04/28 03:29:18 simokawa Exp $
+ * $FreeBSD: src/sys/dev/firewire/fwohci_pci.c,v 1.38 2004/01/23 17:37:09 simokawa Exp $
+ * $DragonFly: src/sys/bus/firewire/fwohci_pci.c,v 1.16 2004/11/08 16:50:33 dillon Exp $
  */
 
 #define BOUNCE_BUFFER_TEST     0
 #include <sys/systm.h>
 #include <sys/kernel.h>
 #include <sys/module.h>
+#include <sys/conf.h>
 #include <sys/bus.h>
 #include <sys/queue.h>
 #include <machine/bus.h>
 #include <sys/rman.h>
 #include <sys/malloc.h>
+#if defined(__FreeBSD__) && __FreeBSD_version >= 501102
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#endif
 #include <machine/resource.h>
 
+#if defined(__DragonFly__) || __FreeBSD_version < 500000
+#include <machine/clock.h>             /* for DELAY() */
+#endif
+
+#ifdef __DragonFly__
+#include <bus/pci/pcivar.h>
+#include <bus/pci/pcireg.h>
+
+#include "firewire.h"
+#include "firewirereg.h"
+
+#include "fwdma.h"
+#include "fwohcireg.h"
+#include "fwohcivar.h"
+#else
+#if __FreeBSD_version < 500000
 #include <pci/pcivar.h>
 #include <pci/pcireg.h>
+#else
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#endif
 
 #include <dev/firewire/firewire.h>
 #include <dev/firewire/firewirereg.h>
@@ -56,6 +82,7 @@
 #include <dev/firewire/fwdma.h>
 #include <dev/firewire/fwohcireg.h>
 #include <dev/firewire/fwohcivar.h>
+#endif
 
 static int fwohci_pci_attach(device_t self);
 static int fwohci_pci_detach(device_t self);
@@ -70,6 +97,10 @@ fwohci_pci_probe( device_t dev )
        u_int32_t id;
 
        id = pci_get_devid(dev);
+       if (id == (FW_VENDORID_NATSEMI | FW_DEVICE_CS4210)) {
+               device_set_desc(dev, "National Semiconductor CS4210");
+               return 0;
+       }
        if (id == (FW_VENDORID_NEC | FW_DEVICE_UPD861)) {
                device_set_desc(dev, "NEC uPD72861");
                return 0;
@@ -86,6 +117,11 @@ fwohci_pci_probe( device_t dev )
                device_set_desc(dev, "NEC uPD72874");
                return 0;
        }
+       if (id == (FW_VENDORID_SIS | FW_DEVICE_7007)) {
+               /* It has no real identifier, using device id. */
+               device_set_desc(dev, "SiS 7007");
+               return 0;
+       }
        if (id == (FW_VENDORID_TI | FW_DEVICE_TITSB22)) {
                device_set_desc(dev, "Texas Instruments TSB12LV22");
                return 0;
@@ -106,10 +142,18 @@ fwohci_pci_probe( device_t dev )
                device_set_desc(dev, "Texas Instruments TSB43AB22/A");
                return 0;
        }
+       if (id == (FW_VENDORID_TI | FW_DEVICE_TITSB43AB21)) {
+               device_set_desc(dev, "Texas Instruments TSB43AB21/A/AI/A-EP");
+               return 0;
+       }
        if (id == (FW_VENDORID_TI | FW_DEVICE_TITSB43AB23)) {
                device_set_desc(dev, "Texas Instruments TSB43AB23");
                return 0;
        }
+       if (id == (FW_VENDORID_TI | FW_DEVICE_TITSB82AA2)) {
+               device_set_desc(dev, "Texas Instruments TSB82AA2");
+               return 0;
+       }
        if (id == (FW_VENDORID_TI | FW_DEVICE_TIPCI4450)) {
                device_set_desc(dev, "Texas Instruments PCI4450");
                return 0;
@@ -122,12 +166,16 @@ fwohci_pci_probe( device_t dev )
                device_set_desc(dev, "Texas Instruments PCI4451");
                return 0;
        }
-       if (id == (FW_VENDORID_SONY | FW_DEVICE_CX3022)) {
-               device_set_desc(dev, "Sony CX3022");
+       if (id == (FW_VENDORID_SONY | FW_DEVICE_CXD1947)) {
+               device_set_desc(dev, "Sony i.LINK (CXD1947)");
+               return 0;
+       }
+       if (id == (FW_VENDORID_SONY | FW_DEVICE_CXD3222)) {
+               device_set_desc(dev, "Sony i.LINK (CXD3222)");
                return 0;
        }
        if (id == (FW_VENDORID_VIA | FW_DEVICE_VT6306)) {
-               device_set_desc(dev, "VIA VT6306");
+               device_set_desc(dev, "VIA Fire II (VT6306)");
                return 0;
        }
        if (id == (FW_VENDORID_RICOH | FW_DEVICE_R5C551)) {
@@ -150,6 +198,14 @@ fwohci_pci_probe( device_t dev )
                device_set_desc(dev, "Lucent FW322/323");
                return 0;
        }
+       if (id == (FW_VENDORID_INTEL | FW_DEVICE_82372FB)) {
+               device_set_desc(dev, "Intel 82372FB");
+               return 0;
+       }
+       if (id == (FW_VENDORID_ADAPTEC | FW_DEVICE_AIC5800)) {
+               device_set_desc(dev, "Adaptec AHA-894x/AIC-5800");
+               return 0;
+       }
 #endif
        if (pci_get_class(dev) == PCIC_SERIALBUS
                        && pci_get_subclass(dev) == PCIS_SERIALBUS_FW
@@ -163,7 +219,7 @@ fwohci_pci_probe( device_t dev )
        return ENXIO;
 }
 
-#if __FreeBSD_version < 500000
+#if defined(__DragonFly__) || __FreeBSD_version < 500000
 static void
 fwohci_dummy_intr(void *arg)
 {
@@ -177,12 +233,23 @@ fwohci_pci_init(device_t self)
        int olatency, latency, ocache_line, cache_line;
        u_int16_t cmd;
 
+       /*
+        * Clear PCIM_CMD_MWRICEN as per FreeBSD/1.20, but note that the
+        * problem may have been related to SERR and PERR being
+        * unconditionally enabled in that rev.
+        *
+        * Do not change the SERRESPEN or PERRESPEN bits.  Use the BIOS
+        * values (probably off).  This crashes some machines in fwohci_init().
+        *
+        * The theory here is that the device may not be properly initializing
+        * its on-chip memory, leaving some of it in a parity errored state,
+        * and enabling parity check may result in the device blowing up.
+        * It's also possible that some hardware is just plain broken.  OpenBSD
+        * does not turn on SERRESPEN or PERRESPEN so we won't either.
+        */
        cmd = pci_read_config(self, PCIR_COMMAND, 2);
-       cmd |= PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN | PCIM_CMD_MWRICEN |
-               PCIM_CMD_SERRESPEN | PCIM_CMD_PERRESPEN;
-#if 1
+       cmd |= PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN;
        cmd &= ~PCIM_CMD_MWRICEN; 
-#endif
        pci_write_config(self, PCIR_COMMAND, cmd, 2);
 
        latency = olatency = pci_read_config(self, PCIR_LATTIMER, 1);
@@ -214,8 +281,8 @@ fwohci_pci_attach(device_t self)
 {
        fwohci_softc_t *sc = device_get_softc(self);
        int err;
-       int rid, s;
-#if __FreeBSD_version < 500000
+       int rid;
+#if defined(__DragonFly__) || __FreeBSD_version < 500000
        int intr;
        /* For the moment, put in a message stating what is wrong */
        intr = pci_read_config(self, PCIR_INTLINE, 1);
@@ -252,13 +319,6 @@ fwohci_pci_attach(device_t self)
                return ENXIO;
        }
 
-       sc->fc.bdev = device_add_child(self, "firewire", -1);
-       if (!sc->fc.bdev) {
-               device_printf(self, "Could not add firewire device\n");
-               fwohci_pci_detach(self);
-               return ENOMEM;
-       }
-       device_set_ivars(sc->fc.bdev, sc);
 
        err = bus_setup_intr(self, sc->irq_res,
 #if FWOHCI_TASKQUEUE
@@ -267,10 +327,13 @@ fwohci_pci_attach(device_t self)
                        INTR_TYPE_NET,
 #endif
                     (driver_intr_t *) fwohci_intr, sc, &sc->ih);
-#if __FreeBSD_version < 500000
+#if defined(__DragonFly__) || __FreeBSD_version < 500000
        /* XXX splcam() should mask this irq for sbp.c*/
        err = bus_setup_intr(self, sc->irq_res, INTR_TYPE_CAM,
                     (driver_intr_t *) fwohci_dummy_intr, sc, &sc->ih_cam);
+       /* XXX splbio() should mask this irq for physio()/fwmem_strategy() */
+       err = bus_setup_intr(self, sc->irq_res, INTR_TYPE_BIO,
+                    (driver_intr_t *) fwohci_dummy_intr, sc, &sc->ih_bio);
 #endif
        if (err) {
                device_printf(self, "Could not setup irq, %d\n", err);
@@ -291,6 +354,10 @@ fwohci_pci_attach(device_t self)
                                /*nsegments*/0x20,
                                /*maxsegsz*/0x8000,
                                /*flags*/BUS_DMA_ALLOCNOW,
+#if defined(__FreeBSD__) && __FreeBSD_version >= 501102
+                               /*lockfunc*/busdma_lock_mutex,
+                               /*lockarg*/&Giant,
+#endif
                                &sc->fc.dmat);
        if (err != 0) {
                printf("fwohci_pci_attach: Could not allocate DMA tag "
@@ -300,22 +367,15 @@ fwohci_pci_attach(device_t self)
 
        err = fwohci_init(sc, self);
 
-       if (!err)
-               err = device_probe_and_attach(sc->fc.bdev);
-
        if (err) {
-               device_printf(self, "FireWire init failed\n");
+               device_printf(self, "fwohci_init failed with err=%d\n", err);
                fwohci_pci_detach(self);
                return EIO;
        }
 
-       /* XXX
-        * Clear the bus reset event flag to start transactions even when
-        * interrupt is disabled during the boot process.
-        */
-       s = splfw();
-       fwohci_intr((void *)sc);
-       splx(s);
+       /* probe and attach a child device(firewire) */
+       bus_generic_probe(self);
+       bus_generic_attach(self);
 
        return 0;
 }
@@ -329,8 +389,14 @@ fwohci_pci_detach(device_t self)
 
        s = splfw();
 
-       fwohci_stop(sc, self);
+       if (sc->bsr)
+               fwohci_stop(sc, self);
+
        bus_generic_detach(self);
+       if (sc->fc.bdev) {
+               device_delete_child(self, sc->fc.bdev);
+               sc->fc.bdev = NULL;
+       }
 
        /* disable interrupts that might have been switched on */
        if (sc->bst && sc->bsh)
@@ -343,17 +409,13 @@ fwohci_pci_detach(device_t self)
                        /* XXX or should we panic? */
                        device_printf(self, "Could not tear down irq, %d\n",
                                      err);
-#if __FreeBSD_version < 500000
-               err = bus_teardown_intr(self, sc->irq_res, sc->ih_cam);
+#if defined(__DragonFly__) || __FreeBSD_version < 500000
+               bus_teardown_intr(self, sc->irq_res, sc->ih_cam);
+               bus_teardown_intr(self, sc->irq_res, sc->ih_bio);
 #endif
                sc->ih = NULL;
        }
 
-       if (sc->fc.bdev) {
-               device_delete_child(self, sc->fc.bdev);
-               sc->fc.bdev = NULL;
-       }
-
        if (sc->irq_res) {
                bus_release_resource(self, SYS_RES_IRQ, 0, sc->irq_res);
                sc->irq_res = NULL;
@@ -375,13 +437,14 @@ fwohci_pci_detach(device_t self)
 static int
 fwohci_pci_suspend(device_t dev)
 {
+       fwohci_softc_t *sc = device_get_softc(dev);
        int err;
 
        device_printf(dev, "fwohci_pci_suspend\n");
        err = bus_generic_suspend(dev);
        if (err)
                return err;
-       /* fwohci_stop(dev); */
+       fwohci_stop(sc, dev);
        return 0;
 }
 
@@ -390,8 +453,11 @@ fwohci_pci_resume(device_t dev)
 {
        fwohci_softc_t *sc = device_get_softc(dev);
 
+#ifndef BURN_BRIDGES
        device_printf(dev, "fwohci_pci_resume: power_state = 0x%08x\n",
                                        pci_get_powerstate(dev));
+       pci_set_powerstate(dev, PCI_POWERSTATE_D0);
+#endif
        fwohci_pci_init(dev);
        fwohci_resume(sc, dev);
        return 0;
@@ -407,6 +473,42 @@ fwohci_pci_shutdown(device_t dev)
        return 0;
 }
 
+static device_t
+fwohci_pci_add_child(device_t dev, int order, const char *name, int unit)
+{
+       struct fwohci_softc *sc;
+       device_t child;
+       int s, err = 0;
+
+       sc = (struct fwohci_softc *)device_get_softc(dev);
+       child = device_add_child(dev, name, unit);
+       if (child == NULL)
+               return (child);
+
+       sc->fc.bdev = child;
+       device_set_ivars(child, (void *)&sc->fc);
+
+       err = device_probe_and_attach(child);
+       if (err) {
+               device_printf(dev, "probe_and_attach failed with err=%d\n",
+                   err);
+               fwohci_pci_detach(dev);
+               device_delete_child(dev, child);
+               return NULL;
+       }
+
+       /* XXX
+        * Clear the bus reset event flag to start transactions even when
+        * interrupt is disabled during the boot process.
+        */
+       DELAY(250); /* 2 cycles */
+       s = splfw();
+       fwohci_poll((void *)sc, 0, -1);
+       splx(s);
+
+       return (child);
+}
+
 static device_method_t fwohci_methods[] = {
        /* Device interface */
        DEVMETHOD(device_probe,         fwohci_pci_probe),
@@ -417,6 +519,7 @@ static device_method_t fwohci_methods[] = {
        DEVMETHOD(device_shutdown,      fwohci_pci_shutdown),
 
        /* Bus interface */
+       DEVMETHOD(bus_add_child,        fwohci_pci_add_child),
        DEVMETHOD(bus_print_child,      bus_generic_print_child),
 
        { 0, 0 }
@@ -430,5 +533,8 @@ static driver_t fwohci_driver = {
 
 static devclass_t fwohci_devclass;
 
+#ifdef FWOHCI_MODULE
+MODULE_DEPEND(fwohci, firewire, 1, 1, 1);
+#endif
 DRIVER_MODULE(fwohci, pci, fwohci_driver, fwohci_devclass, 0, 0);
 DRIVER_MODULE(fwohci, cardbus, fwohci_driver, fwohci_devclass, 0, 0);