static void ata_dbdma_setprd(void *xarg, bus_dma_segment_t *segs, int nsegs, int error) { struct ata_dbdma_dmaload_args *arg = xarg; struct ata_dbdma_channel *sc = arg->sc; int branch_type, command; int prev_stop; int i; mtx_lock(&sc->dbdma_mtx); prev_stop = sc->next_dma_slot-1; if (prev_stop < 0) prev_stop = 0xff; for (i = 0; i < nsegs; i++) { /* Loop back to the beginning if this is our last slot */ if (sc->next_dma_slot == 0xff) branch_type = DBDMA_ALWAYS; else branch_type = DBDMA_NEVER; if (arg->write) { command = (i + 1 < nsegs) ? DBDMA_OUTPUT_MORE : DBDMA_OUTPUT_LAST; } else { command = (i + 1 < nsegs) ? DBDMA_INPUT_MORE : DBDMA_INPUT_LAST; } dbdma_insert_command(sc->dbdma, sc->next_dma_slot++, command, 0, segs[i].ds_addr, segs[i].ds_len, DBDMA_NEVER, branch_type, DBDMA_NEVER, 0); if (branch_type == DBDMA_ALWAYS) sc->next_dma_slot = 0; } /* We have a corner case where the STOP command is the last slot, * but you can't branch in STOP commands. So add a NOP branch here * and the STOP in slot 0. */ if (sc->next_dma_slot == 0xff) { dbdma_insert_branch(sc->dbdma, sc->next_dma_slot, 0); sc->next_dma_slot = 0; } #if 0 dbdma_insert_command(sc->dbdma, sc->next_dma_slot++, DBDMA_NOP, 0, 0, 0, DBDMA_ALWAYS, DBDMA_NEVER, DBDMA_NEVER, 0); #endif dbdma_insert_stop(sc->dbdma, sc->next_dma_slot++); dbdma_insert_nop(sc->dbdma, prev_stop); dbdma_sync_commands(sc->dbdma, BUS_DMASYNC_PREWRITE); mtx_unlock(&sc->dbdma_mtx); arg->nsegs = nsegs; }
void dbdma_insert_branch(dbdma_channel_t *chan, int slot, int to_slot) { dbdma_insert_command(chan, slot, DBDMA_NOP, 0, 0, 0, DBDMA_NEVER, DBDMA_ALWAYS, DBDMA_NEVER, to_slot); }
void dbdma_insert_nop(dbdma_channel_t *chan, int slot) { dbdma_insert_command(chan, slot, DBDMA_NOP, 0, 0, 0, DBDMA_NEVER, DBDMA_NEVER, DBDMA_NEVER, 0); }