aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/rtlwifi/ps.c
diff options
context:
space:
mode:
authorLarry Finger <Larry.Finger@lwfinger.net>2013-03-24 23:06:33 -0400
committerJohn W. Linville <linville@tuxdriver.com>2013-04-01 16:17:06 -0400
commit26634c4b1868323f49f8cd24c3493b57819867fd (patch)
tree281409ae1cc5c43951ea74761065a427a5a3ea84 /drivers/net/wireless/rtlwifi/ps.c
parentcbafb601cad81de612013fad8daf710ca900015a (diff)
rtlwifi Modify existing bits to match vendor version 2013.02.07
These changes add the new variables for P2P and modify the various struct definitions for other new features. This patch updates files base.{c,h} for the changes in the newest vendor driver. This patch updates files ps.{c,h} for the changes in the newest vendor driver. This patch updates files debug.{c,h}, efuse.c, pci.{c,h}, and wifi.h for the changes in the newest vendor driver. This patch updates files core.c, ps.c, rc.c, and wifi.h for the changes in the newest vendor driver. Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net> Cc: jcheung@suse.com Cc: machen@suse.com Cc: mmarek@suse.cz Cc: zhiyuan_yang@realsil.com.cn Cc: page_he@realsil.com.cn Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/rtlwifi/ps.c')
-rw-r--r--drivers/net/wireless/rtlwifi/ps.c330
1 files changed, 305 insertions, 25 deletions
diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c
index 13ad33e85577..884bceae38a9 100644
--- a/drivers/net/wireless/rtlwifi/ps.c
+++ b/drivers/net/wireless/rtlwifi/ps.c
@@ -180,6 +180,9 @@ void rtl_ips_nic_off_wq_callback(void *data)
180 return; 180 return;
181 } 181 }
182 182
183 if (mac->p2p_in_use)
184 return;
185
183 if (mac->link_state > MAC80211_NOLINK) 186 if (mac->link_state > MAC80211_NOLINK)
184 return; 187 return;
185 188
@@ -189,6 +192,9 @@ void rtl_ips_nic_off_wq_callback(void *data)
189 if (rtlpriv->sec.being_setkey) 192 if (rtlpriv->sec.being_setkey)
190 return; 193 return;
191 194
195 if (rtlpriv->cfg->ops->bt_coex_off_before_lps)
196 rtlpriv->cfg->ops->bt_coex_off_before_lps(hw);
197
192 if (ppsc->inactiveps) { 198 if (ppsc->inactiveps) {
193 rtstate = ppsc->rfpwr_state; 199 rtstate = ppsc->rfpwr_state;
194 200
@@ -231,6 +237,9 @@ void rtl_ips_nic_off(struct ieee80211_hw *hw)
231 &rtlpriv->works.ips_nic_off_wq, MSECS(100)); 237 &rtlpriv->works.ips_nic_off_wq, MSECS(100));
232} 238}
233 239
240/* NOTICE: any opmode should exc nic_on, or disable without
241 * nic_on may something wrong, like adhoc TP
242 */
234void rtl_ips_nic_on(struct ieee80211_hw *hw) 243void rtl_ips_nic_on(struct ieee80211_hw *hw)
235{ 244{
236 struct rtl_priv *rtlpriv = rtl_priv(hw); 245 struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -299,7 +308,7 @@ static void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode)
299 struct rtl_priv *rtlpriv = rtl_priv(hw); 308 struct rtl_priv *rtlpriv = rtl_priv(hw);
300 struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); 309 struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
301 struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 310 struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
302 u8 rpwm_val, fw_pwrmode; 311 bool enter_fwlps;
303 312
304 if (mac->opmode == NL80211_IFTYPE_ADHOC) 313 if (mac->opmode == NL80211_IFTYPE_ADHOC)
305 return; 314 return;
@@ -324,43 +333,31 @@ static void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode)
324 */ 333 */
325 334
326 if ((ppsc->fwctrl_lps) && ppsc->report_linked) { 335 if ((ppsc->fwctrl_lps) && ppsc->report_linked) {
327 bool fw_current_inps;
328 if (ppsc->dot11_psmode == EACTIVE) { 336 if (ppsc->dot11_psmode == EACTIVE) {
329 RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, 337 RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
330 "FW LPS leave ps_mode:%x\n", 338 "FW LPS leave ps_mode:%x\n",
331 FW_PS_ACTIVE_MODE); 339 FW_PS_ACTIVE_MODE);
332 340 enter_fwlps = false;
333 rpwm_val = 0x0C; /* RF on */ 341 ppsc->pwr_mode = FW_PS_ACTIVE_MODE;
334 fw_pwrmode = FW_PS_ACTIVE_MODE; 342 ppsc->smart_ps = 0;
335 rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
336 &rpwm_val);
337 rtlpriv->cfg->ops->set_hw_reg(hw, 343 rtlpriv->cfg->ops->set_hw_reg(hw,
338 HW_VAR_H2C_FW_PWRMODE, 344 HW_VAR_FW_LPS_ACTION,
339 &fw_pwrmode); 345 (u8 *)(&enter_fwlps));
340 fw_current_inps = false; 346 if (ppsc->p2p_ps_info.opp_ps)
341 347 rtl_p2p_ps_cmd(hw, P2P_PS_ENABLE);
342 rtlpriv->cfg->ops->set_hw_reg(hw,
343 HW_VAR_FW_PSMODE_STATUS,
344 (u8 *) (&fw_current_inps));
345 348
346 } else { 349 } else {
347 if (rtl_get_fwlps_doze(hw)) { 350 if (rtl_get_fwlps_doze(hw)) {
348 RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, 351 RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
349 "FW LPS enter ps_mode:%x\n", 352 "FW LPS enter ps_mode:%x\n",
350 ppsc->fwctrl_psmode); 353 ppsc->fwctrl_psmode);
351 354 enter_fwlps = true;
352 rpwm_val = 0x02; /* RF off */ 355 ppsc->pwr_mode = ppsc->fwctrl_psmode;
353 fw_current_inps = true; 356 ppsc->smart_ps = 2;
354 rtlpriv->cfg->ops->set_hw_reg(hw, 357 rtlpriv->cfg->ops->set_hw_reg(hw,
355 HW_VAR_FW_PSMODE_STATUS, 358 HW_VAR_FW_LPS_ACTION,
356 (u8 *) (&fw_current_inps)); 359 (u8 *)(&enter_fwlps));
357 rtlpriv->cfg->ops->set_hw_reg(hw,
358 HW_VAR_H2C_FW_PWRMODE,
359 &ppsc->fwctrl_psmode);
360 360
361 rtlpriv->cfg->ops->set_hw_reg(hw,
362 HW_VAR_SET_RPWM,
363 &rpwm_val);
364 } else { 361 } else {
365 /* Reset the power save related parameters. */ 362 /* Reset the power save related parameters. */
366 ppsc->dot11_psmode = EACTIVE; 363 ppsc->dot11_psmode = EACTIVE;
@@ -642,3 +639,286 @@ void rtl_swlps_wq_callback(void *data)
642 rtlpriv->psc.state = ps; 639 rtlpriv->psc.state = ps;
643 } 640 }
644} 641}
642
643static void rtl_p2p_noa_ie(struct ieee80211_hw *hw, void *data,
644 unsigned int len)
645{
646 struct rtl_priv *rtlpriv = rtl_priv(hw);
647 struct ieee80211_mgmt *mgmt = (void *)data;
648 struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info);
649 u8 *pos, *end, *ie;
650 u16 noa_len;
651 static u8 p2p_oui_ie_type[4] = {0x50, 0x6f, 0x9a, 0x09};
652 u8 noa_num, index, i, noa_index = 0;
653 bool find_p2p_ie = false , find_p2p_ps_ie = false;
654 pos = (u8 *)mgmt->u.beacon.variable;
655 end = data + len;
656 ie = NULL;
657
658 while (pos + 1 < end) {
659 if (pos + 2 + pos[1] > end)
660 return;
661
662 if (pos[0] == 221 && pos[1] > 4) {
663 if (memcmp(&pos[2], p2p_oui_ie_type, 4) == 0) {
664 ie = pos + 2+4;
665 break;
666 }
667 }
668 pos += 2 + pos[1];
669 }
670
671 if (ie == NULL)
672 return;
673 find_p2p_ie = true;
674 /*to find noa ie*/
675 while (ie + 1 < end) {
676 noa_len = READEF2BYTE(&ie[1]);
677 if (ie + 3 + ie[1] > end)
678 return;
679
680 if (ie[0] == 12) {
681 find_p2p_ps_ie = true;
682 if ((noa_len - 2) % 13 != 0) {
683 RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
684 "P2P notice of absence: invalid length.%d\n",
685 noa_len);
686 return;
687 } else {
688 noa_num = (noa_len - 2) / 13;
689 }
690 noa_index = ie[3];
691 if (rtlpriv->psc.p2p_ps_info.p2p_ps_mode ==
692 P2P_PS_NONE || noa_index != p2pinfo->noa_index) {
693 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
694 "update NOA ie.\n");
695 p2pinfo->noa_index = noa_index;
696 p2pinfo->opp_ps = (ie[4] >> 7);
697 p2pinfo->ctwindow = ie[4] & 0x7F;
698 p2pinfo->noa_num = noa_num;
699 index = 5;
700 for (i = 0; i < noa_num; i++) {
701 p2pinfo->noa_count_type[i] =
702 READEF1BYTE(ie+index);
703 index += 1;
704 p2pinfo->noa_duration[i] =
705 READEF4BYTE(ie+index);
706 index += 4;
707 p2pinfo->noa_interval[i] =
708 READEF4BYTE(ie+index);
709 index += 4;
710 p2pinfo->noa_start_time[i] =
711 READEF4BYTE(ie+index);
712 index += 4;
713 }
714
715 if (p2pinfo->opp_ps == 1) {
716 p2pinfo->p2p_ps_mode = P2P_PS_CTWINDOW;
717 /* Driver should wait LPS entering
718 * CTWindow
719 */
720 if (rtlpriv->psc.fw_current_inpsmode)
721 rtl_p2p_ps_cmd(hw,
722 P2P_PS_ENABLE);
723 } else if (p2pinfo->noa_num > 0) {
724 p2pinfo->p2p_ps_mode = P2P_PS_NOA;
725 rtl_p2p_ps_cmd(hw, P2P_PS_ENABLE);
726 } else if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) {
727 rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE);
728 }
729 }
730 break;
731 }
732 ie += 3 + noa_len;
733 }
734
735 if (find_p2p_ie == true) {
736 if ((p2pinfo->p2p_ps_mode > P2P_PS_NONE) &&
737 (find_p2p_ps_ie == false))
738 rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE);
739 }
740}
741
742static void rtl_p2p_action_ie(struct ieee80211_hw *hw, void *data,
743 unsigned int len)
744{
745 struct rtl_priv *rtlpriv = rtl_priv(hw);
746 struct ieee80211_mgmt *mgmt = (void *)data;
747 struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info);
748 u8 noa_num, index, i, noa_index = 0;
749 u8 *pos, *end, *ie;
750 u16 noa_len;
751 static u8 p2p_oui_ie_type[4] = {0x50, 0x6f, 0x9a, 0x09};
752
753 pos = (u8 *)&mgmt->u.action.category;
754 end = data + len;
755 ie = NULL;
756
757 if (pos[0] == 0x7f) {
758 if (memcmp(&pos[1], p2p_oui_ie_type, 4) == 0)
759 ie = pos + 3+4;
760 }
761
762 if (ie == NULL)
763 return;
764
765 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "action frame find P2P IE.\n");
766 /*to find noa ie*/
767 while (ie + 1 < end) {
768 noa_len = READEF2BYTE(&ie[1]);
769 if (ie + 3 + ie[1] > end)
770 return;
771
772 if (ie[0] == 12) {
773 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "find NOA IE.\n");
774 RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_LOUD, "noa ie ",
775 ie, noa_len);
776 if ((noa_len - 2) % 13 != 0) {
777 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
778 "P2P notice of absence: invalid length.%d\n",
779 noa_len);
780 return;
781 } else {
782 noa_num = (noa_len - 2) / 13;
783 }
784 noa_index = ie[3];
785 if (rtlpriv->psc.p2p_ps_info.p2p_ps_mode ==
786 P2P_PS_NONE || noa_index != p2pinfo->noa_index) {
787 p2pinfo->noa_index = noa_index;
788 p2pinfo->opp_ps = (ie[4] >> 7);
789 p2pinfo->ctwindow = ie[4] & 0x7F;
790 p2pinfo->noa_num = noa_num;
791 index = 5;
792 for (i = 0; i < noa_num; i++) {
793 p2pinfo->noa_count_type[i] =
794 READEF1BYTE(ie+index);
795 index += 1;
796 p2pinfo->noa_duration[i] =
797 READEF4BYTE(ie+index);
798 index += 4;
799 p2pinfo->noa_interval[i] =
800 READEF4BYTE(ie+index);
801 index += 4;
802 p2pinfo->noa_start_time[i] =
803 READEF4BYTE(ie+index);
804 index += 4;
805 }
806
807 if (p2pinfo->opp_ps == 1) {
808 p2pinfo->p2p_ps_mode = P2P_PS_CTWINDOW;
809 /* Driver should wait LPS entering
810 * CTWindow
811 */
812 if (rtlpriv->psc.fw_current_inpsmode)
813 rtl_p2p_ps_cmd(hw,
814 P2P_PS_ENABLE);
815 } else if (p2pinfo->noa_num > 0) {
816 p2pinfo->p2p_ps_mode = P2P_PS_NOA;
817 rtl_p2p_ps_cmd(hw, P2P_PS_ENABLE);
818 } else if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) {
819 rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE);
820 }
821 }
822 break;
823 }
824 ie += 3 + noa_len;
825 }
826}
827
828void rtl_p2p_ps_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
829{
830 struct rtl_priv *rtlpriv = rtl_priv(hw);
831 struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
832 struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info);
833
834 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, " p2p state %x\n", p2p_ps_state);
835 switch (p2p_ps_state) {
836 case P2P_PS_DISABLE:
837 p2pinfo->p2p_ps_state = p2p_ps_state;
838 rtlpriv->cfg->ops->set_hw_reg(hw,
839 HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
840 (u8 *)(&p2p_ps_state));
841
842 p2pinfo->noa_index = 0;
843 p2pinfo->ctwindow = 0;
844 p2pinfo->opp_ps = 0;
845 p2pinfo->noa_num = 0;
846 p2pinfo->p2p_ps_mode = P2P_PS_NONE;
847 if (rtlps->fw_current_inpsmode == true) {
848 if (rtlps->smart_ps == 0) {
849 rtlps->smart_ps = 2;
850 rtlpriv->cfg->ops->set_hw_reg(hw,
851 HW_VAR_H2C_FW_PWRMODE,
852 (u8 *)(&rtlps->pwr_mode));
853 }
854 }
855 break;
856 case P2P_PS_ENABLE:
857 if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) {
858 p2pinfo->p2p_ps_state = p2p_ps_state;
859
860 if (p2pinfo->ctwindow > 0) {
861 if (rtlps->smart_ps != 0) {
862 rtlps->smart_ps = 0;
863 rtlpriv->cfg->ops->set_hw_reg(hw,
864 HW_VAR_H2C_FW_PWRMODE,
865 (u8 *)(&rtlps->pwr_mode));
866 }
867 }
868 rtlpriv->cfg->ops->set_hw_reg(hw,
869 HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
870 (u8 *)(&p2p_ps_state));
871 }
872 break;
873 case P2P_PS_SCAN:
874 case P2P_PS_SCAN_DONE:
875 case P2P_PS_ALLSTASLEEP:
876 if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) {
877 p2pinfo->p2p_ps_state = p2p_ps_state;
878 rtlpriv->cfg->ops->set_hw_reg(hw,
879 HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
880 (u8 *)(&p2p_ps_state));
881 }
882 break;
883 default:
884 break;
885 }
886 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
887 "ctwindow %x oppps %x\n", p2pinfo->ctwindow, p2pinfo->opp_ps);
888 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
889 "count %x duration %x index %x interval %x start time %x noa num %x\n",
890 p2pinfo->noa_count_type[0], p2pinfo->noa_duration[0],
891 p2pinfo->noa_index, p2pinfo->noa_interval[0],
892 p2pinfo->noa_start_time[0], p2pinfo->noa_num);
893 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "end\n");
894}
895
896void rtl_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len)
897{
898 struct rtl_priv *rtlpriv = rtl_priv(hw);
899 struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
900 struct ieee80211_hdr *hdr = (void *)data;
901
902 if (!mac->p2p)
903 return;
904 if (mac->link_state != MAC80211_LINKED)
905 return;
906 /* min. beacon length + FCS_LEN */
907 if (len <= 40 + FCS_LEN)
908 return;
909
910 /* and only beacons from the associated BSSID, please */
911 if (compare_ether_addr(hdr->addr3, rtlpriv->mac80211.bssid))
912 return;
913
914 /* check if this really is a beacon */
915 if (!(ieee80211_is_beacon(hdr->frame_control) ||
916 ieee80211_is_probe_resp(hdr->frame_control) ||
917 ieee80211_is_action(hdr->frame_control)))
918 return;
919
920 if (ieee80211_is_action(hdr->frame_control))
921 rtl_p2p_action_ie(hw, data, len - FCS_LEN);
922 else
923 rtl_p2p_noa_ie(hw, data, len - FCS_LEN);
924}