cs5530/sc1200: add ->udma_filter methods
CS5530/SC1200 specifies that two drives on the same cable cannot mix UDMA/MDMA. Add {cs5530,sc1200}_udma_filter() to handle this. This also makes it possible to remove open-coded best DMA mode selection and use standard ide_use_dma()/ide_max_dma_mode() helpers. While at it bump version numbers. There should be no functionality changes caused by this patch. Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
This commit is contained in:
@@ -1,10 +1,10 @@
|
|||||||
/*
|
/*
|
||||||
* linux/drivers/ide/pci/cs5530.c Version 0.7 Sept 10, 2002
|
* linux/drivers/ide/pci/cs5530.c Version 0.71 Mar 10 2007
|
||||||
*
|
*
|
||||||
* Copyright (C) 2000 Andre Hedrick <andre@linux-ide.org>
|
* Copyright (C) 2000 Andre Hedrick <andre@linux-ide.org>
|
||||||
* Ditto of GNU General Public License.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2000 Mark Lord <mlord@pobox.com>
|
* Copyright (C) 2000 Mark Lord <mlord@pobox.com>
|
||||||
|
* Copyright (C) 2007 Bartlomiej Zolnierkiewicz
|
||||||
|
*
|
||||||
* May be copied or modified under the terms of the GNU General Public License
|
* May be copied or modified under the terms of the GNU General Public License
|
||||||
*
|
*
|
||||||
* Development of this chipset driver was funded
|
* Development of this chipset driver was funded
|
||||||
@@ -88,79 +88,66 @@ static void cs5530_tuneproc (ide_drive_t *drive, u8 pio) /* pio=255 means "autot
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cs5530_config_dma - select/set DMA and UDMA modes
|
* cs5530_udma_filter - UDMA filter
|
||||||
|
* @drive: drive
|
||||||
|
*
|
||||||
|
* cs5530_udma_filter() does UDMA mask filtering for the given drive
|
||||||
|
* taking into the consideration capabilities of the mate device.
|
||||||
|
*
|
||||||
|
* The CS5530 specifies that two drives sharing a cable cannot mix
|
||||||
|
* UDMA/MDMA. It has to be one or the other, for the pair, though
|
||||||
|
* different timings can still be chosen for each drive. We could
|
||||||
|
* set the appropriate timing bits on the fly, but that might be
|
||||||
|
* a bit confusing. So, for now we statically handle this requirement
|
||||||
|
* by looking at our mate drive to see what it is capable of, before
|
||||||
|
* choosing a mode for our own drive.
|
||||||
|
*
|
||||||
|
* Note: This relies on the fact we never fail from UDMA to MWDMA2
|
||||||
|
* but instead drop to PIO.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static u8 cs5530_udma_filter(ide_drive_t *drive)
|
||||||
|
{
|
||||||
|
ide_hwif_t *hwif = drive->hwif;
|
||||||
|
ide_drive_t *mate = &hwif->drives[(drive->dn & 1) ^ 1];
|
||||||
|
struct hd_driveid *mateid = mate->id;
|
||||||
|
u8 mask = hwif->ultra_mask;
|
||||||
|
|
||||||
|
if (mate->present == 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if ((mateid->capability & 1) && __ide_dma_bad_drive(mate) == 0) {
|
||||||
|
if ((mateid->field_valid & 4) && (mateid->dma_ultra & 7))
|
||||||
|
goto out;
|
||||||
|
if ((mateid->field_valid & 2) && (mateid->dma_mword & 7))
|
||||||
|
mask = 0;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cs5530_config_dma - set DMA/UDMA mode
|
||||||
* @drive: drive to tune
|
* @drive: drive to tune
|
||||||
*
|
*
|
||||||
* cs5530_config_dma() handles selection/setting of DMA/UDMA modes
|
* cs5530_config_dma() handles setting of DMA/UDMA mode
|
||||||
* for both the chipset and drive. The CS5530 has limitations about
|
* for both the chipset and drive.
|
||||||
* mixing DMA/UDMA on the same cable.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int cs5530_config_dma (ide_drive_t *drive)
|
static int cs5530_config_dma(ide_drive_t *drive)
|
||||||
{
|
{
|
||||||
int udma_ok = 1, mode = 0;
|
ide_hwif_t *hwif = drive->hwif;
|
||||||
ide_hwif_t *hwif = HWIF(drive);
|
unsigned int reg, timings = 0;
|
||||||
int unit = drive->select.b.unit;
|
unsigned long basereg;
|
||||||
ide_drive_t *mate = &hwif->drives[unit^1];
|
u8 unit = drive->dn & 1, mode = 0;
|
||||||
struct hd_driveid *id = drive->id;
|
|
||||||
unsigned int reg, timings = 0;
|
|
||||||
unsigned long basereg;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Default to DMA-off in case we run into trouble here.
|
* Default to DMA-off in case we run into trouble here.
|
||||||
*/
|
*/
|
||||||
hwif->dma_off_quietly(drive);
|
hwif->dma_off_quietly(drive);
|
||||||
|
|
||||||
/*
|
if (ide_use_dma(drive))
|
||||||
* The CS5530 specifies that two drives sharing a cable cannot
|
mode = ide_max_dma_mode(drive);
|
||||||
* mix UDMA/MDMA. It has to be one or the other, for the pair,
|
|
||||||
* though different timings can still be chosen for each drive.
|
|
||||||
* We could set the appropriate timing bits on the fly,
|
|
||||||
* but that might be a bit confusing. So, for now we statically
|
|
||||||
* handle this requirement by looking at our mate drive to see
|
|
||||||
* what it is capable of, before choosing a mode for our own drive.
|
|
||||||
*
|
|
||||||
* Note: This relies on the fact we never fail from UDMA to MWDMA_2
|
|
||||||
* but instead drop to PIO
|
|
||||||
*/
|
|
||||||
if (mate->present) {
|
|
||||||
struct hd_driveid *mateid = mate->id;
|
|
||||||
if (mateid && (mateid->capability & 1) &&
|
|
||||||
!__ide_dma_bad_drive(mate)) {
|
|
||||||
if ((mateid->field_valid & 4) &&
|
|
||||||
(mateid->dma_ultra & 7))
|
|
||||||
udma_ok = 1;
|
|
||||||
else if ((mateid->field_valid & 2) &&
|
|
||||||
(mateid->dma_mword & 7))
|
|
||||||
udma_ok = 0;
|
|
||||||
else
|
|
||||||
udma_ok = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Now see what the current drive is capable of,
|
|
||||||
* selecting UDMA only if the mate said it was ok.
|
|
||||||
*/
|
|
||||||
if (id && (id->capability & 1) && drive->autodma &&
|
|
||||||
!__ide_dma_bad_drive(drive)) {
|
|
||||||
if (udma_ok && (id->field_valid & 4) && (id->dma_ultra & 7)) {
|
|
||||||
if (id->dma_ultra & 4)
|
|
||||||
mode = XFER_UDMA_2;
|
|
||||||
else if (id->dma_ultra & 2)
|
|
||||||
mode = XFER_UDMA_1;
|
|
||||||
else if (id->dma_ultra & 1)
|
|
||||||
mode = XFER_UDMA_0;
|
|
||||||
}
|
|
||||||
if (!mode && (id->field_valid & 2) && (id->dma_mword & 7)) {
|
|
||||||
if (id->dma_mword & 4)
|
|
||||||
mode = XFER_MW_DMA_2;
|
|
||||||
else if (id->dma_mword & 2)
|
|
||||||
mode = XFER_MW_DMA_1;
|
|
||||||
else if (id->dma_mword & 1)
|
|
||||||
mode = XFER_MW_DMA_0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tell the drive to switch to the new mode; abort on failure.
|
* Tell the drive to switch to the new mode; abort on failure.
|
||||||
@@ -332,6 +319,7 @@ static void __devinit init_hwif_cs5530 (ide_hwif_t *hwif)
|
|||||||
hwif->ultra_mask = 0x07;
|
hwif->ultra_mask = 0x07;
|
||||||
hwif->mwdma_mask = 0x07;
|
hwif->mwdma_mask = 0x07;
|
||||||
|
|
||||||
|
hwif->udma_filter = cs5530_udma_filter;
|
||||||
hwif->ide_dma_check = &cs5530_config_dma;
|
hwif->ide_dma_check = &cs5530_config_dma;
|
||||||
if (!noautodma)
|
if (!noautodma)
|
||||||
hwif->autodma = 1;
|
hwif->autodma = 1;
|
||||||
|
@@ -1,7 +1,9 @@
|
|||||||
/*
|
/*
|
||||||
* linux/drivers/ide/pci/sc1200.c Version 0.91 28-Jan-2003
|
* linux/drivers/ide/pci/sc1200.c Version 0.92 Mar 10 2007
|
||||||
*
|
*
|
||||||
* Copyright (C) 2000-2002 Mark Lord <mlord@pobox.com>
|
* Copyright (C) 2000-2002 Mark Lord <mlord@pobox.com>
|
||||||
|
* Copyright (C) 2007 Bartlomiej Zolnierkiewicz
|
||||||
|
*
|
||||||
* May be copied or modified under the terms of the GNU General Public License
|
* May be copied or modified under the terms of the GNU General Public License
|
||||||
*
|
*
|
||||||
* Development of this chipset driver was funded
|
* Development of this chipset driver was funded
|
||||||
@@ -93,57 +95,33 @@ static const unsigned int sc1200_pio_timings[4][5] =
|
|||||||
*/
|
*/
|
||||||
//#define SC1200_BAD_PIO(timings) (((timings)&~0x80000000)==0x00009172)
|
//#define SC1200_BAD_PIO(timings) (((timings)&~0x80000000)==0x00009172)
|
||||||
|
|
||||||
static int sc1200_autoselect_dma_mode (ide_drive_t *drive)
|
/*
|
||||||
|
* The SC1200 specifies that two drives sharing a cable cannot mix
|
||||||
|
* UDMA/MDMA. It has to be one or the other, for the pair, though
|
||||||
|
* different timings can still be chosen for each drive. We could
|
||||||
|
* set the appropriate timing bits on the fly, but that might be
|
||||||
|
* a bit confusing. So, for now we statically handle this requirement
|
||||||
|
* by looking at our mate drive to see what it is capable of, before
|
||||||
|
* choosing a mode for our own drive.
|
||||||
|
*/
|
||||||
|
static u8 sc1200_udma_filter(ide_drive_t *drive)
|
||||||
{
|
{
|
||||||
int udma_ok = 1, mode = 0;
|
ide_hwif_t *hwif = drive->hwif;
|
||||||
ide_hwif_t *hwif = HWIF(drive);
|
ide_drive_t *mate = &hwif->drives[(drive->dn & 1) ^ 1];
|
||||||
int unit = drive->select.b.unit;
|
struct hd_driveid *mateid = mate->id;
|
||||||
ide_drive_t *mate = &hwif->drives[unit^1];
|
u8 mask = hwif->ultra_mask;
|
||||||
struct hd_driveid *id = drive->id;
|
|
||||||
|
|
||||||
/*
|
if (mate->present == 0)
|
||||||
* The SC1200 specifies that two drives sharing a cable cannot
|
goto out;
|
||||||
* mix UDMA/MDMA. It has to be one or the other, for the pair,
|
|
||||||
* though different timings can still be chosen for each drive.
|
if ((mateid->capability & 1) && __ide_dma_bad_drive(mate) == 0) {
|
||||||
* We could set the appropriate timing bits on the fly,
|
if ((mateid->field_valid & 4) && (mateid->dma_ultra & 7))
|
||||||
* but that might be a bit confusing. So, for now we statically
|
goto out;
|
||||||
* handle this requirement by looking at our mate drive to see
|
if ((mateid->field_valid & 2) && (mateid->dma_mword & 7))
|
||||||
* what it is capable of, before choosing a mode for our own drive.
|
mask = 0;
|
||||||
*/
|
|
||||||
if (mate->present) {
|
|
||||||
struct hd_driveid *mateid = mate->id;
|
|
||||||
if (mateid && (mateid->capability & 1) && !__ide_dma_bad_drive(mate)) {
|
|
||||||
if ((mateid->field_valid & 4) && (mateid->dma_ultra & 7))
|
|
||||||
udma_ok = 1;
|
|
||||||
else if ((mateid->field_valid & 2) && (mateid->dma_mword & 7))
|
|
||||||
udma_ok = 0;
|
|
||||||
else
|
|
||||||
udma_ok = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/*
|
out:
|
||||||
* Now see what the current drive is capable of,
|
return mask;
|
||||||
* selecting UDMA only if the mate said it was ok.
|
|
||||||
*/
|
|
||||||
if (id && (id->capability & 1) && hwif->autodma && !__ide_dma_bad_drive(drive)) {
|
|
||||||
if (udma_ok && (id->field_valid & 4) && (id->dma_ultra & 7)) {
|
|
||||||
if (id->dma_ultra & 4)
|
|
||||||
mode = XFER_UDMA_2;
|
|
||||||
else if (id->dma_ultra & 2)
|
|
||||||
mode = XFER_UDMA_1;
|
|
||||||
else if (id->dma_ultra & 1)
|
|
||||||
mode = XFER_UDMA_0;
|
|
||||||
}
|
|
||||||
if (!mode && (id->field_valid & 2) && (id->dma_mword & 7)) {
|
|
||||||
if (id->dma_mword & 4)
|
|
||||||
mode = XFER_MW_DMA_2;
|
|
||||||
else if (id->dma_mword & 2)
|
|
||||||
mode = XFER_MW_DMA_1;
|
|
||||||
else if (id->dma_mword & 1)
|
|
||||||
mode = XFER_MW_DMA_0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return mode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -250,7 +228,12 @@ static int sc1200_config_dma2 (ide_drive_t *drive, int mode)
|
|||||||
*/
|
*/
|
||||||
static int sc1200_config_dma (ide_drive_t *drive)
|
static int sc1200_config_dma (ide_drive_t *drive)
|
||||||
{
|
{
|
||||||
return sc1200_config_dma2(drive, sc1200_autoselect_dma_mode(drive));
|
u8 mode = 0;
|
||||||
|
|
||||||
|
if (ide_use_dma(drive))
|
||||||
|
mode = ide_max_dma_mode(drive);
|
||||||
|
|
||||||
|
return sc1200_config_dma2(drive, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -461,6 +444,7 @@ static void __devinit init_hwif_sc1200 (ide_hwif_t *hwif)
|
|||||||
hwif->serialized = hwif->mate->serialized = 1;
|
hwif->serialized = hwif->mate->serialized = 1;
|
||||||
hwif->autodma = 0;
|
hwif->autodma = 0;
|
||||||
if (hwif->dma_base) {
|
if (hwif->dma_base) {
|
||||||
|
hwif->udma_filter = sc1200_udma_filter;
|
||||||
hwif->ide_dma_check = &sc1200_config_dma;
|
hwif->ide_dma_check = &sc1200_config_dma;
|
||||||
hwif->ide_dma_end = &sc1200_ide_dma_end;
|
hwif->ide_dma_end = &sc1200_ide_dma_end;
|
||||||
if (!noautodma)
|
if (!noautodma)
|
||||||
|
Reference in New Issue
Block a user