* piix dma setup code
@ 2004-05-18 11:19 Go Taniguchi
2004-05-19 1:34 ` Jeff Garzik
2004-05-19 16:51 ` Bartlomiej Zolnierkiewicz
0 siblings, 2 replies; 7+ messages in thread
From: Go Taniguchi @ 2004-05-18 11:19 UTC (permalink / raw)
To: linux-ide
[-- Attachment #1: Type: text/plain, Size: 1734 bytes --]
Hi,
I think that there are some problems in piix dma setup code.
At function piix_set_udmamode in ata_piix.c.These is same code in piix.c.
// if (!(reg48 & u_flag))
// pci_write_config_word(dev, 0x48, reg48|u_flag);
ICH PCI register offset 48 "Synchronous DMA Control Register" register size is
8bit. pci_write_config_byte is better.
// if (speed == XFER_UDMA_5) {
If speed is XFER_UDMA_6, base clock is set to low base clock.
It should be "speed >= XFER_UDMA_5". My ICH6 system reported XFER_UDMA_6,
// pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag);
// } else {
// pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
// }
// if (!(reg4a & u_speed)) {
If u_speed is 0, It is always the TRUE.
And I think that this 2bit comparison is wrong.
Probably It is "(reg4a & a_speed) != u_speed"
// pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
This set-up is done overwrite of with next line.
// pci_write_config_word(dev, 0x4a, reg4a|u_speed);
We should do and/or with original data.
So, these are pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed);
// }
// if (speed > XFER_UDMA_2) {
// if (!(reg54 & v_flag)) {
pci_write_config_word(dev, 0x54, reg54|v_flag);
If word accesses to reg54, reg55 is overwritten by old original data.
reg55 set already fails. It should be byte access.
// }
// } else {
// pci_write_config_word(dev, 0x54, reg54 & ~v_flag);
// }
I attched patch file.
Two registers changed it in 8bit access and removed reg44 which was not used.
Sorry for my very poor English.
[-- Attachment #2: piix-dma-setmode.patch --]
[-- Type: text/plain, Size: 3973 bytes --]
diff -urN linux-2.6.6.orig/drivers/ide/pci/piix.c linux-2.6.6/drivers/ide/pci/piix.c
--- linux-2.6.6.orig/drivers/ide/pci/piix.c 2004-05-17 19:09:33.132238864 +0900
+++ linux-2.6.6/drivers/ide/pci/piix.c 2004-05-17 19:08:57.778613432 +0900
@@ -436,15 +436,14 @@
int w_flag = 0x10 << drive->dn;
int u_speed = 0;
int sitre;
- u16 reg4042, reg44, reg48, reg4a, reg54;
- u8 reg55;
+ u16 reg4042, reg4a;
+ u8 reg48, reg54, reg55;
pci_read_config_word(dev, maslave, ®4042);
sitre = (reg4042 & 0x4000) ? 1 : 0;
- pci_read_config_word(dev, 0x44, ®44);
- pci_read_config_word(dev, 0x48, ®48);
+ pci_read_config_byte(dev, 0x48, ®48);
pci_read_config_word(dev, 0x4a, ®4a);
- pci_read_config_word(dev, 0x54, ®54);
+ pci_read_config_byte(dev, 0x54, ®54);
pci_read_config_byte(dev, 0x55, ®55);
switch(speed) {
@@ -466,30 +465,29 @@
if (speed >= XFER_UDMA_0) {
if (!(reg48 & u_flag))
- pci_write_config_word(dev, 0x48, reg48|u_flag);
+ pci_write_config_byte(dev, 0x48, reg48|u_flag);
if (speed == XFER_UDMA_5) {
pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag);
} else {
pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
}
- if (!(reg4a & u_speed)) {
- pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
- pci_write_config_word(dev, 0x4a, reg4a|u_speed);
+ if ((reg4a & a_speed) != u_speed) {
+ pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed);
}
if (speed > XFER_UDMA_2) {
if (!(reg54 & v_flag)) {
- pci_write_config_word(dev, 0x54, reg54|v_flag);
+ pci_write_config_byte(dev, 0x54, reg54|v_flag);
}
} else {
- pci_write_config_word(dev, 0x54, reg54 & ~v_flag);
+ pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
}
} else {
if (reg48 & u_flag)
- pci_write_config_word(dev, 0x48, reg48 & ~u_flag);
+ pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
if (reg4a & a_speed)
pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
if (reg54 & v_flag)
- pci_write_config_word(dev, 0x54, reg54 & ~v_flag);
+ pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
if (reg55 & w_flag)
pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
}
diff -urN linux-2.6.6.orig/drivers/scsi/ata_piix.c linux-2.6.6/drivers/scsi/ata_piix.c
--- linux-2.6.6.orig/drivers/scsi/ata_piix.c 2004-05-17 19:09:33.147236584 +0900
+++ linux-2.6.6/drivers/scsi/ata_piix.c 2004-05-17 19:08:13.861289880 +0900
@@ -424,16 +424,15 @@
int w_flag = 0x10 << drive_dn;
int u_speed = 0;
int sitre;
- u16 reg4042, reg44, reg48, reg4a, reg54;
- u8 reg55;
+ u16 reg4042, reg4a;
+ u8 reg48, reg54, reg55;
pci_read_config_word(dev, maslave, ®4042);
DPRINTK("reg4042 = 0x%04x\n", reg4042);
sitre = (reg4042 & 0x4000) ? 1 : 0;
- pci_read_config_word(dev, 0x44, ®44);
- pci_read_config_word(dev, 0x48, ®48);
+ pci_read_config_byte(dev, 0x48, ®48);
pci_read_config_word(dev, 0x4a, ®4a);
- pci_read_config_word(dev, 0x54, ®54);
+ pci_read_config_byte(dev, 0x54, ®54);
pci_read_config_byte(dev, 0x55, ®55);
switch(speed) {
@@ -450,22 +449,21 @@
}
if (!(reg48 & u_flag))
- pci_write_config_word(dev, 0x48, reg48|u_flag);
- if (speed == XFER_UDMA_5) {
+ pci_write_config_byte(dev, 0x48, reg48|u_flag);
+ if (speed >= XFER_UDMA_5) {
pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag);
} else {
pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
}
- if (!(reg4a & u_speed)) {
- pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
- pci_write_config_word(dev, 0x4a, reg4a|u_speed);
+ if ((reg4a & a_speed) != u_speed) {
+ pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed);
}
if (speed > XFER_UDMA_2) {
if (!(reg54 & v_flag)) {
- pci_write_config_word(dev, 0x54, reg54|v_flag);
+ pci_write_config_byte(dev, 0x54, reg54|v_flag);
}
} else {
- pci_write_config_word(dev, 0x54, reg54 & ~v_flag);
+ pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
}
}
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: piix dma setup code
2004-05-18 11:19 piix dma setup code Go Taniguchi
@ 2004-05-19 1:34 ` Jeff Garzik
2004-05-19 16:51 ` Bartlomiej Zolnierkiewicz
1 sibling, 0 replies; 7+ messages in thread
From: Jeff Garzik @ 2004-05-19 1:34 UTC (permalink / raw)
To: Go Taniguchi; +Cc: linux-ide, Bartlomiej Zolnierkiewicz
Go Taniguchi wrote:
> Hi,
>
> I think that there are some problems in piix dma setup code.
I agree, good catch.
I'll fix up both SATA and IDE, Bart...
Jeff
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: piix dma setup code
2004-05-18 11:19 piix dma setup code Go Taniguchi
2004-05-19 1:34 ` Jeff Garzik
@ 2004-05-19 16:51 ` Bartlomiej Zolnierkiewicz
2004-05-19 22:31 ` Jeff Garzik
1 sibling, 1 reply; 7+ messages in thread
From: Bartlomiej Zolnierkiewicz @ 2004-05-19 16:51 UTC (permalink / raw)
To: Go Taniguchi; +Cc: linux-ide, Jeff Garzik
On Tuesday 18 of May 2004 13:19, Go Taniguchi wrote:
> Hi,
>
> I think that there are some problems in piix dma setup code.
>
> At function piix_set_udmamode in ata_piix.c.These is same code in piix.c.
>
>
> // if (!(reg48 & u_flag))
> // pci_write_config_word(dev, 0x48, reg48|u_flag);
>
> ICH PCI register offset 48 "Synchronous DMA Control Register" register size
> is 8bit. pci_write_config_byte is better.
Yep.
> // if (speed == XFER_UDMA_5) {
>
> If speed is XFER_UDMA_6, base clock is set to low base clock.
> It should be "speed >= XFER_UDMA_5". My ICH6 system reported XFER_UDMA_6,
Jeff, does ICH6 support UDMA6?
ICH5 doesn't but ata_piix.c allows it.
> // pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag);
> // } else {
> // pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
> // }
> // if (!(reg4a & u_speed)) {
>
> If u_speed is 0, It is always the TRUE.
> And I think that this 2bit comparison is wrong.
> Probably It is "(reg4a & a_speed) != u_speed"
Yep, fortunately correct timings were always set thanks to:
> // pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
> This set-up is done overwrite of with next line.
> // pci_write_config_word(dev, 0x4a, reg4a|u_speed);
> We should do and/or with original data.
> So, these are pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) |
> u_speed);
>
> // }
> // if (speed > XFER_UDMA_2) {
> // if (!(reg54 & v_flag)) {
> pci_write_config_word(dev, 0x54, reg54|v_flag);
> If word accesses to reg54, reg55 is overwritten by old original data.
> reg55 set already fails. It should be byte access.
Yep, this is a real bug. Good catch.
> // }
> // } else {
> // pci_write_config_word(dev, 0x54, reg54 & ~v_flag);
> // }
>
> I attched patch file.
> Two registers changed it in 8bit access and removed reg44 which was not
> used.
Thanks.
Jeff, here is updated patch
(limits ata_piix.c to UDMA5 and fixes comments in piix.c).
linux-2.6.6-bk3-bzolnier/drivers/ide/pci/piix.c | 35 +++++++++--------------
linux-2.6.6-bk3-bzolnier/drivers/scsi/ata_piix.c | 30 +++++++------------
2 files changed, 27 insertions(+), 38 deletions(-)
diff -puN drivers/ide/pci/piix.c~piix-dma-setmode drivers/ide/pci/piix.c
--- linux-2.6.6-bk3/drivers/ide/pci/piix.c~piix-dma-setmode 2004-05-19 18:20:03.620392840 +0200
+++ linux-2.6.6-bk3-bzolnier/drivers/ide/pci/piix.c 2004-05-19 18:39:03.421116792 +0200
@@ -49,9 +49,9 @@
* pci_read_config_word(HWIF(drive)->pci_dev, 0x40, ®40);
* pci_read_config_word(HWIF(drive)->pci_dev, 0x42, ®42);
* pci_read_config_word(HWIF(drive)->pci_dev, 0x44, ®44);
- * pci_read_config_word(HWIF(drive)->pci_dev, 0x48, ®48);
+ * pci_read_config_byte(HWIF(drive)->pci_dev, 0x48, ®48);
* pci_read_config_word(HWIF(drive)->pci_dev, 0x4a, ®4a);
- * pci_read_config_word(HWIF(drive)->pci_dev, 0x54, ®54);
+ * pci_read_config_byte(HWIF(drive)->pci_dev, 0x54, ®54);
*
* Documentation
* Publically available from Intel web site. Errata documentation
@@ -432,15 +432,14 @@ static int piix_tune_chipset (ide_drive_
int w_flag = 0x10 << drive->dn;
int u_speed = 0;
int sitre;
- u16 reg4042, reg44, reg48, reg4a, reg54;
- u8 reg55;
+ u16 reg4042, reg4a;
+ u8 reg48, reg54, reg55;
pci_read_config_word(dev, maslave, ®4042);
sitre = (reg4042 & 0x4000) ? 1 : 0;
- pci_read_config_word(dev, 0x44, ®44);
- pci_read_config_word(dev, 0x48, ®48);
+ pci_read_config_byte(dev, 0x48, ®48);
pci_read_config_word(dev, 0x4a, ®4a);
- pci_read_config_word(dev, 0x54, ®54);
+ pci_read_config_byte(dev, 0x54, ®54);
pci_read_config_byte(dev, 0x55, ®55);
switch(speed) {
@@ -462,30 +461,26 @@ static int piix_tune_chipset (ide_drive_
if (speed >= XFER_UDMA_0) {
if (!(reg48 & u_flag))
- pci_write_config_word(dev, 0x48, reg48|u_flag);
+ pci_write_config_byte(dev, 0x48, reg48 | u_flag);
if (speed == XFER_UDMA_5) {
pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag);
} else {
pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
}
- if (!(reg4a & u_speed)) {
- pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
- pci_write_config_word(dev, 0x4a, reg4a|u_speed);
- }
+ if ((reg4a & a_speed) != u_speed)
+ pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed);
if (speed > XFER_UDMA_2) {
- if (!(reg54 & v_flag)) {
- pci_write_config_word(dev, 0x54, reg54|v_flag);
- }
- } else {
- pci_write_config_word(dev, 0x54, reg54 & ~v_flag);
- }
+ if (!(reg54 & v_flag))
+ pci_write_config_byte(dev, 0x54, reg54 | v_flag);
+ } else
+ pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
} else {
if (reg48 & u_flag)
- pci_write_config_word(dev, 0x48, reg48 & ~u_flag);
+ pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
if (reg4a & a_speed)
pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
if (reg54 & v_flag)
- pci_write_config_word(dev, 0x54, reg54 & ~v_flag);
+ pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
if (reg55 & w_flag)
pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
}
diff -puN drivers/scsi/ata_piix.c~piix-dma-setmode drivers/scsi/ata_piix.c
--- linux-2.6.6-bk3/drivers/scsi/ata_piix.c~piix-dma-setmode 2004-05-19 18:20:03.625392080 +0200
+++ linux-2.6.6-bk3-bzolnier/drivers/scsi/ata_piix.c 2004-05-19 18:34:04.613542448 +0200
@@ -187,7 +187,7 @@ static struct ata_port_info piix_port_in
.host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST |
PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR,
.pio_mask = 0x03, /* pio3-4 */
- .udma_mask = 0x7f, /* udma0-6 ; FIXME */
+ .udma_mask = 0x3f, /* udma0-5 ; FIXME */
.port_ops = &piix_sata_ops,
},
@@ -424,22 +424,20 @@ static void piix_set_udmamode (struct at
int w_flag = 0x10 << drive_dn;
int u_speed = 0;
int sitre;
- u16 reg4042, reg44, reg48, reg4a, reg54;
- u8 reg55;
+ u16 reg4042, reg4a;
+ u8 reg48, reg54, reg55;
pci_read_config_word(dev, maslave, ®4042);
DPRINTK("reg4042 = 0x%04x\n", reg4042);
sitre = (reg4042 & 0x4000) ? 1 : 0;
- pci_read_config_word(dev, 0x44, ®44);
- pci_read_config_word(dev, 0x48, ®48);
+ pci_read_config_byte(dev, 0x48, ®48);
pci_read_config_word(dev, 0x4a, ®4a);
- pci_read_config_word(dev, 0x54, ®54);
+ pci_read_config_byte(dev, 0x54, ®54);
pci_read_config_byte(dev, 0x55, ®55);
switch(speed) {
case XFER_UDMA_4:
case XFER_UDMA_2: u_speed = 2 << (drive_dn * 4); break;
- case XFER_UDMA_6:
case XFER_UDMA_5:
case XFER_UDMA_3:
case XFER_UDMA_1: u_speed = 1 << (drive_dn * 4); break;
@@ -450,23 +448,19 @@ static void piix_set_udmamode (struct at
}
if (!(reg48 & u_flag))
- pci_write_config_word(dev, 0x48, reg48|u_flag);
+ pci_write_config_byte(dev, 0x48, reg48 | u_flag);
if (speed == XFER_UDMA_5) {
pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag);
} else {
pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
}
- if (!(reg4a & u_speed)) {
- pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
- pci_write_config_word(dev, 0x4a, reg4a|u_speed);
- }
+ if ((reg4a & a_speed) != u_speed)
+ pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed);
if (speed > XFER_UDMA_2) {
- if (!(reg54 & v_flag)) {
- pci_write_config_word(dev, 0x54, reg54|v_flag);
- }
- } else {
- pci_write_config_word(dev, 0x54, reg54 & ~v_flag);
- }
+ if (!(reg54 & v_flag))
+ pci_write_config_byte(dev, 0x54, reg54 | v_flag);
+ } else
+ pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
}
/* move to PCI layer, integrate w/ MSI stuff */
_
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: piix dma setup code
2004-05-19 16:51 ` Bartlomiej Zolnierkiewicz
@ 2004-05-19 22:31 ` Jeff Garzik
2004-05-19 22:59 ` Bartlomiej Zolnierkiewicz
0 siblings, 1 reply; 7+ messages in thread
From: Jeff Garzik @ 2004-05-19 22:31 UTC (permalink / raw)
To: Bartlomiej Zolnierkiewicz; +Cc: Go Taniguchi, linux-ide, Nakajima, Jun
(added Jun to CC)
Bartlomiej Zolnierkiewicz wrote:
> On Tuesday 18 of May 2004 13:19, Go Taniguchi wrote:
>>If speed is XFER_UDMA_6, base clock is set to low base clock.
>>It should be "speed >= XFER_UDMA_5". My ICH6 system reported XFER_UDMA_6,
>
>
> Jeff, does ICH6 support UDMA6?
> ICH5 doesn't but ata_piix.c allows it.
Good question. AFAICS ICH5 and ICH6 are the same such that:
* PATA does not support UDMA6
* internal base clock is 133Mhz for UDMA5
* SATA PCI device exports, but completely ignores, PATA timing registers
So for ata_piix at least, I would prefer to do
* patch1: your patch, based on Go's patch
* patch2: only configure timing registers for PATA port (PATA is only
used when an #ifdef is defined)
* patch3: do not limit SATA to udma5
Jeff
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: piix dma setup code
2004-05-19 22:31 ` Jeff Garzik
@ 2004-05-19 22:59 ` Bartlomiej Zolnierkiewicz
2004-05-19 23:19 ` Jeff Garzik
0 siblings, 1 reply; 7+ messages in thread
From: Bartlomiej Zolnierkiewicz @ 2004-05-19 22:59 UTC (permalink / raw)
To: Jeff Garzik; +Cc: Go Taniguchi, linux-ide, Nakajima, Jun
On Thursday 20 of May 2004 00:31, Jeff Garzik wrote:
> (added Jun to CC)
>
> Bartlomiej Zolnierkiewicz wrote:
> > On Tuesday 18 of May 2004 13:19, Go Taniguchi wrote:
> >>If speed is XFER_UDMA_6, base clock is set to low base clock.
> >>It should be "speed >= XFER_UDMA_5". My ICH6 system reported XFER_UDMA_6,
> >
> > Jeff, does ICH6 support UDMA6?
> > ICH5 doesn't but ata_piix.c allows it.
>
> Good question. AFAICS ICH5 and ICH6 are the same such that:
> * PATA does not support UDMA6
> * internal base clock is 133Mhz for UDMA5
strange, it is 100MHz according to the datasheet
> * SATA PCI device exports, but completely ignores, PATA timing registers
>
> So for ata_piix at least, I would prefer to do
> * patch1: your patch, based on Go's patch
> * patch2: only configure timing registers for PATA port (PATA is only
> used when an #ifdef is defined)
> * patch3: do not limit SATA to udma5
OK
this reminds me that long time ago I spotted small bug in configuring PATA
timing registers in ata_piix.c but was too lazy to send a patch because code
is #ifdef-ed and bug was (is?) only for slave device 8)
Bartlomiej
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: piix dma setup code
2004-05-19 22:59 ` Bartlomiej Zolnierkiewicz
@ 2004-05-19 23:19 ` Jeff Garzik
2004-05-20 0:10 ` Bartlomiej Zolnierkiewicz
0 siblings, 1 reply; 7+ messages in thread
From: Jeff Garzik @ 2004-05-19 23:19 UTC (permalink / raw)
To: Bartlomiej Zolnierkiewicz; +Cc: Go Taniguchi, linux-ide, Nakajima, Jun
Bartlomiej Zolnierkiewicz wrote:
> On Thursday 20 of May 2004 00:31, Jeff Garzik wrote:
>
>>(added Jun to CC)
>>
>>Bartlomiej Zolnierkiewicz wrote:
>>
>>>On Tuesday 18 of May 2004 13:19, Go Taniguchi wrote:
>>>
>>>>If speed is XFER_UDMA_6, base clock is set to low base clock.
>>>>It should be "speed >= XFER_UDMA_5". My ICH6 system reported XFER_UDMA_6,
>>>
>>>Jeff, does ICH6 support UDMA6?
>>>ICH5 doesn't but ata_piix.c allows it.
>>
>>Good question. AFAICS ICH5 and ICH6 are the same such that:
>>* PATA does not support UDMA6
>>* internal base clock is 133Mhz for UDMA5
>
>
> strange, it is 100MHz according to the datasheet
Grab the latest ICH5 docs from developer.intel.com, they say the same
thing as the ICH6 docs. Section 5.16.6, "Ultra ATA/33/66/100 Timing":
> The internal Base Clock for Ultra ATA/100 (Mode 5) runs at 133 MHz, and
> the Cycle Time (CT) must be set for three Base Clocks. The ICH5 thus
> toggles the write strobe signal every 22.5 ns, transferring two bytes of
>>* SATA PCI device exports, but completely ignores, PATA timing registers
>>
>>So for ata_piix at least, I would prefer to do
>>* patch1: your patch, based on Go's patch
>>* patch2: only configure timing registers for PATA port (PATA is only
>>used when an #ifdef is defined)
>>* patch3: do not limit SATA to udma5
>
>
> OK
>
> this reminds me that long time ago I spotted small bug in configuring PATA
> timing registers in ata_piix.c but was too lazy to send a patch because code
> is #ifdef-ed and bug was (is?) only for slave device 8)
Patches welcome :) Slave device is a possibility on ICH6, which maps 4
SATA ports onto IDE primary/secondary master/slave, when not in evil
combined mode.
If you are motivated, I need to re-copy the drivers/ide/pci/piix.c
tune_chipset function to ata_piix.c, because I need to add MWDMA support
back to that function.
Jeff
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: piix dma setup code
2004-05-19 23:19 ` Jeff Garzik
@ 2004-05-20 0:10 ` Bartlomiej Zolnierkiewicz
0 siblings, 0 replies; 7+ messages in thread
From: Bartlomiej Zolnierkiewicz @ 2004-05-20 0:10 UTC (permalink / raw)
To: Jeff Garzik; +Cc: Go Taniguchi, linux-ide, Nakajima, Jun
On Thursday 20 of May 2004 01:19, Jeff Garzik wrote:
> Bartlomiej Zolnierkiewicz wrote:
> > On Thursday 20 of May 2004 00:31, Jeff Garzik wrote:
> >>(added Jun to CC)
> >>
> >>Bartlomiej Zolnierkiewicz wrote:
> >>>On Tuesday 18 of May 2004 13:19, Go Taniguchi wrote:
> >>>>If speed is XFER_UDMA_6, base clock is set to low base clock.
> >>>>It should be "speed >= XFER_UDMA_5". My ICH6 system reported
> >>>> XFER_UDMA_6,
> >>>
> >>>Jeff, does ICH6 support UDMA6?
> >>>ICH5 doesn't but ata_piix.c allows it.
> >>
> >>Good question. AFAICS ICH5 and ICH6 are the same such that:
> >>* PATA does not support UDMA6
> >>* internal base clock is 133Mhz for UDMA5
> >
> > strange, it is 100MHz according to the datasheet
>
> Grab the latest ICH5 docs from developer.intel.com, they say the same
> thing as the ICH6 docs. Section 5.16.6, "Ultra ATA/33/66/100 Timing":
Thanks.
> > The internal Base Clock for Ultra ATA/100 (Mode 5) runs at 133 MHz, and
> > the Cycle Time (CT) must be set for three Base Clocks. The ICH5 thus
> > toggles the write strobe signal every 22.5 ns, transferring two bytes of
> >
> >>* SATA PCI device exports, but completely ignores, PATA timing registers
> >>
> >>So for ata_piix at least, I would prefer to do
> >>* patch1: your patch, based on Go's patch
> >>* patch2: only configure timing registers for PATA port (PATA is only
> >>used when an #ifdef is defined)
> >>* patch3: do not limit SATA to udma5
> >
> > OK
> >
> > this reminds me that long time ago I spotted small bug in configuring
> > PATA timing registers in ata_piix.c but was too lazy to send a patch
> > because code is #ifdef-ed and bug was (is?) only for slave device 8)
>
> Patches welcome :) Slave device is a possibility on ICH6, which maps 4
> SATA ports onto IDE primary/secondary master/slave, when not in evil
> combined mode.
>
> If you are motivated, I need to re-copy the drivers/ide/pci/piix.c
> tune_chipset function to ata_piix.c, because I need to add MWDMA support
> back to that function.
no ->set_mwdmamode()? That is how I added MWDMA to libata.
The only change visible to existing drivers is that ata_host_set_udma()
no longer limits UDMA mode to the one of the slowest device (master & slave).
Dunno if it works now (it worked in 2.6.1).
linux-2.6.6-bk3-bzolnier/drivers/scsi/libata-core.c | 233 ++++++++++++++------
linux-2.6.6-bk3-bzolnier/include/linux/ata.h | 4
linux-2.6.6-bk3-bzolnier/include/linux/libata.h | 8
3 files changed, 181 insertions(+), 64 deletions(-)
diff -puN drivers/scsi/libata-core.c~pata_mwdma drivers/scsi/libata-core.c
--- linux-2.6.6-bk3/drivers/scsi/libata-core.c~pata_mwdma 2004-05-20 01:43:09.001800544 +0200
+++ linux-2.6.6-bk3-bzolnier/drivers/scsi/libata-core.c 2004-05-20 01:58:14.602128368 +0200
@@ -52,9 +52,10 @@ static unsigned int ata_busy_sleep (stru
static void __ata_dev_select (struct ata_port *ap, unsigned int device);
static void ata_dma_complete(struct ata_queued_cmd *qc, u8 host_stat);
static void ata_host_set_pio(struct ata_port *ap);
-static void ata_host_set_udma(struct ata_port *ap);
+static int ata_host_set_udma(struct ata_port *ap);
+static int ata_host_set_mwdma(struct ata_port *ap);
static void ata_dev_set_pio(struct ata_port *ap, unsigned int device);
-static void ata_dev_set_udma(struct ata_port *ap, unsigned int device);
+static void ata_dev_set_dma(struct ata_port *ap, unsigned int device);
static void ata_set_mode(struct ata_port *ap);
static int ata_qc_issue_prot(struct ata_queued_cmd *qc);
@@ -573,6 +574,12 @@ static void ata_dev_set_protocol(struct
dev->write_cmd = (cmd >> 8) & 0xff;
}
+static const char * mwdma_str[] = {
+ "MWDMA0",
+ "MWDMA1",
+ "MWDMA2",
+};
+
static const char * udma_str[] = {
"UDMA/16",
"UDMA/25",
@@ -585,32 +592,66 @@ static const char * udma_str[] = {
};
/**
- * ata_udma_string - convert UDMA bit offset to string
- * @udma_mask: mask of bits supported; only highest bit counts.
+ * ata_mode_string - convert mode bit offset to string
+ * @mode_mask: mask of bits supported; only highest bit counts.
+ * @max_mode: no. of bit to start checking from (counted from zero)
+ * @mode_str: pointer to array of strings representing speeds
*
* Determine string which represents the highest speed
- * (highest bit in @udma_mask).
+ * (highest bit in @mode_mask).
*
* LOCKING:
* None.
*
* RETURNS:
* Constant C string representing highest speed listed in
- * @udma_mask, or the constant C string "<n/a>".
+ * @mode_mask, or the constant C string "<n/a>".
*/
-static const char *ata_udma_string(unsigned int udma_mask)
+static const char *ata_mode_string(unsigned int mode_mask,
+ const unsigned int max_mode,
+ const char *mode_str[])
{
int i;
- for (i = 7; i >= 0; i--) {
- if (udma_mask & (1 << i))
- return udma_str[i];
+ for (i = max_mode; i >= 0; i--) {
+ if (mode_mask & (1 << i))
+ return mode_str[i];
}
return "<n/a>";
}
+static const char *ata_host_dma_string(struct ata_port *ap)
+{
+ u16 modes;
+
+ modes = ap->udma_mask;
+ if (modes & 0xff)
+ return ata_mode_string(modes, 7, udma_str);
+
+ modes = ap->mwdma_mask;
+ if (modes & 0xff)
+ return ata_mode_string(modes, 2, mwdma_str);
+
+ return "<n/a>";
+}
+
+static const char *ata_dev_dma_string(struct ata_device *dev)
+{
+ u16 modes;
+
+ modes = dev->id[ATA_ID_UDMA_MODES];
+ if (modes & 0xff)
+ return ata_mode_string(modes, 7, udma_str);
+
+ modes = dev->id[ATA_ID_MWDMA_MODES];
+ if (modes & 0xff)
+ return ata_mode_string(modes, 2, mwdma_str);
+
+ return "<n/a>";
+}
+
/**
* ata_pio_devchk - PATA device presence detection
* @ap: ATA channel to examine
@@ -976,6 +1017,15 @@ static inline void ata_dump_id(struct at
dev->id[93]);
}
+static int ata_dev_check_dma(struct ata_device *dev)
+{
+ if ((dev->id[ATA_ID_UDMA_MODES] & 0xff) ||
+ (dev->id[ATA_ID_MWDMA_MODES] & 0xff))
+ return 1;
+
+ return 0;
+}
+
/**
* ata_dev_identify - obtain IDENTIFY x DEVICE page
* @ap: port on which device we wish to probe resides
@@ -1002,7 +1052,7 @@ static void ata_dev_identify(struct ata_
{
struct ata_device *dev = &ap->device[device];
unsigned int i;
- u16 tmp, udma_modes;
+ u16 tmp;
u8 status;
struct ata_taskfile tf;
unsigned int using_edd;
@@ -1117,11 +1167,9 @@ retry:
goto err_out_nosup;
}
- /* we require UDMA support */
- udma_modes =
- tmp = dev->id[ATA_ID_UDMA_MODES];
- if ((tmp & 0xff) == 0) {
- printk(KERN_DEBUG "ata%u: no udma\n", ap->id);
+ /* we require UDMA or MWDMA support */
+ if (!ata_dev_check_dma(dev)) {
+ printk(KERN_DEBUG "ata%u: no udma or mwdma\n", ap->id);
goto err_out_nosup;
}
@@ -1157,7 +1205,7 @@ retry:
/* print device info to dmesg */
printk(KERN_INFO "ata%u: dev %u ATA, max %s, %Lu sectors:%s\n",
ap->id, device,
- ata_udma_string(udma_modes),
+ ata_dev_dma_string(dev),
(unsigned long long)dev->n_sectors,
dev->flags & ATA_DFLAG_LBA48 ? " lba48" : "");
}
@@ -1175,7 +1223,7 @@ retry:
/* print device info to dmesg */
printk(KERN_INFO "ata%u: dev %u ATAPI, max %s\n",
ap->id, device,
- ata_udma_string(udma_modes));
+ ata_dev_dma_string(dev));
}
DPRINTK("EXIT, drv_stat = 0x%x\n", ata_chk_status(ap));
@@ -1320,7 +1368,15 @@ static void ata_set_mode(struct ata_port
if (ap->flags & ATA_FLAG_PORT_DISABLED)
return;
- ata_host_set_udma(ap);
+ if (ata_host_set_udma(ap)) {
+ printk(KERN_WARNING "ata%u: no UDMA support, trying MWDMA\n",
+ ap->id);
+ if (ata_host_set_mwdma(ap)) {
+ printk(KERN_WARNING "ata%u: no MWDMA support, ignoring\n",
+ ap->id);
+ ap->ops->port_disable(ap);
+ }
+ }
if (ap->flags & ATA_FLAG_PORT_DISABLED)
return;
@@ -1334,8 +1390,8 @@ static void ata_set_mode(struct ata_port
ata_dev_set_pio(ap, 0);
ata_dev_set_pio(ap, 1);
} else {
- ata_dev_set_udma(ap, 0);
- ata_dev_set_udma(ap, 1);
+ ata_dev_set_dma(ap, 0);
+ ata_dev_set_dma(ap, 1);
}
if (ap->flags & ATA_FLAG_PORT_DISABLED)
@@ -1656,17 +1712,69 @@ err_out:
}
/**
+ * ata_host_set_mwdma -
+ * @ap:
+ *
+ * LOCKING:
+ */
+
+static int ata_host_set_mwdma(struct ata_port *ap)
+{
+ struct ata_device *master, *slave;
+ int mask;
+ unsigned int i;
+ int mwdma_mode = -1;
+
+ master = &ap->device[0];
+ slave = &ap->device[1];
+
+ assert(ata_dev_present(master) || ata_dev_present(slave));
+ assert((ap->flags & ATA_FLAG_PORT_DISABLED) == 0);
+
+ DPRINTK("mwdma masks: host 0x%X, master 0x%X, slave 0x%X\n",
+ ap->mwdma_mask,
+ (!ata_dev_present(master)) ? 0xff :
+ (master->id[ATA_ID_MWDMA_MODES] & 0xff),
+ (!ata_dev_present(slave)) ? 0xff :
+ (slave->id[ATA_ID_MWDMA_MODES] & 0xff));
+
+ /* require mwdma for host */
+ if (!ap->mwdma_mask)
+ return 1;
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ struct ata_device *dev = &ap->device[i];
+
+ if (ata_dev_present(dev)) {
+ mask = ap->mwdma_mask;
+ mask &= (dev->id[ATA_ID_MWDMA_MODES] & 0xff);
+ mwdma_mode = XFER_MW_DMA_0 + fls(mask) - 1;
+ DPRINTK("mask 0x%X fls(mask)-1 %u mwdma_mode 0x%X\n",
+ mask, fls(mask) - 1, mwdma_mode);
+ if (!mask)
+ continue;
+ dev->dma_mode = mwdma_mode;
+ dev->flags |= ATA_DFLAG_MWDMA;
+ if (ap->ops->set_mwdmamode)
+ ap->ops->set_mwdmamode(ap, dev, mwdma_mode);
+ }
+ }
+
+ return 0;
+}
+
+/**
* ata_host_set_udma -
* @ap:
*
* LOCKING:
*/
-static void ata_host_set_udma(struct ata_port *ap)
+static int ata_host_set_udma(struct ata_port *ap)
{
struct ata_device *master, *slave;
- u16 mask;
- unsigned int i, j;
+ int mask;
+ unsigned int i;
int udma_mode = -1;
master = &ap->device[0];
@@ -1682,43 +1790,28 @@ static void ata_host_set_udma(struct ata
(!ata_dev_present(slave)) ? 0xff :
(slave->id[ATA_ID_UDMA_MODES] & 0xff));
- mask = ap->udma_mask;
- if (ata_dev_present(master))
- mask &= (master->id[ATA_ID_UDMA_MODES] & 0xff);
- if (ata_dev_present(slave))
- mask &= (slave->id[ATA_ID_UDMA_MODES] & 0xff);
-
- i = XFER_UDMA_7;
- while (i >= XFER_UDMA_0) {
- j = i - XFER_UDMA_0;
- DPRINTK("mask 0x%X i 0x%X j %u\n", mask, i, j);
- if (mask & (1 << j)) {
- udma_mode = i;
- break;
- }
-
- i--;
- }
+ /* require udma for host */
+ if (ap->udma_mask < 0)
+ return 1;
- /* require udma for host and all attached devices */
- if (udma_mode < 0) {
- printk(KERN_WARNING "ata%u: no UltraDMA support, ignoring\n",
- ap->id);
- goto err_out;
- }
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ struct ata_device *dev = &ap->device[i];
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- if (ata_dev_present(&ap->device[i])) {
- ap->device[i].udma_mode = udma_mode;
+ if (ata_dev_present(dev)) {
+ mask = ap->udma_mask;
+ mask &= (dev->id[ATA_ID_UDMA_MODES] & 0xff);
+ udma_mode = XFER_UDMA_0 + fls(mask) - 1;
+ DPRINTK("mask 0x%X fls(mask)-1 %u udma_mode 0x%X\n",
+ mask, fls(mask) - 1, umda_mode);
+ if (!mask)
+ continue;
+ dev->dma_mode = udma_mode;
if (ap->ops->set_udmamode)
- ap->ops->set_udmamode(ap, &ap->device[i],
- udma_mode);
+ ap->ops->set_udmamode(ap, dev, udma_mode);
}
+ }
- return;
-
-err_out:
- ap->ops->port_disable(ap);
+ return 0;
}
/**
@@ -1744,7 +1837,7 @@ static void ata_dev_set_xfermode(struct
if (dev->flags & ATA_DFLAG_PIO)
tf.nsect = dev->pio_mode;
else
- tf.nsect = dev->udma_mode;
+ tf.nsect = dev->dma_mode;
/* do bus reset */
ata_tf_to_host(ap, &tf);
@@ -1763,14 +1856,14 @@ static void ata_dev_set_xfermode(struct
}
/**
- * ata_dev_set_udma -
+ * ata_dev_set_dma -
* @ap:
* @device:
*
* LOCKING:
*/
-static void ata_dev_set_udma(struct ata_port *ap, unsigned int device)
+static void ata_dev_set_dma(struct ata_port *ap, unsigned int device)
{
struct ata_device *dev = &ap->device[device];
@@ -1779,11 +1872,22 @@ static void ata_dev_set_udma(struct ata_
ata_dev_set_xfermode(ap, dev);
- assert((dev->udma_mode >= XFER_UDMA_0) &&
- (dev->udma_mode <= XFER_UDMA_7));
+ if (dev->flags & ATA_DFLAG_MWDMA)
+ goto mwdma_mode;
+
+ assert((dev->dma_mode >= XFER_UDMA_0) &&
+ (dev->dma_mode <= XFER_UDMA_7));
+ printk(KERN_INFO "ata%u: dev %u configured for %s\n",
+ ap->id, device,
+ udma_str[dev->dma_mode - XFER_UDMA_0]);
+ return;
+
+mwdma_mode:
+ assert((dev->dma_mode >= XFER_MW_DMA_0) &&
+ (dev->dma_mode <= XFER_MW_DMA_2));
printk(KERN_INFO "ata%u: dev %u configured for %s\n",
ap->id, device,
- udma_str[dev->udma_mode - XFER_UDMA_0]);
+ mwdma_str[dev->dma_mode - XFER_MW_DMA_0]);
}
/**
@@ -2936,6 +3040,7 @@ static void ata_host_init(struct ata_por
ap->host_set = host_set;
ap->port_no = port_no;
ap->pio_mask = ent->pio_mask;
+ ap->mwdma_mask = ent->mwdma_mask;
ap->udma_mask = ent->udma_mask;
ap->flags |= ent->host_flags;
ap->ops = ent->port_ops;
@@ -3048,7 +3153,7 @@ int ata_device_add(struct ata_probe_ent
"bmdma 0x%lX irq %lu\n",
ap->id,
ap->flags & ATA_FLAG_SATA ? 'S' : 'P',
- ata_udma_string(ent->udma_mask),
+ ata_host_dma_string(ap),
ap->ioaddr.cmd_addr,
ap->ioaddr.ctl_addr,
ap->ioaddr.bmdma_addr,
@@ -3280,6 +3385,7 @@ int ata_pci_init_one (struct pci_dev *pd
probe_ent->sht = port0->sht;
probe_ent->host_flags = port0->host_flags;
probe_ent->pio_mask = port0->pio_mask;
+ probe_ent->mwdma_mask = port0->mwdma_mask;
probe_ent->udma_mask = port0->udma_mask;
probe_ent->port_ops = port0->port_ops;
@@ -3302,6 +3408,7 @@ int ata_pci_init_one (struct pci_dev *pd
probe_ent2->sht = port1->sht;
probe_ent2->host_flags = port1->host_flags;
probe_ent2->pio_mask = port1->pio_mask;
+ probe_ent2->mwdma_mask = port1->mwdma_mask;
probe_ent2->udma_mask = port1->udma_mask;
probe_ent2->port_ops = port1->port_ops;
} else {
diff -puN include/linux/ata.h~pata_mwdma include/linux/ata.h
--- linux-2.6.6-bk3/include/linux/ata.h~pata_mwdma 2004-05-20 01:43:09.008799480 +0200
+++ linux-2.6.6-bk3-bzolnier/include/linux/ata.h 2004-05-20 01:43:09.019797808 +0200
@@ -41,6 +41,7 @@ enum {
ATA_ID_SERNO_OFS = 10,
ATA_ID_MAJOR_VER = 80,
ATA_ID_PIO_MODES = 64,
+ ATA_ID_MWDMA_MODES = 63,
ATA_ID_UDMA_MODES = 88,
ATA_ID_PIO4 = (1 << 1),
@@ -129,6 +130,9 @@ enum {
XFER_UDMA_2 = 0x42,
XFER_UDMA_1 = 0x41,
XFER_UDMA_0 = 0x40,
+ XFER_MW_DMA_2 = 0x22,
+ XFER_MW_DMA_1 = 0x21,
+ XFER_MW_DMA_0 = 0x20,
XFER_PIO_4 = 0x0C,
XFER_PIO_3 = 0x0B,
diff -puN include/linux/libata.h~pata_mwdma include/linux/libata.h
--- linux-2.6.6-bk3/include/linux/libata.h~pata_mwdma 2004-05-20 01:43:09.012798872 +0200
+++ linux-2.6.6-bk3-bzolnier/include/linux/libata.h 2004-05-20 01:43:09.020797656 +0200
@@ -90,6 +90,7 @@ enum {
ATA_DFLAG_MASTER = (1 << 2), /* is device 0? */
ATA_DFLAG_WCACHE = (1 << 3), /* has write cache we can
* (hopefully) flush? */
+ ATA_DFLAG_MWDMA = (1 << 4), /* use MWDMA instead of UDMA */
ATA_DEV_UNKNOWN = 0, /* unknown device */
ATA_DEV_ATA = 1, /* ATA device */
@@ -199,6 +200,7 @@ struct ata_probe_ent {
struct ata_ioports port[ATA_MAX_PORTS];
unsigned int n_ports;
unsigned int pio_mask;
+ unsigned int mwdma_mask;
unsigned int udma_mask;
unsigned int legacy_mode;
unsigned long irq;
@@ -257,7 +259,7 @@ struct ata_device {
unsigned int devno; /* 0 or 1 */
u16 id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */
unsigned int pio_mode;
- unsigned int udma_mode;
+ unsigned int dma_mode;
unsigned char vendor[8]; /* space-padded, not ASCIIZ */
unsigned char product[32]; /* WARNING: shorter than
@@ -288,6 +290,7 @@ struct ata_port {
unsigned int bus_state;
unsigned int port_state;
unsigned int pio_mask;
+ unsigned int mwdma_mask;
unsigned int udma_mask;
unsigned int cbl; /* cable type; ATA_CBL_xxx */
@@ -322,6 +325,8 @@ struct ata_port_operations {
void (*set_piomode) (struct ata_port *, struct ata_device *,
unsigned int);
+ void (*set_mwdmamode) (struct ata_port *, struct ata_device *,
+ unsigned int);
void (*set_udmamode) (struct ata_port *, struct ata_device *,
unsigned int);
@@ -355,6 +360,7 @@ struct ata_port_info {
Scsi_Host_Template *sht;
unsigned long host_flags;
unsigned long pio_mask;
+ unsigned long mwdma_mask;
unsigned long udma_mask;
struct ata_port_operations *port_ops;
};
_
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2004-05-20 0:09 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-05-18 11:19 piix dma setup code Go Taniguchi
2004-05-19 1:34 ` Jeff Garzik
2004-05-19 16:51 ` Bartlomiej Zolnierkiewicz
2004-05-19 22:31 ` Jeff Garzik
2004-05-19 22:59 ` Bartlomiej Zolnierkiewicz
2004-05-19 23:19 ` Jeff Garzik
2004-05-20 0:10 ` Bartlomiej Zolnierkiewicz
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).