mac80211: defer master netdev allocation to ieee80211_register_hw
authorJohannes Berg <johannes@sipsolutions.net>
Fri, 8 Feb 2008 08:48:13 +0000 (09:48 +0100)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 29 Feb 2008 20:37:06 +0000 (15:37 -0500)
When we want to go multiqueue, we will need to know the number of
queues the hardware has for registering the master netdev. This
number is only available in ieee80211_register_hw() rather than
ieee80211_alloc_hw(), so defer allocation of the master device to
ieee80211_register_hw().

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
net/mac80211/ieee80211.c

index 91f06c3f4a7c304548015b600acdb588dc60b642..7df14799e38b9922372d50f84e7e144f142743e5 100644 (file)
@@ -1375,9 +1375,7 @@ EXPORT_SYMBOL(ieee80211_tx_status);
 struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
                                        const struct ieee80211_ops *ops)
 {
-       struct net_device *mdev;
        struct ieee80211_local *local;
-       struct ieee80211_sub_if_data *sdata;
        int priv_size;
        struct wiphy *wiphy;
 
@@ -1423,22 +1421,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        BUG_ON(!ops->configure_filter);
        local->ops = ops;
 
-       /* for now, mdev needs sub_if_data :/ */
-       mdev = alloc_netdev(sizeof(struct ieee80211_sub_if_data),
-                           "wmaster%d", ether_setup);
-       if (!mdev) {
-               wiphy_free(wiphy);
-               return NULL;
-       }
-
-       sdata = IEEE80211_DEV_TO_SUB_IF(mdev);
-       mdev->ieee80211_ptr = &sdata->wdev;
-       sdata->wdev.wiphy = wiphy;
-
        local->hw.queues = 1; /* default */
 
-       local->mdev = mdev;
-
        local->bridge_packets = 1;
 
        local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
@@ -1450,26 +1434,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        INIT_LIST_HEAD(&local->interfaces);
 
        INIT_DELAYED_WORK(&local->scan_work, ieee80211_sta_scan_work);
-       ieee80211_rx_bss_list_init(mdev);
 
        sta_info_init(local);
 
-       mdev->hard_start_xmit = ieee80211_master_start_xmit;
-       mdev->open = ieee80211_master_open;
-       mdev->stop = ieee80211_master_stop;
-       mdev->type = ARPHRD_IEEE80211;
-       mdev->header_ops = &ieee80211_header_ops;
-       mdev->set_multicast_list = ieee80211_master_set_multicast_list;
-
-       sdata->vif.type = IEEE80211_IF_TYPE_AP;
-       sdata->dev = mdev;
-       sdata->local = local;
-       sdata->u.ap.force_unicast_rateidx = -1;
-       sdata->u.ap.max_ratectrl_rateidx = -1;
-       ieee80211_if_sdata_init(sdata);
-       /* no RCU needed since we're still during init phase */
-       list_add_tail(&sdata->list, &local->interfaces);
-
        tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending,
                     (unsigned long)local);
        tasklet_disable(&local->tx_pending_tasklet);
@@ -1492,6 +1459,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        const char *name;
        int result;
        enum ieee80211_band band;
+       struct net_device *mdev;
+       struct ieee80211_sub_if_data *sdata;
 
        /*
         * generic code guarantees at least one band,
@@ -1515,6 +1484,37 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        if (result < 0)
                return result;
 
+       /* for now, mdev needs sub_if_data :/ */
+       mdev = alloc_netdev(sizeof(struct ieee80211_sub_if_data),
+                           "wmaster%d", ether_setup);
+       if (!mdev)
+               goto fail_mdev_alloc;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(mdev);
+       mdev->ieee80211_ptr = &sdata->wdev;
+       sdata->wdev.wiphy = local->hw.wiphy;
+
+       local->mdev = mdev;
+
+       ieee80211_rx_bss_list_init(mdev);
+
+       mdev->hard_start_xmit = ieee80211_master_start_xmit;
+       mdev->open = ieee80211_master_open;
+       mdev->stop = ieee80211_master_stop;
+       mdev->type = ARPHRD_IEEE80211;
+       mdev->header_ops = &ieee80211_header_ops;
+       mdev->set_multicast_list = ieee80211_master_set_multicast_list;
+
+       sdata->vif.type = IEEE80211_IF_TYPE_AP;
+       sdata->dev = mdev;
+       sdata->local = local;
+       sdata->u.ap.force_unicast_rateidx = -1;
+       sdata->u.ap.max_ratectrl_rateidx = -1;
+       ieee80211_if_sdata_init(sdata);
+
+       /* no RCU needed since we're still during init phase */
+       list_add_tail(&sdata->list, &local->interfaces);
+
        name = wiphy_dev(local->hw.wiphy)->driver->name;
        local->hw.workqueue = create_singlethread_workqueue(name);
        if (!local->hw.workqueue) {
@@ -1606,6 +1606,9 @@ fail_sta_info:
        debugfs_hw_del(local);
        destroy_workqueue(local->hw.workqueue);
 fail_workqueue:
+       ieee80211_if_free(local->mdev);
+       local->mdev = NULL;
+fail_mdev_alloc:
        wiphy_unregister(local->hw.wiphy);
        return result;
 }
@@ -1666,6 +1669,8 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
        wiphy_unregister(local->hw.wiphy);
        ieee80211_wep_free(local);
        ieee80211_led_exit(local);
+       ieee80211_if_free(local->mdev);
+       local->mdev = NULL;
 }
 EXPORT_SYMBOL(ieee80211_unregister_hw);
 
@@ -1673,7 +1678,6 @@ void ieee80211_free_hw(struct ieee80211_hw *hw)
 {
        struct ieee80211_local *local = hw_to_local(hw);
 
-       ieee80211_if_free(local->mdev);
        wiphy_free(local->hw.wiphy);
 }
 EXPORT_SYMBOL(ieee80211_free_hw);