static int hcsc_pdma_in(struct ncr5380_softc *ncr_sc, int phase, int datalen, uint8_t *data) { struct hcsc_softc *sc = (struct hcsc_softc *)ncr_sc; bus_space_tag_t pdmat = sc->sc_pdmat; bus_space_handle_t pdmah = sc->sc_pdmah; int s, resid, len; s = splbio(); NCR5380_WRITE(ncr_sc, sci_mode, NCR5380_READ(ncr_sc, sci_mode) | SCI_MODE_DMA); NCR5380_WRITE(ncr_sc, sci_irecv, 0); resid = datalen; while (resid > 0) { len = min(resid, HCSC_TSIZE_IN); if (hcsc_ready(ncr_sc) == 0) goto interrupt; bus_space_read_multi_1(pdmat, pdmah, 0, data, len); data += len; resid -= len; } hcsc_wait_not_req(ncr_sc); interrupt: SCI_CLR_INTR(ncr_sc); NCR5380_WRITE(ncr_sc, sci_mode, NCR5380_READ(ncr_sc, sci_mode) & ~SCI_MODE_DMA); splx(s); return datalen - resid; }
void sbc_irq_intr(void *p) { struct ncr5380_softc *ncr_sc = p; struct sbc_softc *sc = (struct sbc_softc *)ncr_sc; int claimed = 0; /* How we ever arrive here without IRQ set is a mystery... */ if (*ncr_sc->sci_csr & SCI_CSR_INT) { #ifdef SBC_DEBUG if (sbc_debug & SBC_DB_INTR) decode_5380_intr(ncr_sc); #endif if (!cold) claimed = ncr5380_intr(ncr_sc); if (!claimed) { if (((*ncr_sc->sci_csr & ~SCI_CSR_PHASE_MATCH) == SCI_CSR_INT) && ((*ncr_sc->sci_bus_csr & ~SCI_BUS_RST) == 0)) { SCI_CLR_INTR(ncr_sc); /* RST interrupt */ if (sc->sc_clrintr) (*sc->sc_clrintr)(ncr_sc); } #ifdef SBC_DEBUG else { printf("%s: spurious intr\n", device_xname(ncr_sc->sc_dev)); SBC_BREAK; } #endif } } }
void se_dma_start(struct ncr5380_softc *ncr_sc) { struct se_softc *sc = (struct se_softc *)ncr_sc; struct sci_req *sr = ncr_sc->sc_current; struct se_dma_handle *dh = sr->sr_dma_hand; volatile struct se_regs *se = sc->sc_regs; int s, xlen; xlen = sc->sc_reqlen; /* This MAY be time critical (not sure). */ s = splhigh(); se->dma_cntr = (ushort)(xlen & 0xFFFF); /* * Acknowledge the phase change. (After DMA setup!) * Put the SBIC into DMA mode, and start the transfer. */ if (dh->dh_flags & SIDH_OUT) { *ncr_sc->sci_tcmd = PHASE_DATA_OUT; SCI_CLR_INTR(ncr_sc); *ncr_sc->sci_icmd = SCI_ICMD_DATA; *ncr_sc->sci_mode |= (SCI_MODE_DMA | SCI_MODE_DMA_IE); *ncr_sc->sci_dma_send = 0; /* start it */ } else { *ncr_sc->sci_tcmd = PHASE_DATA_IN; SCI_CLR_INTR(ncr_sc); *ncr_sc->sci_icmd = 0; *ncr_sc->sci_mode |= (SCI_MODE_DMA | SCI_MODE_DMA_IE); *ncr_sc->sci_irecv = 0; /* start it */ } /* Let'er rip! */ se->se_csr |= SE_CSR_INTR_EN; splx(s); ncr_sc->sc_state |= NCR_DOINGDMA; #ifdef DEBUG if (se_debug & 2) { printf("%s: started, flags=0x%x\n", __func__, ncr_sc->sc_state); } #endif }
void sbc_dma_stop(struct ncr5380_softc *ncr_sc) { struct sbc_softc *sc = (struct sbc_softc *)ncr_sc; struct sci_req *sr = ncr_sc->sc_current; struct sbc_pdma_handle *dh = sr->sr_dma_hand; int ntrans; if ((ncr_sc->sc_state & NCR_DOINGDMA) == 0) { #ifdef SBC_DEBUG if (sbc_debug & SBC_DB_DMA) printf("%s: dma_stop: DMA not running\n", device_xname(ncr_sc->sc_dev)); #endif return; } ncr_sc->sc_state &= ~NCR_DOINGDMA; if ((ncr_sc->sc_state & NCR_ABORTING) == 0) { ntrans = ncr_sc->sc_datalen - dh->dh_len; #ifdef SBC_DEBUG if (sbc_debug & SBC_DB_DMA) printf("%s: dma_stop: ntrans=0x%x\n", device_xname(ncr_sc->sc_dev), ntrans); #endif if (ntrans > ncr_sc->sc_datalen) panic("sbc_dma_stop: excess transfer"); /* Adjust data pointer */ ncr_sc->sc_dataptr += ntrans; ncr_sc->sc_datalen -= ntrans; /* Clear any pending interrupts. */ SCI_CLR_INTR(ncr_sc); if (sc->sc_clrintr) (*sc->sc_clrintr)(ncr_sc); } /* Put SBIC back into PIO mode. */ *ncr_sc->sci_mode &= ~SCI_MODE_DMA; *ncr_sc->sci_icmd = 0; #ifdef SBC_DEBUG if (sbc_debug & SBC_DB_REG) printf("%s: dma_stop: csr=0x%x, bus_csr=0x%x\n", device_xname(ncr_sc->sc_dev), *ncr_sc->sci_csr, *ncr_sc->sci_bus_csr); #endif }
void sbc_dma_start(struct ncr5380_softc *ncr_sc) { struct sbc_softc *sc = (struct sbc_softc *)ncr_sc; struct sci_req *sr = ncr_sc->sc_current; struct sbc_pdma_handle *dh = sr->sr_dma_hand; /* * Match bus phase, clear pending interrupts, set DMA mode, and * assert data bus (for writing only), then start the transfer. */ if (dh->dh_flags & SBC_DH_OUT) { *ncr_sc->sci_tcmd = PHASE_DATA_OUT; SCI_CLR_INTR(ncr_sc); if (sc->sc_clrintr) (*sc->sc_clrintr)(ncr_sc); *ncr_sc->sci_mode |= SCI_MODE_DMA; *ncr_sc->sci_icmd = SCI_ICMD_DATA; *ncr_sc->sci_dma_send = 0; } else { *ncr_sc->sci_tcmd = PHASE_DATA_IN; SCI_CLR_INTR(ncr_sc); if (sc->sc_clrintr) (*sc->sc_clrintr)(ncr_sc); *ncr_sc->sci_mode |= SCI_MODE_DMA; *ncr_sc->sci_icmd = 0; *ncr_sc->sci_irecv = 0; } ncr_sc->sc_state |= NCR_DOINGDMA; #ifdef SBC_DEBUG if (sbc_debug & SBC_DB_DMA) printf("%s: PDMA started, va=%p, len=0x%x\n", device_xname(ncr_sc->sc_dev), dh->dh_addr, dh->dh_len); #endif }
static int oak_pdma_in(struct ncr5380_softc *ncr_sc, int phase, int datalen, u_char *data) { struct oak_softc *sc = (void *)ncr_sc; bus_space_tag_t pdmat = sc->sc_pdmat; bus_space_handle_t pdmah = sc->sc_pdmah; int s, resid, len; s = splbio(); NCR5380_WRITE(ncr_sc, sci_mode, NCR5380_READ(ncr_sc, sci_mode) | SCI_MODE_DMA); NCR5380_WRITE(ncr_sc, sci_irecv, 0); resid = datalen; while (resid > 0) { len = min(resid, OAK_TSIZE_IN); if (oak_ready(ncr_sc) == 0) goto interrupt; KASSERT(BUS_SPACE_ALIGNED_POINTER(data, u_int16_t)); bus_space_read_multi_2(pdmat, pdmah, OAK_PDMA_READ, (u_int16_t *)data, len/2); data += len; resid -= len; } oak_wait_not_req(ncr_sc); interrupt: SCI_CLR_INTR(ncr_sc); NCR5380_WRITE(ncr_sc, sci_mode, NCR5380_READ(ncr_sc, sci_mode) & ~SCI_MODE_DMA); splx(s); return datalen - resid; }
static void sw_reset_adapter(struct ncr5380_softc *ncr_sc) { #ifdef DEBUG if (sw_debug) { printf("%s\n", __func__); } #endif /* * The reset bits in the CSR are active low. */ SWREG_WRITE(ncr_sc, SWREG_CSR, 0); delay(10); SWREG_WRITE(ncr_sc, SWREG_CSR, SW_CSR_SCSI_RES); SWREG_WRITE(ncr_sc, SWREG_DMA_ADDR, 0); SWREG_WRITE(ncr_sc, SWREG_DMA_CNT, 0); delay(10); SWREG_WRITE(ncr_sc, SWREG_CSR, SW_CSR_SCSI_RES | SW_CSR_INTR_EN); SCI_CLR_INTR(ncr_sc); }
static int hcsc_pdma_out(struct ncr5380_softc *ncr_sc, int phase, int datalen, uint8_t *data) { struct hcsc_softc *sc = (struct hcsc_softc *)ncr_sc; bus_space_tag_t pdmat = sc->sc_pdmat; bus_space_handle_t pdmah = sc->sc_pdmah; int i, s, icmd, resid; s = splbio(); icmd = NCR5380_READ(ncr_sc, sci_icmd) & SCI_ICMD_RMASK; NCR5380_WRITE(ncr_sc, sci_icmd, icmd | SCI_ICMD_DATA); NCR5380_WRITE(ncr_sc, sci_mode, NCR5380_READ(ncr_sc, sci_mode) | SCI_MODE_DMA); NCR5380_WRITE(ncr_sc, sci_dma_send, 0); resid = datalen; if (hcsc_ready(ncr_sc) == 0) goto interrupt; if (resid > HCSC_TSIZE_OUT) { /* * Because of the chips DMA prefetch, phase changes * etc, won't be detected until we have written at * least one byte more. We pre-write 4 bytes so * subsequent transfers will be aligned to a 4 byte * boundary. Assuming disconects will only occur on * block boundaries, we then correct for the pre-write * when and if we get a phase change. If the chip had * DMA byte counting hardware, the assumption would not * be necessary. */ bus_space_write_multi_1(pdmat, pdmah, 0, data, 4); data += 4; resid -= 4; for (; resid >= HCSC_TSIZE_OUT; resid -= HCSC_TSIZE_OUT) { if (hcsc_ready(ncr_sc) == 0) { resid += 4; /* Overshot */ goto interrupt; } bus_space_write_multi_1(pdmat, pdmah, 0, data, HCSC_TSIZE_OUT); data += HCSC_TSIZE_OUT; } if (hcsc_ready(ncr_sc) == 0) { resid += 4; /* Overshot */ goto interrupt; } } if (resid) { bus_space_write_multi_1(pdmat, pdmah, 0, data, resid); resid = 0; } for (i = TIMEOUT; i > 0; i--) { if ((NCR5380_READ(ncr_sc, sci_csr) & (SCI_CSR_DREQ|SCI_CSR_PHASE_MATCH)) != SCI_CSR_DREQ) break; } if (i != 0) bus_space_write_1(pdmat, pdmah, 0, 0); else printf("%s: timeout waiting for final SCI_DSR_DREQ.\n", device_xname(ncr_sc->sc_dev)); hcsc_wait_not_req(ncr_sc); interrupt: SCI_CLR_INTR(ncr_sc); NCR5380_WRITE(ncr_sc, sci_mode, NCR5380_READ(ncr_sc, sci_mode) & ~SCI_MODE_DMA); NCR5380_WRITE(ncr_sc, sci_icmd, icmd); splx(s); return datalen - resid; }
int sbc_pdma_out(struct ncr5380_softc *ncr_sc, int phase, int datalen, u_char *data) { struct sbc_softc *sc = (struct sbc_softc *)ncr_sc; volatile u_int32_t *long_data = (u_int32_t *)sc->sc_drq_addr; volatile u_int8_t *byte_data = (u_int8_t *)sc->sc_nodrq_addr; label_t faultbuf; int resid, s; u_int8_t icmd; #if 1 /* Work around lame gcc initialization bug */ (void)&data; #endif if (datalen < ncr_sc->sc_min_dma_len || (sc->sc_options & SBC_PDMA) == 0) return ncr5380_pio_out(ncr_sc, phase, datalen, data); s = splbio(); if (sbc_wait_busy(ncr_sc)) { splx(s); return 0; } icmd = *(ncr_sc->sci_icmd) & SCI_ICMD_RMASK; *ncr_sc->sci_icmd = icmd | SCI_ICMD_DATA; *ncr_sc->sci_mode |= SCI_MODE_DMA; *ncr_sc->sci_dma_send = 0; /* * Setup for a possible bus error caused by SCSI controller * switching out of DATA OUT before we're done with the * current transfer. (See comment before sbc_drq_intr().) */ nofault = &faultbuf; if (setjmp(nofault)) { printf("buf = 0x%lx, fault = 0x%lx\n", (u_long)sc->sc_drq_addr, (u_long)m68k_fault_addr); panic("Unexpected bus error in sbc_pdma_out()"); } #define W1 *byte_data = *(u_int8_t *)data, data += 1 #define W4 *long_data = *(u_int32_t *)data, data += 4 for (resid = datalen; resid >= 64; resid -= 64) { if (sbc_ready(ncr_sc)) goto interrupt; W1; if (sbc_ready(ncr_sc)) goto interrupt; W1; if (sbc_ready(ncr_sc)) goto interrupt; W1; if (sbc_ready(ncr_sc)) goto interrupt; W1; if (sbc_ready(ncr_sc)) goto interrupt; W4; W4; W4; W4; W4; W4; W4; W4; W4; W4; W4; W4; W4; W4; W4; } while (resid) { if (sbc_ready(ncr_sc)) goto interrupt; W1; resid--; } #undef W1 #undef W4 if (sbc_wait_dreq(ncr_sc)) printf("%s: timeout waiting for DREQ.\n", device_xname(ncr_sc->sc_dev)); *byte_data = 0; goto done; interrupt: if ((*ncr_sc->sci_csr & SCI_CSR_PHASE_MATCH) == 0) { *ncr_sc->sci_icmd = icmd & ~SCI_ICMD_DATA; --resid; } done: SCI_CLR_INTR(ncr_sc); *ncr_sc->sci_mode &= ~SCI_MODE_DMA; *ncr_sc->sci_icmd = icmd; splx(s); return (datalen - resid); }
int sbc_pdma_in(struct ncr5380_softc *ncr_sc, int phase, int datalen, u_char *data) { struct sbc_softc *sc = (struct sbc_softc *)ncr_sc; volatile u_int32_t *long_data = (u_int32_t *)sc->sc_drq_addr; volatile u_int8_t *byte_data = (u_int8_t *)sc->sc_nodrq_addr; label_t faultbuf; int resid, s; if (datalen < ncr_sc->sc_min_dma_len || (sc->sc_options & SBC_PDMA) == 0) return ncr5380_pio_in(ncr_sc, phase, datalen, data); s = splbio(); if (sbc_wait_busy(ncr_sc)) { splx(s); return 0; } *ncr_sc->sci_mode |= SCI_MODE_DMA; *ncr_sc->sci_irecv = 0; resid = datalen; /* * Setup for a possible bus error caused by SCSI controller * switching out of DATA OUT before we're done with the * current transfer. (See comment before sbc_drq_intr().) */ nofault = &faultbuf; if (setjmp(nofault)) { goto interrupt; } #define R4 *(u_int32_t *)data = *long_data, data += 4; #define R1 *(u_int8_t *)data = *byte_data, data += 1; for (; resid >= 128; resid -= 128) { if (sbc_ready(ncr_sc)) goto interrupt; R4; R4; R4; R4; R4; R4; R4; R4; R4; R4; R4; R4; R4; R4; R4; R4; R4; R4; R4; R4; R4; R4; R4; R4; R4; R4; R4; R4; R4; R4; R4; R4; /* 128 */ } while (resid) { if (sbc_ready(ncr_sc)) goto interrupt; R1; resid--; } #undef R4 #undef R1 interrupt: nofault = NULL; SCI_CLR_INTR(ncr_sc); *ncr_sc->sci_mode &= ~SCI_MODE_DMA; *ncr_sc->sci_icmd = 0; splx(s); return (datalen - resid); }
void sw_dma_start(struct ncr5380_softc *ncr_sc) { struct sw_softc *sc = (struct sw_softc *)ncr_sc; struct sci_req *sr = ncr_sc->sc_current; struct sw_dma_handle *dh = sr->sr_dma_hand; u_long dva; int xlen, adj, adjlen; u_int mode; uint32_t csr; /* * Get the DVMA mapping for this segment. */ dva = (u_long)(dh->dh_dvma); if (dva & 1) panic("%s: bad dva=0x%lx", __func__, dva); xlen = ncr_sc->sc_datalen; xlen &= ~1; sc->sc_xlen = xlen; /* XXX: or less... */ #ifdef DEBUG if (sw_debug & 2) { printf("%s: dh=%p, dva=0x%lx, xlen=%d\n", __func__, dh, dva, xlen); } #endif /* * Set up the DMA controller. * Note that (dh->dh_len < sc_datalen) */ /* Set direction (send/recv) */ csr = SWREG_READ(ncr_sc, SWREG_CSR); if (dh->dh_flags & SIDH_OUT) { csr |= SW_CSR_SEND; } else { csr &= ~SW_CSR_SEND; } SWREG_WRITE(ncr_sc, SWREG_CSR, csr); /* * The "sw" needs longword aligned transfers. We * detect a shortword aligned transfer here, and adjust the * DMA transfer by 2 bytes. These two bytes are read/written * in PIO mode just before the DMA is started. */ adj = 0; if (dva & 2) { adj = 2; #ifdef DEBUG if (sw_debug & 2) printf("%s: adjusted up %d bytes\n", __func__, adj); #endif } /* We have to frob the address on the "sw". */ dh->dh_startingpa = (dva | 0xF00000); SWREG_WRITE(ncr_sc, SWREG_DMA_ADDR, (u_int)(dh->dh_startingpa + adj)); SWREG_WRITE(ncr_sc, SWREG_DMA_CNT, xlen - adj); /* * Acknowledge the phase change. (After DMA setup!) * Put the SBIC into DMA mode, and start the transfer. */ if (dh->dh_flags & SIDH_OUT) { NCR5380_WRITE(ncr_sc, sci_tcmd, PHASE_DATA_OUT); if (adj) { adjlen = ncr5380_pio_out(ncr_sc, PHASE_DATA_OUT, adj, dh->dh_addr); if (adjlen != adj) printf("%s: bad outgoing adj, %d != %d\n", device_xname(ncr_sc->sc_dev), adjlen, adj); } SCI_CLR_INTR(ncr_sc); NCR5380_WRITE(ncr_sc, sci_icmd, SCI_ICMD_DATA); mode = NCR5380_READ(ncr_sc, sci_mode); mode |= (SCI_MODE_DMA | SCI_MODE_DMA_IE); NCR5380_WRITE(ncr_sc, sci_mode, mode); NCR5380_WRITE(ncr_sc, sci_dma_send, 0); /* start it */ } else { NCR5380_WRITE(ncr_sc, sci_tcmd, PHASE_DATA_IN); if (adj) { adjlen = ncr5380_pio_in(ncr_sc, PHASE_DATA_IN, adj, dh->dh_addr); if (adjlen != adj) printf("%s: bad incoming adj, %d != %d\n", device_xname(ncr_sc->sc_dev), adjlen, adj); } SCI_CLR_INTR(ncr_sc); NCR5380_WRITE(ncr_sc, sci_icmd, 0); mode = NCR5380_READ(ncr_sc, sci_mode); mode |= (SCI_MODE_DMA | SCI_MODE_DMA_IE); NCR5380_WRITE(ncr_sc, sci_mode, mode); NCR5380_WRITE(ncr_sc, sci_irecv, 0); /* start it */ } /* Let'er rip! */ csr |= SW_CSR_DMA_EN; SWREG_WRITE(ncr_sc, SWREG_CSR, csr); ncr_sc->sc_state |= NCR_DOINGDMA; #ifdef DEBUG if (sw_debug & 2) { printf("%s: started, flags=0x%x\n", __func__, ncr_sc->sc_state); } #endif }