First of all I would like to thank you Felix for this great job! Please find one simple question below. 2016-09-05 12:51 GMT+03:00 Felix Fietkau <nbd@xxxxxxxx>: > From: Felix Fietkau <nbd@xxxxxxxxxxx> > > This is a 2x2 PCIe 802.11ac chipset by MediaTek > [skip] > +int mt76x2_init_hardware(struct mt76x2_dev *dev) > +{ > + static const u16 beacon_offsets[16] = { > + /* 1024 byte per beacon */ > + 0xc000, > + 0xc400, > + 0xc800, > + 0xcc00, > + 0xd000, > + 0xd400, > + 0xd800, > + 0xdc00, > + > + /* BSS idx 8-15 not used for beacons */ > + 0xc000, > + 0xc000, > + 0xc000, > + 0xc000, > + 0xc000, > + 0xc000, > + 0xc000, > + 0xc000, > + }; > + u32 val; > + int ret; > + > + dev->beacon_offsets = beacon_offsets; > + tasklet_init(&dev->pre_tbtt_tasklet, mt76x2_pre_tbtt_tasklet, > + (unsigned long) dev); > + > + dev->chainmask = 0x202; > + dev->global_wcid.idx = 255; > + dev->global_wcid.hw_key_idx = -1; > + dev->slottime = 9; > + > + val = mt76_rr(dev, MT_WPDMA_GLO_CFG); > + val &= MT_WPDMA_GLO_CFG_DMA_BURST_SIZE | > + MT_WPDMA_GLO_CFG_BIG_ENDIAN | > + MT_WPDMA_GLO_CFG_HDR_SEG_LEN; > + val |= MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE; > + mt76_wr(dev, MT_WPDMA_GLO_CFG, val); > + > + mt76x2_reset_wlan(dev, true); > + mt76x2_power_on(dev); > + > + ret = mt76x2_eeprom_init(dev); > + if (ret) > + return ret; > + > + ret = mt76x2_mac_reset(dev, true); > + if (ret) > + return ret; > + > + ret = mt76x2_dma_init(dev); > + if (ret) > + return ret; > + > + set_bit(MT76_STATE_INITIALIZED, &dev->mt76.state); > + ret = mt76x2_mac_start(dev); > + if (ret) > + return ret; > + > + ret = mt76x2_mcu_init(dev); > + if (ret) > + return ret; > + > + mt76x2_mac_stop(dev, false); > + dev->rxfilter = mt76_rr(dev, MT_RX_FILTR_CFG); > + > + return 0; > +} [skip] > + > +int mt76x2_register_device(struct mt76x2_dev *dev) > +{ > + struct ieee80211_hw *hw = mt76_hw(dev); > + struct wiphy *wiphy = hw->wiphy; > + void *status_fifo; > + int fifo_size; > + int i, ret; > + > + fifo_size = roundup_pow_of_two(32 * sizeof(struct mt76x2_tx_status)); > + status_fifo = devm_kzalloc(dev->mt76.dev, fifo_size, GFP_KERNEL); > + if (!status_fifo) > + return -ENOMEM; > + > + kfifo_init(&dev->txstatus_fifo, status_fifo, fifo_size); > + > + ret = mt76x2_init_hardware(dev); > + if (ret) > + return ret; > + > + hw->queues = 4; > + hw->max_rates = 1; > + hw->max_report_rates = 7; > + hw->max_rate_tries = 1; > + hw->extra_tx_headroom = 2; > + > + hw->sta_data_size = sizeof(struct mt76x2_sta); > + hw->vif_data_size = sizeof(struct mt76x2_vif); > + > + for (i = 0; i < ARRAY_SIZE(dev->macaddr_list); i++) { > + u8 *addr = dev->macaddr_list[i].addr; > + > + memcpy(addr, dev->mt76.macaddr, ETH_ALEN); > + > + if (!i) > + continue; > + > + addr[0] |= BIT(1); > + addr[0] ^= ((i - 1) << 2); > + } > + wiphy->addresses = dev->macaddr_list; > + wiphy->n_addresses = ARRAY_SIZE(dev->macaddr_list); > + > + wiphy->iface_combinations = if_comb; > + wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); > + > + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS); > + > + ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES); > + INIT_DELAYED_WORK(&dev->cal_work, mt76x2_phy_calibrate); > + INIT_DELAYED_WORK(&dev->mac_work, mt76x2_mac_work); > + > + dev->mt76.sband_2g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; > + dev->mt76.sband_5g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; > + > + ret = mt76_register_device(&dev->mt76, true, mt76x2_rates, > + ARRAY_SIZE(mt76x2_rates)); > + if (ret) > + goto fail; > + > + mt76x2_init_debugfs(dev); > + > + return 0; > + > +fail: > + mt76x2_stop_hardware(dev); > + return ret; > +} Just curious, almost full chip initialization performed in probe procedure, why not do that in start() callback? In such case we could fully restart chip without module reloading, just with ifdown/ifup circle. -- Sergey