2

My team is trying to control the frequency of an Texas Instruments OMAP l138. The default frequency is 300 MHz and we want to put it to 372 MHz in a "complete" form: we would like not only to change the default value to the desired one (or at least configure it at startup), but also be capable of changing the value at run time.

Searching on the web about how to do this, we found an article which tells that one of the ways to do this is by an "echo" command:

echo 372000 /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed

We did some tests with this command and it runs fine with one problem: sometimes the first call to this echo command leads to a error message of "Division by zero in kernel":

PrintScreen with error message

In my personal tests, this error appeared always in the first call to the echo command. All the later calls worked without error. If, then, I reset my processor and calls the command again, the same problem occurs: the first call leads to this error and later calls work without problem.

So my questions are: what is causing this problem? And how could I solve it? (Obviously the answer "always type it twice" doesn't count!)

(Feel free to mention other ways of controlling the OMAP l138's frequency at real time as well!)

4

1 回答 1

1

在我看来,您在davinci_spi_cpufreq_transition()函数中除以零。在这个函数的某个地方(或在davinci_spi_cpufreq_transition调用的某个函数中)有一个错误的除法运算,它试图除以某个变量(在你的情况下)的值为 0。这显然是应该处理的错误情况在代码中正确,但实际上并非如此。

很难说出究竟是哪个代码导致了这种情况,因为我不知道您使用的是哪个内核。如果您可以提供指向内核存储库的链接,那会容易得多。虽然我在上游内核中找不到davinci_spi_cpufreq_transition ,但我在这里找到了。

davinci_spi_cpufreq_transition()函数似乎在drivers/spi/davinci_spi.c中。它调用davinci_spi_calc_clk_div() 函数。那里有2个部门操作。首先是:

prescale = ((clk_rate / hz) - 1);

第二个是:

if (hz < (clk_rate / (prescale + 1)))

其中之一可能导致“除以零”错误。我建议您通过以下方式修改davinci_spi_calc_clk_div()函数来跟踪哪一个(只需添加标记为“+”的行):

    static void davinci_spi_calc_clk_div(struct davinci_spi *davinci_spi)
    {
        struct davinci_spi_platform_data *pdata;
        unsigned long clk_rate;
        u32 hz, cs_num, prescale;

        pdata = davinci_spi->pdata;
        cs_num = davinci_spi->cs_num;
        hz = davinci_spi->speed;
        clk_rate = clk_get_rate(davinci_spi->clk);
+       printk(KERN_ERR "### hz = %u\n", hz);
        prescale = ((clk_rate / hz) - 1);
        if (prescale > 0xff)
            prescale = 0xff;

+       printk("### prescale + 1 = %u\n", prescale + 1UL);
        if (hz < (clk_rate / (prescale + 1)))
            prescale++;

        if (prescale < 2) {
            pr_info("davinci SPI controller min. prescale value is 2\n");
            prescale = 2;
        }

        clear_fmt_bits(davinci_spi->base, 0x0000ff00, cs_num);
        set_fmt_bits(davinci_spi->base, prescale << 8, cs_num);
    }

我的猜测 - 它是“hz”变量,在你的情况下为 0。如果是这样,您可能还需要将下一个调试行添加到davinci_spi_setup_transfer()函数:

        if (!hz)
                hz = spi->max_speed_hz;

+       printk(KERN_ERR "### setup_transfer: setting speed to %u\n", hz);
        davinci_spi->speed = hz;
        davinci_spi->cs_num = spi->chip_select;

完成所有这些修改后,重新构建内核,您可能会明白为什么会出现“div by zero”错误。只需在内核启动日志中查找以“###”开头的行。如果您不知道下一步该做什么——附上这些调试行,我会尽力帮助您。

于 2015-01-27T01:30:19.737 回答