在这篇文章中,我们将讨论高通 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

/* 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);
...
}

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 创建时的回调函数。

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 层

点击展开
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);