Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset a333b7f in mainline


Ignore:
Timestamp:
2014-08-25T09:28:39Z (6 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
master
Children:
932e2f5
Parents:
1412a184
Message:

Interrupt handling - RIRB interrupts.

Location:
uspace/drv/audio/hdaudio
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/audio/hdaudio/hdactl.c

    r1412a184 ra333b7f  
    3939#include <ddi.h>
    4040#include <errno.h>
     41#include <fibril_synch.h>
    4142#include <macros.h>
    4243#include <stdint.h>
     
    222223
    223224        /* Set RINTCNT - Qemu won't read from CORB if this is zero */
    224         hda_reg16_write(&hda->regs->rintcnt, 128);
     225        hda_reg16_write(&hda->regs->rintcnt, hda->ctl->rirb_entries / 2);
    225226
    226227        hda->ctl->rirb_rp = 0;
    227228
    228         /* Start RIRB */
     229        /* Start RIRB and enable RIRB interrupt */
    229230        ctl = hda_reg8_read(&hda->regs->rirbctl);
    230231        ddf_msg(LVL_NOTE, "RIRBctl (0x%x) = 0x%x",
    231232            (unsigned)((void *)&hda->regs->rirbctl - (void *)hda->regs), ctl | BIT_V(uint8_t, rirbctl_run));
    232         hda_reg8_write(&hda->regs->rirbctl, ctl | BIT_V(uint8_t, rirbctl_run));
     233        hda_reg8_write(&hda->regs->rirbctl, ctl | BIT_V(uint8_t, rirbctl_run) |
     234            BIT_V(uint8_t, rirbctl_int));
    233235
    234236        ddf_msg(LVL_NOTE, "RIRB initialized");
     
    327329}
    328330
    329 static int hda_rirb_read(hda_t *hda, hda_rirb_entry_t *data, size_t count)
     331static int hda_rirb_read(hda_t *hda, hda_rirb_entry_t *data)
    330332{
    331333        size_t wp;
    332334        hda_rirb_entry_t resp;
    333335        hda_rirb_entry_t *rirb;
     336
     337        rirb = (hda_rirb_entry_t *)hda->ctl->rirb_virt;
     338
     339        wp = hda_get_rirbwp(hda);
     340        ddf_msg(LVL_DEBUG2, "hda_rirb_read: wp=%d", wp);
     341        if (hda->ctl->rirb_rp == wp)
     342                return ENOENT;
     343
     344        ++hda->ctl->rirb_rp;
     345        resp = rirb[hda->ctl->rirb_rp];
     346
     347        ddf_msg(LVL_DEBUG2, "RESPONSE resp=0x%x respex=0x%x",
     348            resp.resp, resp.respex);
     349        *data = resp;
     350        return EOK;
     351}
     352
     353static int hda_solrb_read(hda_t *hda, hda_rirb_entry_t *data, size_t count)
     354{
     355        hda_rirb_entry_t resp;
    334356        int wcnt;
    335357
    336         rirb = (hda_rirb_entry_t *)hda->ctl->rirb_virt;
     358        wcnt = 10;
     359
     360        fibril_mutex_lock(&hda->ctl->solrb_lock);
    337361
    338362        while (count > 0) {
    339                 wp = hda_get_rirbwp(hda);
    340                 ddf_msg(LVL_DEBUG2, "hda_rirb_read: wp=%d", wp);
    341                 while (count > 0 && hda->ctl->rirb_rp != wp) {
    342                         ++hda->ctl->rirb_rp;
    343                         resp = rirb[hda->ctl->rirb_rp];
    344 
    345                         ddf_msg(LVL_DEBUG2, "RESPONSE resp=0x%x respex=0x%x",
     363                while (count > 0 && hda->ctl->solrb_rp != hda->ctl->solrb_wp) {
     364                        ++hda->ctl->solrb_rp;
     365                        resp = hda->ctl->solrb[hda->ctl->solrb_rp];
     366
     367                        ddf_msg(LVL_DEBUG2, "solrb RESPONSE resp=0x%x respex=0x%x",
    346368                            resp.resp, resp.respex);
    347369                        if ((resp.respex & BIT_V(uint32_t, respex_unsol)) == 0) {
     
    353375
    354376                if (count > 0) {
    355                         wcnt = rirb_wait_max;
    356                         while (wcnt > 0 && hda_get_rirbwp(hda) == hda->ctl->rirb_rp) {
     377                        while (wcnt > 0 && hda->ctl->solrb_wp == hda->ctl->solrb_rp) {
     378                                fibril_mutex_unlock(&hda->ctl->solrb_lock);
    357379                                async_usleep(100);
     380                                fibril_mutex_lock(&hda->ctl->solrb_lock);
    358381                                --wcnt;
    359382                        }
    360383
    361                         if (hda_get_rirbwp(hda) == hda->ctl->rirb_rp)
     384                        if (hda->ctl->solrb_wp == hda->ctl->solrb_rp) {
     385                                ddf_msg(LVL_NOTE, "hda_solrb_read() time out");
     386                                fibril_mutex_unlock(&hda->ctl->solrb_lock);
    362387                                return ETIMEOUT;
    363                 }
    364         }
    365 
     388                        }
     389                }
     390        }
     391
     392        fibril_mutex_unlock(&hda->ctl->solrb_lock);
    366393        return EOK;
    367394}
     
    371398        hda_ctl_t *ctl;
    372399        uint32_t gctl;
     400        uint32_t intctl;
    373401        int cnt;
    374402        int rc;
     
    378406                return NULL;
    379407
     408        fibril_mutex_initialize(&ctl->solrb_lock);
     409        fibril_condvar_initialize(&ctl->solrb_cv);
     410
    380411        hda->ctl = ctl;
     412        ctl->hda = hda;
    381413
    382414        uint8_t vmaj = hda_reg8_read(&hda->regs->vmaj);
     
    391423
    392424        ddf_msg(LVL_NOTE, "reg 0x%zx STATESTS = 0x%x",
    393             (void *)&hda->regs->statests - (void *)hda->regs, hda_reg16_read(&hda->regs->statests));
     425            (void *)&hda->regs->statests - (void *)hda->regs,
     426                hda_reg16_read(&hda->regs->statests));
     427        /**
     428          * Clear STATESTS bits so they don't generate an interrupt later
     429          * when we enable interrupts.
     430          */
     431        hda_reg16_write(&hda->regs->statests, 0x7f);
     432
     433        ddf_msg(LVL_NOTE, "after clearing reg 0x%zx STATESTS = 0x%x",
     434            (void *)&hda->regs->statests - (void *)hda->regs,
     435                hda_reg16_read(&hda->regs->statests));
    394436
    395437        gctl = hda_reg32_read(&hda->regs->gctl);
     
    437479            hda_reg16_read(&hda->regs->statests));
    438480
     481        async_usleep(1000*1000);
     482
     483        /* Enable interrupts */
     484        intctl = hda_reg32_read(&hda->regs->intctl);
     485        ddf_msg(LVL_NOTE, "intctl (0x%x) := 0x%x",
     486            (unsigned)((void *)&hda->regs->intctl - (void *)hda->regs),
     487            intctl | BIT_V(uint32_t, intctl_gie) | BIT_V(uint32_t, intctl_cie));
     488        hda_reg32_write(&hda->regs->intctl, intctl |
     489            BIT_V(uint32_t, intctl_gie) | BIT_V(uint32_t, intctl_cie));
     490
     491        async_usleep(1000*1000);
     492
    439493        rc = hda_corb_init(hda);
    440494        if (rc != EOK)
    441495                goto error;
    442496
     497
     498        async_usleep(1000*1000);
     499
    443500        rc = hda_rirb_init(hda);
    444501        if (rc != EOK)
    445502                goto error;
    446503
     504        async_usleep(1000*1000);
     505
     506        ddf_msg(LVL_NOTE, "call hda_codec_init()");
    447507        hda->ctl->codec = hda_codec_init(hda, 0);
    448         if (hda->ctl->codec == NULL)
    449                 goto error;
     508        if (hda->ctl->codec == NULL) {
     509                ddf_msg(LVL_NOTE, "hda_codec_init() failed");
     510                goto error;
     511        }
    450512
    451513        return ctl;
     
    466528
    467529        if (resp != NULL) {
    468                 rc = hda_rirb_read(hda, &rentry, 1);
     530                rc = hda_solrb_read(hda, &rentry, 1);
    469531                if (rc != EOK)
    470532                        return rc;
     
    483545}
    484546
     547void hda_ctl_interrupt(hda_ctl_t *ctl)
     548{
     549        hda_rirb_entry_t resp;
     550        int rc;
     551
     552        while (true) {
     553                rc = hda_rirb_read(ctl->hda, &resp);
     554                if (rc != EOK) {
     555//                      ddf_msg(LVL_NOTE, "nothing in rirb");
     556                        break;
     557                }
     558
     559                ddf_msg(LVL_NOTE, "writing to solrb");
     560                fibril_mutex_lock(&ctl->solrb_lock);
     561                ctl->solrb_wp = (ctl->solrb_wp + 1) % softrb_entries;
     562                ctl->solrb[ctl->solrb_wp] = resp;
     563                fibril_mutex_unlock(&ctl->solrb_lock);
     564                fibril_condvar_broadcast(&ctl->solrb_cv);
     565        }
     566}
     567
    485568/** @}
    486569 */
  • uspace/drv/audio/hdaudio/hdactl.h

    r1412a184 ra333b7f  
    3636#define HDACTL_H
    3737
     38#include <fibril_synch.h>
    3839#include <stdbool.h>
    3940#include "hdaudio.h"
     41#include "spec/regs.h"
     42
     43enum {
     44        /** Software response buffer size in entries */
     45        softrb_entries = 128
     46};
    4047
    4148typedef struct hda_ctl {
     
    5461        size_t rirb_rp;
    5562
     63        fibril_mutex_t solrb_lock;
     64        fibril_condvar_t solrb_cv;
     65        hda_rirb_entry_t solrb[softrb_entries];
     66        size_t solrb_rp;
     67        size_t solrb_wp;
     68
     69        hda_rirb_entry_t unsolrb[softrb_entries];
     70        size_t unsolrb_rp;
     71        size_t unsolrb_wp;
     72
    5673        struct hda_codec *codec;
     74        struct hda *hda;
    5775} hda_ctl_t;
    5876
    5977extern hda_ctl_t *hda_ctl_init(hda_t *);
    6078extern void hda_ctl_fini(hda_ctl_t *);
     79extern void hda_ctl_interrupt(hda_ctl_t *);
    6180extern int hda_cmd(hda_t *, uint32_t, uint32_t *);
    6281
  • uspace/drv/audio/hdaudio/hdaudio.c

    r1412a184 ra333b7f  
    3434
    3535#include <assert.h>
     36#include <bitops.h>
    3637#include <ddi.h>
    3738#include <device/hw_res_parsed.h>
     
    4041#include <str_error.h>
    4142#include <ddf/driver.h>
     43#include <ddf/interrupt.h>
    4244#include <ddf/log.h>
    4345
     
    5355static int hda_fun_online(ddf_fun_t *fun);
    5456static int hda_fun_offline(ddf_fun_t *fun);
     57
     58static void hdaudio_interrupt(ddf_dev_t *, ipc_callid_t, ipc_call_t *);
    5559
    5660static driver_ops_t driver_ops = {
     
    6771};
    6872
     73irq_pio_range_t hdaudio_irq_pio_ranges[] = {
     74        {
     75                .base = 0,
     76                .size = 8192
     77        }
     78};
     79
     80irq_cmd_t hdaudio_irq_commands[] = {
     81        {
     82                .cmd = CMD_PIO_READ_8,
     83                .addr = NULL,
     84                .dstarg = 2
     85        },
     86        {
     87                .cmd = CMD_AND,
     88                .value = BIT_V(uint8_t, rirbsts_intfl),
     89                .srcarg = 2,
     90                .dstarg = 3
     91        },
     92        {
     93                .cmd = CMD_PREDICATE,
     94                .value = 2,
     95                .srcarg = 3
     96        },
     97        {
     98                .cmd = CMD_PIO_WRITE_8,
     99                .addr = NULL,
     100                .value = BIT_V(uint8_t, rirbsts_intfl),
     101        },
     102        {
     103                .cmd = CMD_ACCEPT
     104        }
     105};
     106
     107irq_code_t hdaudio_irq_code = {
     108        .rangecount = sizeof(hdaudio_irq_pio_ranges) / sizeof(irq_pio_range_t),
     109        .ranges = hdaudio_irq_pio_ranges,
     110        .cmdcount = sizeof(hdaudio_irq_commands) / sizeof(irq_cmd_t),
     111        .cmds = hdaudio_irq_commands
     112};
     113
    69114static int hda_dev_add(ddf_dev_t *dev)
    70115{
     
    110155        hda->rwsize = RNGSZ(res.mem_ranges.ranges[0]);
    111156
     157        ddf_msg(LVL_NOTE, "hda reg base: %" PRIx64,
     158             RNGABS(res.mem_ranges.ranges[0]));
     159
    112160        if (hda->rwsize < sizeof(hda_regs_t)) {
    113161                ddf_msg(LVL_ERROR, "Memory range is too small.");
     
    124172
    125173        hda->regs = (hda_regs_t *)regs;
     174
     175        ddf_msg(LVL_NOTE, "IRQs: %d", res.irqs.count);
     176        if (res.irqs.count != 1) {
     177                ddf_msg(LVL_ERROR, "Unexpected IRQ count %d (!= 1)",
     178                    res.irqs.count);
     179                goto error;
     180        }
     181        ddf_msg(LVL_NOTE, "interrupt no: %d", res.irqs.irqs[0]);
     182
     183        hda_regs_t *rphys = (hda_regs_t *)(uintptr_t)hda->rwbase;
     184        hdaudio_irq_pio_ranges[0].base = (uintptr_t)hda->rwbase;
     185        hdaudio_irq_commands[0].addr = (void *)&rphys->rirbsts;
     186        hdaudio_irq_commands[3].addr = (void *)&rphys->rirbsts;
     187        ddf_msg(LVL_NOTE, "range0.base=%x", hdaudio_irq_pio_ranges[0].base);
     188        ddf_msg(LVL_NOTE, "cmd0.addr=%p", hdaudio_irq_commands[0].addr);
     189        ddf_msg(LVL_NOTE, "cmd3.addr=%p", hdaudio_irq_commands[3].addr);
     190
     191        rc = register_interrupt_handler(dev, res.irqs.irqs[0],
     192            hdaudio_interrupt, &hdaudio_irq_code);
     193        if (rc != EOK) {
     194                ddf_msg(LVL_ERROR, "Failed registering interrupt handler. (%d)",
     195                    rc);
     196                goto error;
     197        }
    126198
    127199        if (hda_ctl_init(hda) == NULL) {
     
    157229        }
    158230
     231        ddf_msg(LVL_NOTE, "Failing hda_dev_add() -> %d", rc);
    159232        return rc;
    160233}
     
    208281}
    209282
     283static void hdaudio_interrupt(ddf_dev_t *dev, ipc_callid_t iid,
     284    ipc_call_t *icall)
     285{
     286        hda_t *hda = (hda_t *)ddf_dev_data_get(dev);
     287
     288        ddf_msg(LVL_NOTE, "## interrupt ##");
     289        hda_ctl_interrupt(hda->ctl);
     290}
     291
    210292int main(int argc, char *argv[])
    211293{
  • uspace/drv/audio/hdaudio/hdaudio.h

    r1412a184 ra333b7f  
    4343
    4444/** High Definition Audio driver instance */
    45 typedef struct {
     45typedef struct hda {
    4646        async_sess_t *parent_sess;
    4747        ddf_fun_t *fun_a;
  • uspace/drv/audio/hdaudio/hdaudio.ma

    r1412a184 ra333b7f  
    1110 pci/ven=1002&dev=4383
     210 pci/ven=8086&dev=1e20
    2310 pci/ven=8086&dev=2668
  • uspace/drv/audio/hdaudio/spec/regs.h

    r1412a184 ra333b7f  
    196196
    197197typedef enum {
     198        /** Global Interrupt Enable */
     199        intctl_gie = 31,
     200        /** Controller Interrupt Enable */
     201        intctl_cie = 30,
     202        /** Stream Interrupt Enable */
     203        intctl_sie = 29
     204} hda_intctl_bits_t;
     205
     206typedef enum {
    198207        /** CORB Read Pointer Reset */
    199208        corbrp_rst = 15,
     
    248257
    249258typedef enum {
     259        /** Response Overrun Interrupt Status */
     260        rirbsts_ois = 2,
     261        /** Response Interrupt */
     262        rirbsts_intfl = 0
     263} hda_rirbsts_bits_t;
     264
     265typedef enum {
    250266        /** RIRB Size Capability (H) */
    251267        rirbsize_cap_h = 7,
  • uspace/drv/audio/hdaudio/stream.c

    r1412a184 ra333b7f  
    175175void hda_stream_start(hda_stream_t *stream)
    176176{
     177        ddf_msg(LVL_NOTE, "hda_stream_start()");
    177178        hda_stream_set_run(stream, true);
    178179}
Note: See TracChangeset for help on using the changeset viewer.