在这篇文章中,我们将讨论高通 WLAN 驱动程序中的对象管理器模块(Object Manager)。

代码位置如下:
https://github.com/WANG-Guangxin/wlan-driver/tree/5113495b16420b49004c444715d2daae2066e7dc/qca-wifi-host-cmn/umac/cmn_services/obj_mgr

主要数据结构

在整个 WLAN 驱动程序中,对象管理器模块主要负责管理 3 个对象:

  1. psoc(Physical System on Chip)
  2. pdev(Physical Device)
  3. vdev(Virtual Device)

他们之间的关系如下已经在开篇图中有所展示。

在全局的 wlan_objmgr_global 对象中包括了有一个 psoc 的指针数组,在每个psoc 对象中又包括了一个 soc_objmgr 对象,这个对象中包括了一个 pdev 的指针数组,和一个 vdev 的指针数组。

每一个 pdev 对象中又包括了一个 pdev_objmgr 对象,这个对象中包括了一个 psoc 的指针,指向了当前 pdev 对象所属的 psoc 对象。

每一个 vdev 对象中又包括了一个 vdev_objmgr 对象,这个对象中包括了一个 pdev 的指针,指向了当前 vdev 对象所属的 pdev 对象。

在整个 WLAN 驱动程序中,几乎所有的配置、状态信息都会附加在这些对象上来进行管理。

对象创建

wlan_objmgr_global 对象创建

在驱动加载函数中 hdd_driver_load 会调用到 wlan_objmgr_global_obj_init 函数来进行内存的分配和初始化。

整个调用流程如下:

hdd_driver_load =>
hdd_component_init =>
dispatcher_init =>
wlan_objmgr_global_obj_init

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
/* Global object, it is declared globally */
struct wlan_objmgr_global *g_umac_glb_obj;

qdf_export_symbol(g_umac_glb_obj);

/*
* APIs to Create/Delete Global object APIs
*/
QDF_STATUS wlan_objmgr_global_obj_init(void)
{
struct wlan_objmgr_global *umac_global_obj;

/* If it is already created, ignore */
if (g_umac_glb_obj) {
obj_mgr_err("Global object is already created");
return QDF_STATUS_E_FAILURE;
}

/* Allocation of memory for Global object */
umac_global_obj = (struct wlan_objmgr_global *)qdf_mem_malloc(
sizeof(*umac_global_obj));
if (!umac_global_obj)
return QDF_STATUS_E_NOMEM;

/* Store Global object pointer in Global variable */
g_umac_glb_obj = umac_global_obj;
/* Initialize spinlock */
qdf_spinlock_create(&g_umac_glb_obj->global_lock);
wlan_objmgr_debug_info_init();

return QDF_STATUS_SUCCESS;
}
qdf_export_symbol(wlan_objmgr_global_obj_init);

值得注意的是,在 dispatcher_init 会初始化大量的 WLAN Driver 内部组件,包括 scan、wifi_pos、dfs 等。

其中,第一个被初始化的就是 wlan_objmgr_global 对象,因为其它组件的对象最终都会附加在这个对象上。

以上过程的最终源头是 module_init(hdd_module_init); , 也就是说在驱动模块被加载时就会调用到这个函数。

在驱动模块被加载时的 dispatcher_init 函数中,其他模块会在 wlan_objmgr_global 对象上注册回调函数。

这些回调函数会在 psoc 对象创建时被调用。

scan 模块为例:

ucfg_scan_init 函数中会调用到 wlan_objmgr_register_psoc_create_handler 函数来注册回调函数。

1
2
3
4
5
6
7
QDF_STATUS ucfg_scan_init(void)
{
QDF_STATUS status;

status = wlan_objmgr_register_psoc_create_handler(WLAN_UMAC_COMP_SCAN,
wlan_scan_psoc_created_notification, NULL);
...

wlan_objmgr_register_psoc_create_handler 会在 wlan_objmgr_global 对象维护的 psoc_create_handler 的表中注册 scan 模块的回调函数。

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
QDF_STATUS wlan_objmgr_register_psoc_create_handler(
enum wlan_umac_comp_id id,
wlan_objmgr_psoc_create_handler handler,
void *arg)
{
/* If id is not within valid range, return */
if (id >= WLAN_UMAC_MAX_COMPONENTS) {
obj_mgr_err("Component %d is out of range", id);
return QDF_STATUS_MAXCOMP_FAIL;
}

qdf_spin_lock_bh(&g_umac_glb_obj->global_lock);
/* If there is a valid entry, return failure */
if (g_umac_glb_obj->psoc_create_handler[id]) {
qdf_spin_unlock_bh(&g_umac_glb_obj->global_lock);
obj_mgr_err("Callback for comp %d is already registered", id);
QDF_ASSERT(0);
return QDF_STATUS_E_FAILURE;
}
/* Store handler and args in Global object table */
g_umac_glb_obj->psoc_create_handler[id] = handler;
g_umac_glb_obj->psoc_create_handler_arg[id] = arg;

qdf_spin_unlock_bh(&g_umac_glb_obj->global_lock);
return QDF_STATUS_SUCCESS;
}
qdf_export_symbol(wlan_objmgr_register_psoc_create_handler);

psoc 对象创建

psoc 对象的创建是在 HDD 上下文创建的过程中被调用的。

hdd_context_create 是在驱动程序的 probe 函数中被调用的。probe 函数的调用会晚于 module_init(hdd_module_init);

wlan_objmgr_psoc_obj_create 函数为 psoc 对象分配内存并进行初始化。

然后通过 for 循环调用 g_umac_glb_obj->psoc_create_handler 中注册的回调函数。
对于 scan 模块来说,这个回调函数是 wlan_scan_psoc_created_notification。参数列表是 NULL。

最后会调用 wlan_objmgr_psoc_object_attach 函数来将 psoc 对象附加到 wlan_objmgr_global 对象上。

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
struct wlan_objmgr_psoc *wlan_objmgr_psoc_obj_create(uint32_t phy_version,
WLAN_DEV_TYPE dev_type)
{
uint8_t id;
struct wlan_objmgr_psoc *psoc = NULL;
wlan_objmgr_psoc_create_handler handler;
wlan_objmgr_psoc_status_handler stat_handler;
struct wlan_objmgr_psoc_objmgr *objmgr;
QDF_STATUS obj_status;
void *arg;

psoc = qdf_mem_malloc(sizeof(*psoc));
if (!psoc)
return NULL;

psoc->obj_state = WLAN_OBJ_STATE_ALLOCATED;
qdf_spinlock_create(&psoc->psoc_lock);
/* Initialize with default values */
objmgr = &psoc->soc_objmgr;
objmgr->wlan_pdev_count = 0;
objmgr->wlan_vdev_count = 0;
objmgr->max_vdev_count = WLAN_UMAC_PSOC_MAX_VDEVS;
objmgr->wlan_peer_count = 0;
objmgr->temp_peer_count = 0;
objmgr->max_peer_count = WLAN_UMAC_PSOC_MAX_PEERS;
qdf_atomic_init(&objmgr->ref_cnt);
objmgr->print_cnt = 0;
/* set phy version, dev_type in psoc */
wlan_psoc_set_nif_phy_version(psoc, phy_version);
wlan_psoc_set_dev_type(psoc, dev_type);
/* Initialize peer list */
wlan_objmgr_psoc_peer_list_init(&objmgr->peer_list);
wlan_objmgr_psoc_get_ref(psoc, WLAN_OBJMGR_ID);
/* Invoke registered create handlers */
for (id = 0; id < WLAN_UMAC_MAX_COMPONENTS; id++) {
handler = g_umac_glb_obj->psoc_create_handler[id];
arg = g_umac_glb_obj->psoc_create_handler_arg[id];
if (handler)
psoc->obj_status[id] = handler(psoc, arg);
else
psoc->obj_status[id] = QDF_STATUS_COMP_DISABLED;
}
/* Derive object status */
obj_status = wlan_objmgr_psoc_object_status(psoc);

if (obj_status == QDF_STATUS_SUCCESS) {
/* Object status is SUCCESS, Object is created */
psoc->obj_state = WLAN_OBJ_STATE_CREATED;
for (id = 0; id < WLAN_UMAC_MAX_COMPONENTS; id++) {
stat_handler = g_umac_glb_obj->psoc_status_handler[id];
arg = g_umac_glb_obj->psoc_status_handler_arg[id];
if (stat_handler)
stat_handler(psoc, arg,
QDF_STATUS_SUCCESS);
}
} else if (obj_status == QDF_STATUS_COMP_ASYNC) {
/*
* Few components operates in Asynchrous communction
* Object state partially created
*/
psoc->obj_state = WLAN_OBJ_STATE_PARTIALLY_CREATED;
} else if (obj_status == QDF_STATUS_E_FAILURE) {
/* Component object failed to be created, clean up the object */
obj_mgr_err("PSOC component objects allocation failed");
/* Clean up the psoc */
wlan_objmgr_psoc_obj_delete(psoc);
return NULL;
}

if (wlan_objmgr_psoc_object_attach(psoc) !=
QDF_STATUS_SUCCESS) {
obj_mgr_err("PSOC object attach failed");
wlan_objmgr_psoc_obj_delete(psoc);
return NULL;
}
wlan_minidump_log(psoc, sizeof(*psoc), psoc,
WLAN_MD_OBJMGR_PSOC, "wlan_objmgr_psoc");
obj_mgr_info("Created psoc %d", psoc->soc_objmgr.psoc_id);

return psoc;
}
qdf_export_symbol(wlan_objmgr_psoc_obj_create);

pdev 对象创建

在驱动程序的 probe 函数中首先通过 hdd_context_create 创建出了 psoc 对象。

然后在 hdd_wlan_startup 函数中,会创建 pdev 对象。

1
2
3
4
5
6
7
8
9
10
11
static int __hdd_soc_probe(struct device *dev,
void *bdev,
const struct hif_bus_id *bid,
enum qdf_bus_type bus_type)
{
...
hdd_ctx = hdd_context_create(dev);
...
errno = hdd_wlan_startup(hdd_ctx);
...
}

hdd_wlan_startup

hdd_wlan_start_modules

cds_open

wma_open

1.设置回调函数wma_handle->tgt_cfg_update_cb = hdd_update_tgt_cfg

2.注册固件回调target_if_register_legacy_service_ready_cb(wma_legacy_service_ready_event_handler)

wmi_ready_event_id 事件

wma_legacy_service_ready_event_handler

wma_rx_ready_event

wma_update_hdd_cfg

执行回调:
ret = wma_handle->tgt_cfg_update_cb(hdd_ctx, &tgt_cfg)

hdd_update_tgt_cfg

hdd_objmgr_create_and_store_pdev

wlan_objmgr_pdev_obj_create

pdev 的创建过程已经在如下代码的注释中给出了解释,其中,pdev 的创建也需要通过 for 循环来调用其他组件在 wlan_objmgr_global 对象中注册的 pdev 创建时的回调函数。

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
struct wlan_objmgr_pdev *wlan_objmgr_pdev_obj_create(
struct wlan_objmgr_psoc *psoc,
struct pdev_osif_priv *osdev_priv)
{
struct wlan_objmgr_pdev *pdev;
uint8_t id;
wlan_objmgr_pdev_create_handler handler;
wlan_objmgr_pdev_status_handler s_handler;
void *arg;
QDF_STATUS obj_status;

if (!psoc) {
obj_mgr_err("psoc is NULL");
return NULL;
}
/* Allocate PDEV object's memory */
pdev = qdf_mem_malloc(sizeof(*pdev));
if (!pdev)
return NULL;

pdev->obj_state = WLAN_OBJ_STATE_ALLOCATED;
/* Initialize PDEV spinlock */
qdf_spinlock_create(&pdev->pdev_lock);
wlan_delayed_peer_obj_free_init(pdev);

/* Attach PDEV with PSOC */
if (wlan_objmgr_psoc_pdev_attach(psoc, pdev)
!= QDF_STATUS_SUCCESS) {
obj_mgr_err("pdev psoc attach failed");
qdf_spinlock_destroy(&pdev->pdev_lock);
qdf_mem_free(pdev);
return NULL;
}
wlan_minidump_log(pdev, sizeof(*pdev), psoc,
WLAN_MD_OBJMGR_PDEV, "wlan_objmgr_pdev");
/* Save PSOC object pointer in PDEV */
wlan_pdev_set_psoc(pdev, psoc);
/* Initialize PDEV's VDEV list, assign default values */
qdf_list_create(&pdev->pdev_objmgr.wlan_vdev_list,
WLAN_UMAC_PDEV_MAX_VDEVS);
pdev->pdev_objmgr.wlan_vdev_count = 0;
pdev->pdev_objmgr.max_vdev_count = WLAN_UMAC_PDEV_MAX_VDEVS;
pdev->pdev_objmgr.wlan_peer_count = 0;
pdev->pdev_objmgr.temp_peer_count = 0;
pdev->pdev_objmgr.max_peer_count = wlan_psoc_get_max_peer_count(psoc);
wlan_pdev_init_mlo_vdev_count(pdev);
wlan_pdev_init_mlo_bridge_vdev_count(pdev);
/* Save HDD/OSIF pointer */
pdev->pdev_nif.pdev_ospriv = osdev_priv;
qdf_atomic_init(&pdev->pdev_objmgr.ref_cnt);
pdev->pdev_objmgr.print_cnt = 0;
wlan_objmgr_pdev_get_ref(pdev, WLAN_OBJMGR_ID);
/* Invoke registered create handlers */
for (id = 0; id < WLAN_UMAC_MAX_COMPONENTS; id++) {
handler = g_umac_glb_obj->pdev_create_handler[id];
arg = g_umac_glb_obj->pdev_create_handler_arg[id];
if (handler)
pdev->obj_status[id] = handler(pdev, arg);
else
pdev->obj_status[id] = QDF_STATUS_COMP_DISABLED;
}
/* Derive object status */
obj_status = wlan_objmgr_pdev_object_status(pdev);

if (obj_status == QDF_STATUS_SUCCESS) {
/* Object status is SUCCESS, Object is created */
pdev->obj_state = WLAN_OBJ_STATE_CREATED;
/* Invoke component registered status handlers */
for (id = 0; id < WLAN_UMAC_MAX_COMPONENTS; id++) {
s_handler = g_umac_glb_obj->pdev_status_handler[id];
arg = g_umac_glb_obj->pdev_status_handler_arg[id];
if (s_handler) {
s_handler(pdev, arg,
QDF_STATUS_SUCCESS);
}
}
/* Few components operates in Asynchrous communction, Object state
partially created */
} else if (obj_status == QDF_STATUS_COMP_ASYNC) {
pdev->obj_state = WLAN_OBJ_STATE_PARTIALLY_CREATED;
/* Component object failed to be created, clean up the object */
} else if (obj_status == QDF_STATUS_E_FAILURE) {
/* Clean up the psoc */
obj_mgr_err("PDEV component objects allocation failed");
wlan_objmgr_pdev_obj_delete(pdev);
return NULL;
}

obj_mgr_debug("Created pdev %d", pdev->pdev_objmgr.wlan_pdev_id);

return pdev;
}
qdf_export_symbol(wlan_objmgr_pdev_obj_create);

vdev 对象创建

vdev 的创建和销毁与 Linux 内核网络设备接口是紧密相关的。

比如,当网络设备打开时(如ifconfig upip link set up), 内核会调用网络设备驱动程序中的 ndo_open 函数。

ndo: network device operations

在高通 WLAN 驱动程序中,ndo_open 函数是 hdd_open 函数。

STA Adapter 流程

驱动接口调用

对象管理调用

hdd_open

hdd_start_adapter

hdd_start_station_adapter (STA 示例)

hdd_vdev_create

sme_vdev_create

wlan_objmgr_vdev_obj_create

HDD 层

SME 层

WLAN ObjMgr 层

点击展开:

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
162
163
164
165
166
struct wlan_objmgr_vdev *wlan_objmgr_vdev_obj_create(
struct wlan_objmgr_pdev *pdev,
struct wlan_vdev_create_params *params)
{
struct wlan_objmgr_vdev *vdev;
struct wlan_objmgr_psoc *psoc;
uint8_t id;
wlan_objmgr_vdev_create_handler handler;
wlan_objmgr_vdev_status_handler stat_handler;
void *arg;
QDF_STATUS obj_status;

if (!pdev) {
obj_mgr_err("pdev is NULL");
return NULL;
}
psoc = wlan_pdev_get_psoc(pdev);
/* PSOC is NULL */
if (!psoc) {
obj_mgr_err("psoc is NULL for pdev-id:%d",
pdev->pdev_objmgr.wlan_pdev_id);
return NULL;
}
/* Allocate vdev object memory */
vdev = qdf_mem_malloc(sizeof(*vdev) + params->size_vdev_priv);
if (!vdev)
return NULL;
vdev->obj_state = WLAN_OBJ_STATE_ALLOCATED;

vdev->vdev_mlme.bss_chan = qdf_mem_malloc(sizeof(struct wlan_channel));
if (!vdev->vdev_mlme.bss_chan) {
qdf_mem_free(vdev);
return NULL;
}

vdev->vdev_mlme.des_chan = qdf_mem_malloc(sizeof(struct wlan_channel));
if (!vdev->vdev_mlme.des_chan) {
qdf_mem_free(vdev->vdev_mlme.bss_chan);
qdf_mem_free(vdev);
return NULL;
}

wlan_create_vdev_mlo_lock(vdev);

wlan_objmgr_vdev_trace_init_lock(vdev);
/* Initialize spinlock */
qdf_spinlock_create(&vdev->vdev_lock);
/* Attach VDEV to PSOC VDEV's list */
if (wlan_objmgr_psoc_vdev_attach(psoc, vdev) !=
QDF_STATUS_SUCCESS) {
obj_mgr_err("psoc vdev attach failed for vdev-id:%d",
vdev->vdev_objmgr.vdev_id);
qdf_mem_free(vdev->vdev_mlme.bss_chan);
qdf_mem_free(vdev->vdev_mlme.des_chan);
wlan_destroy_vdev_mlo_lock(vdev);
qdf_spinlock_destroy(&vdev->vdev_lock);
wlan_objmgr_vdev_trace_deinit_lock(vdev);
qdf_mem_free(vdev);
return NULL;
}
/* Store pdev in vdev */
wlan_vdev_set_pdev(vdev, pdev);
/* Attach vdev to PDEV */
if (wlan_objmgr_pdev_vdev_attach(pdev, vdev) !=
QDF_STATUS_SUCCESS) {
obj_mgr_err("pdev vdev attach failed for vdev-id:%d",
vdev->vdev_objmgr.vdev_id);
wlan_objmgr_psoc_vdev_detach(psoc, vdev);
qdf_mem_free(vdev->vdev_mlme.bss_chan);
qdf_mem_free(vdev->vdev_mlme.des_chan);
wlan_destroy_vdev_mlo_lock(vdev);
qdf_spinlock_destroy(&vdev->vdev_lock);
wlan_objmgr_vdev_trace_deinit_lock(vdev);
qdf_mem_free(vdev);
return NULL;
}
/* set opmode */
wlan_vdev_mlme_set_opmode(vdev, params->opmode);
/* set MAC address */
wlan_vdev_mlme_set_macaddr(vdev, params->macaddr);
/* set MAT address */
wlan_vdev_mlme_set_mataddr(vdev, params->mataddr);
/* set MLD address */
wlan_vdev_mlme_set_mldaddr(vdev, params->mldaddr);
/* set link address */
wlan_vdev_mlme_set_linkaddr(vdev, params->macaddr);
/* Set create flags */
vdev->vdev_objmgr.c_flags = params->flags;
/* store os-specific pointer */
vdev->vdev_nif.osdev = wlan_objmgr_vdev_get_osif_priv(vdev);

/* peer count to 0 */
vdev->vdev_objmgr.wlan_peer_count = 0;
wlan_objmgr_vdev_init_ml_peer_count(vdev);
qdf_atomic_init(&vdev->vdev_objmgr.ref_cnt);
vdev->vdev_objmgr.print_cnt = 0;
wlan_objmgr_vdev_get_ref(vdev, WLAN_OBJMGR_ID);
/* Initialize max peer count based on opmode type */
if (wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE)
vdev->vdev_objmgr.max_peer_count = WLAN_UMAC_MAX_STA_PEERS;
else
vdev->vdev_objmgr.max_peer_count =
wlan_pdev_get_max_peer_count(pdev);

wlan_vdev_init_skip_pumac_cnt(vdev);
if (params->legacy_osif)
vdev->vdev_nif.osdev->legacy_osif_priv = params->legacy_osif;

/* Initialize peer list */
qdf_list_create(&vdev->vdev_objmgr.wlan_peer_list,
vdev->vdev_objmgr.max_peer_count +
WLAN_MAX_PDEV_TEMP_PEERS);
/* TODO init other parameters */

/* Invoke registered create handlers */
for (id = 0; id < WLAN_UMAC_MAX_COMPONENTS; id++) {
handler = g_umac_glb_obj->vdev_create_handler[id];
arg = g_umac_glb_obj->vdev_create_handler_arg[id];
if (handler)
vdev->obj_status[id] = handler(vdev, arg);
else
vdev->obj_status[id] = QDF_STATUS_COMP_DISABLED;
}

/* Derive object status */
obj_status = wlan_objmgr_vdev_object_status(vdev);

if (obj_status == QDF_STATUS_SUCCESS) {
/* Object status is SUCCESS, Object is created */
vdev->obj_state = WLAN_OBJ_STATE_CREATED;
/* Invoke component registered status handlers */
for (id = 0; id < WLAN_UMAC_MAX_COMPONENTS; id++) {
stat_handler = g_umac_glb_obj->vdev_status_handler[id];
arg = g_umac_glb_obj->vdev_status_handler_arg[id];
if (stat_handler) {
stat_handler(vdev, arg,
QDF_STATUS_SUCCESS);
}
}
/*
* Few components operates in Asynchrous communction, Object state
* partially created
*/
} else if (obj_status == QDF_STATUS_COMP_ASYNC) {
vdev->obj_state = WLAN_OBJ_STATE_PARTIALLY_CREATED;
/* Component object failed to be created, clean up the object */
} else if (obj_status == QDF_STATUS_E_FAILURE) {
/* Clean up the psoc */
obj_mgr_err("VDEV comp objects creation failed for vdev-id:%d",
vdev->vdev_objmgr.vdev_id);
wlan_objmgr_vdev_obj_delete(vdev);
return NULL;
}

wlan_minidump_log(vdev, sizeof(*vdev), psoc,
WLAN_MD_OBJMGR_VDEV, "wlan_objmgr_vdev");

obj_mgr_debug("Created vdev %d", vdev->vdev_objmgr.vdev_id);

obj_status = wlan_objmgr_vdev_mlo_dev_ctxt_attach(vdev);
if (obj_status != QDF_STATUS_SUCCESS)
return NULL;

return vdev;
}
qdf_export_symbol(wlan_objmgr_vdev_obj_create);