summaryrefslogtreecommitdiffstats
path: root/sys/dev/ata/ata-lowlevel.c
diff options
context:
space:
mode:
authormarius <marius@FreeBSD.org>2013-02-02 21:57:06 +0000
committermarius <marius@FreeBSD.org>2013-02-02 21:57:06 +0000
commitfb83414a6ee4316b1c8a79da870c9c6e453535a6 (patch)
tree172a8c2a5da6ab5738825163bb13f0285c451cc9 /sys/dev/ata/ata-lowlevel.c
parent4b413731c8635fc79b2a2de63e9dbedca8cc7566 (diff)
downloadFreeBSD-src-fb83414a6ee4316b1c8a79da870c9c6e453535a6.zip
FreeBSD-src-fb83414a6ee4316b1c8a79da870c9c6e453535a6.tar.gz
Improve r238673 to additionally allow for odd-aligned buffers as
passed in by smartd of smartmontools. While at it, hint the compiler that 32-bit PIO is the most likely case (idea from Linux) and use bus_{read,write}_stream_2(9) instead of bus_{read,write}_multi_stream_2(9) for single count reads/writes. MFC after: 1 week
Diffstat (limited to 'sys/dev/ata/ata-lowlevel.c')
-rw-r--r--sys/dev/ata/ata-lowlevel.c49
1 files changed, 39 insertions, 10 deletions
diff --git a/sys/dev/ata/ata-lowlevel.c b/sys/dev/ata/ata-lowlevel.c
index de30603..6f83db7 100644
--- a/sys/dev/ata/ata-lowlevel.c
+++ b/sys/dev/ata/ata-lowlevel.c
@@ -846,14 +846,28 @@ ata_pio_read(struct ata_request *request, int length)
uint8_t *addr;
int size = min(request->transfersize, length);
int resid;
- uint8_t buf[2];
+ uint8_t buf[2] __aligned(sizeof(int16_t));
+#ifndef __NO_STRICT_ALIGNMENT
+ int i;
+#endif
addr = (uint8_t *)request->data + request->donecount;
- if (ch->flags & ATA_USE_16BIT || (size % sizeof(int32_t)) ||
- ((uintptr_t)addr % sizeof(int32_t))) {
- ATA_IDX_INSW_STRM(ch, ATA_DATA, (void*)addr, size / sizeof(int16_t));
+ if (__predict_false(ch->flags & ATA_USE_16BIT ||
+ (size % sizeof(int32_t)) || ((uintptr_t)addr % sizeof(int32_t)))) {
+#ifndef __NO_STRICT_ALIGNMENT
+ if (__predict_false((uintptr_t)addr % sizeof(int16_t))) {
+ for (i = 0, resid = size & ~1; resid > 0; resid -=
+ sizeof(int16_t)) {
+ *(uint16_t *)&buf = ATA_IDX_INW_STRM(ch, ATA_DATA);
+ addr[i++] = buf[0];
+ addr[i++] = buf[1];
+ }
+ } else
+#endif
+ ATA_IDX_INSW_STRM(ch, ATA_DATA, (void*)addr, size /
+ sizeof(int16_t));
if (size & 1) {
- ATA_IDX_INSW_STRM(ch, ATA_DATA, (void*)buf, 1);
+ *(uint16_t *)&buf = ATA_IDX_INW_STRM(ch, ATA_DATA);
(addr + (size & ~1))[0] = buf[0];
}
} else
@@ -875,15 +889,30 @@ ata_pio_write(struct ata_request *request, int length)
uint8_t *addr;
int size = min(request->transfersize, length);
int resid;
- uint8_t buf[2];
+ uint8_t buf[2] __aligned(sizeof(int16_t));
+#ifndef __NO_STRICT_ALIGNMENT
+ int i;
+#endif
+ size = min(request->transfersize, length);
addr = (uint8_t *)request->data + request->donecount;
- if (ch->flags & ATA_USE_16BIT || (size % sizeof(int32_t)) ||
- ((uintptr_t)addr % sizeof(int32_t))) {
- ATA_IDX_OUTSW_STRM(ch, ATA_DATA, (void*)addr, size / sizeof(int16_t));
+ if (__predict_false(ch->flags & ATA_USE_16BIT ||
+ (size % sizeof(int32_t)) || ((uintptr_t)addr % sizeof(int32_t)))) {
+#ifndef __NO_STRICT_ALIGNMENT
+ if (__predict_false((uintptr_t)addr % sizeof(int16_t))) {
+ for (i = 0, resid = size & ~1; resid > 0; resid -=
+ sizeof(int16_t)) {
+ buf[0] = addr[i++];
+ buf[1] = addr[i++];
+ ATA_IDX_OUTW_STRM(ch, ATA_DATA, *(uint16_t *)&buf);
+ }
+ } else
+#endif
+ ATA_IDX_OUTSW_STRM(ch, ATA_DATA, (void*)addr, size /
+ sizeof(int16_t));
if (size & 1) {
buf[0] = (addr + (size & ~1))[0];
- ATA_IDX_OUTSW_STRM(ch, ATA_DATA, (void*)buf, 1);
+ ATA_IDX_OUTW_STRM(ch, ATA_DATA, *(uint16_t *)&buf);
}
} else
ATA_IDX_OUTSL_STRM(ch, ATA_DATA, (void*)addr, size / sizeof(int32_t));
OpenPOWER on IntegriCloud