Author: marius
Date: Sat Feb  2 21:57:06 2013
New Revision: 246257
URL: http://svnweb.freebsd.org/changeset/base/246257

Log:
  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

Modified:
  head/sys/dev/ata/ata-all.h
  head/sys/dev/ata/ata-lowlevel.c

Modified: head/sys/dev/ata/ata-all.h
==============================================================================
--- head/sys/dev/ata/ata-all.h  Sat Feb  2 21:51:14 2013        (r246256)
+++ head/sys/dev/ata/ata-all.h  Sat Feb  2 21:57:06 2013        (r246257)
@@ -698,6 +698,8 @@ MALLOC_DECLARE(M_ATA);
 
 #define ATA_INW(res, offset) \
        bus_read_2((res), (offset))
+#define ATA_INW_STRM(res, offset) \
+       bus_read_stream_2((res), (offset))
 #define ATA_INL(res, offset) \
        bus_read_4((res), (offset))
 #define ATA_INSW(res, offset, addr, count) \
@@ -712,6 +714,8 @@ MALLOC_DECLARE(M_ATA);
        bus_write_1((res), (offset), (value))
 #define ATA_OUTW(res, offset, value) \
        bus_write_2((res), (offset), (value))
+#define ATA_OUTW_STRM(res, offset, value) \
+       bus_write_stream_2((res), (offset), (value))
 #define ATA_OUTL(res, offset, value) \
        bus_write_4((res), (offset), (value))
 #define ATA_OUTSW(res, offset, addr, count) \
@@ -729,6 +733,9 @@ MALLOC_DECLARE(M_ATA);
 #define ATA_IDX_INW(ch, idx) \
        ATA_INW(ch->r_io[idx].res, ch->r_io[idx].offset)
 
+#define ATA_IDX_INW_STRM(ch, idx) \
+       ATA_INW_STRM(ch->r_io[idx].res, ch->r_io[idx].offset)
+
 #define ATA_IDX_INL(ch, idx) \
        ATA_INL(ch->r_io[idx].res, ch->r_io[idx].offset)
 
@@ -750,6 +757,9 @@ MALLOC_DECLARE(M_ATA);
 #define ATA_IDX_OUTW(ch, idx, value) \
        ATA_OUTW(ch->r_io[idx].res, ch->r_io[idx].offset, value)
 
+#define ATA_IDX_OUTW_STRM(ch, idx, value) \
+       ATA_OUTW_STRM(ch->r_io[idx].res, ch->r_io[idx].offset, value)
+
 #define ATA_IDX_OUTL(ch, idx, value) \
        ATA_OUTL(ch->r_io[idx].res, ch->r_io[idx].offset, value)
 

Modified: head/sys/dev/ata/ata-lowlevel.c
==============================================================================
--- head/sys/dev/ata/ata-lowlevel.c     Sat Feb  2 21:51:14 2013        
(r246256)
+++ head/sys/dev/ata/ata-lowlevel.c     Sat Feb  2 21:57:06 2013        
(r246257)
@@ -846,14 +846,28 @@ ata_pio_read(struct ata_request *request
     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 *reques
     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));
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to