ide-io-std.c revision 6762511934e6e7287ce3c8baac0d52ef64e3787b
1 2#include <linux/kernel.h> 3#include <linux/ide.h> 4 5#if defined(CONFIG_ARM) || defined(CONFIG_M68K) || defined(CONFIG_MIPS) || \ 6 defined(CONFIG_PARISC) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) 7#include <asm/ide.h> 8#else 9#include <asm-generic/ide_iops.h> 10#endif 11 12/* 13 * Conventional PIO operations for ATA devices 14 */ 15 16static u8 ide_inb(unsigned long port) 17{ 18 return (u8) inb(port); 19} 20 21static void ide_outb(u8 val, unsigned long port) 22{ 23 outb(val, port); 24} 25 26/* 27 * MMIO operations, typically used for SATA controllers 28 */ 29 30static u8 ide_mm_inb(unsigned long port) 31{ 32 return (u8) readb((void __iomem *) port); 33} 34 35static void ide_mm_outb(u8 value, unsigned long port) 36{ 37 writeb(value, (void __iomem *) port); 38} 39 40void ide_exec_command(ide_hwif_t *hwif, u8 cmd) 41{ 42 if (hwif->host_flags & IDE_HFLAG_MMIO) 43 writeb(cmd, (void __iomem *)hwif->io_ports.command_addr); 44 else 45 outb(cmd, hwif->io_ports.command_addr); 46} 47EXPORT_SYMBOL_GPL(ide_exec_command); 48 49u8 ide_read_status(ide_hwif_t *hwif) 50{ 51 if (hwif->host_flags & IDE_HFLAG_MMIO) 52 return readb((void __iomem *)hwif->io_ports.status_addr); 53 else 54 return inb(hwif->io_ports.status_addr); 55} 56EXPORT_SYMBOL_GPL(ide_read_status); 57 58u8 ide_read_altstatus(ide_hwif_t *hwif) 59{ 60 if (hwif->host_flags & IDE_HFLAG_MMIO) 61 return readb((void __iomem *)hwif->io_ports.ctl_addr); 62 else 63 return inb(hwif->io_ports.ctl_addr); 64} 65EXPORT_SYMBOL_GPL(ide_read_altstatus); 66 67void ide_write_devctl(ide_hwif_t *hwif, u8 ctl) 68{ 69 if (hwif->host_flags & IDE_HFLAG_MMIO) 70 writeb(ctl, (void __iomem *)hwif->io_ports.ctl_addr); 71 else 72 outb(ctl, hwif->io_ports.ctl_addr); 73} 74EXPORT_SYMBOL_GPL(ide_write_devctl); 75 76void ide_tf_load(ide_drive_t *drive, struct ide_cmd *cmd) 77{ 78 ide_hwif_t *hwif = drive->hwif; 79 struct ide_io_ports *io_ports = &hwif->io_ports; 80 struct ide_taskfile *tf = &cmd->tf; 81 void (*tf_outb)(u8 addr, unsigned long port); 82 u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0; 83 u8 HIHI = (cmd->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF; 84 85 if (mmio) 86 tf_outb = ide_mm_outb; 87 else 88 tf_outb = ide_outb; 89 90 if (cmd->ftf_flags & IDE_FTFLAG_FLAGGED) 91 HIHI = 0xFF; 92 93 if (cmd->ftf_flags & IDE_FTFLAG_OUT_DATA) { 94 u16 data = (tf->hob_data << 8) | tf->data; 95 96 if (mmio) 97 writew(data, (void __iomem *)io_ports->data_addr); 98 else 99 outw(data, io_ports->data_addr); 100 } 101 102 if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE) 103 tf_outb(tf->hob_feature, io_ports->feature_addr); 104 if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_NSECT) 105 tf_outb(tf->hob_nsect, io_ports->nsect_addr); 106 if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_LBAL) 107 tf_outb(tf->hob_lbal, io_ports->lbal_addr); 108 if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_LBAM) 109 tf_outb(tf->hob_lbam, io_ports->lbam_addr); 110 if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_LBAH) 111 tf_outb(tf->hob_lbah, io_ports->lbah_addr); 112 113 if (cmd->tf_flags & IDE_TFLAG_OUT_FEATURE) 114 tf_outb(tf->feature, io_ports->feature_addr); 115 if (cmd->tf_flags & IDE_TFLAG_OUT_NSECT) 116 tf_outb(tf->nsect, io_ports->nsect_addr); 117 if (cmd->tf_flags & IDE_TFLAG_OUT_LBAL) 118 tf_outb(tf->lbal, io_ports->lbal_addr); 119 if (cmd->tf_flags & IDE_TFLAG_OUT_LBAM) 120 tf_outb(tf->lbam, io_ports->lbam_addr); 121 if (cmd->tf_flags & IDE_TFLAG_OUT_LBAH) 122 tf_outb(tf->lbah, io_ports->lbah_addr); 123 124 if (cmd->tf_flags & IDE_TFLAG_OUT_DEVICE) 125 tf_outb((tf->device & HIHI) | drive->select, 126 io_ports->device_addr); 127} 128EXPORT_SYMBOL_GPL(ide_tf_load); 129 130void ide_tf_read(ide_drive_t *drive, struct ide_cmd *cmd) 131{ 132 ide_hwif_t *hwif = drive->hwif; 133 struct ide_io_ports *io_ports = &hwif->io_ports; 134 struct ide_taskfile *tf = &cmd->tf; 135 void (*tf_outb)(u8 addr, unsigned long port); 136 u8 (*tf_inb)(unsigned long port); 137 u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0; 138 139 if (mmio) { 140 tf_outb = ide_mm_outb; 141 tf_inb = ide_mm_inb; 142 } else { 143 tf_outb = ide_outb; 144 tf_inb = ide_inb; 145 } 146 147 if (cmd->ftf_flags & IDE_FTFLAG_IN_DATA) { 148 u16 data; 149 150 if (mmio) 151 data = readw((void __iomem *)io_ports->data_addr); 152 else 153 data = inw(io_ports->data_addr); 154 155 tf->data = data & 0xff; 156 tf->hob_data = (data >> 8) & 0xff; 157 } 158 159 /* be sure we're looking at the low order bits */ 160 tf_outb(ATA_DEVCTL_OBS, io_ports->ctl_addr); 161 162 if (cmd->tf_flags & IDE_TFLAG_IN_ERROR) 163 tf->error = tf_inb(io_ports->feature_addr); 164 if (cmd->tf_flags & IDE_TFLAG_IN_NSECT) 165 tf->nsect = tf_inb(io_ports->nsect_addr); 166 if (cmd->tf_flags & IDE_TFLAG_IN_LBAL) 167 tf->lbal = tf_inb(io_ports->lbal_addr); 168 if (cmd->tf_flags & IDE_TFLAG_IN_LBAM) 169 tf->lbam = tf_inb(io_ports->lbam_addr); 170 if (cmd->tf_flags & IDE_TFLAG_IN_LBAH) 171 tf->lbah = tf_inb(io_ports->lbah_addr); 172 if (cmd->tf_flags & IDE_TFLAG_IN_DEVICE) 173 tf->device = tf_inb(io_ports->device_addr); 174 175 if (cmd->tf_flags & IDE_TFLAG_LBA48) { 176 tf_outb(ATA_HOB | ATA_DEVCTL_OBS, io_ports->ctl_addr); 177 178 if (cmd->tf_flags & IDE_TFLAG_IN_HOB_ERROR) 179 tf->hob_error = tf_inb(io_ports->feature_addr); 180 if (cmd->tf_flags & IDE_TFLAG_IN_HOB_NSECT) 181 tf->hob_nsect = tf_inb(io_ports->nsect_addr); 182 if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAL) 183 tf->hob_lbal = tf_inb(io_ports->lbal_addr); 184 if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAM) 185 tf->hob_lbam = tf_inb(io_ports->lbam_addr); 186 if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAH) 187 tf->hob_lbah = tf_inb(io_ports->lbah_addr); 188 } 189} 190EXPORT_SYMBOL_GPL(ide_tf_read); 191 192/* 193 * Some localbus EIDE interfaces require a special access sequence 194 * when using 32-bit I/O instructions to transfer data. We call this 195 * the "vlb_sync" sequence, which consists of three successive reads 196 * of the sector count register location, with interrupts disabled 197 * to ensure that the reads all happen together. 198 */ 199static void ata_vlb_sync(unsigned long port) 200{ 201 (void)inb(port); 202 (void)inb(port); 203 (void)inb(port); 204} 205 206/* 207 * This is used for most PIO data transfers *from* the IDE interface 208 * 209 * These routines will round up any request for an odd number of bytes, 210 * so if an odd len is specified, be sure that there's at least one 211 * extra byte allocated for the buffer. 212 */ 213void ide_input_data(ide_drive_t *drive, struct ide_cmd *cmd, void *buf, 214 unsigned int len) 215{ 216 ide_hwif_t *hwif = drive->hwif; 217 struct ide_io_ports *io_ports = &hwif->io_ports; 218 unsigned long data_addr = io_ports->data_addr; 219 u8 io_32bit = drive->io_32bit; 220 u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0; 221 222 len++; 223 224 if (io_32bit) { 225 unsigned long uninitialized_var(flags); 226 227 if ((io_32bit & 2) && !mmio) { 228 local_irq_save(flags); 229 ata_vlb_sync(io_ports->nsect_addr); 230 } 231 232 if (mmio) 233 __ide_mm_insl((void __iomem *)data_addr, buf, len / 4); 234 else 235 insl(data_addr, buf, len / 4); 236 237 if ((io_32bit & 2) && !mmio) 238 local_irq_restore(flags); 239 240 if ((len & 3) >= 2) { 241 if (mmio) 242 __ide_mm_insw((void __iomem *)data_addr, 243 (u8 *)buf + (len & ~3), 1); 244 else 245 insw(data_addr, (u8 *)buf + (len & ~3), 1); 246 } 247 } else { 248 if (mmio) 249 __ide_mm_insw((void __iomem *)data_addr, buf, len / 2); 250 else 251 insw(data_addr, buf, len / 2); 252 } 253} 254EXPORT_SYMBOL_GPL(ide_input_data); 255 256/* 257 * This is used for most PIO data transfers *to* the IDE interface 258 */ 259void ide_output_data(ide_drive_t *drive, struct ide_cmd *cmd, void *buf, 260 unsigned int len) 261{ 262 ide_hwif_t *hwif = drive->hwif; 263 struct ide_io_ports *io_ports = &hwif->io_ports; 264 unsigned long data_addr = io_ports->data_addr; 265 u8 io_32bit = drive->io_32bit; 266 u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0; 267 268 len++; 269 270 if (io_32bit) { 271 unsigned long uninitialized_var(flags); 272 273 if ((io_32bit & 2) && !mmio) { 274 local_irq_save(flags); 275 ata_vlb_sync(io_ports->nsect_addr); 276 } 277 278 if (mmio) 279 __ide_mm_outsl((void __iomem *)data_addr, buf, len / 4); 280 else 281 outsl(data_addr, buf, len / 4); 282 283 if ((io_32bit & 2) && !mmio) 284 local_irq_restore(flags); 285 286 if ((len & 3) >= 2) { 287 if (mmio) 288 __ide_mm_outsw((void __iomem *)data_addr, 289 (u8 *)buf + (len & ~3), 1); 290 else 291 outsw(data_addr, (u8 *)buf + (len & ~3), 1); 292 } 293 } else { 294 if (mmio) 295 __ide_mm_outsw((void __iomem *)data_addr, buf, len / 2); 296 else 297 outsw(data_addr, buf, len / 2); 298 } 299} 300EXPORT_SYMBOL_GPL(ide_output_data); 301 302const struct ide_tp_ops default_tp_ops = { 303 .exec_command = ide_exec_command, 304 .read_status = ide_read_status, 305 .read_altstatus = ide_read_altstatus, 306 .write_devctl = ide_write_devctl, 307 308 .tf_load = ide_tf_load, 309 .tf_read = ide_tf_read, 310 311 .input_data = ide_input_data, 312 .output_data = ide_output_data, 313}; 314