在这篇文章中,我们将讨论高通 WLAN 驱动程序中的对象管理器模块(Object Manager)。
主要数据结构
在整个 WLAN 驱动程序中,对象管理器模块主要负责管理 3 个对象:
- psoc(Physical System on Chip)
- pdev(Physical Device)
- 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
/* 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
函数来注册回调函数。
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 模块的回调函数。
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
对象上。
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 对象。
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);
...
}
pdev 的创建过程已经在如下代码的注释中给出了解释,其中,pdev 的创建也需要通过 for 循环来调用其他组件在 wlan_objmgr_global
对象中注册的 pdev 创建时的回调函数。
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 up
或ip link set up
), 内核会调用网络设备驱动程序中的 ndo_open
函数。
ndo: network device operations
在高通 WLAN 驱动程序中,ndo_open
函数是 hdd_open
函数。
点击展开
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);