如果使能了CONFIG_NUMA
#ifdef CONFIG_NUMA
static inline int dev_to_node(struct device *dev)
{
return dev->numa_node;
}
static inline void set_dev_node(struct device *dev, int node)
{
dev->numa_node = node;
}
#endif
则会定义dev_to_node和set_dev_node 两个函数,调用dev_to_node就会返回当前dev所在的numa id。
如果是acpi boot的话,则会在acpi_create_platform_device 函数的最后调用那个set_dev_node 来设置当前device所在的numa id
set_dev_node(&pdev->dev, acpi_get_node(adev->handle));
dev_dbg(&adev->dev, "created platform device %s\n",
dev_name(&pdev->dev));
这里是通过acpi_get_node来得到numa id后,在通过set_dev_node将numa id保存在dev->numa_node 中。
int acpi_get_node(acpi_handle handle)
{
int pxm;
pxm = acpi_get_pxm(handle);
return acpi_map_pxm_to_node(pxm);
}
在acpi_get_node 中先通过acpi_get_pxm 得到一个pxm,然后调用acpi_map_pxm_to_node 中从__acpi_map_pxm_to_node这个数组以pxe为index找到numa id
static int acpi_get_pxm(acpi_handle h)
{
unsigned long long pxm;
acpi_status status;
acpi_handle handle;
acpi_handle phandle = h;
do {
handle = phandle;
status = acpi_evaluate_integer(handle, "_PXM", NULL, &pxm);
if (ACPI_SUCCESS(status))
return pxm;
status = acpi_get_parent(handle, &phandle);
} while (ACPI_SUCCESS(status));
return -1;
}
原来pxe是acpi协议的一部分,最终调用acpi_evaluate_integer 从bios runtime service得到pxm
得到pxm后再通过acpi_map_pxm_to_node 将
int acpi_map_pxm_to_node(int pxm)
{
int node;
if (pxm < 0 || pxm >= MAX_PXM_DOMAINS || numa_off)
return NUMA_NO_NODE;
node = pxm_to_node_map[pxm];
if (node == NUMA_NO_NODE) {
if (nodes_weight(nodes_found_map) >= MAX_NUMNODES)
return NUMA_NO_NODE;
node = first_unset_node(nodes_found_map);
__acpi_map_pxm_to_node(pxm, node);
node_set(node, nodes_found_map);
}
return node;
}
可以看到pxm_to_node_map 就是一个数组
static int pxm_to_node_map[MAX_PXM_DOMAINS]
= { [0 ... MAX_PXM_DOMAINS - 1] = NUMA_NO_NODE };
static int node_to_pxm_map[MAX_NUMNODES]
= { [0 ... MAX_NUMNODES - 1] = PXM_INVAL };
unsigned char acpi_srat_revision __initdata;
int acpi_numa __initdata;
int pxm_to_node(int pxm)
{
if (pxm < 0)
return NUMA_NO_NODE;
return pxm_to_node_map[pxm];
}
如果pxm_to_node_map中返回的是NUMA_NO_NODE,则调用first_unset_node 找到nodes_found_map 中第一个为0的node,然后通过__acpi_map_pxm_to_node 来更新pxm_to_node_map和node_to_pxm_map 这两个数组,最后再通过node_set 来更新nodes_found_map。
可以很清楚的看到first_unset_node 是找到maskp->bits中第一个为0的bit,这里的mask 就是nodes_found_map
#define first_unset_node(mask) __first_unset_node(&(mask))
static inline int __first_unset_node(const nodemask_t *maskp)
{
return min_t(int,MAX_NUMNODES,
find_first_zero_bit(maskp->bits, MAX_NUMNODES));
}
__acpi_map_pxm_to_node则更新pxm_to_node_map和node_to_pxm_map 这两个数组
static void __acpi_map_pxm_to_node(int pxm, int node)
{
if (pxm_to_node_map[pxm] == NUMA_NO_NODE || node < pxm_to_node_map[pxm])
pxm_to_node_map[pxm] = node;
if (node_to_pxm_map[node] == PXM_INVAL || pxm < node_to_pxm_map[node])
node_to_pxm_map[node] = pxm;
}
#ifdef CONFIG_NUMA
static inline int dev_to_node(struct device *dev)
{
return dev->numa_node;
}
static inline void set_dev_node(struct device *dev, int node)
{
dev->numa_node = node;
}
#endif
则会定义dev_to_node和set_dev_node 两个函数,调用dev_to_node就会返回当前dev所在的numa id。
如果是acpi boot的话,则会在acpi_create_platform_device 函数的最后调用那个set_dev_node 来设置当前device所在的numa id
set_dev_node(&pdev->dev, acpi_get_node(adev->handle));
dev_dbg(&adev->dev, "created platform device %s\n",
dev_name(&pdev->dev));
这里是通过acpi_get_node来得到numa id后,在通过set_dev_node将numa id保存在dev->numa_node 中。
int acpi_get_node(acpi_handle handle)
{
int pxm;
pxm = acpi_get_pxm(handle);
return acpi_map_pxm_to_node(pxm);
}
在acpi_get_node 中先通过acpi_get_pxm 得到一个pxm,然后调用acpi_map_pxm_to_node 中从__acpi_map_pxm_to_node这个数组以pxe为index找到numa id
static int acpi_get_pxm(acpi_handle h)
{
unsigned long long pxm;
acpi_status status;
acpi_handle handle;
acpi_handle phandle = h;
do {
handle = phandle;
status = acpi_evaluate_integer(handle, "_PXM", NULL, &pxm);
if (ACPI_SUCCESS(status))
return pxm;
status = acpi_get_parent(handle, &phandle);
} while (ACPI_SUCCESS(status));
return -1;
}
原来pxe是acpi协议的一部分,最终调用acpi_evaluate_integer 从bios runtime service得到pxm
得到pxm后再通过acpi_map_pxm_to_node 将
int acpi_map_pxm_to_node(int pxm)
{
int node;
if (pxm < 0 || pxm >= MAX_PXM_DOMAINS || numa_off)
return NUMA_NO_NODE;
node = pxm_to_node_map[pxm];
if (node == NUMA_NO_NODE) {
if (nodes_weight(nodes_found_map) >= MAX_NUMNODES)
return NUMA_NO_NODE;
node = first_unset_node(nodes_found_map);
__acpi_map_pxm_to_node(pxm, node);
node_set(node, nodes_found_map);
}
return node;
}
可以看到pxm_to_node_map 就是一个数组
static int pxm_to_node_map[MAX_PXM_DOMAINS]
= { [0 ... MAX_PXM_DOMAINS - 1] = NUMA_NO_NODE };
static int node_to_pxm_map[MAX_NUMNODES]
= { [0 ... MAX_NUMNODES - 1] = PXM_INVAL };
unsigned char acpi_srat_revision __initdata;
int acpi_numa __initdata;
int pxm_to_node(int pxm)
{
if (pxm < 0)
return NUMA_NO_NODE;
return pxm_to_node_map[pxm];
}
如果pxm_to_node_map中返回的是NUMA_NO_NODE,则调用first_unset_node 找到nodes_found_map 中第一个为0的node,然后通过__acpi_map_pxm_to_node 来更新pxm_to_node_map和node_to_pxm_map 这两个数组,最后再通过node_set 来更新nodes_found_map。
可以很清楚的看到first_unset_node 是找到maskp->bits中第一个为0的bit,这里的mask 就是nodes_found_map
#define first_unset_node(mask) __first_unset_node(&(mask))
static inline int __first_unset_node(const nodemask_t *maskp)
{
return min_t(int,MAX_NUMNODES,
find_first_zero_bit(maskp->bits, MAX_NUMNODES));
}
__acpi_map_pxm_to_node则更新pxm_to_node_map和node_to_pxm_map 这两个数组
static void __acpi_map_pxm_to_node(int pxm, int node)
{
if (pxm_to_node_map[pxm] == NUMA_NO_NODE || node < pxm_to_node_map[pxm])
pxm_to_node_map[pxm] = node;
if (node_to_pxm_map[node] == PXM_INVAL || pxm < node_to_pxm_map[node])
node_to_pxm_map[node] = pxm;
}