|
@@ -2519,6 +2519,20 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words)
|
|
#endif /* __BIG_ENDIAN */
|
|
#endif /* __BIG_ENDIAN */
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * ata_mmio_data_xfer - Transfer data by MMIO
|
|
|
|
+ * @ap: port to read/write
|
|
|
|
+ * @buf: data buffer
|
|
|
|
+ * @buflen: buffer length
|
|
|
|
+ * @do_write: read/write
|
|
|
|
+ *
|
|
|
|
+ * Transfer data from/to the device data register by MMIO.
|
|
|
|
+ *
|
|
|
|
+ * LOCKING:
|
|
|
|
+ * Inherited from caller.
|
|
|
|
+ *
|
|
|
|
+ */
|
|
|
|
+
|
|
static void ata_mmio_data_xfer(struct ata_port *ap, unsigned char *buf,
|
|
static void ata_mmio_data_xfer(struct ata_port *ap, unsigned char *buf,
|
|
unsigned int buflen, int write_data)
|
|
unsigned int buflen, int write_data)
|
|
{
|
|
{
|
|
@@ -2527,6 +2541,7 @@ static void ata_mmio_data_xfer(struct ata_port *ap, unsigned char *buf,
|
|
u16 *buf16 = (u16 *) buf;
|
|
u16 *buf16 = (u16 *) buf;
|
|
void __iomem *mmio = (void __iomem *)ap->ioaddr.data_addr;
|
|
void __iomem *mmio = (void __iomem *)ap->ioaddr.data_addr;
|
|
|
|
|
|
|
|
+ /* Transfer multiple of 2 bytes */
|
|
if (write_data) {
|
|
if (write_data) {
|
|
for (i = 0; i < words; i++)
|
|
for (i = 0; i < words; i++)
|
|
writew(le16_to_cpu(buf16[i]), mmio);
|
|
writew(le16_to_cpu(buf16[i]), mmio);
|
|
@@ -2534,19 +2549,76 @@ static void ata_mmio_data_xfer(struct ata_port *ap, unsigned char *buf,
|
|
for (i = 0; i < words; i++)
|
|
for (i = 0; i < words; i++)
|
|
buf16[i] = cpu_to_le16(readw(mmio));
|
|
buf16[i] = cpu_to_le16(readw(mmio));
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ /* Transfer trailing 1 byte, if any. */
|
|
|
|
+ if (unlikely(buflen & 0x01)) {
|
|
|
|
+ u16 align_buf[1] = { 0 };
|
|
|
|
+ unsigned char *trailing_buf = buf + buflen - 1;
|
|
|
|
+
|
|
|
|
+ if (write_data) {
|
|
|
|
+ memcpy(align_buf, trailing_buf, 1);
|
|
|
|
+ writew(le16_to_cpu(align_buf[0]), mmio);
|
|
|
|
+ } else {
|
|
|
|
+ align_buf[0] = cpu_to_le16(readw(mmio));
|
|
|
|
+ memcpy(trailing_buf, align_buf, 1);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * ata_pio_data_xfer - Transfer data by PIO
|
|
|
|
+ * @ap: port to read/write
|
|
|
|
+ * @buf: data buffer
|
|
|
|
+ * @buflen: buffer length
|
|
|
|
+ * @do_write: read/write
|
|
|
|
+ *
|
|
|
|
+ * Transfer data from/to the device data register by PIO.
|
|
|
|
+ *
|
|
|
|
+ * LOCKING:
|
|
|
|
+ * Inherited from caller.
|
|
|
|
+ *
|
|
|
|
+ */
|
|
|
|
+
|
|
static void ata_pio_data_xfer(struct ata_port *ap, unsigned char *buf,
|
|
static void ata_pio_data_xfer(struct ata_port *ap, unsigned char *buf,
|
|
unsigned int buflen, int write_data)
|
|
unsigned int buflen, int write_data)
|
|
{
|
|
{
|
|
- unsigned int dwords = buflen >> 1;
|
|
|
|
|
|
+ unsigned int words = buflen >> 1;
|
|
|
|
|
|
|
|
+ /* Transfer multiple of 2 bytes */
|
|
if (write_data)
|
|
if (write_data)
|
|
- outsw(ap->ioaddr.data_addr, buf, dwords);
|
|
|
|
|
|
+ outsw(ap->ioaddr.data_addr, buf, words);
|
|
else
|
|
else
|
|
- insw(ap->ioaddr.data_addr, buf, dwords);
|
|
|
|
|
|
+ insw(ap->ioaddr.data_addr, buf, words);
|
|
|
|
+
|
|
|
|
+ /* Transfer trailing 1 byte, if any. */
|
|
|
|
+ if (unlikely(buflen & 0x01)) {
|
|
|
|
+ u16 align_buf[1] = { 0 };
|
|
|
|
+ unsigned char *trailing_buf = buf + buflen - 1;
|
|
|
|
+
|
|
|
|
+ if (write_data) {
|
|
|
|
+ memcpy(align_buf, trailing_buf, 1);
|
|
|
|
+ outw(le16_to_cpu(align_buf[0]), ap->ioaddr.data_addr);
|
|
|
|
+ } else {
|
|
|
|
+ align_buf[0] = cpu_to_le16(inw(ap->ioaddr.data_addr));
|
|
|
|
+ memcpy(trailing_buf, align_buf, 1);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * ata_data_xfer - Transfer data from/to the data register.
|
|
|
|
+ * @ap: port to read/write
|
|
|
|
+ * @buf: data buffer
|
|
|
|
+ * @buflen: buffer length
|
|
|
|
+ * @do_write: read/write
|
|
|
|
+ *
|
|
|
|
+ * Transfer data from/to the device data register.
|
|
|
|
+ *
|
|
|
|
+ * LOCKING:
|
|
|
|
+ * Inherited from caller.
|
|
|
|
+ *
|
|
|
|
+ */
|
|
|
|
+
|
|
static void ata_data_xfer(struct ata_port *ap, unsigned char *buf,
|
|
static void ata_data_xfer(struct ata_port *ap, unsigned char *buf,
|
|
unsigned int buflen, int do_write)
|
|
unsigned int buflen, int do_write)
|
|
{
|
|
{
|
|
@@ -2556,6 +2628,16 @@ static void ata_data_xfer(struct ata_port *ap, unsigned char *buf,
|
|
ata_pio_data_xfer(ap, buf, buflen, do_write);
|
|
ata_pio_data_xfer(ap, buf, buflen, do_write);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * ata_pio_sector - Transfer ATA_SECT_SIZE (512 bytes) of data.
|
|
|
|
+ * @qc: Command on going
|
|
|
|
+ *
|
|
|
|
+ * Transfer ATA_SECT_SIZE of data from/to the ATA device.
|
|
|
|
+ *
|
|
|
|
+ * LOCKING:
|
|
|
|
+ * Inherited from caller.
|
|
|
|
+ */
|
|
|
|
+
|
|
static void ata_pio_sector(struct ata_queued_cmd *qc)
|
|
static void ata_pio_sector(struct ata_queued_cmd *qc)
|
|
{
|
|
{
|
|
int do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
|
|
int do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
|
|
@@ -2594,6 +2676,18 @@ static void ata_pio_sector(struct ata_queued_cmd *qc)
|
|
kunmap(page);
|
|
kunmap(page);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * __atapi_pio_bytes - Transfer data from/to the ATAPI device.
|
|
|
|
+ * @qc: Command on going
|
|
|
|
+ * @bytes: number of bytes
|
|
|
|
+ *
|
|
|
|
+ * Transfer Transfer data from/to the ATAPI device.
|
|
|
|
+ *
|
|
|
|
+ * LOCKING:
|
|
|
|
+ * Inherited from caller.
|
|
|
|
+ *
|
|
|
|
+ */
|
|
|
|
+
|
|
static void __atapi_pio_bytes(struct ata_queued_cmd *qc, unsigned int bytes)
|
|
static void __atapi_pio_bytes(struct ata_queued_cmd *qc, unsigned int bytes)
|
|
{
|
|
{
|
|
int do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
|
|
int do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
|
|
@@ -2645,6 +2739,17 @@ next_sg:
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * atapi_pio_bytes - Transfer data from/to the ATAPI device.
|
|
|
|
+ * @qc: Command on going
|
|
|
|
+ *
|
|
|
|
+ * Transfer Transfer data from/to the ATAPI device.
|
|
|
|
+ *
|
|
|
|
+ * LOCKING:
|
|
|
|
+ * Inherited from caller.
|
|
|
|
+ *
|
|
|
|
+ */
|
|
|
|
+
|
|
static void atapi_pio_bytes(struct ata_queued_cmd *qc)
|
|
static void atapi_pio_bytes(struct ata_queued_cmd *qc)
|
|
{
|
|
{
|
|
struct ata_port *ap = qc->ap;
|
|
struct ata_port *ap = qc->ap;
|