From: Johannes Berg <johannes@sipsolutions.net>
To: yhchuang@realtek.com, kvalo@codeaurora.org
Cc: Larry.Finger@lwfinger.net, pkshih@realtek.com,
tehuang@realtek.com, sgruszka@redhat.com,
linux-wireless@vger.kernel.org
Subject: Re: [RFC v3 01/12] rtw88: main files
Date: Mon, 08 Oct 2018 16:10:05 +0200 [thread overview]
Message-ID: <1539007805.3687.47.camel@sipsolutions.net> (raw)
In-Reply-To: <1538565659-29530-2-git-send-email-yhchuang@realtek.com> (sfid-20181003_132152_136031_D3015842)
On Wed, 2018-10-03 at 19:20 +0800, yhchuang@realtek.com wrote:
>
> +static int rtw_ops_config(struct ieee80211_hw *hw, u32 changed)
> +{
> + struct rtw_dev *rtwdev = hw->priv;
> + int ret = 0;
> +
> + mutex_lock(&rtwdev->mutex);
> +
> + if (changed & IEEE80211_CONF_CHANGE_IDLE) {
> + if (hw->conf.flags & IEEE80211_CONF_IDLE) {
> + rtw_enter_ips(rtwdev);
> + } else {
> + ret = rtw_leave_ips(rtwdev);
> + if (ret) {
> + rtw_err(rtwdev, "failed to leave idle state\n");
> + goto out;
> + }
> + }
> + }
> +
> + if (changed & IEEE80211_CONF_CHANGE_CHANNEL)
> + rtw_set_channel(rtwdev);
You really should consider supporting channel contexts - it's the far
more modern API and likely gives you more control even if you support
only a single channel.
> +static struct rtw_vif_port rtw_vif_port[] = {
> + [0] = {
> + .mac_addr = {.addr = 0x0610},
> + .bssid = {.addr = 0x0618},
> + .net_type = {.addr = 0x0100, .mask = 0x30000},
> + .aid = {.addr = 0x06a8, .mask = 0x7ff},
> + },
err, what's all this?
Anyway, you really cannot make this static - again, multiple devices
might get plugged in.
> + list_add_rcu(&rtwvif->list, &rtwdev->vif_list);
I don't see a reason for you to maintain your own list, you can always
iterate mac80211's list if you really need to?
> + switch (vif->type) {
> + case NL80211_IFTYPE_AP:
> + case NL80211_IFTYPE_MESH_POINT:
> + net_type = RTW_NET_AP_MODE;
> + break;
> + case NL80211_IFTYPE_ADHOC:
> + net_type = RTW_NET_AD_HOC;
> + break;
> + default:
> + net_type = RTW_NET_NO_LINK;
you might to add STATION and then fail in the default case?
> +static void rtw_ops_remove_interface(struct ieee80211_hw *hw,
> + struct ieee80211_vif *vif)
> +{
> + struct rtw_dev *rtwdev = hw->priv;
> + struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
> + u32 config = 0;
> +
> + rtw_info(rtwdev, "stop vif %pM on port %d", vif->addr, rtwvif->port);
> +
> + mutex_lock(&rtwdev->mutex);
> +
> + eth_zero_addr(rtwvif->mac_addr);
> + config |= PORT_SET_MAC_ADDR;
> + rtwvif->net_type = RTW_NET_NO_LINK;
> + config |= PORT_SET_NET_TYPE;
> + rtw_vif_port_config(rtwdev, rtwvif, config);
> +
> + list_del_rcu(&rtwvif->list);
> + synchronize_rcu();
That synchronize_rcu() is *really* expensive, you should probably use
mac80211's list iteration to avoid it.
> +static void rtw_ops_configure_filter(struct ieee80211_hw *hw,
> + unsigned int changed_flags,
> + unsigned int *new_flags,
> + u64 multicast)
> +{
> + struct rtw_dev *rtwdev = hw->priv;
> +
> + *new_flags &= (FIF_ALLMULTI | FIF_OTHER_BSS | FIF_FCSFAIL |
> + FIF_BCN_PRBRESP_PROMISC);
nit: not much need for those parentheses
> +static u8 rtw_acquire_macid(struct rtw_dev *rtwdev)
> +{
> + u8 i;
> +
> + for (i = 0; i < RTW_MAX_MAC_ID_NUM; i++) {
> + if (!rtwdev->macid_used[i]) {
> + rtwdev->macid_used[i] = true;
> + return i;
> + }
> + }
> +
> + return i;
> +}
> +
> +static void rtw_release_macid(struct rtw_dev *rtwdev, u8 mac_id)
> +{
> + rtwdev->macid_used[mac_id] = false;
> +}
This would be way simpler (and use much less memory) with a bitmap and
find_first_zero_bit().
> +static int rtw_ops_sta_add(struct ieee80211_hw *hw,
> + struct ieee80211_vif *vif,
> + struct ieee80211_sta *sta)
You might want to use sta_state() instead of sta_add(), it's likely the
better API.
> + si->sta = sta;
> + si->vif = vif;
> + si->init_ra_lv = 1;
> + ewma_rssi_init(&si->avg_rssi);
What's this for that mac80211 doesn't do already?
> + rtw_update_sta_info(rtwdev, si);
> + rtw_fw_media_status_report(rtwdev, si->mac_id, true);
> +
> + list_add_tail_rcu(&si->list, &rtwvif->sta_list);
Again, you shouldn't need to keep your own list in the driver, mac80211
does all that bookkeeping for you.
> +static int rtw_ops_sta_remove(struct ieee80211_hw *hw,
> + struct ieee80211_vif *vif,
> + struct ieee80211_sta *sta)
> +{
> + struct rtw_dev *rtwdev = hw->priv;
> + struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv;
> +
> + mutex_lock(&rtwdev->mutex);
> +
> + rtw_release_macid(rtwdev, si->mac_id);
> + rtw_fw_media_status_report(rtwdev, si->mac_id, false);
> +
> + list_del_rcu(&si->list);
> + synchronize_rcu();
This synchronize_rcu() will hurt your roaming performance.
> + switch (key->cipher) {
> + case WLAN_CIPHER_SUITE_WEP40:
> + hw_key_type = RTW_CAM_WEP40;
> + break;
> + case WLAN_CIPHER_SUITE_WEP104:
> + hw_key_type = RTW_CAM_WEP104;
> + break;
> + case WLAN_CIPHER_SUITE_TKIP:
> + hw_key_type = RTW_CAM_TKIP;
> + key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
> + break;
> + case WLAN_CIPHER_SUITE_CCMP:
> + hw_key_type = RTW_CAM_AES;
> + key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
> + break;
> + default:
> + return -ENOTSUPP;
> + }
This will provoke error messages to be printed for e.g. CMAC keys, or do
you really not support protected management frames? If you were to pick
"-EOPNOTSUPP" then no errors would be printed.
> + mutex_lock(&rtwdev->mutex);
> +
> + if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {
> + hw_key_idx = rtw_sec_get_free_cam(sec);
> + } else {
> + /* multiple interfaces? */
> + hw_key_idx = key->keyidx;
> + }
Indeed, good question :-)
> +};
> +
> +static struct ieee80211_rate rtw_ratetable_2g[] = {
> + {.bitrate = 10, .hw_value = 0x00,},
> + {.bitrate = 20, .hw_value = 0x01,},
> + {.bitrate = 55, .hw_value = 0x02,},
> + {.bitrate = 110, .hw_value = 0x03,},
> + {.bitrate = 60, .hw_value = 0x04,},
> + {.bitrate = 90, .hw_value = 0x05,},
> + {.bitrate = 120, .hw_value = 0x06,},
> + {.bitrate = 180, .hw_value = 0x07,},
> + {.bitrate = 240, .hw_value = 0x08,},
> + {.bitrate = 360, .hw_value = 0x09,},
> + {.bitrate = 480, .hw_value = 0x0a,},
> + {.bitrate = 540, .hw_value = 0x0b,},
> +};
> +
> +static struct ieee80211_rate rtw_ratetable_5g[] = {
> + {.bitrate = 60, .hw_value = 0x04,},
> + {.bitrate = 90, .hw_value = 0x05,},
> + {.bitrate = 120, .hw_value = 0x06,},
> + {.bitrate = 180, .hw_value = 0x07,},
> + {.bitrate = 240, .hw_value = 0x08,},
> + {.bitrate = 360, .hw_value = 0x09,},
> + {.bitrate = 480, .hw_value = 0x0a,},
> + {.bitrate = 540, .hw_value = 0x0b,},
> +};
The 5G one is the same as the 2G one without the first 4 entries, so you
could do rtw_ratetable_2g+4 to avoid duplicating the data.
> +static struct ieee80211_supported_band rtw_band_2ghz = {
> + .band = NL80211_BAND_2GHZ,
> +
> + .channels = rtw_channeltable_2g,
> + .n_channels = ARRAY_SIZE(rtw_channeltable_2g),
> +
> + .bitrates = rtw_ratetable_2g,
> + .n_bitrates = ARRAY_SIZE(rtw_ratetable_2g),
> +
> + .ht_cap = {0},
> + .vht_cap = {0},
> +};
I see no reason to init the ht/vht cap?
> +static struct ieee80211_supported_band rtw_band_5ghz = {
> + .band = NL80211_BAND_5GHZ,
> +
> + .channels = rtw_channeltable_5g,
> + .n_channels = ARRAY_SIZE(rtw_channeltable_5g),
> +
> + .bitrates = rtw_ratetable_5g,
> + .n_bitrates = ARRAY_SIZE(rtw_ratetable_5g),
> +
> + .ht_cap = {0},
> + .vht_cap = {0},
> +};
dito
> +static void rtw_watch_dog_work(struct work_struct *work)
> +{
> + struct rtw_dev *rtwdev = container_of(work, struct rtw_dev,
> + watch_dog_work.work);
> + struct rtw_vif *rtwvif;
> +
> + if (!rtw_flag_check(rtwdev, RTW_FLAG_RUNNING))
> + return;
> +
> + ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->watch_dog_work,
> + RTW_WATCH_DOG_DELAY_TIME);
You're aware of the power cost of waking up every 2 seconds? That's a
really bad idea, in general, at the very least you should use a more
power efficient scheduling here to combine with other wakeups
(round_jiffies_relative, or so).
> + /* check if we can enter lps */
> + rtw_lps_enter_check(rtwdev);
> +
> + /* reset tx/rx statictics */
> + rtwdev->stats.tx_unicast = 0;
> + rtwdev->stats.rx_unicast = 0;
> + rtwdev->stats.tx_cnt = 0;
> + rtwdev->stats.rx_cnt = 0;
> + rcu_read_lock();
> + list_for_each_entry_rcu(rtwvif, &rtwdev->vif_list, list) {
> + rtwvif->stats.tx_unicast = 0;
> + rtwvif->stats.rx_unicast = 0;
> + rtwvif->stats.tx_cnt = 0;
> + rtwvif->stats.rx_cnt = 0;
> + }
> + rcu_read_unlock();
???
why should statistics be reset evyer 2 seconds?
> +
> + switch (bw_cap) {
> + case EFUSE_HW_CAP_IGNORE:
> + case EFUSE_HW_CAP_SUPP_BW80:
> + bw |= BIT(RTW_CHANNEL_WIDTH_80);
> + /* fall through */
> + case EFUSE_HW_CAP_SUPP_BW40:
> + bw |= BIT(RTW_CHANNEL_WIDTH_40);
> + /* fall through */
I'd probably indent the comments by one more tab (to be where the
"break" would be), but that's really a style nit.
> + case WIRELESS_OFDM | WIRELESS_HT:
Btw ... you have all this HT stuff and 40/80 MHz but no HT/VHT
capabilities?
> +static void rtw_init_ht_cap(struct rtw_dev *rtwdev,
> + struct ieee80211_sta_ht_cap *ht_cap)
> +{
Oh... ok.
> +static void rtw_set_supported_band(struct ieee80211_hw *hw,
> + struct rtw_chip_info *chip)
> +{
> + struct rtw_dev *rtwdev = hw->priv;
> + struct ieee80211_supported_band *sband;
> +
> + if (chip->band & RTW_BAND_2G) {
> + sband = kmalloc(sizeof(*sband), GFP_KERNEL);
> + memcpy(sband, &rtw_band_2ghz, sizeof(rtw_band_2ghz));
error check, kmemdup, make rtw_band_2ghz const.
> + if (chip->band & RTW_BAND_5G) {
> + sband = kmalloc(sizeof(*sband), GFP_KERNEL);
> + memcpy(sband, &rtw_band_5ghz, sizeof(rtw_band_5ghz));
dito
> + if (chip->band & RTW_BAND_2G)
> + kfree(hw->wiphy->bands[NL80211_BAND_2GHZ]);
> + if (chip->band & RTW_BAND_5G)
> + kfree(hw->wiphy->bands[NL80211_BAND_5GHZ]);
Don't really need the if in both cases, kfree(NULL) is fine.
> +static int rtw_load_firmware(struct rtw_dev *rtwdev, const char *fw_name)
> +{
> + struct rtw_fw_state *fw = &rtwdev->fw;
> + const struct firmware *firmware;
> + int ret;
> +
> + ret = request_firmware(&firmware, fw_name, rtwdev->dev);
You should use request_firmware_nowait(), otherwise you can stall the
boot if your driver is built-in (or lives in initramfs?).
> +EXPORT_SYMBOL(rtw_core_init);
You could also remove the exports if you put the pci.c into the same
module. Dunno, maybe it's some sort of future-proofing, but if you're
going to have one module with *everything* except for ~1.2k LOC PCI, it
seems hardly worth it (especially since it's only useful if you load
both anyway)
> + ieee80211_hw_set(hw, MFP_CAPABLE);
so you do have MFP - I guess you should test it and check for spurious
hardware crypto messages
> +#define LE_BITS_CLEARED_TO_4BYTE(addr, offset, len) \
> + (le32_to_cpu(*(__le32 *)(addr)) & (~GENMASK(offset + len - 1, offset)))
> +#define LE_BITS_TO_4BYTE(addr, offset, len) \
> + ((le32_to_cpu(*((__le32 *)(addr))) >> (offset)) & GENMASK(len - 1, 0))
> +#define SET_BITS_TO_LE_4BYTE(addr, offset, len, val) \
> + do { \
> + *((__le32 *)(addr)) = \
> + cpu_to_le32( \
> + LE_BITS_CLEARED_TO_4BYTE(addr, offset, len) | \
> + ((((u32)val) & GENMASK(len - 1, 0)) << (offset)) \
> + ); \
> + } while (0)
Seems like that likely has alignment issues again.
> +struct rtw_2g_1s_pwr_idx_diff {
> +#ifdef __LITTLE_ENDIAN
> + s8 ofdm:4;
> + s8 bw20:4;
> +#else
> + s8 bw20:4;
> + s8 ofdm:4;
> +#endif
You have this a lot, but IMHO it's generally not a good idea to try to
use bitfields when you actually need accurate bit layout for hardware.
Take a look at include/linux/bitfield.h for an alternative.
> +struct rtw_cam_entry {
> + bool used;
> + bool valid;
> + bool group;
> + u8 addr[ETH_ALEN];
> + u8 hw_key_type;
> + struct ieee80211_key_conf *key;
> +};
I'd also argue you should split hardware/firmware API things (like much
of this file) from driver-implementation things (like this and more
below) - it makes the driver easier to maintain since one can then leave
the hardware/firmware things pretty much alone for the most part. Or, if
that changes, just has to look there. The separation is good.
> +struct rtw_sec_desc {
> + /* search strategy */
> + bool default_key_search;
Incidental nit: that seems a bit strange, that's not a "strategy enum"
or so?
> + /* protected by rcu */
> + struct list_head sta_list;
RCU doesn't protect a list by itself - you need to say "protected by xyz
mutex, readers can use RCU" or so.
> +#include "hci.h"
Uh, I think it's more customary to put includes at the top of the file,
and if you can't that's probably a sign you haven't split things up
well.
> +static inline struct rtw_sta_info *get_hdr_sta(struct rtw_dev *rtwdev,
> + struct ieee80211_vif *vif,
> + struct ieee80211_hdr *hdr)
> +{
> + struct rtw_vif *rtwvif;
> + struct rtw_sta_info *si;
> + struct rtw_sta_info *target = NULL;
> +
> + rcu_read_lock();
> + if (vif) {
> + rtwvif = (struct rtw_vif *)vif->drv_priv;
> + list_for_each_entry(si, &rtwvif->sta_list, list) {
> + if (ether_addr_equal(si->sta->addr, hdr->addr2)) {
> + target = si;
> + break;
> + }
> + }
> + } else {
> + list_for_each_entry_rcu(rtwvif, &rtwdev->vif_list, list) {
> + list_for_each_entry(si, &rtwvif->sta_list, list) {
> + if (ether_addr_equal(si->sta->addr, hdr->addr2)) {
> + target = si;
> + break;
> + }
> + }
> + }
> + }
> + rcu_read_unlock();
> +
> + return target;
> +}
Seems a bit large for an inline?
johannes
next prev parent reply other threads:[~2018-10-08 14:10 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-10-03 11:20 [RFC v3 00/12] rtw88: mac80211 driver for Realtek 802.11ac wireless network chips yhchuang
2018-10-03 11:20 ` [RFC v3 01/12] rtw88: main files yhchuang
2018-10-08 14:10 ` Johannes Berg [this message]
[not found] ` <201810081447.w98ElQfu018110@rtits1.realtek.com.tw>
2018-10-11 7:23 ` Tony Chuang
2018-10-11 7:30 ` Johannes Berg
2018-10-13 17:47 ` Kalle Valo
2018-10-22 3:40 ` Tony Chuang
2018-11-15 14:18 ` Kalle Valo
2018-10-03 11:20 ` [RFC v3 02/12] rtw88: core files yhchuang
2018-10-08 14:12 ` Johannes Berg
2018-10-03 11:20 ` [RFC v3 03/12] rtw88: hci files yhchuang
2018-10-03 11:20 ` [RFC v3 04/12] rtw88: trx files yhchuang
2018-10-03 11:20 ` [RFC v3 05/12] rtw88: mac files yhchuang
2018-10-08 13:38 ` Johannes Berg
2018-10-03 11:20 ` [RFC v3 06/12] rtw88: fw and efuse files yhchuang
2018-10-03 11:20 ` [RFC v3 07/12] rtw88: phy files yhchuang
2018-10-04 14:10 ` Stanislaw Gruszka
2018-10-08 2:28 ` Tony Chuang
2018-10-03 11:20 ` [RFC v3 08/12] rtw88: debug files yhchuang
2018-10-04 14:23 ` Stanislaw Gruszka
2018-10-08 7:57 ` Tony Chuang
2018-10-08 13:29 ` Johannes Berg
[not found] ` <201810081446.w98EkN0r017815@rtits1.realtek.com.tw>
2018-10-09 2:42 ` Tony Chuang
2018-10-03 11:20 ` [RFC v3 09/12] rtw88: chip files yhchuang
2018-10-04 14:36 ` Stanislaw Gruszka
2018-10-08 9:38 ` Tony Chuang
2018-10-03 11:20 ` [RFC v3 10/12] rtw88: 8822B init table yhchuang
2018-10-03 11:20 ` [RFC v3 11/12] rtw88: 8822C " yhchuang
2018-10-03 11:20 ` [RFC v3 12/12] rtw88: Kconfig & Makefile yhchuang
2018-10-08 14:00 ` Johannes Berg
[not found] ` <201810081447.w98ElIFH018051@rtits1.realtek.com.tw>
2018-10-09 5:10 ` Tony Chuang
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1539007805.3687.47.camel@sipsolutions.net \
--to=johannes@sipsolutions.net \
--cc=Larry.Finger@lwfinger.net \
--cc=kvalo@codeaurora.org \
--cc=linux-wireless@vger.kernel.org \
--cc=pkshih@realtek.com \
--cc=sgruszka@redhat.com \
--cc=tehuang@realtek.com \
--cc=yhchuang@realtek.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).