diff options
author | Juuso Oikarinen <juuso.oikarinen@nokia.com> | 2010-03-18 06:26:39 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-03-23 16:50:23 -0400 |
commit | 1b72aecd950c4c3cec2d66dbe5436c9e25a487b7 (patch) | |
tree | 1111ab6e6733300a6dd7dfe35f9a0d59c599dfcf /drivers | |
parent | 4695dc917d9ec7a38cb4f91fceb2b78aaec1f945 (diff) |
wl1271: Fix MAC address handling
This patch fixes MAC address handling. To achieve this, firmware booting had
to be delayed from the previous op_start to op_add_interface, which is the point
when the driver gets to know the configured MAC address. As the wl1271 only
supports one virtual interface, this even seems quite logical.
Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com>
Reviewed-by: Kalle Valo <kalle.valo@nokia.com>
Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_boot.c | 8 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_main.c | 149 |
2 files changed, 68 insertions, 89 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c index f88d52e87e82..41c6affbee29 100644 --- a/drivers/net/wireless/wl12xx/wl1271_boot.c +++ b/drivers/net/wireless/wl12xx/wl1271_boot.c | |||
@@ -228,6 +228,14 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) | |||
228 | nvs_len = sizeof(wl->nvs->nvs); | 228 | nvs_len = sizeof(wl->nvs->nvs); |
229 | nvs_ptr = (u8 *)wl->nvs->nvs; | 229 | nvs_ptr = (u8 *)wl->nvs->nvs; |
230 | 230 | ||
231 | /* update current MAC address to NVS */ | ||
232 | nvs_ptr[11] = wl->mac_addr[0]; | ||
233 | nvs_ptr[10] = wl->mac_addr[1]; | ||
234 | nvs_ptr[6] = wl->mac_addr[2]; | ||
235 | nvs_ptr[5] = wl->mac_addr[3]; | ||
236 | nvs_ptr[4] = wl->mac_addr[4]; | ||
237 | nvs_ptr[3] = wl->mac_addr[5]; | ||
238 | |||
231 | /* | 239 | /* |
232 | * Layout before the actual NVS tables: | 240 | * Layout before the actual NVS tables: |
233 | * 1 byte : burst length. | 241 | * 1 byte : burst length. |
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 037a4f4036fd..d8cb51410b2f 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c | |||
@@ -570,40 +570,6 @@ out: | |||
570 | return ret; | 570 | return ret; |
571 | } | 571 | } |
572 | 572 | ||
573 | static int wl1271_update_mac_addr(struct wl1271 *wl) | ||
574 | { | ||
575 | int ret = 0; | ||
576 | u8 *nvs_ptr = (u8 *)wl->nvs->nvs; | ||
577 | |||
578 | /* get mac address from the NVS */ | ||
579 | wl->mac_addr[0] = nvs_ptr[11]; | ||
580 | wl->mac_addr[1] = nvs_ptr[10]; | ||
581 | wl->mac_addr[2] = nvs_ptr[6]; | ||
582 | wl->mac_addr[3] = nvs_ptr[5]; | ||
583 | wl->mac_addr[4] = nvs_ptr[4]; | ||
584 | wl->mac_addr[5] = nvs_ptr[3]; | ||
585 | |||
586 | /* FIXME: if it is a zero-address, we should bail out. Now, instead, | ||
587 | we randomize an address */ | ||
588 | if (is_zero_ether_addr(wl->mac_addr)) { | ||
589 | static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; | ||
590 | memcpy(wl->mac_addr, nokia_oui, 3); | ||
591 | get_random_bytes(wl->mac_addr + 3, 3); | ||
592 | |||
593 | /* update this address to the NVS */ | ||
594 | nvs_ptr[11] = wl->mac_addr[0]; | ||
595 | nvs_ptr[10] = wl->mac_addr[1]; | ||
596 | nvs_ptr[6] = wl->mac_addr[2]; | ||
597 | nvs_ptr[5] = wl->mac_addr[3]; | ||
598 | nvs_ptr[4] = wl->mac_addr[4]; | ||
599 | nvs_ptr[3] = wl->mac_addr[5]; | ||
600 | } | ||
601 | |||
602 | SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); | ||
603 | |||
604 | return ret; | ||
605 | } | ||
606 | |||
607 | static int wl1271_fetch_nvs(struct wl1271 *wl) | 573 | static int wl1271_fetch_nvs(struct wl1271 *wl) |
608 | { | 574 | { |
609 | const struct firmware *fw; | 575 | const struct firmware *fw; |
@@ -633,8 +599,6 @@ static int wl1271_fetch_nvs(struct wl1271 *wl) | |||
633 | 599 | ||
634 | memcpy(wl->nvs, fw->data, sizeof(struct wl1271_nvs_file)); | 600 | memcpy(wl->nvs, fw->data, sizeof(struct wl1271_nvs_file)); |
635 | 601 | ||
636 | ret = wl1271_update_mac_addr(wl); | ||
637 | |||
638 | out: | 602 | out: |
639 | release_firmware(fw); | 603 | release_firmware(fw); |
640 | 604 | ||
@@ -952,13 +916,58 @@ static struct notifier_block wl1271_dev_notifier = { | |||
952 | 916 | ||
953 | static int wl1271_op_start(struct ieee80211_hw *hw) | 917 | static int wl1271_op_start(struct ieee80211_hw *hw) |
954 | { | 918 | { |
919 | wl1271_debug(DEBUG_MAC80211, "mac80211 start"); | ||
920 | |||
921 | /* | ||
922 | * We have to delay the booting of the hardware because | ||
923 | * we need to know the local MAC address before downloading and | ||
924 | * initializing the firmware. The MAC address cannot be changed | ||
925 | * after boot, and without the proper MAC address, the firmware | ||
926 | * will not function properly. | ||
927 | * | ||
928 | * The MAC address is first known when the corresponding interface | ||
929 | * is added. That is where we will initialize the hardware. | ||
930 | */ | ||
931 | |||
932 | return 0; | ||
933 | } | ||
934 | |||
935 | static void wl1271_op_stop(struct ieee80211_hw *hw) | ||
936 | { | ||
937 | wl1271_debug(DEBUG_MAC80211, "mac80211 stop"); | ||
938 | } | ||
939 | |||
940 | static int wl1271_op_add_interface(struct ieee80211_hw *hw, | ||
941 | struct ieee80211_vif *vif) | ||
942 | { | ||
955 | struct wl1271 *wl = hw->priv; | 943 | struct wl1271 *wl = hw->priv; |
956 | int retries = WL1271_BOOT_RETRIES; | 944 | int retries = WL1271_BOOT_RETRIES; |
957 | int ret = 0; | 945 | int ret = 0; |
958 | 946 | ||
959 | wl1271_debug(DEBUG_MAC80211, "mac80211 start"); | 947 | wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", |
948 | vif->type, vif->addr); | ||
960 | 949 | ||
961 | mutex_lock(&wl->mutex); | 950 | mutex_lock(&wl->mutex); |
951 | if (wl->vif) { | ||
952 | ret = -EBUSY; | ||
953 | goto out; | ||
954 | } | ||
955 | |||
956 | wl->vif = vif; | ||
957 | |||
958 | switch (vif->type) { | ||
959 | case NL80211_IFTYPE_STATION: | ||
960 | wl->bss_type = BSS_TYPE_STA_BSS; | ||
961 | break; | ||
962 | case NL80211_IFTYPE_ADHOC: | ||
963 | wl->bss_type = BSS_TYPE_IBSS; | ||
964 | break; | ||
965 | default: | ||
966 | ret = -EOPNOTSUPP; | ||
967 | goto out; | ||
968 | } | ||
969 | |||
970 | memcpy(wl->mac_addr, vif->addr, ETH_ALEN); | ||
962 | 971 | ||
963 | if (wl->state != WL1271_STATE_OFF) { | 972 | if (wl->state != WL1271_STATE_OFF) { |
964 | wl1271_error("cannot start because not in off state: %d", | 973 | wl1271_error("cannot start because not in off state: %d", |
@@ -1014,20 +1023,20 @@ out: | |||
1014 | return ret; | 1023 | return ret; |
1015 | } | 1024 | } |
1016 | 1025 | ||
1017 | static void wl1271_op_stop(struct ieee80211_hw *hw) | 1026 | static void wl1271_op_remove_interface(struct ieee80211_hw *hw, |
1027 | struct ieee80211_vif *vif) | ||
1018 | { | 1028 | { |
1019 | struct wl1271 *wl = hw->priv; | 1029 | struct wl1271 *wl = hw->priv; |
1020 | int i; | 1030 | int i; |
1021 | 1031 | ||
1022 | wl1271_info("down"); | 1032 | mutex_lock(&wl->mutex); |
1033 | wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface"); | ||
1023 | 1034 | ||
1024 | wl1271_debug(DEBUG_MAC80211, "mac80211 stop"); | 1035 | wl1271_info("down"); |
1025 | 1036 | ||
1026 | unregister_inetaddr_notifier(&wl1271_dev_notifier); | 1037 | unregister_inetaddr_notifier(&wl1271_dev_notifier); |
1027 | list_del(&wl->list); | 1038 | list_del(&wl->list); |
1028 | 1039 | ||
1029 | mutex_lock(&wl->mutex); | ||
1030 | |||
1031 | WARN_ON(wl->state != WL1271_STATE_ON); | 1040 | WARN_ON(wl->state != WL1271_STATE_ON); |
1032 | 1041 | ||
1033 | if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) { | 1042 | if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) { |
@@ -1070,6 +1079,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) | |||
1070 | wl->rate_set = CONF_TX_RATE_MASK_BASIC; | 1079 | wl->rate_set = CONF_TX_RATE_MASK_BASIC; |
1071 | wl->sta_rate_set = 0; | 1080 | wl->sta_rate_set = 0; |
1072 | wl->flags = 0; | 1081 | wl->flags = 0; |
1082 | wl->vif = NULL; | ||
1073 | 1083 | ||
1074 | for (i = 0; i < NUM_TX_QUEUES; i++) | 1084 | for (i = 0; i < NUM_TX_QUEUES; i++) |
1075 | wl->tx_blocks_freed[i] = 0; | 1085 | wl->tx_blocks_freed[i] = 0; |
@@ -1078,53 +1088,6 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) | |||
1078 | mutex_unlock(&wl->mutex); | 1088 | mutex_unlock(&wl->mutex); |
1079 | } | 1089 | } |
1080 | 1090 | ||
1081 | static int wl1271_op_add_interface(struct ieee80211_hw *hw, | ||
1082 | struct ieee80211_vif *vif) | ||
1083 | { | ||
1084 | struct wl1271 *wl = hw->priv; | ||
1085 | int ret = 0; | ||
1086 | |||
1087 | wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", | ||
1088 | vif->type, vif->addr); | ||
1089 | |||
1090 | mutex_lock(&wl->mutex); | ||
1091 | if (wl->vif) { | ||
1092 | ret = -EBUSY; | ||
1093 | goto out; | ||
1094 | } | ||
1095 | |||
1096 | wl->vif = vif; | ||
1097 | |||
1098 | switch (vif->type) { | ||
1099 | case NL80211_IFTYPE_STATION: | ||
1100 | wl->bss_type = BSS_TYPE_STA_BSS; | ||
1101 | break; | ||
1102 | case NL80211_IFTYPE_ADHOC: | ||
1103 | wl->bss_type = BSS_TYPE_IBSS; | ||
1104 | break; | ||
1105 | default: | ||
1106 | ret = -EOPNOTSUPP; | ||
1107 | goto out; | ||
1108 | } | ||
1109 | |||
1110 | /* FIXME: what if conf->mac_addr changes? */ | ||
1111 | |||
1112 | out: | ||
1113 | mutex_unlock(&wl->mutex); | ||
1114 | return ret; | ||
1115 | } | ||
1116 | |||
1117 | static void wl1271_op_remove_interface(struct ieee80211_hw *hw, | ||
1118 | struct ieee80211_vif *vif) | ||
1119 | { | ||
1120 | struct wl1271 *wl = hw->priv; | ||
1121 | |||
1122 | mutex_lock(&wl->mutex); | ||
1123 | wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface"); | ||
1124 | wl->vif = NULL; | ||
1125 | mutex_unlock(&wl->mutex); | ||
1126 | } | ||
1127 | |||
1128 | #if 0 | 1091 | #if 0 |
1129 | static int wl1271_op_config_interface(struct ieee80211_hw *hw, | 1092 | static int wl1271_op_config_interface(struct ieee80211_hw *hw, |
1130 | struct ieee80211_vif *vif, | 1093 | struct ieee80211_vif *vif, |
@@ -2114,6 +2077,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void) | |||
2114 | struct ieee80211_hw *hw; | 2077 | struct ieee80211_hw *hw; |
2115 | struct wl1271 *wl; | 2078 | struct wl1271 *wl; |
2116 | int i, ret; | 2079 | int i, ret; |
2080 | static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; | ||
2117 | 2081 | ||
2118 | hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops); | 2082 | hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops); |
2119 | if (!hw) { | 2083 | if (!hw) { |
@@ -2155,6 +2119,13 @@ struct ieee80211_hw *wl1271_alloc_hw(void) | |||
2155 | wl->state = WL1271_STATE_OFF; | 2119 | wl->state = WL1271_STATE_OFF; |
2156 | mutex_init(&wl->mutex); | 2120 | mutex_init(&wl->mutex); |
2157 | 2121 | ||
2122 | /* | ||
2123 | * FIXME: we should use a zero MAC address here, but for now we | ||
2124 | * generate a random Nokia address. | ||
2125 | */ | ||
2126 | memcpy(wl->mac_addr, nokia_oui, 3); | ||
2127 | get_random_bytes(wl->mac_addr + 3, 3); | ||
2128 | |||
2158 | /* Apply default driver configuration. */ | 2129 | /* Apply default driver configuration. */ |
2159 | wl1271_conf_init(wl); | 2130 | wl1271_conf_init(wl); |
2160 | 2131 | ||