1. 程式人生 > 其它 >pci中斷號分配_龍芯中斷初探(二)

pci中斷號分配_龍芯中斷初探(二)

技術標籤:pci中斷號分配

710f66c055c7eda5d860a121cd69adc9.png簡介 “

龍芯核心中斷分析第二部分,中斷註冊。

”0 3時鐘中斷註冊

這裡想不到一個更好的引言了,直接開門見山,龍芯時鐘中斷初始化函式是r4k_clockevent_init。程式碼如下:

 1intr4k_clockevent_init(void)
2{
3unsignedintcpu=smp_processor_id();
4structclock_event_device*cd;
5unsignedintirq,min_delta;
6
7/* 8*Withvectoredinterruptsthingsaregettingplatformspecific. 9*get_c0_compare_intisahooktoallowaplatformtoreturnthe10*interruptnumberofitsliking.11*/
12irq=get_c0_compare_int();
13
14cd=&per_cpu(mips_clockevent_device,cpu);
15
16cd->name="MIPS";
17cd->features=CLOCK_EVT_FEAT_ONESHOT|
18CLOCK_EVT_FEAT_C3STOP|
19CLOCK_EVT_FEAT_PERCPU;
20
21min_delta=calculate_min_delta();
22
23cd->rating=300;
24cd->irq=irq;
25cd->cpumask=cpumask_of(cpu);
26cd->set_next_event=mips_next_event;
27cd->event_handler=mips_event_handler;
28
29clockevents_config_and_register(cd,mips_hpt_frequency,min_delta,0x7fffffff);
30
31if(cp0_timer_irq_installed)
32return0;
33
34cp0_timer_irq_installed=1;
35setup_irq(irq,&c0_compare_irqaction);
36
37return0;
38}

這是裝置初始化函式,流程很清晰,獲取中斷號、初始化裝置名稱、識別符號、頻率、以及裝置需要的一些鉤子函式。這裡我們且關注中斷相關部分。首先是中斷號從哪裡來的。其次是action結構裡是什麼。從程式碼中看到irq是呼叫函式得來的。如下:

1unsignedint__weakget_c0_compare_int(void)2{
3returnMIPS_CPU_IRQ_BASE+cp0_compare_irq;
4}
5
6cp0_compare_irq=(read_c0_intctl()>>INTCTLB_IPTI)&7;

這就相當於時鐘中斷中斷號從暫存器裡讀出來的。那接著看看action結構:

1structirqactionc0_compare_irqaction={
2.handler=c0_compare_interrupt,
3/*4*IRQF_SHARED:Thetimerinterruptmaybesharedwithotherinterrupts5*suchasperfcounterandFDCinterrupts.6*/
7.flags=IRQF_PERCPU|IRQF_TIMER|IRQF_SHARED,
8.name="timer",
9};

只有一個handler,然後是中斷標誌位,名字。

0 4顯示卡中斷註冊

和時鐘中斷註冊相比,顯示卡中斷稍微複雜一些。先看顯示卡初始化函式,目前我手頭的顯示卡基本都是用radeon驅動的,那就看這個吧。

 1intradeon_device_init(structradeon_device*rdev, 2structdrm_device*ddev, 3structpci_dev*pdev, 4uint32_tflags) 5{
6......
7
8r=radeon_asic_init(rdev);
9if(r)
10gotofailed;
11......
12}
13#defineradeon_asic_init(rdev)(rdev)->asic->init((rdev))

顯示卡的init流程非常冗雜,這裡只是拿出和本文相關的一部分程式碼, 這個init上掛的是evergreen_init函式。

 1intevergreen_init(structradeon_device*rdev) 2{
3intr;
4
5/*ReadBIOS*/
6if(!radeon_get_bios(rdev)){
7if(ASIC_IS_AVIVO(rdev))
8return-EINVAL;
9}
10......
11/*Initializeclocks*/
12radeon_get_clock_info(rdev->ddev);
13......
14r=evergreen_startup(rdev);
15if(r){
16dev_err(rdev->dev,"disablingGPUacceleration\n");
17......
18rdev->accel_working=false;
19}

顯示卡讀取bios引數,初始化始終,然後是setup。

 1staticintevergreen_startup(structradeon_device*rdev)
2{
3structradeon_ring*ring;
4intr;
5
6......
7/*EnableIRQ*/
8if(!rdev->irq.installed){
9r=radeon_irq_kms_init(rdev);
10if(r)
11returnr;
12......
13}
14
15intradeon_irq_kms_init(structradeon_device*rdev)
16{
17intr=0;
18
19/*enablemsi*/
20rdev->msi_enabled=0;
21
22if(radeon_msi_ok(rdev)){
23intret=pci_enable_msi(rdev->pdev);
24if(!ret){
25rdev->msi_enabled=1;
26dev_info(rdev->dev,"radeon:usingMSI.\n");
27}
28}
29......
30rdev->irq.installed=true;
31r=drm_irq_install(rdev->ddev,rdev->ddev->pdev->irq);
32
33
34}
35
36intradeon_irq_kms_init(structdrm_device*dev,intirq)
37{
38/*Beforeinstallinghandler*/
39if(dev->driver->irq_preinstall)
40dev->driver->irq_preinstall(dev);
41
42/*Installhandler*/
43if(drm_core_check_feature(dev,DRIVER_IRQ_SHARED))
44sh_flags=IRQF_SHARED;
45
46ret=request_irq(irq,dev->driver->irq_handler,
47sh_flags,dev->driver->name,dev);
48}

哇,好深的一個呼叫啊,從evergreen_startup到radeon_irq_kms_init最後是radeon_irq_kms_init。這裡注意有一個判斷msi的過程。還記得前面留下的一個疑問嗎?56號中斷之前額中斷都被空出來了,這是個msi或者一些老舊的裝置預留的。中斷註冊時候,判斷如果硬體支援MSI,則會優先選擇MSI管理中斷,而不是橋片自己。在pci_enable_msi函式中,pci裝置釋放已經申請好的中斷號和中斷描述符,由msi重新準備一份。

這裡可以看出,顯示卡的中斷號是從pci來的。當然了,顯示卡是pci裝置嘛。pci裝置的中斷號是在啟動時候掃描pci匯流排的時候讀出來的,就是我們熟悉的dmesg總是一開始輸出的類似pci 0000:00:06.0: BAR 2: assigned [mem 0x48000000-0x4fffffff 64bit]這樣的一大堆資料。

 1staticintpci_device_probe(structdevice*dev)
2{
3interror;
4structpci_dev*pci_dev=to_pci_dev(dev);
5structpci_driver*drv=to_pci_driver(dev->driver);
6
7pci_assign_irq(pci_dev);
8
9error=pcibios_alloc_irq(pci_dev);
10if(error0)
11returnerror;
12
13pci_dev_get(pci_dev);
14if(pci_device_can_probe(pci_dev)){
15error=__pci_device_probe(drv,pci_dev);
16if(error){
17pcibios_free_irq(pci_dev);
18pci_dev_put(pci_dev);
19}
20}
21
22returnerror;
23}

這是所有pci裝置的探測入口,呼叫pci_assign_irq函式,讀出每個slot的中斷號。

 1voidpci_assign_irq(structpci_dev*dev) 2{
3u8pin;
4u8slot=-1;
5intirq=0;
6structpci_host_bridge*hbrg=pci_find_host_bridge(dev->bus);
7
8pci_read_config_byte(dev,PCI_INTERRUPT_PIN,&pin);
9/*Copewithillegal.*/
10if(pin>4)
11pin=1;
12
13if(pin){
14/*Followthechainofbridges,swizzlingaswego.*/
15if(hbrg->swizzle_irq)
16slot=(*(hbrg->swizzle_irq))(dev,&pin);
17
18irq=(*(hbrg->map_irq))(dev,slot,pin);
19if(irq==-1)
20irq=0;
21}
22dev->irq=irq;
23}
24
25u8pci_swizzle_interrupt_pin(conststructpci_dev*dev,u8pin)26{
27intslot;
28
29if(pci_ari_enabled(dev->bus))
30slot=0;
31else
32slot=PCI_SLOT(dev->devfn);
33
34return(((pin-1)+slot)%4)+1;
35}

從PCI總線上先讀pin值,接著讀出slot,計算出對應的irq。填充到的pci結構中。這就是中斷註冊的全部內容了。

642f1dcd8355b76b514c399a662cc1de.gifEND 642f1dcd8355b76b514c399a662cc1de.gif f4408083879e3be79d3bcf095a083d11.gif

龍芯中斷初探(一)

710f66c055c7eda5d860a121cd69adc9.png