Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/sound/pci/hda/hdac.c
Show First 20 Lines • Show All 284 Lines • ▼ Show 20 Lines | for (k = 0; len > inv && k < nitems(hdac_quirks_tab); k++) { | ||||
*on &= ~hdac_quirks_tab[k].value; | *on &= ~hdac_quirks_tab[k].value; | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
i = j; | i = j; | ||||
} | } | ||||
} | } | ||||
/**************************************************************************** | |||||
* void hdac_intr_handler(void *) | |||||
* | |||||
* Interrupt handler. Processes interrupts received from the hdac. | |||||
****************************************************************************/ | |||||
static void | static void | ||||
hdac_intr_handler(void *context) | hdac_one_intr(struct hdac_softc *sc, uint32_t intsts) | ||||
{ | { | ||||
struct hdac_softc *sc; | |||||
device_t dev; | device_t dev; | ||||
uint32_t intsts; | |||||
uint8_t rirbsts; | uint8_t rirbsts; | ||||
int i; | int i; | ||||
sc = (struct hdac_softc *)context; | |||||
hdac_lock(sc); | |||||
/* Do we have anything to do? */ | |||||
intsts = HDAC_READ_4(&sc->mem, HDAC_INTSTS); | |||||
if ((intsts & HDAC_INTSTS_GIS) == 0) { | |||||
hdac_unlock(sc); | |||||
return; | |||||
} | |||||
/* Was this a controller interrupt? */ | /* Was this a controller interrupt? */ | ||||
if (intsts & HDAC_INTSTS_CIS) { | if (intsts & HDAC_INTSTS_CIS) { | ||||
rirbsts = HDAC_READ_1(&sc->mem, HDAC_RIRBSTS); | rirbsts = HDAC_READ_1(&sc->mem, HDAC_RIRBSTS); | ||||
/* Get as many responses that we can */ | /* Get as many responses that we can */ | ||||
while (rirbsts & HDAC_RIRBSTS_RINTFL) { | while (rirbsts & HDAC_RIRBSTS_RINTFL) { | ||||
HDAC_WRITE_1(&sc->mem, | HDAC_WRITE_1(&sc->mem, | ||||
HDAC_RIRBSTS, HDAC_RIRBSTS_RINTFL); | HDAC_RIRBSTS, HDAC_RIRBSTS_RINTFL); | ||||
hdac_rirb_flush(sc); | hdac_rirb_flush(sc); | ||||
rirbsts = HDAC_READ_1(&sc->mem, HDAC_RIRBSTS); | rirbsts = HDAC_READ_1(&sc->mem, HDAC_RIRBSTS); | ||||
} | } | ||||
if (sc->unsolq_rp != sc->unsolq_wp) | if (sc->unsolq_rp != sc->unsolq_wp) | ||||
taskqueue_enqueue(taskqueue_thread, &sc->unsolq_task); | taskqueue_enqueue(taskqueue_thread, &sc->unsolq_task); | ||||
} | } | ||||
if (intsts & HDAC_INTSTS_SIS_MASK) { | if (intsts & HDAC_INTSTS_SIS_MASK) { | ||||
for (i = 0; i < sc->num_ss; i++) { | for (i = 0; i < sc->num_ss; i++) { | ||||
if ((intsts & (1 << i)) == 0) | if ((intsts & (1 << i)) == 0) | ||||
continue; | continue; | ||||
HDAC_WRITE_1(&sc->mem, (i << 5) + HDAC_SDSTS, | HDAC_WRITE_1(&sc->mem, (i << 5) + HDAC_SDSTS, | ||||
HDAC_SDSTS_DESE | HDAC_SDSTS_FIFOE | HDAC_SDSTS_BCIS ); | HDAC_SDSTS_DESE | HDAC_SDSTS_FIFOE | HDAC_SDSTS_BCIS); | ||||
if ((dev = sc->streams[i].dev) != NULL) { | if ((dev = sc->streams[i].dev) != NULL) { | ||||
HDAC_STREAM_INTR(dev, | HDAC_STREAM_INTR(dev, | ||||
sc->streams[i].dir, sc->streams[i].stream); | sc->streams[i].dir, sc->streams[i].stream); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | |||||
HDAC_WRITE_4(&sc->mem, HDAC_INTSTS, intsts); | /**************************************************************************** | ||||
mav: What happened to this write? CIS and SIS bits there are RW1C, so must be written after the… | |||||
avgAuthorUnsubmitted Done Inline ActionsAccording to the original Intel HDA specification they are RO. avg: According to the [[ https://www.intel.com/content/dam/www/public/us/en/documents/product… | |||||
mavUnsubmitted Not Done Inline ActionsThe original specification is from 2004, and there they are RW1C. Not sure what they were thinking. mav: The original specification is from 2004, and there they are RW1C. Not sure what they were… | |||||
avgAuthorUnsubmitted Done Inline ActionsOh, I didn't even know about that original original specification. avg: Oh, I didn't even know about that original original specification.
I guess now I know from… | |||||
* void hdac_intr_handler(void *) | |||||
* | |||||
* Interrupt handler. Processes interrupts received from the hdac. | |||||
****************************************************************************/ | |||||
static void | |||||
hdac_intr_handler(void *context) | |||||
{ | |||||
struct hdac_softc *sc; | |||||
uint32_t intsts; | |||||
sc = (struct hdac_softc *)context; | |||||
/* | |||||
* Loop until HDAC_INTSTS_GIS gets clear. | |||||
* It is plausible that hardware interrupts a host only when GIS goes | |||||
* from zero to one. GIS is formed by OR-ing multiple hardware | |||||
* statuses, so it's possible that a previously cleared status gets set | |||||
* again while another status has not been cleared yet. Thus, there | |||||
* will be no new interrupt as GIS always stayed set. If we don't | |||||
* re-examine GIS then we can leave it set and never get an interrupt | |||||
* again. | |||||
*/ | |||||
intsts = HDAC_READ_4(&sc->mem, HDAC_INTSTS); | |||||
while ((intsts & HDAC_INTSTS_GIS) != 0) { | |||||
hdac_lock(sc); | |||||
hdac_one_intr(sc, intsts); | |||||
hdac_unlock(sc); | hdac_unlock(sc); | ||||
intsts = HDAC_READ_4(&sc->mem, HDAC_INTSTS); | |||||
} | |||||
} | } | ||||
static void | static void | ||||
hdac_poll_callback(void *arg) | hdac_poll_callback(void *arg) | ||||
{ | { | ||||
struct hdac_softc *sc = arg; | struct hdac_softc *sc = arg; | ||||
if (sc == NULL) | if (sc == NULL) | ||||
▲ Show 20 Lines • Show All 1,738 Lines • Show Last 20 Lines |
What happened to this write? CIS and SIS bits there are RW1C, so must be written after the interrupt is processed.