studing

//atmci_tasklet_func
1) atmci_interrupt-->
pending & (ATMCI_DATA_ERROR_FLAGS | ATMCI_BLKE | ATMCI_BLKE | ATMCI_CMDRDY)
tasklet_schedule-->atmci_tasklet_func
2)atmci_prepare_data_dma-->
desc->callback = atmci_dma_complete-->
atmci_dma_complete-->tasklet_schedule


//throughput disconnect dump_stack() message
atmel_mci f8000000.mmc: atmci_timeout_timer: host->mrq->cmd->data->error = -110, ATMCI_SR = 0x1 
[] (unwind_backtrace+0x0/0xe0) from [] (atmci_timeout_timer+0x58/0xdc)
[] (atmci_timeout_timer+0x58/0xdc) from [] (run_timer_softirq+0x130/0x1cc)
[] (run_timer_softirq+0x130/0x1cc) from [] (__do_softirq+0x90/0x144)
[] (__do_softirq+0x90/0x144) from [] (irq_exit+0x40/0x4c)
[] (irq_exit+0x40/0x4c) from [] (handle_IRQ+0x64/0x84)
[] (handle_IRQ+0x64/0x84) from [] (__irq_svc+0x40/0x50)
[] (__irq_svc+0x40/0x50) from [] (default_idle+0x24/0x2c)
[] (default_idle+0x24/0x2c) from [] (cpu_idle+0x60/0xb8)
[] (cpu_idle+0x60/0xb8) from [] (start_kernel+0x26c/0x2bc)
net_ratelimit: 1 callbacks suppressed
dhdsdio_txpkt: sdio error -1, abort command and terminate frame.
[] (unwind_backtrace+0x0/0xe0) from [] (dhdsdio_txpkt.isra.8.constprop.16+0x478/0x5d4)
[] (dhdsdio_txpkt.isra.8.constprop.16+0x478/0x5d4) from []


(dhdsdio_sendfromq+0xf0/0x2a0)
[] (dhdsdio_sendfromq+0xf0/0x2a0) from [] (dhdsdio_readframes+0x180/0x1678)
[] (dhdsdio_readframes+0x180/0x1678) from [] (dhd_bus_dpc+0xb78/0xf20)
[] (dhd_bus_dpc+0xb78/0xf20) from [] (dhd_dpc_thread+0x88/0xd0)
[] (dhd_dpc_thread+0x88/0xd0) from [] (kthread+0x80/0x90)
[] (kthread+0x80/0x90) from [] (kernel_thread_exit+0x0/0x8)
atmel_mci f8000000.mmc: atmci_timeout_timer: host->mrq->cmd->data->error = -110, ATMCI_SR = 0x4000015 
[] (unwind_backtrace+0x0/0xe0) from [] (atmci_timeout_timer+0x58/0xdc)
[] (atmci_timeout_timer+0x58/0xdc) from [] (run_timer_softirq+0x130/0x1cc)


//throughput
[<c00116d0>] (unwind_backtrace+0x0/0xe0) from [<c02a391c>] (sdioh_request_packet+0x2c/0x504)
[<c02a391c>] (sdioh_request_packet+0x2c/0x504) from [<c02a4aac>] (sdioh_request_buffer+0x174/0x1c4)
[<c02a4aac>] (sdioh_request_buffer+0x174/0x1c4) from [<c029e170>] (bcmsdh_recv_buf+0x7c/0x9c)
[<c029e170>] (bcmsdh_recv_buf+0x7c/0x9c) from [<c02946cc>] (dhd_bcmsdh_recv_buf.constprop.13+0x94/0xa8)
[<c02946cc>] (dhd_bcmsdh_recv_buf.constprop.13+0x94/0xa8) from [<c0297044>] (dhdsdio_readframes+0x9b8/0x1678)
[<c0297044>] (dhdsdio_readframes+0x9b8/0x1678) from [<c029a8b8>] (dhd_bus_dpc+0xb78/0xf20)
[<c029a8b8>] (dhd_bus_dpc+0xb78/0xf20) from [<c028978c>] (dhd_dpc_thread+0x88/0xd0)
[<c028978c>] (dhd_dpc_thread+0x88/0xd0) from [<c0030910>] (kthread+0x80/0x90)
[<c0030910>] (kthread+0x80/0x90) from [<c000e328>] (kernel_thread_exit+0x0/0x8)




//scan netlist
(ret_fast_syscall+0x0/0x30)-->
(sys_sendmsg+0x3c/0x60) -->
(__sys_sendmsg+0x1c4/0x250) -->
(sock_sendmsg+0x80/0x9c) -->
(netlink_unicast+0x140/0x1ec) -->
(genl_rcv+0x18/0x24) -->
(netlink_rcv_skb+0x50/0xac) -->
(genl_rcv_msg+0x1b0/0x208) -->
(nl80211_get_station+0x5c/0xf8) -->
(wl_cfg80211_get_station+0x388/0x630) -->
(wldev_ioctl+0x40/0x48) -->
(dhd_ioctl_entry_local+0xc0/0xf4) -->
(dhd_wl_ioctl+0x40/0x78) -->
(dhd_prot_ioctl+0x3fc/0x5d4) -->
(dhdcdc_msg+0x54/0x74) -->
(dhd_bus_txctl+0x324/0x4e0) -->
(dhd_bcmsdh_send_buf.constprop.17+0x68/0x7c) -->
(bcmsdh_send_buf+0x7c/0x9c) -->
(sdioh_request_buffer+0x174/0x1c4) -->
(sdioh_request_packet+0x2c/0x504) 




//interrupt
dhd_attach-->
PROC_START(dhd_watchdog_thread, dhd, &dhd->thr_wdt_ctl, 0, "dhd_watchdog_thread");
//dhd_watchdog_thread:284 started
PROC_START(dhd_dpc_thread, dhd, &dhd->thr_dpc_ctl, 0, "dhd_dpc")-->
//ddhd_dpc:285 started
dhd_dpc_thread-->
if (down_interruptible(&tsk->sema) == 0) {......dhd_bus_dpc(dhd->pub.bus)......}-->
dhd_bus_dpc-->
dhdsdio_dpc-->
dhdsdio_readframes-->
dhd_rx_frame-->
netif_rx_ni(skb)-->
//通过netif_rx_ni将封包提交到上层协议
PROC_START(_dhd_sysioc_thread, dhd, &dhd->thr_sysioc_ctl, 0, "dhd_sysioc")
//dhd_sysioc:286 started;


atmci_interrupt-->
if (pending & (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB))
atmci_sdio_interrupt(host, status);-->
mmc_signal_sdio_irq-->
wake_up_process(host->sdio_irq_thread)-->
//sdio_card_irq_get-->host->sdio_irq_thread =kthread_run(sdio_irq_thread, host, "ksdioirqd/%s",mmc_hostname(host));
sdio_irq_thread-->
process_sdio_pending_irqs-->
func->irq_handler(func)-->


1)dhdsdio_probe-->
bcmsdh_intr_reg(sdh, dhdsdio_isr, bus))[bcmsdh.c]-->
 sdioh_interrupt_register(bcmsdh->sdioh, fn, argh)-->
// Configure callback to client when we recieve client interrupt
//sdio_claim_irq(gInstance->func[2], IRQHandlerF2)(sdio_claim_irq(gInstance->func[1], IRQHandler);); no usefull
sdioh_enable_func_intr();


2)sdioh_start-->
//sdio_claim_irq(gInstance->func[2], IRQHandlerF2)(sdio_claim_irq(gInstance->func[1], IRQHandler);); no usefull
sdioh_enable_func_intr
bcmsdh_oob_intr_set(TRUE)






//dhd_sched_dpc
1)
(kernel_thread_exit+0x0/0x8)-->
(kthread+0x80/0x90) -->
(dhd_dpc_thread+0x88/0xd0) -->
(dhd_bus_dpc+0xc08/0xf20) -->
(bcmsdh_oob_intr_set+0x4c/0x58) -->
(__irq_svc+0x40/0x50) -->
(handle_IRQ+0x60/0x84) -->
(generic_handle_irq+0x20/0x30) -->
(gpio_irq_handler+0x98/0xd0) -->
(generic_handle_irq+0x20/0x30) -->
(handle_irq_event+0x28/0x38) -->
(handle_irq_event_percpu+0x2c/0x18c) -->
(wlan_oob_irq+0x40/0x54) -->
(dhdsdio_isr+0x198/0x1cc) -->
dhd_sched_dpc 


2)
(ret_fast_syscall+0x0/0x30)-->
(sys_ioctl+0x30/0x58) -->
(do_vfs_ioctl+0x4f0/0x548) -->
(vfs_ioctl+0x28/0x3c) -->
(sock_ioctl+0x230/0x284) -->
(devinet_ioctl+0x294/0x68c) -->
(dev_change_flags+0x10/0x44) -->
(__dev_change_flags+0x8c/0x110) -->
(__dev_open+0x7c/0x108) -->
(dhd_open+0x154/0x2f4) -->
(wl_android_wifi_on+0xf8/0x1b8) -->
(dhd_preinit_ioctls+0x530/0xb30) -->
(dhd_wl_ioctl_cmd+0x34/0x3c) -->
(dhd_wl_ioctl+0x40/0x78) -->
(dhd_prot_ioctl+0x230/0x5d4) -->
(dhdcdc_msg+0x54/0x74) -->
(dhd_bus_txctl+0x45c/0x4e0) -->
(dhd_os_sdunlock+0x0/0x1c) -->
(__irq_svc+0x40/0x50) -->
(handle_IRQ+0x60/0x84) -->
(generic_handle_irq+0x20/0x30) -->
(gpio_irq_handler+0x98/0xd0) -->
(generic_handle_irq+0x20/0x30) -->
(handle_irq_event+0x28/0x38) -->
(handle_irq_event_percpu+0x2c/0x18c) -->
(wlan_oob_irq+0x40/0x54) -->
(dhdsdio_isr+0x198/0x1cc) -->
>dhd_sched_dpc 




3)
(ret_fast_syscall+0x0/0x30)-->
(sys_write+0x34/0x68) -->
(vfs_write+0xcc/0x130) -->
(__irq_svc+0x40/0x50) -->
(handle_IRQ+0x60/0x84) -->
(generic_handle_irq+0x20/0x30) -->
(gpio_irq_handler+0x98/0xd0) -->
(generic_handle_irq+0x20/0x30) -->
(handle_irq_event+0x28/0x38) -->
(handle_irq_event_percpu+0x2c/0x18c) -->
(wlan_oob_irq+0x40/0x54) -->
(dhdsdio_isr+0x198/0x1cc) -->
>dhd_sched_dpc 


4)
(__irq_usr+0x3c/0x60)-->
(handle_IRQ+0x60/0x84) -->
(generic_handle_irq+0x20/0x30) -->
(gpio_irq_handler+0x98/0xd0) -->
(generic_handle_irq+0x20/0x30) -->
(handle_irq_event+0x28/0x38) -->
(handle_irq_event_percpu+0x2c/0x18c) -->
(wlan_oob_irq+0x40/0x54) -->
(dhdsdio_isr+0x198/0x1cc) -->
>dhd_sched_dpc 




//dhd_watchdog_thread
dhd_watchdog_thread(void *data){
if (down_interruptible (&tsk->sema) == 0) {
if (dhd->pub.dongle_reset == FALSE) {
//Call the bus module watchdog 
dhd_bus_watchdog(&dhd->pub);
// Reschedule the watchdog 
if (dhd->wd_timer_valid)
mod_timer(&dhd->timer,jiffies +msecs_to_jiffies(dhd_watchdog_ms) -
min(msecs_to_jiffies(dhd_watchdog_ms), time_lapse));


}
}


}




//dhd_os_wd_timer
(kernel_thread_exit+0x0/0x8)-->
(kthread+0x80/0x90) -->
(dhd_dpc_thread+0x88/0xd0) -->
(dhd_bus_dpc+0x2f8/0xf20) -->
(dhdsdio_clkctl.isra.2+0x50/0x1d0) -->
(dhd_os_wd_timer+0xfc/0x150) -->
dhd_os_wd_timer-->




//tx and rx
dhd_rx_frame[dhd_linux.c]-->
netif_rx_ni(skb)-->
//If the receive is not processed inside an ISR, the softirqd must be woken explicitly to service the NET_RX_SOFTIRQ.  
//In 2.6 kernels, this is handledby netif_rx_ni(), but in earlier kernels, we needto do it manually.
//引起软中断NET_RX_SOFTIRQ


net_dev_init-->
//在net_dev_init()[net/core/dev.c]中,注册了两个软中断处理函数,所以引起软中断后,最终调用了net_rx_action()
-->open_softirq(NET_TX_SOFTIRQ, net_tx_action);
-->open_softirq(NET_RX_SOFTIRQ, net_rx_action);
-->[1]struct softnet_data *sd = &__get_cpu_var(softnet_data);
[2]list_first_entry(&sd->poll_list, struct napi_struct, poll_list); 
//从poll_list的头中取出一个napi_struct,然后执行代码[3],调用poll()函数;注意到这里在interrupt时,会向poll_list尾部加入一个napi_struct,并引起软中断,在软中断处理函数中,会从poll_list头部移除一个napi_struct,进行处理,理论上说,硬件中断加入的数据在其引起的软中断中被处理
[3] work = n->poll(n, weight);  




//dhd_bus_watchdog
dhd_bus_watchdog{
if (!SLPAUTO_ENAB(bus) && (bus->poll && (++bus->polltick >= bus->pollrate))) {...}
//SLPAUTO_ENAB(bus) = 0, bus->poll= 0, bus->polltick = 0, bus->pollrate = 0
#ifdef DHD_DEBUG
// Poll for console output periodically 
if (dhdp->busstate == DHD_BUS_DATA && dhd_console_ms != 0) {...}
//dhdp->busstate = 2, dhd_console_ms = 0


#ifdef SDTEST
//Generate packets if configured 
if (bus->pktgen_count && (++bus->pktgen_tick >= bus->pktgen_freq)) {...}
//bus->pktgen_count = 0, bus->pktgen_tick = 0, bus->pktgen_freq = 1
//On idle timeout clear activity flag and/or turn off clock
#ifdef DHD_USE_IDLECOUNT
#else
if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) {...} //analyzing


}




//init
dhdsdio_probe[dhd_sdio.c]-->
dhd_net_attach
// Ok, have the per-port tell the stack we're open for business -->
net->netdev_ops = &dhd_ops_virt;
static struct net_device_ops dhd_ops_virt = {
.ndo_get_stats = dhd_get_stats,
.ndo_do_ioctl = dhd_ioctl_entry,
.ndo_start_xmit = dhd_start_xmit,
.ndo_set_mac_address = dhd_set_mac_address,
.ndo_set_multicast_list = dhd_set_multicast_list,
};
#if WIRELESS_EXT > 12
net->wireless_handlers = (struct iw_handler_def *)&wl_iw_handler_def;
//这里的初始化工作很重要,之后的ioctl流程会涉及到对它的使用


[wl_iw.c]const struct iw_handler_def wl_iw_handler_def =
{
.num_standard = ARRAYSIZE(wl_iw_handler),
.num_private = ARRAY_SIZE(wl_iw_priv_handler),
.num_private_args = ARRAY_SIZE(wl_iw_priv_args),
.standard = (iw_handler *) wl_iw_handler,
.private = wl_iw_priv_handler,
.private_args = wl_iw_priv_args,
#if WIRELESS_EXT >= 19
get_wireless_stats: dhd_get_wireless_stats,
#endif 
};




//ioctl
(ret_fast_syscall+0x0/0x30)-->
(sys_ioctl+0x30/0x58) -->
(do_vfs_ioctl+0x4f0/0x548) -->
(vfs_ioctl+0x28/0x3c) -->
(dev_ioctl+0x624/0x654) -->
(wext_handle_ioctl+0x1f0/0x238) -->
// entry point from dev ioctl
wext_ioctl_dispatch(net, ifr, cmd, &info, ioctl_standard_call, ioctl_private_call); -->
1)[wext-core.c]ioctl_standard_call-->
//Get the description of the IOCTL
//ioctl_standard_call-->IW_IOCTL_IDX(cmd)  = 27,  standard_ioctl_num = 55
if (IW_IOCTL_IDX(cmd) >= standard_ioctl_num)
//Check if we have a pointer to user space data or not
//ioctl_standard_call-->descr->header_type  = 8,  IW_HEADER_TYPE_POINT = 8
if (descr->header_type != IW_HEADER_TYPE_POINT) -->
ioctl_standard_iw_point-->
switch (cmd) {
//get ESSID
case SIOCGIWESSID:
...
}
// Main IOCTl dispatcher. Check the type of IOCTL and call the appropriate wrapper...
2)[wext-core.c]wireless_process_ioctl-->
//通过网络接口名获取net_device设备*/
// Permissions are already checked in dev_ioctl() before calling us. The copy_to/from_user() of ifr is also dealt with in there 
// Make sure the device exist 
[1] if ((dev = __dev_get_by_name(net, ifr->ifr_name)) == NULL) 
 
//A bunch of special cases, then the generic case...  Note that 'cmd' is already filtered in dev_ioctl() with (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) 
[2]     if (cmd == SIOCGIWSTATS)
//如果是状态查询命令,调用该函数(回调函数中的一个)
                returnstandard(dev, iwr, cmd, info, &iw_handler_get_iwstats);   


#ifdef CONFIG_WEXT_PRIV
        if (cmd == SIOCGIWPRIV && dev->wireless_handlers)
//如果是专有命令,调用回调函数,同上
                returnstandard(dev, iwr, cmd, info,
                               iw_handler_get_private);     


#endif


  // New driver API : try to find thehandler 
 [3]      handler = get_handler(dev, cmd);    
//根据cmd参数,从dev成员中查询相应的处理函数          
        if (handler) {
                // Standard and private are notthe same
//cmd = 0x8b1b, SIOCIWFIRSTPRIV = 0x8be0
                if (cmd < SIOCIWFIRSTPRIV)
//调用相应命令的处理函数
                        return standard(dev, iwr, cmd, info, handler);  
                else if (private)
                        return private(dev, iwr, cmd, info, handler);     //同上
        }


        //Old driver API : call driver ioctlhandler
        if(dev->netdev_ops->ndo_do_ioctl)
//如果被设置就调用该函数
                return dev->netdev_ops->ndo_do_ioctl(dev,ifr, cmd);    


//该函数的大意是,通过网络接口名称获得一个网络设备,然后根据命令的类型调用相应的处理函数,特别的是当dev->netdev_ops->ndo_do_ioctl或dev->wireless_handlers被设置时,则会查找执行对应的处理函数。Get_handle函数用于查询处理函数使用


//get_handler
get_handler-->
//这里的dev->wireless_handlers在net初始化时被作为扩张功能选择性的设置,前面有提到过
//in dhd_net_attach() net->wireless_handlers = (struct iw_handler_def *)&wl_iw_handler_def;
handlers = dev->wireless_handlers;


//回调函数中对传递过来的handler函数指针进行呼叫,对应的处理函数就会被执行,当然用户传送的命令还不止这些,所以才会有net->netdev_ops的存在的必要性。下面来就来看看执行到:
//wireless_process_ioctl的最后一句
//return dev->netdev_ops->ndo_do_ioctl(dev, ifr, cmd);     
//就会调用dhd_ioctl函数,这是wlan驱动对ioctl调用的处理函数,就是根据用户传递过来的cmd,给它找一个最合适最合理的“归宿”。
dhd_ioctl_entry-->
//cmd = 0x89f1 or 0x89f0
if ((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) {...}
dhd_ioctl_process-->
          


//sdio_host_interrupt
// 1.采用中断方式
atmci_interrupt[atmel-mci.c]-->
if (pending & (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB)) //pending = 0x100, status = 0x125
atmci_sdio_interrupt(host, status);
atmci_sdio_interrupt(host, status)-->
mmc_signal_sdio_irq(slot->mmc)-->
host->ops->enable_sdio_irq(host, 0)-->
wake_up_process(host->sdio_irq_thread);


sdio_irq_thread[sdio_irq.c]-->
enable_sdio_irq(host, 1)-->
atmci_enable_sdio_irq-->


// 2.采用非中断方式
1)//atmci_interrupt: status = 0x800002f, mask = 0xc0600003, pending = 0x3
(kernel_thread_exit+0x0/0x8)-->
(kthread+0x80/0x90) -->
(dhd_dpc_thread+0x88/0xd0) -->
(dhd_bus_dpc+0x358/0xf20) -->
(bcmsdh_reg_read+0x6c/0xc0) -->
(sdioh_request_word+0x194/0x260) -->
(sdio_readl+0x28/0x4c) -->
(sdio_memcpy_fromio+0x14/0x18) -->
(sdio_io_rw_ext_helper+0x184/0x1c0) -->
(mmc_io_rw_extended+0x15c/0x1b4) -->
(mmc_wait_for_req_done+0x18/0x74) -->
(__irq_svc+0x40/0x50) -->
(handle_IRQ+0x60/0x84) -->
(generic_handle_irq+0x20/0x30) -->
(handle_fasteoi_irq+0xa4/0xe4) -->
(handle_irq_event+0x28/0x38) -->
(handle_irq_event_percpu+0x2c/0x18c) -->
(atmci_interrupt+0x88/0x8f0) 


2)//atmci_interrupt: status = 0xc000025, mask = 0xc0600020, pending = 0x20
(kernel_thread_exit+0x0/0x8)-->
(kthread+0x80/0x90) -->
(dhd_dpc_thread+0x88/0xd0) -->
(dhd_bus_dpc+0x358/0xf20) -->
(bcmsdh_reg_read+0x6c/0xc0) -->
(sdioh_request_word+0x194/0x260) -->
(sdio_readl+0x28/0x4c) -->
(sdio_memcpy_fromio+0x14/0x18) -->
(sdio_io_rw_ext_helper+0x184/0x1c0) -->
(mmc_io_rw_extended+0x15c/0x1b4) -->
(mmc_wait_for_req+0x10/0x20) 
(__mmc_start_req+0x134/0x14c) 
(local_bh_enable+0x88/0xbc) 
(do_softirq+0x40/0x4c) 
(__do_softirq+0x90/0x144) 
(tasklet_action+0x70/0xa8) 
(atmci_tasklet_func+0x20/0x3a4) 
(__irq_svc+0x40/0x50) -->
(handle_IRQ+0x60/0x84) -->
(generic_handle_irq+0x20/0x30) -->
(handle_fasteoi_irq+0xa4/0xe4) -->
(handle_irq_event+0x28/0x38) -->
(handle_irq_event_percpu+0x2c/0x18c) -->
(atmci_interrupt+0x88/0x8f0) 


3)//atmci_interrupt: status = 0xe00002d, mask = 0xc0600001, pending = 0x1
(kernel_thread_exit+0x0/0x8)-->
(kthread+0x80/0x90) -->
(dhd_dpc_thread+0x88/0xd0) -->
(dhd_bus_dpc+0x358/0xf20) -->
(dhdsdio_readframes+0x9b8/0x1678) 
(bcmsdh_recv_buf+0x7c/0x9c) 
(sdioh_request_buffer+0x174/0x1c4) 
(sdioh_request_packet+0x49c/0x500) 
(sdio_readsb+0x14/0x18) 
(sdio_io_rw_ext_helper+0x184/0x1c0) 
(mmc_io_rw_extended+0x15c/0x1b4) 
(mmc_wait_for_req+0x10/0x20) 
(__mmc_start_req+0x134/0x14c) 
(atmci_request+0xb4/0xe0) 
(atmci_start_request+0x200/0x224) 
(msecs_to_jiffies+0x18/0x24) 
(__aeabi_uidiv+0x50/0x9c) 
(__irq_svc+0x40/0x50) 
(handle_IRQ+0x60/0x84) 
(generic_handle_irq+0x20/0x30) -->
(handle_fasteoi_irq+0xa4/0xe4) -->
(handle_irq_event+0x28/0x38) -->
(handle_irq_event_percpu+0x2c/0x18c) -->
(atmci_interrupt+0x88/0x8f0) 


4)//atmci_interrupt: status = 0xc00002d, mask = 0xc0600020, pending = 0x20
(kernel_thread_exit+0x0/0x8)-->
(kthread+0x80/0x90) -->
(dhd_dpc_thread+0x88/0xd0) -->
(dhd_bus_dpc+0x358/0xf20) -->
(dhdsdio_sendfromq+0xf0/0x2a0) 
(dhdsdio_txpkt.isra.8.constprop.16+0x3f4/0x5d0) 
(dhd_bcmsdh_send_buf.constprop.17+0x68/0x7c) 
(bcmsdh_send_buf+0x7c/0x9c) 
(sdioh_request_buffer+0x174/0x1c4) 
(sdioh_request_packet+0x460/0x500) 
(sdio_memcpy_toio+0x1c/0x20) 
(sdio_io_rw_ext_helper+0x184/0x1c0) 
(mmc_io_rw_extended+0x15c/0x1b4) 
(mmc_wait_for_req+0x10/0x20) 
(__mmc_start_req+0x134/0x14c) 
(local_bh_enable+0x88/0xbc) 
(do_softirq+0x40/0x4c) 
(__do_softirq+0x90/0x144) 
(tasklet_action+0x70/0xa8) 
(atc_tasklet+0x138/0x148) 
(atc_advance_work+0xe4/0x11c) 
(dma_run_dependencies+0x0/0x4) 
(__irq_svc+0x40/0x50) 
(handle_IRQ+0x60/0x84) 
(generic_handle_irq+0x20/0x30) 
(handle_fasteoi_irq+0xa4/0xe4) 
(handle_irq_event+0x28/0x38) 
(handle_irq_event_percpu+0x2c/0x18c) 
(atmci_interrupt+0x88/0x8f0) 


5)//atmci_interrupt: status = 0x4000005, mask = 0xc0600005, pending = 0x5
(kernel_thread_exit+0x0/0x8)-->
(kthread+0x80/0x90) -->
(dhd_dpc_thread+0x88/0xd0) -->
(dhd_bus_dpc+0x358/0xf20) -->
(bcmsdh_reg_write+0x68/0x8c)
(sdio_writel+0x20/0x2c) 
(sdio_memcpy_toio+0x1c/0x20) 
(sdio_io_rw_ext_helper+0x184/0x1c0) 
(mmc_io_rw_extended+0x15c/0x1b4) 
(mmc_wait_for_req+0x10/0x20) 
(__mmc_start_req+0x134/0x14c) 
(atmci_request+0xb4/0xe0) 
(atmci_start_request+0x200/0x224) 
(msecs_to_jiffies+0x18/0x24) 
(__aeabi_uidiv+0x58/0x9c)
(__irq_svc+0x40/0x50) 
(handle_IRQ+0x60/0x84) 
(generic_handle_irq+0x20/0x30) 
(handle_fasteoi_irq+0xa4/0xe4) 
(handle_irq_event+0x28/0x38) 
(handle_irq_event_percpu+0x2c/0x18c) 
(atmci_interrupt+0x88/0x8f0) 




6)//atmci_interrupt: status = 0x15, mask = 0xc0600001, pending = 0x1
(ret_fast_syscall+0x0/0x30)
(sys_sendmsg+0x3c/0x60) 
(__sys_sendmsg+0x1c4/0x250) 
(sock_sendmsg+0x80/0x9c) 
(netlink_sendmsg+0x290/0x314) 
(netlink_unicast+0x140/0x1ec) 
(genl_rcv+0x18/0x24) 
(netlink_rcv_skb+0x50/0xac) 
(genl_rcv_msg+0x1b0/0x208) 
(nl80211_get_station+0x5c/0xf8) 
(wl_cfg80211_get_station+0x2a0/0x630) 
(dhd_is_associated+0x4c/0x11c) 
(dhd_wl_ioctl_cmd+0x34/0x3c) 
(dhd_wl_ioctl+0x40/0x78) 
(dhd_prot_ioctl+0x3fc/0x5d4) 
(dhdcdc_msg+0x54/0x74) 
(dhd_bus_txctl+0x324/0x4e0) 
(dhd_bcmsdh_send_buf.constprop.17+0x68/0x7c) 
(bcmsdh_send_buf+0x7c/0x9c) 
(sdioh_request_buffer+0x174/0x1c4) 
(sdioh_request_packet+0x460/0x500) 
(sdio_memcpy_toio+0x1c/0x20) 
(sdio_io_rw_ext_helper+0x184/0x1c0) 
(mmc_io_rw_extended+0x15c/0x1b4) 
(mmc_wait_for_req+0x10/0x20) 
(__mmc_start_req+0x134/0x14c) 
(atmci_request+0xb4/0xe0) 
(atmci_start_request+0x200/0x224) 
(msecs_to_jiffies+0xc/0x24) 
(__irq_svc+0x40/0x50) 
(handle_IRQ+0x60/0x84) 
(generic_handle_irq+0x20/0x30) 
(handle_fasteoi_irq+0xa4/0xe4) 
(handle_irq_event+0x28/0x38) 
(handle_irq_event_percpu+0x2c/0x18c) 
(atmci_interrupt+0x88/0x8f0) 




7)atmci_interrupt: status = 0xc000025, mask = 0x1, pending = 0x1
(ret_fast_syscall+0x0/0x30)
(sys_sendmsg+0x3c/0x60) 
(__sys_sendmsg+0x1c4/0x250) 
(sock_sendmsg+0x80/0x9c) 
(netlink_sendmsg+0x290/0x314) 
(netlink_unicast+0x140/0x1ec) 
(genl_rcv+0x18/0x24) 
(netlink_rcv_skb+0x50/0xac) 
(genl_rcv_msg+0x1b0/0x208) 
(nl80211_trigger_scan+0x34c/0x474) 
(wl_cfg80211_scan+0xd8/0x178) 
(__wl_cfg80211_scan+0x8f4/0x10b8) 
(wldev_ioctl+0x40/0x48) 
 (dhd_ioctl_entry_local+0xc0/0xf4) 
(dhd_wl_ioctl+0x40/0x78) 
(dhd_prot_ioctl+0x230/0x5d4) 
(dhdcdc_msg+0x54/0x74) 
(dhd_bus_txctl+0x154/0x4e0) 
(dhdsdio_clkctl.isra.2+0x90/0x1d0) 
(dhdsdio_htclk.isra.1+0xe8/0x42c) 
(bcmsdh_cfg_read+0x50/0x94) 
(sdioh_cfg_read+0x20/0x24) 
(sdioh_request_byte+0x2a4/0x2e4) 
(sdio_readb+0x40/0x64) 
(mmc_io_rw_direct_host+0xb8/0x128) 
(mmc_wait_for_cmd+0x64/0x74) 
(mmc_wait_for_req+0x10/0x20) 
(__mmc_start_req+0x134/0x14c) 
(__irq_svc+0x40/0x50) 
(handle_IRQ+0x60/0x84) 
(generic_handle_irq+0x20/0x30) 
(handle_fasteoi_irq+0xa4/0xe4) 
(handle_irq_event+0x28/0x38) 
(handle_irq_event_percpu+0x2c/0x18c) 
(atmci_interrupt+0x88/0x8f0) 


8)see 7)
(kernel_thread_exit+0x0/0x8)
(kthread+0x80/0x90) 
(dhd_dpc_thread+0x88/0xd0) 
(dhd_bus_dpc+0x2f8/0xf20) 
(dhdsdio_clkctl.isra.2+0x90/0x1d0) 
(dhdsdio_htclk.isra.1+0xe8/0x42c) 
(bcmsdh_cfg_read+0x50/0x94) 
(sdioh_cfg_read+0x20/0x24) 
(sdio_readb+0x40/0x64) 
(mmc_io_rw_direct_host+0xb8/0x128) 
(mmc_wait_for_cmd+0x64/0x74) 
(mmc_wait_for_req_done+0x1c/0x74) 
(wait_for_common+0x120/0x158) 
(schedule_timeout+0x14/0x11c) 
(__irq_svc+0x40/0x50) 
(handle_IRQ+0x60/0x84) 
(generic_handle_irq+0x20/0x30) 
(handle_fasteoi_irq+0xa4/0xe4) 
(handle_irq_event+0x28/0x38) 
(handle_irq_event_percpu+0x2c/0x18c) 
(atmci_interrupt+0x88/0x8f0) 






//1)dhdsdio_isr
(kthread+0x80/0x90) 
(dhd_dpc_thread+0x88/0xd0) 
(dhd_bus_dpc+0xc08/0xf20) 
(bcmsdh_oob_intr_set+0x4c/0x58) 
(__irq_svc+0x40/0x50) 
(handle_IRQ+0x60/0x84) 
(generic_handle_irq+0x20/0x30) 
(gpio_irq_handler+0x98/0xd0) 
(generic_handle_irq+0x20/0x30) 
(handle_irq_event+0x28/0x38) 
(handle_irq_event_percpu+0x2c/0x18c) 
(wlan_oob_irq+0x40/0x54) 
(dhdsdio_isr+0x5c/0x1f4) 




2)
(start_kernel+0x26c/0x2bc)
(cpu_idle+0x60/0xb8) 
(default_idle+0x24/0x2c) 
(__irq_svc+0x40/0x50) 
(handle_IRQ+0x60/0x84) 
(generic_handle_irq+0x20/0x30) 
(gpio_irq_handler+0x98/0xd0) 
(generic_handle_irq+0x20/0x30) 
(handle_irq_event+0x28/0x38) 
 (handle_irq_event_percpu+0x2c/0x18c) 
(wlan_oob_irq+0x40/0x54) 
(dhdsdio_isr+0x5c/0x1f4) 






//dhdsdio_dpc


1)R_SDREG(newstatus, &regs->intstatus, retries);
bus->f1regdata++;
if (bcmsdh_regfail(bus->sdh))
newstatus = 0;
printk("%s:  newstatus = 0x%x, bus->hostintmask = 0x%x\n", 
__FUNCTION__, newstatus, bus->hostintmask); //billows debug
//newstatus == 0x20800040(or 0x800040 or 0x20000000)-->2)
2)bcmsdh_oob_intr_set(1)-->
wlan_oob_irq-->bcmsdh_oob_intr_set(0)






-------------------------------
wlan_oob_irq-->
1)bcmsdh_oob_intr_set(0)
2)dhdsdio_isr-->
(1)bus->ipend = TRUE;
(2)bcmsdh_intr_disable(sdh)
(3)dhd_sched_dpc-->
<1>up(&dhd->thr_dpc_ctl.sema)
--------------------------------




//dhdsdio_readframes
1) 参数:maxframes = 50, *finished = 1
2) bus->pktgen_count = 0x0, bus->pktgen_mode = 0x1,
即Packets to send each burst为0,(Configured mode: tx, rx, or echo)Type of test packets to use is echo
3) bus->rx_seq: Receive sequence number (expected) from 0 to 0xff,  = seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
4) TXCTLOK(bus): bus->tx_max - bus->tx_max = 0x1 = 6, bus->tx_max:from 0 to ff,
bus->ctrl_frame_stat = 0
5)bus->glom = null, bus->glomd = null
6)billows->dhd_readahead = 1, bus->nextlen = 0, 在dhdsdio_probe()中,dhd_readahead = TRUE;
7)-->dhd_bcmsdh_recv_buf(), bus->f2rxhdrs++(Number of header reads ) //Read frame header (hardware and software), bus->rxhdr = 0xdf0bd540(Header of current rx frame (in hdrbuf))
8)// Extract hardware header fields //将连续2个byte(unsigned char)地址中的数据取出来,
len = ltoh16_ua(bus->rxhdr);
check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
9) fcbits = 0x0, bus->flowcontrol = 0,  rx_seq = expected from 0 to 255.
10) >bus->tx_max - bus->tx_seq = 5 0r 6
11) /* Call a separate function for control frames */
12) if (chan == SDPCM_CONTROL_CHANNEL) { //billows->chan = 0 
dhdsdio_read_control(bus, bus->rxhdr, len, doff);
continue;
  }
13) bus->roundup = 0x200,bus->blocksize = 0x200
14) forcealign = 1,  rdlen % 4 == 0








//sk_buff_head
struct sk_buff_head {
/* These two members must be first. */
struct sk_buff *next;
struct sk_buff *prev;


__u32 qlen; //代表串列中元素的数目
spinlock_t lock; //防止对串列的同时存取
};








//sdio clock
static unsigned mmc_sdio_get_max_clock(struct mmc_card *card) //获得sdio最大clock,默认50MHz
{
if (mmc_card_highspeed(card)) {
/*
* The SDIO specification doesn't mention how
* the CIS transfer speed register relates to
* high-speed, but it seems that 50 MHz is
* mandatory.
*/
max_dtr = 50000000;   //trista20130913 remove
} else { 
max_dtr = card->cis.max_dtr;
}


atmci_probe-->
1)host->mck = clk_get(&pdev->dev, "mci_clk")-->
------------------------------------------------
"mci_clk"
1)[arch/arm/mach-at91/sama5d3.c]
static struct clk_lookup periph_clocks_lookups[] = {
// lookup table for DT entries
...
CLKDEV_CON_DEV_ID("mci_clk", "f0000000.mmc", &mmc0_clk),
CLKDEV_CON_DEV_ID("mci_clk", "f8000000.mmc", &mmc1_clk),
CLKDEV_CON_DEV_ID("mci_clk", "f8004000.mmc", &mmc2_clk),
...
}


static struct clk mmc1_clk = {
.name = "mci1_clk",
.pid = SAMA5D3_ID_HSMCI1, //Peripheral identifiers/interrupts. 22
.type = CLK_TYPE_PERIPHERAL, //8
};




------------------
//con_id
struct clk_lookup_alloc {
struct clk_lookup cl;
char dev_id[MAX_DEV_ID];
char con_id[MAX_CON_ID];
};
------------------
-----------------------------------------------
-->[drivers/clk/clkdev.c]struct clk *clk_get(struct device *dev, const char *con_id)
-->clk = of_clk_get_by_name(dev->of_node, con_id);
-->/**
 * of_clk_get_by_name() - Parse and lookup a clock referenced by a device node
 * @np: pointer to clock consumer node
 * @name: name of consumer's clock input, or NULL for the first clock reference
 *
 * This function parses the clocks and clock-names properties,
 * and uses them to look up the struct clk from the registered list of clock
 * providers.
 */
struct clk *of_clk_get_by_name(struct device_node *np, const char *name)
(1)index = of_property_match_string(np, "clock-names", name);
-->[drivers/of/base.c]
/**
 * of_property_match_string() - Find string in a list and return index
 * @np: pointer to node containing string list property
 * @propname: string list property name
 * @string: pointer to string to search for in string list
 *
 * This function searches a string list property and returns the index
 * of a specific string value.
 */


2)host->bus_hz = clk_get_rate(host->mck)-->
rate = clk->rate_hz; //132MHz




3)atmci_init_slot(host, &pdata->slot[0],0, ATMCI_SDCSEL_SLOT_A, ATMCI_SDIOIRQA);
(1) mmc = mmc_alloc_host(sizeof(struct atmel_mci_slot), &host->pdev->dev)-->
mmc_host_clk_init(host)-->
1] host->rescan_disable = 1; // scanning will be enabled when we're ready
2] INIT_DELAYED_WORK(&host->detect, mmc_rescan);


(2) mmc_add_host(mmc)-->
/*
 * Apply power to the MMC stack.  This is a two-stage process.
 * First, we enable power to the card without the clock running.
 * We then wait a bit for the power to stabilise.  Finally,
 * enable the bus drivers and clock to the card.
 *
 * We must _NOT_ enable the clock prior to power stablising.
 *
 * If a host does all the power sequencing itself, ignore the
 * initial MMC_POWER_UP stage.
 */
mmc_start_host(host)-->
1] host->f_init = max(freqs[0], host->f_min);
2] mmc_power_up(host)
[1] host->ios.power_mode = MMC_POWER_UP
[2] mmc_set_ios(host) //mmc1: clock 0Hz busmode 2 powermode 1 cs 0 Vdd 21 width 0 timing 0
[3] mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, false); //Set signal voltage to 3.3V 
[4] host->ios.power_mode = MMC_POWER_ON;
[5] mmc_set_ios(host); //mmc1: clock 400000Hz busmode 2 powermode 2 ......
/**
 * mmc_detect_change - process change of state on a MMC socket
 * @host: host which changed state.
 * @delay: optional delay to wait before detection (jiffies)
 *
 * MMC drivers should call this when they detect a card has been
 * inserted or removed. The MMC layer will confirm that any
 * present card is still functional, and initialize any newly
 * inserted.
 */
3] mmc_detect_change(host, 0)
[1] host->detect_change = 1;
[2] mmc_schedule_delayed_work(&host->detect, delay)-->mmc_rescan()




//mmc_rescan
mmc_rescan-->
1)mmc_rescan_try_freq-->
mmc_attach_sdio //Order's important: probe SDIO, then SD, then MMC -->
(1) mmc_send_io_op_cond
/*Assign a mmc bus handler to a host. Only one bus handler may control a host at any given time.
*/
(2) mmc_attach_bus(host, &mmc_sdio_ops)-->
static const struct mmc_bus_ops mmc_sdio_ops = {
.remove = mmc_sdio_remove,
.detect = mmc_sdio_detect,
.suspend = mmc_sdio_suspend,
.resume = mmc_sdio_resume,
.power_restore = mmc_sdio_power_restore,
.alive = mmc_sdio_alive,
};
-->void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops)
host->bus_ops = ops;
//@1 mmc_rescan-->if (host->bus_ops != NULL)-->mmc_schedule_delayed_work(&host->detect, HZ);
//@2 mmc_rescan-->host->bus_ops->detect(host);
//@3 __mmc_release_bus()-->host->bus_ops = NULL;
2) host->bus_ops->detect(host)
//@1 when mmc_rescan is called for the first time !(host->caps & MMC_CAP_NONREMOVABLE) is ture
//@2 Then we must set host->caps |= MMC_CAP_NONREMOVABLE;
-->[drivers/mmc/core/sdio.c]
mmc_sdio_detect-->
_mmc_detect_card_removed-->
host->caps |= MMC_CAP_NONREMOVABLE;    //trista20130914
if ((host->caps & MMC_CAP_NONREMOVABLE) || !host->bus_ops->alive)   
return 0;
3)if (host->bus_ops != NULL)-->
if (host->caps & MMC_CAP_NEEDS_POLL)
mmc_schedule_delayed_work(&host->detect, HZ);


//mmc_rescan_try_freq
1) mmc_power_up
if(host->ios.power_mode == MMC_POWER_ON)
return;
2)// Some eMMCs (with VCCQ always on) may not be reset after power up, sodo a hardware reset if possible.
 mmc_hw_reset_for_init(host);
(!(host->caps & MMC_CAP_HW_RESET) == 1 and !host->ops->hw_reset) == 1) reutn;
3) /*
* sdio_reset sends CMD52 to reset card.  Since we do not know
* if the card is being re-initialized, just send it.  CMD52
* should be ignored by SD/eMMC cards.
*/
sdio_reset(host); //set SDIO CCCR register I/O Abort(0x06) bit 3(RES) to 1, reset sdio card
4) mmc_go_idle
/*
* Non-SPI hosts need to prevent chipselect going active during
* GO_IDLE; that would put chips into SPI mode.  Remind them of
* that in case of hardware that won't pull up DAT3/nCS otherwise.
*
* SPI hosts ignore ios.chip_select; it's managed according to
* rules that must accommodate non-MMC slaves which this layer
* won't even know about.
*/
(1) mmc_set_chip_select(host, MMC_CS_HIGH); //mmc1: clock 400000Hz busmode 2 powermode 2 cs 1 Vdd 21 width 0 timing 0
(2) err = mmc_wait_for_cmd(host, &cmd, 0); //CMD0: Used to change from SD to SPI mode
(3) mmc_set_chip_select(host, MMC_CS_DONTCARE); //mmc1: clock 400000Hz busmode 2 powermode 2 cs 0 Vdd 21 width 0 timing 0
(4) mmc_send_if_cond(host, host->ocr_avail)
/*
* To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND
* before SD_APP_OP_COND. This command will harmlessly fail for
* SD 1.0 cards.
*/
1] cmd.opcode = SD_SEND_IF_COND; //CMD8 
2] err = mmc_wait_for_cmd(host, &cmd, 0) //err = 0xffffff92, return err;












  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要实现flex布局的两行三列,你可以使用以下代码: ```html <style> .container { display: flex; flex-flow: row wrap; height: 400px; } .item { flex: 0 0 calc(33.33% - 10px); height: 200px; margin: 5px; background-color: #ccc; } </style> <body> <div class="container"> <div class="item"></div> <div class="item"></div> <div class="item"></div> <div class="item"></div> <div class="item"></div> <div class="item"></div> </div> </body> ``` 这段代码中,我们使用了一个容器元素`<div class="container">`来包含六个子元素`<div class="item">`。通过设置`display: flex`可以使容器元素变成一个弹性容器,`flex-flow: row wrap`可以设置子元素按行排列,并自动换行。每个子元素的`flex`属性设置为`0 0 calc(33.33% - 10px)`,表示宽度占比为33.33%,并且不允许缩放和自动填充剩余空间。最后通过设置`margin`属性来控制子元素之间的间距。这样就实现了一个两行三列的flex布局。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [flex两列布局 以及三列布局](https://blog.csdn.net/zw_studing/article/details/108630799)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [Flex布局](https://download.csdn.net/download/weixin_38610870/16215679)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [双飞燕布局、圣杯布局、flex布局实现三列布局(两边固定中间自适应)](https://blog.csdn.net/qq_44742090/article/details/123188562)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值