u8 bus_header[BUS_HEADER_LEN];
        struct brcmf_proto_bcdc_dcmd msg;
        unsigned char buf[BRCMF_DCMD_MAXLEN];
+       struct brcmf_fws_info *fws;
 };
 
 
+struct brcmf_fws_info *drvr_to_fws(struct brcmf_pub *drvr)
+{
+       struct brcmf_bcdc *bcdc = drvr->proto->pd;
+
+       return bcdc->fws;
+}
+
 static int
 brcmf_proto_bcdc_msg(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf,
                     uint len, bool set)
                                          struct sk_buff *skb)
 {
        struct brcmf_if *ifp = brcmf_get_ifp(drvr, ifidx);
+       struct brcmf_bcdc *bcdc = drvr->proto->pd;
 
-       if (!brcmf_fws_queue_skbs(drvr->fws))
+       if (!brcmf_fws_queue_skbs(bcdc->fws))
                return brcmf_proto_txdata(drvr, ifidx, 0, skb);
 
        return brcmf_fws_process_skb(ifp, skb);
                            bool success)
 {
        struct brcmf_bus *bus_if = dev_get_drvdata(dev);
-       struct brcmf_pub *drvr = bus_if->drvr;
+       struct brcmf_bcdc *bcdc = bus_if->drvr->proto->pd;
        struct brcmf_if *ifp;
 
        /* await txstatus signal for firmware if active */
-       if (brcmf_fws_fc_active(drvr->fws)) {
+       if (brcmf_fws_fc_active(bcdc->fws)) {
                if (!success)
-                       brcmf_fws_bustxfail(drvr->fws, txp);
+                       brcmf_fws_bustxfail(bcdc->fws, txp);
        } else {
-               if (brcmf_proto_bcdc_hdrpull(drvr, false, txp, &ifp))
+               if (brcmf_proto_bcdc_hdrpull(bus_if->drvr, false, txp, &ifp))
                        brcmu_pkt_buf_free_skb(txp);
                else
                        brcmf_txfinalize(ifp, txp, success);
 static int
 brcmf_proto_bcdc_init_done(struct brcmf_pub *drvr)
 {
-       return brcmf_fws_attach(drvr);
+       struct brcmf_bcdc *bcdc = drvr->proto->pd;
+       struct brcmf_fws_info *fws;
+
+       fws = brcmf_fws_attach(drvr);
+       if (IS_ERR(fws))
+               return PTR_ERR(fws);
+
+       bcdc->fws = fws;
+       return 0;
 }
 
 int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr)
 
 void brcmf_proto_bcdc_detach(struct brcmf_pub *drvr)
 {
-       brcmf_fws_detach(drvr);
-       kfree(drvr->proto->pd);
+       struct brcmf_bcdc *bcdc = drvr->proto->pd;
+
        drvr->proto->pd = NULL;
+       brcmf_fws_detach(bcdc->fws);
+       kfree(bcdc);
 }
 
 #include "p2p.h"
 #include "cfg80211.h"
 #include "proto.h"
+#include "bcdc.h"
 #include "common.h"
 
 /**
                                       const struct brcmf_event_msg *e,
                                       void *data)
 {
-       struct brcmf_fws_info *fws = ifp->drvr->fws;
+       struct brcmf_fws_info *fws = drvr_to_fws(ifp->drvr);
        int i;
        u8 *credits = data;
 
                                                const struct brcmf_event_msg *e,
                                                void *data)
 {
-       struct brcmf_fws_info *fws = ifp->drvr->fws;
+       struct brcmf_fws_info *fws = drvr_to_fws(ifp->drvr);
 
        if (fws) {
                brcmf_fws_lock(fws);
 void brcmf_fws_hdrpull(struct brcmf_if *ifp, s16 siglen, struct sk_buff *skb)
 {
        struct brcmf_skb_reorder_data *rd;
-       struct brcmf_fws_info *fws = ifp->drvr->fws;
+       struct brcmf_fws_info *fws = drvr_to_fws(ifp->drvr);
        u8 *signal_data;
        s16 data_len;
        u8 type;
 
 int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
 {
-       struct brcmf_pub *drvr = ifp->drvr;
-       struct brcmf_fws_info *fws = drvr->fws;
+       struct brcmf_fws_info *fws = drvr_to_fws(ifp->drvr);
        struct brcmf_skbuff_cb *skcb = brcmf_skbcb(skb);
        struct ethhdr *eh = (struct ethhdr *)(skb->data);
        int fifo = BRCMF_FWS_FIFO_BCMC;
 
 void brcmf_fws_add_interface(struct brcmf_if *ifp)
 {
-       struct brcmf_fws_info *fws = ifp->drvr->fws;
+       struct brcmf_fws_info *fws = drvr_to_fws(ifp->drvr);
        struct brcmf_fws_mac_descriptor *entry;
 
        if (!ifp->ndev || fws->fcmode == BRCMF_FWS_FCMODE_NONE)
 void brcmf_fws_del_interface(struct brcmf_if *ifp)
 {
        struct brcmf_fws_mac_descriptor *entry = ifp->fws_desc;
+       struct brcmf_fws_info *fws = drvr_to_fws(ifp->drvr);
 
        if (!entry)
                return;
 
-       brcmf_fws_lock(ifp->drvr->fws);
+       brcmf_fws_lock(fws);
        ifp->fws_desc = NULL;
        brcmf_dbg(TRACE, "deleting %s\n", entry->name);
        brcmf_fws_macdesc_deinit(entry);
-       brcmf_fws_cleanup(ifp->drvr->fws, ifp->ifidx);
-       brcmf_fws_unlock(ifp->drvr->fws);
+       brcmf_fws_cleanup(fws, ifp->ifidx);
+       brcmf_fws_unlock(fws);
 }
 
 static void brcmf_fws_dequeue_worker(struct work_struct *worker)
 static int brcmf_debugfs_fws_stats_read(struct seq_file *seq, void *data)
 {
        struct brcmf_bus *bus_if = dev_get_drvdata(seq->private);
-       struct brcmf_fws_stats *fwstats = &bus_if->drvr->fws->stats;
+       struct brcmf_fws_stats *fwstats = &(drvr_to_fws(bus_if->drvr)->stats);
 
        seq_printf(seq,
                   "header_pulls:      %u\n"
 }
 #endif
 
-int brcmf_fws_attach(struct brcmf_pub *drvr)
+struct brcmf_fws_info *brcmf_fws_attach(struct brcmf_pub *drvr)
 {
        struct brcmf_fws_info *fws;
        struct brcmf_if *ifp;
        int rc;
        u32 mode;
 
-       drvr->fws = kzalloc(sizeof(*(drvr->fws)), GFP_KERNEL);
-       if (!drvr->fws) {
+       fws = kzalloc(sizeof(*fws), GFP_KERNEL);
+       if (!fws) {
                rc = -ENOMEM;
                goto fail;
        }
 
-       fws = drvr->fws;
-
        spin_lock_init(&fws->spinlock);
 
-       /* set linkage back */
+       /* store drvr reference */
        fws->drvr = drvr;
        fws->fcmode = drvr->settings->fcmode;
 
            (fws->fcmode == BRCMF_FWS_FCMODE_NONE)) {
                fws->avoid_queueing = true;
                brcmf_dbg(INFO, "FWS queueing will be avoided\n");
-               return 0;
+               return fws;
        }
 
        fws->fws_wq = create_singlethread_workqueue("brcmf_fws_wq");
        brcmf_fws_hanger_init(&fws->hanger);
        brcmf_fws_macdesc_init(&fws->desc.other, NULL, 0);
        brcmf_fws_macdesc_set_name(fws, &fws->desc.other);
+       brcmf_dbg(INFO, "added %s\n", fws->desc.other.name);
        brcmu_pktq_init(&fws->desc.other.psq, BRCMF_FWS_PSQ_PREC_COUNT,
                        BRCMF_FWS_PSQ_LEN);
 
 
        brcmf_dbg(INFO, "%s bdcv2 tlv signaling [%x]\n",
                  fws->fw_signals ? "enabled" : "disabled", tlv);
-       return 0;
+       return fws;
 
 fail:
-       brcmf_fws_detach(drvr);
-       return rc;
+       brcmf_fws_detach(fws);
+       return ERR_PTR(rc);
 }
 
-void brcmf_fws_detach(struct brcmf_pub *drvr)
+void brcmf_fws_detach(struct brcmf_fws_info *fws)
 {
-       struct brcmf_fws_info *fws = drvr->fws;
-
        if (!fws)
                return;
 
-       if (drvr->fws->fws_wq)
-               destroy_workqueue(drvr->fws->fws_wq);
+       if (fws->fws_wq)
+               destroy_workqueue(fws->fws_wq);
 
        /* cleanup */
        brcmf_fws_lock(fws);
        brcmf_fws_cleanup(fws, -1);
-       drvr->fws = NULL;
        brcmf_fws_unlock(fws);
 
        /* free top structure */
 
 void brcmf_fws_bus_blocked(struct brcmf_pub *drvr, bool flow_blocked)
 {
-       struct brcmf_fws_info *fws = drvr->fws;
+       struct brcmf_fws_info *fws = drvr_to_fws(drvr);
        struct brcmf_if *ifp;
        int i;