AP处理器开机-> 注册驱动
ipc_router_smd_xprt.c
module_init(msm_ipc_router_smd_xprt_init); -> msm_ipc_router_smd_xprt_probe-> msm_ipc_router_smd_config_init -> msm_ipc_router_smd_driver_register -> 注册驱动
msm_ipc_router_smd_remote_probe(被调用见后续 *)
smem.c
arch_initcall(msm_smem_init); ->
msm_smem_probe-> 主要获取共享内存物理地址歧视地址(1MB)
smem_ram_phys(0x0193d000->87dff080->87d00000)->
of_platform_populate 匹配子设备(smd.c smsm.c probe 被调用) ->
smd.c
msm_smd_probe-> request_irq 主要是申请中断
smd_post_init -> smd_channel_probe_now -> smem_get_entry(13…) 失败此时 modem 还没初始化
通过PIL 从Nand flash modem 分区加载NON-HLOS.ubi 到内存地址0x82a00000)可参考MDM9X07 启动流程
https://blog.csdn.net/hesunwen/article/details/71423463
modem 启动初始化
modem_proc/core/mproc/ipc_router/src/ipc_router_init.c
void ipc_router_init(void)
{
...
/* Link to Apps */
{
static ipc_router_xal_smdl_param_type param =
{
"IPCRTR",
SMD_APPS_MODEM,
SMD_STANDARD_FIFO,
SMDL_OPEN_FLAGS_MODE_PACKET,
TRUE
};
ipc_router_xal_start_xport(&ipc_router_xal_smdl, (void *)¶m, 0, "APPS");
}
...
}
ipc_router_xal_start_xport ->
分配内存 xport
xport->ops->xport_open(xport_params, xport, &xport->handle) ->
ipc_router_xal_smdl.ipc_router_xal_smdl_open(xport_params, xport, &xport->handle) ->
port->handle = smdl_open(param->name,
param->edge,
param->mode,
param->fifo,
ipc_router_xal_smdl_notify,
port);
/**
* Opens a port to the specified remote processor.
*
* Opens the port named \c name between the processors specified by \c edge.
* (The current processor must be one of the two processors connected by \c
* edge.) This function allocates the data structures for the ports in local
* and shared memory and allocates FIFOs for receive and transmit, each of
* size \c fsize.
*
* Clients may not read from or write to the port until it is opened on both
* ends. When the other processor opens the port the \c notify callback will
* be called with argument #SMDL_EVENT_OPEN. If the other end is already open
* when this function is called, the open notification callback will be called
* immediately, and may be called before this function returns.
*
* If a client wishes to know when the SMD port is fully open, and the other
* end asserts its DTR signal when opening the port, the client should wait
* for #SMDL_EVENT_OPEN. If a client wishes to know when the SMD port is fully
* open, and the other end does not assert its DTR signal when opening the
* port, the client should wait for #SMDL_EVENT_CTS, taking care that the
* other end may set and clear its Clear To Send (CTS) signal to enable and
* disable inbound flow during normal operation. If a client doesn't need to
* know when the port is open, and merely wishes to transmit data, the client
* should send data after opening the port. If the port is fully open, SMD
* Lite will transmit the data immediately. If the port is not fully open, SMD
* Lite will notify the client when data can be written (when the remote
* processor asserts its CTS signal) by sending #SMDL_EVENT_WRITE.
*
* Port names uniquely identify the port connecting two processors across a
* single edge. The same name may be used along different edges.
*
* @param[in] name The name for the port.
* @param[in] edge The edge, identifying both processors, on which this
* channel communicates. The edge must include the
* current processor.
* @param[in] flags A bitfield of flags controlling the behavior of the
* port. See #SMDL_OPEN_FLAGS_NONE,
* #SMDL_OPEN_FLAGS_PRIORITY_DEFAULT,
* #SMDL_OPEN_FLAGS_PRIORITY_LOW,
* #SMDL_OPEN_FLAGS_PRIORITY_HIGH,
* #SMDL_OPEN_FLAGS_PRIORITY_IST,
* #SMDL_OPEN_FLAGS_MODE_PACKET, and
* #SMDL_OPEN_FLAGS_MODE_STREAMING.
* @param[in] fsize The size of the FIFO. This is the physical
* size in memory, which is always four bytes greater
* than the total capacity of the FIFO. In packet mode,
* the SMD packet header adds 20 bytes per packet,
* further reducing the capacity. The FIFO size must be
* a multiple of 32 and must not be less than
* SMD_MIN_FIFO or greater than SMD_MAX_FIFO. If this
* parameter is 0, the default size (SMD_STANDARD_FIFO)
* will be used.
* @param[in] notify The callback called when SMD needs to notify the
* client of a remote event on the SMD port.
* @param[in] cb_data The data passed to the notify function.
*
* @return An opaque SMD handle for the opened port, or NULL if an
* error occured while opening the port.
*
* @sideeffects Allocates the local and shared data structures for the SMD
* port. Signals the remote processor.
* Error fatal occurs when SMDL port is already open (by other
* processor) with a different fifo size.
*/
smdl_handle_type smdl_open
(
const char *name,
smd_channel_type edge,
uint32 flags,
uint32 fsize,
smdl_callback_t notify,
void *cb_data
);
smdl_open 高通没开源 api 这么写的,此处猜测意思就是smem_alloc 13放到指定内存,然后发送中断给AP侧 通知ipc 初始化完成 ,static ipc_router_xal_smdl_param_type param 中的"IPCRTR" 与AP 侧 dts 匹配
(通过此处改名字可以测试)
qcom,ipc_router_modem_xprt {
compatible = "qcom,ipc_router_smd_xprt";
qcom,ch-name = "IPCRTR";
qcom,xprt-remote = "modem";
qcom,xprt-linkid = <1>;
qcom,xprt-version = <1>;
qcom,fragmented-data;
qcom,disable-pil-loading;
};
AP侧 中断处理函数
smd_modem_irq_handler -> do_smd_probe ->
smd_channel_probe_worker -> smd_channel_probe_now ->
smem_get_entry(13…) 获取一个元素为64的数组指针 struct smd_alloc_elm *shared
一种是nonsecure 比如smem_get_entry(419…)(获取版本号 alloc 在 bootloader中) 从0x87d0000 地址数据结构struce smem_shared 中 表heap_toc[419] 中取地址偏移量offset (最终地址也就是0x87d0000+offset 中取)
另外一种secure(partions) 比如smem_get_entry(13…)
(一般用于取remote处理器alloc的数据) 地址为0x87d0000+1M-4K 数据结构为smem_toc 表entry[1] 中取offset (获取的是一个 struct smem_partition_header) 最终地址为(0x87d0000 + offset +sizeof(struct smem_partition_header)+sizeof(struct smem_partition_allocation_header) + smem_partition_allocation_header.padding_hdr (item 第一个的情况))
static void *__smem_get_entry_secure(unsigned id,
unsigned *size,
unsigned to_proc,
unsigned flags,
bool skip_init_check,
bool use_rspinlock)
{
....
if (flags & SMEM_ANY_HOST_FLAG || !partitions[to_proc].offset)
return __smem_get_entry_nonsecure(id, size, skip_init_check,
use_rspinlock);
partition_num = partitions[to_proc].partition_num;
hdr = smem_areas[0].virt_addr + partitions[to_proc].offset;
//此处smem_areas[0].virt_addr 对于的物理地址 0x87d0000 offset 就是 0x87d0000 +1M-4K smem_toc.entry[1].offset = 0x87000=540K (这个值来源猜测是寄存器中)
...
if (flags & SMEM_ITEM_CACHED_FLAG) {
a_hdr_size = ALIGN(sizeof(*alloc_hdr),
partitions[to_proc].size_cacheline);
for (alloc_hdr = (void *)(hdr) + hdr->size - a_hdr_size;
(void *)(alloc_hdr) > (void *)(hdr) +
hdr->offset_free_cached;
alloc_hdr = (void *)(alloc_hdr) -
alloc_hdr->size - a_hdr_size) {
if (alloc_hdr->canary != SMEM_ALLOCATION_CANARY) {
LOG_ERR(
"%s: SMEM corruption detected. Partition %d to %d at %p\n",
__func__,
partition_num,
to_proc,
alloc_hdr);
BUG();
}
if (alloc_hdr->smem_type == id) {
/* 8 byte alignment to match legacy */
*size = ALIGN(alloc_hdr->size -
alloc_hdr->padding_data, 8);
item = (void *)(alloc_hdr) - alloc_hdr->size;
break;
}
}
} else {
//注意此处 hdr->offset_free_uncached 初始化为32 sizeof(*hdr) 一样为32 在modem smdl_open 时已经修改了不然不会跑到for 循环
for (alloc_hdr = (void *)(hdr) + sizeof(*hdr);
(void *)(alloc_hdr) < (void *)(hdr) +
hdr->offset_free_uncached;
alloc_hdr = (void *)(alloc_hdr) +
sizeof(*alloc_hdr) +
alloc_hdr->padding_hdr +
alloc_hdr->size) {
if (alloc_hdr->canary != SMEM_ALLOCATION_CANARY) {
LOG_ERR(
"%s: SMEM corruption detected. Partition %d to %d at %p\n",
__func__,
partition_num,
to_proc,
alloc_hdr);
BUG();
}
if (alloc_hdr->smem_type == id) {
/* 8 byte alignment to match legacy */
*size = ALIGN(alloc_hdr->size -
alloc_hdr->padding_data, 8);
item = (void *)(alloc_hdr) +
sizeof(*alloc_hdr) +
alloc_hdr->padding_hdr;
//第一个item 0x87d0000+540K+sizeof(*hdr)+sizeof(*alloc_hdr)+alloc_hdr->padding_hdr
//第二个item
0x87d0000+540K+sizeof(*hdr)+sizeof(*alloc_hdr)+alloc_hdr->padding_hdr+alloc_hdr->size + sizeof(*alloc_hdr)+alloc_hdr->padding_hdr
//smem_get_entry(13..) 放在在第二个item
break;
}
}
}
...
}
IPCRTR 放在shared[1] 中
scan_alloc_table ->
smd_alloc_channel 分配内存 struct smd_channel *ch
platform_device_register(&ch->pdev); 注册IPCRTR设备
此时调用 msm_ipc_router_smd_remote_probe