Subject: Re: kern/23584 (page-fault in clcs(4) after unclean reboot)
To: None <jmcneill@netbsd.org, gnats-admin@netbsd.org,>
From: Jared D. McNeill <jmcneill@invisible.ca>
List: netbsd-bugs
Date: 01/02/2006 18:50:02
The following reply was made to PR kern/23584; it has been noted by GNATS.
From: "Jared D. McNeill" <jmcneill@invisible.ca>
To: gnats-bugs@netbsd.org
Cc: jmcneill@netbsd.org, kern-bug-people@netbsd.org,
netbsd-bugs@netbsd.org, gnats-admin@netbsd.org,
stephane.witzmann@gmail.com
Subject: Re: kern/23584 (page-fault in clcs(4) after unclean reboot)
Date: Mon, 02 Jan 2006 14:49:36 -0400
Can you try the following patch Stephane? Sorry, it's mangled with your
Santa Cruz patch.
Index: cs4280.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/cs4280.c,v
retrieving revision 1.35
diff -u -r1.35 cs4280.c
--- cs4280.c 28 Jun 2005 00:28:41 -0000 1.35
+++ cs4280.c 2 Jan 2006 18:48:12 -0000
@@ -110,6 +110,8 @@
static void cs4280_power(int, void *);
/* Internal functions */
+static const struct cs4280_card_t * cs4280_identify_card(struct
pci_attach_args *);
+static void cs4280_setup_ac97eamp(struct cs428x_softc *);
static void cs4280_set_adc_rate(struct cs428x_softc *, int );
static void cs4280_set_dac_rate(struct cs428x_softc *, int );
static int cs4280_download(struct cs428x_softc *, const uint32_t *,
uint32_t,
@@ -126,6 +128,27 @@
uint32_t);
#endif
+/* Special cards */
+struct cs4280_card_t
+{
+ pcireg_t id;
+ enum cs428x_flag flags;
+};
+
+#define _card(vend, prod, flags) \
+ {PCI_ID_CODE(vend, prod), flags}
+
+static const struct cs4280_card_t cs4280_cards[] = {
+ _card(PCI_VENDOR_MITAC, PCI_PRODUCT_MITAC_MI6020,
+ CS428X_FLAG_AC97EAMP),
+ _card(PCI_VENDOR_TURTLE_BEACH, PCI_PRODUCT_TURTLE_BEACH_SANTA_CRUZ,
+ CS428X_FLAG_AC97EAMP)
+};
+
+#undef _card
+
+#define CS4280_CARDS_SIZE
(sizeof(cs4280_cards)/sizeof(cs4280_cards[0]))
+
static const struct audio_hw_if cs4280_hw_if = {
NULL, /* open */
NULL, /* close */
@@ -206,6 +229,7 @@
struct cs428x_softc *sc;
struct pci_attach_args *pa;
pci_chipset_tag_t pc;
+ const struct cs4280_card_t *cs_card;
char const *intrstr;
pci_intr_handle_t ih;
pcireg_t reg;
@@ -222,6 +246,16 @@
aprint_normal(": %s (rev. 0x%02x)\n", devinfo,
PCI_REVISION(pa->pa_class));
+ cs_card = cs4280_identify_card(pa);
+ if (cs_card != NULL) {
+ aprint_normal("%s: %s %s\n",sc->sc_dev.dv_xname,
+ pci_findvendor(cs_card->id),
+ pci_findproduct(cs_card->id));
+ sc->sc_flags = cs_card->flags;
+ } else {
+ sc->sc_flags = CS428X_FLAG_NONE;
+ }
+
/* Map I/O register */
if (pci_mapreg_map(pa, PCI_BA0,
PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT, 0,
@@ -309,6 +343,9 @@
return;
}
+ /* power AC97 external amp if needed */
+ cs4280_setup_ac97eamp(sc);
+
audio_attach_mi(&cs4280_hw_if, sc, &sc->sc_dev);
#if NMIDI > 0
@@ -364,18 +401,18 @@
if (sc->sc_prun) {
if ((sc->sc_pi%sc->sc_pcount) == 0)
sc->sc_pintr(sc->sc_parg);
+ /* copy buffer */
+ ++sc->sc_pi;
+ empty_dma = sc->sc_pdma->addr;
+ if (sc->sc_pi&1)
+ empty_dma += sc->hw_blocksize;
+ memcpy(empty_dma, sc->sc_pn, sc->hw_blocksize);
+ sc->sc_pn += sc->hw_blocksize;
+ if (sc->sc_pn >= sc->sc_pe)
+ sc->sc_pn = sc->sc_ps;
} else {
printf("unexpected play intr\n");
}
- /* copy buffer */
- ++sc->sc_pi;
- empty_dma = sc->sc_pdma->addr;
- if (sc->sc_pi&1)
- empty_dma += sc->hw_blocksize;
- memcpy(empty_dma, sc->sc_pn, sc->hw_blocksize);
- sc->sc_pn += sc->hw_blocksize;
- if (sc->sc_pn >= sc->sc_pe)
- sc->sc_pn = sc->sc_ps;
BA1WRITE4(sc, CS4280_PFIE, mem);
}
/* Capture Interrupt */
@@ -386,58 +423,62 @@
handled = 1;
mem = BA1READ4(sc, CS4280_CIE);
BA1WRITE4(sc, CS4280_CIE, (mem & ~CIE_CI_MASK) | CIE_CI_DISABLE);
- ++sc->sc_ri;
- empty_dma = sc->sc_rdma->addr;
- if ((sc->sc_ri&1) == 0)
- empty_dma += sc->hw_blocksize;
-
- /*
- * XXX
- * I think this audio data conversion should be
- * happend in upper layer, but I put this here
- * since there is no conversion function available.
- */
- switch(sc->sc_rparam) {
- case CF_16BIT_STEREO:
- /* just copy it */
- memcpy(sc->sc_rn, empty_dma, sc->hw_blocksize);
- sc->sc_rn += sc->hw_blocksize;
- break;
- case CF_16BIT_MONO:
- for (i = 0; i < 512; i++) {
- rdata = *((int16_t *)empty_dma)>>1;
- empty_dma += 2;
- rdata += *((int16_t *)empty_dma)>>1;
- empty_dma += 2;
- *((int16_t *)sc->sc_rn) = rdata;
- sc->sc_rn += 2;
- }
- break;
- case CF_8BIT_STEREO:
- for (i = 0; i < 512; i++) {
- rdata = *((int16_t*)empty_dma);
- empty_dma += 2;
- *sc->sc_rn++ = rdata >> 8;
- rdata = *((int16_t*)empty_dma);
- empty_dma += 2;
- *sc->sc_rn++ = rdata >> 8;
- }
- break;
- case CF_8BIT_MONO:
- for (i = 0; i < 512; i++) {
- rdata = *((int16_t*)empty_dma) >>1;
- empty_dma += 2;
- rdata += *((int16_t*)empty_dma) >>1;
- empty_dma += 2;
- *sc->sc_rn++ = rdata >>8;
+
+ if (sc->sc_rrun) {
+ ++sc->sc_ri;
+ empty_dma = sc->sc_rdma->addr;
+ if ((sc->sc_ri&1) == 0)
+ empty_dma += sc->hw_blocksize;
+
+ /*
+ * XXX
+ * I think this audio data conversion should be
+ * happend in upper layer, but I put this here
+ * since there is no conversion function available.
+ */
+ switch(sc->sc_rparam) {
+ case CF_16BIT_STEREO:
+ /* just copy it */
+ memcpy(sc->sc_rn, empty_dma, sc->hw_blocksize);
+ sc->sc_rn += sc->hw_blocksize;
+ break;
+ case CF_16BIT_MONO:
+ for (i = 0; i < 512; i++) {
+ rdata = *((int16_t *)empty_dma)>>1;
+ empty_dma += 2;
+ rdata += *((int16_t *)empty_dma)>>1;
+ empty_dma += 2;
+ *((int16_t *)sc->sc_rn) = rdata;
+ sc->sc_rn += 2;
+ }
+ break;
+ case CF_8BIT_STEREO:
+ for (i = 0; i < 512; i++) {
+ rdata = *((int16_t*)empty_dma);
+ empty_dma += 2;
+ *sc->sc_rn++ = rdata >> 8;
+ rdata = *((int16_t*)empty_dma);
+ empty_dma += 2;
+ *sc->sc_rn++ = rdata >> 8;
+ }
+ break;
+ case CF_8BIT_MONO:
+ for (i = 0; i < 512; i++) {
+ rdata = *((int16_t*)empty_dma) >>1;
+ empty_dma += 2;
+ rdata += *((int16_t*)empty_dma) >>1;
+ empty_dma += 2;
+ *sc->sc_rn++ = rdata >>8;
+ }
+ break;
+ default:
+ /* Should not reach here */
+ printf("unknown sc->sc_rparam: %d\n",
+ sc->sc_rparam);
}
- break;
- default:
- /* Should not reach here */
- printf("unknown sc->sc_rparam: %d\n", sc->sc_rparam);
+ if (sc->sc_rn >= sc->sc_re)
+ sc->sc_rn = sc->sc_rs;
}
- if (sc->sc_rn >= sc->sc_re)
- sc->sc_rn = sc->sc_rs;
BA1WRITE4(sc, CS4280_CIE, mem);
if (sc->sc_rrun) {
if ((sc->sc_ri%(sc->sc_rcount)) == 0)
@@ -957,11 +998,37 @@
return ETIMEDOUT;
}
}
+
return 0;
}
/* Internal functions */
+static const struct cs4280_card_t *
+cs4280_identify_card(struct pci_attach_args *pa)
+{
+ pcireg_t idreg;
+ u_int16_t i;
+
+ idreg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
+ for (i = 0; i < CS4280_CARDS_SIZE; i++) {
+ if (idreg == cs4280_cards[i].id)
+ return &cs4280_cards[i];
+ }
+
+ return NULL;
+}
+
+static void cs4280_setup_ac97eamp(struct cs428x_softc *sc)
+{
+ uint16_t val;
+
+ if (sc->sc_flags & CS428X_FLAG_AC97EAMP) {
+ cs428x_read_codec(sc, AC97_REG_POWER, &val);
+ cs428x_write_codec(sc, AC97_REG_POWER, val | AC97_POWER_EAMP);
+ }
+}
+
static void
cs4280_set_adc_rate(struct cs428x_softc *sc, int rate)
{
@@ -1125,7 +1192,7 @@
BA1WRITE4(sc, CS4280_PPI, ppi);
}
-/* Download Proceessor Code and Data image */
+/* Download Processor Code and Data image */
static int
cs4280_download(struct cs428x_softc *sc, const uint32_t *src,
uint32_t offset, uint32_t len)
@@ -1244,6 +1311,9 @@
mem = BA0READ4(sc, CS4280_CLKCR1) | CLKCR1_SWCE;
BA0WRITE4(sc, CS4280_CLKCR1, mem);
+ /* Enable FIFO Host Bypass */
+ BA0WRITE4(sc, CS4280_SERBCF, SERBCF_HBP);
+
/* Set the serial port FIFO pointer to the
* first sample in FIFO. (not documented) */
cs4280_clear_fifos(sc);