init.c 13.1 KB
Newer Older
S
Stanislaw Gruszka 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
 * (c) Copyright 2002-2010, Ralink Technology, Inc.
 * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
 * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
 * Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2
 * as published by the Free Software Foundation
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include "mt76x0.h"
#include "eeprom.h"
#include "trace.h"
#include "mcu.h"
21
#include "../mt76x02_util.h"
S
Stanislaw Gruszka 已提交
22 23 24

#include "initvals.h"

25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
static void mt76x0_vht_cap_mask(struct ieee80211_supported_band *sband)
{
	struct ieee80211_sta_vht_cap *vht_cap = &sband->vht_cap;
	u16 mcs_map = 0;
	int i;

	vht_cap->cap &= ~IEEE80211_VHT_CAP_RXLDPC;
	for (i = 0; i < 8; i++) {
		if (!i)
			mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_7 << (i * 2));
		else
			mcs_map |=
				(IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 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);
}

S
Stanislaw Gruszka 已提交
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
static void
mt76x0_set_wlan_state(struct mt76x0_dev *dev, u32 val, bool enable)
{
	int i;

	/* Note: we don't turn off WLAN_CLK because that makes the device
	 *	 not respond properly on the probe path.
	 *	 In case anyone (PSM?) wants to use this function we can
	 *	 bring the clock stuff back and fixup the probe path.
	 */

	if (enable)
		val |= (MT_WLAN_FUN_CTRL_WLAN_EN |
			MT_WLAN_FUN_CTRL_WLAN_CLK_EN);
	else
		val &= ~(MT_WLAN_FUN_CTRL_WLAN_EN);

	mt76_wr(dev, MT_WLAN_FUN_CTRL, val);
	udelay(20);

	if (!enable)
		return;

	for (i = 200; i; i--) {
		val = mt76_rr(dev, MT_CMB_CTRL);

		if (val & MT_CMB_CTRL_XTAL_RDY && val & MT_CMB_CTRL_PLL_LD)
			break;

		udelay(20);
	}

	/* Note: vendor driver tries to disable/enable wlan here and retry
	 *       but the code which does it is so buggy it must have never
	 *       triggered, so don't bother.
	 */
	if (!i)
		dev_err(dev->mt76.dev, "Error: PLL and XTAL check failed!\n");
}

83
void mt76x0_chip_onoff(struct mt76x0_dev *dev, bool enable, bool reset)
S
Stanislaw Gruszka 已提交
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
{
	u32 val;

	mutex_lock(&dev->hw_atomic_mutex);

	val = mt76_rr(dev, MT_WLAN_FUN_CTRL);

	if (reset) {
		val |= MT_WLAN_FUN_CTRL_GPIO_OUT_EN;
		val &= ~MT_WLAN_FUN_CTRL_FRC_WL_ANT_SEL;

		if (val & MT_WLAN_FUN_CTRL_WLAN_EN) {
			val |= (MT_WLAN_FUN_CTRL_WLAN_RESET |
				MT_WLAN_FUN_CTRL_WLAN_RESET_RF);
			mt76_wr(dev, MT_WLAN_FUN_CTRL, val);
			udelay(20);

			val &= ~(MT_WLAN_FUN_CTRL_WLAN_RESET |
				 MT_WLAN_FUN_CTRL_WLAN_RESET_RF);
		}
	}

	mt76_wr(dev, MT_WLAN_FUN_CTRL, val);
	udelay(20);

	mt76x0_set_wlan_state(dev, val, enable);

	mutex_unlock(&dev->hw_atomic_mutex);
}
113
EXPORT_SYMBOL_GPL(mt76x0_chip_onoff);
S
Stanislaw Gruszka 已提交
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134

static void mt76x0_reset_csr_bbp(struct mt76x0_dev *dev)
{
	u32 val;

	val = mt76_rr(dev, MT_PBF_SYS_CTRL);
	val &= ~0x2000;
	mt76_wr(dev, MT_PBF_SYS_CTRL, val);

	mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR |
					 MT_MAC_SYS_CTRL_RESET_BBP);

	msleep(200);
}

static void mt76x0_init_usb_dma(struct mt76x0_dev *dev)
{
	u32 val;

	val = mt76_rr(dev, MT_USB_DMA_CFG);

135
	val |= MT_USB_DMA_CFG_RX_BULK_EN |
S
Stanislaw Gruszka 已提交
136
	       MT_USB_DMA_CFG_TX_BULK_EN;
137 138 139 140 141

	/* disable AGGR_BULK_RX in order to receive one
	 * frame in each rx urb and avoid copies
	 */
	val &= ~MT_USB_DMA_CFG_RX_BULK_AGG_EN;
S
Stanislaw Gruszka 已提交
142 143 144 145 146 147 148 149
	mt76_wr(dev, MT_USB_DMA_CFG, val);

	val = mt76_rr(dev, MT_COM_REG0);
	if (val & 1)
		dev_dbg(dev->mt76.dev, "MCU not ready\n");

	val = mt76_rr(dev, MT_USB_DMA_CFG);

150
	val |= MT_USB_DMA_CFG_RX_DROP_OR_PAD;
S
Stanislaw Gruszka 已提交
151
	mt76_wr(dev, MT_USB_DMA_CFG, val);
152
	val &= ~MT_USB_DMA_CFG_RX_DROP_OR_PAD;
S
Stanislaw Gruszka 已提交
153 154 155
	mt76_wr(dev, MT_USB_DMA_CFG, val);
}

156 157 158
#define RANDOM_WRITE(dev, tab)			\
	mt76_wr_rp(dev, MT_MCU_MEMMAP_WLAN,	\
		   tab, ARRAY_SIZE(tab))
S
Stanislaw Gruszka 已提交
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250

static int mt76x0_init_bbp(struct mt76x0_dev *dev)
{
	int ret, i;

	ret = mt76x0_wait_bbp_ready(dev);
	if (ret)
		return ret;

	RANDOM_WRITE(dev, mt76x0_bbp_init_tab);

	for (i = 0; i < ARRAY_SIZE(mt76x0_bbp_switch_tab); i++) {
		const struct mt76x0_bbp_switch_item *item = &mt76x0_bbp_switch_tab[i];
		const struct mt76_reg_pair *pair = &item->reg_pair;

		if (((RF_G_BAND | RF_BW_20) & item->bw_band) == (RF_G_BAND | RF_BW_20))
			mt76_wr(dev, pair->reg, pair->value);
	}

	RANDOM_WRITE(dev, mt76x0_dcoc_tab);

	return 0;
}

static void
mt76_init_beacon_offsets(struct mt76x0_dev *dev)
{
	u16 base = MT_BEACON_BASE;
	u32 regs[4] = {};
	int i;

	for (i = 0; i < 16; i++) {
		u16 addr = dev->beacon_offsets[i];

		regs[i / 4] |= ((addr - base) / 64) << (8 * (i % 4));
	}

	for (i = 0; i < 4; i++)
		mt76_wr(dev, MT_BCN_OFFSET(i), regs[i]);
}

static void mt76x0_init_mac_registers(struct mt76x0_dev *dev)
{
	u32 reg;

	RANDOM_WRITE(dev, common_mac_reg_table);

	mt76_init_beacon_offsets(dev);

	/* Enable PBF and MAC clock SYS_CTRL[11:10] = 0x3 */
	RANDOM_WRITE(dev, mt76x0_mac_reg_table);

	/* Release BBP and MAC reset MAC_SYS_CTRL[1:0] = 0x0 */
	reg = mt76_rr(dev, MT_MAC_SYS_CTRL);
	reg &= ~0x3;
	mt76_wr(dev, MT_MAC_SYS_CTRL, reg);

	if (is_mt7610e(dev)) {
		/* Disable COEX_EN */
		reg = mt76_rr(dev, MT_COEXCFG0);
		reg &= 0xFFFFFFFE;
		mt76_wr(dev, MT_COEXCFG0, reg);
	}

	/* Set 0x141C[15:12]=0xF */
	reg = mt76_rr(dev, MT_EXT_CCA_CFG);
	reg |= 0x0000F000;
	mt76_wr(dev, MT_EXT_CCA_CFG, reg);

	mt76_clear(dev, MT_FCE_L2_STUFF, MT_FCE_L2_STUFF_WR_MPDU_LEN_EN);

	/*
		TxRing 9 is for Mgmt frame.
		TxRing 8 is for In-band command frame.
		WMM_RG0_TXQMA: This register setting is for FCE to define the rule of TxRing 9.
		WMM_RG1_TXQMA: This register setting is for FCE to define the rule of TxRing 8.
	*/
	reg = mt76_rr(dev, MT_WMM_CTRL);
	reg &= ~0x000003FF;
	reg |= 0x00000201;
	mt76_wr(dev, MT_WMM_CTRL, reg);

	/* TODO: Probably not needed */
	mt76_wr(dev, 0x7028, 0);
	mt76_wr(dev, 0x7010, 0);
	mt76_wr(dev, 0x7024, 0);
	msleep(10);
}

static int mt76x0_init_wcid_mem(struct mt76x0_dev *dev)
{
	u32 *vals;
251
	int i;
S
Stanislaw Gruszka 已提交
252

253
	vals = kmalloc(sizeof(*vals) * MT76_N_WCIDS * 2, GFP_KERNEL);
S
Stanislaw Gruszka 已提交
254 255 256
	if (!vals)
		return -ENOMEM;

257
	for (i = 0; i < MT76_N_WCIDS; i++)  {
S
Stanislaw Gruszka 已提交
258 259 260 261
		vals[i * 2] = 0xffffffff;
		vals[i * 2 + 1] = 0x00ffffff;
	}

262
	mt76_wr_copy(dev, MT_WCID_ADDR_BASE, vals, MT76_N_WCIDS * 2);
S
Stanislaw Gruszka 已提交
263
	kfree(vals);
264
	return 0;
S
Stanislaw Gruszka 已提交
265 266
}

267
static void mt76x0_init_key_mem(struct mt76x0_dev *dev)
S
Stanislaw Gruszka 已提交
268 269 270
{
	u32 vals[4] = {};

271
	mt76_wr_copy(dev, MT_SKEY_MODE_BASE_0, vals, ARRAY_SIZE(vals));
S
Stanislaw Gruszka 已提交
272 273 274 275 276
}

static int mt76x0_init_wcid_attr_mem(struct mt76x0_dev *dev)
{
	u32 *vals;
277
	int i;
S
Stanislaw Gruszka 已提交
278

279
	vals = kmalloc(sizeof(*vals) * MT76_N_WCIDS * 2, GFP_KERNEL);
S
Stanislaw Gruszka 已提交
280 281 282
	if (!vals)
		return -ENOMEM;

283
	for (i = 0; i < MT76_N_WCIDS * 2; i++)
S
Stanislaw Gruszka 已提交
284 285
		vals[i] = 1;

286
	mt76_wr_copy(dev, MT_WCID_ATTR_BASE, vals, MT76_N_WCIDS * 2);
S
Stanislaw Gruszka 已提交
287
	kfree(vals);
288
	return 0;
S
Stanislaw Gruszka 已提交
289 290 291 292
}

static void mt76x0_reset_counters(struct mt76x0_dev *dev)
{
293 294 295 296 297 298
	mt76_rr(dev, MT_RX_STAT_0);
	mt76_rr(dev, MT_RX_STAT_1);
	mt76_rr(dev, MT_RX_STAT_2);
	mt76_rr(dev, MT_TX_STA_0);
	mt76_rr(dev, MT_TX_STA_1);
	mt76_rr(dev, MT_TX_STA_2);
S
Stanislaw Gruszka 已提交
299 300 301 302 303 304 305 306 307 308
}

int mt76x0_mac_start(struct mt76x0_dev *dev)
{
	mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX);

	if (!mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_BUSY |
		       MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 200000))
		return -ETIMEDOUT;

309
	dev->mt76.rxfilter = MT_RX_FILTR_CFG_CRC_ERR |
S
Stanislaw Gruszka 已提交
310 311 312 313 314 315
		MT_RX_FILTR_CFG_PHY_ERR | MT_RX_FILTR_CFG_PROMISC |
		MT_RX_FILTR_CFG_VER_ERR | MT_RX_FILTR_CFG_DUP |
		MT_RX_FILTR_CFG_CFACK | MT_RX_FILTR_CFG_CFEND |
		MT_RX_FILTR_CFG_ACK | MT_RX_FILTR_CFG_CTS |
		MT_RX_FILTR_CFG_RTS | MT_RX_FILTR_CFG_PSPOLL |
		MT_RX_FILTR_CFG_BA | MT_RX_FILTR_CFG_CTRL_RSV;
316
	mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter);
S
Stanislaw Gruszka 已提交
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377

	mt76_wr(dev, MT_MAC_SYS_CTRL,
		   MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX);

	if (!mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_BUSY |
		       MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 50))
		return -ETIMEDOUT;

	return 0;
}

static void mt76x0_mac_stop_hw(struct mt76x0_dev *dev)
{
	int i, ok;

	if (test_bit(MT76_REMOVED, &dev->mt76.state))
		return;

	mt76_clear(dev, MT_BEACON_TIME_CFG, MT_BEACON_TIME_CFG_TIMER_EN |
		   MT_BEACON_TIME_CFG_SYNC_MODE | MT_BEACON_TIME_CFG_TBTT_EN |
		   MT_BEACON_TIME_CFG_BEACON_TX);

	if (!mt76_poll(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_TX_BUSY, 0, 1000))
		dev_warn(dev->mt76.dev, "Warning: TX DMA did not stop!\n");

	/* Page count on TxQ */
	i = 200;
	while (i-- && ((mt76_rr(dev, 0x0438) & 0xffffffff) ||
		       (mt76_rr(dev, 0x0a30) & 0x000000ff) ||
		       (mt76_rr(dev, 0x0a34) & 0x00ff00ff)))
		msleep(10);

	if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_TX, 0, 1000))
		dev_warn(dev->mt76.dev, "Warning: MAC TX did not stop!\n");

	mt76_clear(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_RX |
					 MT_MAC_SYS_CTRL_ENABLE_TX);

	/* Page count on RxQ */
	ok = 0;
	i = 200;
	while (i--) {
		if (!(mt76_rr(dev, MT_RXQ_STA) & 0x00ff0000) &&
		    !mt76_rr(dev, 0x0a30) &&
		    !mt76_rr(dev, 0x0a34)) {
			if (ok++ > 5)
				break;
			continue;
		}
		msleep(1);
	}

	if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_RX, 0, 1000))
		dev_warn(dev->mt76.dev, "Warning: MAC RX did not stop!\n");

	if (!mt76_poll(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_RX_BUSY, 0, 1000))
		dev_warn(dev->mt76.dev, "Warning: RX DMA did not stop!\n");
}

void mt76x0_mac_stop(struct mt76x0_dev *dev)
{
378 379 380
	cancel_delayed_work_sync(&dev->cal_work);
	cancel_delayed_work_sync(&dev->mac_work);
	mt76u_stop_stat_wk(&dev->mt76);
S
Stanislaw Gruszka 已提交
381 382
	mt76x0_mac_stop_hw(dev);
}
383
EXPORT_SYMBOL_GPL(mt76x0_mac_stop);
S
Stanislaw Gruszka 已提交
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399

int mt76x0_init_hardware(struct mt76x0_dev *dev)
{
	static const u16 beacon_offsets[16] = {
		/* 512 byte per beacon */
		0xc000,	0xc200,	0xc400,	0xc600,
		0xc800,	0xca00,	0xcc00,	0xce00,
		0xd000,	0xd200,	0xd400,	0xd600,
		0xd800,	0xda00,	0xdc00,	0xde00
	};
	int ret;

	dev->beacon_offsets = beacon_offsets;

	if (!mt76_poll_msec(dev, MT_WPDMA_GLO_CFG,
			    MT_WPDMA_GLO_CFG_TX_DMA_BUSY |
400 401
			    MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 100))
		return -EIO;
S
Stanislaw Gruszka 已提交
402 403

	/* Wait for ASIC ready after FW load. */
404 405
	if (!mt76x02_wait_for_mac(&dev->mt76))
		return -ETIMEDOUT;
S
Stanislaw Gruszka 已提交
406 407 408 409 410 411 412

	mt76x0_reset_csr_bbp(dev);
	mt76x0_init_usb_dma(dev);

	mt76_wr(dev, MT_HEADER_TRANS_CTRL_REG, 0x0);
	mt76_wr(dev, MT_TSO_CTRL, 0x0);

413
	ret = mt76x02_mcu_function_select(&dev->mt76, Q_SELECT, 1, false);
S
Stanislaw Gruszka 已提交
414
	if (ret)
415
		return ret;
416

S
Stanislaw Gruszka 已提交
417 418 419
	mt76x0_init_mac_registers(dev);

	if (!mt76_poll_msec(dev, MT_MAC_STATUS,
420 421
			    MT_MAC_STATUS_TX | MT_MAC_STATUS_RX, 0, 1000))
		return -EIO;
S
Stanislaw Gruszka 已提交
422 423 424

	ret = mt76x0_init_bbp(dev);
	if (ret)
425
		return ret;
S
Stanislaw Gruszka 已提交
426 427 428

	ret = mt76x0_init_wcid_mem(dev);
	if (ret)
429 430
		return ret;

431
	mt76x0_init_key_mem(dev);
432

S
Stanislaw Gruszka 已提交
433 434
	ret = mt76x0_init_wcid_attr_mem(dev);
	if (ret)
435
		return ret;
S
Stanislaw Gruszka 已提交
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451

	mt76_clear(dev, MT_BEACON_TIME_CFG, (MT_BEACON_TIME_CFG_TIMER_EN |
					     MT_BEACON_TIME_CFG_SYNC_MODE |
					     MT_BEACON_TIME_CFG_TBTT_EN |
					     MT_BEACON_TIME_CFG_BEACON_TX));

	mt76x0_reset_counters(dev);

	mt76_rmw(dev, MT_US_CYC_CFG, MT_US_CYC_CNT, 0x1e);

	mt76_wr(dev, MT_TXOP_CTRL_CFG,
		   FIELD_PREP(MT_TXOP_TRUN_EN, 0x3f) |
		   FIELD_PREP(MT_TXOP_EXT_CCA_DLY, 0x58));

	ret = mt76x0_eeprom_init(dev);
	if (ret)
452
		return ret;
S
Stanislaw Gruszka 已提交
453 454 455

	mt76x0_phy_init(dev);

456
	return 0;
S
Stanislaw Gruszka 已提交
457
}
458
EXPORT_SYMBOL_GPL(mt76x0_init_hardware);
S
Stanislaw Gruszka 已提交
459 460 461

void mt76x0_cleanup(struct mt76x0_dev *dev)
{
462
	clear_bit(MT76_STATE_INITIALIZED, &dev->mt76.state);
463
	mt76x0_chip_onoff(dev, false, false);
464
	mt76u_queues_deinit(&dev->mt76);
465
	mt76u_mcu_deinit(&dev->mt76);
S
Stanislaw Gruszka 已提交
466
}
467
EXPORT_SYMBOL_GPL(mt76x0_cleanup);
S
Stanislaw Gruszka 已提交
468

469 470
struct mt76x0_dev *
mt76x0_alloc_device(struct device *pdev, const struct mt76_driver_ops *drv_ops)
S
Stanislaw Gruszka 已提交
471 472
{
	struct mt76x0_dev *dev;
473
	struct mt76_dev *mdev;
S
Stanislaw Gruszka 已提交
474

475 476
	mdev = mt76_alloc_device(sizeof(*dev), &mt76x0_ops);
	if (!mdev)
S
Stanislaw Gruszka 已提交
477 478
		return NULL;

479
	mdev->dev = pdev;
480
	mdev->drv = drv_ops;
481 482

	dev = container_of(mdev, struct mt76x0_dev, mt76);
S
Stanislaw Gruszka 已提交
483 484 485 486 487 488 489 490
	mutex_init(&dev->reg_atomic_mutex);
	mutex_init(&dev->hw_atomic_mutex);
	spin_lock_init(&dev->mac_lock);
	spin_lock_init(&dev->con_mon_lock);
	atomic_set(&dev->avg_ampdu_len, 1);

	return dev;
}
491
EXPORT_SYMBOL_GPL(mt76x0_alloc_device);
S
Stanislaw Gruszka 已提交
492 493 494

int mt76x0_register_device(struct mt76x0_dev *dev)
{
495 496
	struct mt76_dev *mdev = &dev->mt76;
	struct ieee80211_hw *hw = mdev->hw;
S
Stanislaw Gruszka 已提交
497 498 499
	struct wiphy *wiphy = hw->wiphy;
	int ret;

500 501 502 503
	ret = mt76x0_init_hardware(dev);
	if (ret)
		return ret;

S
Stanislaw Gruszka 已提交
504 505 506
	/* Reserve WCID 0 for mcast - thanks to this APs WCID will go to
	 * entry no. 1 like it does in the vendor driver.
	 */
507
	mdev->wcid_mask[0] |= 1;
S
Stanislaw Gruszka 已提交
508 509

	/* init fake wcid for monitor interfaces */
510 511
	mdev->global_wcid.idx = 0xff;
	mdev->global_wcid.hw_key_idx = -1;
S
Stanislaw Gruszka 已提交
512

513 514
	/* init antenna configuration */
	mdev->antenna_mask = 1;
S
Stanislaw Gruszka 已提交
515 516 517 518 519

	hw->queues = 4;
	hw->max_rates = 1;
	hw->max_report_rates = 7;
	hw->max_rate_tries = 1;
520
	hw->extra_tx_headroom = sizeof(struct mt76x02_txwi) + 4 + 2;
S
Stanislaw Gruszka 已提交
521

522
	hw->sta_data_size = sizeof(struct mt76x02_sta);
523
	hw->vif_data_size = sizeof(struct mt76x02_vif);
S
Stanislaw Gruszka 已提交
524 525 526 527 528

	wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);

	INIT_DELAYED_WORK(&dev->mac_work, mt76x0_mac_work);

529 530
	ret = mt76_register_device(mdev, true, mt76x02_rates,
				   ARRAY_SIZE(mt76x02_rates));
S
Stanislaw Gruszka 已提交
531 532 533
	if (ret)
		return ret;

534 535 536 537
	/* overwrite unsupported features */
	if (mdev->cap.has_5ghz)
		mt76x0_vht_cap_mask(&dev->mt76.sband_5g.sband);

538
	/* check hw sg support in order to enable AMSDU */
539
	if (mt76u_check_sg(mdev))
540 541 542 543
		hw->max_tx_fragments = MT_SG_MAX_SIZE;
	else
		hw->max_tx_fragments = 1;

S
Stanislaw Gruszka 已提交
544 545 546 547
	mt76x0_init_debugfs(dev);

	return 0;
}
548
EXPORT_SYMBOL_GPL(mt76x0_register_device);