FreeBSD: Unable to allocate bus resource

一台很舊、很舊的 server,在從 FreeBSD 8.4,升級到 FreeBSD 10.0 之後,開機時,就出現以下的訊息:

em0: <Intel(R) PRO/1000 Legacy Network Connection 1.0.6> mem 0xfe680000-0xfe69ffff,0xfe660000-0xfe67ffff irq 48 at device 2.0 on pci5
em0: 0x20 bytes of rid 0x20 res 4 failed (0, 0xffffffff).
em0: Unable to allocate bus resource: ioport
em0: Allocation of PCI resources failed
device_attach: em0 attach returned 6

其實不只出現在 em,ahc 也出現類似的訊息:

ahc0: <Adaptec aic7899 Ultra160 SCSI adapter> mem 0xfe8fe000-0xfe8fefff irq 72 at device 6.0 on pci7
ahc0: 0x100 bytes of rid 0x10 res 4 failed (0, 0xffffffff).
ahc0: can't allocate register resources
device_attach: ahc0 attach returned 12

所以我就用我破爛的英文,去 FreeBSD forum 問了,大家人也都很好,可以無視於我破爛的英文,認真回覆我的問題。

會發生這個問題,有一個共同的特徵,就是使用的電腦大概是很舊很舊的,可是放在機房裡面的 server,溫度、濕度都保持的剛剛好,灰塵又少,所以通常壽命又特別長,用上個十年也不會太奇怪。

我一開始因為沒有注意到 ahc 也沒有載入,所以一直以為是em driver的問題, 好險前輩指出,這是 PCI bus 的 bug,em0 是無辜的。

修改 system bootstrap configuration

回到正題,目前論壇裡面可以找到兩個解決法,都是要在 /boot/loader.conf 加上以下其中一個設定:

  • hw.pci.realloc_bars=1
  • hint.agp.0.disabled=1

hw.pci.realloc_bars=1 是之前就可以 Google 到的解法,不過不一定有用,目的是在初始化設備時,如果發生分配 BARs (Base Address Registers,可以參考維基百科的說明) 在設備 firmware 中指定位置的資源失敗時,就重新分配新的位置。

不過很不幸,解決不了我的問題。

後者hint.agp.0.disabled=1 是把大多數人不用,但在這些老機器上偏偏還有的 AGP 給關掉,然後就可以避免 AGP 搶了 em0 的記憶體位置,詳細情形可以看這裡的說明,這個解法對於大多數人都有幫助,不過很不幸,一樣救不了我。

如果你也有類似的問題,希望以上兩個方法,其中一個就可以解決你的問題。

如果你還很菜的話,提醒你,如果要測試,可以用  FreeBSD 的光碟片或者 USB 開機,然後在 Welcome to FreeBSD 的畫面,按 3 進入 loader prompt,然後打:

set hint.agp.0.disabled=1
boot

打了 boot 後,FreeBSD 會繼續開機,開機後,選擇 live CD,就可以檢查該載入的設備,是不是都有正常載入。

如果你懶的試到底是哪個設定有用,就兩個都用也無妨。

找到有用的,記得放到/boot/loader.conf,如果兩個設定都沒有用, 就只好試試我的方法了。

如果你想直接看我的方法,就直接按這裡吧!

為什麼驅動失敗?

 

先看一個 dmesg 裡面一個正常驅動的 em0,已經先把無關的訊息拿掉:

pcib0: <ACPI Host-PCI bridge> port 0xcf8-0xcff on acpi0
pci0: <ACPI PCI bus> on pcib0
pci0: <unknown> at device 0.1 (no driver attached)
pcib1: <ACPI PCI-PCI bridge> at device 3.0 on pci0
pci2: <ACPI PCI bus> on pcib1
pcib3: <ACPI PCI-PCI bridge> at device 31.0 on pci2
pci3: <ACPI PCI bus> on pcib3
em0: <Intel(R) PRO/1000 Legacy Network Connection 1.0.6> port 0x2040-0x207f mem 0xfe8c0000-0xfe8dffff irq 30 at device 7.0 on pci3
em0: Ethernet address: 00:0e:0c:31:69:26

先看 em0,這東西是在 pci3 上面的,往上看,又可以看到 pci3 是在 pcib3 上面的,b 代表的是 bridge,然後 pcib3 又在 pci2 上面,pci2 又在 pcib1 上面,pcib1 在 pci0 上面,pci0 在 pcib0 上面,pcib0 在 ahpi0 上面。

這裡提到的上面 (on),指的是硬體資源的分配,當 xx on yy 時,代表 xx 會使用到 yy 的硬體資源。

所以如果用 devinfo -r 看的話,有興趣可以用 devinfo -r 來研究。

再來看無法驅動的 em0:

acpi0: <A M I OEMRSDT> on motherboard
pcib0: <ACPI Host-PCI bridge> port 0xcf8-0xcff on acpi0
pci0: <ACPI PCI bus> on pcib0
pcib4: <ACPI PCI-PCI bridge> at device 4.0 on pci0
pci2: <ACPI PCI bus> on pcib4
pcib5: <ACPI PCI-PCI bridge> at device 29.0 on pci2
pcib5: failed to allocate initial I/O port window: 0xb000-0xbfff
pci5: <ACPI PCI bus> on pcib5
em0: <Intel(R) PRO/1000 Legacy Network Connection 1.0.6> mem 0xfe680000-0xfe69ffff,0xfe660000-0xfe67ffff irq 48 at device 2.0 on pci5
em0: 0x20 bytes of rid 0x20 res 4 failed (0, 0xffffffff).
em0: Unable to allocate bus resource: ioport
em0: Allocation of PCI resources failed
device_attach: em0 attach returned 6

只要看紅色就好,em0→ pci5 → pcib5,pcib5 無法拿到 0xb000 到 0xbfff 這段記憶體作為 I/O port window,連帶造成 em0 也拿不到,所以就秀出了 em0: Unable to allocate bus resource: ioport 的訊息。


那 0xb000 到 0xbfff 這段記憶體到哪邊去了?有興趣一樣可以用 devinfo 觀察,在我這兒的狀況,是被 pcib4 拿走了,可是 pcib5 → pci2→ pcib4,pcib4 為何不把資源給 em 呢?


凡夫俗子是不會去研究這些 PCI、PCI bridge 是怎麼運作的,所以其實我真的不懂,所以這部份希望可以有人來更正,我以後如果有一天搞清楚了,也會回來修正。


pcib4 不把資源給 em 的原因,要用 verbose boot 比較看的出來 (在 /boot/loader.conf 加上 boot_verbose="YES",或者開機的 Weclome 選單裡面可以 enable),打開後重開機,就可以看到 pcib4 標記為 special decode    ISA,所以跟 pcib4 要資源的其他 PCI bridge,就都必須是標記為 ISA decoding,但是 pcib5 並沒有這樣的標記,所以就沒有要到資源。

pcib4:   domain            0
pcib4:   secondary bus     2
pcib4:   subordinate bus   5
pcib4:   I/O decode        0xb000-0xbfff
pcib4:   memory decode     0xfe300000-0xfe7fffff
pcib4:   prefetched decode 0xff300000-0xff6fffff
pcib4:   special decode    ISA
 
pcib4: I/O range 0xb000-0xbfff overlaps with an ISA alias
pcib5: failed to allocate initial I/O port window: 0xb000-0xbfff
pcib4: allocated memory range (0xfe500000-0xfe6fffff) for rid 20 of pcib5
pcib4: allocated prefetch range (0xff500000-0xff5fffff) for rid 24 of pcib5
pcib5:   domain            0
pcib5:   secondary bus     5
pcib5:   subordinate bus   5
pcib5:   memory decode     0xfe500000-0xfe6fffff
pcib5:   prefetched decode 0xff500000-0xff5fffff

同樣的狀況發生在 ahc0,pci7 → pcib3 → pci6 →  pcib1,pcib1 一樣被標記為 ISA decoding,但是 pcib3 沒有,所以得到 ahc0: can't allocate register resources 的訊息。

至於甚麼是 ISA decoding,為什麼會有這樣的限制?也是 Google 到的,這是根據規格,這些疊來疊去的 PCI bridge,當一個 PCI bridge 被標記為 ISA decoding 時,所有跟他要資源的 PCI bridge,因為會將需求 forward 給要資源來源的 PCI bridge,所以如果沒有同樣被標記為 ISA decoding,就會發生錯誤。

再度強調一次,以上那一堆 PCI、PCI bridge、ISA decoding,希望有人趕緊來幫我更正。

所以,該怎麼辦呢?

新不如舊 

 

就跟情人一樣,常常有了新情人,才覺得舊情人比較好。

這些 PCI、PCI bridge 搞來搞去,目前是 FreeBSD 裡面一個「"new" PCI-PCI bridge driver」負責的,可以看這個地方,了解「"new" PCI-PCI bridge driver」是甚麼東西。

而這個 「"new" PCI-PCI bridge driver」,是在 FreeBSD 9.0 開始成為系統預設的 PCI-PCI bridge driver,在 FreeBSD 8.4 中,還沒有這個預設值

那麼我的舊機器,在舊版本的 FreeBSD 8.4 中是可以正確驅動 em 和 ahc 的,所以我不要用新版本 FreeBSD 才有的「"new" PCI-PCI bridge driver」就好了。

方法是製作一個自己的 kernel,在裡面加上一行:

nooptions       NEW_PCIB

換上新的 kernel 和舊 PCI-PCI bridge driver,終於可以收工了。

以下節錄 dmesg 中 ahc 的部分:

pcib0:  port 0xcf8-0xcff on acpi0
pci0:  on pcib0
pcib1:  at device 3.0 on pci0
pci6:  on pcib1
pcib3:  at device 31.0 on pci6
pci7:  on pcib3
ahc0:  port 0xd400-0xd4ff mem 0xfe8fe000-0xfe8fefff irq 72 at device 6.0 on pci7
aic7899: Ultra160 Wide Channel A, SCSI Id=7, 32/253 SCBs
ahc1:  port 0xd800-0xd8ff mem 0xfe8ff000-0xfe8fffff irq 73 at device 6.1 on pci7
aic7899: Ultra160 Wide Channel B, SCSI Id=7, 32/253 SCBs

以下節錄 dmesg 中 em 的部分:

pcib0:  port 0xcf8-0xcff on acpi0
pci0:  on pcib0
pcib4:  at device 4.0 on pci0
pci2:  on pcib4
pcib5:  at device 29.0 on pci2
pci5:  on pcib5
em0:  port 0xb400-0xb41f mem 0xfe680000-0xfe69ffff,0xfe660000-0xfe67ffff irq 48 at device 2.0 on pci5
em0: Ethernet address: 00:20:ed:xx:xx:xx
em1:  port 0xb800-0xb81f mem 0xfe6e0000-0xfe6fffff,0xfe6c0000-0xfe6dffff irq 49 at device 3.0 on pci5
em1: Ethernet address: 00:20:ed:xx:xx:xx