📄 pciide.c
字号:
{ struct pciide_softc *sc = v; int error, seg; struct pciide_dma_maps *dma_maps = &sc->pciide_channels[channel].dma_maps[drive]; error = bus_dmamap_load(sc->sc_dmat, dma_maps->dmamap_xfer, databuf, datalen, NULL, BUS_DMA_NOWAIT); if (error) { printf("%s:%d: unable to load xfer DMA map for" "drive %d, error=%d\n", sc->sc_wdcdev.sc_dev.dv_xname, channel, drive, error); return error; }#ifndef __OpenBSD__ bus_dmamap_sync(sc->sc_dmat, dma_maps->dmamap_xfer, 0, dma_maps->dmamap_xfer->dm_mapsize, (flags & WDC_DMA_READ) ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);#else bus_dmamap_sync(sc->sc_dmat, dma_maps->dmamap_xfer, (flags & WDC_DMA_READ) ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);#endif for (seg = 0; seg < dma_maps->dmamap_xfer->dm_nsegs; seg++) {#ifdef DIAGNOSTIC /* A segment must not cross a 64k boundary */ { u_long phys = dma_maps->dmamap_xfer->dm_segs[seg].ds_addr; u_long len = dma_maps->dmamap_xfer->dm_segs[seg].ds_len; if ((phys & ~IDEDMA_BYTE_COUNT_MASK) != ((phys + len - 1) & ~IDEDMA_BYTE_COUNT_MASK)) { printf("pciide_dma: segment %d physical addr 0x%lx" " len 0x%lx not properly aligned\n", seg, phys, len); panic("pciide_dma: buf align"); } }#endif dma_maps->dma_table[seg].base_addr = htopci(dma_maps->dmamap_xfer->dm_segs[seg].ds_addr | 0x00000000); dma_maps->dma_table[seg].byte_count = htopci(dma_maps->dmamap_xfer->dm_segs[seg].ds_len & IDEDMA_BYTE_COUNT_MASK); WDCDEBUG_PRINT(("\t seg %d len %d addr 0x%x\n", seg, pcitoh(dma_maps->dma_table[seg].byte_count), pcitoh(dma_maps->dma_table[seg].base_addr)), DEBUG_DMA); } dma_maps->dma_table[dma_maps->dmamap_xfer->dm_nsegs -1].byte_count |= htopci(IDEDMA_BYTE_COUNT_EOT);#ifndef __OpenBSD__ bus_dmamap_sync(sc->sc_dmat, dma_maps->dmamap_table, 0, dma_maps->dmamap_table->dm_mapsize, BUS_DMASYNC_PREWRITE);#else bus_dmamap_sync(sc->sc_dmat, dma_maps->dmamap_table, BUS_DMASYNC_PREWRITE);#endif /* Maps are ready. Start DMA function */#ifdef DIAGNOSTIC if (dma_maps->dmamap_table->dm_segs[0].ds_addr & ~IDEDMA_TBL_MASK) { printf("pciide_dma_init: addr 0x%lx not properly aligned\n", dma_maps->dmamap_table->dm_segs[0].ds_addr); panic("pciide_dma_init: table align"); }#endif /* Clear status bits */ bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh, IDEDMA_CTL + IDEDMA_SCH_OFFSET * channel, bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh, IDEDMA_CTL + IDEDMA_SCH_OFFSET * channel));/* XXX CMD MRDMODE pending bits clear */ bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh, (IDEDMA_CTL-1) + IDEDMA_SCH_OFFSET * channel, bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh, (IDEDMA_CTL-1) + IDEDMA_SCH_OFFSET * channel)); /* Write table addr */printf("dma table start at 0x%08x\n", dma_maps->dmamap_table->dm_segs[0].ds_addr); bus_space_write_4(sc->sc_dma_iot, sc->sc_dma_ioh, IDEDMA_TBL + IDEDMA_SCH_OFFSET * channel, dma_maps->dmamap_table->dm_segs[0].ds_addr | 0x80000000); /* XXX */ /* set read/write */ bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh, IDEDMA_CMD + IDEDMA_SCH_OFFSET * channel, (flags & WDC_DMA_READ) ? IDEDMA_CMD_WRITE: 0); return 0;}voidpciide_dma_start(v, channel, drive, flags) void *v; int channel, drive, flags;{ struct pciide_softc *sc = v; WDCDEBUG_PRINT(("pciide_dma_start\n"),DEBUG_XFERS); bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh, IDEDMA_CMD + IDEDMA_SCH_OFFSET * channel, bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh, IDEDMA_CMD + IDEDMA_SCH_OFFSET * channel) | IDEDMA_CMD_START);}intpciide_dma_finish(v, channel, drive, flags) void *v; int channel, drive; int flags;{ struct pciide_softc *sc = v; u_int8_t status; struct pciide_dma_maps *dma_maps = &sc->pciide_channels[channel].dma_maps[drive]; /* Unload the map of the data buffer */#ifndef __OpenBSD__ bus_dmamap_sync(sc->sc_dmat, dma_maps->dmamap_xfer, 0, dma_maps->dmamap_xfer->dm_mapsize, (flags & WDC_DMA_READ) ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);#else bus_dmamap_sync(sc->sc_dmat, dma_maps->dmamap_xfer, (flags & WDC_DMA_READ) ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);#endif bus_dmamap_unload(sc->sc_dmat, dma_maps->dmamap_xfer); status = bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh, IDEDMA_CTL + IDEDMA_SCH_OFFSET * channel); WDCDEBUG_PRINT(("pciide_dma_finish: status 0x%x\n", status), DEBUG_XFERS); WDCDEBUG_PRINT(("pciide: command/status register=%x\n", pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG)), DEBUG_XFERS); /* stop DMA channel */ bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh, IDEDMA_CMD + IDEDMA_SCH_OFFSET * channel, bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh, IDEDMA_CMD + IDEDMA_SCH_OFFSET * channel) & ~IDEDMA_CMD_START); /* Clear status bits */ bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh, IDEDMA_CTL + IDEDMA_SCH_OFFSET * channel, status); if ((status & IDEDMA_CTL_ERR) != 0) { printf("%s:%d:%d: Bus-Master DMA error: status=0x%x\n", sc->sc_wdcdev.sc_dev.dv_xname, channel, drive, status); return -1; } if ((flags & WDC_DMA_POLL) == 0 && (status & IDEDMA_CTL_INTR) == 0) { printf("%s:%d:%d: Bus-Master DMA error: missing interrupt, " "status=0x%x\n", sc->sc_wdcdev.sc_dev.dv_xname, channel, drive, status); return -1; } if ((status & IDEDMA_CTL_ACT) != 0) { /* data underrun, may be a valid condition for ATAPI */ return 1; } return 0;}#endif/* some common code used by several chip_map */intpciide_chansetup(sc, channel, interface) struct pciide_softc *sc; int channel; pcireg_t interface;{ struct pciide_channel *cp = &sc->pciide_channels[channel]; sc->wdc_chanarray[channel] = &cp->wdc_channel; cp->name = PCIIDE_CHANNEL_NAME(channel); cp->wdc_channel.channel = channel; cp->wdc_channel.wdc = &sc->sc_wdcdev; cp->wdc_channel.ch_queue = malloc(sizeof(struct channel_queue), M_DEVBUF, M_NOWAIT); if (cp->wdc_channel.ch_queue == NULL) { printf("%s: %s " "cannot allocate memory for command queue", sc->sc_wdcdev.sc_dev.dv_xname, cp->name); return 0; } cp->hw_ok = 1; return 1;}/* some common code used by several chip channel_map */voidpciide_mapchan(pa, cp, interface, cmdsizep, ctlsizep, pci_intr) struct pci_attach_args *pa; struct pciide_channel *cp; pcireg_t interface; bus_size_t *cmdsizep, *ctlsizep; int (*pci_intr) __P((void *));{ struct channel_softc *wdc_cp = &cp->wdc_channel; if (interface & PCIIDE_INTERFACE_PCI(wdc_cp->channel)) cp->hw_ok = pciide_mapregs_native(pa, cp, cmdsizep, ctlsizep, pci_intr); else cp->hw_ok = pciide_mapregs_compat(pa, cp, wdc_cp->channel, cmdsizep, ctlsizep); if (cp->hw_ok == 0) return; wdc_cp->data32iot = wdc_cp->cmd_iot; wdc_cp->data32ioh = wdc_cp->cmd_ioh; wdcattach(wdc_cp);}/* * Generic code to call to know if a channel can be disabled. Return 1 * if channel can be disabled, 0 if not */intpciiide_chan_candisable(cp) struct pciide_channel *cp;{ struct channel_softc *wdc_cp = &cp->wdc_channel; if ((wdc_cp->ch_drive[0].drive_flags & DRIVE) == 0 && (wdc_cp->ch_drive[1].drive_flags & DRIVE) == 0) { cp->hw_ok = 0; return 1; } return 0;}/* * generic code to map the compat intr if hw_ok=1 and it is a compat channel. * Set hw_ok=0 on failure */voidpciide_map_compat_intr(pa, cp, compatchan, interface) struct pci_attach_args *pa; struct pciide_channel *cp; int compatchan, interface;{#ifndef PMON struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc; struct channel_softc *wdc_cp = &cp->wdc_channel; if (cp->hw_ok == 0) return; if ((interface & PCIIDE_INTERFACE_PCI(wdc_cp->channel)) != 0) return; cp->ih = pciide_machdep_compat_intr_establish(&sc->sc_wdcdev.sc_dev, pa, compatchan, pciide_compat_intr, cp); if (cp->ih == NULL) { printf("%s: no compatibility interrupt for use by %s\n", sc->sc_wdcdev.sc_dev.dv_xname, cp->name); cp->hw_ok = 0; }#endif}voidpciide_print_channels(nchannels, interface) int nchannels; pcireg_t interface;{ int i; for (i = 0; i < nchannels; i++) { printf(", %s %s to %s", PCIIDE_CHANNEL_NAME(i), (interface & PCIIDE_INTERFACE_SETTABLE(i)) ? "cfg" : "wired", (interface & PCIIDE_INTERFACE_PCI(i)) ? "native-PCI" : "compat"); } printf("\n");}voidpciide_print_modes(cp) struct pciide_channel *cp;{ struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc; int drive; struct channel_softc *chp; struct ata_drive_datas *drvp; chp = &cp->wdc_channel; for (drive = 0; drive < 2; drive++) { drvp = &chp->ch_drive[drive]; if ((drvp->drive_flags & DRIVE) == 0) continue; printf("%s(%s:%d:%d): using PIO mode %d", drvp->drive_name, sc->sc_wdcdev.sc_dev.dv_xname, chp->channel, drive, drvp->PIO_mode); if (drvp->drive_flags & DRIVE_DMA) printf(", DMA mode %d", drvp->DMA_mode); if (drvp->drive_flags & DRIVE_UDMA) printf(", Ultra-DMA mode %d", drvp->UDMA_mode); if (drvp->drive_flags & (DRIVE_DMA | DRIVE_UDMA)) printf(" (using DMA data transfers)"); printf("\n"); }}voiddefault_chip_map(sc, pa) struct pciide_softc *sc; struct pci_attach_args *pa;{ struct pciide_channel *cp; pcireg_t interface = PCI_INTERFACE(pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_CLASS_REG)); pcireg_t csr; int channel;#ifndef PMON int drive; struct ata_drive_datas *drvp; u_int8_t idedma_ctl;#endif bus_size_t cmdsize, ctlsize; char *failreason; if (pciide_chipen(sc, pa) == 0) return; if (interface & PCIIDE_INTERFACE_BUS_MASTER_DMA) { printf(": DMA"); if (sc->sc_pp == &default_product_desc && (sc->sc_wdcdev.sc_dev.dv_cfdata->cf_flags & PCIIDE_OPTIONS_DMA) == 0) { printf(" (unsupported)"); sc->sc_dma_ok = 0; } else { pciide_mapreg_dma(sc, pa); if (sc->sc_dma_ok != 0) printf(", (partial support)"); } } else { printf(": no DMA"); sc->sc_dma_ok = 0; } if (sc->sc_dma_ok) sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA; sc->sc_wdcdev.PIO_cap = 0; sc->sc_wdcdev.DMA_cap = 0; sc->sc_wdcdev.channels = sc->wdc_chanarray; sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS; sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16; pciide_print_channels(sc->sc_wdcdev.nchannels, interface); for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) { cp = &sc->pciide_channels[channel]; if (pciide_chansetup(sc, channel, interface) == 0) continue; if (interface & PCIIDE_INTERFACE_PCI(channel)) { cp->hw_ok = pciide_mapregs_native(pa, cp, &cmdsize, &ctlsize, pciide_pci_intr); } else { cp->hw_ok = pciide_mapregs_compat(pa, cp, channel, &cmdsize, &ctlsize); } if (cp->hw_ok == 0) continue; /* * Check to see if something appears to be there. */ failreason = NULL; if (!wdcprobe(&cp->wdc_channel)) { failreason = "not responding; disabled or no drives?"; goto next; } /* * Now, make sure it's actually attributable to this PCI IDE * channel by trying to access the channel again while the * PCI IDE controller's I/O space is disabled. (If the * channel no longer appears to be there, it belongs to * this controller.) YUCK! */ csr = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG); pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG, csr & ~PCI_COMMAND_IO_ENABLE); if (wdcprobe(&cp->wdc_channel)) failreason = "other hardware responding at addresses"; pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG, csr);next: if (failreason) { printf("%s: %s ignored (%s)\n", sc->sc_wdcdev.sc_dev.dv_xname, cp->name, failreason); cp->hw_ok = 0; bus_space_unmap(cp->wdc_channel.cmd_iot, cp->wdc_channel.cmd_ioh, cmdsize); bus_space_unmap(cp->wdc_channel.ctl_iot, cp->wdc_channel.ctl_ioh, ctlsize); } else { pciide_map_compat_intr(pa, cp, channel, interface); } if (cp->hw_ok) { cp->wdc_channel.data32iot = cp->wdc_channel.cmd_iot; cp->wdc_channel.data32ioh = cp->wdc_channel.cmd_ioh; wdcattach(&cp->wdc_channel); } }#ifndef PMON if (sc->sc_dma_ok == 0) return; /* Allocate DMA maps */ for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) { idedma_ctl = 0; cp = &sc->pciide_channels[channel]; for (drive = 0; drive < 2; drive++) { drvp = &cp->wdc_channel.ch_drive[drive]; /* If no drive, skip */ if ((drvp->drive_flags & DRIVE) == 0) continue; if ((drvp->drive_flags & DRIVE_DMA) == 0) continue; if (pciide_dma_table_setup(sc, channel, drive) != 0) { /* Abort DMA setup */ printf("%s:%d:%d: cannot allocate DMA maps, " "using PIO transfers\n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -