All of lore.kernel.org
 help / color / mirror / Atom feed
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

  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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.