Broadcom fullmac WLAN 驱动解析(1)
在https://wiki.archlinux.org/index.php/Broadcom_wireless里面关于broadcom的wireless驱动有这样的说明
The brcm80211 drivers are included in the kernel. They are named brcmsmac for PCI cards and brcmfmac for SDIO devices.
这里我们分析针对SDIO设备的brcmfmac驱动。
1. 驱动主入口
void brcmf_sdio_init(void) { int ret; brcmf_dbg(TRACE, "Enter\n"); ret = sdio_register_driver(&brcmf_sdmmc_driver); if (ret) brcmf_err("sdio_register_driver failed: %d\n", ret); }
可以看到brcmf_sdmmc_driver被传给了sdio_register_driver(), brcmf_sdmmc_driver的定义如下:
static struct sdio_driver brcmf_sdmmc_driver = { .probe = brcmf_ops_sdio_probe, // probe函数很关键! .remove = brcmf_ops_sdio_remove, .name = "brcmfmac", .id_table = brcmf_sdmmc_ids, #ifdef CONFIG_PM_SLEEP .drv = { .pm = &brcmf_sdio_pm_ops, }, #endif /* CONFIG_PM_SLEEP */ };
2. brcmf_ops_sdio_probe()被调用
关于probe函数是如何调用的,网上的文章很多,这里就再不赘述了。
static int brcmf_ops_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) { int err; struct brcmf_sdio_dev *sdiodev; struct brcmf_bus *bus_if; ... /* Consume func num 1 but dont do anything with it. */ if (func->num == 1) return 0; /* Ignore anything but func 2 */ if (func->num != 2) return -ENODEV; bus_if = kzalloc(sizeof(struct brcmf_bus), GFP_KERNEL); if (!bus_if) return -ENOMEM; sdiodev = kzalloc(sizeof(struct brcmf_sdio_dev), GFP_KERNEL); if (!sdiodev) { kfree(bus_if); return -ENOMEM; } sdiodev->func[0] = func->card->sdio_func[0]; sdiodev->func[1] = func->card->sdio_func[0]; sdiodev->func[2] = func; sdiodev->bus_if = bus_if; bus_if->bus_priv.sdio = sdiodev; bus_if->align = BRCMF_SDALIGN; dev_set_drvdata(&func->dev, bus_if); dev_set_drvdata(&sdiodev->func[1]->dev, bus_if); sdiodev->dev = &sdiodev->func[1]->dev; ... brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_probe...\n"); // 注意这里 err = brcmf_sdio_probe(sdiodev); if (err) { brcmf_err("F2 error, probe failed %d...\n", err); goto fail; } brcmf_dbg(TRACE, "F2 init completed...\n"); return 0; ... }
3. 调用brcmf_sdio_probe()
int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) { u32 regs = 0; int ret = 0; ret = brcmf_sdioh_attach(sdiodev); if (ret) goto out; regs = SI_ENUM_BASE; /* try to attach to the target device */ sdiodev->bus = brcmf_sdbrcm_probe(regs, sdiodev); if (!sdiodev->bus) { brcmf_err("device attach failed\n"); ret = -ENODEV; goto out; } out: if (ret) brcmf_sdio_remove(sdiodev); return ret; }
4. 调用brcmf_sdbrcm_probe()
void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) { int ret; struct brcmf_sdio *bus; struct brcmf_bus_dcmd *dlst; u32 dngl_txglom; u32 dngl_txglomalign; u8 idx; brcmf_dbg(TRACE, "Enter\n"); /* We make an assumption about address window mappings: * regsva == SI_ENUM_BASE*/ /* Allocate private bus interface state */ bus = kzalloc(sizeof(struct brcmf_sdio), GFP_ATOMIC); if (!bus) goto fail; bus->sdiodev = sdiodev; sdiodev->bus = bus; skb_queue_head_init(&bus->glom); bus->txbound = BRCMF_TXBOUND; bus->rxbound = BRCMF_RXBOUND; bus->txminmax = BRCMF_TXMINMAX; bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1; // 初始化工作队列,用来接收/发送数据 INIT_WORK(&bus->datawork, brcmf_sdio_dataworker); bus->brcmf_wq = create_singlethread_workqueue("brcmf_wq"); if (bus->brcmf_wq == NULL) { brcmf_err("insufficient memory to create txworkqueue\n"); goto fail; } /* attempt to attach to the dongle */ if (!(brcmf_sdbrcm_probe_attach(bus, regsva))) { brcmf_err("brcmf_sdbrcm_probe_attach failed\n"); goto fail; } ... /* Assign bus interface call back */ bus->sdiodev->bus_if->dev = bus->sdiodev->dev; // 注意这里的brcmf_sdio_bus_ops bus->sdiodev->bus_if->ops = &brcmf_sdio_bus_ops; bus->sdiodev->bus_if->chip = bus->ci->chip; bus->sdiodev->bus_if->chiprev = bus->ci->chiprev; /* Attach to the brcmf/OS/network interface */ ret = brcmf_attach(SDPCM_RESERVE, bus->sdiodev->dev); if (ret != 0) { brcmf_err("brcmf_attach failed\n"); goto fail; } /* Allocate buffers */ if (!(brcmf_sdbrcm_probe_malloc(bus))) { brcmf_err("brcmf_sdbrcm_probe_malloc failed\n"); goto fail; } if (!(brcmf_sdbrcm_probe_init(bus))) { brcmf_err("brcmf_sdbrcm_probe_init failed\n"); goto fail; } ... /* if firmware path present try to download and bring up bus */ ret = brcmf_bus_start(bus->sdiodev->dev); // 非常重要! if (ret != 0) { brcmf_err("dongle is not responding\n"); goto fail; } return bus; ... }
brcmf_sdio_bus_ops的定义如下:
static struct brcmf_bus_ops brcmf_sdio_bus_ops = { .stop = brcmf_sdbrcm_bus_stop, .init = brcmf_sdbrcm_bus_init, .txdata = brcmf_sdbrcm_bus_txdata, .txctl = brcmf_sdbrcm_bus_txctl, .rxctl = brcmf_sdbrcm_bus_rxctl, };
5. 调用brcmf_bus_start()
int brcmf_bus_start(struct device *dev) { int ret = -1; struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_pub *drvr = bus_if->drvr; struct brcmf_if *ifp; struct brcmf_if *p2p_ifp; brcmf_dbg(TRACE, "\n"); /* Bring up the bus */ // 这里做初始化,request_irq等等 ret = brcmf_bus_init(bus_if); if (ret != 0) { brcmf_err("brcmf_sdbrcm_bus_init failed %d\n", ret); return ret; } /* add primary networking interface */ // 注册网卡 ifp = brcmf_add_if(drvr, 0, 0, "wlan%d", NULL); if (IS_ERR(ifp)) return PTR_ERR(ifp); if (brcmf_p2p_enable) p2p_ifp = brcmf_add_if(drvr, 1, 0, "p2p%d", NULL); else p2p_ifp = NULL; if (IS_ERR(p2p_ifp)) p2p_ifp = NULL; /* signal bus ready */ bus_if->state = BRCMF_BUS_DATA; /* Bus is ready, do any initialization */ ret = brcmf_c_preinit_dcmds(ifp); if (ret < 0) goto fail; drvr->fw_signals = true; (void)brcmf_fws_init(drvr); // 非常重要 drvr->config = brcmf_cfg80211_attach(drvr, bus_if->dev); if (drvr->config == NULL) { ret = -ENOMEM; goto fail; } ret = brcmf_fweh_activate_events(ifp); if (ret < 0) goto fail; // 注册net_device ret = brcmf_net_attach(ifp, false); ... return 0; }
5.1 先来看一下brcmf_bus_init()
static inline int brcmf_bus_init(struct brcmf_bus *bus) { return bus->ops->init(bus->dev); }
显然,由brcmf_sdio_bus_ops的定义可知,brcmf_sdbrcm_bus_init()在这里被触发
static int brcmf_sdbrcm_bus_init(struct device *dev) { struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; struct brcmf_sdio *bus = sdiodev->bus; unsigned long timeout; u8 ready, enable; int err, ret = 0; u8 saveclk; brcmf_dbg(TRACE, "Enter\n"); /* try to download image and nvram to the dongle */ if (bus_if->state == BRCMF_BUS_DOWN) { // 下载firmware: // brcmf_sdbrcm_download_firmware() -> // _brcmf_sdbrcm_download_firmware() -> // brcmf_sdbrcm_download_code_file() -> // request_firmware() if (!(brcmf_sdbrcm_download_firmware(bus))) return -1; } ... if (ret == 0) { //注册/申请中断 ret = brcmf_sdio_intr_register(bus->sdiodev); if (ret != 0) brcmf_err("intr register failed:%d\n", ret); } ... return ret; }
这里有必要跟一下brcmf_sdio_intr_register(),因为这涉及到如何接收数据:
int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev) { int ret = 0; u8 data; unsigned long flags; brcmf_dbg(TRACE, "Entering: irq %d\n", sdiodev->irq); // 注意这里传给request_irq的参数 ret = request_irq(sdiodev->irq, brcmf_sdio_irqhandler, sdiodev->irq_flags, "brcmf_oob_intr", &sdiodev->func[1]->dev); ... return 0; }
当有中断产生时,比如数据到来时,brcmf_sdio_irqhandler()将会以下面的顺序处理:
brcmf_sdio_irqhandler() -> brcmf_sdbrcm_isr() -> queue_work(bus->brcmf_wq, &bus->datawork);
根据前面4.的分析,brcmf_sdio_dataworker()会被触发,从而有下面的call flow:
brcmf_sdio_dataworker() -> brcmf_sdbrcm_dpc() -> brcmf_sdio_readframes()
继续跟一下brcmf_sdio_readframes()
static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) { ... for (rd->seq_num = bus->rx_seq, rxleft = maxframes; !bus->rxskip && rxleft && bus->sdiodev->bus_if->state != BRCMF_BUS_DOWN; rd->seq_num++, rxleft--) { ... rd->len_left = rd->len; /* read header first for unknow frame length */ sdio_claim_host(bus->sdiodev->func[1]); if (!rd->len) { // 从SDIO接收的数据保存到buf ret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad, SDIO_FUNC_2, F2SYNC, bus->rxhdr, BRCMF_FIRSTREAD); ... } ... // 根据buf中的数据生成skb pkt = brcmu_pkt_buf_get_skb(rd->len_left + head_read + BRCMF_SDALIGN); ... skb_queue_head_init(&pktlist); // 放入pktlist skb_queue_tail(&pktlist, pkt); // 调用brcmf_rx_frames()去处理pktlist brcmf_rx_frames(bus->sdiodev->dev, &pktlist); } ... }
brcmf_rx_frames会直接调用netif_rx()把数据发往kernel的网络子系统。
5.2 再来看一下brcmf_add_if()
struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx, char *name, u8 *mac_addr) { struct brcmf_if *ifp; struct net_device *ndev; brcmf_dbg(TRACE, "Enter, idx=%d, ifidx=%d\n", bssidx, ifidx); ifp = drvr->iflist[bssidx]; ... /* Allocate netdev, including space for private structure */ // 分配net_device结构体 ndev = alloc_netdev(sizeof(struct brcmf_if), name, ether_setup); if (!ndev) { brcmf_err("OOM - alloc_netdev\n"); return ERR_PTR(-ENOMEM); } ifp = netdev_priv(ndev); ifp->ndev = ndev; ifp->drvr = drvr; drvr->iflist[bssidx] = ifp; ifp->ifidx = ifidx; ifp->bssidx = bssidx; ... return ifp; }
这里最主要就是分配了net_device结构体。
5.3 分析一下brcmf_cfg80211_attach()
struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, struct device *busdev) { struct net_device *ndev = drvr->iflist[0]->ndev; struct brcmf_cfg80211_info *cfg; struct wiphy *wiphy; struct brcmf_cfg80211_vif *vif; struct brcmf_if *ifp; s32 err = 0; ... ifp = netdev_priv(ndev); // 非常重要,创建一个新的wiphy并且关联上cfg80211_ops wiphy = brcmf_setup_wiphy(busdev); if (IS_ERR(wiphy)) return NULL; cfg = wiphy_priv(wiphy); cfg->wiphy = wiphy; cfg->pub = drvr; init_vif_event(&cfg->vif_event); INIT_LIST_HEAD(&cfg->vif_list); vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION, false); if (IS_ERR(vif)) { wiphy_free(wiphy); return NULL; } vif->ifp = ifp; vif->wdev.netdev = ndev; ndev->ieee80211_ptr = &vif->wdev; SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy)); // wl_init_priv将会调用brcmf_register_event_handlers() // 从而为firemware传上来的事件注册相应的handler err = wl_init_priv(cfg); ... }
跟一下brcmf_setup_wiphy():
static struct wiphy *brcmf_setup_wiphy(struct device *phydev) { ... // 注意wl_cfg80211_ops,以rdev_scan()函数为例,其中的rdev->ops->scan将会触发brcmf_cfg80211_scan() wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info)); if (!wiphy) { brcmf_err("Could not allocate wiphy device\n"); return ERR_PTR(-ENOMEM); } set_wiphy_dev(wiphy, phydev); ... err = wiphy_register(wiphy); if (err < 0) { brcmf_err("Could not register wiphy device (%d)\n", err); wiphy_free(wiphy); return ERR_PTR(err); } return wiphy; }
可以看到跟ieee80211_alloc_hw()里面的代码是很类似的,可以参见http://www.cnblogs.com/hellolwl/archive/2013/04/10/3012569.html中的描述。
5.4 跟进brcmf_net_attach()
int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked) { struct brcmf_pub *drvr = ifp->drvr; struct net_device *ndev; s32 err; brcmf_dbg(TRACE, "Enter, idx=%d mac=%pM\n", ifp->bssidx, ifp->mac_addr); ndev = ifp->ndev; /* set appropriate operations */ // 注意这里的brcmf_netdev_ops_pri ndev->netdev_ops = &brcmf_netdev_ops_pri; ndev->hard_header_len = ETH_HLEN + drvr->hdrlen; ndev->ethtool_ops = &brcmf_ethtool_ops; drvr->rxsz = ndev->mtu + ndev->hard_header_len + drvr->hdrlen; /* set the mac address */ memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN); INIT_WORK(&ifp->setmacaddr_work, _brcmf_set_mac_address); INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list); // 注册net_device if (rtnl_locked) err = register_netdevice(ndev); else err = register_netdev(ndev); if (err != 0) { brcmf_err("couldn't register the net device\n"); goto fail; } brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name); return 0; ... }
根据5.2的分析,net_device已经在之前分配好了,这里就是注册net_device. 再看一下brcmf_netdev_ops_pri()的定义:
static const struct net_device_ops brcmf_netdev_ops_pri = { .ndo_open = brcmf_netdev_open, .ndo_stop = brcmf_netdev_stop, .ndo_get_stats = brcmf_netdev_get_stats, .ndo_do_ioctl = brcmf_netdev_ioctl_entry, .ndo_start_xmit = brcmf_netdev_start_xmit, .ndo_set_mac_address = brcmf_netdev_set_mac_address, .ndo_set_rx_mode = brcmf_netdev_set_multicast_list };
以ndo_start_xmit()为例,kernel发送数据时将会调用ndo_start_xmit. 那么brcmf_netdev_start_xmit()就会被触发。这里顺便分析一下发送数据的流程:
static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev) { ... /* Use bus module to send data frame */ ret = brcmf_bus_txdata(drvr->bus_if, skb); done: if (ret) { ifp->stats.tx_dropped++; } else { ifp->stats.tx_packets++; ifp->stats.tx_bytes += skb->len; } /* Return ok: we always eat the packet */ return NETDEV_TX_OK; }
调用brcmf_bus_tcxdata():
static inline int brcmf_bus_txdata(struct brcmf_bus *bus, struct sk_buff *skb) { return bus->ops->txdata(bus->dev, skb); }
这里bus->ops->txdata就会调用brcmf_sdbrcm_bus_txdata(),参见brcmf_sdio_bus_ops的定义。
static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt) { ... spin_lock_irqsave(&bus->dpc_tl_lock, flags); if (list_empty(&bus->dpc_tsklst)) { spin_unlock_irqrestore(&bus->dpc_tl_lock, flags); brcmf_sdbrcm_adddpctsk(bus); // 注意这里,brcmf_sdio_dataworker()将会被触发 queue_work(bus->brcmf_wq, &bus->datawork); } else { spin_unlock_irqrestore(&bus->dpc_tl_lock, flags); } return ret; }
brcmf_sdio_dataworker()又会调用brcmf_sdbrcm_dpc():
static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) { ... /* Send queued frames (limit 1 if rx may still be pending) */ else if ((bus->clkstate == CLK_AVAIL) && !atomic_read(&bus->fcstate) && brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && data_ok(bus)) { framecnt = bus->rxpending ? min(txlimit, bus->txminmax) : txlimit; // 注意这里 framecnt = brcmf_sdbrcm_sendfromq(bus, framecnt); txlimit -= framecnt; } ... }
调用brcmf_sdbrcm_sendfromq()
static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes) { ... /* Send frames until the limit or some other event */ for (cnt = 0; (cnt < maxframes) && data_ok(bus); cnt++) { ... ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL); ... } ... }
接下来就有这样的调用顺序:
brcmf_sdbrcm_txpkt() -> brcmf_sdcard_send_pkt() -> brcmf_sdioh_request_buffer() -> brcmf_sdioh_request_data() -> sdio_memcpy_toio() -> sdio_io_rw_ext_helper()
顺便提一下,brcmf_sdbrcm_bus_txctl()跟brcmf_sdbrcm_bus_txdata()在call flow上是有区别的。
brcmf_sdbrcm_bus_txctl() -> brcmf_tx_frame() -> brcmf_sdcard_send_buf() -> brcmf_sdcard_send_pkt() -> ...