aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata
diff options
context:
space:
mode:
authorMikael Pettersson <mikpe@it.uu.se>2007-08-18 16:58:53 -0400
committerJeff Garzik <jeff@garzik.org>2007-08-23 05:32:07 -0400
commit78c4af0b43e152c40d232137f8cb637f2c58826a (patch)
treeeac864762ba107d041a1760823881704317e3836 /drivers/ata
parent8270bec40075eec9df8778c1d5da36ef0e535176 (diff)
pata_pdc2027x: PLL detection fixes
Previously I reported that the pata_pdc2027x PLL detection changes in kernel 2.6.22 broke the driver on my PowerMac: >pata_pdc2027x: Invalid PLL input clock 1691742kHz, give up! This is followed by a number of errors and speed reduction steps on the affected ports. There are two bugs in pata_pdc2027x's PLL detection code: 1. The PLL counter's start value is read before the chip is put in "test mode". Outside of test mode the counter is halted, and on the PowerMac the counter is zero because the chip hasn't been initialised by its BIOS. The fix is to move the read of the start value to after test mode is started, but before the mdelay() in test mode. This also improves the precision of the PLL detection. 2. The code to compute the number of PLL decrements during the mdelay() in test mode fails to consider that the PLL counter only is 30 bits wide. If there is a wraparound, it will compute an incorrect and much too large value. On the PowerMac, the start count is zero, the end count is a large 30-bit value, so wraparound occurs and an out of bounds PLL clock is detected. The fix is to mask the (start - end) computation to 30 bits. While debugging this I also noticed that pdc_read_counter() reads the two halves of the 30-bit PLL counter as 16-bit values, and then combines them as if the halves only are 15 bits wide. To avoid confusion, the halves should be read as 15-bit values. This patch implements all three changes. It fixes the PLL detection failure on my PowerMac, and doesn't cause any regressions on an x86 with an identical card. Signed-off-by: Mikael Pettersson <mikpe@it.uu.se> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/ata')
-rw-r--r--drivers/ata/pata_pdc2027x.c18
1 files changed, 9 insertions, 9 deletions
diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c
index 69a5aa4949f5..e3245b36269a 100644
--- a/drivers/ata/pata_pdc2027x.c
+++ b/drivers/ata/pata_pdc2027x.c
@@ -563,13 +563,13 @@ static long pdc_read_counter(struct ata_host *host)
563 u32 bccrl, bccrh, bccrlv, bccrhv; 563 u32 bccrl, bccrh, bccrlv, bccrhv;
564 564
565retry: 565retry:
566 bccrl = readl(mmio_base + PDC_BYTE_COUNT) & 0xffff; 566 bccrl = readl(mmio_base + PDC_BYTE_COUNT) & 0x7fff;
567 bccrh = readl(mmio_base + PDC_BYTE_COUNT + 0x100) & 0xffff; 567 bccrh = readl(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff;
568 rmb(); 568 rmb();
569 569
570 /* Read the counter values again for verification */ 570 /* Read the counter values again for verification */
571 bccrlv = readl(mmio_base + PDC_BYTE_COUNT) & 0xffff; 571 bccrlv = readl(mmio_base + PDC_BYTE_COUNT) & 0x7fff;
572 bccrhv = readl(mmio_base + PDC_BYTE_COUNT + 0x100) & 0xffff; 572 bccrhv = readl(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff;
573 rmb(); 573 rmb();
574 574
575 counter = (bccrh << 15) | bccrl; 575 counter = (bccrh << 15) | bccrl;
@@ -692,16 +692,16 @@ static long pdc_detect_pll_input_clock(struct ata_host *host)
692 struct timeval start_time, end_time; 692 struct timeval start_time, end_time;
693 long pll_clock, usec_elapsed; 693 long pll_clock, usec_elapsed;
694 694
695 /* Read current counter value */
696 start_count = pdc_read_counter(host);
697 do_gettimeofday(&start_time);
698
699 /* Start the test mode */ 695 /* Start the test mode */
700 scr = readl(mmio_base + PDC_SYS_CTL); 696 scr = readl(mmio_base + PDC_SYS_CTL);
701 PDPRINTK("scr[%X]\n", scr); 697 PDPRINTK("scr[%X]\n", scr);
702 writel(scr | (0x01 << 14), mmio_base + PDC_SYS_CTL); 698 writel(scr | (0x01 << 14), mmio_base + PDC_SYS_CTL);
703 readl(mmio_base + PDC_SYS_CTL); /* flush */ 699 readl(mmio_base + PDC_SYS_CTL); /* flush */
704 700
701 /* Read current counter value */
702 start_count = pdc_read_counter(host);
703 do_gettimeofday(&start_time);
704
705 /* Let the counter run for 100 ms. */ 705 /* Let the counter run for 100 ms. */
706 mdelay(100); 706 mdelay(100);
707 707
@@ -719,7 +719,7 @@ static long pdc_detect_pll_input_clock(struct ata_host *host)
719 usec_elapsed = (end_time.tv_sec - start_time.tv_sec) * 1000000 + 719 usec_elapsed = (end_time.tv_sec - start_time.tv_sec) * 1000000 +
720 (end_time.tv_usec - start_time.tv_usec); 720 (end_time.tv_usec - start_time.tv_usec);
721 721
722 pll_clock = (start_count - end_count) / 100 * 722 pll_clock = ((start_count - end_count) & 0x3fffffff) / 100 *
723 (100000000 / usec_elapsed); 723 (100000000 / usec_elapsed);
724 724
725 PDPRINTK("start[%ld] end[%ld] \n", start_count, end_count); 725 PDPRINTK("start[%ld] end[%ld] \n", start_count, end_count);