some ATI azalia controllers are brojen after resume, as in PR 6550.
the following diff gathers most of the pci conf register manipulation
done in azalia_pci_attach() into a new function, azalia_configure_pci(),
and calls that function in azalia_pci_attach() and azalia_resume().

this fixes one reported case of post-resume brokenness and doesn't
cause any problems on other machines I've tested on, including an
ATI device that was working.  waiting to hear back about the PR and
other reports, but wanted to get this out for testing asap.

please test.  thanks.

-- 
jake...@sdf.lonestar.org
SDF Public Access UNIX System - http://sdf.lonestar.org

Index: azalia.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/azalia.c,v
retrieving revision 1.190
diff -u -p azalia.c
--- azalia.c    17 Feb 2011 17:38:55 -0000      1.190
+++ azalia.c    28 Feb 2011 22:25:56 -0000
@@ -198,6 +198,7 @@ int azalia_pci_match(struct device *, void *, void *);
 void   azalia_pci_attach(struct device *, struct device *, void *);
 int    azalia_pci_activate(struct device *, int);
 int    azalia_pci_detach(struct device *, int);
+void   azalia_configure_pci(azalia_t *);
 int    azalia_intr(void *);
 void   azalia_print_codec(codec_t *);
 int    azalia_reset(azalia_t *);
@@ -375,66 +376,37 @@ azalia_pci_write(pci_chipset_tag_t pc, pcitag_t pa, in
        pci_conf_write(pc, pa, (reg & ~0x03), pcival);
 }
 
-int
-azalia_pci_match(struct device *parent, void *match, void *aux)
-{
-       struct pci_attach_args *pa;
-
-       pa = aux;
-       if (PCI_CLASS(pa->pa_class) == PCI_CLASS_MULTIMEDIA
-           && PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MULTIMEDIA_HDAUDIO)
-               return 1;
-       return 0;
-}
-
 void
-azalia_pci_attach(struct device *parent, struct device *self, void *aux)
+azalia_configure_pci(azalia_t *az)
 {
-       azalia_t *sc;
-       struct pci_attach_args *pa;
        pcireg_t v;
-       pci_intr_handle_t ih;
-       const char *interrupt_str;
        uint8_t reg;
 
-       sc = (azalia_t*)self;
-       pa = aux;
-
-       sc->dmat = pa->pa_dmat;
-
-       v = pci_conf_read(pa->pa_pc, pa->pa_tag, ICH_PCI_HDBARL);
-       v &= PCI_MAPREG_TYPE_MASK | PCI_MAPREG_MEM_TYPE_MASK;
-       if (pci_mapreg_map(pa, ICH_PCI_HDBARL, v, 0,
-                          &sc->iot, &sc->ioh, NULL, &sc->map_size, 0)) {
-               printf(": can't map device i/o space\n");
-               return;
-       }
-
        /* enable back-to-back */
-       v = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
-       pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
+       v = pci_conf_read(az->pc, az->tag, PCI_COMMAND_STATUS_REG);
+       pci_conf_write(az->pc, az->tag, PCI_COMMAND_STATUS_REG,
            v | PCI_COMMAND_BACKTOBACK_ENABLE);
 
        /* traffic class select */
-       v = pci_conf_read(pa->pa_pc, pa->pa_tag, ICH_PCI_HDTCSEL);
-       pci_conf_write(pa->pa_pc, pa->pa_tag, ICH_PCI_HDTCSEL,
+       v = pci_conf_read(az->pc, az->tag, ICH_PCI_HDTCSEL);
+       pci_conf_write(az->pc, az->tag, ICH_PCI_HDTCSEL,
            v & ~(ICH_PCI_HDTCSEL_MASK));
 
        /* disable MSI, use INTx instead */
-       if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_INTEL) {
-               reg = azalia_pci_read(pa->pa_pc, pa->pa_tag, ICH_PCI_MMC);
+       if (PCI_VENDOR(az->pciid) == PCI_VENDOR_INTEL) {
+               reg = azalia_pci_read(az->pc, az->tag, ICH_PCI_MMC);
                reg &= ~(ICH_PCI_MMC_ME);
-               azalia_pci_write(pa->pa_pc, pa->pa_tag, ICH_PCI_MMC, reg);
+               azalia_pci_write(az->pc, az->tag, ICH_PCI_MMC, reg);
        }
 
        /* enable PCIe snoop */
-       switch (PCI_PRODUCT(pa->pa_id)) {
+       switch (PCI_PRODUCT(az->pciid)) {
        case PCI_PRODUCT_ATI_SB450_HDA:
        case PCI_PRODUCT_ATI_SBX00_HDA:
-               reg = azalia_pci_read(pa->pa_pc, pa->pa_tag, 
ATI_PCIE_SNOOP_REG);
+               reg = azalia_pci_read(az->pc, az->tag, ATI_PCIE_SNOOP_REG);
                reg &= ATI_PCIE_SNOOP_MASK;
                reg |= ATI_PCIE_SNOOP_ENABLE;
-               azalia_pci_write(pa->pa_pc, pa->pa_tag, ATI_PCIE_SNOOP_REG, 
reg);
+               azalia_pci_write(az->pc, az->tag, ATI_PCIE_SNOOP_REG, reg);
                break;
        case PCI_PRODUCT_NVIDIA_MCP51_HDA:
        case PCI_PRODUCT_NVIDIA_MCP55_HDA:
@@ -458,26 +430,26 @@ azalia_pci_attach(struct device *parent, struct device
        case PCI_PRODUCT_NVIDIA_MCP89_HDA_2:
        case PCI_PRODUCT_NVIDIA_MCP89_HDA_3:
        case PCI_PRODUCT_NVIDIA_MCP89_HDA_4:
-               reg = azalia_pci_read(pa->pa_pc, pa->pa_tag,
+               reg = azalia_pci_read(az->pc, az->tag,
                    NVIDIA_HDA_OSTR_COH_REG);
                reg |= NVIDIA_HDA_STR_COH_ENABLE;
-               azalia_pci_write(pa->pa_pc, pa->pa_tag,
+               azalia_pci_write(az->pc, az->tag,
                    NVIDIA_HDA_OSTR_COH_REG, reg);
 
-               reg = azalia_pci_read(pa->pa_pc, pa->pa_tag,
+               reg = azalia_pci_read(az->pc, az->tag,
                    NVIDIA_HDA_ISTR_COH_REG);
                reg |= NVIDIA_HDA_STR_COH_ENABLE;
-               azalia_pci_write(pa->pa_pc, pa->pa_tag,
+               azalia_pci_write(az->pc, az->tag,
                    NVIDIA_HDA_ISTR_COH_REG, reg);
 
-               reg = azalia_pci_read(pa->pa_pc, pa->pa_tag,
+               reg = azalia_pci_read(az->pc, az->tag,
                    NVIDIA_PCIE_SNOOP_REG);
                reg &= NVIDIA_PCIE_SNOOP_MASK;
                reg |= NVIDIA_PCIE_SNOOP_ENABLE;
-               azalia_pci_write(pa->pa_pc, pa->pa_tag,
+               azalia_pci_write(az->pc, az->tag,
                    NVIDIA_PCIE_SNOOP_REG, reg);
 
-               reg = azalia_pci_read(pa->pa_pc, pa->pa_tag,
+               reg = azalia_pci_read(az->pc, az->tag,
                    NVIDIA_PCIE_SNOOP_REG);
                if ((reg & NVIDIA_PCIE_SNOOP_ENABLE) !=
                    NVIDIA_PCIE_SNOOP_ENABLE) {
@@ -486,14 +458,54 @@ azalia_pci_attach(struct device *parent, struct device
 
                break;
        }
+}
 
+int
+azalia_pci_match(struct device *parent, void *match, void *aux)
+{
+       struct pci_attach_args *pa;
+
+       pa = aux;
+       if (PCI_CLASS(pa->pa_class) == PCI_CLASS_MULTIMEDIA
+           && PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MULTIMEDIA_HDAUDIO)
+               return 1;
+       return 0;
+}
+
+void
+azalia_pci_attach(struct device *parent, struct device *self, void *aux)
+{
+       azalia_t *sc;
+       struct pci_attach_args *pa;
+       pcireg_t v;
+       pci_intr_handle_t ih;
+       const char *interrupt_str;
+
+       sc = (azalia_t*)self;
+       pa = aux;
+
+       sc->dmat = pa->pa_dmat;
+
+       v = pci_conf_read(pa->pa_pc, pa->pa_tag, ICH_PCI_HDBARL);
+       v &= PCI_MAPREG_TYPE_MASK | PCI_MAPREG_MEM_TYPE_MASK;
+       if (pci_mapreg_map(pa, ICH_PCI_HDBARL, v, 0,
+                          &sc->iot, &sc->ioh, NULL, &sc->map_size, 0)) {
+               printf(": can't map device i/o space\n");
+               return;
+       }
+
+       sc->pc = pa->pa_pc;
+       sc->tag = pa->pa_tag;
+       sc->pciid = pa->pa_id;
+       sc->subid = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
+
+       azalia_configure_pci(sc);
+
        /* interrupt */
        if (pci_intr_map(pa, &ih)) {
                printf(": can't map interrupt\n");
                return;
        }
-       sc->pc = pa->pa_pc;
-       sc->tag = pa->pa_tag;
        interrupt_str = pci_intr_string(pa->pa_pc, ih);
        sc->ih = pci_intr_establish(pa->pa_pc, ih, IPL_AUDIO, azalia_intr,
            sc, sc->dev.dv_xname);
@@ -506,9 +518,6 @@ azalia_pci_attach(struct device *parent, struct device
        }
        printf(": %s\n", interrupt_str);
 
-       sc->pciid = pa->pa_id;
-       sc->subid = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
-
        if (azalia_init(sc, 0))
                goto err_exit;
 
@@ -1409,21 +1418,12 @@ azalia_resume_codec(codec_t *this)
 int
 azalia_resume(azalia_t *az)
 {
-       pcireg_t v;
        int err;
 
        if (az->detached)
                return 0;
 
-       /* enable back-to-back */
-       v = pci_conf_read(az->pc, az->tag, PCI_COMMAND_STATUS_REG);
-       pci_conf_write(az->pc, az->tag, PCI_COMMAND_STATUS_REG,
-           v | PCI_COMMAND_BACKTOBACK_ENABLE);
-
-       /* traffic class select */
-       v = pci_conf_read(az->pc, az->tag, ICH_PCI_HDTCSEL);
-       pci_conf_write(az->pc, az->tag, ICH_PCI_HDTCSEL,
-           v & ~(ICH_PCI_HDTCSEL_MASK));
+       azalia_configure_pci(az);
 
        /* is this necessary? */
        pci_conf_write(az->pc, az->tag, PCI_SUBSYS_ID_REG, az->subid);

Reply via email to