Changeset 64cf7a3 in mainline


Ignore:
Timestamp:
2024-05-06T18:33:22Z (3 months ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
master
Children:
2791fbb7
Parents:
21989e5
Message:

ATA Block Driver support for IRQ

You can fall back to PIO mode by not assigning an IRQ resource to
the driver instance.

Location:
uspace/drv
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/block/ata_bd/ata_bd.c

    r21989e5 r64cf7a3  
    11/*
    2  * Copyright (c) 2013 Jiri Svoboda
     2 * Copyright (c) 2024 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    4949
    5050#include <ddi.h>
     51#include <ddf/interrupt.h>
    5152#include <ddf/log.h>
    5253#include <async.h>
     
    7374#define NAME       "ata_bd"
    7475
    75 /** Number of defined legacy controller base addresses. */
    76 #define LEGACY_CTLS 4
    77 
    7876/**
    7977 * Size of data returned from Identify Device or Identify Packet Device
     
    8482static errno_t ata_bd_init_io(ata_ctrl_t *ctrl);
    8583static void ata_bd_fini_io(ata_ctrl_t *ctrl);
     84static errno_t ata_bd_init_irq(ata_ctrl_t *ctrl);
     85static void ata_bd_fini_irq(ata_ctrl_t *ctrl);
    8686
    8787static errno_t ata_bd_open(bd_srvs_t *, bd_srv_t *);
     
    121121static errno_t wait_status(ata_ctrl_t *ctrl, unsigned set, unsigned n_reset,
    122122    uint8_t *pstatus, unsigned timeout);
     123static errno_t wait_irq(ata_ctrl_t *ctrl, uint8_t *pstatus, unsigned timeout);
     124static void ata_irq_handler(ipc_call_t *call, ddf_dev_t *dev);
    123125
    124126bd_ops_t ata_bd_ops = {
     
    133135};
    134136
     137static const irq_pio_range_t ata_irq_ranges[] = {
     138        {
     139                .base = 0,
     140                .size = sizeof(ata_cmd_t)
     141        }
     142};
     143
     144/** ATA interrupt pseudo code. */
     145static const irq_cmd_t ata_irq_cmds[] = {
     146        {
     147                .cmd = CMD_PIO_READ_8,
     148                .addr = NULL,  /* will be patched in run-time */
     149                .dstarg = 1
     150        },
     151        {
     152                .cmd = CMD_ACCEPT
     153        }
     154};
     155
    135156static disk_t *bd_srv_disk(bd_srv_t *bd)
    136157{
     
    144165
    145166/** Initialize ATA controller. */
    146 errno_t ata_ctrl_init(ata_ctrl_t *ctrl, ata_base_t *res)
     167errno_t ata_ctrl_init(ata_ctrl_t *ctrl, ata_hwres_t *res)
    147168{
    148169        int i;
    149170        errno_t rc;
    150171        int n_disks;
     172        bool irq_inited = false;
    151173
    152174        ddf_msg(LVL_DEBUG, "ata_ctrl_init()");
    153175
    154176        fibril_mutex_initialize(&ctrl->lock);
     177        fibril_mutex_initialize(&ctrl->irq_lock);
     178        fibril_condvar_initialize(&ctrl->irq_cv);
    155179        ctrl->cmd_physical = res->cmd;
    156180        ctrl->ctl_physical = res->ctl;
     181        ctrl->irq = res->irq;
    157182
    158183        ddf_msg(LVL_NOTE, "I/O address %p/%p", (void *) ctrl->cmd_physical,
     
    162187        if (rc != EOK)
    163188                return rc;
     189
     190        rc = ata_bd_init_irq(ctrl);
     191        if (rc != EOK)
     192                return rc;
     193
     194        irq_inited = true;
    164195
    165196        for (i = 0; i < MAX_DISKS; i++) {
     
    205236                }
    206237        }
     238        if (irq_inited)
     239                ata_bd_fini_irq(ctrl);
    207240        ata_bd_fini_io(ctrl);
    208241        return rc;
     
    228261        }
    229262
     263        ata_bd_fini_irq(ctrl);
    230264        ata_bd_fini_io(ctrl);
    231265        fibril_mutex_unlock(&ctrl->lock);
     
    329363
    330364        ctrl->ctl = vaddr;
    331 
    332365        return EOK;
    333366}
     
    338371        (void) ctrl;
    339372        /* XXX TODO */
     373}
     374
     375/** Initialize IRQ. */
     376static errno_t ata_bd_init_irq(ata_ctrl_t *ctrl)
     377{
     378        irq_code_t irq_code;
     379        async_sess_t *parent_sess;
     380        irq_pio_range_t *ranges;
     381        irq_cmd_t *cmds;
     382        errno_t rc;
     383
     384        if (ctrl->irq < 0)
     385                return EOK;
     386
     387        ranges = malloc(sizeof(ata_irq_ranges));
     388        if (ranges == NULL)
     389                return ENOMEM;
     390
     391        cmds = malloc(sizeof(ata_irq_cmds));
     392        if (cmds == NULL) {
     393                free(cmds);
     394                return ENOMEM;
     395        }
     396
     397        memcpy(ranges, &ata_irq_ranges, sizeof(ata_irq_ranges));
     398        ranges[0].base = ctrl->cmd_physical;
     399        memcpy(cmds, &ata_irq_cmds, sizeof(ata_irq_cmds));
     400        cmds[0].addr = &ctrl->cmd->status;
     401
     402        irq_code.rangecount = sizeof(ata_irq_ranges) / sizeof(irq_pio_range_t);
     403        irq_code.ranges = ranges;
     404        irq_code.cmdcount = sizeof(ata_irq_cmds) / sizeof(irq_cmd_t);
     405        irq_code.cmds = cmds;
     406
     407        ddf_msg(LVL_NOTE, "IRQ %d", ctrl->irq);
     408        rc = register_interrupt_handler(ctrl->dev, ctrl->irq, ata_irq_handler,
     409            &irq_code, &ctrl->ihandle);
     410        if (rc != EOK) {
     411                ddf_msg(LVL_ERROR, "Error registering IRQ.");
     412                goto error;
     413        }
     414
     415        parent_sess = ddf_dev_parent_sess_get(ctrl->dev);
     416
     417        rc = hw_res_enable_interrupt(parent_sess, ctrl->irq);
     418        if (rc != EOK) {
     419                ddf_msg(LVL_ERROR, "Error enabling IRQ.");
     420                (void) unregister_interrupt_handler(ctrl->dev,
     421                    ctrl->ihandle);
     422                goto error;
     423        }
     424
     425        free(ranges);
     426        free(cmds);
     427        return EOK;
     428error:
     429        free(ranges);
     430        free(cmds);
     431        return rc;
     432}
     433
     434/** Clean up IRQ. */
     435static void ata_bd_fini_irq(ata_ctrl_t *ctrl)
     436{
     437        errno_t rc;
     438        async_sess_t *parent_sess;
     439
     440        parent_sess = ddf_dev_parent_sess_get(ctrl->dev);
     441
     442        rc = hw_res_disable_interrupt(parent_sess, ctrl->irq);
     443        if (rc != EOK)
     444                ddf_msg(LVL_ERROR, "Error disabling IRQ.");
     445
     446        (void) unregister_interrupt_handler(ctrl->dev, ctrl->ihandle);
    340447}
    341448
     
    519626        errno_t rc;
    520627
    521         if (size < cnt * disk->block_size)
    522                 return EINVAL;
     628        if (size < cnt * disk->block_size) {
     629                rc = EINVAL;
     630                goto error;
     631        }
    523632
    524633        /* Maximum number of blocks to transfer at the same time */
     
    534643
    535644                if (rc != EOK)
    536                         return rc;
     645                        goto error;
    537646
    538647                ba += nb;
     
    542651
    543652        return EOK;
     653error:
     654        ddf_msg(LVL_DEBUG, "ata_bd_read_blocks: rc=%d", rc);
     655        return rc;
    544656}
    545657
     
    622734        size_t bidx;
    623735        uint8_t status;
     736        errno_t rc;
    624737
    625738        assert(nblocks > 0);
     
    628741        bidx = 0;
    629742        while (nblocks > 0) {
    630                 if (wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK)
     743                if (ctrl->irq >= 0)
     744                        rc = wait_irq(ctrl, &status, TIMEOUT_BSY);
     745                else
     746                        rc = wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY);
     747
     748                if (rc != EOK) {
     749                        ddf_msg(LVL_DEBUG, "wait_irq/wait_status failed");
    631750                        return EIO;
     751                }
    632752
    633753                if ((status & SR_DRQ) == 0) {
     754                        ddf_msg(LVL_DEBUG, "DRQ == 0");
    634755                        break;
    635756                }
     
    644765        }
    645766
    646         if ((status & SR_ERR) != 0)
    647                 return EIO;
    648         if (nblocks > 0)
    649                 return EIO;
     767        if ((status & SR_ERR) != 0) {
     768                ddf_msg(LVL_DEBUG, "status & SR_ERR != 0");
     769                return EIO;
     770        }
     771        if (nblocks > 0) {
     772                ddf_msg(LVL_DEBUG, "remaining nblocks = %zu", nblocks);
     773                return EIO;
     774        }
    650775
    651776        return EOK;
     
    660785        size_t bidx;
    661786        uint8_t status;
     787        errno_t rc;
    662788
    663789        assert(nblocks > 0);
    664790        assert(blk_size % 2 == 0);
    665791
     792        rc = wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY);
     793        if (rc != EOK)
     794                return EIO;
     795
    666796        bidx = 0;
    667797        while (nblocks > 0) {
    668                 if (wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK)
    669                         return EIO;
    670 
    671                 if ((status & SR_DRQ) == 0)
     798                if ((status & SR_DRQ) == 0) {
     799                        ddf_msg(LVL_DEBUG, "pio_data_out: unexpected DRQ=0");
    672800                        break;
     801                }
    673802
    674803                /* Write data to the device buffer. */
     
    678807                }
    679808
     809                if (ctrl->irq >= 0)
     810                        rc = wait_irq(ctrl, &status, TIMEOUT_BSY);
     811                else
     812                        rc = wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY);
     813                if (rc != EOK)
     814                        return EIO;
     815
    680816                --nblocks;
    681817        }
     
    694830        ata_ctrl_t *ctrl = disk->ctrl;
    695831        uint8_t status;
    696 
    697         if (wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK)
     832        errno_t rc;
     833
     834        if (ctrl->irq >= 0)
     835                rc = wait_irq(ctrl, &status, TIMEOUT_BSY);
     836        else
     837                rc = wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY);
     838
     839        if (rc != EOK)
    698840                return EIO;
    699841
     
    738880        pio_write_8(&ctrl->cmd->command, CMD_IDENTIFY_DRIVE);
    739881
    740         if (wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_PROBE) != EOK)
    741                 return ETIMEOUT;
    742 
    743         /*
    744          * If ERR is set, this may be a packet device, so return EIO to cause
    745          * the caller to check for one.
    746          */
    747         if ((status & SR_ERR) != 0)
    748                 return EIO;
    749 
    750882        /*
    751883         * For probing purposes we need to wait for some status bit to become
    752884         * active - otherwise we could be fooled just by receiving all zeroes.
    753885         */
    754         if (wait_status(ctrl, SR_DRQ, ~SR_BSY, &status, TIMEOUT_PROBE) != EOK)
    755                 return ETIMEOUT;
     886        if (wait_status(ctrl, SR_DRQ, ~SR_BSY, &status, TIMEOUT_PROBE) != EOK) {
     887                if ((status & SR_ERR) == 0) {
     888                        /* Probably no device at all */
     889                        return ETIMEOUT;
     890                }
     891        }
    756892
    757893        return ata_pio_data_in(disk, buf, identify_data_size,
     
    811947        size_t bidx;
    812948        uint16_t val;
     949        errno_t rc;
    813950
    814951        fibril_mutex_lock(&ctrl->lock);
     
    848985        remain = obuf_size;
    849986        while (remain > 0) {
    850                 if (wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
     987                if (ctrl->irq >= 0)
     988                        rc = wait_irq(ctrl, &status, TIMEOUT_BSY);
     989                else
     990                        rc = wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY);
     991
     992                if (rc != EOK) {
    851993                        fibril_mutex_unlock(&ctrl->lock);
    852994                        return EIO;
     
    8751017                remain -= data_size;
    8761018        }
     1019
     1020        if (ctrl->irq >= 0)
     1021                rc = wait_irq(ctrl, &status, TIMEOUT_BSY);
     1022        else
     1023                rc = wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY);
    8771024
    8781025        fibril_mutex_unlock(&ctrl->lock);
     
    10471194
    10481195        /* Compute block coordinates. */
    1049         if (coord_calc(disk, ba, &bc) != EOK)
     1196        if (coord_calc(disk, ba, &bc) != EOK) {
     1197                ddf_msg(LVL_NOTE, "ata_rcmd_read() -> coord_calc failed");
    10501198                return EINVAL;
     1199        }
    10511200
    10521201        /* New value for Drive/Head register */
     
    10621211        if (wait_status(ctrl, 0, ~SR_BSY, NULL, TIMEOUT_BSY) != EOK) {
    10631212                fibril_mutex_unlock(&ctrl->lock);
     1213                ddf_msg(LVL_NOTE, "ata_rcmd_read() -> wait_status failed");
    10641214                return EIO;
    10651215        }
     
    10691219        if (wait_status(ctrl, SR_DRDY, ~SR_BSY, NULL, TIMEOUT_DRDY) != EOK) {
    10701220                fibril_mutex_unlock(&ctrl->lock);
     1221                ddf_msg(LVL_NOTE, "ata_rcmd_read() -> wait_status 2 failed");
    10711222                return EIO;
    10721223        }
     
    10831234        fibril_mutex_unlock(&ctrl->lock);
    10841235
     1236        if (rc != EOK)
     1237                ddf_msg(LVL_NOTE, "ata_rcmd_read() -> pio_data_in->%d", rc);
    10851238        return rc;
    10861239}
     
    13551508}
    13561509
     1510/** Wait for IRQ and return status.
     1511 *
     1512 * @param ctrl          Controller
     1513 * @param pstatus       Pointer where to store last read status or NULL.
     1514 * @param timeout       Timeout in 10ms units.
     1515 *
     1516 * @return              EOK on success, EIO on timeout.
     1517 */
     1518static errno_t wait_irq(ata_ctrl_t *ctrl, uint8_t *pstatus, unsigned timeout)
     1519{
     1520        fibril_mutex_lock(&ctrl->irq_lock);
     1521        while (!ctrl->irq_fired)
     1522                fibril_condvar_wait(&ctrl->irq_cv, &ctrl->irq_lock);
     1523
     1524        ctrl->irq_fired = false;
     1525        *pstatus = ctrl->irq_status;
     1526        fibril_mutex_unlock(&ctrl->irq_lock);
     1527        return EOK;
     1528}
     1529
     1530/** Interrupt handler.
     1531 *
     1532 * @param call Call data
     1533 * @param dev Device that caused the interrupt
     1534 */
     1535static void ata_irq_handler(ipc_call_t *call, ddf_dev_t *dev)
     1536{
     1537        ata_ctrl_t *ctrl = (ata_ctrl_t *)ddf_dev_data_get(dev);
     1538        uint8_t status;
     1539        async_sess_t *parent_sess;
     1540
     1541        status = ipc_get_arg1(call);
     1542
     1543        fibril_mutex_lock(&ctrl->irq_lock);
     1544        ctrl->irq_fired = true;
     1545        ctrl->irq_status = status;
     1546        fibril_mutex_unlock(&ctrl->irq_lock);
     1547        fibril_condvar_broadcast(&ctrl->irq_cv);
     1548
     1549        parent_sess = ddf_dev_parent_sess_get(dev);
     1550        hw_res_clear_interrupt(parent_sess, ctrl->irq);
     1551}
     1552
    13571553/**
    13581554 * @}
  • uspace/drv/block/ata_bd/ata_bd.h

    r21989e5 r64cf7a3  
    11/*
    2  * Copyright (c) 2009 Jiri Svoboda
     2 * Copyright (c) 2024 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    4040#include <ddf/driver.h>
    4141#include <fibril_synch.h>
     42#include <stdbool.h>
    4243#include <str.h>
    4344#include <stdint.h>
     
    4748#define NAME "ata_bd"
    4849
    49 /** Base addresses for ATA I/O blocks. */
     50/** ATA hardware resources */
    5051typedef struct {
    5152        uintptr_t cmd;  /**< Command block base address. */
    5253        uintptr_t ctl;  /**< Control block base address. */
    53 } ata_base_t;
     54        int irq;        /**< IRQ */
     55} ata_hwres_t;
    5456
    5557/** Timeout definitions. Unit is 10 ms. */
     
    140142        /** Control registers */
    141143        ata_ctl_t *ctl;
     144        /** IRQ (-1 if not used) */
     145        int irq;
     146        /** IRQ handle */
     147        cap_irq_handle_t ihandle;
    142148
    143149        /** Per-disk state. */
    144150        disk_t disk[MAX_DISKS];
    145151
     152        /** Synchronize controller access */
    146153        fibril_mutex_t lock;
     154        /** Synchronize access to irq_fired/irq_status */
     155        fibril_mutex_t irq_lock;
     156        /** Signalled by IRQ handler */
     157        fibril_condvar_t irq_cv;
     158        /** Set to true when interrupt occurs */
     159        bool irq_fired;
     160        /** Value of status register read by interrupt handler */
     161        uint8_t irq_status;
    147162} ata_ctrl_t;
    148163
     
    153168} ata_fun_t;
    154169
    155 extern errno_t ata_ctrl_init(ata_ctrl_t *, ata_base_t *);
     170extern errno_t ata_ctrl_init(ata_ctrl_t *, ata_hwres_t *);
    156171extern errno_t ata_ctrl_remove(ata_ctrl_t *);
    157172extern errno_t ata_ctrl_gone(ata_ctrl_t *);
  • uspace/drv/block/ata_bd/main.c

    r21989e5 r64cf7a3  
    11/*
    2  * Copyright (c) 2013 Jiri Svoboda
     2 * Copyright (c) 2024 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    6666};
    6767
    68 static errno_t ata_get_res(ddf_dev_t *dev, ata_base_t *ata_res)
     68static errno_t ata_get_res(ddf_dev_t *dev, ata_hwres_t *ata_res)
    6969{
    7070        async_sess_t *parent_sess;
     
    8686        }
    8787
     88        /* I/O ranges */
     89
    8890        addr_range_t *cmd_rng = &hw_res.io_ranges.ranges[0];
    8991        addr_range_t *ctl_rng = &hw_res.io_ranges.ranges[1];
     
    101103        }
    102104
     105        /* IRQ */
     106        if (hw_res.irqs.count > 0) {
     107                ata_res->irq = hw_res.irqs.irqs[0];
     108        } else {
     109                ata_res->irq = -1;
     110        }
     111
    103112        return EOK;
    104113error:
     
    115124{
    116125        ata_ctrl_t *ctrl;
    117         ata_base_t res;
     126        ata_hwres_t res;
    118127        errno_t rc;
    119128
  • uspace/drv/bus/isa/isa.dev

    r21989e5 r64cf7a3  
    5555        io_range 0x1f0 8
    5656        io_range 0x3f0 8
     57        irq 14
    5758
    5859ata-c2:
     
    6061        io_range 0x170 8
    6162        io_range 0x370 8
    62 
    63 ata-c3:
    64         match 100 isa/ata_bd
    65         io_range 0x1e8 8
    66         io_range 0x3e8 8
    67 
    68 ata-c4:
    69         match 100 isa/ata_bd
    70         io_range 0x168 8
    71         io_range 0x368 8
     63        irq 15
Note: See TracChangeset for help on using the changeset viewer.