diff mbox series

[01/12] rtwlan: main files

Message ID 1537509847-21087-2-git-send-email-yhchuang@realtek.com (mailing list archive)
State Changes Requested
Delegated to: Kalle Valo
Headers show
Series rtwlan: mac80211 driver for Realtek 802.11ac wireless network chips | expand

Commit Message

Tony Chuang Sept. 21, 2018, 6:03 a.m. UTC
From: Yan-Hsuan Chuang <yhchuang@realtek.com>

main files for Realtek 802.11ac wireless network chips

Signed-off-by: Yan-Hsuan Chuang <yhchuang@realtek.com>
---
 drivers/net/wireless/realtek/rtwlan/mac80211.c |  447 +++++++++
 drivers/net/wireless/realtek/rtwlan/main.c     | 1164 +++++++++++++++++++++++
 drivers/net/wireless/realtek/rtwlan/main.h     | 1188 ++++++++++++++++++++++++
 drivers/net/wireless/realtek/rtwlan/reg.h      |  399 ++++++++
 4 files changed, 3198 insertions(+)
 create mode 100644 drivers/net/wireless/realtek/rtwlan/mac80211.c
 create mode 100644 drivers/net/wireless/realtek/rtwlan/main.c
 create mode 100644 drivers/net/wireless/realtek/rtwlan/main.h
 create mode 100644 drivers/net/wireless/realtek/rtwlan/reg.h

Comments

Stanislaw Gruszka Sept. 27, 2018, 1:50 p.m. UTC | #1
Hi,

Below is some more detailed review of first patch (with mostly
nitpicks).

On Fri, Sep 21, 2018 at 02:03:56PM +0800, yhchuang@realtek.com wrote:
> +static void rtw_ops_tx(struct ieee80211_hw *hw,
> +		       struct ieee80211_tx_control *control,
> +		       struct sk_buff *skb)
> +{
> +	struct rtw_dev *rtwdev = hw->priv;
> +	struct rtw_tx_pkt_info pkt_info;
> +
> +	if (!rtw_flag_check(rtwdev, RTW_FLAG_RUNNING))
> +		goto out;
> +
> +	memset(&pkt_info, 0, sizeof(pkt_info));
> +	rtw_tx_pkt_info_update(rtwdev, &pkt_info, control, skb);
> +	if (rtw_hci_tx(rtwdev, &pkt_info, skb))
> +		goto out;
> +
> +	return;
> +
> +out:
> +	dev_kfree_skb_any(skb);
This can be simplified by just do kfree after if ().
   
> +static int rtw_ops_add_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;
> +	enum rtw_net_type net_type;
> +	u32 config = 0;
> +	u8 port = 0;
<snip>
> +	list_add(&rtwvif->list, &rtwdev->vif_list);
How rtwdev->vif_list is protected agains concurent access ?

> +	INIT_LIST_HEAD(&rtwvif->sta_list);
> +
> +	rtwvif->conf = &rtw_vif_port[port];
port is always 0, this either should be fixes or max interfaces for
STA should be set to 1 (temporally).
 
> +static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw,
> +				     struct ieee80211_vif *vif,
> +				     struct ieee80211_bss_conf *conf,
> +				     u32 changed)
> +{
> +	struct rtw_dev *rtwdev = hw->priv;
> +	struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
> +	u32 config = 0;
> +
> +	if (changed & BSS_CHANGED_ASSOC) {
> +		struct rtw_sta_info *ap;
> +		struct rtw_chip_info *chip = rtwdev->chip;
> +		enum rtw_net_type net_type;
> +
> +		ap = list_first_entry(&rtwvif->sta_list,
> +				      struct rtw_sta_info, list);
How rtlwvif->sta_list is protected against concurrent access ? 

> +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;
> +}
> +
> +static int rtw_ops_sta_add(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;
> +	struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
> +
> +	si->mac_id = rtw_acquire_macid(rtwdev);
<snip>
> +
> +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;
> +
> +	rtw_release_macid(rtwdev, si->mac_id);
I'm not sure if mac80211 can not add one STA and remove another one
STA at the same time. This need to be verified.

> +static struct ieee80211_iface_limit rtw_5port_limits[] = {
> +	{ .max = 1, .types = BIT(NL80211_IFTYPE_AP) |
> +			     BIT(NL80211_IFTYPE_ADHOC) |
> +			     BIT(NL80211_IFTYPE_MESH_POINT), },
> +	{ .max = 5, .types = BIT(NL80211_IFTYPE_STATION), },
<snip>
> +static struct ieee80211_iface_combination rtw_5port_if_combs[] = {
> +	{
> +		.limits = rtw_5port_limits,
> +		.n_limits = ARRAY_SIZE(rtw_5port_limits),
> +		.max_interfaces = 5,
> +		.num_different_channels = 1,
> +	},
Here: change to max interfaces to 1 or fix port in add/remove interface.

> +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);
> +
> +	/* 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;
> +	list_for_each_entry(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;
If we just nulify statistics here, what is the point to provide them ?
I can not see code where we read those stats. Perhaps code
that use them will be added, so this possibly is fine.

> +	hal->current_channel = center_chan;
Not used anywhere.

> +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);
> +	if (ret) {
> +		rtw_err(rtwdev, "failed to request firmware\n");
> +		return ret;
> +	}
> +
> +	fw->firmware = firmware;
> +	fw->data = firmware->data;
> +	fw->size = firmware->size;
Seems not needed, we can use fw->firmware->{data,size}
since fw->firwware is not released till chip de-init.

> +#define BIT_LEN_MASK_32(__bitlen) (0xFFFFFFFF >> (32 - (__bitlen)))
> +#define BIT_OFFSET_LEN_MASK_32(__bitoffset, __bitlen)                          \
> +	(BIT_LEN_MASK_32(__bitlen) << (__bitoffset))
> +#define LE_P4BYTE_TO_HOST_4BYTE(__start) (le32_to_cpu(*((__le32 *)(__start))))
> +#define LE_BITS_CLEARED_TO_4BYTE(__start, __bitoffset, __bitlen)               \
> +	(LE_P4BYTE_TO_HOST_4BYTE(__start) &                                    \
> +	 (~BIT_OFFSET_LEN_MASK_32(__bitoffset, __bitlen)))
> +#define LE_BITS_TO_4BYTE(__start, __bitoffset, __bitlen)                       \
> +	((LE_P4BYTE_TO_HOST_4BYTE(__start) >> (__bitoffset)) &                 \
> +	 BIT_LEN_MASK_32(__bitlen))
> +#define SET_BITS_TO_LE_4BYTE(__start, __bitoffset, __bitlen, __value)          \
> +	do {                                                                   \
> +		*((__le32 *)(__start)) = \
> +		cpu_to_le32( \
> +		LE_BITS_CLEARED_TO_4BYTE(__start, __bitoffset, __bitlen) |     \
> +		((((u32)__value) & BIT_LEN_MASK_32(__bitlen)) << (__bitoffset))\
> +		);                                                             \
> +	} while (0)
I think this should be somehow cleaned up or replaced by something sane.

> +struct rtw_sta_info {
> +	struct list_head list;
> +
> +	struct ieee80211_sta *sta;
> +	struct ieee80211_vif *vif;
> +
> +	struct ewma_rssi avg_rssi;
> +	u8 rssi_level;
> +
> +	u8 mac_id;
> +	u8 rate_id;
> +	enum rtw_bandwidth bw_mode;

Can we talk with different STA using different bandwidh ? I think this
is configures channel property and bw_mode is the same for all
connected stations.
 
> +struct rtw_table {
> +	const void *data;
> +	const u32 size;
> +	void (*parse)(struct rtw_dev *rtwdev, const struct rtw_table *tbl);
> +	void (*do_cfg)(struct rtw_dev *rtwdev, const struct rtw_table *tbl,
> +		       u32 addr, u32 data);
> +	enum rtw_rf_path rf_path;
> +};
> +
> +static inline void rtw_load_table(struct rtw_dev *rtwdev,
> +				  const struct rtw_table *tbl)
> +{
> +	(*tbl->parse)(rtwdev, tbl);
> +}

This interface of loading/processing tables of data looks very strange.
I don't think is incorrect, but seems to be somewhat not necessary
complicated. I'll try provide more detailed comment about that when
review other files.

> +static inline u8 *get_hdr_bssid(struct ieee80211_hdr *hdr)
> +{
> +	__le16 fc = hdr->frame_control;
> +	u8 *bssid;
> +
> +	if (ieee80211_has_tods(fc))
> +		bssid = hdr->addr1;
> +	else if (ieee80211_has_fromds(fc))
> +		bssid = hdr->addr2;
> +	else
> +		bssid = hdr->addr3;
> +
> +	return bssid;

This seems to not to be that simple and depend on frame type and
interface type. See ieee80211_get_bssid().

> +#define BIT_SET_RXGCK_VHT_FIFOTHR(x, v)                                        \
> +	(BIT_CLEAR_RXGCK_VHT_FIFOTHR(x) | BIT_RXGCK_VHT_FIFOTHR(v))
> +
> +#define BIT_SHIFT_RXGCK_HT_FIFOTHR 24
> +#define BIT_MASK_RXGCK_HT_FIFOTHR 0x3
> +#define BIT_RXGCK_HT_FIFOTHR(x)                                                \
> +	(((x) & BIT_MASK_RXGCK_HT_FIFOTHR) << BIT_SHIFT_RXGCK_HT_FIFOTHR)
> +#define BITS_RXGCK_HT_FIFOTHR                                                  \
> +	(BIT_MASK_RXGCK_HT_FIFOTHR << BIT_SHIFT_RXGCK_HT_FIFOTHR)
> +#define BIT_CLEAR_RXGCK_HT_FIFOTHR(x) ((x) & (~BITS_RXGCK_HT_FIFOTHR))
> +#define BIT_GET_RXGCK_HT_FIFOTHR(x)                                            \
> +	(((x) >> BIT_SHIFT_RXGCK_HT_FIFOTHR) & BIT_MASK_RXGCK_HT_FIFOTHR)
> +#define BIT_SET_RXGCK_HT_FIFOTHR(x, v)                                         \
> +	(BIT_CLEAR_RXGCK_HT_FIFOTHR(x) | BIT_RXGCK_HT_FIFOTHR(v))
> +
> +#define BIT_SHIFT_RXGCK_OFDM_FIFOTHR 22
> +#define BIT_MASK_RXGCK_OFDM_FIFOTHR 0x3
> +#define BIT_RXGCK_OFDM_FIFOTHR(x)                                              \
> +	(((x) & BIT_MASK_RXGCK_OFDM_FIFOTHR) << BIT_SHIFT_RXGCK_OFDM_FIFOTHR)
> +#define BITS_RXGCK_OFDM_FIFOTHR                                                \
> +	(BIT_MASK_RXGCK_OFDM_FIFOTHR << BIT_SHIFT_RXGCK_OFDM_FIFOTHR)
> +#define BIT_CLEAR_RXGCK_OFDM_FIFOTHR(x) ((x) & (~BITS_RXGCK_OFDM_FIFOTHR))
> +#define BIT_GET_RXGCK_OFDM_FIFOTHR(x)                                          \
> +	(((x) >> BIT_SHIFT_RXGCK_OFDM_FIFOTHR) & BIT_MASK_RXGCK_OFDM_FIFOTHR)
> +#define BIT_SET_RXGCK_OFDM_FIFOTHR(x, v)                                       \
> +	(BIT_CLEAR_RXGCK_OFDM_FIFOTHR(x) | BIT_RXGCK_OFDM_FIFOTHR(v))

Lot of not used defines.

Regards
Stanislaw
Larry Finger Sept. 27, 2018, 3:40 p.m. UTC | #2
On 9/27/18 8:50 AM, Stanislaw Gruszka wrote:
--snip

> 
>> +#define BIT_LEN_MASK_32(__bitlen) (0xFFFFFFFF >> (32 - (__bitlen)))
>> +#define BIT_OFFSET_LEN_MASK_32(__bitoffset, __bitlen)                          \
>> +	(BIT_LEN_MASK_32(__bitlen) << (__bitoffset))
>> +#define LE_P4BYTE_TO_HOST_4BYTE(__start) (le32_to_cpu(*((__le32 *)(__start))))
>> +#define LE_BITS_CLEARED_TO_4BYTE(__start, __bitoffset, __bitlen)               \
>> +	(LE_P4BYTE_TO_HOST_4BYTE(__start) &                                    \
>> +	 (~BIT_OFFSET_LEN_MASK_32(__bitoffset, __bitlen)))
>> +#define LE_BITS_TO_4BYTE(__start, __bitoffset, __bitlen)                       \
>> +	((LE_P4BYTE_TO_HOST_4BYTE(__start) >> (__bitoffset)) &                 \
>> +	 BIT_LEN_MASK_32(__bitlen))
>> +#define SET_BITS_TO_LE_4BYTE(__start, __bitoffset, __bitlen, __value)          \
>> +	do {                                                                   \
>> +		*((__le32 *)(__start)) = \
>> +		cpu_to_le32( \
>> +		LE_BITS_CLEARED_TO_4BYTE(__start, __bitoffset, __bitlen) |     \
>> +		((((u32)__value) & BIT_LEN_MASK_32(__bitlen)) << (__bitoffset))\
>> +		);                                                             \
>> +	} while (0)

Stanislaw,

I have never loved these macros, and it took a lot of time to get them to be 
endian correct. Could you point me to a method that would overwrite a portion of 
a 32-bit little-endian word that would be correct for both little- and 
big-endian machines? Keep in mind that Kalle hates the use of compile tests on 
__LITTLE_ENDIAN.

Thanks,

Larry
Tony Chuang Sept. 28, 2018, 3:20 a.m. UTC | #3
Stanislaw,

Thanks a lot to point them some, some of them I have not even noticed!

> -----Original Message-----
> From: Stanislaw Gruszka [mailto:sgruszka@redhat.com]
> Sent: Thursday, September 27, 2018 9:51 PM
> To: Tony Chuang
> Cc: kvalo@codeaurora.org; Larry.Finger@lwfinger.net;
> linux-wireless@vger.kernel.org; Pkshih; Andy Huang
> Subject: Re: [PATCH 01/12] rtwlan: main files
> 
> Hi,
> 
> Below is some more detailed review of first patch (with mostly
> nitpicks).
> 
> On Fri, Sep 21, 2018 at 02:03:56PM +0800, yhchuang@realtek.com wrote:
> > +static void rtw_ops_tx(struct ieee80211_hw *hw,
> > +		       struct ieee80211_tx_control *control,
> > +		       struct sk_buff *skb)
> > +{
> > +	struct rtw_dev *rtwdev = hw->priv;
> > +	struct rtw_tx_pkt_info pkt_info;
> > +
> > +	if (!rtw_flag_check(rtwdev, RTW_FLAG_RUNNING))
> > +		goto out;
> > +
> > +	memset(&pkt_info, 0, sizeof(pkt_info));
> > +	rtw_tx_pkt_info_update(rtwdev, &pkt_info, control, skb);
> > +	if (rtw_hci_tx(rtwdev, &pkt_info, skb))
> > +		goto out;
> > +
> > +	return;
> > +
> > +out:
> > +	dev_kfree_skb_any(skb);
> This can be simplified by just do kfree after if ().


OK, will replace them with ieee80211_free_txskb


> > +static int rtw_ops_add_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;
> > +	enum rtw_net_type net_type;
> > +	u32 config = 0;
> > +	u8 port = 0;
> <snip>
> > +	list_add(&rtwvif->list, &rtwdev->vif_list);
> How rtwdev->vif_list is protected agains concurent access ?
> 
> > +	INIT_LIST_HEAD(&rtwvif->sta_list);
> > +
> > +	rtwvif->conf = &rtw_vif_port[port];
> port is always 0, this either should be fixes or max interfaces for
> STA should be set to 1 (temporally).
> 
> > +static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw,
> > +				     struct ieee80211_vif *vif,
> > +				     struct ieee80211_bss_conf *conf,
> > +				     u32 changed)
> > +{
> > +	struct rtw_dev *rtwdev = hw->priv;
> > +	struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
> > +	u32 config = 0;
> > +
> > +	if (changed & BSS_CHANGED_ASSOC) {
> > +		struct rtw_sta_info *ap;
> > +		struct rtw_chip_info *chip = rtwdev->chip;
> > +		enum rtw_net_type net_type;
> > +
> > +		ap = list_first_entry(&rtwvif->sta_list,
> > +				      struct rtw_sta_info, list);
> How rtlwvif->sta_list is protected against concurrent access ?


Have not noticed so far, cause not we can only support on vif.

And only STA mode is tested, should first modify the iface_conbination.
Then modify them back again if we submit patches support concurrents

I think that vif_list & sta_list could be protected by a single mutex that
protects concurrent access against mac80211 callbacks, and further add
some rcu locks to protect sta_info. You have some suggestions?


> 
> > +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;
> > +}
> > +
> > +static int rtw_ops_sta_add(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;
> > +	struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
> > +
> > +	si->mac_id = rtw_acquire_macid(rtwdev);
> <snip>
> > +
> > +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;
> > +
> > +	rtw_release_macid(rtwdev, si->mac_id);
> I'm not sure if mac80211 can not add one STA and remove another one
> STA at the same time. This need to be verified.


I think mac80211 will do it "if the vif is different", but under the same vif,
mac80211 will protect it with "sdata->wdev.mtx". Not sure if I am right.


> 
> > +static struct ieee80211_iface_limit rtw_5port_limits[] = {
> > +	{ .max = 1, .types = BIT(NL80211_IFTYPE_AP) |
> > +			     BIT(NL80211_IFTYPE_ADHOC) |
> > +			     BIT(NL80211_IFTYPE_MESH_POINT), },
> > +	{ .max = 5, .types = BIT(NL80211_IFTYPE_STATION), },
> <snip>
> > +static struct ieee80211_iface_combination rtw_5port_if_combs[] = {
> > +	{
> > +		.limits = rtw_5port_limits,
> > +		.n_limits = ARRAY_SIZE(rtw_5port_limits),
> > +		.max_interfaces = 5,
> > +		.num_different_channels = 1,
> > +	},
> Here: change to max interfaces to 1 or fix port in add/remove interface.


OK


> > +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);
> > +
> > +	/* 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;
> > +	list_for_each_entry(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;
> If we just nulify statistics here, what is the point to provide them ?
> I can not see code where we read those stats. Perhaps code
> that use them will be added, so this possibly is fine.


Yeah the will be used.


> > +	hal->current_channel = center_chan;
> Not used anywhere.


Will be used in set channel, but missed that in this patch


> > +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);
> > +	if (ret) {
> > +		rtw_err(rtwdev, "failed to request firmware\n");
> > +		return ret;
> > +	}
> > +
> > +	fw->firmware = firmware;
> > +	fw->data = firmware->data;
> > +	fw->size = firmware->size;
> Seems not needed, we can use fw->firmware->{data,size}
> since fw->firwware is not released till chip de-init.


OK


> > +#define BIT_LEN_MASK_32(__bitlen) (0xFFFFFFFF >> (32 - (__bitlen)))
> > +#define BIT_OFFSET_LEN_MASK_32(__bitoffset, __bitlen)
> \
> > +	(BIT_LEN_MASK_32(__bitlen) << (__bitoffset))
> > +#define LE_P4BYTE_TO_HOST_4BYTE(__start) (le32_to_cpu(*((__le32
> *)(__start))))
> > +#define LE_BITS_CLEARED_TO_4BYTE(__start, __bitoffset, __bitlen)
> \
> > +	(LE_P4BYTE_TO_HOST_4BYTE(__start) &
> \
> > +	 (~BIT_OFFSET_LEN_MASK_32(__bitoffset, __bitlen)))
> > +#define LE_BITS_TO_4BYTE(__start, __bitoffset, __bitlen)
> \
> > +	((LE_P4BYTE_TO_HOST_4BYTE(__start) >> (__bitoffset)) &
> \
> > +	 BIT_LEN_MASK_32(__bitlen))
> > +#define SET_BITS_TO_LE_4BYTE(__start, __bitoffset, __bitlen, __value)
> \
> > +	do
> {
>     \
> > +		*((__le32 *)(__start)) = \
> > +		cpu_to_le32( \
> > +		LE_BITS_CLEARED_TO_4BYTE(__start, __bitoffset, __bitlen) |     \
> > +		((((u32)__value) & BIT_LEN_MASK_32(__bitlen)) << (__bitoffset))\
> > +		);
> \
> > +	} while (0)
> I think this should be somehow cleaned up or replaced by something sane.


Larry replied you, and that is exactly what I wanted to ask.


> > +struct rtw_sta_info {
> > +	struct list_head list;
> > +
> > +	struct ieee80211_sta *sta;
> > +	struct ieee80211_vif *vif;
> > +
> > +	struct ewma_rssi avg_rssi;
> > +	u8 rssi_level;
> > +
> > +	u8 mac_id;
> > +	u8 rate_id;
> > +	enum rtw_bandwidth bw_mode;
> 
> Can we talk with different STA using different bandwidh ? I think this
> is configures channel property and bw_mode is the same for all
> connected stations.


Yes, we can. If we have TDLS peer in STA mode or in AP mode, we could have
different bw_mode, by the sta_info mac80211 passed to us, and that sta_info is
checked by mac80211 based on the capabilities (IE) of the peer.


> > +struct rtw_table {
> > +	const void *data;
> > +	const u32 size;
> > +	void (*parse)(struct rtw_dev *rtwdev, const struct rtw_table *tbl);
> > +	void (*do_cfg)(struct rtw_dev *rtwdev, const struct rtw_table *tbl,
> > +		       u32 addr, u32 data);
> > +	enum rtw_rf_path rf_path;
> > +};
> > +
> > +static inline void rtw_load_table(struct rtw_dev *rtwdev,
> > +				  const struct rtw_table *tbl)
> > +{
> > +	(*tbl->parse)(rtwdev, tbl);
> > +}
> 
> This interface of loading/processing tables of data looks very strange.
> I don't think is incorrect, but seems to be somewhat not necessary
> complicated. I'll try provide more detailed comment about that when
> review other files.


OK, but I think this is needed, our tables have different forms ....


> > +static inline u8 *get_hdr_bssid(struct ieee80211_hdr *hdr)
> > +{
> > +	__le16 fc = hdr->frame_control;
> > +	u8 *bssid;
> > +
> > +	if (ieee80211_has_tods(fc))
> > +		bssid = hdr->addr1;
> > +	else if (ieee80211_has_fromds(fc))
> > +		bssid = hdr->addr2;
> > +	else
> > +		bssid = hdr->addr3;
> > +
> > +	return bssid;
> 
> This seems to not to be that simple and depend on frame type and
> interface type. See ieee80211_get_bssid().


OK, thanks.



> > +#define BIT_SET_RXGCK_VHT_FIFOTHR(x, v)
> \
> > +	(BIT_CLEAR_RXGCK_VHT_FIFOTHR(x) | BIT_RXGCK_VHT_FIFOTHR(v))
> > +
> > +#define BIT_SHIFT_RXGCK_HT_FIFOTHR 24
> > +#define BIT_MASK_RXGCK_HT_FIFOTHR 0x3
> > +#define BIT_RXGCK_HT_FIFOTHR(x)
> \
> > +	(((x) & BIT_MASK_RXGCK_HT_FIFOTHR) <<
> BIT_SHIFT_RXGCK_HT_FIFOTHR)
> > +#define BITS_RXGCK_HT_FIFOTHR
> \
> > +	(BIT_MASK_RXGCK_HT_FIFOTHR << BIT_SHIFT_RXGCK_HT_FIFOTHR)
> > +#define BIT_CLEAR_RXGCK_HT_FIFOTHR(x) ((x) &
> (~BITS_RXGCK_HT_FIFOTHR))
> > +#define BIT_GET_RXGCK_HT_FIFOTHR(x)
> \
> > +	(((x) >> BIT_SHIFT_RXGCK_HT_FIFOTHR) &
> BIT_MASK_RXGCK_HT_FIFOTHR)
> > +#define BIT_SET_RXGCK_HT_FIFOTHR(x, v)
> \
> > +	(BIT_CLEAR_RXGCK_HT_FIFOTHR(x) | BIT_RXGCK_HT_FIFOTHR(v))
> > +
> > +#define BIT_SHIFT_RXGCK_OFDM_FIFOTHR 22
> > +#define BIT_MASK_RXGCK_OFDM_FIFOTHR 0x3
> > +#define BIT_RXGCK_OFDM_FIFOTHR(x)
> \
> > +	(((x) & BIT_MASK_RXGCK_OFDM_FIFOTHR) <<
> BIT_SHIFT_RXGCK_OFDM_FIFOTHR)
> > +#define BITS_RXGCK_OFDM_FIFOTHR
> \
> > +	(BIT_MASK_RXGCK_OFDM_FIFOTHR <<
> BIT_SHIFT_RXGCK_OFDM_FIFOTHR)
> > +#define BIT_CLEAR_RXGCK_OFDM_FIFOTHR(x) ((x) &
> (~BITS_RXGCK_OFDM_FIFOTHR))
> > +#define BIT_GET_RXGCK_OFDM_FIFOTHR(x)
> \
> > +	(((x) >> BIT_SHIFT_RXGCK_OFDM_FIFOTHR) &
> BIT_MASK_RXGCK_OFDM_FIFOTHR)
> > +#define BIT_SET_RXGCK_OFDM_FIFOTHR(x, v)
> \
> > +	(BIT_CLEAR_RXGCK_OFDM_FIFOTHR(x) | BIT_RXGCK_OFDM_FIFOTHR(v))
> 
> Lot of not used defines.


Will remove them.


> Regards
> Stanislaw
> 
> ------Please consider the environment before printing this e-mail.


Anyway, appreciate your review and suggestion

Yan-Hsuan Chuang
Stanislaw Gruszka Sept. 28, 2018, 9:08 a.m. UTC | #4
On Thu, Sep 27, 2018 at 10:40:44AM -0500, Larry Finger wrote:
> On 9/27/18 8:50 AM, Stanislaw Gruszka wrote:
> --snip
> 
> > 
> > > +#define BIT_LEN_MASK_32(__bitlen) (0xFFFFFFFF >> (32 - (__bitlen)))
> > > +#define BIT_OFFSET_LEN_MASK_32(__bitoffset, __bitlen)                          \
> > > +	(BIT_LEN_MASK_32(__bitlen) << (__bitoffset))
> > > +#define LE_P4BYTE_TO_HOST_4BYTE(__start) (le32_to_cpu(*((__le32 *)(__start))))
> > > +#define LE_BITS_CLEARED_TO_4BYTE(__start, __bitoffset, __bitlen)               \
> > > +	(LE_P4BYTE_TO_HOST_4BYTE(__start) &                                    \
> > > +	 (~BIT_OFFSET_LEN_MASK_32(__bitoffset, __bitlen)))
> > > +#define LE_BITS_TO_4BYTE(__start, __bitoffset, __bitlen)                       \
> > > +	((LE_P4BYTE_TO_HOST_4BYTE(__start) >> (__bitoffset)) &                 \
> > > +	 BIT_LEN_MASK_32(__bitlen))
> > > +#define SET_BITS_TO_LE_4BYTE(__start, __bitoffset, __bitlen, __value)          \
> > > +	do {                                                                   \
> > > +		*((__le32 *)(__start)) = \
> > > +		cpu_to_le32( \
> > > +		LE_BITS_CLEARED_TO_4BYTE(__start, __bitoffset, __bitlen) |     \
> > > +		((((u32)__value) & BIT_LEN_MASK_32(__bitlen)) << (__bitoffset))\
> > > +		);                                                             \
> > > +	} while (0)
> 
> Stanislaw,
> 
> I have never loved these macros, and it took a lot of time to get them to be
> endian correct. Could you point me to a method that would overwrite a
> portion of a 32-bit little-endian word that would be correct for both
> little- and big-endian machines? Keep in mind that Kalle hates the use of
> compile tests on __LITTLE_ENDIAN.

Maybe something like this (not tested)

#define SET_LE32(reg, off, len, val) \
	((reg & cpu_to_le32(~GENMASK(off + len - 1, off))) | cpu_to_le32(val << off))

?

There are plenty of bitops and endian primitives in kernel, it's
very very unlikly you need custom macros for handle that.

Thanks
Stanislaw
Stanislaw Gruszka Sept. 28, 2018, 9:29 a.m. UTC | #5
Hi

On Fri, Sep 28, 2018 at 03:20:45AM +0000, Tony Chuang wrote:
> > > +	rtw_tx_pkt_info_update(rtwdev, &pkt_info, control, skb);
> > > +	if (rtw_hci_tx(rtwdev, &pkt_info, skb))
> > > +		goto out;
> > > +
> > > +	return;
> > > +
> > > +out:
> > > +	dev_kfree_skb_any(skb);
> > This can be simplified by just do kfree after if ().
> 
> 
> OK, will replace them with ieee80211_free_txskb

I was thinking about:

	if (rtw_hci_tx(rtwdev, &pkt_info, skb))
		dev_kfree_skb_any(skb)

just to remove 'return;' and out label.

> Have not noticed so far, cause not we can only support on vif.
> 
> And only STA mode is tested, should first modify the iface_conbination.
> Then modify them back again if we submit patches support concurrents
> 
> I think that vif_list & sta_list could be protected by a single mutex that
> protects concurrent access against mac80211 callbacks, and further add
> some rcu locks to protect sta_info. You have some suggestions?

That's good solution, sync multiple possible writes via mutex and
reads of list against writes via RCU.

> I think mac80211 will do it "if the vif is different", but under the same vif,
> mac80211 will protect it with "sdata->wdev.mtx". Not sure if I am right.

I need to check that as well :-)

> Yes, we can. If we have TDLS peer in STA mode or in AP mode, we could have
> different bw_mode, by the sta_info mac80211 passed to us, and that sta_info is
> checked by mac80211 based on the capabilities (IE) of the peer.
How this work with respect we configure band-width when we change the channel?
If we set band-width per sta, should then setting band-width on channel
setup be droped ?

> > > +static inline void rtw_load_table(struct rtw_dev *rtwdev,
> > > +				  const struct rtw_table *tbl)
> > > +{
> > > +	(*tbl->parse)(rtwdev, tbl);
> > > +}
> > 
> > This interface of loading/processing tables of data looks very strange.
> > I don't think is incorrect, but seems to be somewhat not necessary
> > complicated. I'll try provide more detailed comment about that when
> > review other files.
> 
> 
> OK, but I think this is needed, our tables have different forms ....

Not sure if that is better solution, but could the tables be pre-prarsed
by user-space program and then embed in the driver in ready to send
to the hardware from ?

Also there are lot of redundancy in those tables, for example:

+	0x81C, 0xFF000003,
+	0x81C, 0xF5000003,
+	0x81C, 0xF4020003,
+	0x81C, 0xF3040003,
+	0x81C, 0xF2060003,
+	0x81C, 0xF1080003,
+	0x81C, 0xF00A0003,
+	0x81C, 0xEF0C0003,
+	0x81C, 0xEE0E0003,
+	0x81C, 0xED100003,
+	0x81C, 0xEC120003,
+	0x81C, 0xEB140003,
+	0x81C, 0xEA160003,
+	0x81C, 0xE9180003,
+	0x81C, 0xE81A0003,
+	0x81C, 0xE71C0003,
+	0x81C, 0xE61E0003,
+	0x81C, 0xE5200003,

0x81C and 0003 repeats in many lines. 

This seems to be parse data, not that we have to write 0x81C
register many times. Would be possible to remove the redundancy?

Thanks
Stanislaw
Tony Chuang Sept. 28, 2018, 11:32 a.m. UTC | #6
> -----Original Message-----
> From: Stanislaw Gruszka [mailto:sgruszka@redhat.com]
> Sent: Friday, September 28, 2018 5:29 PM
> To: Tony Chuang
> Cc: kvalo@codeaurora.org; Larry.Finger@lwfinger.net;
> linux-wireless@vger.kernel.org; Pkshih; Andy Huang
> Subject: Re: [PATCH 01/12] rtwlan: main files
> 
> Hi
> 
> On Fri, Sep 28, 2018 at 03:20:45AM +0000, Tony Chuang wrote:
> > > > +	rtw_tx_pkt_info_update(rtwdev, &pkt_info, control, skb);
> > > > +	if (rtw_hci_tx(rtwdev, &pkt_info, skb))
> > > > +		goto out;
> > > > +
> > > > +	return;
> > > > +
> > > > +out:
> > > > +	dev_kfree_skb_any(skb);
> > > This can be simplified by just do kfree after if ().
> >
> >
> > OK, will replace them with ieee80211_free_txskb
> 
> I was thinking about:
> 
> 	if (rtw_hci_tx(rtwdev, &pkt_info, skb))
> 		dev_kfree_skb_any(skb)
> 
> just to remove 'return;' and out label.


OK, but why not use ieee80211_free_txskb, should it be better for mac80211?


> > Have not noticed so far, cause not we can only support on vif.
> >
> > And only STA mode is tested, should first modify the iface_conbination.
> > Then modify them back again if we submit patches support concurrents
> >
> > I think that vif_list & sta_list could be protected by a single mutex that
> > protects concurrent access against mac80211 callbacks, and further add
> > some rcu locks to protect sta_info. You have some suggestions?
> 
> That's good solution, sync multiple possible writes via mutex and
> reads of list against writes via RCU.
> 
> > I think mac80211 will do it "if the vif is different", but under the same vif,
> > mac80211 will protect it with "sdata->wdev.mtx". Not sure if I am right.
> 
> I need to check that as well :-)
> 
> > Yes, we can. If we have TDLS peer in STA mode or in AP mode, we could have
> > different bw_mode, by the sta_info mac80211 passed to us, and that
> sta_info is
> > checked by mac80211 based on the capabilities (IE) of the peer.
> How this work with respect we configure band-width when we change the
> channel?
> If we set band-width per sta, should then setting band-width on channel
> setup be droped ?


The channel setup and per-sta are required.

Now suppose we are STA mode, capable of 80Mhz, connecting to an AP that
is also capable of 80Mhz, then mac80211 will ask us to setup channel to 80Mhz.
Before change the channel, mac80211 will intersect the capabilities.

And now another peer joined, like TDLS, and the peer is only capable of 40Mhz,
after mac80211 intersect our capabilities, the sta_info passed will be 40Mhz.
Then we can talk to AP with 80Mhz BW, and to TDLS peer with 40Mhz.

Hence we need the per-sta capabilities.

> 
> > > > +static inline void rtw_load_table(struct rtw_dev *rtwdev,
> > > > +				  const struct rtw_table *tbl)
> > > > +{
> > > > +	(*tbl->parse)(rtwdev, tbl);
> > > > +}
> > >
> > > This interface of loading/processing tables of data looks very strange.
> > > I don't think is incorrect, but seems to be somewhat not necessary
> > > complicated. I'll try provide more detailed comment about that when
> > > review other files.
> >
> >
> > OK, but I think this is needed, our tables have different forms ....
> 
> Not sure if that is better solution, but could the tables be pre-prarsed
> by user-space program and then embed in the driver in ready to send
> to the hardware from ?
> 
> Also there are lot of redundancy in those tables, for example:
> 
> +	0x81C, 0xFF000003,
> +	0x81C, 0xF5000003,
> +	0x81C, 0xF4020003,
> +	0x81C, 0xF3040003,
> +	0x81C, 0xF2060003,
> +	0x81C, 0xF1080003,
> +	0x81C, 0xF00A0003,
> +	0x81C, 0xEF0C0003,
> +	0x81C, 0xEE0E0003,
> +	0x81C, 0xED100003,
> +	0x81C, 0xEC120003,
> +	0x81C, 0xEB140003,
> +	0x81C, 0xEA160003,
> +	0x81C, 0xE9180003,
> +	0x81C, 0xE81A0003,
> +	0x81C, 0xE71C0003,
> +	0x81C, 0xE61E0003,
> +	0x81C, 0xE5200003,
> 
> 0x81C and 0003 repeats in many lines.
> 
> This seems to be parse data, not that we have to write 0x81C
> register many times. Would be possible to remove the redundancy?


No, they cannot be removed, the sequence matters.
And it is really writing to 0x81C ...
It is really magic, I cannot believe to this, too.

Yan-Hsuan Chuang
Tony Chuang Oct. 2, 2018, 9:35 a.m. UTC | #7
Hi Kale & Stanislaw,

I am working on the driver code and making some changes that Stanislaw
have mentioned. And I expected that I will finish them tomorrow, what
should I do after I finished them?

Should I send an RFCv2, or start a new RFC for it ? Because our driver will
be renamed from rtwlan to rtw88 for 8822B/8822C

Thanks
Yan-Hsuan Chuang
Stanislaw Gruszka Oct. 2, 2018, 10:14 a.m. UTC | #8
Hi

On Tue, Oct 02, 2018 at 09:35:35AM +0000, Tony Chuang wrote:
> 
> Hi Kale & Stanislaw,
> 
> I am working on the driver code and making some changes that Stanislaw
> have mentioned. And I expected that I will finish them tomorrow, what
> should I do after I finished them?
> 
> Should I send an RFCv2, or start a new RFC for it ? Because our driver will
> be renamed from rtwlan to rtw88 for 8822B/8822C

I think RFCv2 since this is is second iteration and name change is part
of it.

Thanks
Stanislaw
Stanislaw Gruszka Oct. 2, 2018, 10:29 a.m. UTC | #9
On Fri, Sep 28, 2018 at 11:32:41AM +0000, Tony Chuang wrote:
> > 	if (rtw_hci_tx(rtwdev, &pkt_info, skb))
> > 		dev_kfree_skb_any(skb)
> > 
> > just to remove 'return;' and out label.
> 
> 
> OK, but why not use ieee80211_free_txskb, should it be better for mac80211?

Yes, it is better as it also do some extra thing for dropped frame.

> > > OK, but I think this is needed, our tables have different forms ....
> > 
> > Not sure if that is better solution, but could the tables be pre-prarsed
> > by user-space program and then embed in the driver in ready to send
> > to the hardware from ?
> > 
> > Also there are lot of redundancy in those tables, for example:
> > 
> > +	0x81C, 0xFF000003,
> > +	0x81C, 0xF5000003,
> > +	0x81C, 0xF4020003,
> > +	0x81C, 0xF3040003,
> > +	0x81C, 0xF2060003,
> > +	0x81C, 0xF1080003,
> > +	0x81C, 0xF00A0003,
> > +	0x81C, 0xEF0C0003,
> > +	0x81C, 0xEE0E0003,
> > +	0x81C, 0xED100003,
> > +	0x81C, 0xEC120003,
> > +	0x81C, 0xEB140003,
> > +	0x81C, 0xEA160003,
> > +	0x81C, 0xE9180003,
> > +	0x81C, 0xE81A0003,
> > +	0x81C, 0xE71C0003,
> > +	0x81C, 0xE61E0003,
> > +	0x81C, 0xE5200003,
> > 
> > 0x81C and 0003 repeats in many lines.
> > 
> > This seems to be parse data, not that we have to write 0x81C
> > register many times. Would be possible to remove the redundancy?
> 
> 
> No, they cannot be removed, the sequence matters.
> And it is really writing to 0x81C ...
> It is really magic, I cannot believe to this, too.

This is contradiction for what I asked you before, i.e. doing parsing
in user space, but since we have this parsing mechanism in the driver
perhaps the tables can be coded in some more compact way, for example:

{ prefix, suffix, len, {data} }

{ 0x81C, 0x0003, N ,
  { 0xFF02 , 0xF500 , .... , 0xE520 } }

The rtw8822b_table.c file is quite big. 

Thanks
Stanislaw
Larry Finger Oct. 2, 2018, 3:23 p.m. UTC | #10
On 10/2/18 5:29 AM, Stanislaw Gruszka wrote:
> On Fri, Sep 28, 2018 at 11:32:41AM +0000, Tony Chuang wrote:
>>> 	if (rtw_hci_tx(rtwdev, &pkt_info, skb))
>>> 		dev_kfree_skb_any(skb)
>>>
>>> just to remove 'return;' and out label.
>>
>>
>> OK, but why not use ieee80211_free_txskb, should it be better for mac80211?
> 
> Yes, it is better as it also do some extra thing for dropped frame.
> 
>>>> OK, but I think this is needed, our tables have different forms ....
>>>
>>> Not sure if that is better solution, but could the tables be pre-prarsed
>>> by user-space program and then embed in the driver in ready to send
>>> to the hardware from ?
>>>
>>> Also there are lot of redundancy in those tables, for example:
>>>
>>> +	0x81C, 0xFF000003,
>>> +	0x81C, 0xF5000003,
>>> +	0x81C, 0xF4020003,
>>> +	0x81C, 0xF3040003,
>>> +	0x81C, 0xF2060003,
>>> +	0x81C, 0xF1080003,
>>> +	0x81C, 0xF00A0003,
>>> +	0x81C, 0xEF0C0003,
>>> +	0x81C, 0xEE0E0003,
>>> +	0x81C, 0xED100003,
>>> +	0x81C, 0xEC120003,
>>> +	0x81C, 0xEB140003,
>>> +	0x81C, 0xEA160003,
>>> +	0x81C, 0xE9180003,
>>> +	0x81C, 0xE81A0003,
>>> +	0x81C, 0xE71C0003,
>>> +	0x81C, 0xE61E0003,
>>> +	0x81C, 0xE5200003,
>>>
>>> 0x81C and 0003 repeats in many lines.
>>>
>>> This seems to be parse data, not that we have to write 0x81C
>>> register many times. Would be possible to remove the redundancy?
>>
>>
>> No, they cannot be removed, the sequence matters.
>> And it is really writing to 0x81C ...
>> It is really magic, I cannot believe to this, too.
> 
> This is contradiction for what I asked you before, i.e. doing parsing
> in user space, but since we have this parsing mechanism in the driver
> perhaps the tables can be coded in some more compact way, for example:
> 
> { prefix, suffix, len, {data} }
> 
> { 0x81C, 0x0003, N ,
>    { 0xFF02 , 0xF500 , .... , 0xE520 } }
> 
> The rtw8822b_table.c file is quite big.

You might also consider having these tables as a configuration file read from 
the firmware directory.

Larry
Tony Chuang Oct. 3, 2018, 2:57 a.m. UTC | #11
> -----Original Message-----
> From: Larry Finger [mailto:larry.finger@gmail.com] On Behalf Of Larry Finger
> Sent: Tuesday, October 02, 2018 11:24 PM
> To: Stanislaw Gruszka; Tony Chuang
> Cc: kvalo@codeaurora.org; linux-wireless@vger.kernel.org; Pkshih; Andy
> Huang
> Subject: Re: [PATCH 01/12] rtwlan: main files
> 
> On 10/2/18 5:29 AM, Stanislaw Gruszka wrote:
> > On Fri, Sep 28, 2018 at 11:32:41AM +0000, Tony Chuang wrote:
> >>> 	if (rtw_hci_tx(rtwdev, &pkt_info, skb))
> >>> 		dev_kfree_skb_any(skb)
> >>>
> >>> just to remove 'return;' and out label.
> >>
> >>
> >> OK, but why not use ieee80211_free_txskb, should it be better for
> mac80211?
> >
> > Yes, it is better as it also do some extra thing for dropped frame.
> >
> >>>> OK, but I think this is needed, our tables have different forms ....
> >>>
> >>> Not sure if that is better solution, but could the tables be pre-prarsed
> >>> by user-space program and then embed in the driver in ready to send
> >>> to the hardware from ?
> >>>
> >>> Also there are lot of redundancy in those tables, for example:
> >>>
> >>> +	0x81C, 0xFF000003,
> >>> +	0x81C, 0xF5000003,
> >>> +	0x81C, 0xF4020003,
> >>> +	0x81C, 0xF3040003,
> >>> +	0x81C, 0xF2060003,
> >>> +	0x81C, 0xF1080003,
> >>> +	0x81C, 0xF00A0003,
> >>> +	0x81C, 0xEF0C0003,
> >>> +	0x81C, 0xEE0E0003,
> >>> +	0x81C, 0xED100003,
> >>> +	0x81C, 0xEC120003,
> >>> +	0x81C, 0xEB140003,
> >>> +	0x81C, 0xEA160003,
> >>> +	0x81C, 0xE9180003,
> >>> +	0x81C, 0xE81A0003,
> >>> +	0x81C, 0xE71C0003,
> >>> +	0x81C, 0xE61E0003,
> >>> +	0x81C, 0xE5200003,
> >>>
> >>> 0x81C and 0003 repeats in many lines.
> >>>
> >>> This seems to be parse data, not that we have to write 0x81C
> >>> register many times. Would be possible to remove the redundancy?
> >>
> >>
> >> No, they cannot be removed, the sequence matters.
> >> And it is really writing to 0x81C ...
> >> It is really magic, I cannot believe to this, too.
> >
> > This is contradiction for what I asked you before, i.e. doing parsing
> > in user space, but since we have this parsing mechanism in the driver
> > perhaps the tables can be coded in some more compact way, for example:
> >
> > { prefix, suffix, len, {data} }
> >
> > { 0x81C, 0x0003, N ,
> >    { 0xFF02 , 0xF500 , .... , 0xE520 } }
> >
> > The rtw8822b_table.c file is quite big.
> 
> You might also consider having these tables as a configuration file read from
> the firmware directory.
> 

Hi Larry,

Can we put the configuration file in the firmware directory?
Should we package them into binary files? Or just put the raw data.

We can test the performance for it. After we got the result, we will make a decision
about it. And if we decide to put them in the firmware directory, will send a patch.
For now, I think we can just leave them in the .c.

Yan-Hsuan Chuang
Tony Chuang Oct. 3, 2018, 3:25 a.m. UTC | #12
> -----Original Message-----
> From: Stanislaw Gruszka [mailto:sgruszka@redhat.com]
> Sent: Tuesday, October 02, 2018 6:14 PM
> To: Tony Chuang
> Cc: kvalo@codeaurora.org; Larry.Finger@lwfinger.net;
> linux-wireless@vger.kernel.org; Pkshih; Andy Huang
> Subject: Re: [PATCH 01/12] rtwlan: main files
> 
> Hi
> 
> On Tue, Oct 02, 2018 at 09:35:35AM +0000, Tony Chuang wrote:
> >
> > Hi Kale & Stanislaw,
> >
> > I am working on the driver code and making some changes that Stanislaw
> > have mentioned. And I expected that I will finish them tomorrow, what
> > should I do after I finished them?
> >
> > Should I send an RFCv2, or start a new RFC for it ? Because our driver will
> > be renamed from rtwlan to rtw88 for 8822B/8822C
> 
> I think RFCv2 since this is is second iteration and name change is part
> of it.
> 
> Thanks
> Stanislaw
> 

Can I add you as Reviewed-by in RFCv2 ?
You helped me a lot :)

Thanks
Yan-Hsuan Chuang
Larry Finger Oct. 3, 2018, 5:40 a.m. UTC | #13
On 10/2/18 9:57 PM, Tony Chuang wrote:
> 
> 
>> -----Original Message-----
>> From: Larry Finger [mailto:larry.finger@gmail.com] On Behalf Of Larry Finger
>> Sent: Tuesday, October 02, 2018 11:24 PM
>> To: Stanislaw Gruszka; Tony Chuang
>> Cc: kvalo@codeaurora.org; linux-wireless@vger.kernel.org; Pkshih; Andy
>> Huang
>> Subject: Re: [PATCH 01/12] rtwlan: main files
>>
>> On 10/2/18 5:29 AM, Stanislaw Gruszka wrote:
>>> On Fri, Sep 28, 2018 at 11:32:41AM +0000, Tony Chuang wrote:
>>>>> 	if (rtw_hci_tx(rtwdev, &pkt_info, skb))
>>>>> 		dev_kfree_skb_any(skb)
>>>>>
>>>>> just to remove 'return;' and out label.
>>>>
>>>>
>>>> OK, but why not use ieee80211_free_txskb, should it be better for
>> mac80211?
>>>
>>> Yes, it is better as it also do some extra thing for dropped frame.
>>>
>>>>>> OK, but I think this is needed, our tables have different forms ....
>>>>>
>>>>> Not sure if that is better solution, but could the tables be pre-prarsed
>>>>> by user-space program and then embed in the driver in ready to send
>>>>> to the hardware from ?
>>>>>
>>>>> Also there are lot of redundancy in those tables, for example:
>>>>>
>>>>> +	0x81C, 0xFF000003,
>>>>> +	0x81C, 0xF5000003,
>>>>> +	0x81C, 0xF4020003,
>>>>> +	0x81C, 0xF3040003,
>>>>> +	0x81C, 0xF2060003,
>>>>> +	0x81C, 0xF1080003,
>>>>> +	0x81C, 0xF00A0003,
>>>>> +	0x81C, 0xEF0C0003,
>>>>> +	0x81C, 0xEE0E0003,
>>>>> +	0x81C, 0xED100003,
>>>>> +	0x81C, 0xEC120003,
>>>>> +	0x81C, 0xEB140003,
>>>>> +	0x81C, 0xEA160003,
>>>>> +	0x81C, 0xE9180003,
>>>>> +	0x81C, 0xE81A0003,
>>>>> +	0x81C, 0xE71C0003,
>>>>> +	0x81C, 0xE61E0003,
>>>>> +	0x81C, 0xE5200003,
>>>>>
>>>>> 0x81C and 0003 repeats in many lines.
>>>>>
>>>>> This seems to be parse data, not that we have to write 0x81C
>>>>> register many times. Would be possible to remove the redundancy?
>>>>
>>>>
>>>> No, they cannot be removed, the sequence matters.
>>>> And it is really writing to 0x81C ...
>>>> It is really magic, I cannot believe to this, too.
>>>
>>> This is contradiction for what I asked you before, i.e. doing parsing
>>> in user space, but since we have this parsing mechanism in the driver
>>> perhaps the tables can be coded in some more compact way, for example:
>>>
>>> { prefix, suffix, len, {data} }
>>>
>>> { 0x81C, 0x0003, N ,
>>>     { 0xFF02 , 0xF500 , .... , 0xE520 } }
>>>
>>> The rtw8822b_table.c file is quite big.
>>
>> You might also consider having these tables as a configuration file read from
>> the firmware directory.
>>
> 
> Hi Larry,
> 
> Can we put the configuration file in the firmware directory?
> Should we package them into binary files? Or just put the raw data.
> 
> We can test the performance for it. After we got the result, we will make a decision
> about it. And if we decide to put them in the firmware directory, will send a patch.
> For now, I think we can just leave them in the .c.

Yes, you could put the configuration files in the firmware directory. I would 
put them in binary form, not as text files. That way the size would be smaller, 
and it would not be possible to alter them, particularly if the binary file is 
checksummed.

It would likely be OK if only the agc table was stored in this way. That would 
take away about half of the lines in the 8822b table file.

Larry
Stanislaw Gruszka Oct. 3, 2018, 6:05 a.m. UTC | #14
On Wed, Oct 03, 2018 at 03:25:37AM +0000, Tony Chuang wrote:
> Can I add you as Reviewed-by in RFCv2 ?

Not yet :-) I'm going to review all (v2) patches in detail,
not just first one, but this will take time. I'll post
Reviewed-by tag when done and if I will have no remarks.

> You helped me a lot :)
You welcome ;-)

Thanks
Stanislaw
Kalle Valo Oct. 4, 2018, 12:30 p.m. UTC | #15
Tony Chuang <yhchuang@realtek.com> writes:

> Hi Kale & Stanislaw,
>
> I am working on the driver code and making some changes that Stanislaw
> have mentioned. And I expected that I will finish them tomorrow, what
> should I do after I finished them?
>
> Should I send an RFCv2, or start a new RFC for it ?

Like Stanislaw said, RFCv2 is the right thing to do and I see that you
did that already.

> Because our driver will be renamed from rtwlan to rtw88 for
> 8822B/8822C

I like rtw88, a good choise.
Kalle Valo Oct. 4, 2018, 12:32 p.m. UTC | #16
Stanislaw Gruszka <sgruszka@redhat.com> writes:

> On Thu, Sep 27, 2018 at 10:40:44AM -0500, Larry Finger wrote:
>> On 9/27/18 8:50 AM, Stanislaw Gruszka wrote:
>> --snip
>> 
>> > 
>> > > +#define BIT_LEN_MASK_32(__bitlen) (0xFFFFFFFF >> (32 - (__bitlen)))
>> > > +#define BIT_OFFSET_LEN_MASK_32(__bitoffset, __bitlen)                          \
>> > > +	(BIT_LEN_MASK_32(__bitlen) << (__bitoffset))
>> > > +#define LE_P4BYTE_TO_HOST_4BYTE(__start) (le32_to_cpu(*((__le32 *)(__start))))
>> > > +#define LE_BITS_CLEARED_TO_4BYTE(__start, __bitoffset, __bitlen)               \
>> > > +	(LE_P4BYTE_TO_HOST_4BYTE(__start) &                                    \
>> > > +	 (~BIT_OFFSET_LEN_MASK_32(__bitoffset, __bitlen)))
>> > > +#define LE_BITS_TO_4BYTE(__start, __bitoffset, __bitlen)                       \
>> > > +	((LE_P4BYTE_TO_HOST_4BYTE(__start) >> (__bitoffset)) &                 \
>> > > +	 BIT_LEN_MASK_32(__bitlen))
>> > > +#define SET_BITS_TO_LE_4BYTE(__start, __bitoffset, __bitlen, __value)          \
>> > > +	do {                                                                   \
>> > > +		*((__le32 *)(__start)) = \
>> > > +		cpu_to_le32( \
>> > > +		LE_BITS_CLEARED_TO_4BYTE(__start, __bitoffset, __bitlen) |     \
>> > > +		((((u32)__value) & BIT_LEN_MASK_32(__bitlen)) << (__bitoffset))\
>> > > +		);                                                             \
>> > > +	} while (0)

This is horrible.

>> Stanislaw,
>> 
>> I have never loved these macros, and it took a lot of time to get them to be
>> endian correct. Could you point me to a method that would overwrite a
>> portion of a 32-bit little-endian word that would be correct for both
>> little- and big-endian machines? Keep in mind that Kalle hates the use of
>> compile tests on __LITTLE_ENDIAN.
>
> Maybe something like this (not tested)
>
> #define SET_LE32(reg, off, len, val) \
> 	((reg & cpu_to_le32(~GENMASK(off + len - 1, off))) | cpu_to_le32(val << off))
>
> ?
>
> There are plenty of bitops and endian primitives in kernel, it's
> very very unlikly you need custom macros for handle that.

Indeed, try avoiding reinventing wheel as much as possible.
Kalle Valo Oct. 4, 2018, 12:35 p.m. UTC | #17
Larry Finger <Larry.Finger@lwfinger.net> writes:

> On 10/2/18 5:29 AM, Stanislaw Gruszka wrote:
>> On Fri, Sep 28, 2018 at 11:32:41AM +0000, Tony Chuang wrote:
>>>> 	if (rtw_hci_tx(rtwdev, &pkt_info, skb))
>>>> 		dev_kfree_skb_any(skb)
>>>>
>>>> just to remove 'return;' and out label.
>>>
>>>
>>> OK, but why not use ieee80211_free_txskb, should it be better for mac80211?
>>
>> Yes, it is better as it also do some extra thing for dropped frame.
>>
>>>>> OK, but I think this is needed, our tables have different forms ....
>>>>
>>>> Not sure if that is better solution, but could the tables be pre-prarsed
>>>> by user-space program and then embed in the driver in ready to send
>>>> to the hardware from ?
>>>>
>>>> Also there are lot of redundancy in those tables, for example:
>>>>
>>>> +	0x81C, 0xFF000003,
>>>> +	0x81C, 0xF5000003,
>>>> +	0x81C, 0xF4020003,
>>>> +	0x81C, 0xF3040003,
>>>> +	0x81C, 0xF2060003,
>>>> +	0x81C, 0xF1080003,
>>>> +	0x81C, 0xF00A0003,
>>>> +	0x81C, 0xEF0C0003,
>>>> +	0x81C, 0xEE0E0003,
>>>> +	0x81C, 0xED100003,
>>>> +	0x81C, 0xEC120003,
>>>> +	0x81C, 0xEB140003,
>>>> +	0x81C, 0xEA160003,
>>>> +	0x81C, 0xE9180003,
>>>> +	0x81C, 0xE81A0003,
>>>> +	0x81C, 0xE71C0003,
>>>> +	0x81C, 0xE61E0003,
>>>> +	0x81C, 0xE5200003,
>>>>
>>>> 0x81C and 0003 repeats in many lines.
>>>>
>>>> This seems to be parse data, not that we have to write 0x81C
>>>> register many times. Would be possible to remove the redundancy?
>>>
>>>
>>> No, they cannot be removed, the sequence matters.
>>> And it is really writing to 0x81C ...
>>> It is really magic, I cannot believe to this, too.
>>
>> This is contradiction for what I asked you before, i.e. doing parsing
>> in user space, but since we have this parsing mechanism in the driver
>> perhaps the tables can be coded in some more compact way, for example:
>>
>> { prefix, suffix, len, {data} }
>>
>> { 0x81C, 0x0003, N ,
>>    { 0xFF02 , 0xF500 , .... , 0xE520 } }
>>
>> The rtw8822b_table.c file is quite big.
>
> You might also consider having these tables as a configuration file
> read from the firmware directory.

Configuration files for upstream drivers is something I would like to
avoid until we have a generic solution. That seems to come up now and
then but there does not seem to be any consensus how it should be
implemented.
Kalle Valo Oct. 4, 2018, 12:39 p.m. UTC | #18
Larry Finger <Larry.Finger@lwfinger.net> writes:

> On 10/2/18 9:57 PM, Tony Chuang wrote:
>>
>>
>>> -----Original Message-----
>>> From: Larry Finger [mailto:larry.finger@gmail.com] On Behalf Of Larry Finger
>>> Sent: Tuesday, October 02, 2018 11:24 PM
>>> To: Stanislaw Gruszka; Tony Chuang
>>> Cc: kvalo@codeaurora.org; linux-wireless@vger.kernel.org; Pkshih; Andy
>>> Huang
>>> Subject: Re: [PATCH 01/12] rtwlan: main files
>>>
>>> On 10/2/18 5:29 AM, Stanislaw Gruszka wrote:
>>>> On Fri, Sep 28, 2018 at 11:32:41AM +0000, Tony Chuang wrote:
>>>>>> 	if (rtw_hci_tx(rtwdev, &pkt_info, skb))
>>>>>> 		dev_kfree_skb_any(skb)
>>>>>>
>>>>>> just to remove 'return;' and out label.
>>>>>
>>>>>
>>>>> OK, but why not use ieee80211_free_txskb, should it be better for
>>> mac80211?
>>>>
>>>> Yes, it is better as it also do some extra thing for dropped frame.
>>>>
>>>>>>> OK, but I think this is needed, our tables have different forms ....
>>>>>>
>>>>>> Not sure if that is better solution, but could the tables be pre-prarsed
>>>>>> by user-space program and then embed in the driver in ready to send
>>>>>> to the hardware from ?
>>>>>>
>>>>>> Also there are lot of redundancy in those tables, for example:
>>>>>>
>>>>>> +	0x81C, 0xFF000003,
>>>>>> +	0x81C, 0xF5000003,
>>>>>> +	0x81C, 0xF4020003,
>>>>>> +	0x81C, 0xF3040003,
>>>>>> +	0x81C, 0xF2060003,
>>>>>> +	0x81C, 0xF1080003,
>>>>>> +	0x81C, 0xF00A0003,
>>>>>> +	0x81C, 0xEF0C0003,
>>>>>> +	0x81C, 0xEE0E0003,
>>>>>> +	0x81C, 0xED100003,
>>>>>> +	0x81C, 0xEC120003,
>>>>>> +	0x81C, 0xEB140003,
>>>>>> +	0x81C, 0xEA160003,
>>>>>> +	0x81C, 0xE9180003,
>>>>>> +	0x81C, 0xE81A0003,
>>>>>> +	0x81C, 0xE71C0003,
>>>>>> +	0x81C, 0xE61E0003,
>>>>>> +	0x81C, 0xE5200003,
>>>>>>
>>>>>> 0x81C and 0003 repeats in many lines.
>>>>>>
>>>>>> This seems to be parse data, not that we have to write 0x81C
>>>>>> register many times. Would be possible to remove the redundancy?
>>>>>
>>>>>
>>>>> No, they cannot be removed, the sequence matters.
>>>>> And it is really writing to 0x81C ...
>>>>> It is really magic, I cannot believe to this, too.
>>>>
>>>> This is contradiction for what I asked you before, i.e. doing parsing
>>>> in user space, but since we have this parsing mechanism in the driver
>>>> perhaps the tables can be coded in some more compact way, for example:
>>>>
>>>> { prefix, suffix, len, {data} }
>>>>
>>>> { 0x81C, 0x0003, N ,
>>>>     { 0xFF02 , 0xF500 , .... , 0xE520 } }
>>>>
>>>> The rtw8822b_table.c file is quite big.
>>>
>>> You might also consider having these tables as a configuration file read from
>>> the firmware directory.
>>>
>>
>> Hi Larry,
>>
>> Can we put the configuration file in the firmware directory?
>> Should we package them into binary files? Or just put the raw data.
>>
>> We can test the performance for it. After we got the result, we will make a decision
>> about it. And if we decide to put them in the firmware directory, will send a patch.
>> For now, I think we can just leave them in the .c.
>
> Yes, you could put the configuration files in the firmware directory.
> I would put them in binary form, not as text files. That way the size
> would be smaller, and it would not be possible to alter them,
> particularly if the binary file is checksummed.
>
> It would likely be OK if only the agc table was stored in this way.
> That would take away about half of the lines in the 8822b table file.

So what's the worry here? The lines of source code, binary size or what?

 .../net/wireless/realtek/rtw88/rtw8822b_table.c    | 20783 +++++++++++++++++++

Looking at the diffstat rtw8822b_table.c seems to be 20 kLOC, IMHO it's
not that bad as it's just data. But of course I might be missing
something as I haven't checked patches yet.
Stanislaw Gruszka Oct. 4, 2018, 1:42 p.m. UTC | #19
On Thu, Oct 04, 2018 at 03:39:55PM +0300, Kalle Valo wrote:
> >> Can we put the configuration file in the firmware directory?
> >> Should we package them into binary files? Or just put the raw data.
> >>
> >> We can test the performance for it. After we got the result, we will make a decision
> >> about it. And if we decide to put them in the firmware directory, will send a patch.
> >> For now, I think we can just leave them in the .c.
> >
> > Yes, you could put the configuration files in the firmware directory.
> > I would put them in binary form, not as text files. That way the size
> > would be smaller, and it would not be possible to alter them,
> > particularly if the binary file is checksummed.
> >
> > It would likely be OK if only the agc table was stored in this way.
> > That would take away about half of the lines in the 8822b table file.
> 
> So what's the worry here? The lines of source code, binary size or what?
> 
>  .../net/wireless/realtek/rtw88/rtw8822b_table.c    | 20783 +++++++++++++++++++
> 
> Looking at the diffstat rtw8822b_table.c seems to be 20 kLOC, IMHO it's
> not that bad as it's just data. But of course I might be missing
> something as I haven't checked patches yet.

My concern was it's plenty of redundant data, for example:

        0x81C, 0xFF000003,
        0x81C, 0xFE000003,
        0x81C, 0xFD020003,
        0x81C, 0xFC040003,
        0x81C, 0xFB060003,
        0x81C, 0xFA080003,
        0x81C, 0xF90A0003,
        0x81C, 0xF80C0003,
        0x81C, 0xF70E0003,
        0x81C, 0xF6100003,

Approx 10000 lines like this, braked by lines like this

        0x90000012,     0x00000000,     0x40000000,     0x00000000,

in more or less regular way.

Not big deal, but perhaps this could be coded in much more compact way.

Regards
Stanislaw
Larry Finger Oct. 4, 2018, 4:19 p.m. UTC | #20
On 10/4/18 8:42 AM, Stanislaw Gruszka wrote:
> On Thu, Oct 04, 2018 at 03:39:55PM +0300, Kalle Valo wrote:
>>>> Can we put the configuration file in the firmware directory?
>>>> Should we package them into binary files? Or just put the raw data.
>>>>
>>>> We can test the performance for it. After we got the result, we will make a decision
>>>> about it. And if we decide to put them in the firmware directory, will send a patch.
>>>> For now, I think we can just leave them in the .c.
>>>
>>> Yes, you could put the configuration files in the firmware directory.
>>> I would put them in binary form, not as text files. That way the size
>>> would be smaller, and it would not be possible to alter them,
>>> particularly if the binary file is checksummed.
>>>
>>> It would likely be OK if only the agc table was stored in this way.
>>> That would take away about half of the lines in the 8822b table file.
>>
>> So what's the worry here? The lines of source code, binary size or what?
>>
>>   .../net/wireless/realtek/rtw88/rtw8822b_table.c    | 20783 +++++++++++++++++++
>>
>> Looking at the diffstat rtw8822b_table.c seems to be 20 kLOC, IMHO it's
>> not that bad as it's just data. But of course I might be missing
>> something as I haven't checked patches yet.
> 
> My concern was it's plenty of redundant data, for example:
> 
>          0x81C, 0xFF000003,
>          0x81C, 0xFE000003,
>          0x81C, 0xFD020003,
>          0x81C, 0xFC040003,
>          0x81C, 0xFB060003,
>          0x81C, 0xFA080003,
>          0x81C, 0xF90A0003,
>          0x81C, 0xF80C0003,
>          0x81C, 0xF70E0003,
>          0x81C, 0xF6100003,
> 
> Approx 10000 lines like this, braked by lines like this
> 
>          0x90000012,     0x00000000,     0x40000000,     0x00000000,
> 
> in more or less regular way.
> 
> Not big deal, but perhaps this could be coded in much more compact way.

What should be the tradeoff between large tables of redundant data and 
complicated generation and interpretation? I think this table should be 
converted to binary in its present form and added to the "firmware", the way 
that is done for b43. That way the source is smaller, and the loading will be 
only a bit more time consuming.

Larry
Stanislaw Gruszka Oct. 5, 2018, 7:51 a.m. UTC | #21
On Thu, Oct 04, 2018 at 11:19:59AM -0500, Larry Finger wrote:
> On 10/4/18 8:42 AM, Stanislaw Gruszka wrote:
> >On Thu, Oct 04, 2018 at 03:39:55PM +0300, Kalle Valo wrote:
> >>>>Can we put the configuration file in the firmware directory?
> >>>>Should we package them into binary files? Or just put the raw data.
> >>>>
> >>>>We can test the performance for it. After we got the result, we will make a decision
> >>>>about it. And if we decide to put them in the firmware directory, will send a patch.
> >>>>For now, I think we can just leave them in the .c.
> >>>
> >>>Yes, you could put the configuration files in the firmware directory.
> >>>I would put them in binary form, not as text files. That way the size
> >>>would be smaller, and it would not be possible to alter them,
> >>>particularly if the binary file is checksummed.
> >>>
> >>>It would likely be OK if only the agc table was stored in this way.
> >>>That would take away about half of the lines in the 8822b table file.
> >>
> >>So what's the worry here? The lines of source code, binary size or what?
> >>
> >>  .../net/wireless/realtek/rtw88/rtw8822b_table.c    | 20783 +++++++++++++++++++
> >>
> >>Looking at the diffstat rtw8822b_table.c seems to be 20 kLOC, IMHO it's
> >>not that bad as it's just data. But of course I might be missing
> >>something as I haven't checked patches yet.
> >
> >My concern was it's plenty of redundant data, for example:
> >
> >         0x81C, 0xFF000003,
> >         0x81C, 0xFE000003,
> >         0x81C, 0xFD020003,
> >         0x81C, 0xFC040003,
> >         0x81C, 0xFB060003,
> >         0x81C, 0xFA080003,
> >         0x81C, 0xF90A0003,
> >         0x81C, 0xF80C0003,
> >         0x81C, 0xF70E0003,
> >         0x81C, 0xF6100003,
> >
> >Approx 10000 lines like this, braked by lines like this
> >
> >         0x90000012,     0x00000000,     0x40000000,     0x00000000,
> >
> >in more or less regular way.
> >
> >Not big deal, but perhaps this could be coded in much more compact way.
> 
> What should be the tradeoff between large tables of redundant data
> and complicated generation and interpretation? I think this table
> should be converted to binary in its present form and added to the
> "firmware", the way that is done for b43. That way the source is
> smaller, and the loading will be only a bit more time consuming.

If at stake is bigger data and simpler parsing/processing I would take
that. But processing is already complex (see RTW_DECL_TABLE* and
related functions) and I hope rearranging the data structures could
even lead to simplified processing.

Thanks
Stanislaw
Kalle Valo Oct. 6, 2018, 12:16 p.m. UTC | #22
Stanislaw Gruszka <sgruszka@redhat.com> writes:

> On Thu, Oct 04, 2018 at 03:39:55PM +0300, Kalle Valo wrote:
>> >> Can we put the configuration file in the firmware directory?
>> >> Should we package them into binary files? Or just put the raw data.
>> >>
>> >> We can test the performance for it. After we got the result, we
>> >> will make a decision
>> >> about it. And if we decide to put them in the firmware directory,
>> >> will send a patch.
>> >> For now, I think we can just leave them in the .c.
>> >
>> > Yes, you could put the configuration files in the firmware directory.
>> > I would put them in binary form, not as text files. That way the size
>> > would be smaller, and it would not be possible to alter them,
>> > particularly if the binary file is checksummed.
>> >
>> > It would likely be OK if only the agc table was stored in this way.
>> > That would take away about half of the lines in the 8822b table file.
>> 
>> So what's the worry here? The lines of source code, binary size or what?
>> 
>>  .../net/wireless/realtek/rtw88/rtw8822b_table.c    | 20783 +++++++++++++++++++
>> 
>> Looking at the diffstat rtw8822b_table.c seems to be 20 kLOC, IMHO it's
>> not that bad as it's just data. But of course I might be missing
>> something as I haven't checked patches yet.
>
> My concern was it's plenty of redundant data, for example:
>
>         0x81C, 0xFF000003,
>         0x81C, 0xFE000003,
>         0x81C, 0xFD020003,
>         0x81C, 0xFC040003,
>         0x81C, 0xFB060003,
>         0x81C, 0xFA080003,
>         0x81C, 0xF90A0003,
>         0x81C, 0xF80C0003,
>         0x81C, 0xF70E0003,
>         0x81C, 0xF6100003,
>
> Approx 10000 lines like this, braked by lines like this
>
>         0x90000012,     0x00000000,     0x40000000,     0x00000000,
>
> in more or less regular way.
>
> Not big deal, but perhaps this could be coded in much more compact way.

Sure, making it more compact makes sense to me.

But I don't see that as a strict requirement, that could be done also
after the driver is accepted. Do note that I haven't reviewed the driver
yet so I reserve the right to change my opinion :)
Kalle Valo Oct. 6, 2018, 12:20 p.m. UTC | #23
Larry Finger <Larry.Finger@lwfinger.net> writes:

> On 10/4/18 8:42 AM, Stanislaw Gruszka wrote:
>> On Thu, Oct 04, 2018 at 03:39:55PM +0300, Kalle Valo wrote:
>>>>> Can we put the configuration file in the firmware directory?
>>>>> Should we package them into binary files? Or just put the raw data.
>>>>>
>>>>> We can test the performance for it. After we got the result, we
>>>>> will make a decision
>>>>> about it. And if we decide to put them in the firmware directory,
>>>>> will send a patch.
>>>>> For now, I think we can just leave them in the .c.
>>>>
>>>> Yes, you could put the configuration files in the firmware directory.
>>>> I would put them in binary form, not as text files. That way the size
>>>> would be smaller, and it would not be possible to alter them,
>>>> particularly if the binary file is checksummed.
>>>>
>>>> It would likely be OK if only the agc table was stored in this way.
>>>> That would take away about half of the lines in the 8822b table file.
>>>
>>> So what's the worry here? The lines of source code, binary size or what?
>>>
>>>   .../net/wireless/realtek/rtw88/rtw8822b_table.c    | 20783 +++++++++++++++++++
>>>
>>> Looking at the diffstat rtw8822b_table.c seems to be 20 kLOC, IMHO it's
>>> not that bad as it's just data. But of course I might be missing
>>> something as I haven't checked patches yet.
>>
>> My concern was it's plenty of redundant data, for example:
>>
>>          0x81C, 0xFF000003,
>>          0x81C, 0xFE000003,
>>          0x81C, 0xFD020003,
>>          0x81C, 0xFC040003,
>>          0x81C, 0xFB060003,
>>          0x81C, 0xFA080003,
>>          0x81C, 0xF90A0003,
>>          0x81C, 0xF80C0003,
>>          0x81C, 0xF70E0003,
>>          0x81C, 0xF6100003,
>>
>> Approx 10000 lines like this, braked by lines like this
>>
>>          0x90000012,     0x00000000,     0x40000000,     0x00000000,
>>
>> in more or less regular way.
>>
>> Not big deal, but perhaps this could be coded in much more compact way.
>
> What should be the tradeoff between large tables of redundant data and
> complicated generation and interpretation? I think this table should
> be converted to binary in its present form and added to the
> "firmware", the way that is done for b43. That way the source is
> smaller, and the loading will be only a bit more time consuming.

But separating the data from the driver creates another set of problems.
For example, what if the data is dependent on the driver changes? Then
we need to think about backwards compatibility etc, which creates more
work us. I prefer simple solutions, less work and less problems :)
diff mbox series

Patch

diff --git a/drivers/net/wireless/realtek/rtwlan/mac80211.c b/drivers/net/wireless/realtek/rtwlan/mac80211.c
new file mode 100644
index 0000000..f218341
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtwlan/mac80211.c
@@ -0,0 +1,447 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2018  Realtek Corporation.
+ */
+
+#include "main.h"
+#include "sec.h"
+#include "tx.h"
+#include "fw.h"
+#include "mac.h"
+#include "ps.h"
+#include "reg.h"
+#include "debug.h"
+
+static void rtw_ops_tx(struct ieee80211_hw *hw,
+		       struct ieee80211_tx_control *control,
+		       struct sk_buff *skb)
+{
+	struct rtw_dev *rtwdev = hw->priv;
+	struct rtw_tx_pkt_info pkt_info;
+
+	if (!rtw_flag_check(rtwdev, RTW_FLAG_RUNNING))
+		goto out;
+
+	memset(&pkt_info, 0, sizeof(pkt_info));
+	rtw_tx_pkt_info_update(rtwdev, &pkt_info, control, skb);
+	if (rtw_hci_tx(rtwdev, &pkt_info, skb))
+		goto out;
+
+	return;
+
+out:
+	dev_kfree_skb_any(skb);
+}
+
+static int rtw_ops_start(struct ieee80211_hw *hw)
+{
+	struct rtw_dev *rtwdev = hw->priv;
+
+	return rtw_core_start(rtwdev);
+}
+
+static void rtw_ops_stop(struct ieee80211_hw *hw)
+{
+	struct rtw_dev *rtwdev = hw->priv;
+
+	rtw_core_stop(rtwdev);
+}
+
+static int rtw_ops_config(struct ieee80211_hw *hw, u32 changed)
+{
+	struct rtw_dev *rtwdev = hw->priv;
+	int ret;
+
+	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");
+				return ret;
+			}
+		}
+	}
+
+	if (changed & IEEE80211_CONF_CHANGE_CHANNEL)
+		rtw_set_channel(rtwdev);
+
+	return 0;
+}
+
+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},
+	},
+	[1] = {
+		.mac_addr	= {.addr = 0x0700},
+		.bssid		= {.addr = 0x0708},
+		.net_type	= {.addr = 0x0100, .mask = 0xc0000},
+		.aid		= {.addr = 0x0710, .mask = 0x7ff},
+	},
+	[2] = {
+		.mac_addr	= {.addr = 0x1620},
+		.bssid		= {.addr = 0x1628},
+		.net_type	= {.addr = 0x1100, .mask = 0x3},
+		.aid		= {.addr = 0x1600, .mask = 0x7ff},
+	},
+	[3] = {
+		.mac_addr	= {.addr = 0x1630},
+		.bssid		= {.addr = 0x1638},
+		.net_type	= {.addr = 0x1100, .mask = 0xc},
+		.aid		= {.addr = 0x1604, .mask = 0x7ff},
+	},
+	[4] = {
+		.mac_addr	= {.addr = 0x1640},
+		.bssid		= {.addr = 0x1648},
+		.net_type	= {.addr = 0x1100, .mask = 0x30},
+		.aid		= {.addr = 0x1608, .mask = 0x7ff},
+	},
+};
+
+static int rtw_ops_add_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;
+	enum rtw_net_type net_type;
+	u32 config = 0;
+	u8 port = 0;
+
+	vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
+	rtwvif->port = port;
+	rtwvif->vif = vif;
+	rtwvif->stats.tx_unicast = 0;
+	rtwvif->stats.rx_unicast = 0;
+	rtwvif->stats.tx_cnt = 0;
+	rtwvif->stats.rx_cnt = 0;
+	rtwvif->in_lps = false;
+	list_add(&rtwvif->list, &rtwdev->vif_list);
+	INIT_LIST_HEAD(&rtwvif->sta_list);
+
+	rtwvif->conf = &rtw_vif_port[port];
+
+	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;
+		break;
+	}
+
+	ether_addr_copy(rtwvif->mac_addr, vif->addr);
+	config |= PORT_SET_MAC_ADDR;
+	rtwvif->net_type = net_type;
+	config |= PORT_SET_NET_TYPE;
+	rtw_vif_port_config(rtwdev, rtwvif, config);
+
+	rtw_info(rtwdev, "start vif %pM on port %d", vif->addr, rtwvif->port);
+
+	return 0;
+}
+
+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);
+
+	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(&rtwvif->list);
+}
+
+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);
+
+	if (changed_flags & FIF_ALLMULTI) {
+		if (*new_flags & FIF_ALLMULTI)
+			rtwdev->hal.rcr |= BIT_AM | BIT_AB;
+		else
+			rtwdev->hal.rcr &= ~(BIT_AM | BIT_AB);
+	}
+	if (changed_flags & FIF_FCSFAIL) {
+		if (*new_flags & FIF_FCSFAIL)
+			rtwdev->hal.rcr |= BIT_ACRC32;
+		else
+			rtwdev->hal.rcr &= ~(BIT_ACRC32);
+	}
+	if (changed_flags & FIF_OTHER_BSS) {
+		if (*new_flags & FIF_OTHER_BSS)
+			rtwdev->hal.rcr |= BIT_AAP;
+		else
+			rtwdev->hal.rcr &= ~(BIT_AAP);
+	}
+	if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
+		if (*new_flags & FIF_BCN_PRBRESP_PROMISC)
+			rtwdev->hal.rcr &= ~(BIT_CBSSID_BCN | BIT_CBSSID_DATA);
+		else
+			rtwdev->hal.rcr |= BIT_CBSSID_BCN;
+	}
+
+	rtw_dbg(rtwdev, "config rx filter, changed=0x%08x, new=0x%08x, rcr=0x%08x",
+		changed_flags, *new_flags, rtwdev->hal.rcr);
+
+	rtw_write32(rtwdev, REG_RCR, rtwdev->hal.rcr);
+}
+
+static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw,
+				     struct ieee80211_vif *vif,
+				     struct ieee80211_bss_conf *conf,
+				     u32 changed)
+{
+	struct rtw_dev *rtwdev = hw->priv;
+	struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
+	u32 config = 0;
+
+	if (changed & BSS_CHANGED_ASSOC) {
+		struct rtw_sta_info *ap;
+		struct rtw_chip_info *chip = rtwdev->chip;
+		enum rtw_net_type net_type;
+
+		ap = list_first_entry(&rtwvif->sta_list,
+				      struct rtw_sta_info, list);
+		if (conf->assoc) {
+			net_type = RTW_NET_MGD_LINKED;
+			chip->ops->do_iqk(rtwdev);
+
+			rtwvif->aid = conf->aid;
+			rtw_add_rsvd_page(rtwdev, RSVD_PS_POLL, true);
+			rtw_add_rsvd_page(rtwdev, RSVD_QOS_NULL, true);
+			rtw_add_rsvd_page(rtwdev, RSVD_NULL, true);
+			rtw_fw_download_rsvd_page(rtwdev, vif);
+		} else {
+			net_type = RTW_NET_NO_LINK;
+			rtwvif->aid = 0;
+			rtw_reset_rsvd_page(rtwdev);
+		}
+
+		rtwvif->net_type = net_type;
+		config |= PORT_SET_NET_TYPE;
+		config |= PORT_SET_AID;
+		rtw_fw_media_status_report(rtwdev, ap->mac_id, conf->assoc);
+	}
+
+	if (changed & BSS_CHANGED_BSSID) {
+		ether_addr_copy(rtwvif->bssid, conf->bssid);
+		config |= PORT_SET_BSSID;
+	}
+
+	if (changed & BSS_CHANGED_BEACON)
+		rtw_fw_download_rsvd_page(rtwdev, vif);
+
+	rtw_vif_port_config(rtwdev, rtwvif, config);
+}
+
+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;
+}
+
+static int rtw_ops_sta_add(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;
+	struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
+
+	si->mac_id = rtw_acquire_macid(rtwdev);
+	if (si->mac_id >= RTW_MAX_MAC_ID_NUM)
+		return -ENOSPC;
+
+	si->sta = sta;
+	si->vif = vif;
+	si->init_ra_lv = 1;
+	ewma_rssi_init(&si->avg_rssi);
+
+	rtw_update_sta_info(rtwdev, si);
+
+	list_add_tail(&si->list, &rtwvif->sta_list);
+
+	rtw_info(rtwdev, "sta %pM joined with macid %d", sta->addr, si->mac_id);
+
+	return 0;
+}
+
+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;
+
+	rtw_release_macid(rtwdev, si->mac_id);
+
+	list_del(&si->list);
+
+	rtw_info(rtwdev, "sta %pM with macid %d left", sta->addr, si->mac_id);
+
+	return 0;
+}
+
+static int rtw_ops_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+			   struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+			   struct ieee80211_key_conf *key)
+{
+	struct rtw_dev *rtwdev = hw->priv;
+	struct rtw_sec_desc *sec = &rtwdev->sec;
+	u8 hw_key_type;
+	u8 hw_key_idx;
+	int ret = 0;
+
+	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;
+	}
+
+	mutex_lock(&sec->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;
+	}
+
+	if (hw_key_idx > sec->total_cam_num) {
+		ret = -ENOSPC;
+		goto out;
+	}
+
+	switch (cmd) {
+	case SET_KEY:
+		/* need sw generated IV */
+		key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+		key->hw_key_idx = hw_key_idx;
+		rtw_sec_write_cam(rtwdev, sec, sta, key,
+				  hw_key_type, hw_key_idx);
+		break;
+	case DISABLE_KEY:
+		rtw_sec_clear_cam(rtwdev, sec, key->hw_key_idx);
+		break;
+	}
+
+out:
+	mutex_unlock(&sec->mutex);
+
+	return ret;
+}
+
+static int rtw_ops_ampdu_action(struct ieee80211_hw *hw,
+				struct ieee80211_vif *vif,
+				struct ieee80211_ampdu_params *params)
+{
+	struct ieee80211_sta *sta = params->sta;
+	u16 tid = params->tid;
+
+	switch (params->action) {
+	case IEEE80211_AMPDU_TX_START:
+		ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+		break;
+	case IEEE80211_AMPDU_TX_STOP_CONT:
+	case IEEE80211_AMPDU_TX_STOP_FLUSH:
+	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
+		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+		break;
+	case IEEE80211_AMPDU_TX_OPERATIONAL:
+	case IEEE80211_AMPDU_RX_START:
+	case IEEE80211_AMPDU_RX_STOP:
+		break;
+	default:
+		WARN_ON(1);
+		return -ENOTSUPP;
+	}
+
+	return 0;
+}
+
+static void rtw_ops_sw_scan_start(struct ieee80211_hw *hw,
+				  struct ieee80211_vif *vif,
+				  const u8 *mac_addr)
+{
+	struct rtw_dev *rtwdev = hw->priv;
+	struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
+
+	rtw_leave_lps(rtwdev, rtwvif);
+
+	rtw_flag_set(rtwdev, RTW_FLAG_DIG_DISABLE);
+	rtw_flag_set(rtwdev, RTW_FLAG_SCANNING);
+}
+
+static void rtw_ops_sw_scan_complete(struct ieee80211_hw *hw,
+				     struct ieee80211_vif *vif)
+{
+	struct rtw_dev *rtwdev = hw->priv;
+
+	rtw_flag_clear(rtwdev, RTW_FLAG_SCANNING);
+	rtw_flag_clear(rtwdev, RTW_FLAG_DIG_DISABLE);
+}
+
+const struct ieee80211_ops rtw_ops = {
+	.tx			= rtw_ops_tx,
+	.start			= rtw_ops_start,
+	.stop			= rtw_ops_stop,
+	.config			= rtw_ops_config,
+	.add_interface		= rtw_ops_add_interface,
+	.remove_interface	= rtw_ops_remove_interface,
+	.configure_filter	= rtw_ops_configure_filter,
+	.bss_info_changed	= rtw_ops_bss_info_changed,
+	.sta_add		= rtw_ops_sta_add,
+	.sta_remove		= rtw_ops_sta_remove,
+	.set_key		= rtw_ops_set_key,
+	.ampdu_action		= rtw_ops_ampdu_action,
+	.sw_scan_start		= rtw_ops_sw_scan_start,
+	.sw_scan_complete	= rtw_ops_sw_scan_complete,
+};
+EXPORT_SYMBOL(rtw_ops);
diff --git a/drivers/net/wireless/realtek/rtwlan/main.c b/drivers/net/wireless/realtek/rtwlan/main.c
new file mode 100644
index 0000000..0462a9e
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtwlan/main.c
@@ -0,0 +1,1164 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2018  Realtek Corporation.
+ */
+
+#include "main.h"
+#include "regd.h"
+#include "fw.h"
+#include "ps.h"
+#include "sec.h"
+#include "mac.h"
+#include "phy.h"
+#include "reg.h"
+#include "efuse.h"
+#include "debug.h"
+
+static struct ieee80211_channel rtw_channeltable_2g[] = {
+	{.center_freq = 2412, .hw_value = 1,},
+	{.center_freq = 2417, .hw_value = 2,},
+	{.center_freq = 2422, .hw_value = 3,},
+	{.center_freq = 2427, .hw_value = 4,},
+	{.center_freq = 2432, .hw_value = 5,},
+	{.center_freq = 2437, .hw_value = 6,},
+	{.center_freq = 2442, .hw_value = 7,},
+	{.center_freq = 2447, .hw_value = 8,},
+	{.center_freq = 2452, .hw_value = 9,},
+	{.center_freq = 2457, .hw_value = 10,},
+	{.center_freq = 2462, .hw_value = 11,},
+	{.center_freq = 2467, .hw_value = 12,},
+	{.center_freq = 2472, .hw_value = 13,},
+	{.center_freq = 2484, .hw_value = 14,},
+};
+
+static struct ieee80211_channel rtw_channeltable_5g[] = {
+	{.center_freq = 5180, .hw_value = 36,},
+	{.center_freq = 5200, .hw_value = 40,},
+	{.center_freq = 5220, .hw_value = 44,},
+	{.center_freq = 5240, .hw_value = 48,},
+	{.center_freq = 5260, .hw_value = 52,},
+	{.center_freq = 5280, .hw_value = 56,},
+	{.center_freq = 5300, .hw_value = 60,},
+	{.center_freq = 5320, .hw_value = 64,},
+	{.center_freq = 5500, .hw_value = 100,},
+	{.center_freq = 5520, .hw_value = 104,},
+	{.center_freq = 5540, .hw_value = 108,},
+	{.center_freq = 5560, .hw_value = 112,},
+	{.center_freq = 5580, .hw_value = 116,},
+	{.center_freq = 5600, .hw_value = 120,},
+	{.center_freq = 5620, .hw_value = 124,},
+	{.center_freq = 5640, .hw_value = 128,},
+	{.center_freq = 5660, .hw_value = 132,},
+	{.center_freq = 5680, .hw_value = 136,},
+	{.center_freq = 5700, .hw_value = 140,},
+	{.center_freq = 5745, .hw_value = 149,},
+	{.center_freq = 5765, .hw_value = 153,},
+	{.center_freq = 5785, .hw_value = 157,},
+	{.center_freq = 5805, .hw_value = 161,},
+	{.center_freq = 5825, .hw_value = 165,
+	 .flags = IEEE80211_CHAN_NO_HT40MINUS},
+};
+
+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,},
+};
+
+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},
+};
+
+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},
+};
+
+static struct ieee80211_iface_limit rtw_5port_limits[] = {
+	{ .max = 1, .types = BIT(NL80211_IFTYPE_AP) |
+			     BIT(NL80211_IFTYPE_ADHOC) |
+			     BIT(NL80211_IFTYPE_MESH_POINT), },
+	{ .max = 5, .types = BIT(NL80211_IFTYPE_STATION), },
+};
+
+static struct ieee80211_iface_combination rtw_5port_if_combs[] = {
+	{
+		.limits = rtw_5port_limits,
+		.n_limits = ARRAY_SIZE(rtw_5port_limits),
+		.max_interfaces = 5,
+		.num_different_channels = 1,
+	},
+};
+
+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);
+
+	/* 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;
+	list_for_each_entry(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;
+	}
+
+	if (rtw_flag_check(rtwdev, RTW_FLAG_SCANNING))
+		return;
+
+	rtw_phy_dynamic_mechanism(rtwdev);
+
+	rtwdev->watch_dog_cnt++;
+}
+
+static void rtw_c2h_work(struct work_struct *work)
+{
+	struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, c2h_work);
+	struct sk_buff *skb, *tmp;
+
+	skb_queue_walk_safe(&rtwdev->c2h_queue, skb, tmp) {
+		skb_unlink(skb, &rtwdev->c2h_queue);
+		rtw_fw_c2h_cmd_handle(rtwdev, skb);
+		dev_kfree_skb_any(skb);
+	}
+}
+
+void rtw_get_channel_params(struct cfg80211_chan_def *chandef,
+			    struct rtw_channel_params *chan_params)
+{
+	struct ieee80211_channel *channel = chandef->chan;
+	enum nl80211_chan_width width = chandef->width;
+	u32 primary_freq, center_freq;
+	u8 center_chan;
+	u8 bandwidth = RTW_CHANNEL_WIDTH_20;
+	u8 primary_chan_idx = 0;
+
+	center_chan = channel->hw_value;
+	primary_freq = channel->center_freq;
+	center_freq = chandef->center_freq1;
+
+	switch (width) {
+	case NL80211_CHAN_WIDTH_20_NOHT:
+	case NL80211_CHAN_WIDTH_20:
+		bandwidth = RTW_CHANNEL_WIDTH_20;
+		primary_chan_idx = 0;
+		break;
+	case NL80211_CHAN_WIDTH_40:
+		bandwidth = RTW_CHANNEL_WIDTH_40;
+		if (primary_freq > center_freq) {
+			primary_chan_idx = 1;
+			center_chan -= 2;
+		} else {
+			primary_chan_idx = 2;
+			center_chan += 2;
+		}
+		break;
+	case NL80211_CHAN_WIDTH_80:
+		bandwidth = RTW_CHANNEL_WIDTH_80;
+		if (primary_freq > center_freq) {
+			if (primary_freq - center_freq == 10) {
+				primary_chan_idx = 1;
+				center_chan -= 2;
+			} else {
+				primary_chan_idx = 3;
+				center_chan -= 6;
+			}
+		} else {
+			if (center_freq - primary_freq == 10) {
+				primary_chan_idx = 2;
+				center_chan += 2;
+			} else {
+				primary_chan_idx = 4;
+				center_chan += 6;
+			}
+		}
+		break;
+	default:
+		center_chan = 0;
+		break;
+	}
+
+	chan_params->center_chan = center_chan;
+	chan_params->bandwidth = bandwidth;
+	chan_params->primary_chan_idx = primary_chan_idx;
+}
+
+void rtw_set_channel(struct rtw_dev *rtwdev)
+{
+	struct ieee80211_hw *hw = rtwdev->hw;
+	struct rtw_hal *hal = &rtwdev->hal;
+	struct rtw_chip_info *chip = rtwdev->chip;
+	struct rtw_channel_params ch_param;
+	u8 center_chan, bandwidth, primary_chan_idx;
+
+	rtw_get_channel_params(&hw->conf.chandef, &ch_param);
+	if (WARN(ch_param.center_chan == 0, "Invalid channel"))
+		return;
+
+	center_chan = ch_param.center_chan;
+	bandwidth = ch_param.bandwidth;
+	primary_chan_idx = ch_param.primary_chan_idx;
+
+	hal->current_band_width = bandwidth;
+	hal->current_channel = center_chan;
+	hal->current_band_type = center_chan > 14 ? RTW_BAND_5G : RTW_BAND_2G;
+	chip->ops->set_channel(rtwdev, center_chan, bandwidth, primary_chan_idx);
+
+	rtw_phy_set_tx_power_level(rtwdev, center_chan);
+}
+
+static void rtw_vif_write_addr(struct rtw_dev *rtwdev, u32 start, u8 *addr)
+{
+	int i;
+
+	for (i = 0; i < ETH_ALEN; i++)
+		rtw_write8(rtwdev, start + i, addr[i]);
+}
+
+void rtw_vif_port_config(struct rtw_dev *rtwdev,
+			 struct rtw_vif *rtwvif,
+			 u32 config)
+{
+	u32 addr, mask;
+
+	if (config & PORT_SET_MAC_ADDR) {
+		addr = rtwvif->conf->mac_addr.addr;
+		rtw_vif_write_addr(rtwdev, addr, rtwvif->mac_addr);
+	}
+	if (config & PORT_SET_BSSID) {
+		addr = rtwvif->conf->bssid.addr;
+		rtw_vif_write_addr(rtwdev, addr, rtwvif->bssid);
+	}
+	if (config & PORT_SET_NET_TYPE) {
+		addr = rtwvif->conf->net_type.addr;
+		mask = rtwvif->conf->net_type.mask;
+		rtw_write32_mask(rtwdev, addr, mask, rtwvif->net_type);
+	}
+	if (config & PORT_SET_AID) {
+		addr = rtwvif->conf->aid.addr;
+		mask = rtwvif->conf->aid.mask;
+		rtw_write32_mask(rtwdev, addr, mask, rtwvif->aid);
+	}
+}
+
+static u8 hw_bw_cap_to_bitamp(u8 bw_cap)
+{
+	u8 bw = 0;
+
+	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 */
+	default:
+		bw |= BIT(RTW_CHANNEL_WIDTH_20);
+		break;
+	}
+
+	return bw;
+}
+
+static void rtw_hw_config_rf_ant_num(struct rtw_dev *rtwdev, u8 hw_ant_num)
+{
+	struct rtw_hal *hal = &rtwdev->hal;
+
+	if (hw_ant_num == EFUSE_HW_CAP_IGNORE ||
+	    hw_ant_num >= hal->rf_path_num)
+		return;
+
+	switch (hw_ant_num) {
+	case 1:
+		hal->rf_type = RF_1T1R;
+		hal->rf_path_num = 1;
+		hal->antenna_tx = BB_PATH_A;
+		hal->antenna_rx = BB_PATH_A;
+		break;
+	default:
+		WARN(1, "invalid hw configuration from efuse");
+		break;
+	}
+}
+
+static u64 get_vht_ra_mask(struct ieee80211_sta *sta)
+{
+	u64 ra_mask = 0;
+	u16 mcs_map = le16_to_cpu(sta->vht_cap.vht_mcs.rx_mcs_map);
+	u8 vht_mcs_cap;
+	int i, nss;
+
+	/* 4SS, every two bits for MCS7/8/9 */
+	for (i = 0, nss = 12; i < 4; i++, mcs_map >>= 2, nss += 10) {
+		vht_mcs_cap = mcs_map & 0x3;
+		switch (vht_mcs_cap) {
+		case 2: /* MCS9 */
+			ra_mask |= 0x3ff << nss;
+			break;
+		case 1: /* MCS8 */
+			ra_mask |= 0x1ff << nss;
+			break;
+		case 0: /* MCS7 */
+			ra_mask |= 0x0ff << nss;
+			break;
+		default:
+			break;
+		}
+	}
+
+	return ra_mask;
+}
+
+static u8 get_rate_id(u8 wireless_set, enum rtw_bandwidth bw_mode, u8 tx_num)
+{
+	u8 rate_id = 0;
+
+	switch (wireless_set) {
+	case WIRELESS_CCK:
+		rate_id = RTW_RATEID_B_20M;
+		break;
+	case WIRELESS_OFDM:
+		rate_id = RTW_RATEID_G;
+		break;
+	case WIRELESS_CCK | WIRELESS_OFDM:
+		rate_id = RTW_RATEID_BG;
+		break;
+	case WIRELESS_OFDM | WIRELESS_HT:
+		if (tx_num == 1)
+			rate_id = RTW_RATEID_GN_N1SS;
+		else if (tx_num == 2)
+			rate_id = RTW_RATEID_GN_N2SS;
+		else if (tx_num == 3)
+			rate_id = RTW_RATEID_ARFR5_N_3SS;
+		break;
+	case WIRELESS_CCK | WIRELESS_OFDM | WIRELESS_HT:
+		if (bw_mode == RTW_CHANNEL_WIDTH_40) {
+			if (tx_num == 1)
+				rate_id = RTW_RATEID_BGN_40M_1SS;
+			else if (tx_num == 2)
+				rate_id = RTW_RATEID_BGN_40M_2SS;
+			else if (tx_num == 3)
+				rate_id = RTW_RATEID_ARFR5_N_3SS;
+			else if (tx_num == 4)
+				rate_id = RTW_RATEID_ARFR7_N_4SS;
+		} else {
+			if (tx_num == 1)
+				rate_id = RTW_RATEID_BGN_20M_1SS;
+			else if (tx_num == 2)
+				rate_id = RTW_RATEID_BGN_20M_2SS;
+			else if (tx_num == 3)
+				rate_id = RTW_RATEID_ARFR5_N_3SS;
+			else if (tx_num == 4)
+				rate_id = RTW_RATEID_ARFR7_N_4SS;
+		}
+		break;
+	case WIRELESS_OFDM | WIRELESS_VHT:
+		if (tx_num == 1)
+			rate_id = RTW_RATEID_ARFR1_AC_1SS;
+		else if (tx_num == 2)
+			rate_id = RTW_RATEID_ARFR0_AC_2SS;
+		else if (tx_num == 3)
+			rate_id = RTW_RATEID_ARFR4_AC_3SS;
+		else if (tx_num == 4)
+			rate_id = RTW_RATEID_ARFR6_AC_4SS;
+		break;
+	case WIRELESS_CCK | WIRELESS_OFDM | WIRELESS_VHT:
+		if (bw_mode >= RTW_CHANNEL_WIDTH_80) {
+			if (tx_num == 1)
+				rate_id = RTW_RATEID_ARFR1_AC_1SS;
+			else if (tx_num == 2)
+				rate_id = RTW_RATEID_ARFR0_AC_2SS;
+			else if (tx_num == 3)
+				rate_id = RTW_RATEID_ARFR4_AC_3SS;
+			else if (tx_num == 4)
+				rate_id = RTW_RATEID_ARFR6_AC_4SS;
+		} else {
+			if (tx_num == 1)
+				rate_id = RTW_RATEID_ARFR2_AC_2G_1SS;
+			else if (tx_num == 2)
+				rate_id = RTW_RATEID_ARFR3_AC_2G_2SS;
+			else if (tx_num == 3)
+				rate_id = RTW_RATEID_ARFR4_AC_3SS;
+			else if (tx_num == 4)
+				rate_id = RTW_RATEID_ARFR6_AC_4SS;
+		}
+		break;
+	default:
+		break;
+	}
+
+	return rate_id;
+}
+
+#define RA_MASK_CCK_RATES	0x0000f
+#define RA_MASK_OFDM_RATES	0x00ff0
+#define RA_MASK_HT_RATES_1SS	(0xff000 << 0)
+#define RA_MASK_HT_RATES_2SS	(0xff000 << 8)
+#define RA_MASK_HT_RATES_3SS	(0xff000 << 16)
+#define RA_MASK_HT_RATES	(RA_MASK_HT_RATES_1SS | \
+				 RA_MASK_HT_RATES_2SS | \
+				 RA_MASK_HT_RATES_3SS)
+#define RA_MASK_VHT_RATES_1SS	(0x3ff000 << 0)
+#define RA_MASK_VHT_RATES_2SS	(0x3ff000 << 10)
+#define RA_MASK_VHT_RATES_3SS	(0x3ff000 << 20)
+#define RA_MASK_VHT_RATES	(RA_MASK_VHT_RATES_1SS | \
+				 RA_MASK_VHT_RATES_2SS | \
+				 RA_MASK_VHT_RATES_3SS)
+#define RA_MASK_CCK_IN_HT	0x00005
+#define RA_MASK_CCK_IN_VHT	0x00005
+#define RA_MASK_OFDM_IN_VHT	0x00010
+#define RA_MASK_OFDM_IN_HT_2G	0x00010
+#define RA_MASK_OFDM_IN_HT_5G	0x00030
+
+void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si)
+{
+	struct ieee80211_sta *sta = si->sta;
+	struct rtw_efuse *efuse = &rtwdev->efuse;
+	struct rtw_hal *hal = &rtwdev->hal;
+	u8 rssi_level;
+	u8 wireless_set;
+	u8 bw_mode;
+	u8 rate_id;
+	u8 rf_type = RF_1T1R;
+	u8 stbc_en = 0;
+	u8 ldpc_en = 0;
+	u8 tx_num = 1;
+	u64 ra_mask = 0;
+	bool is_vht_enable = false;
+	bool is_support_sgi = false;
+
+	if (sta->vht_cap.vht_supported) {
+		is_vht_enable = true;
+		ra_mask |= get_vht_ra_mask(sta);
+		if (sta->vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK)
+			stbc_en = VHT_STBC_EN;
+		if (sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC)
+			ldpc_en = VHT_LDPC_EN;
+		if (sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80)
+			is_support_sgi = true;
+	} else if (sta->ht_cap.ht_supported) {
+		ra_mask |= (sta->ht_cap.mcs.rx_mask[NL80211_BAND_5GHZ] << 20) |
+			   (sta->ht_cap.mcs.rx_mask[NL80211_BAND_2GHZ] << 12);
+		if (sta->ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)
+			stbc_en = HT_STBC_EN;
+		if (sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING)
+			ldpc_en = HT_LDPC_EN;
+		if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20 ||
+		    sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40)
+			is_support_sgi = true;
+	}
+
+	if (hal->current_band_type == RTW_BAND_5G) {
+		ra_mask |= (u64)sta->supp_rates[NL80211_BAND_5GHZ] << 4;
+		if (sta->vht_cap.vht_supported) {
+			ra_mask &= RA_MASK_VHT_RATES | RA_MASK_OFDM_IN_VHT;
+			wireless_set = WIRELESS_OFDM | WIRELESS_VHT;
+		} else if (sta->ht_cap.ht_supported) {
+			ra_mask &= RA_MASK_HT_RATES | RA_MASK_OFDM_IN_HT_5G;
+			wireless_set = WIRELESS_OFDM | WIRELESS_HT;
+		} else {
+			wireless_set = WIRELESS_OFDM;
+		}
+	} else if (hal->current_band_type == RTW_BAND_2G) {
+		ra_mask |= sta->supp_rates[NL80211_BAND_2GHZ];
+		if (sta->vht_cap.vht_supported) {
+			ra_mask &= RA_MASK_VHT_RATES | RA_MASK_CCK_IN_VHT |
+				   RA_MASK_OFDM_IN_VHT;
+			wireless_set = WIRELESS_CCK | WIRELESS_OFDM |
+				       WIRELESS_HT | WIRELESS_VHT;
+		} else if (sta->ht_cap.ht_supported) {
+			ra_mask &= RA_MASK_HT_RATES | RA_MASK_CCK_IN_HT |
+				   RA_MASK_OFDM_IN_HT_2G;
+			wireless_set = WIRELESS_CCK | WIRELESS_OFDM |
+				       WIRELESS_HT;
+		} else if (sta->supp_rates[0] <= 0xf) {
+			wireless_set = WIRELESS_CCK;
+		} else {
+			wireless_set = WIRELESS_CCK | WIRELESS_OFDM;
+		}
+	} else {
+		pr_err("Unknown band type\n");
+		wireless_set = 0;
+	}
+
+	if (efuse->hw_cap.nss == 1) {
+		ra_mask &= RA_MASK_VHT_RATES_1SS;
+		ra_mask &= RA_MASK_HT_RATES_1SS;
+	}
+
+	switch (sta->bandwidth) {
+	case IEEE80211_STA_RX_BW_80:
+		bw_mode = RTW_CHANNEL_WIDTH_80;
+		break;
+	case IEEE80211_STA_RX_BW_40:
+		bw_mode = RTW_CHANNEL_WIDTH_40;
+		break;
+	default:
+		bw_mode = RTW_CHANNEL_WIDTH_20;
+		break;
+	}
+
+	if (sta->vht_cap.vht_supported && ra_mask & 0xffc00000) {
+		tx_num = 2;
+		rf_type = RF_2T2R;
+	} else if (sta->ht_cap.ht_supported && ra_mask & 0xfff00000) {
+		tx_num = 2;
+		rf_type = RF_2T2R;
+	}
+
+	rate_id = get_rate_id(wireless_set, bw_mode, tx_num);
+
+	if (wireless_set != WIRELESS_CCK) {
+		rssi_level = si->rssi_level;
+		if (rssi_level == 0)
+			ra_mask &= 0xffffffffffffffffULL;
+		else if (rssi_level == 1)
+			ra_mask &= 0xfffffffffffffff0ULL;
+		else if (rssi_level == 2)
+			ra_mask &= 0xffffffffffffefe0ULL;
+		else if (rssi_level == 3)
+			ra_mask &= 0xffffffffffffcfc0ULL;
+		else if (rssi_level == 4)
+			ra_mask &= 0xffffffffffff8f80ULL;
+		else if (rssi_level >= 5)
+			ra_mask &= 0xffffffffffff0f00ULL;
+	}
+
+	si->bw_mode = bw_mode;
+	si->stbc_en = stbc_en;
+	si->ldpc_en = ldpc_en;
+	si->rf_type = rf_type;
+	si->wireless_set = wireless_set;
+	si->sgi_enable = is_support_sgi;
+	si->vht_enable = is_vht_enable;
+	si->ra_mask = ra_mask;
+	si->rate_id = rate_id;
+
+	rtw_fw_send_ra_info(rtwdev, si);
+}
+
+static int rtw_power_on(struct rtw_dev *rtwdev)
+{
+	struct rtw_chip_info *chip = rtwdev->chip;
+	struct rtw_fw_state *fw = &rtwdev->fw;
+	int ret;
+
+	ret = rtw_hci_setup(rtwdev);
+	if (ret) {
+		rtw_err(rtwdev, "failed to setup hci\n");
+		goto err;
+	}
+
+	/* power on MAC before firmware downloaded */
+	ret = rtw_mac_power_on(rtwdev);
+	if (ret) {
+		rtw_err(rtwdev, "failed to power on mac\n");
+		goto err;
+	}
+
+	ret = rtw_download_firmware(rtwdev, fw->data, fw->size);
+	if (ret) {
+		rtw_err(rtwdev, "failed to download firmware\n");
+		goto err_off;
+	}
+
+	/* config mac after firmware downloaded */
+	ret = rtw_mac_init(rtwdev);
+	if (ret) {
+		rtw_err(rtwdev, "failed to configure mac\n");
+		goto err_off;
+	}
+
+	chip->ops->phy_set_param(rtwdev);
+
+	ret = rtw_hci_start(rtwdev);
+	if (ret) {
+		rtw_err(rtwdev, "failed to start hci\n");
+		goto err_off;
+	}
+
+	return 0;
+
+err_off:
+	rtw_mac_power_off(rtwdev);
+
+err:
+	return ret;
+}
+
+int rtw_core_start(struct rtw_dev *rtwdev)
+{
+	int ret;
+
+	ret = rtw_power_on(rtwdev);
+	if (ret)
+		return ret;
+
+	rtwdev->hal.last_box_num = 0;
+
+	rtw_sec_enable_sec_engine(rtwdev);
+
+	/* rcr reset after powered on */
+	rtw_write32(rtwdev, REG_RCR, rtwdev->hal.rcr);
+
+	ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->watch_dog_work,
+				     RTW_WATCH_DOG_DELAY_TIME);
+
+	rtw_flag_set(rtwdev, RTW_FLAG_RUNNING);
+
+	return 0;
+}
+
+static void rtw_power_off(struct rtw_dev *rtwdev)
+{
+	rtwdev->hci.ops->stop(rtwdev);
+	rtw_mac_power_off(rtwdev);
+}
+
+void rtw_core_stop(struct rtw_dev *rtwdev)
+{
+	rtw_flag_clear(rtwdev, RTW_FLAG_RUNNING);
+	rtw_flag_clear(rtwdev, RTW_FLAG_FW_RUNNING);
+
+	cancel_delayed_work_sync(&rtwdev->watch_dog_work);
+
+	rtw_power_off(rtwdev);
+}
+
+static void rtw_init_ht_cap(struct rtw_dev *rtwdev,
+			    struct ieee80211_sta_ht_cap *ht_cap)
+{
+	struct rtw_efuse *efuse = &rtwdev->efuse;
+
+	ht_cap->ht_supported = true;
+	ht_cap->cap = 0;
+	ht_cap->cap |= IEEE80211_HT_CAP_SGI_20 |
+			IEEE80211_HT_CAP_MAX_AMSDU |
+			IEEE80211_HT_CAP_LDPC_CODING |
+			(1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
+	if (efuse->hw_cap.bw & BIT(RTW_CHANNEL_WIDTH_40))
+		ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
+				IEEE80211_HT_CAP_DSSSCCK40 |
+				IEEE80211_HT_CAP_SGI_40;
+	ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
+	ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
+	ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+	if (efuse->hw_cap.nss > 1) {
+		ht_cap->mcs.rx_mask[0] = 0xFF;
+		ht_cap->mcs.rx_mask[1] = 0xFF;
+		ht_cap->mcs.rx_mask[4] = 0x01;
+		ht_cap->mcs.rx_highest = cpu_to_le16(300);
+	} else {
+		ht_cap->mcs.rx_mask[0] = 0xFF;
+		ht_cap->mcs.rx_mask[1] = 0x00;
+		ht_cap->mcs.rx_mask[4] = 0x01;
+		ht_cap->mcs.rx_highest = cpu_to_le16(150);
+	}
+}
+
+static void rtw_init_vht_cap(struct rtw_dev *rtwdev,
+			     struct ieee80211_sta_vht_cap *vht_cap)
+{
+	struct rtw_efuse *efuse = &rtwdev->efuse;
+	u16 mcs_map;
+	__le16 highest;
+
+	if (efuse->hw_cap.ptcl != EFUSE_HW_CAP_IGNORE &&
+	    efuse->hw_cap.ptcl != EFUSE_HW_CAP_PTCL_VHT)
+		return;
+
+	vht_cap->vht_supported = true;
+	vht_cap->cap = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
+		       IEEE80211_VHT_CAP_RXLDPC |
+		       IEEE80211_VHT_CAP_SHORT_GI_80 |
+		       IEEE80211_VHT_CAP_TXSTBC |
+		       IEEE80211_VHT_CAP_RXSTBC_1 |
+		       IEEE80211_VHT_CAP_HTC_VHT |
+		       IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK |
+		       0;
+	mcs_map = IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 |
+		  IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 |
+		  IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 |
+		  IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 |
+		  IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 |
+		  IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 |
+		  IEEE80211_VHT_MCS_NOT_SUPPORTED << 14;
+	if (efuse->hw_cap.nss > 1) {
+		highest = cpu_to_le16(780);
+		mcs_map |= IEEE80211_VHT_MCS_SUPPORT_0_9 << 2;
+	} else {
+		highest = cpu_to_le16(390);
+		mcs_map |= IEEE80211_VHT_MCS_NOT_SUPPORTED << 2;
+	}
+
+	vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
+	vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
+	vht_cap->vht_mcs.rx_highest = highest;
+	vht_cap->vht_mcs.tx_highest = highest;
+}
+
+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));
+		if (chip->ht_supported)
+			rtw_init_ht_cap(rtwdev, &sband->ht_cap);
+		hw->wiphy->bands[NL80211_BAND_2GHZ] = sband;
+	}
+
+	if (chip->band & RTW_BAND_5G) {
+		sband = kmalloc(sizeof(*sband), GFP_KERNEL);
+		memcpy(sband, &rtw_band_5ghz, sizeof(rtw_band_5ghz));
+		if (chip->ht_supported)
+			rtw_init_ht_cap(rtwdev, &sband->ht_cap);
+		if (chip->vht_supported)
+			rtw_init_vht_cap(rtwdev, &sband->vht_cap);
+		hw->wiphy->bands[NL80211_BAND_5GHZ] = sband;
+	}
+}
+
+static void rtw_unset_supported_band(struct ieee80211_hw *hw,
+				     struct rtw_chip_info *chip)
+{
+	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]);
+}
+
+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);
+	if (ret) {
+		rtw_err(rtwdev, "failed to request firmware\n");
+		return ret;
+	}
+
+	fw->firmware = firmware;
+	fw->data = firmware->data;
+	fw->size = firmware->size;
+
+	return 0;
+}
+
+static int rtw_chip_parameter_setup(struct rtw_dev *rtwdev)
+{
+	struct rtw_chip_info *chip = rtwdev->chip;
+	struct rtw_hal *hal = &rtwdev->hal;
+	struct rtw_efuse *efuse = &rtwdev->efuse;
+	u32 wl_bt_pwr_ctrl;
+	int ret = 0;
+
+	switch (rtw_hci_type(rtwdev)) {
+	case RTW_HCI_TYPE_PCIE:
+		rtwdev->hci.rpwm_addr = 0x03d9;
+		break;
+	default:
+		rtw_err(rtwdev, "unsupported hci type");
+		return -EINVAL;
+	}
+
+	wl_bt_pwr_ctrl = rtw_read32(rtwdev, REG_WL_BT_PWR_CTRL);
+	if (wl_bt_pwr_ctrl & BIT_BT_FUNC_EN)
+		rtwdev->efuse.btcoex = true;
+	hal->chip_version = rtw_read32(rtwdev, REG_SYS_CFG1);
+	hal->fab_version = BIT_GET_VENDOR_ID(hal->chip_version) >> 2;
+	hal->cut_version = BIT_GET_CHIP_VER(hal->chip_version);
+	hal->mp_chip = (hal->chip_version & BIT_RTL_ID) ? 0 : 1;
+	if (hal->chip_version & BIT_RF_TYPE_ID) {
+		hal->rf_type = RF_2T2R;
+		hal->rf_path_num = 2;
+		hal->antenna_tx = BB_PATH_AB;
+		hal->antenna_rx = BB_PATH_AB;
+	} else {
+		hal->rf_type = RF_1T1R;
+		hal->rf_path_num = 1;
+		hal->antenna_tx = BB_PATH_A;
+		hal->antenna_rx = BB_PATH_A;
+	}
+
+	if (hal->fab_version == 2)
+		hal->fab_version = 1;
+	else if (hal->fab_version == 1)
+		hal->fab_version = 2;
+
+	efuse->physical_size = chip->phy_efuse_size;
+	efuse->logical_size = chip->log_efuse_size;
+	efuse->protect_size = chip->ptct_efuse_size;
+
+	/* default use ack */
+	rtwdev->hal.rcr |= BIT_VHT_DACK;
+
+	return ret;
+}
+
+static int rtw_chip_efuse_enable(struct rtw_dev *rtwdev)
+{
+	struct rtw_fw_state *fw = &rtwdev->fw;
+	int ret;
+
+	ret = rtw_hci_setup(rtwdev);
+	if (ret) {
+		rtw_err(rtwdev, "failed to setup hci\n");
+		goto err;
+	}
+
+	ret = rtw_mac_power_on(rtwdev);
+	if (ret) {
+		rtw_err(rtwdev, "failed to power on mac\n");
+		goto err;
+	}
+
+	rtw_write8(rtwdev, REG_C2HEVT, C2H_HW_FEATURE_DUMP);
+	ret = rtw_download_firmware(rtwdev, fw->data, fw->size);
+	if (ret) {
+		rtw_err(rtwdev, "failed to download firmware\n");
+		goto err_off;
+	}
+
+	/* config mac after firmware downloaded */
+	ret = rtw_mac_init(rtwdev);
+	if (ret) {
+		rtw_err(rtwdev, "failed to configure mac\n");
+		goto err_off;
+	}
+
+	ret = rtw_hci_start(rtwdev);
+	if (ret) {
+		rtw_err(rtwdev, "failed to start hci\n");
+		goto err_off;
+	}
+
+	return 0;
+
+err_off:
+	rtw_mac_power_off(rtwdev);
+
+err:
+	return ret;
+}
+
+static int rtw_dump_hw_feature(struct rtw_dev *rtwdev)
+{
+	struct rtw_efuse *efuse = &rtwdev->efuse;
+	struct efuse_hw_cap *hw_cap;
+	u8 hw_feature[HW_FEATURE_LEN];
+	u8 id;
+	int i;
+
+	BUILD_BUG_ON(sizeof(*hw_cap) != HW_FEATURE_LEN);
+
+	id = rtw_read8(rtwdev, REG_C2HEVT);
+	if (id != C2H_HW_FEATURE_REPORT) {
+		rtw_err(rtwdev, "failed to read hw feature report\n");
+		return -EBUSY;
+	}
+
+	for (i = 0; i < HW_FEATURE_LEN; i++)
+		hw_feature[i] = rtw_read8(rtwdev, REG_C2HEVT + 2 + i);
+
+	rtw_write8(rtwdev, REG_C2HEVT, 0);
+
+	hw_cap = (struct efuse_hw_cap *)hw_feature;
+
+	efuse->hw_cap.bw = hw_bw_cap_to_bitamp(hw_cap->bw);
+	efuse->hw_cap.hci = hw_cap->hci;
+	efuse->hw_cap.nss = hw_cap->nss;
+	efuse->hw_cap.ptcl = hw_cap->ptcl;
+	efuse->hw_cap.ant_num = hw_cap->ant_num;
+
+	rtw_hw_config_rf_ant_num(rtwdev, efuse->hw_cap.ant_num);
+
+	if (efuse->hw_cap.nss == EFUSE_HW_CAP_IGNORE)
+		efuse->hw_cap.nss = rtwdev->hal.rf_path_num;
+
+	rtw_dbg(rtwdev, "hw cap: hci=0x%02x, bw=0x%02x, ptcl=0x%02x, ant_num=%d, nss=%d",
+		efuse->hw_cap.hci, efuse->hw_cap.bw, efuse->hw_cap.ptcl,
+		efuse->hw_cap.ant_num, efuse->hw_cap.nss);
+
+	return 0;
+}
+
+static void rtw_chip_efuse_disable(struct rtw_dev *rtwdev)
+{
+	rtw_hci_stop(rtwdev);
+	rtw_mac_power_off(rtwdev);
+}
+
+static int rtw_chip_efuse_info_setup(struct rtw_dev *rtwdev)
+{
+	struct rtw_efuse *efuse = &rtwdev->efuse;
+	int ret;
+
+	/* power on mac to read efuse */
+	ret = rtw_chip_efuse_enable(rtwdev);
+	if (ret)
+		return ret;
+
+	ret = rtw_parse_efuse_map(rtwdev);
+	if (ret)
+		return ret;
+
+	ret = rtw_dump_hw_feature(rtwdev);
+	if (ret)
+		return ret;
+
+	ret = rtw_check_supported_rfe(rtwdev);
+	if (ret)
+		return ret;
+
+	if (efuse->crystal_cap == 0xff)
+		efuse->crystal_cap = 0;
+	if (efuse->pa_type_2g == 0xff)
+		efuse->pa_type_2g = 0;
+	if (efuse->pa_type_5g == 0xff)
+		efuse->pa_type_5g = 0;
+	if (efuse->lna_type_2g == 0xff)
+		efuse->lna_type_2g = 0;
+	if (efuse->lna_type_5g == 0xff)
+		efuse->lna_type_5g = 0;
+	if (efuse->channel_plan == 0xff)
+		efuse->channel_plan = 0x7f;
+	if (efuse->bt_setting & BIT(0))
+		efuse->share_ant = true;
+	if (efuse->regd == 0xff)
+		efuse->regd = 0;
+
+	efuse->ext_pa_2g = efuse->pa_type_2g & BIT(4) ? 1 : 0;
+	efuse->ext_lna_2g = efuse->lna_type_2g & BIT(3) ? 1 : 0;
+	efuse->ext_pa_5g = efuse->pa_type_5g & BIT(0) ? 1 : 0;
+	efuse->ext_lna_2g = efuse->lna_type_5g & BIT(3) ? 1 : 0;
+
+	rtw_chip_efuse_disable(rtwdev);
+
+	return 0;
+}
+
+static int rtw_chip_board_info_setup(struct rtw_dev *rtwdev)
+{
+	struct rtw_hal *hal = &rtwdev->hal;
+	const struct rtw_rfe_def *rfe_def = rtw_get_rfe_def(rtwdev);
+
+	if (!rfe_def)
+		return -ENODEV;
+
+	rtw_phy_setup_phy_cond(rtwdev, 0);
+
+	rtw_hw_init_tx_power(hal);
+	if (rtwdev->chip->id != RTW_CHIP_TYPE_8822C)
+		rtw_load_table(rtwdev, rfe_def->phy_pg_tbl);
+	rtw_load_table(rtwdev, rfe_def->txpwr_lmt_tbl);
+	rtw_phy_tx_power_by_rate_config(hal);
+	rtw_phy_tx_power_limit_config(hal);
+
+	return 0;
+}
+
+int rtw_chip_info_setup(struct rtw_dev *rtwdev)
+{
+	int ret;
+
+	ret = rtw_chip_parameter_setup(rtwdev);
+	if (ret) {
+		rtw_err(rtwdev, "failed to setup chip parameters\n");
+		goto err_out;
+	}
+
+	ret = rtw_chip_efuse_info_setup(rtwdev);
+	if (ret) {
+		rtw_err(rtwdev, "failed to setup chip efuse info\n");
+		goto err_out;
+	}
+
+	ret = rtw_chip_board_info_setup(rtwdev);
+	if (ret) {
+		rtw_err(rtwdev, "failed to setup chip board info\n");
+		goto err_out;
+	}
+
+	return 0;
+
+err_out:
+	return ret;
+}
+EXPORT_SYMBOL(rtw_chip_info_setup);
+
+int rtw_core_init(struct rtw_dev *rtwdev)
+{
+	int ret;
+
+	INIT_LIST_HEAD(&rtwdev->vif_list);
+	INIT_LIST_HEAD(&rtwdev->rsvd_page_list);
+	rtw_add_rsvd_page(rtwdev, RSVD_BEACON, false);
+
+	INIT_DELAYED_WORK(&rtwdev->watch_dog_work, rtw_watch_dog_work);
+	INIT_DELAYED_WORK(&rtwdev->lps_work, rtw_lps_work);
+	INIT_WORK(&rtwdev->c2h_work, rtw_c2h_work);
+	skb_queue_head_init(&rtwdev->c2h_queue);
+
+	spin_lock_init(&rtwdev->dm_lock);
+	spin_lock_init(&rtwdev->rf_lock);
+
+	mutex_init(&rtwdev->sec.mutex);
+	mutex_init(&rtwdev->hal.h2c_mutex);
+	mutex_init(&rtwdev->hal.tx_power_mutex);
+	mutex_init(&rtwdev->efuse.mutex);
+	rtwdev->sec.total_cam_num = 32;
+	rtwdev->macid_used[RTW_BC_MC_MACID] = true;
+
+	/* default rx filter setting */
+	rtwdev->hal.rcr = BIT_APP_FCS | BIT_APP_MIC | BIT_APP_ICV |
+			  BIT_HTC_LOC_CTRL | BIT_APP_PHYSTS |
+			  BIT_AB | BIT_AM | BIT_APM;
+
+	ret = rtw_load_firmware(rtwdev, rtwdev->chip->fw_name);
+	if (ret) {
+		rtw_warn(rtwdev, "no firmware loaded");
+		return ret;
+	}
+
+	rtw_debugfs_init(rtwdev);
+
+	return 0;
+}
+EXPORT_SYMBOL(rtw_core_init);
+
+void rtw_core_deinit(struct rtw_dev *rtwdev)
+{
+	struct rtw_fw_state *fw = &rtwdev->fw;
+	struct rtw_rsvd_page *rsvd_pkt, *tmp;
+
+	if (fw->firmware)
+		release_firmware(fw->firmware);
+
+	list_for_each_entry_safe(rsvd_pkt, tmp, &rtwdev->rsvd_page_list, list) {
+		list_del(&rsvd_pkt->list);
+		kfree(rsvd_pkt);
+	}
+
+	rtw_debugfs_deinit();
+	mutex_destroy(&rtwdev->sec.mutex);
+	mutex_destroy(&rtwdev->hal.h2c_mutex);
+	mutex_destroy(&rtwdev->hal.tx_power_mutex);
+	mutex_destroy(&rtwdev->efuse.mutex);
+}
+EXPORT_SYMBOL(rtw_core_deinit);
+
+int rtw_register_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw)
+{
+	int max_tx_headroom = 0;
+	int ret;
+
+	/* TODO: USB & SDIO may need extra room? */
+	max_tx_headroom = rtwdev->chip->tx_pkt_desc_sz;
+
+	hw->extra_tx_headroom = max_tx_headroom;
+	hw->queues = IEEE80211_NUM_ACS;
+	hw->sta_data_size = sizeof(struct rtw_sta_info);
+	hw->vif_data_size = sizeof(struct rtw_vif);
+
+	ieee80211_hw_set(hw, SIGNAL_DBM);
+	ieee80211_hw_set(hw, RX_INCLUDES_FCS);
+	ieee80211_hw_set(hw, AMPDU_AGGREGATION);
+	ieee80211_hw_set(hw, MFP_CAPABLE);
+	ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
+	ieee80211_hw_set(hw, SUPPORTS_PS);
+	ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
+
+	hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+				     BIT(NL80211_IFTYPE_AP) |
+				     BIT(NL80211_IFTYPE_ADHOC) |
+				     BIT(NL80211_IFTYPE_MESH_POINT);
+	hw->wiphy->iface_combinations = rtw_5port_if_combs;
+	hw->wiphy->n_iface_combinations = ARRAY_SIZE(rtw_5port_if_combs);
+
+	hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS |
+			    WIPHY_FLAG_TDLS_EXTERNAL_SETUP;
+
+	rtw_set_supported_band(hw, rtwdev->chip);
+	SET_IEEE80211_PERM_ADDR(hw, rtwdev->efuse.addr);
+
+	rtw_regd_init(rtwdev, rtw_regd_notifier);
+
+	ret = ieee80211_register_hw(hw);
+	if (ret) {
+		rtw_err(rtwdev, "hw register failed");
+		return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(rtw_register_hw);
+
+void rtw_unregister_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw)
+{
+	struct rtw_chip_info *chip = rtwdev->chip;
+
+	ieee80211_unregister_hw(hw);
+	rtw_unset_supported_band(hw, chip);
+}
+EXPORT_SYMBOL(rtw_unregister_hw);
+
+MODULE_AUTHOR("Realtek Corporation");
+MODULE_DESCRIPTION("Realtek 802.11ac wireless core module");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/realtek/rtwlan/main.h b/drivers/net/wireless/realtek/rtwlan/main.h
new file mode 100644
index 0000000..6853266
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtwlan/main.h
@@ -0,0 +1,1188 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2018  Realtek Corporation.
+ */
+
+#ifndef __RTK_MAIN_H_
+#define __RTK_MAIN_H_
+
+#include <net/mac80211.h>
+#include <linux/vmalloc.h>
+#include <linux/firmware.h>
+#include <linux/average.h>
+
+#define RTW_MAX_MAC_ID_NUM		32
+#define RTW_MAX_SEC_CAM_NUM		32
+
+#define RTW_WATCH_DOG_DELAY_TIME	(HZ * 2)
+
+#define RFREG_MASK			0xfffff
+#define INV_RF_DATA			0xffffffff
+#define TX_PAGE_SIZE_SHIFT		7
+
+#define RTW_CHANNEL_WIDTH_MAX		3
+#define RTW_RF_PATH_MAX			4
+#define HW_FEATURE_LEN			13
+
+extern const struct ieee80211_ops rtw_ops;
+extern struct rtw_chip_info rtw8822b_hw_spec;
+extern struct rtw_chip_info rtw8822c_hw_spec;
+
+#define BIT_LEN_MASK_32(__bitlen) (0xFFFFFFFF >> (32 - (__bitlen)))
+#define BIT_OFFSET_LEN_MASK_32(__bitoffset, __bitlen)                          \
+	(BIT_LEN_MASK_32(__bitlen) << (__bitoffset))
+#define LE_P4BYTE_TO_HOST_4BYTE(__start) (le32_to_cpu(*((__le32 *)(__start))))
+#define LE_BITS_CLEARED_TO_4BYTE(__start, __bitoffset, __bitlen)               \
+	(LE_P4BYTE_TO_HOST_4BYTE(__start) &                                    \
+	 (~BIT_OFFSET_LEN_MASK_32(__bitoffset, __bitlen)))
+#define LE_BITS_TO_4BYTE(__start, __bitoffset, __bitlen)                       \
+	((LE_P4BYTE_TO_HOST_4BYTE(__start) >> (__bitoffset)) &                 \
+	 BIT_LEN_MASK_32(__bitlen))
+#define SET_BITS_TO_LE_4BYTE(__start, __bitoffset, __bitlen, __value)          \
+	do {                                                                   \
+		*((__le32 *)(__start)) = \
+		cpu_to_le32( \
+		LE_BITS_CLEARED_TO_4BYTE(__start, __bitoffset, __bitlen) |     \
+		((((u32)__value) & BIT_LEN_MASK_32(__bitlen)) << (__bitoffset))\
+		);                                                             \
+	} while (0)
+
+#define RTW_MAX_CHANNEL_NUM_2G 14
+#define RTW_MAX_CHANNEL_NUM_5G 49
+
+struct rtw_dev;
+
+enum rtw_hci_type {
+	RTW_HCI_TYPE_PCIE,
+	RTW_HCI_TYPE_USB,
+	RTW_HCI_TYPE_SDIO,
+
+	RTW_HCI_TYPE_UNDEFINE,
+};
+
+struct rtw_hci {
+	struct rtw_hci_ops *ops;
+	enum rtw_hci_type type;
+
+	u32 rpwm_addr;
+
+	u8 bulkout_num;
+};
+
+enum rtw_supported_band {
+	RTW_BAND_2G = 1 << 0,
+	RTW_BAND_5G = 1 << 1,
+	RTW_BAND_60G = 1 << 2,
+
+	RTW_BAND_MAX,
+};
+
+enum rtw_bandwidth {
+	RTW_CHANNEL_WIDTH_20	= 0,
+	RTW_CHANNEL_WIDTH_40	= 1,
+	RTW_CHANNEL_WIDTH_80	= 2,
+	RTW_CHANNEL_WIDTH_160	= 3,
+	RTW_CHANNEL_WIDTH_80_80	= 4,
+	RTW_CHANNEL_WIDTH_5	= 5,
+	RTW_CHANNEL_WIDTH_10	= 6,
+};
+
+enum rtw_net_type {
+	RTW_NET_NO_LINK		= 0,
+	RTW_NET_AD_HOC		= 1,
+	RTW_NET_MGD_LINKED	= 2,
+	RTW_NET_AP_MODE		= 3,
+};
+
+enum rtw_rf_type {
+	RF_1T1R			= 0,
+	RF_1T2R			= 1,
+	RF_2T2R			= 2,
+	RF_2T3R			= 3,
+	RF_2T4R			= 4,
+	RF_3T3R			= 5,
+	RF_3T4R			= 6,
+	RF_4T4R			= 7,
+	RF_TYPE_MAX,
+};
+
+enum rtw_rf_path {
+	RF_PATH_A = 0,
+	RF_PATH_B = 1,
+	RF_PATH_C = 2,
+	RF_PATH_D = 3,
+};
+
+enum rtw_bb_path {
+	BB_PATH_A = BIT(0),
+	BB_PATH_B = BIT(1),
+	BB_PATH_C = BIT(2),
+	BB_PATH_D = BIT(3),
+
+	BB_PATH_AB = (BB_PATH_A | BB_PATH_B),
+	BB_PATH_AC = (BB_PATH_A | BB_PATH_C),
+	BB_PATH_AD = (BB_PATH_A | BB_PATH_D),
+	BB_PATH_BC = (BB_PATH_B | BB_PATH_C),
+	BB_PATH_BD = (BB_PATH_B | BB_PATH_D),
+	BB_PATH_CD = (BB_PATH_C | BB_PATH_D),
+
+	BB_PATH_ABC = (BB_PATH_A | BB_PATH_B | BB_PATH_C),
+	BB_PATH_ABD = (BB_PATH_A | BB_PATH_B | BB_PATH_D),
+	BB_PATH_ACD = (BB_PATH_A | BB_PATH_C | BB_PATH_D),
+	BB_PATH_BCD = (BB_PATH_B | BB_PATH_C | BB_PATH_D),
+
+	BB_PATH_ABCD = (BB_PATH_A | BB_PATH_B | BB_PATH_C | BB_PATH_D),
+};
+
+enum rtw_rate_section {
+	RTW_RATE_SECTION_CCK = 0,
+	RTW_RATE_SECTION_OFDM,
+	RTW_RATE_SECTION_HT_1S,
+	RTW_RATE_SECTION_HT_2S,
+	RTW_RATE_SECTION_VHT_1S,
+	RTW_RATE_SECTION_VHT_2S,
+
+	/* keep last */
+	RTW_RATE_SECTION_MAX,
+};
+
+enum rtw_wireless_set {
+	WIRELESS_CCK	= 0x00000001,
+	WIRELESS_OFDM	= 0x00000002,
+	WIRELESS_HT	= 0x00000004,
+	WIRELESS_VHT	= 0x00000008,
+};
+
+#define HT_STBC_EN	BIT(0)
+#define VHT_STBC_EN	BIT(1)
+#define HT_LDPC_EN	BIT(0)
+#define VHT_LDPC_EN	BIT(1)
+
+enum rtw_chip_type {
+	RTW_CHIP_TYPE_8822B,
+	RTW_CHIP_TYPE_8822C,
+};
+
+enum rtw_tx_queue_type {
+	/* the order of AC queues matters */
+	RTW_TX_QUEUE_BK = 0x0,
+	RTW_TX_QUEUE_BE = 0x1,
+	RTW_TX_QUEUE_VI = 0x2,
+	RTW_TX_QUEUE_VO = 0x3,
+
+	RTW_TX_QUEUE_BCN = 0x4,
+	RTW_TX_QUEUE_MGMT = 0x5,
+	RTW_TX_QUEUE_HI0 = 0x6,
+	RTW_TX_QUEUE_H2C = 0x7,
+	/* keep it last */
+	RTK_MAX_TX_QUEUE_NUM
+};
+
+enum rtw_rx_queue_type {
+	RTW_RX_QUEUE_MPDU = 0x0,
+	RTW_RX_QUEUE_C2H = 0x1,
+	/* keep it last */
+	RTK_MAX_RX_QUEUE_NUM
+};
+
+enum rtw_rate_index {
+	RTW_RATEID_BGN_40M_2SS	= 0,
+	RTW_RATEID_BGN_40M_1SS	= 1,
+	RTW_RATEID_BGN_20M_2SS	= 2,
+	RTW_RATEID_BGN_20M_1SS	= 3,
+	RTW_RATEID_GN_N2SS	= 4,
+	RTW_RATEID_GN_N1SS	= 5,
+	RTW_RATEID_BG		= 6,
+	RTW_RATEID_G		= 7,
+	RTW_RATEID_B_20M	= 8,
+	RTW_RATEID_ARFR0_AC_2SS	= 9,
+	RTW_RATEID_ARFR1_AC_1SS	= 10,
+	RTW_RATEID_ARFR2_AC_2G_1SS = 11,
+	RTW_RATEID_ARFR3_AC_2G_2SS = 12,
+	RTW_RATEID_ARFR4_AC_3SS	= 13,
+	RTW_RATEID_ARFR5_N_3SS	= 14,
+	RTW_RATEID_ARFR7_N_4SS	= 15,
+	RTW_RATEID_ARFR6_AC_4SS	= 16
+};
+
+enum rtw_trx_desc_rate {
+	DESC_RATE1M	= 0x00,
+	DESC_RATE2M	= 0x01,
+	DESC_RATE5_5M	= 0x02,
+	DESC_RATE11M	= 0x03,
+
+	DESC_RATE6M	= 0x04,
+	DESC_RATE9M	= 0x05,
+	DESC_RATE12M	= 0x06,
+	DESC_RATE18M	= 0x07,
+	DESC_RATE24M	= 0x08,
+	DESC_RATE36M	= 0x09,
+	DESC_RATE48M	= 0x0a,
+	DESC_RATE54M	= 0x0b,
+
+	DESC_RATEMCS0	= 0x0c,
+	DESC_RATEMCS1	= 0x0d,
+	DESC_RATEMCS2	= 0x0e,
+	DESC_RATEMCS3	= 0x0f,
+	DESC_RATEMCS4	= 0x10,
+	DESC_RATEMCS5	= 0x11,
+	DESC_RATEMCS6	= 0x12,
+	DESC_RATEMCS7	= 0x13,
+	DESC_RATEMCS8	= 0x14,
+	DESC_RATEMCS9	= 0x15,
+	DESC_RATEMCS10	= 0x16,
+	DESC_RATEMCS11	= 0x17,
+	DESC_RATEMCS12	= 0x18,
+	DESC_RATEMCS13	= 0x19,
+	DESC_RATEMCS14	= 0x1a,
+	DESC_RATEMCS15	= 0x1b,
+	DESC_RATEMCS16	= 0x1c,
+	DESC_RATEMCS17	= 0x1d,
+	DESC_RATEMCS18	= 0x1e,
+	DESC_RATEMCS19	= 0x1f,
+	DESC_RATEMCS20	= 0x20,
+	DESC_RATEMCS21	= 0x21,
+	DESC_RATEMCS22	= 0x22,
+	DESC_RATEMCS23	= 0x23,
+	DESC_RATEMCS24	= 0x24,
+	DESC_RATEMCS25	= 0x25,
+	DESC_RATEMCS26	= 0x26,
+	DESC_RATEMCS27	= 0x27,
+	DESC_RATEMCS28	= 0x28,
+	DESC_RATEMCS29	= 0x29,
+	DESC_RATEMCS30	= 0x2a,
+	DESC_RATEMCS31	= 0x2b,
+
+	DESC_RATEVHT1SS_MCS0	= 0x2c,
+	DESC_RATEVHT1SS_MCS1	= 0x2d,
+	DESC_RATEVHT1SS_MCS2	= 0x2e,
+	DESC_RATEVHT1SS_MCS3	= 0x2f,
+	DESC_RATEVHT1SS_MCS4	= 0x30,
+	DESC_RATEVHT1SS_MCS5	= 0x31,
+	DESC_RATEVHT1SS_MCS6	= 0x32,
+	DESC_RATEVHT1SS_MCS7	= 0x33,
+	DESC_RATEVHT1SS_MCS8	= 0x34,
+	DESC_RATEVHT1SS_MCS9	= 0x35,
+
+	DESC_RATEVHT2SS_MCS0	= 0x36,
+	DESC_RATEVHT2SS_MCS1	= 0x37,
+	DESC_RATEVHT2SS_MCS2	= 0x38,
+	DESC_RATEVHT2SS_MCS3	= 0x39,
+	DESC_RATEVHT2SS_MCS4	= 0x3a,
+	DESC_RATEVHT2SS_MCS5	= 0x3b,
+	DESC_RATEVHT2SS_MCS6	= 0x3c,
+	DESC_RATEVHT2SS_MCS7	= 0x3d,
+	DESC_RATEVHT2SS_MCS8	= 0x3e,
+	DESC_RATEVHT2SS_MCS9	= 0x3f,
+
+	DESC_RATEVHT3SS_MCS0	= 0x40,
+	DESC_RATEVHT3SS_MCS1	= 0x41,
+	DESC_RATEVHT3SS_MCS2	= 0x42,
+	DESC_RATEVHT3SS_MCS3	= 0x43,
+	DESC_RATEVHT3SS_MCS4	= 0x44,
+	DESC_RATEVHT3SS_MCS5	= 0x45,
+	DESC_RATEVHT3SS_MCS6	= 0x46,
+	DESC_RATEVHT3SS_MCS7	= 0x47,
+	DESC_RATEVHT3SS_MCS8	= 0x48,
+	DESC_RATEVHT3SS_MCS9	= 0x49,
+
+	DESC_RATEVHT4SS_MCS0	= 0x4a,
+	DESC_RATEVHT4SS_MCS1	= 0x4b,
+	DESC_RATEVHT4SS_MCS2	= 0x4c,
+	DESC_RATEVHT4SS_MCS3	= 0x4d,
+	DESC_RATEVHT4SS_MCS4	= 0x4e,
+	DESC_RATEVHT4SS_MCS5	= 0x4f,
+	DESC_RATEVHT4SS_MCS6	= 0x50,
+	DESC_RATEVHT4SS_MCS7	= 0x51,
+	DESC_RATEVHT4SS_MCS8	= 0x52,
+	DESC_RATEVHT4SS_MCS9	= 0x53,
+
+	DESC_RATE_MAX,
+};
+
+enum rtw_regulatory_domains {
+	RTW_REGD_FCC	= 0,
+	RTW_REGD_MKK	= 1,
+	RTW_REGD_ETSI	= 2,
+	RTW_REGD_WW	= 3,
+
+	RTW_REGD_MAX
+};
+
+enum rtw_flags {
+	RTW_FLAG_RUNNING,
+	RTW_FLAG_FW_RUNNING,
+	RTW_FLAG_SCANNING,
+	RTW_FLAG_INACTIVE_PS,
+	RTW_FLAG_LEISURE_PS,
+	RTW_FLAG_DIG_DISABLE,
+
+	NUM_OF_RTW_FLAGS,
+};
+
+/* the power index is represented by differences, which cck-1s & ht40-1s are
+ * the base values, so for 1s's differences, there are only ht20 & ofdm
+ */
+struct rtw_2g_1s_pwr_idx_diff {
+#ifdef __LITTLE_ENDIAN
+	s8 ofdm:4;
+	s8 bw20:4;
+#else
+	s8 bw20:4;
+	s8 ofdm:4;
+#endif
+} __packed;
+
+struct rtw_2g_ns_pwr_idx_diff {
+#ifdef __LITTLE_ENDIAN
+	s8 bw20:4;
+	s8 bw40:4;
+	s8 cck:4;
+	s8 ofdm:4;
+#else
+	s8 ofdm:4;
+	s8 cck:4;
+	s8 bw40:4;
+	s8 bw20:4;
+#endif
+} __packed;
+
+struct rtw_2g_txpwr_idx {
+	u8 cck_base[6];
+	u8 bw40_base[5];
+	struct rtw_2g_1s_pwr_idx_diff ht_1s_diff;
+	struct rtw_2g_ns_pwr_idx_diff ht_2s_diff;
+	struct rtw_2g_ns_pwr_idx_diff ht_3s_diff;
+	struct rtw_2g_ns_pwr_idx_diff ht_4s_diff;
+};
+
+struct rtw_5g_ht_1s_pwr_idx_diff {
+#ifdef __LITTLE_ENDIAN
+	s8 ofdm:4;
+	s8 bw20:4;
+#else
+	s8 bw20:4;
+	s8 ofdm:4;
+#endif
+} __packed;
+
+struct rtw_5g_ht_ns_pwr_idx_diff {
+#ifdef __LITTLE_ENDIAN
+	s8 bw20:4;
+	s8 bw40:4;
+#else
+	s8 bw40:4;
+	s8 bw20:4;
+#endif
+} __packed;
+
+struct rtw_5g_ofdm_ns_pwr_idx_diff {
+#ifdef __LITTLE_ENDIAN
+	s8 ofdm_3s:4;
+	s8 ofdm_2s:4;
+	s8 ofdm_4s:4;
+	s8 res:4;
+#else
+	s8 res:4;
+	s8 ofdm_4s:4;
+	s8 ofdm_2s:4;
+	s8 ofdm_3s:4;
+#endif
+} __packed;
+
+struct rtw_5g_vht_ns_pwr_idx_diff {
+#ifdef __LITTLE_ENDIAN
+	s8 bw160:4;
+	s8 bw80:4;
+#else
+	s8 bw80:4;
+	s8 bw160:4;
+#endif
+} __packed;
+
+struct rtw_5g_txpwr_idx {
+	u8 bw40_base[14];
+	struct rtw_5g_ht_1s_pwr_idx_diff ht_1s_diff;
+	struct rtw_5g_ht_ns_pwr_idx_diff ht_2s_diff;
+	struct rtw_5g_ht_ns_pwr_idx_diff ht_3s_diff;
+	struct rtw_5g_ht_ns_pwr_idx_diff ht_4s_diff;
+	struct rtw_5g_ofdm_ns_pwr_idx_diff ofdm_diff;
+	struct rtw_5g_vht_ns_pwr_idx_diff vht_1s_diff;
+	struct rtw_5g_vht_ns_pwr_idx_diff vht_2s_diff;
+	struct rtw_5g_vht_ns_pwr_idx_diff vht_3s_diff;
+	struct rtw_5g_vht_ns_pwr_idx_diff vht_4s_diff;
+};
+
+struct rtw_txpwr_idx {
+	struct rtw_2g_txpwr_idx pwr_idx_2g;
+	struct rtw_5g_txpwr_idx pwr_idx_5g;
+};
+
+struct rtw_timer_list {
+	struct timer_list timer;
+	void (*function)(void *data);
+	void *args;
+};
+
+struct rtw_channel_params {
+	u8 center_chan;
+	u8 bandwidth;
+	u8 primary_chan_idx;
+};
+
+struct rtw_hw_reg {
+	u32 addr;
+	u32 mask;
+};
+
+struct rtw_backup_info {
+	u8 len;
+	u32 reg;
+	u32 val;
+};
+
+enum rtw_vif_port_set {
+	PORT_SET_MAC_ADDR	= BIT(0),
+	PORT_SET_BSSID		= BIT(1),
+	PORT_SET_NET_TYPE	= BIT(2),
+	PORT_SET_AID		= BIT(3),
+};
+
+struct rtw_vif_port {
+	struct rtw_hw_reg mac_addr;
+	struct rtw_hw_reg bssid;
+	struct rtw_hw_reg net_type;
+	struct rtw_hw_reg aid;
+};
+
+struct rtw_tx_pkt_info {
+	u32 tx_pkt_size;
+	u8 offset;
+	u8 pkt_offset;
+	u8 mac_id;
+	u8 rate_id;
+	u8 rate;
+	u8 qsel;
+	u8 bw;
+	u8 sec_type;
+	bool ampdu_en;
+	u8 ampdu_factor;
+	u8 ampdu_density;
+	u16 seq;
+	bool stbc;
+	bool ldpc;
+	bool dis_rate_fallback;
+	bool bmc;
+	bool use_rate;
+	bool ls;
+	bool fs;
+	bool short_gi;
+};
+
+struct rtw_rx_pkt_stat {
+	bool phy_status;
+	bool icv_err;
+	bool crc_err;
+	bool decrypted;
+	bool is_c2h;
+
+	s32 signal_power;
+	u16 pkt_len;
+	u8 bw;
+	u8 drv_info_sz;
+	u8 shift;
+	u8 rate;
+	u8 mac_id;
+	u8 cam_id;
+	u8 ppdu_cnt;
+	u32 tsf_low;
+	s8 rx_power[RTW_RF_PATH_MAX];
+	u8 rssi;
+	u8 rxsc;
+	struct rtw_sta_info *si;
+	struct ieee80211_vif *vif;
+};
+
+struct rtw_traffic_stats {
+	/* units in bytes */
+	u64 tx_unicast;
+	u64 rx_unicast;
+
+	/* count for packets */
+	u64 tx_cnt;
+	u64 rx_cnt;
+
+	/* units in Mbps */
+	u32 tx_throughput;
+	u32 rx_throughput;
+};
+
+enum rtw_lps_mode {
+	RTW_MODE_ACTIVE	= 0,
+	RTW_MODE_LPS	= 1,
+	RTW_MODE_WMM_PS	= 2,
+};
+
+enum rtw_pwr_state {
+	RTW_RF_OFF	= 0x0,
+	RTW_RF_ON	= 0x4,
+	RTW_ALL_ON	= 0xc,
+};
+
+struct rtw_lps_conf {
+	/* the interface to enter lps */
+	struct rtw_vif *rtwvif;
+	enum rtw_lps_mode mode;
+	enum rtw_pwr_state state;
+	u8 awake_interval;
+	u8 rlbm;
+	u8 smart_ps;
+	u8 port_id;
+};
+
+enum rtw_hw_key_type {
+	RTW_CAM_NONE	= 0,
+	RTW_CAM_WEP40	= 1,
+	RTW_CAM_TKIP	= 2,
+	RTW_CAM_AES	= 4,
+	RTW_CAM_WEP104	= 5,
+};
+
+struct rtw_cam_entry {
+	bool used;
+	bool valid;
+	bool group;
+	u8 addr[ETH_ALEN];
+	u8 hw_key_type;
+	struct ieee80211_key_conf *key;
+};
+
+struct rtw_sec_desc {
+	/* protect cam write/clear */
+	struct mutex mutex;
+
+	/* search strategy */
+	bool default_key_search;
+
+	u32 total_cam_num;
+	struct rtw_cam_entry cam_table[RTW_MAX_SEC_CAM_NUM];
+};
+
+#define RTW_BC_MC_MACID 1
+DECLARE_EWMA(rssi, 10, 16);
+
+struct rtw_sta_info {
+	struct list_head list;
+
+	struct ieee80211_sta *sta;
+	struct ieee80211_vif *vif;
+
+	struct ewma_rssi avg_rssi;
+	u8 rssi_level;
+
+	u8 mac_id;
+	u8 rate_id;
+	enum rtw_bandwidth bw_mode;
+	enum rtw_rf_type rf_type;
+	enum rtw_wireless_set wireless_set;
+	u8 stbc_en:2;
+	u8 ldpc_en:2;
+	bool sgi_enable;
+	bool vht_enable;
+	bool updated;
+	u8 init_ra_lv;
+	u64 ra_mask;
+};
+
+struct rtw_vif {
+	struct list_head list;
+
+	struct ieee80211_vif *vif;
+	enum rtw_net_type net_type;
+	u16 aid;
+	u8 mac_addr[ETH_ALEN];
+	u8 bssid[ETH_ALEN];
+
+	struct list_head sta_list;
+
+	u8 port;
+	struct rtw_vif_port *conf;
+
+	struct rtw_traffic_stats stats;
+	bool in_lps;
+};
+
+struct rtw_regulatory {
+	s8 alpha2[2];
+	u16 country_code;
+};
+
+struct rtw_chip_ops {
+	int (*mac_init)(struct rtw_dev *rtwdev);
+	int (*read_efuse)(struct rtw_dev *rtwdev, u8 *map);
+	void (*phy_set_param)(struct rtw_dev *rtwdev);
+	void (*set_channel)(struct rtw_dev *rtwdev, u8 channel,
+			    u8 bandwidth, u8 primary_chan_idx);
+	void (*query_rx_desc)(struct rtw_dev *rtwdev, u8 *rx_desc,
+			      struct rtw_rx_pkt_stat *pkt_stat,
+			      struct ieee80211_rx_status *rx_status);
+	u32 (*read_rf)(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
+		       u32 addr, u32 mask);
+	bool (*write_rf)(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
+			 u32 addr, u32 mask, u32 data);
+	void (*set_tx_power_index)(struct rtw_dev *rtwdev, u8 power_index,
+				   u8 rf_path, u8 rate);
+	int (*rsvd_page_dump)(struct rtw_dev *rtwdev, u8 *buf, u32 offset,
+			      u32 size);
+	void (*set_antenna)(struct rtw_dev *rtwdev, u8 antenna_tx,
+			    u8 antenna_rx);
+	void (*cfg_ldo25)(struct rtw_dev *rtwdev, bool enable);
+	void (*false_alarm_statistics)(struct rtw_dev *rtwdev);
+	void (*do_iqk)(struct rtw_dev *rtwdev);
+};
+
+#define RTW_PWR_POLLING_CNT	20000
+
+#define RTW_PWR_CMD_READ	0x00
+#define RTW_PWR_CMD_WRITE	0x01
+#define RTW_PWR_CMD_POLLING	0x02
+#define RTW_PWR_CMD_DELAY	0x03
+#define RTW_PWR_CMD_END		0x04
+
+/* define the base address of each block */
+#define RTW_PWR_ADDR_MAC	0x00
+#define RTW_PWR_ADDR_USB	0x01
+#define RTW_PWR_ADDR_PCIE	0x02
+#define RTW_PWR_ADDR_SDIO	0x03
+
+#define RTW_PWR_INTF_SDIO_MSK	BIT(0)
+#define RTW_PWR_INTF_USB_MSK	BIT(1)
+#define RTW_PWR_INTF_PCI_MSK	BIT(2)
+#define RTW_PWR_INTF_ALL_MSK	(BIT(0) | BIT(1) | BIT(2) | BIT(3))
+
+#define RTW_PWR_CUT_A_MSK	BIT(1)
+#define RTW_PWR_CUT_B_MSK	BIT(2)
+#define RTW_PWR_CUT_C_MSK	BIT(3)
+#define RTW_PWR_CUT_D_MSK	BIT(4)
+#define RTW_PWR_CUT_E_MSK	BIT(5)
+#define RTW_PWR_CUT_F_MSK	BIT(6)
+#define RTW_PWR_CUT_G_MSK	BIT(7)
+#define RTW_PWR_CUT_ALL_MSK	0xFF
+
+enum rtw_pwr_seq_cmd_delay_unit {
+	RTW_PWR_DELAY_US,
+	RTW_PWR_DELAY_MS,
+};
+
+struct rtw_pwr_seq_cmd {
+	u16 offset;
+	u8 cut_mask;
+	u8 intf_mask;
+	u8 base:4;
+	u8 cmd:4;
+	u8 mask;
+	u8 value;
+};
+
+enum rtw_chip_ver {
+	RTW_CHIP_VER_CUT_A = 0x00,
+	RTW_CHIP_VER_CUT_B = 0x01,
+	RTW_CHIP_VER_CUT_C = 0x02,
+	RTW_CHIP_VER_CUT_D = 0x03,
+	RTW_CHIP_VER_CUT_E = 0x04,
+	RTW_CHIP_VER_CUT_F = 0x05,
+	RTW_CHIP_VER_CUT_G = 0x06,
+};
+
+#define RTW_INTF_PHY_PLATFORM_ALL 0
+
+enum rtw_intf_phy_cut {
+	RTW_INTF_PHY_CUT_A = BIT(0),
+	RTW_INTF_PHY_CUT_B = BIT(1),
+	RTW_INTF_PHY_CUT_C = BIT(2),
+	RTW_INTF_PHY_CUT_D = BIT(3),
+	RTW_INTF_PHY_CUT_E = BIT(4),
+	RTW_INTF_PHY_CUT_F = BIT(5),
+	RTW_INTF_PHY_CUT_G = BIT(6),
+	RTW_INTF_PHY_CUT_ALL = 0xFFFF,
+};
+
+enum rtw_ip_sel {
+	RTW_IP_SEL_PHY = 0,
+	RTW_IP_SEL_MAC = 1,
+	RTW_IP_SEL_DBI = 2,
+
+	RTW_IP_SEL_UNDEF = 0xFFFF
+};
+
+enum rtw_pq_map_id {
+	RTW_PQ_MAP_VO = 0x0,
+	RTW_PQ_MAP_VI = 0x1,
+	RTW_PQ_MAP_BE = 0x2,
+	RTW_PQ_MAP_BK = 0x3,
+	RTW_PQ_MAP_MG = 0x4,
+	RTW_PQ_MAP_HI = 0x5,
+	RTW_PQ_MAP_NUM = 0x6,
+
+	RTW_PQ_MAP_UNDEF,
+};
+
+enum rtw_dma_mapping {
+	RTW_DMA_MAPPING_EXTRA	= 0,
+	RTW_DMA_MAPPING_LOW	= 1,
+	RTW_DMA_MAPPING_NORMAL	= 2,
+	RTW_DMA_MAPPING_HIGH	= 3,
+
+	RTW_DMA_MAPPING_UNDEF,
+};
+
+struct rtw_rqpn {
+	enum rtw_dma_mapping dma_map_vo;
+	enum rtw_dma_mapping dma_map_vi;
+	enum rtw_dma_mapping dma_map_be;
+	enum rtw_dma_mapping dma_map_bk;
+	enum rtw_dma_mapping dma_map_mg;
+	enum rtw_dma_mapping dma_map_hi;
+};
+
+struct rtw_page_table {
+	u16 hq_num;
+	u16 nq_num;
+	u16 lq_num;
+	u16 exq_num;
+	u16 gapq_num;
+};
+
+struct rtw_intf_phy_para {
+	u16 offset;
+	u16 value;
+	u16 ip_sel;
+	u16 cut_mask;
+	u16 platform;
+};
+
+struct rtw_intf_phy_para_table {
+	struct rtw_intf_phy_para *usb2_para;
+	struct rtw_intf_phy_para *usb3_para;
+	struct rtw_intf_phy_para *gen1_para;
+	struct rtw_intf_phy_para *gen2_para;
+	u8 n_usb2_para;
+	u8 n_usb3_para;
+	u8 n_gen1_para;
+	u8 n_gen2_para;
+};
+
+struct rtw_table {
+	const void *data;
+	const u32 size;
+	void (*parse)(struct rtw_dev *rtwdev, const struct rtw_table *tbl);
+	void (*do_cfg)(struct rtw_dev *rtwdev, const struct rtw_table *tbl,
+		       u32 addr, u32 data);
+	enum rtw_rf_path rf_path;
+};
+
+static inline void rtw_load_table(struct rtw_dev *rtwdev,
+				  const struct rtw_table *tbl)
+{
+	(*tbl->parse)(rtwdev, tbl);
+}
+
+enum rtw_rfe_fem {
+	RTW_RFE_IFEM,
+	RTW_RFE_EFEM,
+	RTW_RFE_IFEM2G_EFEM5G,
+	RTW_RFE_NUM,
+};
+
+struct rtw_rfe_def {
+	const struct rtw_table *phy_pg_tbl;
+	const struct rtw_table *txpwr_lmt_tbl;
+};
+
+#define RTW_DEF_RFE(chip, bb_pg, pwrlmt) {				  \
+	.phy_pg_tbl = &rtw ## chip ## _bb_pg_type ## bb_pg ## _tbl,	  \
+	.txpwr_lmt_tbl = &rtw ## chip ## _txpwr_lmt_type ## pwrlmt ## _tbl, \
+	}
+
+/* hardware configuration for each IC */
+struct rtw_chip_info {
+	struct rtw_chip_ops *ops;
+	u8 id;
+
+	const char *fw_name;
+	u8 tx_pkt_desc_sz;
+	u8 tx_buf_desc_sz;
+	u8 rx_pkt_desc_sz;
+	u8 rx_buf_desc_sz;
+	u32 phy_efuse_size;
+	u32 log_efuse_size;
+	u32 ptct_efuse_size;
+	u32 txff_size;
+	u32 rxff_size;
+	u8 band;
+	u8 page_size;
+	u8 csi_buf_pg_num;
+	u8 dig_max;
+	u8 dig_min;
+
+	bool ht_supported;
+	bool vht_supported;
+
+	/* init values */
+	u8 sys_func_en;
+	struct rtw_pwr_seq_cmd **pwr_on_seq;
+	struct rtw_pwr_seq_cmd **pwr_off_seq;
+	struct rtw_rqpn *rqpn_table;
+	struct rtw_page_table *page_table;
+	struct rtw_intf_phy_para_table *intf_table;
+
+	struct rtw_hw_reg *dig;
+	u32 rf_base_addr[2];
+	u32 rf_sipi_addr[2];
+
+	const struct rtw_table *mac_tbl;
+	const struct rtw_table *agc_tbl;
+	const struct rtw_table *bb_tbl;
+	const struct rtw_table *rf_tbl[RTW_RF_PATH_MAX];
+
+	const struct rtw_rfe_def *rfe_defs;
+	u32 rfe_defs_size;
+};
+
+struct rtw_dm_info {
+	u32 cck_fa_cnt;
+	u32 ofdm_fa_cnt;
+	u32 total_fa_cnt;
+	u8 min_rssi;
+	u8 pre_min_rssi;
+	u16 fa_history[4];
+	u8 igi_history[4];
+	u8 igi_bitmap;
+	bool damping;
+	u8 damping_cnt;
+	u8 damping_rssi;
+
+	u8 cck_gi_u_bnd;
+	u8 cck_gi_l_bnd;
+};
+
+struct rtw_efuse {
+	/* protect efuse map read/write */
+	struct mutex mutex;
+	u32 size;
+	u32 physical_size;
+	u32 logical_size;
+	u32 protect_size;
+
+	u8 addr[ETH_ALEN];
+	u8 channel_plan;
+	u8 rfe_option;
+	u8 thermal_meter;
+	u8 crystal_cap;
+	u8 ant_div_cfg;
+	u8 ant_div_type;
+	u8 regd;
+
+	u8 lna_type_2g;
+	u8 lna_type_5g;
+	u8 glna_type;
+	u8 alna_type;
+	bool ext_lna_2g;
+	bool ext_lna_5g;
+	u8 pa_type_2g;
+	u8 pa_type_5g;
+	u8 gpa_type;
+	u8 apa_type;
+	bool ext_pa_2g;
+	bool ext_pa_5g;
+	u8 x3d7;
+	u8 x3d8;
+
+	bool btcoex;
+	/* bt share antenna with wifi */
+	bool share_ant;
+	u8 bt_setting;
+
+	struct {
+		u8 hci;
+		u8 bw;
+		u8 ptcl;
+		u8 nss;
+		u8 ant_num;
+	} hw_cap;
+
+	struct rtw_txpwr_idx txpwr_idx_table[4];
+};
+
+struct rtw_phy_cond {
+#ifdef __LITTLE_ENDIAN
+	u32 rfe:8;
+	u32 intf:4;
+	u32 pkg:4;
+	u32 plat:4;
+	u32 intf_rsvd:4;
+	u32 cut:4;
+	u32 branch:2;
+	u32 neg:1;
+	u32 pos:1;
+#else
+	u32 pos:1;
+	u32 neg:1;
+	u32 branch:2;
+	u32 cut:4;
+	u32 intf_rsvd:4;
+	u32 plat:4;
+	u32 pkg:4;
+	u32 intf:4;
+	u32 rfe:8;
+#endif
+	/* for intf:4 */
+	#define INTF_PCIE	BIT(0)
+	#define INTF_USB	BIT(1)
+	#define INTF_SDIO	BIT(2)
+	/* for branch:2 */
+	#define BRANCH_IF	0
+	#define BRANCH_ELIF	1
+	#define BRANCH_ELSE	2
+	#define BRANCH_ENDIF	3
+};
+
+struct rtw_fifo_conf {
+	/* tx fifo information */
+	u16 rsvd_boundary;
+	u16 rsvd_pg_num;
+	u16 rsvd_drv_pg_num;
+	u16 txff_pg_num;
+	u16 acq_pg_num;
+	u16 rsvd_drv_addr;
+	u16 rsvd_h2c_info_addr;
+	u16 rsvd_h2c_sta_info_addr;
+	u16 rsvd_h2cq_addr;
+	u16 rsvd_cpu_instr_addr;
+	u16 rsvd_fw_txbuf_addr;
+	u16 rsvd_csibuf_addr;
+	enum rtw_dma_mapping pq_map[RTW_PQ_MAP_NUM];
+};
+
+struct rtw_fw_state {
+	const struct firmware *firmware;
+	const u8 *data;
+	u32 size;
+	u16 version;
+	u8 sub_version;
+	u8 sub_index;
+	u16 h2c_version;
+};
+
+struct rtw_hal {
+	u32 rcr;
+
+	u32 chip_version;
+	u8 fab_version;
+	u8 cut_version;
+	u8 mp_chip;
+	u8 oem_id;
+	struct rtw_phy_cond phy_cond;
+
+	/* incicate the mail box to use with fw */
+	u8 last_box_num;
+	/* protect to send h2c to fw */
+	struct mutex h2c_mutex;
+	u32 buf_sz;
+	u32 seq;
+
+	u8 ps_mode;
+	u8 current_channel;
+	u8 current_band_width;
+	u8 current_band_type;
+	u8 sec_ch_offset;
+	u8 rf_type;
+	u8 rf_path_num;
+	u8 antenna_tx;
+	u8 antenna_rx;
+
+	/* protect tx power section */
+	struct mutex tx_power_mutex;
+	s8 tx_pwr_by_rate_offset_2g[RTW_RF_PATH_MAX]
+				   [DESC_RATE_MAX];
+	s8 tx_pwr_by_rate_offset_5g[RTW_RF_PATH_MAX]
+				   [DESC_RATE_MAX];
+	s8 tx_pwr_by_rate_base_2g[RTW_RF_PATH_MAX]
+				 [RTW_RATE_SECTION_MAX];
+	s8 tx_pwr_by_rate_base_5g[RTW_RF_PATH_MAX]
+				 [RTW_RATE_SECTION_MAX];
+	s8 tx_pwr_limit_2g[RTW_REGD_MAX]
+			  [RTW_CHANNEL_WIDTH_MAX]
+			  [RTW_RATE_SECTION_MAX]
+			  [RTW_MAX_CHANNEL_NUM_2G];
+	s8 tx_pwr_limit_5g[RTW_REGD_MAX]
+			  [RTW_CHANNEL_WIDTH_MAX]
+			  [RTW_RATE_SECTION_MAX]
+			  [RTW_MAX_CHANNEL_NUM_5G];
+};
+
+struct rtw_dev {
+	struct ieee80211_hw *hw;
+	struct device *dev;
+
+	struct rtw_hci hci;
+
+	struct rtw_chip_info *chip;
+	struct rtw_hal hal;
+	struct rtw_fifo_conf fifo;
+	struct rtw_fw_state fw;
+	struct rtw_efuse efuse;
+	struct rtw_sec_desc sec;
+	struct rtw_traffic_stats stats;
+	struct rtw_regulatory regd;
+
+	struct rtw_dm_info dm_info;
+
+	/* lock for dm to use */
+	spinlock_t dm_lock;
+
+	/* read/write rf register */
+	spinlock_t rf_lock;
+
+	/* watch dog every 2 sec */
+	struct delayed_work watch_dog_work;
+	u32 watch_dog_cnt;
+
+	/* list for virtual interfaces */
+	struct list_head vif_list;
+
+	struct list_head rsvd_page_list;
+
+	/* c2h cmd queue & handler work */
+	struct sk_buff_head c2h_queue;
+	struct work_struct c2h_work;
+
+	/* lps power state & handler work */
+	struct rtw_lps_conf lps_conf;
+	struct delayed_work lps_work;
+
+	bool macid_used[RTW_MAX_MAC_ID_NUM];
+
+	unsigned long flags[BITS_TO_LONGS(NUM_OF_RTW_FLAGS)];
+
+	u8 mp_mode;
+
+	/* hci related data, must be last */
+	u8 priv[0] __aligned(sizeof(void *));
+};
+
+#include "hci.h"
+
+static inline bool rtw_flag_check(struct rtw_dev *rtwdev, enum rtw_flags flag)
+{
+	return test_bit(flag, rtwdev->flags);
+}
+
+static inline void rtw_flag_clear(struct rtw_dev *rtwdev, enum rtw_flags flag)
+{
+	clear_bit(flag, rtwdev->flags);
+}
+
+static inline void rtw_flag_set(struct rtw_dev *rtwdev, enum rtw_flags flag)
+{
+	set_bit(flag, rtwdev->flags);
+}
+
+static inline bool get_hdr_match_bssid(struct rtw_dev *rtwdev,
+				       struct ieee80211_hdr *hdr,
+				       u8 *bssid)
+{
+	struct ieee80211_vif *vif;
+	struct rtw_vif *rtwvif;
+
+	list_for_each_entry(rtwvif, &rtwdev->vif_list, list) {
+		vif = rtwvif->vif;
+		if (ether_addr_equal(vif->bss_conf.bssid, bssid))
+			return true;
+	}
+
+	return false;
+}
+
+static inline struct ieee80211_vif *get_hdr_vif(struct rtw_dev *rtwdev,
+						struct ieee80211_hdr *hdr)
+{
+	struct ieee80211_vif *vif;
+	struct rtw_vif *rtwvif;
+
+	list_for_each_entry(rtwvif, &rtwdev->vif_list, list) {
+		vif = rtwvif->vif;
+		if (ether_addr_equal(vif->addr, hdr->addr1))
+			return vif;
+	}
+
+	return NULL;
+}
+
+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;
+
+	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))
+				return si;
+		}
+	} else {
+		list_for_each_entry(rtwvif, &rtwdev->vif_list, list) {
+			list_for_each_entry(si, &rtwvif->sta_list, list) {
+				if (ether_addr_equal(si->sta->addr, hdr->addr2))
+					return si;
+			}
+		}
+	}
+
+	return NULL;
+}
+
+static inline u8 *get_hdr_bssid(struct ieee80211_hdr *hdr)
+{
+	__le16 fc = hdr->frame_control;
+	u8 *bssid;
+
+	if (ieee80211_has_tods(fc))
+		bssid = hdr->addr1;
+	else if (ieee80211_has_fromds(fc))
+		bssid = hdr->addr2;
+	else
+		bssid = hdr->addr3;
+
+	return bssid;
+}
+
+static inline bool get_link_status(struct rtw_dev *rtwdev)
+{
+	struct rtw_vif *rtwvif;
+
+	list_for_each_entry(rtwvif, &rtwdev->vif_list, list) {
+		/* test if we have any peer in present */
+		if (!list_empty(&rtwvif->sta_list))
+			return true;
+	}
+
+	return false;
+}
+
+void rtw_get_channel_params(struct cfg80211_chan_def *chandef,
+			    struct rtw_channel_params *ch_param);
+void rtw_set_channel(struct rtw_dev *rtwdev);
+void rtw_vif_port_config(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif,
+			 u32 config);
+void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si);
+int rtw_core_start(struct rtw_dev *rtwdev);
+void rtw_core_stop(struct rtw_dev *rtwdev);
+int rtw_chip_info_setup(struct rtw_dev *rtwdev);
+int rtw_core_init(struct rtw_dev *rtwdev);
+void rtw_core_deinit(struct rtw_dev *rtwdev);
+int rtw_register_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw);
+void rtw_unregister_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw);
+
+#endif
diff --git a/drivers/net/wireless/realtek/rtwlan/reg.h b/drivers/net/wireless/realtek/rtwlan/reg.h
new file mode 100644
index 0000000..7adf568
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtwlan/reg.h
@@ -0,0 +1,399 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2018  Realtek Corporation.
+ */
+
+#ifndef __RTW_REG_DEF_H__
+#define __RTW_REG_DEF_H__
+
+#define REG_SYS_FUNC_EN		0x0002
+#define REG_SYS_PW_CTRL		0x0004
+#define REG_SYS_CLK_CTRL	0x0008
+
+#define REG_RSV_CTRL		0x001C
+#define REG_RF_CTRL		0x001F
+
+#define REG_EFUSE_CTRL		0x0030
+#define BIT_EF_FLAG		BIT(31)
+#define BIT_SHIFT_EF_ADDR	8
+#define BIT_MASK_EF_ADDR	0x3ff
+#define BIT_MASK_EF_DATA	0xff
+#define BITS_EF_ADDR		(BIT_MASK_EF_ADDR << BIT_SHIFT_EF_ADDR)
+
+#define REG_LDO_EFUSE_CTRL	0x0034
+
+#define REG_GPIO_MUXCFG		0x0040
+#define BIT_FSPI_EN		BIT(19)
+
+#define REG_LED_CFG		0x004C
+#define REG_PAD_CTRL1		0x0064
+#define REG_WL_BT_PWR_CTRL	0x0068
+#define BIT_BT_FUNC_EN		BIT(18)
+#define REG_HCI_OPT_CTRL	0x0074
+
+#define REG_MCUFW_CTRL		0x0080
+#define BIT_ANA_PORT_EN		BIT(22)
+#define BIT_MAC_PORT_EN		BIT(21)
+#define BIT_BOOT_FSPI_EN	BIT(20)
+#define BIT_FW_DW_RDY		BIT(14)
+#define BIT_DMEM_CHKSUM_OK	BIT(6)
+#define BIT_DMEM_DW_OK		BIT(5)
+#define BIT_IMEM_CHKSUM_OK	BIT(4)
+#define BIT_IMEM_DW_OK		BIT(3)
+
+#define REG_SYS_CFG1		0x00F0
+#define	BIT_RTL_ID		BIT(23)
+#define BIT_RF_TYPE_ID		BIT(27)
+#define BIT_SHIFT_VENDOR_ID	16
+#define BIT_MASK_VENDOR_ID	0xf
+#define BIT_VENDOR_ID(x) (((x) & BIT_MASK_VENDOR_ID) << BIT_SHIFT_VENDOR_ID)
+#define BITS_VENDOR_ID		(BIT_MASK_VENDOR_ID << BIT_SHIFT_VENDOR_ID)
+#define BIT_CLEAR_VENDOR_ID(x)	((x) & (~BITS_VENDOR_ID))
+#define BIT_GET_VENDOR_ID(x) (((x) >> BIT_SHIFT_VENDOR_ID) & BIT_MASK_VENDOR_ID)
+#define BIT_SHIFT_CHIP_VER	12
+#define BIT_MASK_CHIP_VER	0xf
+#define BIT_CHIP_VER(x)	 (((x) & BIT_MASK_CHIP_VER) << BIT_SHIFT_CHIP_VER)
+#define BITS_CHIP_VER		(BIT_MASK_CHIP_VER << BIT_SHIFT_CHIP_VER)
+#define BIT_CLEAR_CHIP_VER(x)	((x) & (~BITS_CHIP_VER))
+#define BIT_GET_CHIP_VER(x) (((x) >> BIT_SHIFT_CHIP_VER) & BIT_MASK_CHIP_VER)
+#define REG_SYS_STATUS1		0x00F4
+#define REG_SYS_STATUS2		0x00F8
+#define REG_SYS_CFG2		0x00FC
+#define REG_WLRF1		0x00EC
+#define REG_CR			0x0100
+#define BIT_32K_CAL_TMR_EN	BIT(10)
+#define BIT_MAC_SEC_EN		BIT(9)
+#define BIT_ENSWBCN		BIT(8)
+#define BIT_MACRXEN		BIT(7)
+#define BIT_MACTXEN		BIT(6)
+#define BIT_SCHEDULE_EN		BIT(5)
+#define BIT_PROTOCOL_EN		BIT(4)
+#define BIT_RXDMA_EN		BIT(3)
+#define BIT_TXDMA_EN		BIT(2)
+#define BIT_HCI_RXDMA_EN	BIT(1)
+#define BIT_HCI_TXDMA_EN	BIT(0)
+#define MAC_TRX_ENABLE	(BIT_HCI_TXDMA_EN | BIT_HCI_RXDMA_EN | BIT_TXDMA_EN | \
+			BIT_RXDMA_EN | BIT_PROTOCOL_EN | BIT_SCHEDULE_EN | \
+			BIT_MACTXEN | BIT_MACRXEN)
+#define BIT_SHIFT_TXDMA_VOQ_MAP	4
+#define BIT_MASK_TXDMA_VOQ_MAP	0x3
+#define BIT_TXDMA_VOQ_MAP(x)                                                   \
+	(((x) & BIT_MASK_TXDMA_VOQ_MAP) << BIT_SHIFT_TXDMA_VOQ_MAP)
+#define BIT_SHIFT_TXDMA_VIQ_MAP	6
+#define BIT_MASK_TXDMA_VIQ_MAP	0x3
+#define BIT_TXDMA_VIQ_MAP(x)                                                   \
+	(((x) & BIT_MASK_TXDMA_VIQ_MAP) << BIT_SHIFT_TXDMA_VIQ_MAP)
+#define REG_TXDMA_PQ_MAP	0x010C
+#define BIT_SHIFT_TXDMA_BEQ_MAP	8
+#define BIT_MASK_TXDMA_BEQ_MAP	0x3
+#define BIT_TXDMA_BEQ_MAP(x)                                                   \
+	(((x) & BIT_MASK_TXDMA_BEQ_MAP) << BIT_SHIFT_TXDMA_BEQ_MAP)
+#define BIT_SHIFT_TXDMA_BKQ_MAP	10
+#define BIT_MASK_TXDMA_BKQ_MAP	0x3
+#define BIT_TXDMA_BKQ_MAP(x)                                                   \
+	(((x) & BIT_MASK_TXDMA_BKQ_MAP) << BIT_SHIFT_TXDMA_BKQ_MAP)
+#define BIT_SHIFT_TXDMA_MGQ_MAP	12
+#define BIT_MASK_TXDMA_MGQ_MAP	0x3
+#define BIT_TXDMA_MGQ_MAP(x)                                                   \
+	(((x) & BIT_MASK_TXDMA_MGQ_MAP) << BIT_SHIFT_TXDMA_MGQ_MAP)
+#define BIT_SHIFT_TXDMA_HIQ_MAP	14
+#define BIT_MASK_TXDMA_HIQ_MAP	0x3
+#define BIT_TXDMA_HIQ_MAP(x)                                                   \
+	(((x) & BIT_MASK_TXDMA_HIQ_MAP) << BIT_SHIFT_TXDMA_HIQ_MAP)
+#define BIT_SHIFT_TXSC_40M	4
+#define BIT_MASK_TXSC_40M	0xf
+#define BIT_TXSC_40M(x)							       \
+	(((x) & BIT_MASK_TXSC_40M) << BIT_SHIFT_TXSC_40M)
+#define BIT_SHIFT_TXSC_20M	0
+#define BIT_MASK_TXSC_20M	0xf
+#define BIT_TXSC_20M(x)							       \
+	(((x) & BIT_MASK_TXSC_20M) << BIT_SHIFT_TXSC_20M)
+#define BIT_SHIFT_MAC_CLK_SEL	20
+#define MAC_CLK_HW_DEF_80M	0
+#define MAC_CLK_HW_DEF_40M	1
+#define MAC_CLK_HW_DEF_20M	2
+#define MAC_CLK_SPEED		80
+
+#define REG_AFE_CTRL1		0x0024
+
+#define REG_CR			0x0100
+#define REG_TRXFF_BNDY		0x0114
+#define REG_RXFF_BNDY		0x011C
+#define REG_PKTBUF_DBG_CTRL	0x0140
+#define REG_C2HEVT		0x01A0
+#define REG_HMETFR		0x01CC
+#define REG_HMEBOX0		0x01D0
+#define REG_HMEBOX1		0x01D4
+#define REG_HMEBOX2		0x01D8
+#define REG_HMEBOX3		0x01DC
+#define REG_HMEBOX0_EX		0x01F0
+#define REG_HMEBOX1_EX		0x01F4
+#define REG_HMEBOX2_EX		0x01F8
+#define REG_HMEBOX3_EX		0x01FC
+
+#define REG_FIFOPAGE_CTRL_2	0x0204
+#define BIT_MASK_BCN_HEAD_1_V1	0xfff
+#define REG_AUTO_LLT_V1		0x0208
+#define BIT_AUTO_INIT_LLT_V1	BIT(0)
+#define REG_TXDMA_OFFSET_CHK	0x020C
+#define REG_TXDMA_STATUS	0x0210
+#define REG_RQPN_CTRL_1		0x0228
+#define REG_RQPN_CTRL_2		0x022C
+#define REG_FIFOPAGE_INFO_1	0x0230
+#define REG_FIFOPAGE_INFO_2	0x0234
+#define REG_FIFOPAGE_INFO_3	0x0238
+#define REG_FIFOPAGE_INFO_4	0x023C
+#define REG_FIFOPAGE_INFO_5	0x0240
+#define REG_H2C_HEAD		0x0244
+#define REG_H2C_TAIL		0x0248
+#define REG_H2C_READ_ADDR	0x024C
+#define REG_H2C_INFO		0x0254
+
+#define REG_FWHW_TXQ_CTRL	0x0420
+#define REG_BCNQ_BDNY_V1	0x0424
+#define REG_LIFETIME_EN		0x0426
+#define REG_SPEC_SIFS		0x0428
+#define REG_DARFRC		0x0430
+#define REG_DARFRCH		0x0434
+#define REG_RARFRCH		0x043C
+#define REG_ARFR0		0x0444
+#define REG_ARFRH0		0x0448
+#define REG_ARFR1_V1		0x044C
+#define REG_ARFRH1_V1		0x0450
+#define REG_CCK_CHECK		0x0454
+#define REG_AMPDU_MAX_TIME_V1	0x0455
+#define REG_BCNQ1_BDNY_V1	0x0456
+#define REG_TX_HANG_CTRL	0x045E
+#define BIT_EN_EOF_V1		BIT(2)
+#define REG_DATA_SC		0x0483
+#define REG_ARFR4		0x049C
+#define REG_ARFRH4		0x04A0
+#define REG_ARFR5		0x04A4
+#define REG_ARFRH5		0x04A8
+#define REG_SW_AMPDU_BURST_MODE_CTRL 0x04BC
+#define REG_PROT_MODE_CTRL	0x04C8
+#define REG_BAR_MODE_CTRL	0x04CC
+#define REG_PRECNT_CTRL		0x04E5
+#define BIT_EN_PRECNT		BIT(11)
+
+#define REG_EDCA_VO_PARAM	0x0500
+#define REG_EDCA_VI_PARAM	0x0504
+#define REG_EDCA_BE_PARAM	0x0508
+#define REG_EDCA_BK_PARAM	0x050C
+#define REG_PIFS		0x0512
+#define REG_SIFS		0x0514
+#define BIT_SHIFT_SIFS_OFDM_CTX	8
+#define BIT_SHIFT_SIFS_CCK_TRX	16
+#define BIT_SHIFT_SIFS_OFDM_TRX	24
+#define REG_SLOT		0x051B
+#define REG_TX_PTCL_CTRL	0x0520
+#define REG_TXPAUSE		0x0522
+#define REG_RD_CTRL		0x0524
+#define REG_TBTT_PROHIBIT	0x0540
+#define BIT_SHIFT_TBTT_HOLD_TIME_AP 8
+#define REG_RD_NAV_NXT		0x0544
+#define REG_BCN_CTRL		0x0550
+#define BIT_EN_BCN_FUNCTION	BIT(3)
+#define REG_BCN_CTRL_CLINT0	0x0551
+#define REG_DRVERLYINT		0x0558
+#define REG_BCNDMATIM		0x0559
+#define REG_USTIME_TSF		0x055C
+#define REG_BCN_MAX_ERR		0x055D
+#define REG_RXTSF_OFFSET_CCK	0x055E
+#define REG_MISC_CTRL		0x0577
+#define REG_TIMER0_SRC_SEL	0x05B4
+
+#define REG_TCR			0x0604
+#define REG_RCR			0x0608
+#define BIT_APP_FCS		BIT(31)
+#define BIT_APP_MIC		BIT(30)
+#define BIT_APP_ICV		BIT(29)
+#define BIT_APP_PHYSTS		BIT(28)
+#define BIT_APP_BASSN		BIT(27)
+#define BIT_VHT_DACK		BIT(26)
+#define BIT_TCPOFLD_EN		BIT(25)
+#define BIT_ENMBID		BIT(24)
+#define BIT_LSIGEN		BIT(23)
+#define BIT_MFBEN		BIT(22)
+#define BIT_DISCHKPPDLLEN	BIT(21)
+#define BIT_PKTCTL_DLEN		BIT(20)
+#define BIT_TIM_PARSER_EN	BIT(18)
+#define BIT_BC_MD_EN		BIT(17)
+#define BIT_UC_MD_EN		BIT(16)
+#define BIT_RXSK_PERPKT		BIT(15)
+#define BIT_HTC_LOC_CTRL	BIT(14)
+#define BIT_RPFM_CAM_ENABLE	BIT(12)
+#define BIT_TA_BCN		BIT(11)
+#define BIT_DISDECMYPKT		BIT(10)
+#define BIT_AICV		BIT(9)
+#define BIT_ACRC32		BIT(8)
+#define BIT_CBSSID_BCN		BIT(7)
+#define BIT_CBSSID_DATA		BIT(6)
+#define BIT_APWRMGT		BIT(5)
+#define BIT_ADD3		BIT(4)
+#define BIT_AB			BIT(3)
+#define BIT_AM			BIT(2)
+#define BIT_APM			BIT(1)
+#define BIT_AAP			BIT(0)
+#define REG_RX_PKT_LIMIT	0x060C
+#define REG_RX_DRVINFO_SZ	0x060F
+#define BIT_APP_PHYSTS		BIT(28)
+#define REG_USTIME_EDCA		0x0638
+#define REG_RESP_SIFS_CCK	0x063C
+#define REG_RESP_SIFS_OFDM	0x063E
+#define REG_ACKTO		0x0640
+#define REG_EIFS		0x0642
+#define REG_NAV_CTRL		0x0650
+#define REG_WMAC_TRXPTCL_CTL	0x0668
+#define REG_WMAC_TRXPTCL_CTL_H	0x066C
+#define REG_RXFLTMAP0		0x06A0
+#define REG_RXFLTMAP1		0x06A2
+#define REG_RXFLTMAP2		0x06A4
+#define REG_BBPSF_CTRL		0x06DC
+
+#define REG_WMAC_OPTION_FUNCTION 0x07D0
+#define REG_WMAC_OPTION_FUNCTION_1 0x07D4
+
+#define REG_CPU_DMEM_CON	0x1080
+#define BIT_WL_PLATFORM_RST	BIT(16)
+#define BIT_WL_SECURITY_CLK	BIT(15)
+#define BIT_DDMA_EN		BIT(8)
+
+#define REG_H2C_PKT_READADDR	0x10D0
+#define REG_H2C_PKT_WRITEADDR	0x10D4
+#define REG_FW_DBG7		0x10FC
+
+#define REG_CR_EXT		0x1100
+
+#define REG_DDMA_CH0SA		0x1200
+#define REG_DDMA_CH0DA		0x1204
+#define REG_DDMA_CH0CTRL	0x1208
+#define BIT_DDMACH0_OWN		BIT(31)
+#define BIT_DDMACH0_CHKSUM_EN	BIT(29)
+#define BIT_DDMACH0_CHKSUM_STS	BIT(27)
+#define BIT_DDMACH0_RESET_CHKSUM_STS BIT(25)
+#define BIT_DDMACH0_CHKSUM_CONT	BIT(24)
+#define BIT_MASK_DDMACH0_DLEN	0x3ffff
+
+#define REG_H2CQ_CSR		0x1330
+#define REG_FAST_EDCA_VOVI_SETTING 0x1448
+#define REG_FAST_EDCA_BEBK_SETTING 0x144C
+
+#define REG_RXPSF_CTRL		0x1610
+#define BIT_RXGCK_FIFOTHR_EN	BIT(28)
+
+#define BIT_SHIFT_RXGCK_VHT_FIFOTHR 26
+#define BIT_MASK_RXGCK_VHT_FIFOTHR 0x3
+#define BIT_RXGCK_VHT_FIFOTHR(x)                                               \
+	(((x) & BIT_MASK_RXGCK_VHT_FIFOTHR) << BIT_SHIFT_RXGCK_VHT_FIFOTHR)
+#define BITS_RXGCK_VHT_FIFOTHR                                                 \
+	(BIT_MASK_RXGCK_VHT_FIFOTHR << BIT_SHIFT_RXGCK_VHT_FIFOTHR)
+#define BIT_CLEAR_RXGCK_VHT_FIFOTHR(x) ((x) & (~BITS_RXGCK_VHT_FIFOTHR))
+#define BIT_GET_RXGCK_VHT_FIFOTHR(x)                                           \
+	(((x) >> BIT_SHIFT_RXGCK_VHT_FIFOTHR) & BIT_MASK_RXGCK_VHT_FIFOTHR)
+#define BIT_SET_RXGCK_VHT_FIFOTHR(x, v)                                        \
+	(BIT_CLEAR_RXGCK_VHT_FIFOTHR(x) | BIT_RXGCK_VHT_FIFOTHR(v))
+
+#define BIT_SHIFT_RXGCK_HT_FIFOTHR 24
+#define BIT_MASK_RXGCK_HT_FIFOTHR 0x3
+#define BIT_RXGCK_HT_FIFOTHR(x)                                                \
+	(((x) & BIT_MASK_RXGCK_HT_FIFOTHR) << BIT_SHIFT_RXGCK_HT_FIFOTHR)
+#define BITS_RXGCK_HT_FIFOTHR                                                  \
+	(BIT_MASK_RXGCK_HT_FIFOTHR << BIT_SHIFT_RXGCK_HT_FIFOTHR)
+#define BIT_CLEAR_RXGCK_HT_FIFOTHR(x) ((x) & (~BITS_RXGCK_HT_FIFOTHR))
+#define BIT_GET_RXGCK_HT_FIFOTHR(x)                                            \
+	(((x) >> BIT_SHIFT_RXGCK_HT_FIFOTHR) & BIT_MASK_RXGCK_HT_FIFOTHR)
+#define BIT_SET_RXGCK_HT_FIFOTHR(x, v)                                         \
+	(BIT_CLEAR_RXGCK_HT_FIFOTHR(x) | BIT_RXGCK_HT_FIFOTHR(v))
+
+#define BIT_SHIFT_RXGCK_OFDM_FIFOTHR 22
+#define BIT_MASK_RXGCK_OFDM_FIFOTHR 0x3
+#define BIT_RXGCK_OFDM_FIFOTHR(x)                                              \
+	(((x) & BIT_MASK_RXGCK_OFDM_FIFOTHR) << BIT_SHIFT_RXGCK_OFDM_FIFOTHR)
+#define BITS_RXGCK_OFDM_FIFOTHR                                                \
+	(BIT_MASK_RXGCK_OFDM_FIFOTHR << BIT_SHIFT_RXGCK_OFDM_FIFOTHR)
+#define BIT_CLEAR_RXGCK_OFDM_FIFOTHR(x) ((x) & (~BITS_RXGCK_OFDM_FIFOTHR))
+#define BIT_GET_RXGCK_OFDM_FIFOTHR(x)                                          \
+	(((x) >> BIT_SHIFT_RXGCK_OFDM_FIFOTHR) & BIT_MASK_RXGCK_OFDM_FIFOTHR)
+#define BIT_SET_RXGCK_OFDM_FIFOTHR(x, v)                                       \
+	(BIT_CLEAR_RXGCK_OFDM_FIFOTHR(x) | BIT_RXGCK_OFDM_FIFOTHR(v))
+
+#define BIT_SHIFT_RXGCK_CCK_FIFOTHR 20
+#define BIT_MASK_RXGCK_CCK_FIFOTHR 0x3
+#define BIT_RXGCK_CCK_FIFOTHR(x)                                               \
+	(((x) & BIT_MASK_RXGCK_CCK_FIFOTHR) << BIT_SHIFT_RXGCK_CCK_FIFOTHR)
+#define BITS_RXGCK_CCK_FIFOTHR                                                 \
+	(BIT_MASK_RXGCK_CCK_FIFOTHR << BIT_SHIFT_RXGCK_CCK_FIFOTHR)
+#define BIT_CLEAR_RXGCK_CCK_FIFOTHR(x) ((x) & (~BITS_RXGCK_CCK_FIFOTHR))
+#define BIT_GET_RXGCK_CCK_FIFOTHR(x)                                           \
+	(((x) >> BIT_SHIFT_RXGCK_CCK_FIFOTHR) & BIT_MASK_RXGCK_CCK_FIFOTHR)
+#define BIT_SET_RXGCK_CCK_FIFOTHR(x, v)                                        \
+	(BIT_CLEAR_RXGCK_CCK_FIFOTHR(x) | BIT_RXGCK_CCK_FIFOTHR(v))
+
+#define BIT_SHIFT_RXGCK_ENTRY_DELAY 17
+#define BIT_MASK_RXGCK_ENTRY_DELAY 0x7
+#define BIT_RXGCK_ENTRY_DELAY(x)                                               \
+	(((x) & BIT_MASK_RXGCK_ENTRY_DELAY) << BIT_SHIFT_RXGCK_ENTRY_DELAY)
+#define BITS_RXGCK_ENTRY_DELAY                                                 \
+	(BIT_MASK_RXGCK_ENTRY_DELAY << BIT_SHIFT_RXGCK_ENTRY_DELAY)
+#define BIT_CLEAR_RXGCK_ENTRY_DELAY(x) ((x) & (~BITS_RXGCK_ENTRY_DELAY))
+#define BIT_GET_RXGCK_ENTRY_DELAY(x)                                           \
+	(((x) >> BIT_SHIFT_RXGCK_ENTRY_DELAY) & BIT_MASK_RXGCK_ENTRY_DELAY)
+#define BIT_SET_RXGCK_ENTRY_DELAY(x, v)                                        \
+	(BIT_CLEAR_RXGCK_ENTRY_DELAY(x) | BIT_RXGCK_ENTRY_DELAY(v))
+
+#define BIT_RXGCK_OFDMCCA_EN BIT(16)
+
+#define BIT_SHIFT_RXPSF_PKTLENTHR 13
+#define BIT_MASK_RXPSF_PKTLENTHR 0x7
+#define BIT_RXPSF_PKTLENTHR(x)                                                 \
+	(((x) & BIT_MASK_RXPSF_PKTLENTHR) << BIT_SHIFT_RXPSF_PKTLENTHR)
+#define BITS_RXPSF_PKTLENTHR                                                   \
+	(BIT_MASK_RXPSF_PKTLENTHR << BIT_SHIFT_RXPSF_PKTLENTHR)
+#define BIT_CLEAR_RXPSF_PKTLENTHR(x) ((x) & (~BITS_RXPSF_PKTLENTHR))
+#define BIT_GET_RXPSF_PKTLENTHR(x)                                             \
+	(((x) >> BIT_SHIFT_RXPSF_PKTLENTHR) & BIT_MASK_RXPSF_PKTLENTHR)
+#define BIT_SET_RXPSF_PKTLENTHR(x, v)                                          \
+	(BIT_CLEAR_RXPSF_PKTLENTHR(x) | BIT_RXPSF_PKTLENTHR(v))
+
+#define BIT_RXPSF_CTRLEN	BIT(12)
+#define BIT_RXPSF_VHTCHKEN	BIT(11)
+#define BIT_RXPSF_HTCHKEN	BIT(10)
+#define BIT_RXPSF_OFDMCHKEN	BIT(9)
+#define BIT_RXPSF_CCKCHKEN	BIT(8)
+#define BIT_RXPSF_OFDMRST	BIT(7)
+#define BIT_RXPSF_CCKRST	BIT(6)
+#define BIT_RXPSF_MHCHKEN	BIT(5)
+#define BIT_RXPSF_CONT_ERRCHKEN	BIT(4)
+#define BIT_RXPSF_ALL_ERRCHKEN	BIT(3)
+
+#define BIT_SHIFT_RXPSF_ERRTHR 0
+#define BIT_MASK_RXPSF_ERRTHR 0x7
+#define BIT_RXPSF_ERRTHR(x)                                                    \
+	(((x) & BIT_MASK_RXPSF_ERRTHR) << BIT_SHIFT_RXPSF_ERRTHR)
+#define BITS_RXPSF_ERRTHR (BIT_MASK_RXPSF_ERRTHR << BIT_SHIFT_RXPSF_ERRTHR)
+#define BIT_CLEAR_RXPSF_ERRTHR(x) ((x) & (~BITS_RXPSF_ERRTHR))
+#define BIT_GET_RXPSF_ERRTHR(x)                                                \
+	(((x) >> BIT_SHIFT_RXPSF_ERRTHR) & BIT_MASK_RXPSF_ERRTHR)
+#define BIT_SET_RXPSF_ERRTHR(x, v)                                             \
+	(BIT_CLEAR_RXPSF_ERRTHR(x) | BIT_RXPSF_ERRTHR(v))
+
+#define REG_RXPSF_TYPE_CTRL	0x1614
+
+#define REG_WL2LTECOEX_INDIRECT_ACCESS_CTRL_V1		0x1700
+#define REG_WL2LTECOEX_INDIRECT_ACCESS_WRITE_DATA_V1	0x1704
+#define REG_WL2LTECOEX_INDIRECT_ACCESS_READ_DATA_V1	0x1708
+#define LTECOEX_ACCESS_CTRL REG_WL2LTECOEX_INDIRECT_ACCESS_CTRL_V1
+#define LTECOEX_WRITE_DATA REG_WL2LTECOEX_INDIRECT_ACCESS_WRITE_DATA_V1
+#define LTECOEX_READ_DATA REG_WL2LTECOEX_INDIRECT_ACCESS_READ_DATA_V1
+
+#define RF_DTXLOK	0x08
+#define RF_CFGCH	0x18
+#define RF_LUTWA	0x33
+#define RF_LUTWD1	0x3e
+#define RF_LUTWD0	0x3f
+#define RF_XTALX2	0xb8
+#define RF_MALSEL	0xbe
+#define RF_LUTDBG	0xdf
+#define RF_LUTWE	0xef
+
+#endif