1 #pragma once
2 
3 #include <common/glib.h>
4 #include <DragonOS/stdint.h>
5 
6 #define PORT_PCI_CONFIG_ADDRESS 0xcf8
7 #define PORT_PCI_CONFIG_DATA 0xcfc
8 
9 // pci设备结构信息的链表
10 struct List *pci_device_structure_list = NULL;
11 
12 /**
13  * @brief 初始化pci驱动
14  *
15  */
16 void pci_init();
17 
18 // pci设备结构的通用标题字段
19 struct pci_device_structure_header_t
20 {
21     struct List list;
22 
23     // 包含msix table地址的bar的mmio基地址
24     uint64_t msix_mmio_vaddr;
25     uint64_t msix_mmio_size;  // msix映射长度
26     uint32_t msix_offset;     // msix表的offset
27     uint16_t msix_table_size; // msix表的表项数量
28 
29     // ==== 以下三个变量表示该结构体所处的位置
30     uint8_t bus;
31     uint8_t device;
32     uint8_t func;
33 
34     uint16_t Vendor_ID; // 供应商ID 0xffff是一个无效值,在读取访问不存在的设备的配置空间寄存器时返回
35     uint16_t Device_ID; // 设备ID,标志特定设备
36 
37     uint16_t Command; // 提供对设备生成和响应pci周期的能力的控制 向该寄存器写入0时,设备与pci总线断开除配置空间访问以外的所有连接
38     uint16_t Status;  // 用于记录pci总线相关时间的状态信息寄存器
39 
40     uint8_t RevisionID; // 修订ID,指定特定设备的修订标志符
41     uint8_t ProgIF;     // 编程接口字节,一个只读寄存器,指定设备具有的寄存器级别的编程接口(如果有的话)
42     uint8_t SubClass;   // 子类。指定设备执行的特定功能的只读寄存器
43     uint8_t Class_code; // 类代码,一个只读寄存器,指定设备执行的功能类型
44 
45     uint8_t CacheLineSize; // 缓存线大小:以 32 位为单位指定系统缓存线大小。设备可以限制它可以支持的缓存线大小的数量,如果不支持的值写入该字段,设备将表现得好像写入了 0 值
46     uint8_t LatencyTimer;  // 延迟计时器:以 PCI 总线时钟为单位指定延迟计时器。
47     uint8_t HeaderType;    // 标头类型 a value of 0x0 specifies a general device, a value of 0x1 specifies a PCI-to-PCI bridge, and a value of 0x2 specifies a CardBus bridge. If bit 7 of this register is set, the device has multiple functions; otherwise, it is a single function device.
48     uint8_t BIST;          // Represents that status and allows control of a devices BIST (built-in self test).
49                            // Here is the layout of the BIST register:
50                            // |     bit7     |    bit6    | Bits 5-4 |     Bits 3-0    |
51                            // | BIST Capable | Start BIST | Reserved | Completion Code |
52                            // for more details, please visit https://wiki.osdev.org/PCI
53 };
54 
55 /**
56  * @brief 表头类型为0x0的pci设备结构
57  *
58  */
59 struct pci_device_structure_general_device_t
60 {
61     struct pci_device_structure_header_t header;
62     uint32_t BAR0;
63     uint32_t BAR1;
64     uint32_t BAR2;
65     uint32_t BAR3;
66     uint32_t BAR4;
67     uint32_t BAR5;
68     uint32_t Cardbus_CIS_Pointer; // 指向卡信息结构,供在 CardBus 和 PCI 之间共享芯片的设备使用。
69 
70     uint16_t Subsystem_Vendor_ID;
71     uint16_t Subsystem_ID;
72 
73     uint32_t Expansion_ROM_base_address;
74 
75     uint8_t Capabilities_Pointer;
76     uint8_t reserved0;
77     uint16_t reserved1;
78 
79     uint32_t reserved2;
80 
81     uint8_t Interrupt_Line; // 指定设备的中断引脚连接到系统中断控制器的哪个输入,并由任何使用中断引脚的设备实现。对于 x86 架构,此寄存器对应于 PIC IRQ 编号 0-15(而不是 I/O APIC IRQ 编号),并且值0xFF定义为无连接。
82     uint8_t Interrupt_PIN;  // 指定设备使用的中断引脚。其中值为0x1INTA#、0x2INTB#、0x3INTC#、0x4INTD#,0x0表示设备不使用中断引脚。
83     uint8_t Min_Grant;      // 一个只读寄存器,用于指定设备所需的突发周期长度(以 1/4 微秒为单位)(假设时钟速率为 33 MHz)
84     uint8_t Max_Latency;    // 一个只读寄存器,指定设备需要多长时间访问一次 PCI 总线(以 1/4 微秒为单位)。
85 } __attribute__((packed));
86 
87 /**
88  * @brief 表头类型为0x1的pci设备结构(PCI to PCI Bridge)
89  *
90  */
91 struct pci_device_structure_pci_to_pci_bridge_t
92 {
93     struct pci_device_structure_header_t header;
94 
95     uint32_t BAR0;
96     uint32_t BAR1;
97 
98     uint8_t Primary_Bus_Number;
99     uint8_t Secondary_Bus_Number;
100     uint8_t Subordinate_Bus_Number;
101     uint8_t Secondary_Latency_Timer;
102 
103     uint8_t io_base;
104     uint8_t io_limit;
105     uint16_t Secondary_Status;
106 
107     uint16_t Memory_Base;
108     uint16_t Memory_Limit;
109 
110     uint16_t Prefetchable_Memory_Base;
111     uint16_t Prefetchable_Memory_Limit;
112 
113     uint32_t Prefetchable_Base_Upper_32_Bits;
114     uint32_t Prefetchable_Limit_Upper_32_Bits;
115 
116     uint16_t io_Base_Upper_16_Bits;
117     uint16_t io_Limit_Upper_16_Bits;
118 
119     uint8_t Capability_Pointer;
120     uint8_t reserved0;
121     uint16_t reserved1;
122 
123     uint32_t Expansion_ROM_base_address;
124 
125     uint8_t Interrupt_Line;
126     uint8_t Interrupt_PIN;
127     uint16_t Bridge_Control;
128 
129 } __attribute__((packed));
130 
131 /**
132  * @brief 表头类型为0x2的pci设备结构(PCI to CardBus Bridge)
133  *
134  */
135 struct pci_device_structure_pci_to_cardbus_bridge_t
136 {
137     struct pci_device_structure_header_t header;
138 
139     uint32_t CardBus_Socket_ExCa_base_address;
140 
141     uint8_t Offset_of_capabilities_list;
142     uint8_t Reserved;
143     uint16_t Secondary_status;
144 
145     uint8_t PCI_bus_number;
146     uint8_t CardBus_bus_number;
147     uint8_t Subordinate_bus_number;
148     uint8_t CardBus_latency_timer;
149 
150     uint32_t Memory_Base_Address0;
151     uint32_t Memory_Limit0;
152     uint32_t Memory_Base_Address1;
153     uint32_t Memory_Limit1;
154     uint32_t IO_Base_Address0;
155     uint32_t IO_Limit0;
156     uint32_t IO_Base_Address1;
157     uint32_t IO_Limit1;
158 
159     uint8_t Interrupt_Line;
160     uint8_t Interrupt_PIN;
161     uint16_t Bridge_Control;
162 
163     uint16_t Subsystem_Device_ID;
164     uint16_t Subsystem_Vendor_ID;
165 
166     uint32_t PC_Card_legacy_mode_base_address_16_bit;
167 
168 } __attribute__((packed));
169 
170 /**
171  * @brief 从pci配置空间读取信息
172  *
173  * @param bus 总线号
174  * @param slot 插槽号
175  * @param func 功能号
176  * @param offset 字节偏移量
177  * @return uint 寄存器值
178  */
179 uint32_t pci_read_config(uchar bus, uchar slot, uchar func, uchar offset);
180 
181 /**
182  * @brief 向pci配置空间写入信息
183  *
184  * @param bus 总线号
185  * @param slot 设备号
186  * @param func 功能号
187  * @param offset 字节偏移量
188  * @return uint 寄存器值
189  */
190 uint pci_write_config(uchar bus, uchar slot, uchar func, uchar offset, uint32_t data);
191 
192 /**
193  * @brief 读取pci设备标头
194  *
195  * @param type 标头类型
196  * @param bus 总线号
197  * @param slot 插槽号
198  * @param func 功能号
199  * @return 返回的header的指针
200  */
201 void *pci_read_header(int *type, uchar bus, uchar slot, uchar func, bool add_to_list);
202 
203 /**
204  * @brief 扫描所有pci总线上的所有设备
205  *
206  */
207 void pci_checkAllBuses();
208 
209 /**
210  * @brief 获取 device structure
211  *
212  * @param class_code
213  * @param sub_class
214  * @param res 返回的结果数组
215  */
216 void pci_get_device_structure(uint8_t class_code, uint8_t sub_class, struct pci_device_structure_header_t *res[], uint32_t *count_res);
217 
218 /**
219  * @brief 寻找符合指定类型的capability list
220  *
221  * @param pci_dev pci设备header
222  * @param cap_type c要寻找的capability类型
223  * @return uint64_t cap list的偏移量
224  */
225 int32_t pci_enumerate_capability_list(struct pci_device_structure_header_t *pci_dev, uint32_t cap_type);