Changeset 645d3832 in mainline for uspace/drv/block/pci-ide/pci-ide.c


Ignore:
Timestamp:
2024-06-10T17:29:13Z (4 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)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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 *
Note: See TracChangeset for help on using the changeset viewer.