===================================================================
@@ -68,14 +68,18 @@ static int efar_cable_detect(struct ata_
return ATA_CBL_PATA80;
}
+static DEFINE_SPINLOCK(efar_lock);
+
static void efar_set_timings(struct ata_port *ap, struct ata_device *adev,
u8 pio, bool use_mwdma)
{
struct pci_dev *dev = to_pci_dev(ap->host->dev);
+ unsigned long flags;
unsigned int is_slave = (adev->devno != 0);
u8 master_port = ap->port_no ? 0x42 : 0x40;
u16 master_data;
u8 slave_data;
+ u8 udma_enable;
int control = 0;
/*
@@ -103,6 +107,8 @@ static void efar_set_timings(struct ata_
/* Enable DMA timing only */
control |= 8; /* PIO cycles in PIO0 */
+ spin_lock_irqsave(&efar_lock, flags);
+
pci_read_config_word(dev, master_port, &master_data);
/* Set PPE, IE, and TIME as appropriate */
@@ -127,6 +133,12 @@ static void efar_set_timings(struct ata_
pci_write_config_word(dev, master_port, master_data);
if (is_slave)
pci_write_config_byte(dev, 0x44, slave_data);
+
+ pci_read_config_byte(dev, 0x48, &udma_enable);
+ udma_enable &= ~(1 << (2 * ap->port_no + adev->devno));
+ pci_write_config_byte(dev, 0x48, udma_enable);
+
+ spin_unlock_irqrestore(&efar_lock, flags);
}
/**
@@ -159,16 +171,19 @@ static void efar_set_piomode(struct ata_
static void efar_set_dmamode (struct ata_port *ap, struct ata_device *adev)
{
struct pci_dev *dev = to_pci_dev(ap->host->dev);
+ unsigned long flags;
u8 speed = adev->dma_mode;
int devid = adev->devno + 2 * ap->port_no;
u8 udma_enable;
- pci_read_config_byte(dev, 0x48, &udma_enable);
-
if (speed >= XFER_UDMA_0) {
unsigned int udma = speed - XFER_UDMA_0;
u16 udma_timing;
+ spin_lock_irqsave(&efar_lock, flags);
+
+ pci_read_config_byte(dev, 0x48, &udma_enable);
+
udma_enable |= (1 << devid);
/* Load the UDMA mode number */
@@ -176,13 +191,13 @@ static void efar_set_dmamode (struct ata
udma_timing &= ~(7 << (4 * devid));
udma_timing |= udma << (4 * devid);
pci_write_config_word(dev, 0x4A, udma_timing);
- } else {
+
+ pci_write_config_byte(dev, 0x48, udma_enable);
+
+ spin_unlock_irqrestore(&efar_lock, flags);
+ } else
/* MWDMA is driven by the PIO timings. */
efar_set_timings(ap, adev, ata_mwdma_to_pio(speed), 1);
-
- udma_enable &= ~(1 << devid);
- }
- pci_write_config_byte(dev, 0x48, udma_enable);
}
static struct scsi_host_template efar_sht = {