diff --git a/mt76.h b/mt76.h index d76762cb..0f53f520 100644 --- a/mt76.h +++ b/mt76.h @@ -123,7 +123,7 @@ struct mt76_txq { }; struct mt76_txwi_cache { - u32 txwi[6]; + u32 txwi[8]; dma_addr_t dma_addr; struct list_head list; }; diff --git a/mt7603.h b/mt7603.h index 547d43b5..7e3f74ac 100644 --- a/mt7603.h +++ b/mt7603.h @@ -89,6 +89,9 @@ void mt7603_dma_cleanup(struct mt7603_dev *dev); int mt7603_mcu_init(struct mt7603_dev *dev); int mt7603_tx_queue_mcu(struct mt7603_dev *dev, enum mt76_txq_id qid, struct sk_buff *skb); +int mt7603_tx_queue_skb(struct mt76_dev *cdev, struct mt76_queue *q, + struct sk_buff *skb, struct mt76_txwi_cache *t, + struct mt76_wcid *wcid, struct ieee80211_sta *sta); void mt7603_set_irq_mask(struct mt7603_dev *dev, u32 clear, u32 set); @@ -115,4 +118,8 @@ int mt7603_mcu_exit(struct mt7603_dev *dev); void mt7603_wtbl_init(struct mt7603_dev *dev, int idx, const u8 *addr); void mt7603_wtbl_clear(struct mt7603_dev *dev, int idx); +int mt7603_mac_write_txwi(struct mt76_dev *mdev, void *txwi_ptr, + struct sk_buff *skb, struct mt76_wcid *wcid, + struct ieee80211_sta *sta); + #endif diff --git a/mt7603_dma.c b/mt7603_dma.c index f8785b25..173410ff 100644 --- a/mt7603_dma.c +++ b/mt7603_dma.c @@ -36,6 +36,27 @@ mt7603_tx_queue_mcu(struct mt7603_dev *dev, enum mt76_txq_id qid, return 0; } +int +mt7603_tx_queue_skb(struct mt76_dev *cdev, struct mt76_queue *q, + struct sk_buff *skb, struct mt76_txwi_cache *t, + struct mt76_wcid *wcid, struct ieee80211_sta *sta) +{ + struct mt7603_dev *dev = container_of(cdev, struct mt7603_dev, mt76); + dma_addr_t addr; + int idx; + + addr = dma_map_single(dev->mt76.dev, skb->data, skb->len, DMA_TO_DEVICE); + if (dma_mapping_error(dev->mt76.dev, addr)) + return -ENOMEM; + + idx = mt76_queue_add_buf(dev, q, t->dma_addr, MT_TXD_SIZE, + addr, skb->len, 0); + q->entry[idx].skb = skb; + q->entry[idx].txwi = t; + + return idx; +} + static void mt7603_tx_cleanup_entry(struct mt76_dev *mdev, struct mt76_queue *q, struct mt76_queue_entry *e) diff --git a/mt7603_init.c b/mt7603_init.c index df90e9de..f090169a 100644 --- a/mt7603_init.c +++ b/mt7603_init.c @@ -18,6 +18,10 @@ struct mt7603_dev *mt7603_alloc_device(struct device *pdev) { + static const struct mt76_driver_ops drv_ops = { + .fill_txwi = mt7603_mac_write_txwi, + .tx_queue_skb = mt7603_tx_queue_skb, + }; struct ieee80211_hw *hw; struct mt7603_dev *dev; @@ -28,6 +32,7 @@ struct mt7603_dev *mt7603_alloc_device(struct device *pdev) dev = hw->priv; dev->mt76.dev = pdev; dev->mt76.hw = hw; + dev->mt76.drv = &drv_ops; return dev; } diff --git a/mt7603_mac.c b/mt7603_mac.c index d21a0f14..d47de63d 100644 --- a/mt7603_mac.c +++ b/mt7603_mac.c @@ -11,6 +11,7 @@ * GNU General Public License for more details. */ +#include #include "mt7603.h" #include "mt7603_mac.h" @@ -233,6 +234,122 @@ mt7603_mac_fill_rx(struct mt7603_dev *dev, struct sk_buff *skb) return 0; } +static u16 +mt7603_mac_tx_rate_val(struct mt7603_dev *dev, + const struct ieee80211_tx_rate *rate, u8 *nss, u8 *bw) +{ + u8 phy, rate_idx; + + *nss = 1; + *bw = 0; + if (rate->flags & IEEE80211_TX_RC_MCS) { + rate_idx = rate->idx; + *nss = 1 + (rate->idx >> 3); + phy = MT_PHY_TYPE_HT; + if (rate->flags & IEEE80211_TX_RC_GREEN_FIELD) + phy = MT_PHY_TYPE_HT_GF; + if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + *bw = 1; + } else { + const struct ieee80211_rate *r; + int band = dev->chandef.chan->band; + u16 val; + + r = &mt76_hw(dev)->wiphy->bands[band]->bitrates[rate->idx]; + if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) + val = r->hw_value_short; + else + val = r->hw_value; + + phy = val >> 8; + rate_idx = val & 0xff; + } + + return (MT76_SET(MT_TX_RATE_IDX, rate_idx) | + MT76_SET(MT_TX_RATE_MODE, phy)); +} + +int mt7603_mac_write_txwi(struct mt76_dev *mdev, void *txwi_ptr, + struct sk_buff *skb, struct mt76_wcid *wcid, + struct ieee80211_sta *sta) +{ + struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_tx_rate *rate = &info->control.rates[0]; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + __le32 *txwi = txwi_ptr; + int wlan_idx; + int hdr_len = ieee80211_get_hdrlen_from_skb(skb); + u8 frame_type, frame_subtype; + u8 nss, bw; + + if (wcid) + wlan_idx = wcid->idx; + else + wlan_idx = MT7603_WTBL_RESERVED; + + frame_type = MT76_GET(IEEE80211_FCTL_FTYPE, + le16_to_cpu(hdr->frame_control)); + frame_subtype = MT76_GET(IEEE80211_FCTL_STYPE, + le16_to_cpu(hdr->frame_control)); + + txwi[0] = cpu_to_le32( + MT76_SET(MT_TXD0_TX_BYTES, skb->len + MT_TXD_SIZE) | + MT76_SET(MT_TXD0_Q_IDX, skb_get_queue_mapping(skb)) + ); + txwi[1] = cpu_to_le32( + MT_TXD1_LONG_FORMAT | + MT76_SET(MT_TXD1_OWN_MAC, 0) | + MT76_SET(MT_TXD1_TID, skb->priority & + IEEE80211_QOS_CTL_TID_MASK) | + MT76_SET(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) | + MT76_SET(MT_TXD1_HDR_INFO, hdr_len / 2) | + MT76_SET(MT_TXD1_WLAN_IDX, wlan_idx) + ); + + if (info->flags & IEEE80211_TX_CTL_NO_ACK) + txwi[1] |= cpu_to_le32(MT_TXD1_NO_ACK); + + txwi[2] = cpu_to_le32( + MT76_SET(MT_TXD2_FRAME_TYPE, frame_type) | + MT76_SET(MT_TXD2_SUB_TYPE, frame_subtype) | + MT76_SET(MT_TXD2_MULTICAST, is_multicast_ether_addr(hdr->addr1)) + ); + if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) + txwi[2] |= cpu_to_le32(MT_TXD2_BA_DISABLE); + + txwi[3] = cpu_to_le32(MT76_SET(MT_TXD3_REM_TX_COUNT, 0xf)); + txwi[4] = 0; + txwi[5] = cpu_to_le32(MT_TXD5_TX_STATUS_HOST | MT_TXD5_SW_POWER_MGMT); + txwi[6] = 0; + + spin_lock_bh(&dev->mt76.lock); + if (rate->idx >= 0 && !rate->count) { + u16 rateval = mt7603_mac_tx_rate_val(dev, rate, &nss, &bw); + + if ((info->flags & IEEE80211_TX_CTL_STBC) && nss == 1) + rateval |= MT_TX_RATE_STBC; + + txwi[6] |= cpu_to_le32( + MT_TXD6_FIXED_RATE | + MT_TXD6_FIXED_BW | + MT76_SET(MT_TXD6_BW, bw) | + MT76_SET(MT_TXD6_TX_RATE, rateval) + ); + + if (rate->flags & IEEE80211_TX_RC_SHORT_GI) + txwi[6] |= cpu_to_le32(MT_TXD6_SGI); + } + spin_unlock_bh(&dev->mt76.lock); + + if (info->flags & IEEE80211_TX_CTL_LDPC) + txwi[6] |= cpu_to_le32(MT_TXD6_LDPC); + + txwi[7] = 0; + + return 0; +} + void mt7603_mac_start(struct mt7603_dev *dev) { mt76_clear(dev, MT_WF_ARB_SCR, MT_WF_ARB_TX_DISABLE | MT_WF_ARB_RX_DISABLE); diff --git a/mt7603_mac.h b/mt7603_mac.h index fa4f38f0..eaf75e27 100644 --- a/mt7603_mac.h +++ b/mt7603_mac.h @@ -129,6 +129,15 @@ enum rx_pkt_type { #define MT_RXV6_NF1 GENMASK(15, 8) #define MT_RXV6_NF0 GENMASK(7, 0) +enum mt7603_tx_header_format { + MT_HDR_FORMAT_802_3, + MT_HDR_FORMAT_CMD, + MT_HDR_FORMAT_802_11, + MT_HDR_FORMAT_802_11_EXT, +}; + +#define MT_TXD_SIZE (8 * 4) + #define MT_TXD0_P_IDX BIT(31) #define MT_TXD0_Q_IDX GENMASK(30, 27) #define MT_TXD0_UTXB BIT(26) @@ -143,7 +152,7 @@ enum rx_pkt_type { #define MT_TXD1_TID GENMASK(22, 20) #define MT_TXD1_NO_ACK BIT(19) #define MT_TXD1_HDR_PAD GENMASK(18, 16) -#define MT_TXD1_FT BIT(15) +#define MT_TXD1_LONG_FORMAT BIT(15) #define MT_TXD1_HDR_FORMAT GENMASK(14, 13) #define MT_TXD1_HDR_INFO GENMASK(12, 8) #define MT_TXD1_WLAN_IDX GENMASK(7, 0) @@ -190,8 +199,14 @@ enum rx_pkt_type { #define MT_TXD6_DYN_BW BIT(15) #define MT_TXD6_ANT_PRI GENMASK(14, 12) #define MT_TXD6_SPE_EN BIT(11) -#define MT_TXD6_BW GENMASK(10, 8) +#define MT_TXD6_FIXED_BW BIT(10) +#define MT_TXD6_BW GENMASK(9, 8) #define MT_TXD6_ANT_ID GENMASK(7, 2) #define MT_TXD6_FIXED_RATE BIT(0) +#define MT_TX_RATE_STBC BIT(11) +#define MT_TX_RATE_NSS GENAMSK(10, 9) +#define MT_TX_RATE_MODE GENMASK(8, 6) +#define MT_TX_RATE_IDX GENMASK(5, 0) + #endif