Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 | // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* Copyright(c) 2018-2019 Realtek Corporation */ #include "main.h" #include "util.h" #include "reg.h" bool check_hw_ready(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 target) { u32 cnt; for (cnt = 0; cnt < 1000; cnt++) { if (rtw_read32_mask(rtwdev, addr, mask) == target) return true; udelay(10); } return false; } EXPORT_SYMBOL(check_hw_ready); bool ltecoex_read_reg(struct rtw_dev *rtwdev, u16 offset, u32 *val) { const struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_ltecoex_addr *ltecoex = chip->ltecoex_addr; if (!check_hw_ready(rtwdev, ltecoex->ctrl, LTECOEX_READY, 1)) return false; rtw_write32(rtwdev, ltecoex->ctrl, 0x800F0000 | offset); *val = rtw_read32(rtwdev, ltecoex->rdata); return true; } bool ltecoex_reg_write(struct rtw_dev *rtwdev, u16 offset, u32 value) { const struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_ltecoex_addr *ltecoex = chip->ltecoex_addr; if (!check_hw_ready(rtwdev, ltecoex->ctrl, LTECOEX_READY, 1)) return false; rtw_write32(rtwdev, ltecoex->wdata, value); rtw_write32(rtwdev, ltecoex->ctrl, 0xC00F0000 | offset); return true; } void rtw_restore_reg(struct rtw_dev *rtwdev, struct rtw_backup_info *bckp, u32 num) { u8 len; u32 reg; u32 val; int i; for (i = 0; i < num; i++, bckp++) { len = bckp->len; reg = bckp->reg; val = bckp->val; switch (len) { case 1: rtw_write8(rtwdev, reg, (u8)val); break; case 2: rtw_write16(rtwdev, reg, (u16)val); break; case 4: rtw_write32(rtwdev, reg, (u32)val); break; default: break; } } } EXPORT_SYMBOL(rtw_restore_reg); void rtw_desc_to_mcsrate(u16 rate, u8 *mcs, u8 *nss) { if (rate <= DESC_RATE54M) return; if (rate >= DESC_RATEVHT1SS_MCS0 && rate <= DESC_RATEVHT1SS_MCS9) { *nss = 1; *mcs = rate - DESC_RATEVHT1SS_MCS0; } else if (rate >= DESC_RATEVHT2SS_MCS0 && rate <= DESC_RATEVHT2SS_MCS9) { *nss = 2; *mcs = rate - DESC_RATEVHT2SS_MCS0; } else if (rate >= DESC_RATEVHT3SS_MCS0 && rate <= DESC_RATEVHT3SS_MCS9) { *nss = 3; *mcs = rate - DESC_RATEVHT3SS_MCS0; } else if (rate >= DESC_RATEVHT4SS_MCS0 && rate <= DESC_RATEVHT4SS_MCS9) { *nss = 4; *mcs = rate - DESC_RATEVHT4SS_MCS0; } else if (rate >= DESC_RATEMCS0 && rate <= DESC_RATEMCS15) { *mcs = rate - DESC_RATEMCS0; } } struct rtw_stas_entry { struct list_head list; struct ieee80211_sta *sta; }; struct rtw_iter_stas_data { struct rtw_dev *rtwdev; struct list_head list; }; static void rtw_collect_sta_iter(void *data, struct ieee80211_sta *sta) { struct rtw_iter_stas_data *iter_stas = data; struct rtw_stas_entry *stas_entry; stas_entry = kmalloc(sizeof(*stas_entry), GFP_ATOMIC); if (!stas_entry) return; stas_entry->sta = sta; list_add_tail(&stas_entry->list, &iter_stas->list); } void rtw_iterate_stas(struct rtw_dev *rtwdev, void (*iterator)(void *data, struct ieee80211_sta *sta), void *data) { struct rtw_iter_stas_data iter_data; struct rtw_stas_entry *sta_entry, *tmp; /* &rtwdev->mutex makes sure no stations can be removed between * collecting the stations and iterating over them. */ lockdep_assert_held(&rtwdev->mutex); iter_data.rtwdev = rtwdev; INIT_LIST_HEAD(&iter_data.list); ieee80211_iterate_stations_atomic(rtwdev->hw, rtw_collect_sta_iter, &iter_data); list_for_each_entry_safe(sta_entry, tmp, &iter_data.list, list) { list_del_init(&sta_entry->list); iterator(data, sta_entry->sta); kfree(sta_entry); } } struct rtw_vifs_entry { struct list_head list; struct ieee80211_vif *vif; u8 mac[ETH_ALEN]; }; struct rtw_iter_vifs_data { struct rtw_dev *rtwdev; struct list_head list; }; static void rtw_collect_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { struct rtw_iter_vifs_data *iter_stas = data; struct rtw_vifs_entry *vifs_entry; vifs_entry = kmalloc(sizeof(*vifs_entry), GFP_ATOMIC); if (!vifs_entry) return; vifs_entry->vif = vif; ether_addr_copy(vifs_entry->mac, mac); list_add_tail(&vifs_entry->list, &iter_stas->list); } void rtw_iterate_vifs(struct rtw_dev *rtwdev, void (*iterator)(void *data, u8 *mac, struct ieee80211_vif *vif), void *data) { struct rtw_iter_vifs_data iter_data; struct rtw_vifs_entry *vif_entry, *tmp; /* &rtwdev->mutex makes sure no interfaces can be removed between * collecting the interfaces and iterating over them. */ lockdep_assert_held(&rtwdev->mutex); iter_data.rtwdev = rtwdev; INIT_LIST_HEAD(&iter_data.list); ieee80211_iterate_active_interfaces_atomic(rtwdev->hw, IEEE80211_IFACE_ITER_NORMAL, rtw_collect_vif_iter, &iter_data); list_for_each_entry_safe(vif_entry, tmp, &iter_data.list, list) { list_del_init(&vif_entry->list); iterator(data, vif_entry->mac, vif_entry->vif); kfree(vif_entry); } } |