Re: [PATCH 2.6.23-rc3] pata_pdc2027x: PLL detection fixes

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Mikael Pettersson wrote:
> 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.

The wrap-around situation was handled by checking if (pll_clock < 0)
in pdc_hardware_init() then retrying pdc_detect_pll_input_clock().
But it seems not working correctly. :(

> 
> 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@xxxxxxxx>
> ---
>  drivers/ata/pata_pdc2027x.c |   18 +++++++++---------
>  1 files changed, 9 insertions(+), 9 deletions(-)
> 
> diff -rupN linux-2.6.23-rc3/drivers/ata/pata_pdc2027x.c linux-2.6.23-rc3.pata_pdc2027x-pll-detection-fixes/drivers/ata/pata_pdc2027x.c
> --- linux-2.6.23-rc3/drivers/ata/pata_pdc2027x.c	2007-07-09 22:01:31.000000000 +0200
> +++ linux-2.6.23-rc3.pata_pdc2027x-pll-detection-fixes/drivers/ata/pata_pdc2027x.c	2007-08-18 21:53:40.000000000 +0200
> @@ -563,13 +563,13 @@ static long pdc_read_counter(struct ata_
>  	u32 bccrl, bccrh, bccrlv, bccrhv;
>  
>  retry:
> -	bccrl = readl(mmio_base + PDC_BYTE_COUNT) & 0xffff;
> -	bccrh = readl(mmio_base + PDC_BYTE_COUNT + 0x100) & 0xffff;
> +	bccrl = readl(mmio_base + PDC_BYTE_COUNT) & 0x7fff;
> +	bccrh = readl(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff;
>  	rmb();
>  
>  	/* Read the counter values again for verification */
> -	bccrlv = readl(mmio_base + PDC_BYTE_COUNT) & 0xffff;
> -	bccrhv = readl(mmio_base + PDC_BYTE_COUNT + 0x100) & 0xffff;
> +	bccrlv = readl(mmio_base + PDC_BYTE_COUNT) & 0x7fff;
> +	bccrhv = readl(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff;
>  	rmb();

Agreed this looks safer. (Although the high bit 15 of the counter
is always zero during my test.)

>  
>  	counter = (bccrh << 15) | bccrl;
> @@ -692,16 +692,16 @@ static long pdc_detect_pll_input_clock(s
>  	struct timeval start_time, end_time;
>  	long pll_clock, usec_elapsed;
>  
> -	/* Read current counter value */
> -	start_count = pdc_read_counter(host);
> -	do_gettimeofday(&start_time);
> -
>  	/* Start the test mode */
>  	scr = readl(mmio_base + PDC_SYS_CTL);
>  	PDPRINTK("scr[%X]\n", scr);
>  	writel(scr | (0x01 << 14), mmio_base + PDC_SYS_CTL);
>  	readl(mmio_base + PDC_SYS_CTL); /* flush */
>  
> +	/* Read current counter value */
> +	start_count = pdc_read_counter(host);
> +	do_gettimeofday(&start_time);
> +
>  	/* Let the counter run for 100 ms. */
>  	mdelay(100);

Looks good (though reading the start_count before or after doesn't
really matter since we can treat "start the test mode" as part of
the 100ms delay time).

>  
> @@ -719,7 +719,7 @@ static long pdc_detect_pll_input_clock(s
>  	usec_elapsed = (end_time.tv_sec - start_time.tv_sec) * 1000000 +
>  		(end_time.tv_usec - start_time.tv_usec);
>  
> -	pll_clock = (start_count - end_count) / 100 *
> +	pll_clock = ((start_count - end_count) & 0x3fffffff) / 100 *
>  		(100000000 / usec_elapsed);
>  
>  	PDPRINTK("start[%ld] end[%ld] \n", start_count, end_count);
> 
> 

Hmm, this one alone looks like the real fix for the problem. I guess my
previous patch changing pll_clock from "(start_count - end_count) * 10"
to "(start_count - end_count) / 100 * (100000000 / usec_elapsed)" somehow
broke the (pll_clock < 0) check...

Thanks for fixing it. Maybe we also need this fix for the IDE
pdc202xx_new.c driver...

Acked-by: Albert Lee <albertcc@xxxxxxxxxx>
--
albert

-
To unsubscribe from this list: send the line "unsubscribe linux-ide" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Filesystems]     [Linux SCSI]     [Linux RAID]     [Git]     [Kernel Newbies]     [Linux Newbie]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Samba]     [Device Mapper]

  Powered by Linux