18c2ecf20Sopenharmony_ci 28c2ecf20Sopenharmony_ci/* Linux device driver for RTL8180 / RTL8185 / RTL8187SE 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright 2007 Michael Wu <flamingice@sourmilk.net> 58c2ecf20Sopenharmony_ci * Copyright 2007,2014 Andrea Merello <andrea.merello@gmail.com> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Based on the r8180 driver, which is: 88c2ecf20Sopenharmony_ci * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Thanks to Realtek for their support! 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci ************************************************************************ 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * The driver was extended to the RTL8187SE in 2014 by 158c2ecf20Sopenharmony_ci * Andrea Merello <andrea.merello@gmail.com> 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * based also on: 188c2ecf20Sopenharmony_ci * - portions of rtl8187se Linux staging driver, Copyright Realtek corp. 198c2ecf20Sopenharmony_ci * (available in drivers/staging/rtl8187se directory of Linux 3.14) 208c2ecf20Sopenharmony_ci * - other GPL, unpublished (until now), Linux driver code, 218c2ecf20Sopenharmony_ci * Copyright Larry Finger <Larry.Finger@lwfinger.net> 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * A huge thanks goes to Sara V. Nari who forgives me when I'm 248c2ecf20Sopenharmony_ci * sitting in front of my laptop at evening, week-end, night... 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci * A special thanks goes to Antonio Cuni, who helped me with 278c2ecf20Sopenharmony_ci * some python userspace stuff I used to debug RTL8187SE code, and who 288c2ecf20Sopenharmony_ci * bought a laptop with an unsupported Wi-Fi card some years ago... 298c2ecf20Sopenharmony_ci * 308c2ecf20Sopenharmony_ci * Thanks to Larry Finger for writing some code for rtl8187se and for 318c2ecf20Sopenharmony_ci * his suggestions. 328c2ecf20Sopenharmony_ci * 338c2ecf20Sopenharmony_ci * Thanks to Dan Carpenter for reviewing my initial patch and for his 348c2ecf20Sopenharmony_ci * suggestions. 358c2ecf20Sopenharmony_ci * 368c2ecf20Sopenharmony_ci * Thanks to Bernhard Schiffner for his help in testing and for his 378c2ecf20Sopenharmony_ci * suggestions. 388c2ecf20Sopenharmony_ci * 398c2ecf20Sopenharmony_ci ************************************************************************ 408c2ecf20Sopenharmony_ci * 418c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 428c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License version 2 as 438c2ecf20Sopenharmony_ci * published by the Free Software Foundation. 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 478c2ecf20Sopenharmony_ci#include <linux/pci.h> 488c2ecf20Sopenharmony_ci#include <linux/slab.h> 498c2ecf20Sopenharmony_ci#include <linux/delay.h> 508c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 518c2ecf20Sopenharmony_ci#include <linux/eeprom_93cx6.h> 528c2ecf20Sopenharmony_ci#include <linux/module.h> 538c2ecf20Sopenharmony_ci#include <net/mac80211.h> 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#include "rtl8180.h" 568c2ecf20Sopenharmony_ci#include "rtl8225.h" 578c2ecf20Sopenharmony_ci#include "sa2400.h" 588c2ecf20Sopenharmony_ci#include "max2820.h" 598c2ecf20Sopenharmony_ci#include "grf5101.h" 608c2ecf20Sopenharmony_ci#include "rtl8225se.h" 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ciMODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>"); 638c2ecf20Sopenharmony_ciMODULE_AUTHOR("Andrea Merello <andrea.merello@gmail.com>"); 648c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("RTL8180 / RTL8185 / RTL8187SE PCI wireless driver"); 658c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic const struct pci_device_id rtl8180_table[] = { 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci /* rtl8187se */ 708c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8199) }, 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci /* rtl8185 */ 738c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8185) }, 748c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_BELKIN, 0x700f) }, 758c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_BELKIN, 0x701f) }, 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci /* rtl8180 */ 788c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8180) }, 798c2ecf20Sopenharmony_ci { PCI_DEVICE(0x1799, 0x6001) }, 808c2ecf20Sopenharmony_ci { PCI_DEVICE(0x1799, 0x6020) }, 818c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x3300) }, 828c2ecf20Sopenharmony_ci { PCI_DEVICE(0x1186, 0x3301) }, 838c2ecf20Sopenharmony_ci { PCI_DEVICE(0x1432, 0x7106) }, 848c2ecf20Sopenharmony_ci { } 858c2ecf20Sopenharmony_ci}; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, rtl8180_table); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic const struct ieee80211_rate rtl818x_rates[] = { 908c2ecf20Sopenharmony_ci { .bitrate = 10, .hw_value = 0, }, 918c2ecf20Sopenharmony_ci { .bitrate = 20, .hw_value = 1, }, 928c2ecf20Sopenharmony_ci { .bitrate = 55, .hw_value = 2, }, 938c2ecf20Sopenharmony_ci { .bitrate = 110, .hw_value = 3, }, 948c2ecf20Sopenharmony_ci { .bitrate = 60, .hw_value = 4, }, 958c2ecf20Sopenharmony_ci { .bitrate = 90, .hw_value = 5, }, 968c2ecf20Sopenharmony_ci { .bitrate = 120, .hw_value = 6, }, 978c2ecf20Sopenharmony_ci { .bitrate = 180, .hw_value = 7, }, 988c2ecf20Sopenharmony_ci { .bitrate = 240, .hw_value = 8, }, 998c2ecf20Sopenharmony_ci { .bitrate = 360, .hw_value = 9, }, 1008c2ecf20Sopenharmony_ci { .bitrate = 480, .hw_value = 10, }, 1018c2ecf20Sopenharmony_ci { .bitrate = 540, .hw_value = 11, }, 1028c2ecf20Sopenharmony_ci}; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic const struct ieee80211_channel rtl818x_channels[] = { 1058c2ecf20Sopenharmony_ci { .center_freq = 2412 }, 1068c2ecf20Sopenharmony_ci { .center_freq = 2417 }, 1078c2ecf20Sopenharmony_ci { .center_freq = 2422 }, 1088c2ecf20Sopenharmony_ci { .center_freq = 2427 }, 1098c2ecf20Sopenharmony_ci { .center_freq = 2432 }, 1108c2ecf20Sopenharmony_ci { .center_freq = 2437 }, 1118c2ecf20Sopenharmony_ci { .center_freq = 2442 }, 1128c2ecf20Sopenharmony_ci { .center_freq = 2447 }, 1138c2ecf20Sopenharmony_ci { .center_freq = 2452 }, 1148c2ecf20Sopenharmony_ci { .center_freq = 2457 }, 1158c2ecf20Sopenharmony_ci { .center_freq = 2462 }, 1168c2ecf20Sopenharmony_ci { .center_freq = 2467 }, 1178c2ecf20Sopenharmony_ci { .center_freq = 2472 }, 1188c2ecf20Sopenharmony_ci { .center_freq = 2484 }, 1198c2ecf20Sopenharmony_ci}; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci/* Queues for rtl8187se card 1228c2ecf20Sopenharmony_ci * 1238c2ecf20Sopenharmony_ci * name | reg | queue 1248c2ecf20Sopenharmony_ci * BC | 7 | 6 1258c2ecf20Sopenharmony_ci * MG | 1 | 0 1268c2ecf20Sopenharmony_ci * HI | 6 | 1 1278c2ecf20Sopenharmony_ci * VO | 5 | 2 1288c2ecf20Sopenharmony_ci * VI | 4 | 3 1298c2ecf20Sopenharmony_ci * BE | 3 | 4 1308c2ecf20Sopenharmony_ci * BK | 2 | 5 1318c2ecf20Sopenharmony_ci * 1328c2ecf20Sopenharmony_ci * The complete map for DMA kick reg using use all queue is: 1338c2ecf20Sopenharmony_ci * static const int rtl8187se_queues_map[RTL8187SE_NR_TX_QUEUES] = 1348c2ecf20Sopenharmony_ci * {1, 6, 5, 4, 3, 2, 7}; 1358c2ecf20Sopenharmony_ci * 1368c2ecf20Sopenharmony_ci * .. but.. Because for mac80211 4 queues are enough for QoS we use this 1378c2ecf20Sopenharmony_ci * 1388c2ecf20Sopenharmony_ci * name | reg | queue 1398c2ecf20Sopenharmony_ci * BC | 7 | 4 <- currently not used yet 1408c2ecf20Sopenharmony_ci * MG | 1 | x <- Not used 1418c2ecf20Sopenharmony_ci * HI | 6 | x <- Not used 1428c2ecf20Sopenharmony_ci * VO | 5 | 0 <- used 1438c2ecf20Sopenharmony_ci * VI | 4 | 1 <- used 1448c2ecf20Sopenharmony_ci * BE | 3 | 2 <- used 1458c2ecf20Sopenharmony_ci * BK | 2 | 3 <- used 1468c2ecf20Sopenharmony_ci * 1478c2ecf20Sopenharmony_ci * Beacon queue could be used, but this is not finished yet. 1488c2ecf20Sopenharmony_ci * 1498c2ecf20Sopenharmony_ci * I thougth about using the other two queues but I decided not to do this: 1508c2ecf20Sopenharmony_ci * 1518c2ecf20Sopenharmony_ci * - I'm unsure whether the mac80211 will ever try to use more than 4 queues 1528c2ecf20Sopenharmony_ci * by itself. 1538c2ecf20Sopenharmony_ci * 1548c2ecf20Sopenharmony_ci * - I could route MGMT frames (currently sent over VO queue) to the MGMT 1558c2ecf20Sopenharmony_ci * queue but since mac80211 will do not know about it, I will probably gain 1568c2ecf20Sopenharmony_ci * some HW priority whenever the VO queue is not empty, but this gain is 1578c2ecf20Sopenharmony_ci * limited by the fact that I had to stop the mac80211 queue whenever one of 1588c2ecf20Sopenharmony_ci * the VO or MGMT queues is full, stopping also submitting of MGMT frame 1598c2ecf20Sopenharmony_ci * to the driver. 1608c2ecf20Sopenharmony_ci * 1618c2ecf20Sopenharmony_ci * - I don't know how to set in the HW the contention window params for MGMT 1628c2ecf20Sopenharmony_ci * and HI-prio queues. 1638c2ecf20Sopenharmony_ci */ 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic const int rtl8187se_queues_map[RTL8187SE_NR_TX_QUEUES] = {5, 4, 3, 2, 7}; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci/* Queues for rtl8180/rtl8185 cards 1688c2ecf20Sopenharmony_ci * 1698c2ecf20Sopenharmony_ci * name | reg | prio 1708c2ecf20Sopenharmony_ci * BC | 7 | 3 1718c2ecf20Sopenharmony_ci * HI | 6 | 0 1728c2ecf20Sopenharmony_ci * NO | 5 | 1 1738c2ecf20Sopenharmony_ci * LO | 4 | 2 1748c2ecf20Sopenharmony_ci * 1758c2ecf20Sopenharmony_ci * The complete map for DMA kick reg using all queue is: 1768c2ecf20Sopenharmony_ci * static const int rtl8180_queues_map[RTL8180_NR_TX_QUEUES] = {6, 5, 4, 7}; 1778c2ecf20Sopenharmony_ci * 1788c2ecf20Sopenharmony_ci * .. but .. Because the mac80211 needs at least 4 queues for QoS or 1798c2ecf20Sopenharmony_ci * otherwise QoS can't be done, we use just one. 1808c2ecf20Sopenharmony_ci * Beacon queue could be used, but this is not finished yet. 1818c2ecf20Sopenharmony_ci * Actual map is: 1828c2ecf20Sopenharmony_ci * 1838c2ecf20Sopenharmony_ci * name | reg | prio 1848c2ecf20Sopenharmony_ci * BC | 7 | 1 <- currently not used yet. 1858c2ecf20Sopenharmony_ci * HI | 6 | x <- not used 1868c2ecf20Sopenharmony_ci * NO | 5 | x <- not used 1878c2ecf20Sopenharmony_ci * LO | 4 | 0 <- used 1888c2ecf20Sopenharmony_ci */ 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic const int rtl8180_queues_map[RTL8180_NR_TX_QUEUES] = {4, 7}; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci/* LNA gain table for rtl8187se */ 1938c2ecf20Sopenharmony_cistatic const u8 rtl8187se_lna_gain[4] = {02, 17, 29, 39}; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_civoid rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 1988c2ecf20Sopenharmony_ci int i = 10; 1998c2ecf20Sopenharmony_ci u32 buf; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci buf = (data << 8) | addr; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->PHY[0], buf | 0x80); 2048c2ecf20Sopenharmony_ci while (i--) { 2058c2ecf20Sopenharmony_ci rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->PHY[0], buf); 2068c2ecf20Sopenharmony_ci if (rtl818x_ioread8(priv, &priv->map->PHY[2]) == (data & 0xFF)) 2078c2ecf20Sopenharmony_ci return; 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic void rtl8180_handle_rx(struct ieee80211_hw *dev) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 2148c2ecf20Sopenharmony_ci struct rtl818x_rx_cmd_desc *cmd_desc; 2158c2ecf20Sopenharmony_ci unsigned int count = 32; 2168c2ecf20Sopenharmony_ci u8 agc, sq; 2178c2ecf20Sopenharmony_ci s8 signal = 1; 2188c2ecf20Sopenharmony_ci dma_addr_t mapping; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci while (count--) { 2218c2ecf20Sopenharmony_ci void *entry = priv->rx_ring + priv->rx_idx * priv->rx_ring_sz; 2228c2ecf20Sopenharmony_ci struct sk_buff *skb = priv->rx_buf[priv->rx_idx]; 2238c2ecf20Sopenharmony_ci u32 flags, flags2, flags3 = 0; 2248c2ecf20Sopenharmony_ci u64 tsft; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) { 2278c2ecf20Sopenharmony_ci struct rtl8187se_rx_desc *desc = entry; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci flags = le32_to_cpu(desc->flags); 2308c2ecf20Sopenharmony_ci /* if ownership flag is set, then we can trust the 2318c2ecf20Sopenharmony_ci * HW has written other fields. We must not trust 2328c2ecf20Sopenharmony_ci * other descriptor data read before we checked (read) 2338c2ecf20Sopenharmony_ci * the ownership flag 2348c2ecf20Sopenharmony_ci */ 2358c2ecf20Sopenharmony_ci rmb(); 2368c2ecf20Sopenharmony_ci flags3 = le32_to_cpu(desc->flags3); 2378c2ecf20Sopenharmony_ci flags2 = le32_to_cpu(desc->flags2); 2388c2ecf20Sopenharmony_ci tsft = le64_to_cpu(desc->tsft); 2398c2ecf20Sopenharmony_ci } else { 2408c2ecf20Sopenharmony_ci struct rtl8180_rx_desc *desc = entry; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci flags = le32_to_cpu(desc->flags); 2438c2ecf20Sopenharmony_ci /* same as above */ 2448c2ecf20Sopenharmony_ci rmb(); 2458c2ecf20Sopenharmony_ci flags2 = le32_to_cpu(desc->flags2); 2468c2ecf20Sopenharmony_ci tsft = le64_to_cpu(desc->tsft); 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci if (flags & RTL818X_RX_DESC_FLAG_OWN) 2508c2ecf20Sopenharmony_ci return; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci if (unlikely(flags & (RTL818X_RX_DESC_FLAG_DMA_FAIL | 2538c2ecf20Sopenharmony_ci RTL818X_RX_DESC_FLAG_FOF | 2548c2ecf20Sopenharmony_ci RTL818X_RX_DESC_FLAG_RX_ERR))) 2558c2ecf20Sopenharmony_ci goto done; 2568c2ecf20Sopenharmony_ci else { 2578c2ecf20Sopenharmony_ci struct ieee80211_rx_status rx_status = {0}; 2588c2ecf20Sopenharmony_ci struct sk_buff *new_skb = dev_alloc_skb(MAX_RX_SIZE); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci if (unlikely(!new_skb)) 2618c2ecf20Sopenharmony_ci goto done; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci mapping = dma_map_single(&priv->pdev->dev, 2648c2ecf20Sopenharmony_ci skb_tail_pointer(new_skb), 2658c2ecf20Sopenharmony_ci MAX_RX_SIZE, DMA_FROM_DEVICE); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (dma_mapping_error(&priv->pdev->dev, mapping)) { 2688c2ecf20Sopenharmony_ci kfree_skb(new_skb); 2698c2ecf20Sopenharmony_ci dev_err(&priv->pdev->dev, "RX DMA map error\n"); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci goto done; 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci dma_unmap_single(&priv->pdev->dev, 2758c2ecf20Sopenharmony_ci *((dma_addr_t *)skb->cb), 2768c2ecf20Sopenharmony_ci MAX_RX_SIZE, DMA_FROM_DEVICE); 2778c2ecf20Sopenharmony_ci skb_put(skb, flags & 0xFFF); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci rx_status.antenna = (flags2 >> 15) & 1; 2808c2ecf20Sopenharmony_ci rx_status.rate_idx = (flags >> 20) & 0xF; 2818c2ecf20Sopenharmony_ci agc = (flags2 >> 17) & 0x7F; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci switch (priv->chip_family) { 2848c2ecf20Sopenharmony_ci case RTL818X_CHIP_FAMILY_RTL8185: 2858c2ecf20Sopenharmony_ci if (rx_status.rate_idx > 3) 2868c2ecf20Sopenharmony_ci signal = -clamp_t(u8, agc, 25, 90) - 9; 2878c2ecf20Sopenharmony_ci else 2888c2ecf20Sopenharmony_ci signal = -clamp_t(u8, agc, 30, 95); 2898c2ecf20Sopenharmony_ci break; 2908c2ecf20Sopenharmony_ci case RTL818X_CHIP_FAMILY_RTL8180: 2918c2ecf20Sopenharmony_ci sq = flags2 & 0xff; 2928c2ecf20Sopenharmony_ci signal = priv->rf->calc_rssi(agc, sq); 2938c2ecf20Sopenharmony_ci break; 2948c2ecf20Sopenharmony_ci case RTL818X_CHIP_FAMILY_RTL8187SE: 2958c2ecf20Sopenharmony_ci /* OFDM measure reported by HW is signed, 2968c2ecf20Sopenharmony_ci * in 0.5dBm unit, with zero centered @ -41dBm 2978c2ecf20Sopenharmony_ci * input signal. 2988c2ecf20Sopenharmony_ci */ 2998c2ecf20Sopenharmony_ci if (rx_status.rate_idx > 3) { 3008c2ecf20Sopenharmony_ci signal = (s8)((flags3 >> 16) & 0xff); 3018c2ecf20Sopenharmony_ci signal = signal / 2 - 41; 3028c2ecf20Sopenharmony_ci } else { 3038c2ecf20Sopenharmony_ci int idx, bb; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci idx = (agc & 0x60) >> 5; 3068c2ecf20Sopenharmony_ci bb = (agc & 0x1F) * 2; 3078c2ecf20Sopenharmony_ci /* bias + BB gain + LNA gain */ 3088c2ecf20Sopenharmony_ci signal = 4 - bb - rtl8187se_lna_gain[idx]; 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci break; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci rx_status.signal = signal; 3138c2ecf20Sopenharmony_ci rx_status.freq = dev->conf.chandef.chan->center_freq; 3148c2ecf20Sopenharmony_ci rx_status.band = dev->conf.chandef.chan->band; 3158c2ecf20Sopenharmony_ci rx_status.mactime = tsft; 3168c2ecf20Sopenharmony_ci rx_status.flag |= RX_FLAG_MACTIME_START; 3178c2ecf20Sopenharmony_ci if (flags & RTL818X_RX_DESC_FLAG_SPLCP) 3188c2ecf20Sopenharmony_ci rx_status.enc_flags |= RX_ENC_FLAG_SHORTPRE; 3198c2ecf20Sopenharmony_ci if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR) 3208c2ecf20Sopenharmony_ci rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); 3238c2ecf20Sopenharmony_ci ieee80211_rx_irqsafe(dev, skb); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci skb = new_skb; 3268c2ecf20Sopenharmony_ci priv->rx_buf[priv->rx_idx] = skb; 3278c2ecf20Sopenharmony_ci *((dma_addr_t *) skb->cb) = mapping; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci done: 3318c2ecf20Sopenharmony_ci cmd_desc = entry; 3328c2ecf20Sopenharmony_ci cmd_desc->rx_buf = cpu_to_le32(*((dma_addr_t *)skb->cb)); 3338c2ecf20Sopenharmony_ci cmd_desc->flags = cpu_to_le32(RTL818X_RX_DESC_FLAG_OWN | 3348c2ecf20Sopenharmony_ci MAX_RX_SIZE); 3358c2ecf20Sopenharmony_ci if (priv->rx_idx == 31) 3368c2ecf20Sopenharmony_ci cmd_desc->flags |= 3378c2ecf20Sopenharmony_ci cpu_to_le32(RTL818X_RX_DESC_FLAG_EOR); 3388c2ecf20Sopenharmony_ci priv->rx_idx = (priv->rx_idx + 1) % 32; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cistatic void rtl8180_handle_tx(struct ieee80211_hw *dev, unsigned int prio) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 3458c2ecf20Sopenharmony_ci struct rtl8180_tx_ring *ring = &priv->tx_ring[prio]; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci while (skb_queue_len(&ring->queue)) { 3488c2ecf20Sopenharmony_ci struct rtl8180_tx_desc *entry = &ring->desc[ring->idx]; 3498c2ecf20Sopenharmony_ci struct sk_buff *skb; 3508c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info; 3518c2ecf20Sopenharmony_ci u32 flags = le32_to_cpu(entry->flags); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci if (flags & RTL818X_TX_DESC_FLAG_OWN) 3548c2ecf20Sopenharmony_ci return; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci ring->idx = (ring->idx + 1) % ring->entries; 3578c2ecf20Sopenharmony_ci skb = __skb_dequeue(&ring->queue); 3588c2ecf20Sopenharmony_ci dma_unmap_single(&priv->pdev->dev, le32_to_cpu(entry->tx_buf), 3598c2ecf20Sopenharmony_ci skb->len, DMA_TO_DEVICE); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci info = IEEE80211_SKB_CB(skb); 3628c2ecf20Sopenharmony_ci ieee80211_tx_info_clear_status(info); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && 3658c2ecf20Sopenharmony_ci (flags & RTL818X_TX_DESC_FLAG_TX_OK)) 3668c2ecf20Sopenharmony_ci info->flags |= IEEE80211_TX_STAT_ACK; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci info->status.rates[0].count = (flags & 0xFF) + 1; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci ieee80211_tx_status_irqsafe(dev, skb); 3718c2ecf20Sopenharmony_ci if (ring->entries - skb_queue_len(&ring->queue) == 2) 3728c2ecf20Sopenharmony_ci ieee80211_wake_queue(dev, prio); 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_cistatic irqreturn_t rtl8187se_interrupt(int irq, void *dev_id) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci struct ieee80211_hw *dev = dev_id; 3798c2ecf20Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 3808c2ecf20Sopenharmony_ci u32 reg; 3818c2ecf20Sopenharmony_ci unsigned long flags; 3828c2ecf20Sopenharmony_ci static int desc_err; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 3858c2ecf20Sopenharmony_ci /* Note: 32-bit interrupt status */ 3868c2ecf20Sopenharmony_ci reg = rtl818x_ioread32(priv, &priv->map->INT_STATUS_SE); 3878c2ecf20Sopenharmony_ci if (unlikely(reg == 0xFFFFFFFF)) { 3888c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 3898c2ecf20Sopenharmony_ci return IRQ_HANDLED; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci rtl818x_iowrite32(priv, &priv->map->INT_STATUS_SE, reg); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci if (reg & IMR_TIMEOUT1) 3958c2ecf20Sopenharmony_ci rtl818x_iowrite32(priv, &priv->map->INT_TIMEOUT, 0); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci if (reg & (IMR_TBDOK | IMR_TBDER)) 3988c2ecf20Sopenharmony_ci rtl8180_handle_tx(dev, 4); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci if (reg & (IMR_TVODOK | IMR_TVODER)) 4018c2ecf20Sopenharmony_ci rtl8180_handle_tx(dev, 0); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci if (reg & (IMR_TVIDOK | IMR_TVIDER)) 4048c2ecf20Sopenharmony_ci rtl8180_handle_tx(dev, 1); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci if (reg & (IMR_TBEDOK | IMR_TBEDER)) 4078c2ecf20Sopenharmony_ci rtl8180_handle_tx(dev, 2); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci if (reg & (IMR_TBKDOK | IMR_TBKDER)) 4108c2ecf20Sopenharmony_ci rtl8180_handle_tx(dev, 3); 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci if (reg & (IMR_ROK | IMR_RER | RTL818X_INT_SE_RX_DU | IMR_RQOSOK)) 4138c2ecf20Sopenharmony_ci rtl8180_handle_rx(dev); 4148c2ecf20Sopenharmony_ci /* The interface sometimes generates several RX DMA descriptor errors 4158c2ecf20Sopenharmony_ci * at startup. Do not report these. 4168c2ecf20Sopenharmony_ci */ 4178c2ecf20Sopenharmony_ci if ((reg & RTL818X_INT_SE_RX_DU) && desc_err++ > 2) 4188c2ecf20Sopenharmony_ci if (net_ratelimit()) 4198c2ecf20Sopenharmony_ci wiphy_err(dev->wiphy, "No RX DMA Descriptor avail\n"); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 4228c2ecf20Sopenharmony_ci return IRQ_HANDLED; 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cistatic irqreturn_t rtl8180_interrupt(int irq, void *dev_id) 4268c2ecf20Sopenharmony_ci{ 4278c2ecf20Sopenharmony_ci struct ieee80211_hw *dev = dev_id; 4288c2ecf20Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 4298c2ecf20Sopenharmony_ci u16 reg; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci spin_lock(&priv->lock); 4328c2ecf20Sopenharmony_ci reg = rtl818x_ioread16(priv, &priv->map->INT_STATUS); 4338c2ecf20Sopenharmony_ci if (unlikely(reg == 0xFFFF)) { 4348c2ecf20Sopenharmony_ci spin_unlock(&priv->lock); 4358c2ecf20Sopenharmony_ci return IRQ_HANDLED; 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci rtl818x_iowrite16(priv, &priv->map->INT_STATUS, reg); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci if (reg & (RTL818X_INT_TXB_OK | RTL818X_INT_TXB_ERR)) 4418c2ecf20Sopenharmony_ci rtl8180_handle_tx(dev, 1); 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci if (reg & (RTL818X_INT_TXL_OK | RTL818X_INT_TXL_ERR)) 4448c2ecf20Sopenharmony_ci rtl8180_handle_tx(dev, 0); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci if (reg & (RTL818X_INT_RX_OK | RTL818X_INT_RX_ERR)) 4478c2ecf20Sopenharmony_ci rtl8180_handle_rx(dev); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci spin_unlock(&priv->lock); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci return IRQ_HANDLED; 4528c2ecf20Sopenharmony_ci} 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_cistatic void rtl8180_tx(struct ieee80211_hw *dev, 4558c2ecf20Sopenharmony_ci struct ieee80211_tx_control *control, 4568c2ecf20Sopenharmony_ci struct sk_buff *skb) 4578c2ecf20Sopenharmony_ci{ 4588c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 4598c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 4608c2ecf20Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 4618c2ecf20Sopenharmony_ci struct rtl8180_tx_ring *ring; 4628c2ecf20Sopenharmony_ci struct rtl8180_tx_desc *entry; 4638c2ecf20Sopenharmony_ci unsigned int prio = 0; 4648c2ecf20Sopenharmony_ci unsigned long flags; 4658c2ecf20Sopenharmony_ci unsigned int idx, hw_prio; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci dma_addr_t mapping; 4688c2ecf20Sopenharmony_ci u32 tx_flags; 4698c2ecf20Sopenharmony_ci u8 rc_flags; 4708c2ecf20Sopenharmony_ci u16 plcp_len = 0; 4718c2ecf20Sopenharmony_ci __le16 rts_duration = 0; 4728c2ecf20Sopenharmony_ci /* do arithmetic and then convert to le16 */ 4738c2ecf20Sopenharmony_ci u16 frame_duration = 0; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci /* rtl8180/rtl8185 only has one useable tx queue */ 4768c2ecf20Sopenharmony_ci if (dev->queues > IEEE80211_AC_BK) 4778c2ecf20Sopenharmony_ci prio = skb_get_queue_mapping(skb); 4788c2ecf20Sopenharmony_ci ring = &priv->tx_ring[prio]; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci mapping = dma_map_single(&priv->pdev->dev, skb->data, skb->len, 4818c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci if (dma_mapping_error(&priv->pdev->dev, mapping)) { 4848c2ecf20Sopenharmony_ci kfree_skb(skb); 4858c2ecf20Sopenharmony_ci dev_err(&priv->pdev->dev, "TX DMA mapping error\n"); 4868c2ecf20Sopenharmony_ci return; 4878c2ecf20Sopenharmony_ci } 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci tx_flags = RTL818X_TX_DESC_FLAG_OWN | RTL818X_TX_DESC_FLAG_FS | 4908c2ecf20Sopenharmony_ci RTL818X_TX_DESC_FLAG_LS | 4918c2ecf20Sopenharmony_ci (ieee80211_get_tx_rate(dev, info)->hw_value << 24) | 4928c2ecf20Sopenharmony_ci skb->len; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci if (priv->chip_family != RTL818X_CHIP_FAMILY_RTL8180) 4958c2ecf20Sopenharmony_ci tx_flags |= RTL818X_TX_DESC_FLAG_DMA | 4968c2ecf20Sopenharmony_ci RTL818X_TX_DESC_FLAG_NO_ENC; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci rc_flags = info->control.rates[0].flags; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci /* HW will perform RTS-CTS when only RTS flags is set. 5018c2ecf20Sopenharmony_ci * HW will perform CTS-to-self when both RTS and CTS flags are set. 5028c2ecf20Sopenharmony_ci * RTS rate and RTS duration will be used also for CTS-to-self. 5038c2ecf20Sopenharmony_ci */ 5048c2ecf20Sopenharmony_ci if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) { 5058c2ecf20Sopenharmony_ci tx_flags |= RTL818X_TX_DESC_FLAG_RTS; 5068c2ecf20Sopenharmony_ci tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; 5078c2ecf20Sopenharmony_ci rts_duration = ieee80211_rts_duration(dev, priv->vif, 5088c2ecf20Sopenharmony_ci skb->len, info); 5098c2ecf20Sopenharmony_ci } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { 5108c2ecf20Sopenharmony_ci tx_flags |= RTL818X_TX_DESC_FLAG_RTS | RTL818X_TX_DESC_FLAG_CTS; 5118c2ecf20Sopenharmony_ci tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; 5128c2ecf20Sopenharmony_ci rts_duration = ieee80211_ctstoself_duration(dev, priv->vif, 5138c2ecf20Sopenharmony_ci skb->len, info); 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8180) { 5178c2ecf20Sopenharmony_ci unsigned int remainder; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci plcp_len = DIV_ROUND_UP(16 * (skb->len + 4), 5208c2ecf20Sopenharmony_ci (ieee80211_get_tx_rate(dev, info)->bitrate * 2) / 10); 5218c2ecf20Sopenharmony_ci remainder = (16 * (skb->len + 4)) % 5228c2ecf20Sopenharmony_ci ((ieee80211_get_tx_rate(dev, info)->bitrate * 2) / 10); 5238c2ecf20Sopenharmony_ci if (remainder <= 6) 5248c2ecf20Sopenharmony_ci plcp_len |= 1 << 15; 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) { 5288c2ecf20Sopenharmony_ci __le16 duration; 5298c2ecf20Sopenharmony_ci /* SIFS time (required by HW) is already included by 5308c2ecf20Sopenharmony_ci * ieee80211_generic_frame_duration 5318c2ecf20Sopenharmony_ci */ 5328c2ecf20Sopenharmony_ci duration = ieee80211_generic_frame_duration(dev, priv->vif, 5338c2ecf20Sopenharmony_ci NL80211_BAND_2GHZ, skb->len, 5348c2ecf20Sopenharmony_ci ieee80211_get_tx_rate(dev, info)); 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci frame_duration = priv->ack_time + le16_to_cpu(duration); 5378c2ecf20Sopenharmony_ci } 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { 5428c2ecf20Sopenharmony_ci if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) 5438c2ecf20Sopenharmony_ci priv->seqno += 0x10; 5448c2ecf20Sopenharmony_ci hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); 5458c2ecf20Sopenharmony_ci hdr->seq_ctrl |= cpu_to_le16(priv->seqno); 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci idx = (ring->idx + skb_queue_len(&ring->queue)) % ring->entries; 5498c2ecf20Sopenharmony_ci entry = &ring->desc[idx]; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) { 5528c2ecf20Sopenharmony_ci entry->frame_duration = cpu_to_le16(frame_duration); 5538c2ecf20Sopenharmony_ci entry->frame_len_se = cpu_to_le16(skb->len); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci /* tpc polarity */ 5568c2ecf20Sopenharmony_ci entry->flags3 = cpu_to_le16(1<<4); 5578c2ecf20Sopenharmony_ci } else 5588c2ecf20Sopenharmony_ci entry->frame_len = cpu_to_le32(skb->len); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci entry->rts_duration = rts_duration; 5618c2ecf20Sopenharmony_ci entry->plcp_len = cpu_to_le16(plcp_len); 5628c2ecf20Sopenharmony_ci entry->tx_buf = cpu_to_le32(mapping); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci entry->retry_limit = info->control.rates[0].count - 1; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci /* We must be sure that tx_flags is written last because the HW 5678c2ecf20Sopenharmony_ci * looks at it to check if the rest of data is valid or not 5688c2ecf20Sopenharmony_ci */ 5698c2ecf20Sopenharmony_ci wmb(); 5708c2ecf20Sopenharmony_ci entry->flags = cpu_to_le32(tx_flags); 5718c2ecf20Sopenharmony_ci /* We must be sure this has been written before followings HW 5728c2ecf20Sopenharmony_ci * register write, because this write will made the HW attempts 5738c2ecf20Sopenharmony_ci * to DMA the just-written data 5748c2ecf20Sopenharmony_ci */ 5758c2ecf20Sopenharmony_ci wmb(); 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci __skb_queue_tail(&ring->queue, skb); 5788c2ecf20Sopenharmony_ci if (ring->entries - skb_queue_len(&ring->queue) < 2) 5798c2ecf20Sopenharmony_ci ieee80211_stop_queue(dev, prio); 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) { 5848c2ecf20Sopenharmony_ci /* just poll: rings are stopped with TPPollStop reg */ 5858c2ecf20Sopenharmony_ci hw_prio = rtl8187se_queues_map[prio]; 5868c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING, 5878c2ecf20Sopenharmony_ci (1 << hw_prio)); 5888c2ecf20Sopenharmony_ci } else { 5898c2ecf20Sopenharmony_ci hw_prio = rtl8180_queues_map[prio]; 5908c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING, 5918c2ecf20Sopenharmony_ci (1 << hw_prio) | /* ring to poll */ 5928c2ecf20Sopenharmony_ci (1<<1) | (1<<2));/* stopped rings */ 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci} 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_cistatic void rtl8180_set_anaparam3(struct rtl8180_priv *priv, u16 anaparam3) 5978c2ecf20Sopenharmony_ci{ 5988c2ecf20Sopenharmony_ci u8 reg; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, 6018c2ecf20Sopenharmony_ci RTL818X_EEPROM_CMD_CONFIG); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); 6048c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->CONFIG3, 6058c2ecf20Sopenharmony_ci reg | RTL818X_CONFIG3_ANAPARAM_WRITE); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci rtl818x_iowrite16(priv, &priv->map->ANAPARAM3, anaparam3); 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->CONFIG3, 6108c2ecf20Sopenharmony_ci reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, 6138c2ecf20Sopenharmony_ci RTL818X_EEPROM_CMD_NORMAL); 6148c2ecf20Sopenharmony_ci} 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_civoid rtl8180_set_anaparam2(struct rtl8180_priv *priv, u32 anaparam2) 6178c2ecf20Sopenharmony_ci{ 6188c2ecf20Sopenharmony_ci u8 reg; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, 6218c2ecf20Sopenharmony_ci RTL818X_EEPROM_CMD_CONFIG); 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); 6248c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->CONFIG3, 6258c2ecf20Sopenharmony_ci reg | RTL818X_CONFIG3_ANAPARAM_WRITE); 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, anaparam2); 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->CONFIG3, 6308c2ecf20Sopenharmony_ci reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, 6338c2ecf20Sopenharmony_ci RTL818X_EEPROM_CMD_NORMAL); 6348c2ecf20Sopenharmony_ci} 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_civoid rtl8180_set_anaparam(struct rtl8180_priv *priv, u32 anaparam) 6378c2ecf20Sopenharmony_ci{ 6388c2ecf20Sopenharmony_ci u8 reg; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); 6418c2ecf20Sopenharmony_ci reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); 6428c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->CONFIG3, 6438c2ecf20Sopenharmony_ci reg | RTL818X_CONFIG3_ANAPARAM_WRITE); 6448c2ecf20Sopenharmony_ci rtl818x_iowrite32(priv, &priv->map->ANAPARAM, anaparam); 6458c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->CONFIG3, 6468c2ecf20Sopenharmony_ci reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); 6478c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); 6488c2ecf20Sopenharmony_ci} 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_cistatic void rtl8187se_mac_config(struct ieee80211_hw *dev) 6518c2ecf20Sopenharmony_ci{ 6528c2ecf20Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 6538c2ecf20Sopenharmony_ci u8 reg; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci rtl818x_iowrite32(priv, REG_ADDR4(0x1F0), 0); 6568c2ecf20Sopenharmony_ci rtl818x_ioread32(priv, REG_ADDR4(0x1F0)); 6578c2ecf20Sopenharmony_ci rtl818x_iowrite32(priv, REG_ADDR4(0x1F4), 0); 6588c2ecf20Sopenharmony_ci rtl818x_ioread32(priv, REG_ADDR4(0x1F4)); 6598c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, REG_ADDR1(0x1F8), 0); 6608c2ecf20Sopenharmony_ci rtl818x_ioread8(priv, REG_ADDR1(0x1F8)); 6618c2ecf20Sopenharmony_ci /* Enable DA10 TX power saving */ 6628c2ecf20Sopenharmony_ci reg = rtl818x_ioread8(priv, &priv->map->PHY_PR); 6638c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->PHY_PR, reg | 0x04); 6648c2ecf20Sopenharmony_ci /* Power */ 6658c2ecf20Sopenharmony_ci rtl818x_iowrite16(priv, PI_DATA_REG, 0x1000); 6668c2ecf20Sopenharmony_ci rtl818x_iowrite16(priv, SI_DATA_REG, 0x1000); 6678c2ecf20Sopenharmony_ci /* AFE - default to power ON */ 6688c2ecf20Sopenharmony_ci rtl818x_iowrite16(priv, REG_ADDR2(0x370), 0x0560); 6698c2ecf20Sopenharmony_ci rtl818x_iowrite16(priv, REG_ADDR2(0x372), 0x0560); 6708c2ecf20Sopenharmony_ci rtl818x_iowrite16(priv, REG_ADDR2(0x374), 0x0DA4); 6718c2ecf20Sopenharmony_ci rtl818x_iowrite16(priv, REG_ADDR2(0x376), 0x0DA4); 6728c2ecf20Sopenharmony_ci rtl818x_iowrite16(priv, REG_ADDR2(0x378), 0x0560); 6738c2ecf20Sopenharmony_ci rtl818x_iowrite16(priv, REG_ADDR2(0x37A), 0x0560); 6748c2ecf20Sopenharmony_ci rtl818x_iowrite16(priv, REG_ADDR2(0x37C), 0x00EC); 6758c2ecf20Sopenharmony_ci rtl818x_iowrite16(priv, REG_ADDR2(0x37E), 0x00EC); 6768c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, REG_ADDR1(0x24E), 0x01); 6778c2ecf20Sopenharmony_ci /* unknown, needed for suspend to RAM resume */ 6788c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, REG_ADDR1(0x0A), 0x72); 6798c2ecf20Sopenharmony_ci} 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_cistatic void rtl8187se_set_antenna_config(struct ieee80211_hw *dev, u8 def_ant, 6828c2ecf20Sopenharmony_ci bool diversity) 6838c2ecf20Sopenharmony_ci{ 6848c2ecf20Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci rtl8225_write_phy_cck(dev, 0x0C, 0x09); 6878c2ecf20Sopenharmony_ci if (diversity) { 6888c2ecf20Sopenharmony_ci if (def_ant == 1) { 6898c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x00); 6908c2ecf20Sopenharmony_ci rtl8225_write_phy_cck(dev, 0x11, 0xBB); 6918c2ecf20Sopenharmony_ci rtl8225_write_phy_cck(dev, 0x01, 0xC7); 6928c2ecf20Sopenharmony_ci rtl8225_write_phy_ofdm(dev, 0x0D, 0x54); 6938c2ecf20Sopenharmony_ci rtl8225_write_phy_ofdm(dev, 0x18, 0xB2); 6948c2ecf20Sopenharmony_ci } else { /* main antenna */ 6958c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); 6968c2ecf20Sopenharmony_ci rtl8225_write_phy_cck(dev, 0x11, 0x9B); 6978c2ecf20Sopenharmony_ci rtl8225_write_phy_cck(dev, 0x01, 0xC7); 6988c2ecf20Sopenharmony_ci rtl8225_write_phy_ofdm(dev, 0x0D, 0x5C); 6998c2ecf20Sopenharmony_ci rtl8225_write_phy_ofdm(dev, 0x18, 0xB2); 7008c2ecf20Sopenharmony_ci } 7018c2ecf20Sopenharmony_ci } else { /* disable antenna diversity */ 7028c2ecf20Sopenharmony_ci if (def_ant == 1) { 7038c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x00); 7048c2ecf20Sopenharmony_ci rtl8225_write_phy_cck(dev, 0x11, 0xBB); 7058c2ecf20Sopenharmony_ci rtl8225_write_phy_cck(dev, 0x01, 0x47); 7068c2ecf20Sopenharmony_ci rtl8225_write_phy_ofdm(dev, 0x0D, 0x54); 7078c2ecf20Sopenharmony_ci rtl8225_write_phy_ofdm(dev, 0x18, 0x32); 7088c2ecf20Sopenharmony_ci } else { /* main antenna */ 7098c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); 7108c2ecf20Sopenharmony_ci rtl8225_write_phy_cck(dev, 0x11, 0x9B); 7118c2ecf20Sopenharmony_ci rtl8225_write_phy_cck(dev, 0x01, 0x47); 7128c2ecf20Sopenharmony_ci rtl8225_write_phy_ofdm(dev, 0x0D, 0x5C); 7138c2ecf20Sopenharmony_ci rtl8225_write_phy_ofdm(dev, 0x18, 0x32); 7148c2ecf20Sopenharmony_ci } 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci /* priv->curr_ant = def_ant; */ 7178c2ecf20Sopenharmony_ci} 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_cistatic void rtl8180_int_enable(struct ieee80211_hw *dev) 7208c2ecf20Sopenharmony_ci{ 7218c2ecf20Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) { 7248c2ecf20Sopenharmony_ci rtl818x_iowrite32(priv, &priv->map->IMR, 7258c2ecf20Sopenharmony_ci IMR_TBDER | IMR_TBDOK | 7268c2ecf20Sopenharmony_ci IMR_TVODER | IMR_TVODOK | 7278c2ecf20Sopenharmony_ci IMR_TVIDER | IMR_TVIDOK | 7288c2ecf20Sopenharmony_ci IMR_TBEDER | IMR_TBEDOK | 7298c2ecf20Sopenharmony_ci IMR_TBKDER | IMR_TBKDOK | 7308c2ecf20Sopenharmony_ci IMR_RDU | IMR_RER | 7318c2ecf20Sopenharmony_ci IMR_ROK | IMR_RQOSOK); 7328c2ecf20Sopenharmony_ci } else { 7338c2ecf20Sopenharmony_ci rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF); 7348c2ecf20Sopenharmony_ci } 7358c2ecf20Sopenharmony_ci} 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_cistatic void rtl8180_int_disable(struct ieee80211_hw *dev) 7388c2ecf20Sopenharmony_ci{ 7398c2ecf20Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) { 7428c2ecf20Sopenharmony_ci rtl818x_iowrite32(priv, &priv->map->IMR, 0); 7438c2ecf20Sopenharmony_ci } else { 7448c2ecf20Sopenharmony_ci rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); 7458c2ecf20Sopenharmony_ci } 7468c2ecf20Sopenharmony_ci} 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_cistatic void rtl8180_conf_basic_rates(struct ieee80211_hw *dev, 7498c2ecf20Sopenharmony_ci u32 basic_mask) 7508c2ecf20Sopenharmony_ci{ 7518c2ecf20Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 7528c2ecf20Sopenharmony_ci u16 reg; 7538c2ecf20Sopenharmony_ci u32 resp_mask; 7548c2ecf20Sopenharmony_ci u8 basic_max; 7558c2ecf20Sopenharmony_ci u8 resp_max, resp_min; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci resp_mask = basic_mask; 7588c2ecf20Sopenharmony_ci /* IEEE80211 says the response rate should be equal to the highest basic 7598c2ecf20Sopenharmony_ci * rate that is not faster than received frame. But it says also that if 7608c2ecf20Sopenharmony_ci * the basic rate set does not contains any rate for the current 7618c2ecf20Sopenharmony_ci * modulation class then mandatory rate set must be used for that 7628c2ecf20Sopenharmony_ci * modulation class. Eventually add OFDM mandatory rates.. 7638c2ecf20Sopenharmony_ci */ 7648c2ecf20Sopenharmony_ci if ((resp_mask & 0xf) == resp_mask) 7658c2ecf20Sopenharmony_ci resp_mask |= 0x150; /* 6, 12, 24Mbps */ 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci switch (priv->chip_family) { 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci case RTL818X_CHIP_FAMILY_RTL8180: 7708c2ecf20Sopenharmony_ci /* in 8180 this is NOT a BITMAP */ 7718c2ecf20Sopenharmony_ci basic_max = fls(basic_mask) - 1; 7728c2ecf20Sopenharmony_ci reg = rtl818x_ioread16(priv, &priv->map->BRSR); 7738c2ecf20Sopenharmony_ci reg &= ~3; 7748c2ecf20Sopenharmony_ci reg |= basic_max; 7758c2ecf20Sopenharmony_ci rtl818x_iowrite16(priv, &priv->map->BRSR, reg); 7768c2ecf20Sopenharmony_ci break; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci case RTL818X_CHIP_FAMILY_RTL8185: 7798c2ecf20Sopenharmony_ci resp_max = fls(resp_mask) - 1; 7808c2ecf20Sopenharmony_ci resp_min = ffs(resp_mask) - 1; 7818c2ecf20Sopenharmony_ci /* in 8185 this is a BITMAP */ 7828c2ecf20Sopenharmony_ci rtl818x_iowrite16(priv, &priv->map->BRSR, basic_mask); 7838c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->RESP_RATE, (resp_max << 4) | 7848c2ecf20Sopenharmony_ci resp_min); 7858c2ecf20Sopenharmony_ci break; 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci case RTL818X_CHIP_FAMILY_RTL8187SE: 7888c2ecf20Sopenharmony_ci /* in 8187se this is a BITMAP. BRSR reg actually sets 7898c2ecf20Sopenharmony_ci * response rates. 7908c2ecf20Sopenharmony_ci */ 7918c2ecf20Sopenharmony_ci rtl818x_iowrite16(priv, &priv->map->BRSR_8187SE, resp_mask); 7928c2ecf20Sopenharmony_ci break; 7938c2ecf20Sopenharmony_ci } 7948c2ecf20Sopenharmony_ci} 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_cistatic void rtl8180_config_cardbus(struct ieee80211_hw *dev) 7978c2ecf20Sopenharmony_ci{ 7988c2ecf20Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 7998c2ecf20Sopenharmony_ci u16 reg16; 8008c2ecf20Sopenharmony_ci u8 reg8; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci reg8 = rtl818x_ioread8(priv, &priv->map->CONFIG3); 8038c2ecf20Sopenharmony_ci reg8 |= 1 << 1; 8048c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg8); 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) { 8078c2ecf20Sopenharmony_ci rtl818x_iowrite16(priv, FEMR_SE, 0xffff); 8088c2ecf20Sopenharmony_ci } else { 8098c2ecf20Sopenharmony_ci reg16 = rtl818x_ioread16(priv, &priv->map->FEMR); 8108c2ecf20Sopenharmony_ci reg16 |= (1 << 15) | (1 << 14) | (1 << 4); 8118c2ecf20Sopenharmony_ci rtl818x_iowrite16(priv, &priv->map->FEMR, reg16); 8128c2ecf20Sopenharmony_ci } 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci} 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_cistatic int rtl8180_init_hw(struct ieee80211_hw *dev) 8178c2ecf20Sopenharmony_ci{ 8188c2ecf20Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 8198c2ecf20Sopenharmony_ci u16 reg; 8208c2ecf20Sopenharmony_ci u32 reg32; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->CMD, 0); 8238c2ecf20Sopenharmony_ci rtl818x_ioread8(priv, &priv->map->CMD); 8248c2ecf20Sopenharmony_ci msleep(10); 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci /* reset */ 8278c2ecf20Sopenharmony_ci rtl8180_int_disable(dev); 8288c2ecf20Sopenharmony_ci rtl818x_ioread8(priv, &priv->map->CMD); 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci reg = rtl818x_ioread8(priv, &priv->map->CMD); 8318c2ecf20Sopenharmony_ci reg &= (1 << 1); 8328c2ecf20Sopenharmony_ci reg |= RTL818X_CMD_RESET; 8338c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->CMD, RTL818X_CMD_RESET); 8348c2ecf20Sopenharmony_ci rtl818x_ioread8(priv, &priv->map->CMD); 8358c2ecf20Sopenharmony_ci msleep(200); 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci /* check success of reset */ 8388c2ecf20Sopenharmony_ci if (rtl818x_ioread8(priv, &priv->map->CMD) & RTL818X_CMD_RESET) { 8398c2ecf20Sopenharmony_ci wiphy_err(dev->wiphy, "reset timeout!\n"); 8408c2ecf20Sopenharmony_ci return -ETIMEDOUT; 8418c2ecf20Sopenharmony_ci } 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_LOAD); 8448c2ecf20Sopenharmony_ci rtl818x_ioread8(priv, &priv->map->CMD); 8458c2ecf20Sopenharmony_ci msleep(200); 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci if (rtl818x_ioread8(priv, &priv->map->CONFIG3) & (1 << 3)) { 8488c2ecf20Sopenharmony_ci rtl8180_config_cardbus(dev); 8498c2ecf20Sopenharmony_ci } 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) 8528c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->MSR, RTL818X_MSR_ENEDCA); 8538c2ecf20Sopenharmony_ci else 8548c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->MSR, 0); 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8180) 8578c2ecf20Sopenharmony_ci rtl8180_set_anaparam(priv, priv->anaparam); 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci rtl818x_iowrite32(priv, &priv->map->RDSAR, priv->rx_ring_dma); 8608c2ecf20Sopenharmony_ci /* mac80211 queue have higher prio for lower index. The last queue 8618c2ecf20Sopenharmony_ci * (that mac80211 is not aware of) is reserved for beacons (and have 8628c2ecf20Sopenharmony_ci * the highest priority on the NIC) 8638c2ecf20Sopenharmony_ci */ 8648c2ecf20Sopenharmony_ci if (priv->chip_family != RTL818X_CHIP_FAMILY_RTL8187SE) { 8658c2ecf20Sopenharmony_ci rtl818x_iowrite32(priv, &priv->map->TBDA, 8668c2ecf20Sopenharmony_ci priv->tx_ring[1].dma); 8678c2ecf20Sopenharmony_ci rtl818x_iowrite32(priv, &priv->map->TLPDA, 8688c2ecf20Sopenharmony_ci priv->tx_ring[0].dma); 8698c2ecf20Sopenharmony_ci } else { 8708c2ecf20Sopenharmony_ci rtl818x_iowrite32(priv, &priv->map->TBDA, 8718c2ecf20Sopenharmony_ci priv->tx_ring[4].dma); 8728c2ecf20Sopenharmony_ci rtl818x_iowrite32(priv, &priv->map->TVODA, 8738c2ecf20Sopenharmony_ci priv->tx_ring[0].dma); 8748c2ecf20Sopenharmony_ci rtl818x_iowrite32(priv, &priv->map->TVIDA, 8758c2ecf20Sopenharmony_ci priv->tx_ring[1].dma); 8768c2ecf20Sopenharmony_ci rtl818x_iowrite32(priv, &priv->map->TBEDA, 8778c2ecf20Sopenharmony_ci priv->tx_ring[2].dma); 8788c2ecf20Sopenharmony_ci rtl818x_iowrite32(priv, &priv->map->TBKDA, 8798c2ecf20Sopenharmony_ci priv->tx_ring[3].dma); 8808c2ecf20Sopenharmony_ci } 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci /* TODO: necessary? specs indicate not */ 8838c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); 8848c2ecf20Sopenharmony_ci reg = rtl818x_ioread8(priv, &priv->map->CONFIG2); 8858c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->CONFIG2, reg & ~(1 << 3)); 8868c2ecf20Sopenharmony_ci if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8185) { 8878c2ecf20Sopenharmony_ci reg = rtl818x_ioread8(priv, &priv->map->CONFIG2); 8888c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->CONFIG2, reg | (1 << 4)); 8898c2ecf20Sopenharmony_ci } 8908c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci /* TODO: set CONFIG5 for calibrating AGC on rtl8180 + philips radio? */ 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci /* TODO: turn off hw wep on rtl8180 */ 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci rtl818x_iowrite32(priv, &priv->map->INT_TIMEOUT, 0); 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci if (priv->chip_family != RTL818X_CHIP_FAMILY_RTL8180) { 8998c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->WPA_CONF, 0); 9008c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->RATE_FALLBACK, 0); 9018c2ecf20Sopenharmony_ci } else { 9028c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->SECURITY, 0); 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->PHY_DELAY, 0x6); 9058c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->CARRIER_SENSE_COUNTER, 0x4C); 9068c2ecf20Sopenharmony_ci } 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8185) { 9098c2ecf20Sopenharmony_ci /* TODO: set ClkRun enable? necessary? */ 9108c2ecf20Sopenharmony_ci reg = rtl818x_ioread8(priv, &priv->map->GP_ENABLE); 9118c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, reg & ~(1 << 6)); 9128c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); 9138c2ecf20Sopenharmony_ci reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); 9148c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | (1 << 2)); 9158c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); 9168c2ecf20Sopenharmony_ci /* fix eccessive IFS after CTS-to-self */ 9178c2ecf20Sopenharmony_ci if (priv->map_pio) { 9188c2ecf20Sopenharmony_ci u8 reg; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci reg = rtl818x_ioread8(priv, &priv->map->PGSELECT); 9218c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg | 1); 9228c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, REG_ADDR1(0xff), 0x35); 9238c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg); 9248c2ecf20Sopenharmony_ci } else 9258c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, REG_ADDR1(0x1ff), 0x35); 9268c2ecf20Sopenharmony_ci } 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) { 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci /* the set auto rate fallback bitmask from 1M to 54 Mb/s */ 9318c2ecf20Sopenharmony_ci rtl818x_iowrite16(priv, ARFR, 0xFFF); 9328c2ecf20Sopenharmony_ci rtl818x_ioread16(priv, ARFR); 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci /* stop unused queus (no dma alloc) */ 9358c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->TPPOLL_STOP, 9368c2ecf20Sopenharmony_ci RTL818x_TPPOLL_STOP_MG | RTL818x_TPPOLL_STOP_HI); 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->ACM_CONTROL, 0x00); 9398c2ecf20Sopenharmony_ci rtl818x_iowrite16(priv, &priv->map->TID_AC_MAP, 0xFA50); 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci rtl818x_iowrite16(priv, &priv->map->INT_MIG, 0); 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci /* some black magic here.. */ 9448c2ecf20Sopenharmony_ci rtl8187se_mac_config(dev); 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci rtl818x_iowrite16(priv, RFSW_CTRL, 0x569A); 9478c2ecf20Sopenharmony_ci rtl818x_ioread16(priv, RFSW_CTRL); 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci rtl8180_set_anaparam(priv, RTL8225SE_ANAPARAM_ON); 9508c2ecf20Sopenharmony_ci rtl8180_set_anaparam2(priv, RTL8225SE_ANAPARAM2_ON); 9518c2ecf20Sopenharmony_ci rtl8180_set_anaparam3(priv, RTL8225SE_ANAPARAM3); 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->CONFIG5, 9558c2ecf20Sopenharmony_ci rtl818x_ioread8(priv, &priv->map->CONFIG5) & 0x7F); 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci /*probably this switch led on */ 9588c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->PGSELECT, 9598c2ecf20Sopenharmony_ci rtl818x_ioread8(priv, &priv->map->PGSELECT) | 0x08); 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480); 9628c2ecf20Sopenharmony_ci rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1BFF); 9638c2ecf20Sopenharmony_ci rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x2488); 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x4003); 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci /* the reference code mac hardcode table write 9688c2ecf20Sopenharmony_ci * this reg by doing byte-wide accesses. 9698c2ecf20Sopenharmony_ci * It does it just for lowest and highest byte.. 9708c2ecf20Sopenharmony_ci */ 9718c2ecf20Sopenharmony_ci reg32 = rtl818x_ioread32(priv, &priv->map->RF_PARA); 9728c2ecf20Sopenharmony_ci reg32 &= 0x00ffff00; 9738c2ecf20Sopenharmony_ci reg32 |= 0xb8000054; 9748c2ecf20Sopenharmony_ci rtl818x_iowrite32(priv, &priv->map->RF_PARA, reg32); 9758c2ecf20Sopenharmony_ci } else 9768c2ecf20Sopenharmony_ci /* stop unused queus (no dma alloc) */ 9778c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING, 9788c2ecf20Sopenharmony_ci (1<<1) | (1<<2)); 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci priv->rf->init(dev); 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci /* default basic rates are 1,2 Mbps for rtl8180. 1,2,6,9,12,18,24 Mbps 9838c2ecf20Sopenharmony_ci * otherwise. bitmask 0x3 and 0x01f3 respectively. 9848c2ecf20Sopenharmony_ci * NOTE: currenty rtl8225 RF code changes basic rates, so we need to do 9858c2ecf20Sopenharmony_ci * this after rf init. 9868c2ecf20Sopenharmony_ci * TODO: try to find out whether RF code really needs to do this.. 9878c2ecf20Sopenharmony_ci */ 9888c2ecf20Sopenharmony_ci if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8180) 9898c2ecf20Sopenharmony_ci rtl8180_conf_basic_rates(dev, 0x3); 9908c2ecf20Sopenharmony_ci else 9918c2ecf20Sopenharmony_ci rtl8180_conf_basic_rates(dev, 0x1f3); 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) 9948c2ecf20Sopenharmony_ci rtl8187se_set_antenna_config(dev, 9958c2ecf20Sopenharmony_ci priv->antenna_diversity_default, 9968c2ecf20Sopenharmony_ci priv->antenna_diversity_en); 9978c2ecf20Sopenharmony_ci return 0; 9988c2ecf20Sopenharmony_ci} 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_cistatic int rtl8180_init_rx_ring(struct ieee80211_hw *dev) 10018c2ecf20Sopenharmony_ci{ 10028c2ecf20Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 10038c2ecf20Sopenharmony_ci struct rtl818x_rx_cmd_desc *entry; 10048c2ecf20Sopenharmony_ci int i; 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) 10078c2ecf20Sopenharmony_ci priv->rx_ring_sz = sizeof(struct rtl8187se_rx_desc); 10088c2ecf20Sopenharmony_ci else 10098c2ecf20Sopenharmony_ci priv->rx_ring_sz = sizeof(struct rtl8180_rx_desc); 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci priv->rx_ring = dma_alloc_coherent(&priv->pdev->dev, 10128c2ecf20Sopenharmony_ci priv->rx_ring_sz * 32, 10138c2ecf20Sopenharmony_ci &priv->rx_ring_dma, GFP_KERNEL); 10148c2ecf20Sopenharmony_ci if (!priv->rx_ring || (unsigned long)priv->rx_ring & 0xFF) { 10158c2ecf20Sopenharmony_ci wiphy_err(dev->wiphy, "Cannot allocate RX ring\n"); 10168c2ecf20Sopenharmony_ci return -ENOMEM; 10178c2ecf20Sopenharmony_ci } 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci priv->rx_idx = 0; 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci for (i = 0; i < 32; i++) { 10228c2ecf20Sopenharmony_ci struct sk_buff *skb = dev_alloc_skb(MAX_RX_SIZE); 10238c2ecf20Sopenharmony_ci dma_addr_t *mapping; 10248c2ecf20Sopenharmony_ci entry = priv->rx_ring + priv->rx_ring_sz*i; 10258c2ecf20Sopenharmony_ci if (!skb) { 10268c2ecf20Sopenharmony_ci dma_free_coherent(&priv->pdev->dev, 10278c2ecf20Sopenharmony_ci priv->rx_ring_sz * 32, 10288c2ecf20Sopenharmony_ci priv->rx_ring, priv->rx_ring_dma); 10298c2ecf20Sopenharmony_ci wiphy_err(dev->wiphy, "Cannot allocate RX skb\n"); 10308c2ecf20Sopenharmony_ci return -ENOMEM; 10318c2ecf20Sopenharmony_ci } 10328c2ecf20Sopenharmony_ci priv->rx_buf[i] = skb; 10338c2ecf20Sopenharmony_ci mapping = (dma_addr_t *)skb->cb; 10348c2ecf20Sopenharmony_ci *mapping = dma_map_single(&priv->pdev->dev, 10358c2ecf20Sopenharmony_ci skb_tail_pointer(skb), MAX_RX_SIZE, 10368c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci if (dma_mapping_error(&priv->pdev->dev, *mapping)) { 10398c2ecf20Sopenharmony_ci kfree_skb(skb); 10408c2ecf20Sopenharmony_ci dma_free_coherent(&priv->pdev->dev, 10418c2ecf20Sopenharmony_ci priv->rx_ring_sz * 32, 10428c2ecf20Sopenharmony_ci priv->rx_ring, priv->rx_ring_dma); 10438c2ecf20Sopenharmony_ci wiphy_err(dev->wiphy, "Cannot map DMA for RX skb\n"); 10448c2ecf20Sopenharmony_ci return -ENOMEM; 10458c2ecf20Sopenharmony_ci } 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci entry->rx_buf = cpu_to_le32(*mapping); 10488c2ecf20Sopenharmony_ci entry->flags = cpu_to_le32(RTL818X_RX_DESC_FLAG_OWN | 10498c2ecf20Sopenharmony_ci MAX_RX_SIZE); 10508c2ecf20Sopenharmony_ci } 10518c2ecf20Sopenharmony_ci entry->flags |= cpu_to_le32(RTL818X_RX_DESC_FLAG_EOR); 10528c2ecf20Sopenharmony_ci return 0; 10538c2ecf20Sopenharmony_ci} 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_cistatic void rtl8180_free_rx_ring(struct ieee80211_hw *dev) 10568c2ecf20Sopenharmony_ci{ 10578c2ecf20Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 10588c2ecf20Sopenharmony_ci int i; 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci for (i = 0; i < 32; i++) { 10618c2ecf20Sopenharmony_ci struct sk_buff *skb = priv->rx_buf[i]; 10628c2ecf20Sopenharmony_ci if (!skb) 10638c2ecf20Sopenharmony_ci continue; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci dma_unmap_single(&priv->pdev->dev, *((dma_addr_t *)skb->cb), 10668c2ecf20Sopenharmony_ci MAX_RX_SIZE, DMA_FROM_DEVICE); 10678c2ecf20Sopenharmony_ci kfree_skb(skb); 10688c2ecf20Sopenharmony_ci } 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci dma_free_coherent(&priv->pdev->dev, priv->rx_ring_sz * 32, 10718c2ecf20Sopenharmony_ci priv->rx_ring, priv->rx_ring_dma); 10728c2ecf20Sopenharmony_ci priv->rx_ring = NULL; 10738c2ecf20Sopenharmony_ci} 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_cistatic int rtl8180_init_tx_ring(struct ieee80211_hw *dev, 10768c2ecf20Sopenharmony_ci unsigned int prio, unsigned int entries) 10778c2ecf20Sopenharmony_ci{ 10788c2ecf20Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 10798c2ecf20Sopenharmony_ci struct rtl8180_tx_desc *ring; 10808c2ecf20Sopenharmony_ci dma_addr_t dma; 10818c2ecf20Sopenharmony_ci int i; 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci ring = dma_alloc_coherent(&priv->pdev->dev, sizeof(*ring) * entries, 10848c2ecf20Sopenharmony_ci &dma, GFP_KERNEL); 10858c2ecf20Sopenharmony_ci if (!ring || (unsigned long)ring & 0xFF) { 10868c2ecf20Sopenharmony_ci wiphy_err(dev->wiphy, "Cannot allocate TX ring (prio = %d)\n", 10878c2ecf20Sopenharmony_ci prio); 10888c2ecf20Sopenharmony_ci return -ENOMEM; 10898c2ecf20Sopenharmony_ci } 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci priv->tx_ring[prio].desc = ring; 10928c2ecf20Sopenharmony_ci priv->tx_ring[prio].dma = dma; 10938c2ecf20Sopenharmony_ci priv->tx_ring[prio].idx = 0; 10948c2ecf20Sopenharmony_ci priv->tx_ring[prio].entries = entries; 10958c2ecf20Sopenharmony_ci skb_queue_head_init(&priv->tx_ring[prio].queue); 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci for (i = 0; i < entries; i++) 10988c2ecf20Sopenharmony_ci ring[i].next_tx_desc = 10998c2ecf20Sopenharmony_ci cpu_to_le32((u32)dma + ((i + 1) % entries) * sizeof(*ring)); 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci return 0; 11028c2ecf20Sopenharmony_ci} 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_cistatic void rtl8180_free_tx_ring(struct ieee80211_hw *dev, unsigned int prio) 11058c2ecf20Sopenharmony_ci{ 11068c2ecf20Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 11078c2ecf20Sopenharmony_ci struct rtl8180_tx_ring *ring = &priv->tx_ring[prio]; 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci while (skb_queue_len(&ring->queue)) { 11108c2ecf20Sopenharmony_ci struct rtl8180_tx_desc *entry = &ring->desc[ring->idx]; 11118c2ecf20Sopenharmony_ci struct sk_buff *skb = __skb_dequeue(&ring->queue); 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci dma_unmap_single(&priv->pdev->dev, le32_to_cpu(entry->tx_buf), 11148c2ecf20Sopenharmony_ci skb->len, DMA_TO_DEVICE); 11158c2ecf20Sopenharmony_ci kfree_skb(skb); 11168c2ecf20Sopenharmony_ci ring->idx = (ring->idx + 1) % ring->entries; 11178c2ecf20Sopenharmony_ci } 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci dma_free_coherent(&priv->pdev->dev, 11208c2ecf20Sopenharmony_ci sizeof(*ring->desc) * ring->entries, ring->desc, 11218c2ecf20Sopenharmony_ci ring->dma); 11228c2ecf20Sopenharmony_ci ring->desc = NULL; 11238c2ecf20Sopenharmony_ci} 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_cistatic int rtl8180_start(struct ieee80211_hw *dev) 11268c2ecf20Sopenharmony_ci{ 11278c2ecf20Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 11288c2ecf20Sopenharmony_ci int ret, i; 11298c2ecf20Sopenharmony_ci u32 reg; 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci ret = rtl8180_init_rx_ring(dev); 11328c2ecf20Sopenharmony_ci if (ret) 11338c2ecf20Sopenharmony_ci return ret; 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci for (i = 0; i < (dev->queues + 1); i++) 11368c2ecf20Sopenharmony_ci if ((ret = rtl8180_init_tx_ring(dev, i, 16))) 11378c2ecf20Sopenharmony_ci goto err_free_rings; 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci ret = rtl8180_init_hw(dev); 11408c2ecf20Sopenharmony_ci if (ret) 11418c2ecf20Sopenharmony_ci goto err_free_rings; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) { 11448c2ecf20Sopenharmony_ci ret = request_irq(priv->pdev->irq, rtl8187se_interrupt, 11458c2ecf20Sopenharmony_ci IRQF_SHARED, KBUILD_MODNAME, dev); 11468c2ecf20Sopenharmony_ci } else { 11478c2ecf20Sopenharmony_ci ret = request_irq(priv->pdev->irq, rtl8180_interrupt, 11488c2ecf20Sopenharmony_ci IRQF_SHARED, KBUILD_MODNAME, dev); 11498c2ecf20Sopenharmony_ci } 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci if (ret) { 11528c2ecf20Sopenharmony_ci wiphy_err(dev->wiphy, "failed to register IRQ handler\n"); 11538c2ecf20Sopenharmony_ci goto err_free_rings; 11548c2ecf20Sopenharmony_ci } 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci rtl8180_int_enable(dev); 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci /* in rtl8187se at MAR regs offset there is the management 11598c2ecf20Sopenharmony_ci * TX descriptor DMA addres.. 11608c2ecf20Sopenharmony_ci */ 11618c2ecf20Sopenharmony_ci if (priv->chip_family != RTL818X_CHIP_FAMILY_RTL8187SE) { 11628c2ecf20Sopenharmony_ci rtl818x_iowrite32(priv, &priv->map->MAR[0], ~0); 11638c2ecf20Sopenharmony_ci rtl818x_iowrite32(priv, &priv->map->MAR[1], ~0); 11648c2ecf20Sopenharmony_ci } 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci reg = RTL818X_RX_CONF_ONLYERLPKT | 11678c2ecf20Sopenharmony_ci RTL818X_RX_CONF_RX_AUTORESETPHY | 11688c2ecf20Sopenharmony_ci RTL818X_RX_CONF_MGMT | 11698c2ecf20Sopenharmony_ci RTL818X_RX_CONF_DATA | 11708c2ecf20Sopenharmony_ci (7 << 8 /* MAX RX DMA */) | 11718c2ecf20Sopenharmony_ci RTL818X_RX_CONF_BROADCAST | 11728c2ecf20Sopenharmony_ci RTL818X_RX_CONF_NICMAC; 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8185) 11758c2ecf20Sopenharmony_ci reg |= RTL818X_RX_CONF_CSDM1 | RTL818X_RX_CONF_CSDM2; 11768c2ecf20Sopenharmony_ci else if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8180) { 11778c2ecf20Sopenharmony_ci reg |= (priv->rfparam & RF_PARAM_CARRIERSENSE1) 11788c2ecf20Sopenharmony_ci ? RTL818X_RX_CONF_CSDM1 : 0; 11798c2ecf20Sopenharmony_ci reg |= (priv->rfparam & RF_PARAM_CARRIERSENSE2) 11808c2ecf20Sopenharmony_ci ? RTL818X_RX_CONF_CSDM2 : 0; 11818c2ecf20Sopenharmony_ci } else { 11828c2ecf20Sopenharmony_ci reg &= ~(RTL818X_RX_CONF_CSDM1 | RTL818X_RX_CONF_CSDM2); 11838c2ecf20Sopenharmony_ci } 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci priv->rx_conf = reg; 11868c2ecf20Sopenharmony_ci rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg); 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci if (priv->chip_family != RTL818X_CHIP_FAMILY_RTL8180) { 11898c2ecf20Sopenharmony_ci reg = rtl818x_ioread8(priv, &priv->map->CW_CONF); 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci /* CW is not on per-packet basis. 11928c2ecf20Sopenharmony_ci * in rtl8185 the CW_VALUE reg is used. 11938c2ecf20Sopenharmony_ci * in rtl8187se the AC param regs are used. 11948c2ecf20Sopenharmony_ci */ 11958c2ecf20Sopenharmony_ci reg &= ~RTL818X_CW_CONF_PERPACKET_CW; 11968c2ecf20Sopenharmony_ci /* retry limit IS on per-packet basis. 11978c2ecf20Sopenharmony_ci * the short and long retry limit in TX_CONF 11988c2ecf20Sopenharmony_ci * reg are ignored 11998c2ecf20Sopenharmony_ci */ 12008c2ecf20Sopenharmony_ci reg |= RTL818X_CW_CONF_PERPACKET_RETRY; 12018c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->CW_CONF, reg); 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci reg = rtl818x_ioread8(priv, &priv->map->TX_AGC_CTL); 12048c2ecf20Sopenharmony_ci /* TX antenna and TX gain are not on per-packet basis. 12058c2ecf20Sopenharmony_ci * TX Antenna is selected by ANTSEL reg (RX in BB regs). 12068c2ecf20Sopenharmony_ci * TX gain is selected with CCK_TX_AGC and OFDM_TX_AGC regs 12078c2ecf20Sopenharmony_ci */ 12088c2ecf20Sopenharmony_ci reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_GAIN; 12098c2ecf20Sopenharmony_ci reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL; 12108c2ecf20Sopenharmony_ci reg |= RTL818X_TX_AGC_CTL_FEEDBACK_ANT; 12118c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->TX_AGC_CTL, reg); 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci /* disable early TX */ 12148c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, (u8 __iomem *)priv->map + 0xec, 0x3f); 12158c2ecf20Sopenharmony_ci } 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci reg = rtl818x_ioread32(priv, &priv->map->TX_CONF); 12188c2ecf20Sopenharmony_ci reg |= (6 << 21 /* MAX TX DMA */) | 12198c2ecf20Sopenharmony_ci RTL818X_TX_CONF_NO_ICV; 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) 12228c2ecf20Sopenharmony_ci reg |= 1<<30; /* "duration procedure mode" */ 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci if (priv->chip_family != RTL818X_CHIP_FAMILY_RTL8180) 12258c2ecf20Sopenharmony_ci reg &= ~RTL818X_TX_CONF_PROBE_DTS; 12268c2ecf20Sopenharmony_ci else 12278c2ecf20Sopenharmony_ci reg &= ~RTL818X_TX_CONF_HW_SEQNUM; 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci reg &= ~RTL818X_TX_CONF_DISCW; 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci /* different meaning, same value on both rtl8185 and rtl8180 */ 12328c2ecf20Sopenharmony_ci reg &= ~RTL818X_TX_CONF_SAT_HWPLCP; 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg); 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci reg = rtl818x_ioread8(priv, &priv->map->CMD); 12378c2ecf20Sopenharmony_ci reg |= RTL818X_CMD_RX_ENABLE; 12388c2ecf20Sopenharmony_ci reg |= RTL818X_CMD_TX_ENABLE; 12398c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->CMD, reg); 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci return 0; 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci err_free_rings: 12448c2ecf20Sopenharmony_ci rtl8180_free_rx_ring(dev); 12458c2ecf20Sopenharmony_ci for (i = 0; i < (dev->queues + 1); i++) 12468c2ecf20Sopenharmony_ci if (priv->tx_ring[i].desc) 12478c2ecf20Sopenharmony_ci rtl8180_free_tx_ring(dev, i); 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci return ret; 12508c2ecf20Sopenharmony_ci} 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_cistatic void rtl8180_stop(struct ieee80211_hw *dev) 12538c2ecf20Sopenharmony_ci{ 12548c2ecf20Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 12558c2ecf20Sopenharmony_ci u8 reg; 12568c2ecf20Sopenharmony_ci int i; 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci rtl8180_int_disable(dev); 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci reg = rtl818x_ioread8(priv, &priv->map->CMD); 12618c2ecf20Sopenharmony_ci reg &= ~RTL818X_CMD_TX_ENABLE; 12628c2ecf20Sopenharmony_ci reg &= ~RTL818X_CMD_RX_ENABLE; 12638c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->CMD, reg); 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci priv->rf->stop(dev); 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); 12688c2ecf20Sopenharmony_ci reg = rtl818x_ioread8(priv, &priv->map->CONFIG4); 12698c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->CONFIG4, reg | RTL818X_CONFIG4_VCOOFF); 12708c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci free_irq(priv->pdev->irq, dev); 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci rtl8180_free_rx_ring(dev); 12758c2ecf20Sopenharmony_ci for (i = 0; i < (dev->queues + 1); i++) 12768c2ecf20Sopenharmony_ci rtl8180_free_tx_ring(dev, i); 12778c2ecf20Sopenharmony_ci} 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_cistatic u64 rtl8180_get_tsf(struct ieee80211_hw *dev, 12808c2ecf20Sopenharmony_ci struct ieee80211_vif *vif) 12818c2ecf20Sopenharmony_ci{ 12828c2ecf20Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci return rtl818x_ioread32(priv, &priv->map->TSFT[0]) | 12858c2ecf20Sopenharmony_ci (u64)(rtl818x_ioread32(priv, &priv->map->TSFT[1])) << 32; 12868c2ecf20Sopenharmony_ci} 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_cistatic void rtl8180_beacon_work(struct work_struct *work) 12898c2ecf20Sopenharmony_ci{ 12908c2ecf20Sopenharmony_ci struct rtl8180_vif *vif_priv = 12918c2ecf20Sopenharmony_ci container_of(work, struct rtl8180_vif, beacon_work.work); 12928c2ecf20Sopenharmony_ci struct ieee80211_vif *vif = 12938c2ecf20Sopenharmony_ci container_of((void *)vif_priv, struct ieee80211_vif, drv_priv); 12948c2ecf20Sopenharmony_ci struct ieee80211_hw *dev = vif_priv->dev; 12958c2ecf20Sopenharmony_ci struct ieee80211_mgmt *mgmt; 12968c2ecf20Sopenharmony_ci struct sk_buff *skb; 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci /* don't overflow the tx ring */ 12998c2ecf20Sopenharmony_ci if (ieee80211_queue_stopped(dev, 0)) 13008c2ecf20Sopenharmony_ci goto resched; 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci /* grab a fresh beacon */ 13038c2ecf20Sopenharmony_ci skb = ieee80211_beacon_get(dev, vif); 13048c2ecf20Sopenharmony_ci if (!skb) 13058c2ecf20Sopenharmony_ci goto resched; 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci /* 13088c2ecf20Sopenharmony_ci * update beacon timestamp w/ TSF value 13098c2ecf20Sopenharmony_ci * TODO: make hardware update beacon timestamp 13108c2ecf20Sopenharmony_ci */ 13118c2ecf20Sopenharmony_ci mgmt = (struct ieee80211_mgmt *)skb->data; 13128c2ecf20Sopenharmony_ci mgmt->u.beacon.timestamp = cpu_to_le64(rtl8180_get_tsf(dev, vif)); 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci /* TODO: use actual beacon queue */ 13158c2ecf20Sopenharmony_ci skb_set_queue_mapping(skb, 0); 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci rtl8180_tx(dev, NULL, skb); 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ciresched: 13208c2ecf20Sopenharmony_ci /* 13218c2ecf20Sopenharmony_ci * schedule next beacon 13228c2ecf20Sopenharmony_ci * TODO: use hardware support for beacon timing 13238c2ecf20Sopenharmony_ci */ 13248c2ecf20Sopenharmony_ci schedule_delayed_work(&vif_priv->beacon_work, 13258c2ecf20Sopenharmony_ci usecs_to_jiffies(1024 * vif->bss_conf.beacon_int)); 13268c2ecf20Sopenharmony_ci} 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_cistatic int rtl8180_add_interface(struct ieee80211_hw *dev, 13298c2ecf20Sopenharmony_ci struct ieee80211_vif *vif) 13308c2ecf20Sopenharmony_ci{ 13318c2ecf20Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 13328c2ecf20Sopenharmony_ci struct rtl8180_vif *vif_priv; 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci /* 13358c2ecf20Sopenharmony_ci * We only support one active interface at a time. 13368c2ecf20Sopenharmony_ci */ 13378c2ecf20Sopenharmony_ci if (priv->vif) 13388c2ecf20Sopenharmony_ci return -EBUSY; 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci switch (vif->type) { 13418c2ecf20Sopenharmony_ci case NL80211_IFTYPE_STATION: 13428c2ecf20Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 13438c2ecf20Sopenharmony_ci break; 13448c2ecf20Sopenharmony_ci default: 13458c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 13468c2ecf20Sopenharmony_ci } 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci priv->vif = vif; 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci /* Initialize driver private area */ 13518c2ecf20Sopenharmony_ci vif_priv = (struct rtl8180_vif *)&vif->drv_priv; 13528c2ecf20Sopenharmony_ci vif_priv->dev = dev; 13538c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&vif_priv->beacon_work, rtl8180_beacon_work); 13548c2ecf20Sopenharmony_ci vif_priv->enable_beacon = false; 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); 13578c2ecf20Sopenharmony_ci rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->MAC[0], 13588c2ecf20Sopenharmony_ci le32_to_cpu(*(__le32 *)vif->addr)); 13598c2ecf20Sopenharmony_ci rtl818x_iowrite16(priv, (__le16 __iomem *)&priv->map->MAC[4], 13608c2ecf20Sopenharmony_ci le16_to_cpu(*(__le16 *)(vif->addr + 4))); 13618c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci return 0; 13648c2ecf20Sopenharmony_ci} 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_cistatic void rtl8180_remove_interface(struct ieee80211_hw *dev, 13678c2ecf20Sopenharmony_ci struct ieee80211_vif *vif) 13688c2ecf20Sopenharmony_ci{ 13698c2ecf20Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 13708c2ecf20Sopenharmony_ci priv->vif = NULL; 13718c2ecf20Sopenharmony_ci} 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_cistatic int rtl8180_config(struct ieee80211_hw *dev, u32 changed) 13748c2ecf20Sopenharmony_ci{ 13758c2ecf20Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 13768c2ecf20Sopenharmony_ci struct ieee80211_conf *conf = &dev->conf; 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci priv->rf->set_chan(dev, conf); 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci return 0; 13818c2ecf20Sopenharmony_ci} 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_cistatic void rtl8187se_conf_ac_parm(struct ieee80211_hw *dev, u8 queue) 13848c2ecf20Sopenharmony_ci{ 13858c2ecf20Sopenharmony_ci const struct ieee80211_tx_queue_params *params; 13868c2ecf20Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci /* hw value */ 13898c2ecf20Sopenharmony_ci u32 ac_param; 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci u8 aifs; 13928c2ecf20Sopenharmony_ci u8 txop; 13938c2ecf20Sopenharmony_ci u8 cw_min, cw_max; 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci params = &priv->queue_param[queue]; 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci cw_min = fls(params->cw_min); 13988c2ecf20Sopenharmony_ci cw_max = fls(params->cw_max); 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci aifs = 10 + params->aifs * priv->slot_time; 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci /* TODO: check if txop HW is in us (mult by 32) */ 14038c2ecf20Sopenharmony_ci txop = params->txop; 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ci ac_param = txop << AC_PARAM_TXOP_LIMIT_SHIFT | 14068c2ecf20Sopenharmony_ci cw_max << AC_PARAM_ECW_MAX_SHIFT | 14078c2ecf20Sopenharmony_ci cw_min << AC_PARAM_ECW_MIN_SHIFT | 14088c2ecf20Sopenharmony_ci aifs << AC_PARAM_AIFS_SHIFT; 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci switch (queue) { 14118c2ecf20Sopenharmony_ci case IEEE80211_AC_BK: 14128c2ecf20Sopenharmony_ci rtl818x_iowrite32(priv, &priv->map->AC_BK_PARAM, ac_param); 14138c2ecf20Sopenharmony_ci break; 14148c2ecf20Sopenharmony_ci case IEEE80211_AC_BE: 14158c2ecf20Sopenharmony_ci rtl818x_iowrite32(priv, &priv->map->AC_BE_PARAM, ac_param); 14168c2ecf20Sopenharmony_ci break; 14178c2ecf20Sopenharmony_ci case IEEE80211_AC_VI: 14188c2ecf20Sopenharmony_ci rtl818x_iowrite32(priv, &priv->map->AC_VI_PARAM, ac_param); 14198c2ecf20Sopenharmony_ci break; 14208c2ecf20Sopenharmony_ci case IEEE80211_AC_VO: 14218c2ecf20Sopenharmony_ci rtl818x_iowrite32(priv, &priv->map->AC_VO_PARAM, ac_param); 14228c2ecf20Sopenharmony_ci break; 14238c2ecf20Sopenharmony_ci } 14248c2ecf20Sopenharmony_ci} 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_cistatic int rtl8180_conf_tx(struct ieee80211_hw *dev, 14278c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, u16 queue, 14288c2ecf20Sopenharmony_ci const struct ieee80211_tx_queue_params *params) 14298c2ecf20Sopenharmony_ci{ 14308c2ecf20Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 14318c2ecf20Sopenharmony_ci u8 cw_min, cw_max; 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci /* nothing to do ? */ 14348c2ecf20Sopenharmony_ci if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8180) 14358c2ecf20Sopenharmony_ci return 0; 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci cw_min = fls(params->cw_min); 14388c2ecf20Sopenharmony_ci cw_max = fls(params->cw_max); 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) { 14418c2ecf20Sopenharmony_ci priv->queue_param[queue] = *params; 14428c2ecf20Sopenharmony_ci rtl8187se_conf_ac_parm(dev, queue); 14438c2ecf20Sopenharmony_ci } else 14448c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->CW_VAL, 14458c2ecf20Sopenharmony_ci (cw_max << 4) | cw_min); 14468c2ecf20Sopenharmony_ci return 0; 14478c2ecf20Sopenharmony_ci} 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_cistatic void rtl8180_conf_erp(struct ieee80211_hw *dev, 14508c2ecf20Sopenharmony_ci struct ieee80211_bss_conf *info) 14518c2ecf20Sopenharmony_ci{ 14528c2ecf20Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 14538c2ecf20Sopenharmony_ci u8 sifs, difs; 14548c2ecf20Sopenharmony_ci int eifs; 14558c2ecf20Sopenharmony_ci u8 hw_eifs; 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci /* TODO: should we do something ? */ 14588c2ecf20Sopenharmony_ci if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8180) 14598c2ecf20Sopenharmony_ci return; 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci /* I _hope_ this means 10uS for the HW. 14628c2ecf20Sopenharmony_ci * In reference code it is 0x22 for 14638c2ecf20Sopenharmony_ci * both rtl8187L and rtl8187SE 14648c2ecf20Sopenharmony_ci */ 14658c2ecf20Sopenharmony_ci sifs = 0x22; 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci if (info->use_short_slot) 14688c2ecf20Sopenharmony_ci priv->slot_time = 9; 14698c2ecf20Sopenharmony_ci else 14708c2ecf20Sopenharmony_ci priv->slot_time = 20; 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci /* 10 is SIFS time in uS */ 14738c2ecf20Sopenharmony_ci difs = 10 + 2 * priv->slot_time; 14748c2ecf20Sopenharmony_ci eifs = 10 + difs + priv->ack_time; 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci /* HW should use 4uS units for EIFS (I'm sure for rtl8185)*/ 14778c2ecf20Sopenharmony_ci hw_eifs = DIV_ROUND_UP(eifs, 4); 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->SLOT, priv->slot_time); 14818c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->SIFS, sifs); 14828c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->DIFS, difs); 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci /* from reference code. set ack timeout reg = eifs reg */ 14858c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->CARRIER_SENSE_COUNTER, hw_eifs); 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) 14888c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->EIFS_8187SE, hw_eifs); 14898c2ecf20Sopenharmony_ci else if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8185) { 14908c2ecf20Sopenharmony_ci /* rtl8187/rtl8185 HW bug. After EIFS is elapsed, 14918c2ecf20Sopenharmony_ci * the HW still wait for DIFS. 14928c2ecf20Sopenharmony_ci * HW uses 4uS units for EIFS. 14938c2ecf20Sopenharmony_ci */ 14948c2ecf20Sopenharmony_ci hw_eifs = DIV_ROUND_UP(eifs - difs, 4); 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->EIFS, hw_eifs); 14978c2ecf20Sopenharmony_ci } 14988c2ecf20Sopenharmony_ci} 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_cistatic void rtl8180_bss_info_changed(struct ieee80211_hw *dev, 15018c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 15028c2ecf20Sopenharmony_ci struct ieee80211_bss_conf *info, 15038c2ecf20Sopenharmony_ci u32 changed) 15048c2ecf20Sopenharmony_ci{ 15058c2ecf20Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 15068c2ecf20Sopenharmony_ci struct rtl8180_vif *vif_priv; 15078c2ecf20Sopenharmony_ci int i; 15088c2ecf20Sopenharmony_ci u8 reg; 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci vif_priv = (struct rtl8180_vif *)&vif->drv_priv; 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci if (changed & BSS_CHANGED_BSSID) { 15138c2ecf20Sopenharmony_ci rtl818x_iowrite16(priv, (__le16 __iomem *)&priv->map->BSSID[0], 15148c2ecf20Sopenharmony_ci le16_to_cpu(*(__le16 *)info->bssid)); 15158c2ecf20Sopenharmony_ci rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->BSSID[2], 15168c2ecf20Sopenharmony_ci le32_to_cpu(*(__le32 *)(info->bssid + 2))); 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci if (is_valid_ether_addr(info->bssid)) { 15198c2ecf20Sopenharmony_ci if (vif->type == NL80211_IFTYPE_ADHOC) 15208c2ecf20Sopenharmony_ci reg = RTL818X_MSR_ADHOC; 15218c2ecf20Sopenharmony_ci else 15228c2ecf20Sopenharmony_ci reg = RTL818X_MSR_INFRA; 15238c2ecf20Sopenharmony_ci } else 15248c2ecf20Sopenharmony_ci reg = RTL818X_MSR_NO_LINK; 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) 15278c2ecf20Sopenharmony_ci reg |= RTL818X_MSR_ENEDCA; 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->MSR, reg); 15308c2ecf20Sopenharmony_ci } 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci if (changed & BSS_CHANGED_BASIC_RATES) 15338c2ecf20Sopenharmony_ci rtl8180_conf_basic_rates(dev, info->basic_rates); 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci if (changed & (BSS_CHANGED_ERP_SLOT | BSS_CHANGED_ERP_PREAMBLE)) { 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci /* when preamble changes, acktime duration changes, and erp must 15388c2ecf20Sopenharmony_ci * be recalculated. ACK time is calculated at lowest rate. 15398c2ecf20Sopenharmony_ci * Since mac80211 include SIFS time we remove it (-10) 15408c2ecf20Sopenharmony_ci */ 15418c2ecf20Sopenharmony_ci priv->ack_time = 15428c2ecf20Sopenharmony_ci le16_to_cpu(ieee80211_generic_frame_duration(dev, 15438c2ecf20Sopenharmony_ci priv->vif, 15448c2ecf20Sopenharmony_ci NL80211_BAND_2GHZ, 10, 15458c2ecf20Sopenharmony_ci &priv->rates[0])) - 10; 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci rtl8180_conf_erp(dev, info); 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci /* mac80211 supplies aifs_n to driver and calls 15508c2ecf20Sopenharmony_ci * conf_tx callback whether aifs_n changes, NOT 15518c2ecf20Sopenharmony_ci * when aifs changes. 15528c2ecf20Sopenharmony_ci * Aifs should be recalculated if slot changes. 15538c2ecf20Sopenharmony_ci */ 15548c2ecf20Sopenharmony_ci if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) { 15558c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) 15568c2ecf20Sopenharmony_ci rtl8187se_conf_ac_parm(dev, i); 15578c2ecf20Sopenharmony_ci } 15588c2ecf20Sopenharmony_ci } 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci if (changed & BSS_CHANGED_BEACON_ENABLED) 15618c2ecf20Sopenharmony_ci vif_priv->enable_beacon = info->enable_beacon; 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci if (changed & (BSS_CHANGED_BEACON_ENABLED | BSS_CHANGED_BEACON)) { 15648c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&vif_priv->beacon_work); 15658c2ecf20Sopenharmony_ci if (vif_priv->enable_beacon) 15668c2ecf20Sopenharmony_ci schedule_work(&vif_priv->beacon_work.work); 15678c2ecf20Sopenharmony_ci } 15688c2ecf20Sopenharmony_ci} 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_cistatic u64 rtl8180_prepare_multicast(struct ieee80211_hw *dev, 15718c2ecf20Sopenharmony_ci struct netdev_hw_addr_list *mc_list) 15728c2ecf20Sopenharmony_ci{ 15738c2ecf20Sopenharmony_ci return netdev_hw_addr_list_count(mc_list); 15748c2ecf20Sopenharmony_ci} 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_cistatic void rtl8180_configure_filter(struct ieee80211_hw *dev, 15778c2ecf20Sopenharmony_ci unsigned int changed_flags, 15788c2ecf20Sopenharmony_ci unsigned int *total_flags, 15798c2ecf20Sopenharmony_ci u64 multicast) 15808c2ecf20Sopenharmony_ci{ 15818c2ecf20Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_ci if (changed_flags & FIF_FCSFAIL) 15848c2ecf20Sopenharmony_ci priv->rx_conf ^= RTL818X_RX_CONF_FCS; 15858c2ecf20Sopenharmony_ci if (changed_flags & FIF_CONTROL) 15868c2ecf20Sopenharmony_ci priv->rx_conf ^= RTL818X_RX_CONF_CTRL; 15878c2ecf20Sopenharmony_ci if (changed_flags & FIF_OTHER_BSS) 15888c2ecf20Sopenharmony_ci priv->rx_conf ^= RTL818X_RX_CONF_MONITOR; 15898c2ecf20Sopenharmony_ci if (*total_flags & FIF_ALLMULTI || multicast > 0) 15908c2ecf20Sopenharmony_ci priv->rx_conf |= RTL818X_RX_CONF_MULTICAST; 15918c2ecf20Sopenharmony_ci else 15928c2ecf20Sopenharmony_ci priv->rx_conf &= ~RTL818X_RX_CONF_MULTICAST; 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci *total_flags = 0; 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci if (priv->rx_conf & RTL818X_RX_CONF_FCS) 15978c2ecf20Sopenharmony_ci *total_flags |= FIF_FCSFAIL; 15988c2ecf20Sopenharmony_ci if (priv->rx_conf & RTL818X_RX_CONF_CTRL) 15998c2ecf20Sopenharmony_ci *total_flags |= FIF_CONTROL; 16008c2ecf20Sopenharmony_ci if (priv->rx_conf & RTL818X_RX_CONF_MONITOR) 16018c2ecf20Sopenharmony_ci *total_flags |= FIF_OTHER_BSS; 16028c2ecf20Sopenharmony_ci if (priv->rx_conf & RTL818X_RX_CONF_MULTICAST) 16038c2ecf20Sopenharmony_ci *total_flags |= FIF_ALLMULTI; 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci rtl818x_iowrite32(priv, &priv->map->RX_CONF, priv->rx_conf); 16068c2ecf20Sopenharmony_ci} 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_cistatic const struct ieee80211_ops rtl8180_ops = { 16098c2ecf20Sopenharmony_ci .tx = rtl8180_tx, 16108c2ecf20Sopenharmony_ci .start = rtl8180_start, 16118c2ecf20Sopenharmony_ci .stop = rtl8180_stop, 16128c2ecf20Sopenharmony_ci .add_interface = rtl8180_add_interface, 16138c2ecf20Sopenharmony_ci .remove_interface = rtl8180_remove_interface, 16148c2ecf20Sopenharmony_ci .config = rtl8180_config, 16158c2ecf20Sopenharmony_ci .bss_info_changed = rtl8180_bss_info_changed, 16168c2ecf20Sopenharmony_ci .conf_tx = rtl8180_conf_tx, 16178c2ecf20Sopenharmony_ci .prepare_multicast = rtl8180_prepare_multicast, 16188c2ecf20Sopenharmony_ci .configure_filter = rtl8180_configure_filter, 16198c2ecf20Sopenharmony_ci .get_tsf = rtl8180_get_tsf, 16208c2ecf20Sopenharmony_ci}; 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_cistatic void rtl8180_eeprom_register_read(struct eeprom_93cx6 *eeprom) 16238c2ecf20Sopenharmony_ci{ 16248c2ecf20Sopenharmony_ci struct rtl8180_priv *priv = eeprom->data; 16258c2ecf20Sopenharmony_ci u8 reg = rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci eeprom->reg_data_in = reg & RTL818X_EEPROM_CMD_WRITE; 16288c2ecf20Sopenharmony_ci eeprom->reg_data_out = reg & RTL818X_EEPROM_CMD_READ; 16298c2ecf20Sopenharmony_ci eeprom->reg_data_clock = reg & RTL818X_EEPROM_CMD_CK; 16308c2ecf20Sopenharmony_ci eeprom->reg_chip_select = reg & RTL818X_EEPROM_CMD_CS; 16318c2ecf20Sopenharmony_ci} 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_cistatic void rtl8180_eeprom_register_write(struct eeprom_93cx6 *eeprom) 16348c2ecf20Sopenharmony_ci{ 16358c2ecf20Sopenharmony_ci struct rtl8180_priv *priv = eeprom->data; 16368c2ecf20Sopenharmony_ci u8 reg = 2 << 6; 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci if (eeprom->reg_data_in) 16398c2ecf20Sopenharmony_ci reg |= RTL818X_EEPROM_CMD_WRITE; 16408c2ecf20Sopenharmony_ci if (eeprom->reg_data_out) 16418c2ecf20Sopenharmony_ci reg |= RTL818X_EEPROM_CMD_READ; 16428c2ecf20Sopenharmony_ci if (eeprom->reg_data_clock) 16438c2ecf20Sopenharmony_ci reg |= RTL818X_EEPROM_CMD_CK; 16448c2ecf20Sopenharmony_ci if (eeprom->reg_chip_select) 16458c2ecf20Sopenharmony_ci reg |= RTL818X_EEPROM_CMD_CS; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, reg); 16488c2ecf20Sopenharmony_ci rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); 16498c2ecf20Sopenharmony_ci udelay(10); 16508c2ecf20Sopenharmony_ci} 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_cistatic void rtl8180_eeprom_read(struct rtl8180_priv *priv) 16538c2ecf20Sopenharmony_ci{ 16548c2ecf20Sopenharmony_ci struct eeprom_93cx6 eeprom; 16558c2ecf20Sopenharmony_ci int eeprom_cck_table_adr; 16568c2ecf20Sopenharmony_ci u16 eeprom_val; 16578c2ecf20Sopenharmony_ci int i; 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci eeprom.data = priv; 16608c2ecf20Sopenharmony_ci eeprom.register_read = rtl8180_eeprom_register_read; 16618c2ecf20Sopenharmony_ci eeprom.register_write = rtl8180_eeprom_register_write; 16628c2ecf20Sopenharmony_ci if (rtl818x_ioread32(priv, &priv->map->RX_CONF) & (1 << 6)) 16638c2ecf20Sopenharmony_ci eeprom.width = PCI_EEPROM_WIDTH_93C66; 16648c2ecf20Sopenharmony_ci else 16658c2ecf20Sopenharmony_ci eeprom.width = PCI_EEPROM_WIDTH_93C46; 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, 16688c2ecf20Sopenharmony_ci RTL818X_EEPROM_CMD_PROGRAM); 16698c2ecf20Sopenharmony_ci rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); 16708c2ecf20Sopenharmony_ci udelay(10); 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci eeprom_93cx6_read(&eeprom, 0x06, &eeprom_val); 16738c2ecf20Sopenharmony_ci eeprom_val &= 0xFF; 16748c2ecf20Sopenharmony_ci priv->rf_type = eeprom_val; 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci eeprom_93cx6_read(&eeprom, 0x17, &eeprom_val); 16778c2ecf20Sopenharmony_ci priv->csthreshold = eeprom_val >> 8; 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci eeprom_93cx6_multiread(&eeprom, 0x7, (__le16 *)priv->mac_addr, 3); 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) 16828c2ecf20Sopenharmony_ci eeprom_cck_table_adr = 0x30; 16838c2ecf20Sopenharmony_ci else 16848c2ecf20Sopenharmony_ci eeprom_cck_table_adr = 0x10; 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci /* CCK TX power */ 16878c2ecf20Sopenharmony_ci for (i = 0; i < 14; i += 2) { 16888c2ecf20Sopenharmony_ci u16 txpwr; 16898c2ecf20Sopenharmony_ci eeprom_93cx6_read(&eeprom, eeprom_cck_table_adr + (i >> 1), 16908c2ecf20Sopenharmony_ci &txpwr); 16918c2ecf20Sopenharmony_ci priv->channels[i].hw_value = txpwr & 0xFF; 16928c2ecf20Sopenharmony_ci priv->channels[i + 1].hw_value = txpwr >> 8; 16938c2ecf20Sopenharmony_ci } 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci /* OFDM TX power */ 16968c2ecf20Sopenharmony_ci if (priv->chip_family != RTL818X_CHIP_FAMILY_RTL8180) { 16978c2ecf20Sopenharmony_ci for (i = 0; i < 14; i += 2) { 16988c2ecf20Sopenharmony_ci u16 txpwr; 16998c2ecf20Sopenharmony_ci eeprom_93cx6_read(&eeprom, 0x20 + (i >> 1), &txpwr); 17008c2ecf20Sopenharmony_ci priv->channels[i].hw_value |= (txpwr & 0xFF) << 8; 17018c2ecf20Sopenharmony_ci priv->channels[i + 1].hw_value |= txpwr & 0xFF00; 17028c2ecf20Sopenharmony_ci } 17038c2ecf20Sopenharmony_ci } 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8180) { 17068c2ecf20Sopenharmony_ci __le32 anaparam; 17078c2ecf20Sopenharmony_ci eeprom_93cx6_multiread(&eeprom, 0xD, (__le16 *)&anaparam, 2); 17088c2ecf20Sopenharmony_ci priv->anaparam = le32_to_cpu(anaparam); 17098c2ecf20Sopenharmony_ci eeprom_93cx6_read(&eeprom, 0x19, &priv->rfparam); 17108c2ecf20Sopenharmony_ci } 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) { 17138c2ecf20Sopenharmony_ci eeprom_93cx6_read(&eeprom, 0x3F, &eeprom_val); 17148c2ecf20Sopenharmony_ci priv->antenna_diversity_en = !!(eeprom_val & 0x100); 17158c2ecf20Sopenharmony_ci priv->antenna_diversity_default = (eeprom_val & 0xC00) == 0x400; 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_ci eeprom_93cx6_read(&eeprom, 0x7C, &eeprom_val); 17188c2ecf20Sopenharmony_ci priv->xtal_out = eeprom_val & 0xF; 17198c2ecf20Sopenharmony_ci priv->xtal_in = (eeprom_val & 0xF0) >> 4; 17208c2ecf20Sopenharmony_ci priv->xtal_cal = !!(eeprom_val & 0x1000); 17218c2ecf20Sopenharmony_ci priv->thermal_meter_val = (eeprom_val & 0xF00) >> 8; 17228c2ecf20Sopenharmony_ci priv->thermal_meter_en = !!(eeprom_val & 0x2000); 17238c2ecf20Sopenharmony_ci } 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_ci rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, 17268c2ecf20Sopenharmony_ci RTL818X_EEPROM_CMD_NORMAL); 17278c2ecf20Sopenharmony_ci} 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_cistatic int rtl8180_probe(struct pci_dev *pdev, 17308c2ecf20Sopenharmony_ci const struct pci_device_id *id) 17318c2ecf20Sopenharmony_ci{ 17328c2ecf20Sopenharmony_ci struct ieee80211_hw *dev; 17338c2ecf20Sopenharmony_ci struct rtl8180_priv *priv; 17348c2ecf20Sopenharmony_ci unsigned long mem_len; 17358c2ecf20Sopenharmony_ci unsigned int io_len; 17368c2ecf20Sopenharmony_ci int err; 17378c2ecf20Sopenharmony_ci const char *chip_name, *rf_name = NULL; 17388c2ecf20Sopenharmony_ci u32 reg; 17398c2ecf20Sopenharmony_ci 17408c2ecf20Sopenharmony_ci err = pci_enable_device(pdev); 17418c2ecf20Sopenharmony_ci if (err) { 17428c2ecf20Sopenharmony_ci printk(KERN_ERR "%s (rtl8180): Cannot enable new PCI device\n", 17438c2ecf20Sopenharmony_ci pci_name(pdev)); 17448c2ecf20Sopenharmony_ci return err; 17458c2ecf20Sopenharmony_ci } 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_ci err = pci_request_regions(pdev, KBUILD_MODNAME); 17488c2ecf20Sopenharmony_ci if (err) { 17498c2ecf20Sopenharmony_ci printk(KERN_ERR "%s (rtl8180): Cannot obtain PCI resources\n", 17508c2ecf20Sopenharmony_ci pci_name(pdev)); 17518c2ecf20Sopenharmony_ci goto err_disable_dev; 17528c2ecf20Sopenharmony_ci } 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_ci io_len = pci_resource_len(pdev, 0); 17558c2ecf20Sopenharmony_ci mem_len = pci_resource_len(pdev, 1); 17568c2ecf20Sopenharmony_ci 17578c2ecf20Sopenharmony_ci if (mem_len < sizeof(struct rtl818x_csr) || 17588c2ecf20Sopenharmony_ci io_len < sizeof(struct rtl818x_csr)) { 17598c2ecf20Sopenharmony_ci printk(KERN_ERR "%s (rtl8180): Too short PCI resources\n", 17608c2ecf20Sopenharmony_ci pci_name(pdev)); 17618c2ecf20Sopenharmony_ci err = -ENOMEM; 17628c2ecf20Sopenharmony_ci goto err_free_reg; 17638c2ecf20Sopenharmony_ci } 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_ci if ((err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) || 17668c2ecf20Sopenharmony_ci (err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)))) { 17678c2ecf20Sopenharmony_ci printk(KERN_ERR "%s (rtl8180): No suitable DMA available\n", 17688c2ecf20Sopenharmony_ci pci_name(pdev)); 17698c2ecf20Sopenharmony_ci goto err_free_reg; 17708c2ecf20Sopenharmony_ci } 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci pci_set_master(pdev); 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci dev = ieee80211_alloc_hw(sizeof(*priv), &rtl8180_ops); 17758c2ecf20Sopenharmony_ci if (!dev) { 17768c2ecf20Sopenharmony_ci printk(KERN_ERR "%s (rtl8180): ieee80211 alloc failed\n", 17778c2ecf20Sopenharmony_ci pci_name(pdev)); 17788c2ecf20Sopenharmony_ci err = -ENOMEM; 17798c2ecf20Sopenharmony_ci goto err_free_reg; 17808c2ecf20Sopenharmony_ci } 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_ci priv = dev->priv; 17838c2ecf20Sopenharmony_ci priv->pdev = pdev; 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_ci dev->max_rates = 1; 17868c2ecf20Sopenharmony_ci SET_IEEE80211_DEV(dev, &pdev->dev); 17878c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, dev); 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_ci priv->map_pio = false; 17908c2ecf20Sopenharmony_ci priv->map = pci_iomap(pdev, 1, mem_len); 17918c2ecf20Sopenharmony_ci if (!priv->map) { 17928c2ecf20Sopenharmony_ci priv->map = pci_iomap(pdev, 0, io_len); 17938c2ecf20Sopenharmony_ci priv->map_pio = true; 17948c2ecf20Sopenharmony_ci } 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ci if (!priv->map) { 17978c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Cannot map device memory/PIO\n"); 17988c2ecf20Sopenharmony_ci err = -ENOMEM; 17998c2ecf20Sopenharmony_ci goto err_free_dev; 18008c2ecf20Sopenharmony_ci } 18018c2ecf20Sopenharmony_ci 18028c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(priv->channels) != sizeof(rtl818x_channels)); 18038c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(priv->rates) != sizeof(rtl818x_rates)); 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci memcpy(priv->channels, rtl818x_channels, sizeof(rtl818x_channels)); 18068c2ecf20Sopenharmony_ci memcpy(priv->rates, rtl818x_rates, sizeof(rtl818x_rates)); 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci priv->band.band = NL80211_BAND_2GHZ; 18098c2ecf20Sopenharmony_ci priv->band.channels = priv->channels; 18108c2ecf20Sopenharmony_ci priv->band.n_channels = ARRAY_SIZE(rtl818x_channels); 18118c2ecf20Sopenharmony_ci priv->band.bitrates = priv->rates; 18128c2ecf20Sopenharmony_ci priv->band.n_bitrates = 4; 18138c2ecf20Sopenharmony_ci dev->wiphy->bands[NL80211_BAND_2GHZ] = &priv->band; 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci ieee80211_hw_set(dev, HOST_BROADCAST_PS_BUFFERING); 18168c2ecf20Sopenharmony_ci ieee80211_hw_set(dev, RX_INCLUDES_FCS); 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_ci dev->vif_data_size = sizeof(struct rtl8180_vif); 18198c2ecf20Sopenharmony_ci dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | 18208c2ecf20Sopenharmony_ci BIT(NL80211_IFTYPE_ADHOC); 18218c2ecf20Sopenharmony_ci dev->max_signal = 65; 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci reg = rtl818x_ioread32(priv, &priv->map->TX_CONF); 18248c2ecf20Sopenharmony_ci reg &= RTL818X_TX_CONF_HWVER_MASK; 18258c2ecf20Sopenharmony_ci switch (reg) { 18268c2ecf20Sopenharmony_ci case RTL818X_TX_CONF_R8180_ABCD: 18278c2ecf20Sopenharmony_ci chip_name = "RTL8180"; 18288c2ecf20Sopenharmony_ci priv->chip_family = RTL818X_CHIP_FAMILY_RTL8180; 18298c2ecf20Sopenharmony_ci break; 18308c2ecf20Sopenharmony_ci 18318c2ecf20Sopenharmony_ci case RTL818X_TX_CONF_R8180_F: 18328c2ecf20Sopenharmony_ci chip_name = "RTL8180vF"; 18338c2ecf20Sopenharmony_ci priv->chip_family = RTL818X_CHIP_FAMILY_RTL8180; 18348c2ecf20Sopenharmony_ci break; 18358c2ecf20Sopenharmony_ci 18368c2ecf20Sopenharmony_ci case RTL818X_TX_CONF_R8185_ABC: 18378c2ecf20Sopenharmony_ci chip_name = "RTL8185"; 18388c2ecf20Sopenharmony_ci priv->chip_family = RTL818X_CHIP_FAMILY_RTL8185; 18398c2ecf20Sopenharmony_ci break; 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_ci case RTL818X_TX_CONF_R8185_D: 18428c2ecf20Sopenharmony_ci chip_name = "RTL8185vD"; 18438c2ecf20Sopenharmony_ci priv->chip_family = RTL818X_CHIP_FAMILY_RTL8185; 18448c2ecf20Sopenharmony_ci break; 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_ci case RTL818X_TX_CONF_RTL8187SE: 18478c2ecf20Sopenharmony_ci chip_name = "RTL8187SE"; 18488c2ecf20Sopenharmony_ci if (priv->map_pio) { 18498c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 18508c2ecf20Sopenharmony_ci "MMIO failed. PIO not supported on RTL8187SE\n"); 18518c2ecf20Sopenharmony_ci err = -ENOMEM; 18528c2ecf20Sopenharmony_ci goto err_iounmap; 18538c2ecf20Sopenharmony_ci } 18548c2ecf20Sopenharmony_ci priv->chip_family = RTL818X_CHIP_FAMILY_RTL8187SE; 18558c2ecf20Sopenharmony_ci break; 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_ci default: 18588c2ecf20Sopenharmony_ci printk(KERN_ERR "%s (rtl8180): Unknown chip! (0x%x)\n", 18598c2ecf20Sopenharmony_ci pci_name(pdev), reg >> 25); 18608c2ecf20Sopenharmony_ci err = -ENODEV; 18618c2ecf20Sopenharmony_ci goto err_iounmap; 18628c2ecf20Sopenharmony_ci } 18638c2ecf20Sopenharmony_ci 18648c2ecf20Sopenharmony_ci /* we declare to MAC80211 all the queues except for beacon queue 18658c2ecf20Sopenharmony_ci * that will be eventually handled by DRV. 18668c2ecf20Sopenharmony_ci * TX rings are arranged in such a way that lower is the IDX, 18678c2ecf20Sopenharmony_ci * higher is the priority, in order to achieve direct mapping 18688c2ecf20Sopenharmony_ci * with mac80211, however the beacon queue is an exception and it 18698c2ecf20Sopenharmony_ci * is mapped on the highst tx ring IDX. 18708c2ecf20Sopenharmony_ci */ 18718c2ecf20Sopenharmony_ci if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) 18728c2ecf20Sopenharmony_ci dev->queues = RTL8187SE_NR_TX_QUEUES - 1; 18738c2ecf20Sopenharmony_ci else 18748c2ecf20Sopenharmony_ci dev->queues = RTL8180_NR_TX_QUEUES - 1; 18758c2ecf20Sopenharmony_ci 18768c2ecf20Sopenharmony_ci if (priv->chip_family != RTL818X_CHIP_FAMILY_RTL8180) { 18778c2ecf20Sopenharmony_ci priv->band.n_bitrates = ARRAY_SIZE(rtl818x_rates); 18788c2ecf20Sopenharmony_ci pci_try_set_mwi(pdev); 18798c2ecf20Sopenharmony_ci } 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_ci if (priv->chip_family != RTL818X_CHIP_FAMILY_RTL8180) 18828c2ecf20Sopenharmony_ci ieee80211_hw_set(dev, SIGNAL_DBM); 18838c2ecf20Sopenharmony_ci else 18848c2ecf20Sopenharmony_ci ieee80211_hw_set(dev, SIGNAL_UNSPEC); 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_ci wiphy_ext_feature_set(dev->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci rtl8180_eeprom_read(priv); 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_ci switch (priv->rf_type) { 18918c2ecf20Sopenharmony_ci case 1: rf_name = "Intersil"; 18928c2ecf20Sopenharmony_ci break; 18938c2ecf20Sopenharmony_ci case 2: rf_name = "RFMD"; 18948c2ecf20Sopenharmony_ci break; 18958c2ecf20Sopenharmony_ci case 3: priv->rf = &sa2400_rf_ops; 18968c2ecf20Sopenharmony_ci break; 18978c2ecf20Sopenharmony_ci case 4: priv->rf = &max2820_rf_ops; 18988c2ecf20Sopenharmony_ci break; 18998c2ecf20Sopenharmony_ci case 5: priv->rf = &grf5101_rf_ops; 19008c2ecf20Sopenharmony_ci break; 19018c2ecf20Sopenharmony_ci case 9: 19028c2ecf20Sopenharmony_ci if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) 19038c2ecf20Sopenharmony_ci priv->rf = rtl8187se_detect_rf(dev); 19048c2ecf20Sopenharmony_ci else 19058c2ecf20Sopenharmony_ci priv->rf = rtl8180_detect_rf(dev); 19068c2ecf20Sopenharmony_ci break; 19078c2ecf20Sopenharmony_ci case 10: 19088c2ecf20Sopenharmony_ci rf_name = "RTL8255"; 19098c2ecf20Sopenharmony_ci break; 19108c2ecf20Sopenharmony_ci default: 19118c2ecf20Sopenharmony_ci printk(KERN_ERR "%s (rtl8180): Unknown RF! (0x%x)\n", 19128c2ecf20Sopenharmony_ci pci_name(pdev), priv->rf_type); 19138c2ecf20Sopenharmony_ci err = -ENODEV; 19148c2ecf20Sopenharmony_ci goto err_iounmap; 19158c2ecf20Sopenharmony_ci } 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_ci if (!priv->rf) { 19188c2ecf20Sopenharmony_ci printk(KERN_ERR "%s (rtl8180): %s RF frontend not supported!\n", 19198c2ecf20Sopenharmony_ci pci_name(pdev), rf_name); 19208c2ecf20Sopenharmony_ci err = -ENODEV; 19218c2ecf20Sopenharmony_ci goto err_iounmap; 19228c2ecf20Sopenharmony_ci } 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(priv->mac_addr)) { 19258c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s (rtl8180): Invalid hwaddr! Using" 19268c2ecf20Sopenharmony_ci " randomly generated MAC addr\n", pci_name(pdev)); 19278c2ecf20Sopenharmony_ci eth_random_addr(priv->mac_addr); 19288c2ecf20Sopenharmony_ci } 19298c2ecf20Sopenharmony_ci SET_IEEE80211_PERM_ADDR(dev, priv->mac_addr); 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_ci spin_lock_init(&priv->lock); 19328c2ecf20Sopenharmony_ci 19338c2ecf20Sopenharmony_ci err = ieee80211_register_hw(dev); 19348c2ecf20Sopenharmony_ci if (err) { 19358c2ecf20Sopenharmony_ci printk(KERN_ERR "%s (rtl8180): Cannot register device\n", 19368c2ecf20Sopenharmony_ci pci_name(pdev)); 19378c2ecf20Sopenharmony_ci goto err_iounmap; 19388c2ecf20Sopenharmony_ci } 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_ci wiphy_info(dev->wiphy, "hwaddr %pm, %s + %s\n", 19418c2ecf20Sopenharmony_ci priv->mac_addr, chip_name, priv->rf->name); 19428c2ecf20Sopenharmony_ci 19438c2ecf20Sopenharmony_ci return 0; 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ci err_iounmap: 19468c2ecf20Sopenharmony_ci pci_iounmap(pdev, priv->map); 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci err_free_dev: 19498c2ecf20Sopenharmony_ci ieee80211_free_hw(dev); 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_ci err_free_reg: 19528c2ecf20Sopenharmony_ci pci_release_regions(pdev); 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_ci err_disable_dev: 19558c2ecf20Sopenharmony_ci pci_disable_device(pdev); 19568c2ecf20Sopenharmony_ci return err; 19578c2ecf20Sopenharmony_ci} 19588c2ecf20Sopenharmony_ci 19598c2ecf20Sopenharmony_cistatic void rtl8180_remove(struct pci_dev *pdev) 19608c2ecf20Sopenharmony_ci{ 19618c2ecf20Sopenharmony_ci struct ieee80211_hw *dev = pci_get_drvdata(pdev); 19628c2ecf20Sopenharmony_ci struct rtl8180_priv *priv; 19638c2ecf20Sopenharmony_ci 19648c2ecf20Sopenharmony_ci if (!dev) 19658c2ecf20Sopenharmony_ci return; 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_ci ieee80211_unregister_hw(dev); 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_ci priv = dev->priv; 19708c2ecf20Sopenharmony_ci 19718c2ecf20Sopenharmony_ci pci_iounmap(pdev, priv->map); 19728c2ecf20Sopenharmony_ci pci_release_regions(pdev); 19738c2ecf20Sopenharmony_ci pci_disable_device(pdev); 19748c2ecf20Sopenharmony_ci ieee80211_free_hw(dev); 19758c2ecf20Sopenharmony_ci} 19768c2ecf20Sopenharmony_ci 19778c2ecf20Sopenharmony_ci#define rtl8180_suspend NULL 19788c2ecf20Sopenharmony_ci#define rtl8180_resume NULL 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(rtl8180_pm_ops, rtl8180_suspend, rtl8180_resume); 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_cistatic struct pci_driver rtl8180_driver = { 19838c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 19848c2ecf20Sopenharmony_ci .id_table = rtl8180_table, 19858c2ecf20Sopenharmony_ci .probe = rtl8180_probe, 19868c2ecf20Sopenharmony_ci .remove = rtl8180_remove, 19878c2ecf20Sopenharmony_ci .driver.pm = &rtl8180_pm_ops, 19888c2ecf20Sopenharmony_ci}; 19898c2ecf20Sopenharmony_ci 19908c2ecf20Sopenharmony_cimodule_pci_driver(rtl8180_driver); 1991