summaryrefslogtreecommitdiff
path: root/sys/dev/ic
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2014-03-31 03:38:47 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2014-03-31 03:38:47 +0000
commit2117bdcd13e0d1755b28b5f9100c85cd53075e86 (patch)
tree0ae1c5bdd348e529c530c87d8ce02aa5ff1bca59 /sys/dev/ic
parent041d750fc84d3da0e701dcdcf6a62d8eac4d06b7 (diff)
massage the prdt (what an sgl is on every other chip) loading with
better ops and alignment. ok jmatthew@ who was cruel and made me test hibernate before he oked it.
Diffstat (limited to 'sys/dev/ic')
-rw-r--r--sys/dev/ic/ahci.c60
-rw-r--r--sys/dev/ic/ahcivar.h7
2 files changed, 28 insertions, 39 deletions
diff --git a/sys/dev/ic/ahci.c b/sys/dev/ic/ahci.c
index 8fc88dd3315..8405ff484d1 100644
--- a/sys/dev/ic/ahci.c
+++ b/sys/dev/ic/ahci.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ahci.c,v 1.8 2014/03/28 17:57:11 mpi Exp $ */
+/* $OpenBSD: ahci.c,v 1.9 2014/03/31 03:38:46 dlg Exp $ */
/*
* Copyright (c) 2006 David Gwynne <dlg@openbsd.org>
@@ -86,6 +86,8 @@ int ahci_pmp_port_portreset(struct ahci_port *, int);
int ahci_pmp_port_probe(struct ahci_port *ap, int pmp_port);
int ahci_load_prdt(struct ahci_ccb *);
+void ahci_load_prdt_seg(struct ahci_prdt *, u_int64_t,
+ u_int32_t, u_int32_t);
void ahci_unload_prdt(struct ahci_ccb *);
int ahci_poll(struct ahci_ccb *, int, void (*)(void *));
@@ -1640,16 +1642,25 @@ ahci_port_detect_pmp(struct ahci_port *ap)
return (rc);
}
+void
+ahci_load_prdt_seg(struct ahci_prdt *prd, u_int64_t addr, u_int32_t len,
+ u_int32_t flags)
+{
+ flags |= len - 1;
+
+ htolem64(&prd->dba, addr);
+ htolem32(&prd->flags, flags);
+}
+
int
ahci_load_prdt(struct ahci_ccb *ccb)
{
struct ahci_port *ap = ccb->ccb_port;
struct ahci_softc *sc = ap->ap_sc;
struct ata_xfer *xa = &ccb->ccb_xa;
- struct ahci_prdt *prdt = ccb->ccb_cmd_table->prdt, *prd;
+ struct ahci_prdt *prdt = ccb->ccb_cmd_table->prdt;
bus_dmamap_t dmap = ccb->ccb_dmamap;
struct ahci_cmd_hdr *cmd_slot = ccb->ccb_cmd_hdr;
- u_int64_t addr;
int i, error;
if (xa->datalen == 0) {
@@ -1664,42 +1675,22 @@ ahci_load_prdt(struct ahci_ccb *ccb)
return (1);
}
- for (i = 0; i < dmap->dm_nsegs; i++) {
- prd = &prdt[i];
-
- addr = dmap->dm_segs[i].ds_addr;
- prd->dba_hi = htole32((u_int32_t)(addr >> 32));
- prd->dba_lo = htole32((u_int32_t)addr);
-#ifdef DIAGNOSTIC
- if (addr & 1) {
- printf("%s: requested DMA at an odd address %llx\n",
- PORTNAME(ap), (unsigned long long)addr);
- goto diagerr;
- }
- if (dmap->dm_segs[i].ds_len & 1) {
- printf("%s: requested DMA length %d is not even\n",
- PORTNAME(ap), (int)dmap->dm_segs[i].ds_len);
- goto diagerr;
- }
-#endif
- prd->flags = htole32(dmap->dm_segs[i].ds_len - 1);
+ for (i = 0; i < dmap->dm_nsegs - 1; i++) {
+ ahci_load_prdt_seg(&prdt[i], dmap->dm_segs[i].ds_addr,
+ dmap->dm_segs[i].ds_len, 0);
}
- if (xa->flags & ATA_F_PIO)
- prd->flags |= htole32(AHCI_PRDT_FLAG_INTR);
- cmd_slot->prdtl = htole16(dmap->dm_nsegs);
+ ahci_load_prdt_seg(&prdt[i],
+ dmap->dm_segs[i].ds_addr, dmap->dm_segs[i].ds_len,
+ ISSET(xa->flags, ATA_F_PIO) ? AHCI_PRDT_FLAG_INTR : 0);
+
+ htolem16(&cmd_slot->prdtl, dmap->dm_nsegs);
bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize,
(xa->flags & ATA_F_READ) ? BUS_DMASYNC_PREREAD :
BUS_DMASYNC_PREWRITE);
return (0);
-
-#ifdef DIAGNOSTIC
-diagerr:
- bus_dmamap_unload(sc->sc_dmat, dmap);
- return (1);
-#endif
}
void
@@ -1721,7 +1712,7 @@ ahci_unload_prdt(struct ahci_ccb *ccb)
xa->resid = 0;
else
xa->resid = xa->datalen -
- letoh32(ccb->ccb_cmd_hdr->prdbc);
+ lemtoh32(&ccb->ccb_cmd_hdr->prdbc);
}
}
@@ -3143,9 +3134,8 @@ ahci_hibernate_load_prdt(struct ahci_ccb *ccb)
if (buflen < seglen)
seglen = buflen;
- prd->dba_hi = htole32((u_int32_t)(data_bus_phys >> 32));
- prd->dba_lo = htole32((u_int32_t)data_bus_phys);
- prd->flags = htole32(seglen - 1);
+ ahci_load_prdt_seg(&prdt[i], data_bus_phys, seglen, 0);
+
data_addr += seglen;
buflen -= seglen;
}
diff --git a/sys/dev/ic/ahcivar.h b/sys/dev/ic/ahcivar.h
index 405498e2538..4fd9aea3270 100644
--- a/sys/dev/ic/ahcivar.h
+++ b/sys/dev/ic/ahcivar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ahcivar.h,v 1.4 2014/03/31 00:19:30 dlg Exp $ */
+/* $OpenBSD: ahcivar.h,v 1.5 2014/03/31 03:38:46 dlg Exp $ */
/*
* Copyright (c) 2006 David Gwynne <dlg@openbsd.org>
@@ -59,12 +59,11 @@ struct ahci_rfis {
} __packed;
struct ahci_prdt {
- u_int32_t dba_lo;
- u_int32_t dba_hi;
+ u_int64_t dba;
u_int32_t reserved;
u_int32_t flags;
#define AHCI_PRDT_FLAG_INTR (1<<31) /* interrupt on completion */
-} __packed;
+} __packed __aligned(8);
/* this makes ahci_cmd_table 512 bytes, supporting 128-byte alignment */
#define AHCI_MAX_PRDT 24