diff options
| author | JosephChan@via.com.tw <JosephChan@via.com.tw> | 2008-07-30 12:32:48 -0700 | 
|---|---|---|
| committer | Jeff Garzik <jgarzik@redhat.com> | 2008-07-31 01:39:31 -0400 | 
| commit | bfce5e0179ad059035df28558724ff60af708e09 (patch) | |
| tree | 0b00598e38e57559f48983ee22039e589278fbcb /drivers/ata | |
| parent | e8389f0c44652ee63d95bc0a7f8d565ac25dac77 (diff) | |
pata_via: add VX800 flag; add function for fixing h/w bugs
Add flag VIA_SATA_PATA for vx800, VX800 uses the same
chipset(0x0581/0x5324) as CX700, which has 1 PATA channel(Master/Slave)
and 1 SATA channel(Master/Slave) Add function <via_ata_tf_load>.  This is
to fix the internal bug of VIA chipsets, which will reset the device
register after changing the IEN bit in CTL register
Signed-off-by: Joseph Chan <josephchan@via.com.tw>
Cc: Tejun Heo <tj@kernel.org>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/ata')
| -rw-r--r-- | drivers/ata/pata_via.c | 64 | 
1 files changed, 63 insertions, 1 deletions
| diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index 708ed144ede9..57d951b11f2d 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -98,7 +98,8 @@ static const struct via_isa_bridge {  	u8 rev_max;  	u16 flags;  } via_isa_bridges[] = { -	{ "vx800",	PCI_DEVICE_ID_VIA_VX800,    0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, +	{ "vx800",	PCI_DEVICE_ID_VIA_VX800,    0x00, 0x2f, VIA_UDMA_133 | +	VIA_BAD_AST | VIA_SATA_PATA },  	{ "vt8237s",	PCI_DEVICE_ID_VIA_8237S,    0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },  	{ "vt8251",	PCI_DEVICE_ID_VIA_8251,     0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },  	{ "cx700",	PCI_DEVICE_ID_VIA_CX700,    0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST | VIA_SATA_PATA }, @@ -322,6 +323,65 @@ static void via_set_dmamode(struct ata_port *ap, struct ata_device *adev)  	via_do_set_mode(ap, adev, adev->dma_mode, tclock[mode], set_ast, udma[mode]);  } +/** + *	via_ata_sff_tf_load - send taskfile registers to host controller + *	@ap: Port to which output is sent + *	@tf: ATA taskfile register set + * + *	Outputs ATA taskfile to standard ATA host controller. + * + *	Note: This is to fix the internal bug of via chipsets, which + *  will reset the device register after changing the IEN bit on + *  ctl register + */ +static void via_ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) +{ +	struct ata_ioports *ioaddr = &ap->ioaddr; +	unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; + +	if (tf->ctl != ap->last_ctl) { +		iowrite8(tf->ctl, ioaddr->ctl_addr); +		iowrite8(tf->device, ioaddr->device_addr); +		ap->last_ctl = tf->ctl; +		ata_wait_idle(ap); +	} + +	if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { +		iowrite8(tf->hob_feature, ioaddr->feature_addr); +		iowrite8(tf->hob_nsect, ioaddr->nsect_addr); +		iowrite8(tf->hob_lbal, ioaddr->lbal_addr); +		iowrite8(tf->hob_lbam, ioaddr->lbam_addr); +		iowrite8(tf->hob_lbah, ioaddr->lbah_addr); +		VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n", +			tf->hob_feature, +			tf->hob_nsect, +			tf->hob_lbal, +			tf->hob_lbam, +			tf->hob_lbah); +	} + +	if (is_addr) { +		iowrite8(tf->feature, ioaddr->feature_addr); +		iowrite8(tf->nsect, ioaddr->nsect_addr); +		iowrite8(tf->lbal, ioaddr->lbal_addr); +		iowrite8(tf->lbam, ioaddr->lbam_addr); +		iowrite8(tf->lbah, ioaddr->lbah_addr); +		VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n", +			tf->feature, +			tf->nsect, +			tf->lbal, +			tf->lbam, +			tf->lbah); +	} + +	if (tf->flags & ATA_TFLAG_DEVICE) { +		iowrite8(tf->device, ioaddr->device_addr); +		VPRINTK("device 0x%X\n", tf->device); +	} + +	ata_wait_idle(ap); +} +  static struct scsi_host_template via_sht = {  	ATA_BMDMA_SHT(DRV_NAME),  }; @@ -332,11 +392,13 @@ static struct ata_port_operations via_port_ops = {  	.set_piomode	= via_set_piomode,  	.set_dmamode	= via_set_dmamode,  	.prereset	= via_pre_reset, +	.sff_tf_load = via_ata_tf_load,  };  static struct ata_port_operations via_port_ops_noirq = {  	.inherits	= &via_port_ops,  	.sff_data_xfer	= ata_sff_data_xfer_noirq, +	.sff_tf_load = via_ata_tf_load,  };  /** | 
