加入星計劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴散
  • 作品版權(quán)保護
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長期合作伙伴
立即加入
  • 正文
    • GIC 驅(qū)動
    • 設(shè)備樹
    • 初始化
    • 中斷的映射
  • 推薦器件
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請入駐 產(chǎn)業(yè)圖譜

Linux BSP實戰(zhàn)課(中斷篇):中斷控制器的驅(qū)動實現(xiàn)

06/04 16:10
1265
閱讀需 18 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

GIC 驅(qū)動

設(shè)備樹

初始化

中斷的映射

數(shù)據(jù)結(jié)構(gòu)

中斷控制器注冊 irq_domain

外設(shè)的驅(qū)動創(chuàng)建硬中斷和虛擬中斷號的映射關(guān)系

中斷的注冊

中斷的處理

保護現(xiàn)場

中斷處理

恢復(fù)現(xiàn)場

總結(jié)

GIC 驅(qū)動

這里主要分析 linux kernel 中 GIC v3 中斷控制器的代碼(drivers/irqchip/irq-gic-v3.c)。

設(shè)備樹

先來看下一個中斷控制器的設(shè)備樹信息:

gic:?interrupt-controller@48000000?{
?compatible?=?"arm,gic-v3";
?reg?=?<0?0x48000000?0?0x10000>,
???????<0?0x48040000?0?0xc0000>;
?#interrupt-cells?=?<3>;
?interrupt-controller;
?interrupts?=?<GIC_PPI?9?IRQ_TYPE_LEVEL_HIGH>;
?interrupt-parent?=?<&gic>;
};

compatible

    • :用于匹配GICv3驅(qū)動

reg

    • :GIC的物理基地址,分別對應(yīng)GICD,GICR,GICC…

#interrupt-cells

    • :這是一個中斷控制器節(jié)點的屬性。它聲明了該中斷控制器的中斷指示符(interrupts)中 cell 的個數(shù)

interrupt-controller

    • : 表示該節(jié)點是一個中斷控制器

interrupts

    : 分別代表中斷類型,中斷號,中斷類型, PPI中斷親和, 保留字段

關(guān)于設(shè)備數(shù)的各個字段含義,詳細可以參考 Documentation/devicetree/bindings 下的對應(yīng)信息。

初始化

1. irq chip driver 的聲明:

IRQCHIP_DECLARE(gic_v3,?"arm,gic-v3",?gic_of_init);

定義 IRQCHIP_DECLARE 之后,相應(yīng)的內(nèi)容會保存到 __irqchip_of_table 里邊:

#define?IRQCHIP_DECLARE(name,?compat,?fn)?OF_DECLARE_2(irqchip,?name,?compat,?fn)

#define?OF_DECLARE_2(table,?name,?compat,?fn)??
????????_OF_DECLARE(table,?name,?compat,?fn,?of_init_fn_2)

#define?_OF_DECLARE(table,?name,?compat,?fn,?fn_type)?????????????
????static?const?struct?of_device_id?__of_table_##name?????????
????????__used?__section(__##table##_of_table)?????????????
?????????=?{?.compatible?=?compat,?????????????????
?????????????.data?=?(fn?==?(fn_type)NULL)???fn?:?fn??}

__irqchip_of_table 在鏈接腳本 vmlinux.lds 里,被放到了 __irqchip_begin 和 __irqchip_of_end 之間,該段用于存放中斷控制器信息:

#ifdef?CONFIG_IRQCHIP
????#define?IRQCHIP_OF_MATCH_TABLE()????????????????????
????????.?=?ALIGN(8);???????????????????????????
????????VMLINUX_SYMBOL(__irqchip_begin)?=?.;????????????????
????????*(__irqchip_of_table)???????????????????????
????????*(__irqchip_of_end)
#endif

在內(nèi)核啟動初始化中斷的函數(shù)中,of_irq_init 函數(shù)會去查找設(shè)備節(jié)點信息,該函數(shù)的傳入?yún)?shù)就是 __irqchip_of_table 段,由于 IRQCHIP_DECLARE 已經(jīng)將信息填充好了,of_irq_init 函數(shù)會根據(jù) “arm,gic-v3” 去查找對應(yīng)的設(shè)備節(jié)點,并獲取設(shè)備的信息。or_irq_init 函數(shù)中,最終會回調(diào) IRQCHIP_DECLARE 聲明的回調(diào)函數(shù),也就是 gic_of_init,而這個函數(shù)就是 GIC 驅(qū)動的初始化入口。

2. gic_of_init 流程:

static?int?__init?gic_of_init(struct?device_node?*node,?struct?device_node?*parent)
{
??......
?dist_base?=?of_iomap(node,?0);???????????????????????????????????????????------(1)
?if?(!dist_base)?{
??pr_err("%pOF:?unable?to?map?gic?dist?registersn",?node);
??return?-ENXIO;
?}

?err?=?gic_validate_dist_version(dist_base);??????????????????????????????------(2)
?if?(err)?{
??pr_err("%pOF:?no?distributor?detected,?giving?upn",?node);
??goto?out_unmap_dist;
?}

?if?(of_property_read_u32(node,?"#redistributor-regions",?&nr_redist_regions))??------(3)
??nr_redist_regions?=?1;

?rdist_regs?=?kzalloc(sizeof(*rdist_regs)?*?nr_redist_regions,?GFP_KERNEL);
?if?(!rdist_regs)?{
??err?=?-ENOMEM;
??goto?out_unmap_dist;
?}

?for?(i?=?0;?i?<?nr_redist_regions;?i++)?{????????????????????????????????------(4)
??struct?resource?res;
??int?ret;

??ret?=?of_address_to_resource(node,?1?+?i,?&res);
??rdist_regs[i].redist_base?=?of_iomap(node,?1?+?i);
??if?(ret?||?!rdist_regs[i].redist_base)?{
???pr_err("%pOF:?couldn't?map?region?%dn",?node,?i);
???err?=?-ENODEV;
???goto?out_unmap_rdist;
??}
??rdist_regs[i].phys_base?=?res.start;
?}
?
?if?(of_property_read_u64(node,?"redistributor-stride",?&redist_stride))??------(5)
??redist_stride?=?0;

?err?=?gic_init_bases(dist_base,?rdist_regs,?nr_redist_regions,???????????------(6)
????????redist_stride,?&node->fwnode);
?if?(err)
??goto?out_unmap_rdist;

?gic_populate_ppi_partitions(node);???????????????????????????????????????------(7)
?gic_of_setup_kvm_info(node);
?return?0;
??......
?return?err;
}
    映射 GICD 的寄存器地址空間。驗證 GICD 的版本是 GICv3 還是 GICv4(主要通過讀GICD_PIDR2寄存器bit[7:4]. 0x1代表GICv1, 0x2代表GICv2…以此類推)。通過 DTS 讀取 redistributor-regions 的值。為一個 GICR 域分配基地址。通過 DTS 讀取 redistributor-stride 的值。下面詳細介紹。設(shè)置一組 PPI 的親和性。
static?int?__init?gic_init_bases(void?__iomem?*dist_base,
?????struct?redist_region?*rdist_regs,
?????u32?nr_redist_regions,
?????u64?redist_stride,
?????struct?fwnode_handle?*handle)
{
??......
?typer?=?readl_relaxed(gic_data.dist_base?+?GICD_TYPER);????????????????------(1)
?gic_data.rdists.id_bits?=?GICD_TYPER_ID_BITS(typer);
?gic_irqs?=?GICD_TYPER_IRQS(typer);
?if?(gic_irqs?>?1020)
??gic_irqs?=?1020;
?gic_data.irq_nr?=?gic_irqs;

?gic_data.domain?=?irq_domain_create_tree(handle,?&gic_irq_domain_ops,??------(2)
???????&gic_data);
?gic_data.rdists.rdist?=?alloc_percpu(typeof(*gic_data.rdists.rdist));
?gic_data.rdists.has_vlpis?=?true;
?gic_data.rdists.has_direct_lpi?=?true;
??......
?set_handle_irq(gic_handle_irq);????????????????????????????????????????------(3)

?gic_update_vlpi_properties();??????????????????????????????????????????------(4)

?if?(IS_ENABLED(CONFIG_ARM_GIC_V3_ITS)?&&?gic_dist_supports_lpis())
??its_init(handle,?&gic_data.rdists,?gic_data.domain);??????????????????------(5)

?gic_smp_init();????????????????????????????????????????????????????????------(6)
?gic_dist_init();???????????????????????????????????????????????????????------(7)
?gic_cpu_init();????????????????????????????????????????????????????????------(8)
?gic_cpu_pm_init();?????????????????????????????????????????????????????------(9)

?return?0;
??......
}
    確認支持 SPI 中斷號最大的值為多少。向系統(tǒng)中注冊一個 irq domain 的數(shù)據(jù)結(jié)構(gòu),irq_domain 主要作用是將硬件中斷號映射到 irq number,后面會做詳細的介紹。設(shè)定 arch 相關(guān)的 irq handler。gic_irq_handle 是內(nèi)核 gic 中斷處理的入口函數(shù),后面會做詳細的介紹。gic 虛擬化相關(guān)的內(nèi)容。初始化 ITS。設(shè)置 SMP 核間交互的回調(diào)函數(shù),用于 IPI,回到函數(shù)為 gic_raise_softir。初始化 Distributor。初始化 CPU interface。初始化 GIC 電源管理。

中斷的映射

當(dāng)早期的系統(tǒng)只存在一個中斷控制器,而且中斷數(shù)目也不多的時候,一個很簡單的做法就是一個中斷號對應(yīng)到中斷控制器的一個號,可以說是簡單的線性映射:

但當(dāng)一個系統(tǒng)中有多個中斷控制器,而且中斷號也逐漸增加的時候。linux 內(nèi)核為了應(yīng)對此問題,引入了 irq_domain 的概念。

推薦器件

更多器件
器件型號 數(shù)量 器件廠商 器件描述 數(shù)據(jù)手冊 ECAD模型 風(fēng)險等級 參考價格 更多信息
SHF-105-01-L-D-SM 1 Samtec Inc Board Connector, 10 Contact(s), 2 Row(s), Male, Straight, 0.05 inch Pitch, Surface Mount Terminal, Black Insulator, Receptacle, ROHS COMPLIANT

ECAD模型

下載ECAD模型
$3.87 查看
ACS102-6T1-TR 1 STMicroelectronics Overvoltage protected AC switch

ECAD模型

下載ECAD模型
$0.74 查看
C0603C560J5GACTU 1 KEMET Corporation Capacitor, Ceramic, Chip, General Purpose, 56pF, 50V, ±5%, C0G/NP0, 0603 (1608 mm), -55o ~ +125oC, 7" Reel/Unmarked

ECAD模型

下載ECAD模型
$0.1 查看

相關(guān)推薦

電子產(chǎn)業(yè)圖譜

針對嵌入式人工智能,物聯(lián)網(wǎng)等專業(yè)技術(shù)分享和交流平臺,內(nèi)容涉及arm,linux,android等各方面。

Arm64 ?;厮?>
				</a>
							</li>
						<li id=
  • Linux BSP實戰(zhàn)課(中斷篇):中斷控制器的驅(qū)動實現(xiàn)
  • 查看更多