Support DMA on ATAPI devices (finally).

This makes my system use only ~5% CPU on reading 4.5Mbyte/sec
from a CDROM, which before was limitted to 1.8Mbyte/sec due
to 100% CPU load..
This commit is contained in:
sos 1999-08-10 21:59:58 +00:00
parent 4368f24089
commit 51df811367
4 changed files with 98 additions and 13 deletions

View File

@ -25,7 +25,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: ata-all.h,v 1.6 1999/04/18 20:48:15 sos Exp $
* $Id: ata-all.h,v 1.7 1999/06/25 09:02:57 sos Exp $
*/
/* ATA register defines */
@ -87,12 +87,6 @@
#define ATA_OP_FINISHED 0x00
#define ATA_OP_CONTINUES 0x01
/* devices types */
#define ATA_ATA_MASTER 0x01
#define ATA_ATA_SLAVE 0x02
#define ATA_ATAPI_MASTER 0x04
#define ATA_ATAPI_SLAVE 0x08
/* busmaster DMA related defines */
#define ATA_BM_OFFSET1 0x08
#define ATA_DMA_ENTRIES 256
@ -132,6 +126,11 @@ struct ata_softc {
struct ata_dmaentry *dmatab[2]; /* DMA transfer tables */
int32_t flags; /* controller flags */
int32_t devices; /* what is present */
#define ATA_ATA_MASTER 0x01
#define ATA_ATA_SLAVE 0x02
#define ATA_ATAPI_MASTER 0x04
#define ATA_ATAPI_SLAVE 0x08
u_int8_t status; /* last controller status */
u_int8_t error; /* last controller error */
int32_t active; /* active processing request */

View File

@ -25,7 +25,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: ata-disk.c,v 1.14 1999/06/25 09:02:59 sos Exp $
* $Id: ata-disk.c,v 1.15 1999/07/17 17:55:53 phk Exp $
*/
#include "ata.h"
@ -540,6 +540,10 @@ ad_transfer(struct ad_request *request)
/* setup transfer parameters */
count = howmany(request->bytecount, DEV_BSIZE);
if (count > 256) {
count = 256;
printf("ad_transfer: count=%d not supported\n", count);
}
if (adp->flags & AD_F_LBA_ENABLED) {
sector = (blkno >> 0) & 0xff;
@ -745,7 +749,7 @@ ad_drvinit(void)
if (!ad_devsw_installed) {
if (!ad_cdevsw.d_maxio)
ad_cdevsw.d_maxio = 254 * DEV_BSIZE;
ad_cdevsw.d_maxio = 256 * DEV_BSIZE;
cdevsw_add(&ad_cdevsw);
fakewd_cdevsw = ad_cdevsw;
fakewd_cdevsw.d_maj = 3;

View File

@ -25,7 +25,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: ata-dma.c,v 1.8 1999/05/26 23:01:57 gallatin Exp $
* $Id: ata-dma.c,v 1.9 1999/08/06 17:39:38 sos Exp $
*/
#include "ata.h"
@ -169,6 +169,11 @@ ata_dmainit(struct ata_softc *scp, int32_t device,
case 0x4d33105a: /* Promise Ultra/33 / FastTrack controllers */
case 0x4d38105a: /* Promise Ultra/66 controllers */
/* the promise seems to have trouble with DMA on ATAPI devices */
if ((device == ATA_MASTER && scp->devices & ATA_ATAPI_MASTER) ||
(device == ATA_SLAVE && scp->devices & ATA_ATAPI_SLAVE))
break;
devno = (scp->unit << 1) + (device ? 1 : 0);
if (udmamode >=2) {
printf("ata%d: %s: setting up UDMA2 mode on Promise chip ",

View File

@ -25,7 +25,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: atapi-all.c,v 1.9 1999/05/20 09:12:04 sos Exp $
* $Id: atapi-all.c,v 1.10 1999/06/25 09:03:01 sos Exp $
*/
#include "ata.h"
@ -64,6 +64,38 @@ int32_t astattach(struct atapi_softc *);
static struct intr_config_hook *atapi_attach_hook;
static __inline int
apiomode(struct atapi_params *ap)
{
if ((ap->atavalid & 2) == 2) {
if ((ap->apiomodes & 2) == 2) return 4;
if ((ap->apiomodes & 1) == 1) return 3;
}
return -1;
}
static __inline int
wdmamode(struct atapi_params *ap)
{
if ((ap->atavalid & 2) == 2) {
if ((ap->wdmamodes & 4) == 4) return 2;
if ((ap->wdmamodes & 2) == 2) return 1;
if ((ap->wdmamodes & 1) == 1) return 0;
}
return -1;
}
static __inline int
udmamode(struct atapi_params *ap)
{
if ((ap->atavalid & 4) == 4) {
if ((ap->udmamodes & 4) == 4) return 2;
if ((ap->udmamodes & 2) == 2) return 1;
if ((ap->udmamodes & 1) == 1) return 0;
}
return -1;
}
static void
atapi_attach(void *notused)
{
@ -90,6 +122,19 @@ atapi_attach(void *notused)
free(atp, M_DEVBUF);
continue;
}
printf("atapi: piomode=%d, dmamode=%d, udmamode=%d\n",
apiomode(atp->atapi_parm),
wdmamode(atp->atapi_parm),
udmamode(atp->atapi_parm));
if (!(atp->atapi_parm->drqtype == ATAPI_DRQT_INTR) &&
!ata_dmainit(atp->controller, atp->unit,
apiomode(atp->atapi_parm),
wdmamode(atp->atapi_parm),
udmamode(atp->atapi_parm)))
atp->flags |= ATAPI_F_DMA_ENABLED;
printf("atapi: %s transfer mode set\n",
(atp->flags & ATAPI_F_DMA_ENABLED) ? "DMA" :"PIO");
switch (atp->atapi_parm->device_type) {
#if NATAPICD > 0
@ -240,10 +285,21 @@ atapi_transfer(struct atapi_request *request)
#ifdef ATAPI_DEBUG
printf("atapi: trying to start %s cmd\n", atapi_cmd2str(request->ccb[0]));
#endif
/* if DMA enabled setup DMA hardware */
atp->flags &= ~ATAPI_F_DMA_USED;
if ((request->ccb[0]==ATAPI_READ_BIG || request->ccb[0]==ATAPI_WRITE_BIG) &&
(atp->flags & ATAPI_F_DMA_ENABLED) &&
!ata_dmasetup(atp->controller, atp->unit,
(void *)request->data, request->bytecount,
request->flags & A_READ)) {
atp->flags |= ATAPI_F_DMA_USED;
}
/* start ATAPI operation */
ata_command(atp->controller, atp->unit, ATA_C_PACKET_CMD,
request->bytecount, 0, 0, 0, 0, ATA_IMMEDIATE);
request->bytecount, 0, 0, 0,
(atp->flags & ATAPI_F_DMA_USED) ? ATA_F_DMA : 0,
ATA_IMMEDIATE);
/* command interrupt device ? just return */
if (atp->atapi_parm->drqtype == ATAPI_DRQT_INTR)
@ -268,6 +324,9 @@ atapi_transfer(struct atapi_request *request)
/* this seems to be needed for some (slow) devices */
DELAY(10);
if (atp->flags & ATAPI_F_DMA_USED)
ata_dmastart(atp->controller, atp->unit);
/* send actual command */
outsw(atp->controller->ioaddr + ATA_DATA, request->ccb,
request->ccbsize / sizeof(int16_t));
@ -277,7 +336,7 @@ int32_t
atapi_interrupt(struct atapi_request *request)
{
struct atapi_softc *atp;
int32_t length, reason, resid;
int32_t length, reason, resid, dma_stat = 0;
#ifdef ATAPI_DEBUG
printf("atapi_interrupt: enter\n");
@ -285,6 +344,9 @@ printf("atapi_interrupt: enter\n");
/* get device params */
atp = request->device;
if (atp->flags & ATAPI_F_DMA_USED)
dma_stat = ata_dmadone(atp->controller, atp->unit);
/* get drive status */
if (atapi_wait(atp, 0) < 0) {
printf("atapi_interrupt: timeout waiting for status");
@ -304,6 +366,21 @@ printf("atapi_interrupt: enter\n");
printf("atapi_interrupt: length=%d reason=0x%02x\n", length, reason);
#endif
if (atp->flags & ATAPI_F_DMA_USED) {
if (atp->controller->status & (ATA_S_ERROR | ATA_S_DWF) &&
dma_stat != ATA_BMSTAT_INTERRUPT)
request->result = atp->controller->error;
else {
request->donecount = request->bytecount;
request->bytecount = 0;
request->result = 0;
}
TAILQ_REMOVE(&atp->controller->atapi_queue, request, chain);
atp->flags &= ~ATAPI_F_DMA_USED;
wakeup((caddr_t)request);
return ATA_OP_FINISHED;
}
switch (reason) {
case ATAPI_P_CMDOUT: