0%

PCIe学习笔记(四)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
pci_assign_unassigned_bus_resources(b)
void pci_assign_unassigned_bus_resources(struct pci_bus *bus)
{
struct pci_dev *dev;
LIST_HEAD(add_list); /* list of resources that
want additional resources */

down_read(&pci_bus_sem);
list_for_each_entry(dev, &bus->devices, bus_list)
if (pci_is_bridge(dev) && pci_has_subordinate(dev))
/* 这里传入的参数是bus 1对应的pci_bus */
__pci_bus_size_bridges(dev->subordinate,
&add_list);
up_read(&pci_bus_sem);
/* 配置各个桥和设备的BAR,配置桥的MEM,I/O,prefetch MEM base/limit */
__pci_bus_assign_resources(bus, &add_list, NULL);
BUG_ON(!list_empty(&add_list));
}

__pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head)
...
/* 在当前的连接状态下,list中的代码不会执行。下面的代码层层递归,直到
* 最底层设备的上的pci_bus,这时最底层设备是没有下一级的pci_bus的。
* 所以,继续执行后面的代码。
*/
-->list_for_each_entry(dev, &bus->devices, bus_list) {
...
case PCI_CLASS_BRIDGE_PCI:
default:
__pci_bus_size_bridges(b, realloc_head);
break;
}
...
/* 当前pci_bus的桥对应的pci_dev, 这里应该是host */
-->switch (bus->self->class >> 8) {
...
case PCI_CLASS_BRIDGE_PCI:
/* 会执行这里 */
pci_bridge_check_ranges(bus);
...
default:
/* 这个函数改变了pci_bus->resource[]中的值。start对齐4K,size是该bus下
* 所有I/O空间的总和。但是似乎realloc_head
* list似乎没有node添加上去
*/
pbus_size_io(bus, realloc_head ? 0 : additional_io_size,
additional_io_size, realloc_head);

/*
* If there's a 64-bit prefetchable MMIO window, compute
* the size required to put all 64-bit prefetchable
* resources in it.
*/
b_res = &bus->self->resource[PCI_BRIDGE_RESOURCES];
mask = IORESOURCE_MEM;
prefmask = IORESOURCE_MEM | IORESOURCE_PREFETCH;
if (b_res[2].flags & IORESOURCE_MEM_64) {
prefmask |= IORESOURCE_MEM_64;
ret = pbus_size_mem(bus, prefmask, prefmask,
prefmask, prefmask,
realloc_head ? 0 : additional_mem_size,
additional_mem_size, realloc_head);

/*
* If successful, all non-prefetchable resources
* and any 32-bit prefetchable resources will go in
* the non-prefetchable window.
*/
if (ret == 0) {
mask = prefmask;
type2 = prefmask & ~IORESOURCE_MEM_64;
type3 = prefmask & ~IORESOURCE_PREFETCH;
}
}

/*
* If there is no 64-bit prefetchable window, compute the
* size required to put all prefetchable resources in the
* 32-bit prefetchable window (if there is one).
*/
if (!type2) {
prefmask &= ~IORESOURCE_MEM_64;
ret = pbus_size_mem(bus, prefmask, prefmask,
prefmask, prefmask,
realloc_head ? 0 : additional_mem_size,
additional_mem_size, realloc_head);

/*
* If successful, only non-prefetchable resources
* will go in the non-prefetchable window.
*/
if (ret == 0)
mask = prefmask;
else
additional_mem_size += additional_mem_size;

type2 = type3 = IORESOURCE_MEM;
}

/*
* Compute the size required to put everything else in the
* non-prefetchable window. This includes:
*
* - all non-prefetchable resources
* - 32-bit prefetchable resources if there's a 64-bit
* prefetchable window or no prefetchable window at all
* - 64-bit prefetchable resources if there's no
* prefetchable window at all
*
* Note that the strategy in __pci_assign_resource() must
* match that used here. Specifically, we cannot put a
* 32-bit prefetchable resource in a 64-bit prefetchable
* window.
*/
pbus_size_mem(bus, mask, IORESOURCE_MEM, type2, type3,
realloc_head ? 0 : additional_mem_size,
additional_mem_size, realloc_head);
break;
}
}

__pci_bus_assign_resources(bus, &add_list, NULL)
/* bus:0, 会对该bus上的所有device分别调用__dev_sort_resource
* 然后统一调用一个__assign_resources_sorted()。之后程序进入
* 下面的list中,又会嵌套进入__pci_bus_assign_resources, 这时
* bus:1。重复上面的过程。在bus:1是__pci_bus_assign_resources
* 在处理处理完pbus_assign_resources_sorted后不回往下执行,返回
* 上层。这时bus:0, 进入pci_setup_bridge执行。
* 其中,会在pbus_assign_resources_sorted中配置BAR,在
* __pci_setup_bridge中配mem, I/O, prefetch mem的base/limit
*/
--> pbus_assign_resources_sorted(bus, realloc_head, fail_head);
--> list_for_each_entry(dev, &bus->devices, bus_list)
--> __pci_bus_assign_resources(b, realloc_head, fail_head);
--> switch (dev->class >> 8)
case PCI_CLASS_BRIDGE_PCI:
--> pci_setup_bridge(b);

static void pbus_assign_resources_sorted()
--> LIST_HEAD(head);
--> list_for_each_entry(dev, &bus->devices, bus_list)
__dev_sort_resources(dev, &head);
/* 把pci_dev中的resource[]从大到小排序, 存入链表head中 */
--> pdev_sort_resources(dev, head);
--> __assign_resources_sorted(&head, realloc_head, fail_head);
/* 因为realloc_head为空链表,所以直接到requested_and_reassign */
--> if (!realloc_head || list_empty(realloc_head))
goto requested_and_reassign;
...
requested_and_reassign:
--> assign_requested_resources_sorted(head, fail_head);
/* dev_res(pci_dev_resource)存储一个device中一个配置空间
* 的资源(一个设备可有多个mem或I/O配置空间)
*/
--> list_for_each_entry(dev_res, head, list)
--> resource_size(res) &&
pci_assign_resource(dev_res->dev, idx)
--> _pci_assign_resource(dev, resno, size, align);
--> pci_update_resource(dev, resno);

--> reassign_resources_sorted(realloc_head, head);