How to Map Contiguous Pages Allocated in the Kernel Space to the User Space

さてと、お買い物も済ませたし、今日の午後はドライバを kernel 2.6 に対応 させようかしら。はいはいもうすぐ出来ますからね、良い子にしててね、バブ バブバァ〜。はい、出来たわよ。

あれ、何ザマスこれ、ちょっとおかしいじゃないの。4096 byte まではちゃん と DMA 出来るのにページ境界またいだらハングしちゃったわ。いったいどう いうことなの? 大変、もうそろそろ子供達も学校から帰ってくるのに。どうしましょう、、、

という、家庭の主夫なら誰もが一度は経験する悩みを一発解決。

対象とする読者

というところでハマっている人を対象としています。まぁ要するに世界中のほとんどの人ですね。


*1) __get_free_pages() とか pci_alloc_consistent() とかを使おう。

*2) 分からない人は第 15 章 430 ページあたりを読もう。

げいいん

ここ (ch15 p431 の下の方)に 書いてあるように、__get_free_pages() とかを使って連続した複数ページを 確保すると、最初のページしか reference count がセットされない模様。 kernel 2.4 ではそんなことは無かった。2.6 の仕様らしい。ていうか /usr/src/linux/mm/page_alloc.c の set_page_refs() を見ると確かに

    set_page_count(page, 1);
とかなってる。変更の理由はパフォーマンス向上のため、と書いてあるけど、 普通の人はこんな仕様で大丈夫なのか?

対処法

良く分からんけど、ページを確保した後で確保した全てのページの reference count をセットしたら動いてるみたいでっす。

#define EHIBRAMORDER (3) /* 2^3 pages */
#define EHIBRAMSIZE (PAGE_SIZE * (1 << EHIBRAMORDER)) /* 32kbyte, 8pages */
int
pciemem_init(void)
{
    int i, ii;
    Page pageptr;

    (前略)

    /* allocate DMA read buffers */
    dmarbuf[i] = pci_alloc_consistent(pciemem[i], EHIBRAMSIZE, &dmarbufpa[i]);
    if (NULL == dmarbuf[i]) {
        printk(KERN_ALERT "pciemem: pci_alloc_consistent failed\n");
        for (ii = i-1; ii >= 0; ii--) {
            pci_free_consistent(pciemem[ii], EHIBRAMSIZE, dmarbuf[ii], dmarbufpa[ii]);
        }
        return (-ENOMEM);
    }
    pageptr = virt_to_page((unsigned long)dmarbuf[i]);
    for (ii = 0; ii < (1 << EHIBRAMORDER); ii++) {
      set_page_count(pageptr + ii, 1);
    }

    (後略)
}
ドライバを unload する時に kernel 樣がお怒りのメッセージを沢山吐きます が、普通の人はどうせ shutdown する時まで unload しないからキニシナイ。
void
pciemem_exit(void)
{
    (前略)
    for (i = 0; i < npciemem; i++) {
        pageptr = virt_to_page((unsigned long)dmarbuf[i]);
        for (ii = 0; ii < (1 << EHIBRAMORDER); ii++) {
          set_page_count(pageptr + ii, 0);
        }
        pci_free_consistent(pciemem[i], EHIBRAMSIZE, dmarbuf[i], dmarbufpa[i]);
    }
    (後略)
}

ああそうか、最初のページの reference count だけは pci_alloc/free_consistent() が面倒みてるから、ii = 0ってとこがii = 1じゃなきゃいけ ないのであった。直った直った。めでたしめでたし。



How to Top
おれんち
ためしにこんなんつけてみた。どうか? プライバシー侵害? うへへへへ