Changeset 645d3832 in mainline


Ignore:
Timestamp:
2024-06-10T17:29:13Z (6 weeks ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
master
Children:
a38d504
Parents:
69c376b5
git-author:
Jiri Svoboda <jiri@…> (2024-06-10 17:24:58)
git-committer:
Jiri Svoboda <jiri@…> (2024-06-10 17:29:13)
Message:

Add DMA support to PCI-IDE / libata (register commands)

Location:
uspace
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/block/pci-ide/main.c

    r69c376b5 r645d3832  
    150150        ctrl->dev = dev;
    151151
     152        rc = pci_ide_ctrl_init(ctrl, &res);
     153        if (rc != EOK)
     154                goto error;
     155
    152156        rc = pci_ide_channel_init(ctrl, &ctrl->channel[0], 0, &res);
    153157        if (rc == ENOENT)
     
    333337        ddf_msg(LVL_DEBUG, "pci_ide_dev_gone(%p)", dev);
    334338
     339        rc = pci_ide_ctrl_fini(ctrl);
     340        if (rc != EOK)
     341                return rc;
     342
    335343        rc = pci_ide_channel_fini(&ctrl->channel[0]);
    336344        if (rc != EOK)
  • uspace/drv/block/pci-ide/pci-ide.c

    r69c376b5 r645d3832  
    3636 */
    3737
     38#include <assert.h>
    3839#include <ddi.h>
    3940#include <ddf/interrupt.h>
     
    6768static errno_t pci_ide_irq_enable(void *);
    6869static errno_t pci_ide_irq_disable(void *);
     70static void pci_ide_dma_chan_setup(void *, void *, size_t, ata_dma_dir_t);
     71static void pci_ide_dma_chan_teardown(void *);
    6972static errno_t pci_ide_add_device(void *, unsigned, void *);
    7073static errno_t pci_ide_remove_device(void *, unsigned);
     
    9396};
    9497
     98/** Initialize PCI IDE controller.
     99 *
     100 * @param ctrl PCI IDE controller
     101 * @param res Hardware resources
     102 *
     103 * @return EOK on success or an error code
     104 */
     105errno_t pci_ide_ctrl_init(pci_ide_ctrl_t *ctrl, pci_ide_hwres_t *res)
     106{
     107        errno_t rc;
     108        void *vaddr;
     109
     110        ddf_msg(LVL_DEBUG, "pci_ide_ctrl_init()");
     111        ctrl->bmregs_physical = res->bmregs;
     112
     113        ddf_msg(LVL_NOTE, "Bus master IDE regs I/O address: 0x%lx",
     114            ctrl->bmregs_physical);
     115
     116        rc = pio_enable((void *)ctrl->bmregs_physical, sizeof(pci_ide_regs_t),
     117            &vaddr);
     118        if (rc != EOK) {
     119                ddf_msg(LVL_ERROR, "Cannot initialize device I/O space.");
     120                return rc;
     121        }
     122
     123        ctrl->bmregs = vaddr;
     124
     125        ddf_msg(LVL_DEBUG, "pci_ide_ctrl_init: DONE");
     126        return EOK;
     127}
     128
     129/** Finalize PCI IDE controller.
     130 *
     131 * @param ctrl PCI IDE controller
     132 * @return EOK on success or an error code
     133 */
     134errno_t pci_ide_ctrl_fini(pci_ide_ctrl_t *ctrl)
     135{
     136        ddf_msg(LVL_DEBUG, ": pci_ide_ctrl_fini()");
     137
     138        // XXX TODO
     139        return EOK;
     140}
     141
    95142/** Initialize PCI IDE channel. */
    96143errno_t pci_ide_channel_init(pci_ide_ctrl_t *ctrl, pci_ide_channel_t *chan,
     
    100147        bool irq_inited = false;
    101148        ata_params_t params;
    102 
    103         ddf_msg(LVL_DEBUG, "pci_ide_ctrl_init()");
     149        void *buffer;
     150
     151        ddf_msg(LVL_DEBUG, "pci_ide_channel_init()");
    104152
    105153        chan->ctrl = ctrl;
     
    116164        }
    117165
     166        chan->dma_buf_size = 8192;
     167
    118168        ddf_msg(LVL_NOTE, "I/O address %p/%p", (void *) chan->cmd_physical,
    119169            (void *) chan->ctl_physical);
     
    128178        if (rc != EOK) {
    129179                ddf_msg(LVL_NOTE, "init IRQ failed");
    130                 return rc;
     180                goto error;
    131181        }
    132182
    133183        irq_inited = true;
    134184
    135         ddf_msg(LVL_DEBUG, "pci_ide_ctrl_init(): Initialize IDE channel");
     185        ddf_msg(LVL_DEBUG, "Allocate PRD table");
     186
     187        buffer = AS_AREA_ANY;
     188        rc = dmamem_map_anonymous(sizeof (pci_ide_prd_t), DMAMEM_4GiB | 0xffff,
     189            AS_AREA_WRITE | AS_AREA_READ, 0, &chan->prdt_pa, &buffer);
     190        if (rc != EOK) {
     191                ddf_msg(LVL_NOTE, "Failed allocating PRD table.");
     192                goto error;
     193        }
     194
     195        chan->prdt = (pci_ide_prd_t *)buffer;
     196
     197        ddf_msg(LVL_DEBUG, "Allocate DMA buffer");
     198
     199        buffer = AS_AREA_ANY;
     200        rc = dmamem_map_anonymous(chan->dma_buf_size, DMAMEM_4GiB | 0xffff,
     201            AS_AREA_WRITE | AS_AREA_READ, 0, &chan->dma_buf_pa, &buffer);
     202        if (rc != EOK) {
     203                ddf_msg(LVL_NOTE, "Failed allocating PRD table.");
     204                goto error;
     205        }
     206
     207        chan->dma_buf = buffer;
     208
     209        /* Populate PRD with information on our single DMA buffer */
     210        chan->prdt->pba = host2uint32_t_le(chan->dma_buf_pa);
     211        chan->prdt->bcnt = host2uint16_t_le(chan->dma_buf_size);
     212        chan->prdt->eot_res = host2uint16_t_le(pci_ide_prd_eot);
     213
     214        /* Program PRD table pointer register */
     215        if (chan_id == 0) {
     216                pio_write_32(&chan->ctrl->bmregs->bmidtpp,
     217                    (uint32_t)chan->prdt_pa);
     218        } else {
     219                pio_write_32(&chan->ctrl->bmregs->bmidtps,
     220                    (uint32_t)chan->prdt_pa);
     221        }
     222
     223        ddf_msg(LVL_DEBUG, "pci_ide_channel_init(): Initialize IDE channel");
    136224
    137225        params.arg = (void *)chan;
    138226        params.have_irq = (chan->irq >= 0) ? true : false;
     227        params.use_dma = true;
    139228        params.write_data_16 = pci_ide_write_data_16;
    140229        params.read_data_16 = pci_ide_read_data_16;
     
    145234        params.irq_enable = pci_ide_irq_enable;
    146235        params.irq_disable = pci_ide_irq_disable;
     236        params.dma_chan_setup = pci_ide_dma_chan_setup;
     237        params.dma_chan_teardown = pci_ide_dma_chan_teardown;
    147238        params.add_device = pci_ide_add_device;
    148239        params.remove_device = pci_ide_remove_device;
     
    160251                goto error;
    161252
    162         ddf_msg(LVL_DEBUG, "pci_ide_ctrl_init: DONE");
     253        ddf_msg(LVL_DEBUG, "pci_ide_channel_init: DONE");
    163254        return EOK;
    164255error:
     
    174265        errno_t rc;
    175266
    176         ddf_msg(LVL_DEBUG, ": pci_ide_ctrl_remove()");
     267        ddf_msg(LVL_DEBUG, ": pci_ide_channel_fini()");
    177268
    178269        fibril_mutex_lock(&chan->lock);
     
    212303
    213304        chan->ctl = vaddr;
     305
     306        rc = pio_enable((void *) chan->cmd_physical, sizeof(ata_cmd_t), &vaddr);
     307        if (rc != EOK) {
     308                ddf_msg(LVL_ERROR, "Cannot initialize device I/O space.");
     309                return rc;
     310        }
     311
     312        chan->cmd = vaddr;
     313
    214314        return EOK;
    215315}
     
    435535}
    436536
     537/** Set up DMA channel callback handler
     538 *
     539 * @param arg Argument (pci_ide_channel_t *)
     540 * @param buf Buffer
     541 * @param buf_size Buffer size
     542 * @param dir DMA transfer direction
     543 */
     544static void pci_ide_dma_chan_setup(void *arg, void *buf, size_t buf_size,
     545    ata_dma_dir_t dir)
     546{
     547        pci_ide_channel_t *chan = (pci_ide_channel_t *)arg;
     548        uint8_t *bmicx;
     549        uint8_t val;
     550
     551        /* Needed later in teardown */
     552        chan->cur_dir = dir;
     553        chan->cur_buf = buf;
     554        chan->cur_buf_size = buf_size;
     555
     556        if (dir == ata_dma_write) {
     557                assert(buf_size < chan->dma_buf_size);
     558                memcpy(chan->dma_buf, buf, buf_size);
     559        }
     560
     561        /* Primary or secondary channel control register */
     562        bmicx = (chan->chan_id == 0) ? &chan->ctrl->bmregs->bmicp :
     563            &chan->ctrl->bmregs->bmics;
     564
     565        /* Set read / write */
     566        val = (dir == ata_dma_write) ? bmicx_rwcon : 0;
     567        pio_write_8(bmicx, val);
     568
     569        /* Start bus master DMA engine */
     570        val = val | bmicx_ssbm;
     571        pio_write_8(bmicx, val);
     572}
     573
     574/** Tear down DMA channel callback handler
     575 *
     576 * @param arg Argument (pci_ide_channel_t *)
     577 */
     578static void pci_ide_dma_chan_teardown(void *arg)
     579{
     580        pci_ide_channel_t *chan = (pci_ide_channel_t *)arg;
     581        uint8_t *bmicx;
     582        uint8_t val;
     583
     584        /* Primary or secondary channel control register */
     585        bmicx = (chan->chan_id == 0) ? &chan->ctrl->bmregs->bmicp :
     586            &chan->ctrl->bmregs->bmics;
     587
     588        /* Stop bus master DMA engine clear SSBM but keep RWCON the same */
     589        val = (chan->cur_dir == ata_dma_write) ? bmicx_rwcon : 0;
     590        pio_write_8(bmicx, val);
     591
     592        if (chan->cur_dir == ata_dma_read) {
     593                assert(chan->cur_buf_size < chan->dma_buf_size);
     594                memcpy(chan->cur_buf, chan->dma_buf, chan->cur_buf_size);
     595        }
     596}
     597
    437598/** Add ATA device callback handler.
    438599 *
  • uspace/drv/block/pci-ide/pci-ide.h

    r69c376b5 r645d3832  
    4242#include <stdbool.h>
    4343#include <stdint.h>
     44#include "pci-ide_hw.h"
    4445
    4546#define NAME "pci-ide"
     
    7980        uint8_t irq_status;
    8081
     82        /** Physical region descriptor table */
     83        pci_ide_prd_t *prdt;
     84        /** Physical region descriptor table physical address */
     85        uintptr_t prdt_pa;
     86        /** DMA buffer */
     87        void *dma_buf;
     88        /** DMA buffer physical address */
     89        uintptr_t dma_buf_pa;
     90        /** DMA buffer size */
     91        size_t dma_buf_size;
     92        /** Current DMA transfer direction */
     93        ata_dma_dir_t cur_dir;
     94        /** Current data buffer */
     95        void *cur_buf;
     96        /** Current data buffer size */
     97        size_t cur_buf_size;
     98
    8199        /** Libata ATA channel */
    82100        ata_channel_t *channel;
     
    92110        ddf_dev_t *dev;
    93111
     112        /** I/O base address of bus master IDE registers */
     113        uintptr_t bmregs_physical;
     114        /** Bus master IDE registers */
     115        pci_ide_regs_t *bmregs;
    94116        /** Primary and secondary channel */
    95117        pci_ide_channel_t channel[2];
     
    102124} pci_ide_fun_t;
    103125
     126extern errno_t pci_ide_ctrl_init(pci_ide_ctrl_t *, pci_ide_hwres_t *);
     127extern errno_t pci_ide_ctrl_fini(pci_ide_ctrl_t *);
    104128extern errno_t pci_ide_channel_init(pci_ide_ctrl_t *, pci_ide_channel_t *,
    105129    unsigned, pci_ide_hwres_t *);
  • uspace/drv/block/pci-ide/pci-ide_hw.h

    r69c376b5 r645d3832  
    9898};
    9999
     100enum {
     101        pci_ide_prd_eot = 0x8000
     102};
     103
     104/** PIIX physical region descriptor */
     105typedef struct {
     106        /** Physical base address */
     107        uint32_t pba;
     108        /** Byte count */
     109        uint16_t bcnt;
     110        /** EOT / reserved */
     111        uint16_t eot_res;
     112} pci_ide_prd_t;
     113
    100114#endif
    101115
  • uspace/lib/ata/include/ata/ata.h

    r69c376b5 r645d3832  
    4747struct ata_device;
    4848
     49/** ATA DMA direction */
     50typedef enum {
     51        /** DMA read */
     52        ata_dma_read,
     53        /** DMA write */
     54        ata_dma_write
     55} ata_dma_dir_t;
     56
    4957/** ATA channel creation parameters */
    5058typedef struct {
     
    5361        /** IRQ is available */
    5462        bool have_irq;
     63        /** Use DMA transfers */
     64        bool use_dma;
    5565        /** Read 16 bits from the data port */
    5666        void (*write_data_16)(void *, uint16_t *, size_t);
     
    6979        /** Disable interrupts */
    7080        errno_t (*irq_disable)(void *);
     81        /** Set up DMA channel */
     82        void (*dma_chan_setup)(void *, void *, size_t, ata_dma_dir_t);
     83        /** Set up DMA channel */
     84        void (*dma_chan_teardown)(void *);
    7185        /** Add new device */
    7286        errno_t (*add_device)(void *, unsigned, void *);
  • uspace/lib/ata/include/ata/ata_hw.h

    r69c376b5 r645d3832  
    141141        CMD_READ_SECTORS        = 0x20,
    142142        CMD_READ_SECTORS_EXT    = 0x24,
     143        CMD_READ_DMA_EXT        = 0x25,
    143144        CMD_WRITE_SECTORS       = 0x30,
    144145        CMD_WRITE_SECTORS_EXT   = 0x34,
     146        CMD_WRITE_DMA_EXT       = 0x35,
    145147        CMD_PACKET              = 0xA0,
    146148        CMD_IDENTIFY_PKT_DEV    = 0xA1,
     149        CMD_READ_DMA            = 0xC8,
     150        CMD_WRITE_DMA           = 0xCA,
    147151        CMD_IDENTIFY_DRIVE      = 0xEC,
    148152        CMD_FLUSH_CACHE         = 0xE7
  • uspace/lib/ata/src/ata.c

    r69c376b5 r645d3832  
    118118    unsigned);
    119119static errno_t wait_irq(ata_channel_t *, uint8_t *, unsigned);
     120static void ata_dma_chan_setup(ata_device_t *, void *, size_t, ata_dma_dir_t);
     121static void ata_dma_chan_teardown(ata_device_t *);
    120122
    121123static bd_ops_t ata_bd_ops = {
     
    849851}
    850852
     853/** DMA command protocol.
     854 *
     855 * @param device ATA device
     856 * @param cmd Command code
     857 * @param buf Data buffer
     858 * @param buf_size Data buffer size in bytes
     859 * @param dir DMA direction
     860 *
     861 * @return EOK on success or an error code
     862 */
     863static errno_t ata_dma_proto(ata_device_t *device, uint8_t cmd, void *buf,
     864    size_t buf_size, ata_dma_dir_t dir)
     865{
     866        ata_channel_t *chan = device->chan;
     867        uint8_t status;
     868        errno_t rc;
     869
     870        /* Set up DMA channel */
     871        ata_dma_chan_setup(device, buf, buf_size, dir);
     872
     873        ata_write_cmd_8(chan, REG_COMMAND, cmd);
     874
     875        if (chan->params.have_irq)
     876                rc = wait_irq(chan, &status, TIMEOUT_BSY);
     877        else
     878                rc = wait_status(chan, 0, ~SR_BSY, &status, TIMEOUT_BSY);
     879
     880        if (rc != EOK) {
     881                ata_msg_debug(chan, "wait_irq/wait_status failed");
     882                return EIO;
     883        }
     884
     885        /* Tear down DMA channel */
     886        ata_dma_chan_teardown(device);
     887
     888        if ((status & SR_ERR) != 0) {
     889                ata_msg_debug(chan, "status & SR_ERR != 0");
     890                return EIO;
     891        }
     892
     893        return EOK;
     894}
     895
    851896/** Issue IDENTIFY DEVICE command.
    852897 *
     
    11841229        uint8_t drv_head;
    11851230        block_coord_t bc;
     1231        uint8_t cmd;
    11861232        errno_t rc;
    11871233
     
    12221268        coord_sc_program(chan, &bc, blk_cnt);
    12231269
    1224         ata_write_cmd_8(chan, REG_COMMAND, device->amode == am_lba48 ?
    1225             CMD_READ_SECTORS_EXT : CMD_READ_SECTORS);
    1226 
    1227         rc = ata_pio_data_in(device, buf, blk_cnt * device->block_size,
    1228             device->block_size, blk_cnt);
     1270        if (chan->params.use_dma) {
     1271                cmd = (device->amode == am_lba48) ? CMD_READ_DMA_EXT :
     1272                    CMD_READ_DMA;
     1273
     1274                rc = ata_dma_proto(device, cmd, buf,
     1275                    blk_cnt * device->block_size, ata_dma_read);
     1276                if (rc != EOK) {
     1277                        ata_msg_note(chan, "ata_rcmd_read() -> dma_proto->%d",
     1278                            rc);
     1279                }
     1280        } else {
     1281                ata_write_cmd_8(chan, REG_COMMAND, device->amode == am_lba48 ?
     1282                    CMD_READ_SECTORS_EXT : CMD_READ_SECTORS);
     1283
     1284                rc = ata_pio_data_in(device, buf, blk_cnt * device->block_size,
     1285                    device->block_size, blk_cnt);
     1286                if (rc != EOK) {
     1287                        ata_msg_note(chan, "ata_rcmd_read() -> pio_data_in->%d",
     1288                            rc);
     1289                }
     1290        }
    12291291
    12301292        fibril_mutex_unlock(&chan->lock);
    12311293
    1232         if (rc != EOK)
    1233                 ata_msg_note(chan, "ata_rcmd_read() -> pio_data_in->%d", rc);
    12341294        return rc;
    12351295}
     
    12501310        uint8_t drv_head;
    12511311        block_coord_t bc;
     1312        uint8_t cmd;
    12521313        errno_t rc;
    12531314
     
    12841345        coord_sc_program(chan, &bc, cnt);
    12851346
    1286         ata_write_cmd_8(chan, REG_COMMAND, device->amode == am_lba48 ?
    1287             CMD_WRITE_SECTORS_EXT : CMD_WRITE_SECTORS);
    1288 
    1289         rc = ata_pio_data_out(device, buf, cnt * device->block_size,
    1290             device->block_size, cnt);
     1347        if (chan->params.use_dma) {
     1348                cmd = (device->amode == am_lba48) ? CMD_WRITE_DMA_EXT :
     1349                    CMD_WRITE_DMA;
     1350
     1351                rc = ata_dma_proto(device, cmd, (void *)buf,
     1352                    cnt * device->block_size, ata_dma_write);
     1353                if (rc != EOK) {
     1354                        ata_msg_note(chan, "ata_rcmd_write() -> dma_proto->%d",
     1355                            rc);
     1356                }
     1357        } else {
     1358                ata_write_cmd_8(chan, REG_COMMAND, device->amode == am_lba48 ?
     1359                    CMD_WRITE_SECTORS_EXT : CMD_WRITE_SECTORS);
     1360
     1361                rc = ata_pio_data_out(device, buf, cnt * device->block_size,
     1362                    device->block_size, cnt);
     1363                if (rc != EOK) {
     1364                        ata_msg_note(chan,
     1365                            "ata_rcmd_read() -> pio_data_out->%d", rc);
     1366                }
     1367        }
    12911368
    12921369        fibril_mutex_unlock(&chan->lock);
     
    15221599}
    15231600
     1601/** Set up DMA channel.
     1602 *
     1603 * @param device ATA device
     1604 * @param buf Data buffer
     1605 * @param buf_size Data buffer size in bytes
     1606 * @param dir DMA direction
     1607 */
     1608static void ata_dma_chan_setup(ata_device_t *device, void *buf,
     1609    size_t buf_size, ata_dma_dir_t dir)
     1610{
     1611        device->chan->params.dma_chan_setup(device->chan->params.arg,
     1612            buf, buf_size, dir);
     1613}
     1614
     1615/** Tear down DMA channel.
     1616 *
     1617 * @param device ATA device
     1618 */
     1619static void ata_dma_chan_teardown(ata_device_t *device)
     1620{
     1621        device->chan->params.dma_chan_teardown(device->chan->params.arg);
     1622}
     1623
    15241624/** Interrupt handler.
    15251625 *
Note: See TracChangeset for help on using the changeset viewer.