Suspend/resume for agp_amd.c
authoroga <oga@openbsd.org>
Sat, 7 Aug 2010 19:32:44 +0000 (19:32 +0000)
committeroga <oga@openbsd.org>
Sat, 7 Aug 2010 19:32:44 +0000 (19:32 +0000)
Note: the unconditional restore of the status register is ok because all
of the bits are either ones we want to preserve or read-only.

ok deraadt@

sys/dev/pci/agp_amd.c

index 7e40096..2256fd2 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: agp_amd.c,v 1.15 2010/04/08 00:23:53 tedu Exp $       */
+/*     $OpenBSD: agp_amd.c,v 1.16 2010/08/07 19:32:44 oga Exp $        */
 /*     $NetBSD: agp_amd.c,v 1.6 2001/10/06 02:48:50 thorpej Exp $      */
 
 /*-
@@ -73,9 +73,15 @@ struct agp_amd_softc {
        bus_space_tag_t          iot;
        bus_addr_t               asc_apaddr;
        bus_size_t               asc_apsize;
+       pcireg_t                 asc_apctrl;
+       pcireg_t                 asc_modectrl;
+       u_int16_t                asc_status;
 };
 
 void   agp_amd_attach(struct device *, struct device *, void *);
+int    agp_amd_activate(struct device *, int);
+void   agp_amd_save(struct agp_amd_softc *);
+void   agp_amd_restore(struct agp_amd_softc *);
 int    agp_amd_probe(struct device *, void *, void *);
 bus_size_t agp_amd_get_aperture(void *);
 struct agp_amd_gatt *agp_amd_alloc_gatt(bus_dma_tag_t, bus_size_t);
@@ -85,7 +91,8 @@ void  agp_amd_unbind_page(void *, bus_size_t);
 void   agp_amd_flush_tlb(void *);
 
 struct cfattach amdagp_ca = {
-       sizeof(struct agp_amd_softc), agp_amd_probe, agp_amd_attach
+       sizeof(struct agp_amd_softc), agp_amd_probe, agp_amd_attach, NULL,
+       agp_amd_activate
 };
 
 struct cfdriver amdagp_cd = {
@@ -269,6 +276,52 @@ agp_amd_detach(void *sc)
 }
 #endif
 
+int
+agp_amd_activate(struct device *arg, int act)
+{
+       struct agp_amd_softc *asc = (struct agp_amd_softc *)arg;
+
+       switch (act) {
+       case DVACT_SUSPEND:
+               agp_amd_save(asc);
+               break;
+       case DVACT_RESUME:
+               agp_amd_restore(asc);
+               break;
+       }
+
+       return (0);
+}
+
+void
+agp_amd_save(struct agp_amd_softc *asc)
+{
+       asc->asc_apctrl = pci_conf_read(asc->asc_pc, asc->asc_tag,
+           AGP_AMD751_APCTRL);
+       asc->asc_modectrl = pci_conf_read(asc->asc_pc, asc->asc_tag,
+           AGP_AMD751_MODECTRL);
+       asc->asc_status = READ2(AGP_AMD751_STATUS);
+}
+
+void
+agp_amd_restore(struct agp_amd_softc *asc)
+{
+
+       /* restore aperture size */
+       pci_conf_write(asc->asc_pc, asc->asc_tag, AGP_AMD751_APCTRL,
+           asc->asc_apctrl);
+
+       /* Install the gatt. */
+       WRITE4(AGP_AMD751_ATTBASE, asc->gatt->ag_physical);
+
+       /* Reenable synchronisation between host and agp. */
+       pci_conf_write(asc->asc_pc, asc->asc_tag, AGP_AMD751_MODECTRL,
+           asc->asc_modectrl);
+       /* Enable the TLB and flush */
+       WRITE2(AGP_AMD751_STATUS, asc->asc_status);
+       agp_amd_flush_tlb(asc);
+}
+
 bus_size_t
 agp_amd_get_aperture(void *sc)
 {