Commit f931a5d5785d7b7c44871bd7ad2762e29dfddf29

Authored by Bartlomiej Zolnierkiewicz
Committed by David S. Miller
1 parent a13e4865fa

via82cxxx: workaround h/w bugs

Add custom struct ide_tp_ops instance to fix the internal bug of some VIA
chipsets which will reset the device register after changing the nIEN bit
in the device control register.

Based on commit bfce5e0 for pata_via host driver.

Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 1 changed file with 57 additions and 0 deletions Side-by-side Diff

drivers/ide/via82cxxx.c
... ... @@ -107,6 +107,7 @@
107 107 {
108 108 struct via_isa_bridge *via_config;
109 109 unsigned int via_80w;
  110 + u8 cached_device[2];
110 111 };
111 112  
112 113 /**
113 114  
... ... @@ -382,10 +383,66 @@
382 383 .cable_detect = via82cxxx_cable_detect,
383 384 };
384 385  
  386 +static void via_write_devctl(ide_hwif_t *hwif, u8 ctl)
  387 +{
  388 + struct via82cxxx_dev *vdev = hwif->host->host_priv;
  389 +
  390 + outb(ctl, hwif->io_ports.ctl_addr);
  391 + outb(vdev->cached_device[hwif->channel], hwif->io_ports.device_addr);
  392 +}
  393 +
  394 +static void __via_dev_select(ide_drive_t *drive, u8 select)
  395 +{
  396 + ide_hwif_t *hwif = drive->hwif;
  397 + struct via82cxxx_dev *vdev = hwif->host->host_priv;
  398 +
  399 + outb(select, hwif->io_ports.device_addr);
  400 + vdev->cached_device[hwif->channel] = select;
  401 +}
  402 +
  403 +static void via_dev_select(ide_drive_t *drive)
  404 +{
  405 + __via_dev_select(drive, drive->select | ATA_DEVICE_OBS);
  406 +}
  407 +
  408 +static void via_tf_load(ide_drive_t *drive, struct ide_taskfile *tf, u8 valid)
  409 +{
  410 + ide_hwif_t *hwif = drive->hwif;
  411 + struct ide_io_ports *io_ports = &hwif->io_ports;
  412 +
  413 + if (valid & IDE_VALID_FEATURE)
  414 + outb(tf->feature, io_ports->feature_addr);
  415 + if (valid & IDE_VALID_NSECT)
  416 + outb(tf->nsect, io_ports->nsect_addr);
  417 + if (valid & IDE_VALID_LBAL)
  418 + outb(tf->lbal, io_ports->lbal_addr);
  419 + if (valid & IDE_VALID_LBAM)
  420 + outb(tf->lbam, io_ports->lbam_addr);
  421 + if (valid & IDE_VALID_LBAH)
  422 + outb(tf->lbah, io_ports->lbah_addr);
  423 + if (valid & IDE_VALID_DEVICE)
  424 + __via_dev_select(drive, tf->device);
  425 +}
  426 +
  427 +const struct ide_tp_ops via_tp_ops = {
  428 + .exec_command = ide_exec_command,
  429 + .read_status = ide_read_status,
  430 + .read_altstatus = ide_read_altstatus,
  431 + .write_devctl = via_write_devctl,
  432 +
  433 + .dev_select = via_dev_select,
  434 + .tf_load = via_tf_load,
  435 + .tf_read = ide_tf_read,
  436 +
  437 + .input_data = ide_input_data,
  438 + .output_data = ide_output_data,
  439 +};
  440 +
385 441 static const struct ide_port_info via82cxxx_chipset __devinitdata = {
386 442 .name = DRV_NAME,
387 443 .init_chipset = init_chipset_via82cxxx,
388 444 .enablebits = { { 0x40, 0x02, 0x02 }, { 0x40, 0x01, 0x01 } },
  445 + .tp_ops = &via_tp_ops,
389 446 .port_ops = &via_port_ops,
390 447 .host_flags = IDE_HFLAG_PIO_NO_BLACKLIST |
391 448 IDE_HFLAG_POST_SET_MODE |