Changeset 0eacc32 in mainline


Ignore:
Timestamp:
2015-04-10T07:06:21Z (10 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
13888eb0
Parents:
07c913b
Message:

Register and handle ddisk interrupt.
Implement ddisk_bd_read/write_blocks().

File:
1 edited

Legend:

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

    r07c913b r0eacc32  
    3737#include <str_error.h>
    3838#include <ddf/driver.h>
     39#include <ddf/interrupt.h>
    3940#include <ddf/log.h>
    4041#include <device/hw_res_parsed.h>
     
    5051#define DDISK_BLOCK_SIZE        512
    5152
    52 static int ddisk_dev_add(ddf_dev_t *dev);
    53 static int ddisk_dev_remove(ddf_dev_t *dev);
    54 static int ddisk_dev_gone(ddf_dev_t *dev);
    55 static int ddisk_fun_online(ddf_fun_t *fun);
    56 static int ddisk_fun_offline(ddf_fun_t *fun);
     53#define DDISK_STAT_IRQ_PENDING  0x4
     54#define DDISK_CMD_READ          0x1
     55#define DDISK_CMD_WRITE         0x2
     56#define DDISK_CMD_IRQ_DEASSERT  0x4
     57
     58static int ddisk_dev_add(ddf_dev_t *);
     59static int ddisk_dev_remove(ddf_dev_t *);
     60static int ddisk_dev_gone(ddf_dev_t *);
     61static int ddisk_fun_online(ddf_fun_t *);
     62static int ddisk_fun_offline(ddf_fun_t *);
    5763
    5864static void ddisk_bd_connection(ipc_callid_t, ipc_call_t *, void *);
     65
     66static void ddisk_irq_handler(ipc_callid_t, ipc_call_t *, ddf_dev_t *);
    5967
    6068static driver_ops_t driver_ops = {
     
    99107typedef struct ddisk_dev {
    100108        fibril_mutex_t lock;
     109        fibril_condvar_t io_cv;
     110        bool io_busy;
    101111        ddf_dev_t *dev;
    102112        ddisk_res_t ddisk_res;
     
    109119static int ddisk_bd_open(bd_srvs_t *, bd_srv_t *);
    110120static int ddisk_bd_close(bd_srv_t *);
    111 static int ddisk_bd_read_blocks(bd_srv_t *, uint64_t, size_t, void *, size_t);
    112 static int ddisk_bd_write_blocks(bd_srv_t *, uint64_t, size_t, const void *,
     121static int ddisk_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, size_t);
     122static int ddisk_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, const void *,
    113123    size_t);
    114124static int ddisk_bd_get_block_size(bd_srv_t *, size_t *);
     
    124134};
    125135
     136irq_pio_range_t ddisk_irq_pio_ranges[] = {
     137        {
     138                .base = 0,
     139                .size = sizeof(ddisk_regs_t)
     140        }
     141};
     142
     143irq_cmd_t ddisk_irq_commands[] = {
     144        {
     145                .cmd = CMD_PIO_READ_32,
     146                .addr = NULL,
     147                .dstarg = 1
     148        },
     149        {
     150                .cmd = CMD_AND,
     151                .srcarg = 1,
     152                .value = DDISK_STAT_IRQ_PENDING,
     153                .dstarg = 2
     154        },
     155        {
     156                .cmd = CMD_PREDICATE,
     157                .srcarg = 2,
     158                .value = 2
     159        },
     160        {
     161                /* Deassert the DMA interrupt. */
     162                .cmd = CMD_PIO_WRITE_32,
     163                .value = DDISK_CMD_IRQ_DEASSERT,
     164                .addr = NULL
     165        },
     166        {
     167                .cmd = CMD_ACCEPT
     168        }
     169};
     170
     171irq_code_t ddisk_irq_code = {
     172        .rangecount = 1,
     173        .ranges = ddisk_irq_pio_ranges,
     174        .cmdcount = sizeof(ddisk_irq_commands) / sizeof(irq_cmd_t),
     175        .cmds = ddisk_irq_commands,
     176};
     177
     178void ddisk_irq_handler(ipc_callid_t iid, ipc_call_t *icall, ddf_dev_t *dev)
     179{
     180        ddf_msg(LVL_NOTE, "ddisk_irq_handler(), status=%" PRIx32,
     181            (uint32_t) IPC_GET_ARG1(*icall));
     182
     183        ddisk_dev_t *ddisk_dev = (ddisk_dev_t *) ddf_dev_data_get(dev);
     184       
     185        fibril_mutex_lock(&ddisk_dev->lock);
     186        fibril_condvar_broadcast(&ddisk_dev->io_cv);
     187        fibril_mutex_unlock(&ddisk_dev->lock);
     188}
     189
    126190int ddisk_bd_open(bd_srvs_t *bds, bd_srv_t *bd)
    127191{
     
    134198}
    135199
    136 int
    137 ddisk_bd_read_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt, void *buf,
    138     size_t size)
    139 {
     200static
     201int ddisk_rw_block(ddisk_dev_t *ddisk_dev, bool read, aoff64_t ba, void *buf)
     202{
     203        fibril_mutex_lock(&ddisk_dev->lock);
     204
     205        ddf_msg(LVL_NOTE, "ddisk_rw_block(): read=%d, ba=%" PRId64 ", buf=%p",
     206            read, ba, buf);
     207
     208        if (ba >= ddisk_dev->ddisk_fun->blocks)
     209                return ELIMIT;
     210
     211        while (ddisk_dev->io_busy)
     212                fibril_condvar_wait(&ddisk_dev->io_cv, &ddisk_dev->lock);
     213
     214        ddisk_dev->io_busy = true;
     215
     216        if (!read)
     217                memcpy(ddisk_dev->dma_buffer, buf, DDISK_BLOCK_SIZE);
     218       
     219        pio_write_32(&ddisk_dev->ddisk_regs->dma_buffer,
     220            ddisk_dev->dma_buffer_phys);
     221        pio_write_32(&ddisk_dev->ddisk_regs->block, (uint32_t) ba);
     222        pio_write_32(&ddisk_dev->ddisk_regs->command,
     223            read ? DDISK_CMD_READ : DDISK_CMD_WRITE);
     224
     225        fibril_condvar_wait(&ddisk_dev->io_cv, &ddisk_dev->lock);
     226
     227        if (read)
     228                memcpy(buf, ddisk_dev->dma_buffer, DDISK_BLOCK_SIZE);
     229
     230        ddisk_dev->io_busy = false;
     231        fibril_condvar_signal(&ddisk_dev->io_cv);
     232        fibril_mutex_unlock(&ddisk_dev->lock);
     233
     234        return EOK;
     235}
     236
     237static
     238int ddisk_bd_rw_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, void *buf,
     239    size_t size, bool is_read)
     240{
     241        ddisk_fun_t *ddisk_fun = (ddisk_fun_t *) bd->srvs->sarg;
     242        aoff64_t i;
     243        int rc;
     244
    140245        if (size < cnt * DDISK_BLOCK_SIZE)
    141246                return EINVAL;         
    142247
    143         return ENOTSUP;
    144 }
    145 
    146 int ddisk_bd_write_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt,
     248        for (i = 0; i < cnt; i++) {
     249                rc = ddisk_rw_block(ddisk_fun->ddisk_dev, is_read, ba + i,
     250                    buf + i * DDISK_BLOCK_SIZE);
     251                if (rc != EOK)
     252                        return rc;
     253        }
     254
     255        return EOK;
     256}
     257
     258int ddisk_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt, void *buf,
     259    size_t size)
     260{
     261        return ddisk_bd_rw_blocks(bd, ba, cnt, buf, size, true);
     262}
     263
     264int ddisk_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt,
    147265    const void *buf, size_t size)
    148266{
    149         if (size < cnt * DDISK_BLOCK_SIZE)
    150                 return EINVAL;         
    151 
    152         return ENOTSUP;
     267        return ddisk_bd_rw_blocks(bd, ba, cnt, (void *) buf, size, false);
    153268}
    154269
     
    332447
    333448        fibril_mutex_initialize(&ddisk_dev->lock);
     449        fibril_condvar_initialize(&ddisk_dev->io_cv);
     450        ddisk_dev->io_busy = false;
    334451        ddisk_dev->dev = dev;
    335452        ddisk_dev->ddisk_res = res;
     
    374491        }
    375492
    376         ddf_msg(LVL_NOTE, "Device at %p with %d blocks (%dB) using interrupt %d",
     493        /*
     494         * Register IRQ handler.
     495         */
     496        ddisk_regs_t *res_phys = (ddisk_regs_t *) res.base;
     497        ddisk_irq_pio_ranges[0].base = res.base;
     498        ddisk_irq_commands[0].addr = (void *) &res_phys->status;
     499        ddisk_irq_commands[3].addr = (void *) &res_phys->command;
     500        rc = register_interrupt_handler(dev, ddisk_dev->ddisk_res.irq,
     501            ddisk_irq_handler, &ddisk_irq_code);
     502        if (rc != EOK) {
     503                ddf_msg(LVL_ERROR, "Failed to register interrupt handler.");
     504                goto error;
     505        }
     506
     507        /*
     508         * Success, report what we have found.
     509         */
     510        ddf_msg(LVL_NOTE,
     511            "Device at %p with %zu blocks (%zuB) using interrupt %d",
    377512            (void *) ddisk_dev->ddisk_res.base, ddisk_dev->ddisk_fun->blocks,
    378             ddisk_dev->ddisk_fun->blocks * DDISK_BLOCK_SIZE, ddisk_dev->ddisk_res.irq);
     513            ddisk_dev->ddisk_fun->blocks * DDISK_BLOCK_SIZE,
     514            ddisk_dev->ddisk_res.irq);
    379515
    380516        return EOK;
Note: See TracChangeset for help on using the changeset viewer.