diff options
Diffstat (limited to 'drivers/net')
386 files changed, 33509 insertions, 17639 deletions
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index 91abb965fb44..cb39dedf46bd 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -185,7 +185,7 @@ static int max_interrupt_work = 10; static int nopnp; #endif -static int __devinit el3_common_init(struct net_device *dev); +static int el3_common_init(struct net_device *dev); static void el3_common_remove(struct net_device *dev); static ushort id_read_eeprom(int index); static ushort read_eeprom(int ioaddr, int index); @@ -395,7 +395,7 @@ static struct isa_driver el3_isa_driver = { static int isa_registered; #ifdef CONFIG_PNP -static struct pnp_device_id el3_pnp_ids[] = { +static const struct pnp_device_id el3_pnp_ids[] __devinitconst = { { .id = "TCM5090" }, /* 3Com Etherlink III (TP) */ { .id = "TCM5091" }, /* 3Com Etherlink III */ { .id = "TCM5094" }, /* 3Com Etherlink III (combo) */ @@ -478,7 +478,7 @@ static int pnp_registered; #endif /* CONFIG_PNP */ #ifdef CONFIG_EISA -static struct eisa_device_id el3_eisa_ids[] = { +static const struct eisa_device_id el3_eisa_ids[] __devinitconst = { { "TCM5090" }, { "TCM5091" }, { "TCM5092" }, @@ -508,7 +508,7 @@ static int eisa_registered; #ifdef CONFIG_MCA static int el3_mca_probe(struct device *dev); -static short el3_mca_adapter_ids[] __initdata = { +static const short el3_mca_adapter_ids[] __devinitconst = { 0x627c, 0x627d, 0x62db, @@ -517,7 +517,7 @@ static short el3_mca_adapter_ids[] __initdata = { 0x0000 }; -static char *el3_mca_adapter_names[] __initdata = { +static const char *const el3_mca_adapter_names[] __devinitconst = { "3Com 3c529 EtherLink III (10base2)", "3Com 3c529 EtherLink III (10baseT)", "3Com 3c529 EtherLink III (test mode)", @@ -601,7 +601,7 @@ static void el3_common_remove (struct net_device *dev) } #ifdef CONFIG_MCA -static int __init el3_mca_probe(struct device *device) +static int __devinit el3_mca_probe(struct device *device) { /* Based on Erik Nygren's (nygren@mit.edu) 3c529 patch, * heavily modified by Chris Beauregard @@ -671,7 +671,7 @@ static int __init el3_mca_probe(struct device *device) #endif /* CONFIG_MCA */ #ifdef CONFIG_EISA -static int __init el3_eisa_probe (struct device *device) +static int __devinit el3_eisa_probe (struct device *device) { short i; int ioaddr, irq, if_port; diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 8cc22568ebd3..99f43d275442 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -901,14 +901,14 @@ static const struct dev_pm_ops vortex_pm_ops = { #endif /* !CONFIG_PM */ #ifdef CONFIG_EISA -static struct eisa_device_id vortex_eisa_ids[] = { +static const struct eisa_device_id vortex_eisa_ids[] __devinitconst = { { "TCM5920", CH_3C592 }, { "TCM5970", CH_3C597 }, { "" } }; MODULE_DEVICE_TABLE(eisa, vortex_eisa_ids); -static int __init vortex_eisa_probe(struct device *device) +static int __devinit vortex_eisa_probe(struct device *device) { void __iomem *ioaddr; struct eisa_device *edev; diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index dd16e83933a2..10c45051caea 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -758,8 +758,7 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb, entry = cp->tx_head; eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0; - if (dev->features & NETIF_F_TSO) - mss = skb_shinfo(skb)->gso_size; + mss = skb_shinfo(skb)->gso_size; if (skb_shinfo(skb)->nr_frags == 0) { struct cp_desc *txd = &cp->tx_ring[entry]; @@ -1416,32 +1415,23 @@ static void cp_set_msglevel(struct net_device *dev, u32 value) cp->msg_enable = value; } -static u32 cp_get_rx_csum(struct net_device *dev) +static int cp_set_features(struct net_device *dev, u32 features) { struct cp_private *cp = netdev_priv(dev); - return (cpr16(CpCmd) & RxChkSum) ? 1 : 0; -} + unsigned long flags; -static int cp_set_rx_csum(struct net_device *dev, u32 data) -{ - struct cp_private *cp = netdev_priv(dev); - u16 cmd = cp->cpcmd, newcmd; + if (!((dev->features ^ features) & NETIF_F_RXCSUM)) + return 0; - newcmd = cmd; + spin_lock_irqsave(&cp->lock, flags); - if (data) - newcmd |= RxChkSum; + if (features & NETIF_F_RXCSUM) + cp->cpcmd |= RxChkSum; else - newcmd &= ~RxChkSum; - - if (newcmd != cmd) { - unsigned long flags; + cp->cpcmd &= ~RxChkSum; - spin_lock_irqsave(&cp->lock, flags); - cp->cpcmd = newcmd; - cpw16_f(CpCmd, newcmd); - spin_unlock_irqrestore(&cp->lock, flags); - } + cpw16_f(CpCmd, cp->cpcmd); + spin_unlock_irqrestore(&cp->lock, flags); return 0; } @@ -1554,11 +1544,6 @@ static const struct ethtool_ops cp_ethtool_ops = { .get_link = ethtool_op_get_link, .get_msglevel = cp_get_msglevel, .set_msglevel = cp_set_msglevel, - .get_rx_csum = cp_get_rx_csum, - .set_rx_csum = cp_set_rx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, /* local! */ - .set_sg = ethtool_op_set_sg, - .set_tso = ethtool_op_set_tso, .get_regs = cp_get_regs, .get_wol = cp_get_wol, .set_wol = cp_set_wol, @@ -1831,6 +1816,7 @@ static const struct net_device_ops cp_netdev_ops = { .ndo_do_ioctl = cp_ioctl, .ndo_start_xmit = cp_start_xmit, .ndo_tx_timeout = cp_tx_timeout, + .ndo_set_features = cp_set_features, #if CP_VLAN_TAG_USED .ndo_vlan_rx_register = cp_vlan_rx_register, #endif @@ -1934,6 +1920,9 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) cp->cpcmd = (pci_using_dac ? PCIDAC : 0) | PCIMulRW | RxChkSum | CpRxOn | CpTxOn; + dev->features |= NETIF_F_RXCSUM; + dev->hw_features |= NETIF_F_RXCSUM; + regs = ioremap(pciaddr, CP_REGS_SIZE); if (!regs) { rc = -EIO; @@ -1966,9 +1955,8 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (pci_using_dac) dev->features |= NETIF_F_HIGHDMA; -#if 0 /* disabled by default until verified */ - dev->features |= NETIF_F_TSO; -#endif + /* disabled by default until verified */ + dev->hw_features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO; dev->irq = pdev->irq; diff --git a/drivers/net/atl1c/atl1c_ethtool.c b/drivers/net/atl1c/atl1c_ethtool.c index 7c521508313c..3af5a336a5af 100644 --- a/drivers/net/atl1c/atl1c_ethtool.c +++ b/drivers/net/atl1c/atl1c_ethtool.c @@ -113,11 +113,6 @@ static int atl1c_set_settings(struct net_device *netdev, return 0; } -static u32 atl1c_get_tx_csum(struct net_device *netdev) -{ - return (netdev->features & NETIF_F_HW_CSUM) != 0; -} - static u32 atl1c_get_msglevel(struct net_device *netdev) { struct atl1c_adapter *adapter = netdev_priv(netdev); @@ -307,9 +302,6 @@ static const struct ethtool_ops atl1c_ethtool_ops = { .get_link = ethtool_op_get_link, .get_eeprom_len = atl1c_get_eeprom_len, .get_eeprom = atl1c_get_eeprom, - .get_tx_csum = atl1c_get_tx_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, }; void atl1c_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c index 7d9d5067a65c..5c64a5d91544 100644 --- a/drivers/net/atl1c/atl1c_main.c +++ b/drivers/net/atl1c/atl1c_main.c @@ -484,6 +484,15 @@ static void atl1c_set_rxbufsize(struct atl1c_adapter *adapter, adapter->rx_buffer_len = mtu > AT_RX_BUF_SIZE ? roundup(mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN, 8) : AT_RX_BUF_SIZE; } + +static u32 atl1c_fix_features(struct net_device *netdev, u32 features) +{ + if (netdev->mtu > MAX_TSO_FRAME_SIZE) + features &= ~(NETIF_F_TSO | NETIF_F_TSO6); + + return features; +} + /* * atl1c_change_mtu - Change the Maximum Transfer Unit * @netdev: network interface device structure @@ -510,14 +519,8 @@ static int atl1c_change_mtu(struct net_device *netdev, int new_mtu) netdev->mtu = new_mtu; adapter->hw.max_frame_size = new_mtu; atl1c_set_rxbufsize(adapter, netdev); - if (new_mtu > MAX_TSO_FRAME_SIZE) { - adapter->netdev->features &= ~NETIF_F_TSO; - adapter->netdev->features &= ~NETIF_F_TSO6; - } else { - adapter->netdev->features |= NETIF_F_TSO; - adapter->netdev->features |= NETIF_F_TSO6; - } atl1c_down(adapter); + netdev_update_features(netdev); atl1c_up(adapter); clear_bit(__AT_RESETTING, &adapter->flags); if (adapter->hw.ctrl_flags & ATL1C_FPGA_VERSION) { @@ -1092,10 +1095,8 @@ static void atl1c_configure_tx(struct atl1c_adapter *adapter) u32 max_pay_load; u16 tx_offload_thresh; u32 txq_ctrl_data; - u32 extra_size = 0; /* Jumbo frame threshold in QWORD unit */ u32 max_pay_load_data; - extra_size = ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN; tx_offload_thresh = MAX_TX_OFFLOAD_THRESH; AT_WRITE_REG(hw, REG_TX_TSO_OFFLOAD_THRESH, (tx_offload_thresh >> 3) & TX_TSO_OFFLOAD_THRESH_MASK); @@ -2585,6 +2586,7 @@ static const struct net_device_ops atl1c_netdev_ops = { .ndo_set_mac_address = atl1c_set_mac_addr, .ndo_set_multicast_list = atl1c_set_multi, .ndo_change_mtu = atl1c_change_mtu, + .ndo_fix_features = atl1c_fix_features, .ndo_do_ioctl = atl1c_ioctl, .ndo_tx_timeout = atl1c_tx_timeout, .ndo_get_stats = atl1c_get_stats, @@ -2605,12 +2607,13 @@ static int atl1c_init_netdev(struct net_device *netdev, struct pci_dev *pdev) atl1c_set_ethtool_ops(netdev); /* TODO: add when ready */ - netdev->features = NETIF_F_SG | + netdev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HW_VLAN_TX | - NETIF_F_HW_VLAN_RX | NETIF_F_TSO | NETIF_F_TSO6; + netdev->features = netdev->hw_features | + NETIF_F_HW_VLAN_RX; return 0; } diff --git a/drivers/net/atl1e/atl1e_ethtool.c b/drivers/net/atl1e/atl1e_ethtool.c index 1209297433b8..47783749d9fa 100644 --- a/drivers/net/atl1e/atl1e_ethtool.c +++ b/drivers/net/atl1e/atl1e_ethtool.c @@ -382,9 +382,6 @@ static const struct ethtool_ops atl1e_ethtool_ops = { .get_eeprom_len = atl1e_get_eeprom_len, .get_eeprom = atl1e_get_eeprom, .set_eeprom = atl1e_set_eeprom, - .set_tx_csum = ethtool_op_set_tx_hw_csum, - .set_sg = ethtool_op_set_sg, - .set_tso = ethtool_op_set_tso, }; void atl1e_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c index b0a71e2f28a9..86a912283134 100644 --- a/drivers/net/atl1e/atl1e_main.c +++ b/drivers/net/atl1e/atl1e_main.c @@ -691,10 +691,8 @@ static void atl1e_cal_ring_size(struct atl1e_adapter *adapter, u32 *ring_size) static void atl1e_init_ring_resources(struct atl1e_adapter *adapter) { - struct atl1e_tx_ring *tx_ring = NULL; struct atl1e_rx_ring *rx_ring = NULL; - tx_ring = &adapter->tx_ring; rx_ring = &adapter->rx_ring; rx_ring->real_page_size = adapter->rx_ring.page_size @@ -1927,11 +1925,7 @@ void atl1e_down(struct atl1e_adapter *adapter) * reschedule our watchdog timer */ set_bit(__AT_DOWN, &adapter->flags); -#ifdef NETIF_F_LLTX netif_stop_queue(netdev); -#else - netif_tx_disable(netdev); -#endif /* reset MAC to disable all RX/TX */ atl1e_reset_hw(&adapter->hw); @@ -2223,10 +2217,10 @@ static int atl1e_init_netdev(struct net_device *netdev, struct pci_dev *pdev) netdev->watchdog_timeo = AT_TX_WATCHDOG; atl1e_set_ethtool_ops(netdev); - netdev->features = NETIF_F_SG | NETIF_F_HW_CSUM | - NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - netdev->features |= NETIF_F_LLTX; - netdev->features |= NETIF_F_TSO; + netdev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO | + NETIF_F_HW_VLAN_TX; + netdev->features = netdev->hw_features | + NETIF_F_HW_VLAN_RX | NETIF_F_LLTX; return 0; } diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index 67f40b9c16ed..dffa6919a419 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -2074,9 +2074,6 @@ static void atl1_intr_tx(struct atl1_adapter *adapter) cmb_tpd_next_to_clean = le16_to_cpu(adapter->cmb.cmb->tpd_cons_idx); while (cmb_tpd_next_to_clean != sw_tpd_next_to_clean) { - struct tx_packet_desc *tpd; - - tpd = ATL1_TPD_DESC(tpd_ring, sw_tpd_next_to_clean); buffer_info = &tpd_ring->buffer_info[sw_tpd_next_to_clean]; if (buffer_info->dma) { pci_unmap_page(adapter->pdev, buffer_info->dma, @@ -2572,7 +2569,7 @@ static s32 atl1_up(struct atl1_adapter *adapter) { struct net_device *netdev = adapter->netdev; int err; - int irq_flags = IRQF_SAMPLE_RANDOM; + int irq_flags = 0; /* hardware has been reset, we need to reload some things */ atlx_set_multi(netdev); @@ -2986,6 +2983,11 @@ static int __devinit atl1_probe(struct pci_dev *pdev, netdev->features |= NETIF_F_SG; netdev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX); + netdev->hw_features = NETIF_F_HW_CSUM | NETIF_F_SG | NETIF_F_TSO; + + /* is this valid? see atl1_setup_mac_ctrl() */ + netdev->features |= NETIF_F_RXCSUM; + /* * patch for some L1 of old version, * the final version of L1 may not need these @@ -3595,12 +3597,6 @@ static int atl1_set_pauseparam(struct net_device *netdev, return 0; } -/* FIXME: is this right? -- CHS */ -static u32 atl1_get_rx_csum(struct net_device *netdev) -{ - return 1; -} - static void atl1_get_strings(struct net_device *netdev, u32 stringset, u8 *data) { @@ -3668,13 +3664,9 @@ static const struct ethtool_ops atl1_ethtool_ops = { .set_ringparam = atl1_set_ringparam, .get_pauseparam = atl1_get_pauseparam, .set_pauseparam = atl1_set_pauseparam, - .get_rx_csum = atl1_get_rx_csum, - .set_tx_csum = ethtool_op_set_tx_hw_csum, .get_link = ethtool_op_get_link, - .set_sg = ethtool_op_set_sg, .get_strings = atl1_get_strings, .nway_reset = atl1_nway_reset, .get_ethtool_stats = atl1_get_ethtool_stats, .get_sset_count = atl1_get_sset_count, - .set_tso = ethtool_op_set_tso, }; diff --git a/drivers/net/atlx/atl2.c b/drivers/net/atlx/atl2.c index e3cbf45dc612..b75aa295d37e 100644 --- a/drivers/net/atlx/atl2.c +++ b/drivers/net/atlx/atl2.c @@ -1411,9 +1411,8 @@ static int __devinit atl2_probe(struct pci_dev *pdev, err = -EIO; -#ifdef NETIF_F_HW_VLAN_TX + netdev->hw_features = NETIF_F_SG; netdev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX); -#endif /* Init PHY as early as possible due to power saving issue */ atl2_phy_init(&adapter->hw); @@ -1840,11 +1839,6 @@ static int atl2_set_settings(struct net_device *netdev, return 0; } -static u32 atl2_get_tx_csum(struct net_device *netdev) -{ - return (netdev->features & NETIF_F_HW_CSUM) != 0; -} - static u32 atl2_get_msglevel(struct net_device *netdev) { return 0; @@ -2112,12 +2106,6 @@ static const struct ethtool_ops atl2_ethtool_ops = { .get_eeprom_len = atl2_get_eeprom_len, .get_eeprom = atl2_get_eeprom, .set_eeprom = atl2_set_eeprom, - .get_tx_csum = atl2_get_tx_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, -#ifdef NETIF_F_TSO - .get_tso = ethtool_op_get_tso, -#endif }; static void atl2_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/bcm63xx_enet.c b/drivers/net/bcm63xx_enet.c index c48104b08861..e68ffe622e69 100644 --- a/drivers/net/bcm63xx_enet.c +++ b/drivers/net/bcm63xx_enet.c @@ -839,8 +839,8 @@ static int bcm_enet_open(struct net_device *dev) if (ret) goto out_phy_disconnect; - ret = request_irq(priv->irq_rx, bcm_enet_isr_dma, - IRQF_SAMPLE_RANDOM | IRQF_DISABLED, dev->name, dev); + ret = request_irq(priv->irq_rx, bcm_enet_isr_dma, IRQF_DISABLED, + dev->name, dev); if (ret) goto out_freeirq; diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index 66823eded7a3..a0b4743d7224 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -84,15 +84,14 @@ static inline char *nic_name(struct pci_dev *pdev) #define MCC_CQ_LEN 256 #define MAX_RSS_QS 4 /* BE limit is 4 queues/port */ -#define BE_MAX_MSIX_VECTORS (MAX_RSS_QS + 1 + 1)/* RSS qs + 1 def Rx + Tx */ +#define MAX_RX_QS (MAX_RSS_QS + 1) /* RSS qs + 1 def Rx */ +#define BE_MAX_MSIX_VECTORS (MAX_RX_QS + 1)/* RX + TX */ #define BE_NAPI_WEIGHT 64 #define MAX_RX_POST BE_NAPI_WEIGHT /* Frags posted at a time */ #define RX_FRAGS_REFILL_WM (RX_Q_LEN - MAX_RX_POST) #define FW_VER_LEN 32 -#define BE_MAX_VF 32 - struct be_dma_mem { void *va; dma_addr_t dma; @@ -276,7 +275,7 @@ struct be_adapter { spinlock_t mcc_cq_lock; struct msix_entry msix_entries[BE_MAX_MSIX_VECTORS]; - bool msix_enabled; + u32 num_msix_vec; bool isr_registered; /* TX Rings */ @@ -287,7 +286,7 @@ struct be_adapter { u32 cache_line_break[8]; /* Rx rings */ - struct be_rx_obj rx_obj[MAX_RSS_QS + 1]; /* one default non-rss Q */ + struct be_rx_obj rx_obj[MAX_RX_QS]; u32 num_rx_qs; u32 big_page_size; /* Compounded page size shared by rx wrbs */ @@ -308,10 +307,10 @@ struct be_adapter { u16 work_counter; /* Ethtool knobs and info */ - bool rx_csum; /* BE card must perform rx-checksumming */ char fw_ver[FW_VER_LEN]; u32 if_handle; /* Used to configure filtering */ u32 pmac_id; /* MAC addr handle used by BE card */ + u32 beacon_state; /* for set_phys_id */ bool eeh_err; bool link_up; @@ -334,7 +333,7 @@ struct be_adapter { bool be3_native; bool sriov_enabled; - struct be_vf_cfg vf_cfg[BE_MAX_VF]; + struct be_vf_cfg *vf_cfg; u8 is_virtfn; u32 sli_family; u8 hba_port_num; @@ -351,6 +350,7 @@ struct be_adapter { extern const struct ethtool_ops be_ethtool_ops; +#define msix_enabled(adapter) (adapter->num_msix_vec > 0) #define tx_stats(adapter) (&adapter->tx_stats) #define rx_stats(rxo) (&rxo->stats) @@ -455,18 +455,10 @@ static inline u8 is_udp_pkt(struct sk_buff *skb) static inline void be_check_sriov_fn_type(struct be_adapter *adapter) { - u8 data; u32 sli_intf; - if (lancer_chip(adapter)) { - pci_read_config_dword(adapter->pdev, SLI_INTF_REG_OFFSET, - &sli_intf); - adapter->is_virtfn = (sli_intf & SLI_INTF_FT_MASK) ? 1 : 0; - } else { - pci_write_config_byte(adapter->pdev, 0xFE, 0xAA); - pci_read_config_byte(adapter->pdev, 0xFE, &data); - adapter->is_virtfn = (data != 0xAA); - } + pci_read_config_dword(adapter->pdev, SLI_INTF_REG_OFFSET, &sli_intf); + adapter->is_virtfn = (sli_intf & SLI_INTF_FT_MASK) ? 1 : 0; } static inline void be_vf_eth_addr_generate(struct be_adapter *adapter, u8 *mac) @@ -482,6 +474,11 @@ static inline void be_vf_eth_addr_generate(struct be_adapter *adapter, u8 *mac) memcpy(mac, adapter->netdev->dev_addr, 3); } +static inline bool be_multi_rxq(const struct be_adapter *adapter) +{ + return adapter->num_rx_qs > 1; +} + extern void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, u16 num_popped); extern void be_link_status_update(struct be_adapter *adapter, bool link_up); diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index 1e2d825bb94a..11b774a5eaff 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -1186,6 +1186,113 @@ err: return status; } +/* Uses synchronous mcc */ +int be_cmd_get_reg_len(struct be_adapter *adapter, u32 *log_size) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_get_fat *req; + int status; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + req = embedded_payload(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_MANAGE_FAT); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_MANAGE_FAT, sizeof(*req)); + req->fat_operation = cpu_to_le32(QUERY_FAT); + status = be_mcc_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_get_fat *resp = embedded_payload(wrb); + if (log_size && resp->log_size) + *log_size = le32_to_cpu(resp->log_size - + sizeof(u32)); + } +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + +void be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf) +{ + struct be_dma_mem get_fat_cmd; + struct be_mcc_wrb *wrb; + struct be_cmd_req_get_fat *req; + struct be_sge *sge; + u32 offset = 0, total_size, buf_size, log_offset = sizeof(u32); + int status; + + if (buf_len == 0) + return; + + total_size = buf_len; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + while (total_size) { + buf_size = min(total_size, (u32)60*1024); + total_size -= buf_size; + + get_fat_cmd.size = sizeof(struct be_cmd_req_get_fat) + buf_size; + get_fat_cmd.va = pci_alloc_consistent(adapter->pdev, + get_fat_cmd.size, + &get_fat_cmd.dma); + if (!get_fat_cmd.va) { + status = -ENOMEM; + dev_err(&adapter->pdev->dev, + "Memory allocation failure while retrieving FAT data\n"); + goto err; + } + req = get_fat_cmd.va; + sge = nonembedded_sgl(wrb); + + be_wrb_hdr_prepare(wrb, get_fat_cmd.size, false, 1, + OPCODE_COMMON_MANAGE_FAT); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_MANAGE_FAT, get_fat_cmd.size); + + sge->pa_hi = cpu_to_le32(upper_32_bits(get_fat_cmd.size)); + sge->pa_lo = cpu_to_le32(get_fat_cmd.dma & 0xFFFFFFFF); + sge->len = cpu_to_le32(get_fat_cmd.size); + + req->fat_operation = cpu_to_le32(RETRIEVE_FAT); + req->read_log_offset = cpu_to_le32(log_offset); + req->read_log_length = cpu_to_le32(buf_size); + req->data_buffer_size = cpu_to_le32(buf_size); + + status = be_mcc_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_get_fat *resp = get_fat_cmd.va; + memcpy(buf + offset, + resp->data_buffer, + resp->read_log_length); + } + pci_free_consistent(adapter->pdev, get_fat_cmd.size, + get_fat_cmd.va, + get_fat_cmd.dma); + if (status) + dev_err(&adapter->pdev->dev, "FAT Table Retrieve error\n"); + + offset += buf_size; + log_offset += buf_size; + } +err: + spin_unlock_bh(&adapter->mcc_lock); +} + /* Uses Mbox */ int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver) { diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h index 4f254cfaabe2..3fb6e0a3ad7a 100644 --- a/drivers/net/benet/be_cmds.h +++ b/drivers/net/benet/be_cmds.h @@ -186,6 +186,7 @@ struct be_mcc_mailbox { #define OPCODE_COMMON_NTWK_PMAC_ADD 59 #define OPCODE_COMMON_NTWK_PMAC_DEL 60 #define OPCODE_COMMON_FUNCTION_RESET 61 +#define OPCODE_COMMON_MANAGE_FAT 68 #define OPCODE_COMMON_ENABLE_DISABLE_BEACON 69 #define OPCODE_COMMON_GET_BEACON_STATE 70 #define OPCODE_COMMON_READ_TRANSRECV_DATA 73 @@ -380,6 +381,24 @@ struct be_cmd_resp_cq_create { u16 rsvd0; } __packed; +struct be_cmd_req_get_fat { + struct be_cmd_req_hdr hdr; + u32 fat_operation; + u32 read_log_offset; + u32 read_log_length; + u32 data_buffer_size; + u32 data_buffer[1]; +} __packed; + +struct be_cmd_resp_get_fat { + struct be_cmd_resp_hdr hdr; + u32 log_size; + u32 read_log_length; + u32 rsvd[2]; + u32 data_buffer[1]; +} __packed; + + /******************** Create MCCQ ***************************/ /* Pseudo amap definition in which each bit of the actual structure is defined * as a byte: used to calculate offset/shift/mask of each field */ @@ -1148,4 +1167,6 @@ extern void be_detect_dump_ue(struct be_adapter *adapter); extern int be_cmd_get_die_temperature(struct be_adapter *adapter); extern int be_cmd_get_cntl_attributes(struct be_adapter *adapter); extern int be_cmd_check_native_mode(struct be_adapter *adapter); +extern int be_cmd_get_reg_len(struct be_adapter *adapter, u32 *log_size); +extern void be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf); diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index aac248fbd18b..28716a6061bc 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c @@ -156,6 +156,25 @@ be_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) } static int +be_get_reg_len(struct net_device *netdev) +{ + struct be_adapter *adapter = netdev_priv(netdev); + u32 log_size = 0; + + be_cmd_get_reg_len(adapter, &log_size); + return log_size; +} + +static void +be_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *buf) +{ + struct be_adapter *adapter = netdev_priv(netdev); + + memset(buf, 0, regs->len); + be_cmd_get_regs(adapter, regs->len, buf); +} + +static int be_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) { struct be_adapter *adapter = netdev_priv(netdev); @@ -186,9 +205,9 @@ be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) struct be_rx_obj *rxo; struct be_eq_obj *rx_eq; struct be_eq_obj *tx_eq = &adapter->tx_eq; - u32 tx_max, tx_min, tx_cur; u32 rx_max, rx_min, rx_cur; int status = 0, i; + u32 tx_cur; if (coalesce->use_adaptive_tx_coalesce == 1) return -EINVAL; @@ -227,8 +246,6 @@ be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) } } - tx_max = coalesce->tx_coalesce_usecs_high; - tx_min = coalesce->tx_coalesce_usecs_low; tx_cur = coalesce->tx_coalesce_usecs; if (tx_cur > BE_MAX_EQD) @@ -242,25 +259,6 @@ be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) return 0; } -static u32 be_get_rx_csum(struct net_device *netdev) -{ - struct be_adapter *adapter = netdev_priv(netdev); - - return adapter->rx_csum; -} - -static int be_set_rx_csum(struct net_device *netdev, uint32_t data) -{ - struct be_adapter *adapter = netdev_priv(netdev); - - if (data) - adapter->rx_csum = true; - else - adapter->rx_csum = false; - - return 0; -} - static void be_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, uint64_t *data) @@ -507,29 +505,33 @@ be_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd) } static int -be_phys_id(struct net_device *netdev, u32 data) +be_set_phys_id(struct net_device *netdev, + enum ethtool_phys_id_state state) { struct be_adapter *adapter = netdev_priv(netdev); - int status; - u32 cur; - be_cmd_get_beacon_state(adapter, adapter->hba_port_num, &cur); + switch (state) { + case ETHTOOL_ID_ACTIVE: + be_cmd_get_beacon_state(adapter, adapter->hba_port_num, + &adapter->beacon_state); + return 1; /* cycle on/off once per second */ - if (cur == BEACON_STATE_ENABLED) - return 0; - - if (data < 2) - data = 2; + case ETHTOOL_ID_ON: + be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0, + BEACON_STATE_ENABLED); + break; - status = be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0, - BEACON_STATE_ENABLED); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(data*HZ); + case ETHTOOL_ID_OFF: + be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0, + BEACON_STATE_DISABLED); + break; - status = be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0, - BEACON_STATE_DISABLED); + case ETHTOOL_ID_INACTIVE: + be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0, + adapter->beacon_state); + } - return status; + return 0; } static bool @@ -660,11 +662,9 @@ be_do_flash(struct net_device *netdev, struct ethtool_flash *efl) { struct be_adapter *adapter = netdev_priv(netdev); char file_name[ETHTOOL_FLASH_MAX_FILENAME]; - u32 region; file_name[ETHTOOL_FLASH_MAX_FILENAME - 1] = 0; strcpy(file_name, efl->data); - region = efl->region; return be_load_fw(adapter, file_name); } @@ -725,18 +725,12 @@ const struct ethtool_ops be_ethtool_ops = { .get_ringparam = be_get_ringparam, .get_pauseparam = be_get_pauseparam, .set_pauseparam = be_set_pauseparam, - .get_rx_csum = be_get_rx_csum, - .set_rx_csum = be_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_hw_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, - .set_tso = ethtool_op_set_tso, .get_strings = be_get_stat_strings, - .phys_id = be_phys_id, + .set_phys_id = be_set_phys_id, .get_sset_count = be_get_sset_count, .get_ethtool_stats = be_get_ethtool_stats, + .get_regs_len = be_get_reg_len, + .get_regs = be_get_regs, .flash_device = be_do_flash, .self_test = be_self_test, }; diff --git a/drivers/net/benet/be_hw.h b/drivers/net/benet/be_hw.h index d4344a06090b..53d658afea2a 100644 --- a/drivers/net/benet/be_hw.h +++ b/drivers/net/benet/be_hw.h @@ -155,6 +155,10 @@ /********** SRIOV VF PCICFG OFFSET ********/ #define SRIOV_VF_PCICFG_OFFSET (4096) +/********** FAT TABLE ********/ +#define RETRIEVE_FAT 0 +#define QUERY_FAT 1 + /* Flashrom related descriptors */ #define IMAGE_TYPE_FIRMWARE 160 #define IMAGE_TYPE_BOOTCODE 224 diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 7cb5a114c733..1bb763cda3ad 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -116,11 +116,6 @@ static char *ue_status_hi_desc[] = { "Unknown" }; -static inline bool be_multi_rxq(struct be_adapter *adapter) -{ - return (adapter->num_rx_qs > 1); -} - static void be_queue_free(struct be_adapter *adapter, struct be_queue_info *q) { struct be_dma_mem *mem = &q->dma_mem; @@ -993,9 +988,10 @@ static void be_rx_compl_process(struct be_adapter *adapter, struct be_rx_obj *rxo, struct be_rx_compl_info *rxcp) { + struct net_device *netdev = adapter->netdev; struct sk_buff *skb; - skb = netdev_alloc_skb_ip_align(adapter->netdev, BE_HDR_LEN); + skb = netdev_alloc_skb_ip_align(netdev, BE_HDR_LEN); if (unlikely(!skb)) { if (net_ratelimit()) dev_warn(&adapter->pdev->dev, "skb alloc failed\n"); @@ -1005,13 +1001,16 @@ static void be_rx_compl_process(struct be_adapter *adapter, skb_fill_rx_data(adapter, rxo, skb, rxcp); - if (likely(adapter->rx_csum && csum_passed(rxcp))) + if (likely((netdev->features & NETIF_F_RXCSUM) && csum_passed(rxcp))) skb->ip_summed = CHECKSUM_UNNECESSARY; else skb_checksum_none_assert(skb); skb->truesize = skb->len + sizeof(struct sk_buff); - skb->protocol = eth_type_trans(skb, adapter->netdev); + skb->protocol = eth_type_trans(skb, netdev); + if (adapter->netdev->features & NETIF_F_RXHASH) + skb->rxhash = rxcp->rss_hash; + if (unlikely(rxcp->vlanf)) { if (!adapter->vlan_grp || adapter->vlans_added == 0) { @@ -1072,6 +1071,8 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter, skb->data_len = rxcp->pkt_size; skb->truesize += rxcp->pkt_size; skb->ip_summed = CHECKSUM_UNNECESSARY; + if (adapter->netdev->features & NETIF_F_RXHASH) + skb->rxhash = rxcp->rss_hash; if (likely(!rxcp->vlanf)) napi_gro_frags(&eq_obj->napi); @@ -1101,8 +1102,14 @@ static void be_parse_rx_compl_v1(struct be_adapter *adapter, AMAP_GET_BITS(struct amap_eth_rx_compl_v1, numfrags, compl); rxcp->pkt_type = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, cast_enc, compl); - rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vtm, compl); - rxcp->vid = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vlan_tag, compl); + rxcp->rss_hash = + AMAP_GET_BITS(struct amap_eth_rx_compl_v1, rsshash, rxcp); + if (rxcp->vlanf) { + rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vtm, + compl); + rxcp->vid = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vlan_tag, + compl); + } } static void be_parse_rx_compl_v0(struct be_adapter *adapter, @@ -1127,8 +1134,14 @@ static void be_parse_rx_compl_v0(struct be_adapter *adapter, AMAP_GET_BITS(struct amap_eth_rx_compl_v0, numfrags, compl); rxcp->pkt_type = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, cast_enc, compl); - rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vtm, compl); - rxcp->vid = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vlan_tag, compl); + rxcp->rss_hash = + AMAP_GET_BITS(struct amap_eth_rx_compl_v0, rsshash, rxcp); + if (rxcp->vlanf) { + rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vtm, + compl); + rxcp->vid = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vlan_tag, + compl); + } } static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo) @@ -1150,15 +1163,19 @@ static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo) else be_parse_rx_compl_v0(adapter, compl, rxcp); - /* vlanf could be wrongly set in some cards. ignore if vtm is not set */ - if ((adapter->function_mode & 0x400) && !rxcp->vtm) - rxcp->vlanf = 0; + if (rxcp->vlanf) { + /* vlanf could be wrongly set in some cards. + * ignore if vtm is not set */ + if ((adapter->function_mode & 0x400) && !rxcp->vtm) + rxcp->vlanf = 0; - if (!lancer_chip(adapter)) - rxcp->vid = swab16(rxcp->vid); + if (!lancer_chip(adapter)) + rxcp->vid = swab16(rxcp->vid); - if ((adapter->pvid == rxcp->vid) && !adapter->vlan_tag[rxcp->vid]) - rxcp->vlanf = 0; + if ((adapter->pvid == rxcp->vid) && + !adapter->vlan_tag[rxcp->vid]) + rxcp->vlanf = 0; + } /* As the compl has been parsed, reset it; we wont touch it again */ compl->dw[offsetof(struct amap_eth_rx_compl_v1, valid) / 32] = 0; @@ -1567,12 +1584,31 @@ static void be_rx_queues_destroy(struct be_adapter *adapter) } } +static u32 be_num_rxqs_want(struct be_adapter *adapter) +{ + if (multi_rxq && (adapter->function_caps & BE_FUNCTION_CAPS_RSS) && + !adapter->sriov_enabled && !(adapter->function_mode & 0x400)) { + return 1 + MAX_RSS_QS; /* one default non-RSS queue */ + } else { + dev_warn(&adapter->pdev->dev, + "No support for multiple RX queues\n"); + return 1; + } +} + static int be_rx_queues_create(struct be_adapter *adapter) { struct be_queue_info *eq, *q, *cq; struct be_rx_obj *rxo; int rc, i; + adapter->num_rx_qs = min(be_num_rxqs_want(adapter), + msix_enabled(adapter) ? + adapter->num_msix_vec - 1 : 1); + if (adapter->num_rx_qs != MAX_RX_QS) + dev_warn(&adapter->pdev->dev, + "Can create only %d RX queues", adapter->num_rx_qs); + adapter->big_page_size = (1 << get_order(rx_frag_size)) * PAGE_SIZE; for_all_rx_queues(adapter, rxo, i) { rxo->adapter = adapter; @@ -1837,6 +1873,9 @@ static void be_worker(struct work_struct *work) struct be_rx_obj *rxo; int i; + if (!adapter->ue_detected && !lancer_chip(adapter)) + be_detect_dump_ue(adapter); + /* when interrupts are not yet enabled, just reap any pending * mcc completions */ if (!netif_running(adapter->netdev)) { @@ -1849,9 +1888,6 @@ static void be_worker(struct work_struct *work) be_cq_notify(adapter, mcc_obj->cq.id, false, mcc_compl); } - if (!adapter->ue_detected && !lancer_chip(adapter)) - be_detect_dump_ue(adapter); - goto reschedule; } @@ -1869,8 +1905,6 @@ static void be_worker(struct work_struct *work) be_post_rx_frags(rxo, GFP_KERNEL); } } - if (!adapter->ue_detected && !lancer_chip(adapter)) - be_detect_dump_ue(adapter); reschedule: schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000)); @@ -1878,51 +1912,35 @@ reschedule: static void be_msix_disable(struct be_adapter *adapter) { - if (adapter->msix_enabled) { + if (msix_enabled(adapter)) { pci_disable_msix(adapter->pdev); - adapter->msix_enabled = false; - } -} - -static int be_num_rxqs_get(struct be_adapter *adapter) -{ - if (multi_rxq && (adapter->function_caps & BE_FUNCTION_CAPS_RSS) && - !adapter->sriov_enabled && !(adapter->function_mode & 0x400)) { - return 1 + MAX_RSS_QS; /* one default non-RSS queue */ - } else { - dev_warn(&adapter->pdev->dev, - "No support for multiple RX queues\n"); - return 1; + adapter->num_msix_vec = 0; } } static void be_msix_enable(struct be_adapter *adapter) { #define BE_MIN_MSIX_VECTORS (1 + 1) /* Rx + Tx */ - int i, status; + int i, status, num_vec; - adapter->num_rx_qs = be_num_rxqs_get(adapter); + num_vec = be_num_rxqs_want(adapter) + 1; - for (i = 0; i < (adapter->num_rx_qs + 1); i++) + for (i = 0; i < num_vec; i++) adapter->msix_entries[i].entry = i; - status = pci_enable_msix(adapter->pdev, adapter->msix_entries, - adapter->num_rx_qs + 1); + status = pci_enable_msix(adapter->pdev, adapter->msix_entries, num_vec); if (status == 0) { goto done; } else if (status >= BE_MIN_MSIX_VECTORS) { + num_vec = status; if (pci_enable_msix(adapter->pdev, adapter->msix_entries, - status) == 0) { - adapter->num_rx_qs = status - 1; - dev_warn(&adapter->pdev->dev, - "Could alloc only %d MSIx vectors. " - "Using %d RX Qs\n", status, adapter->num_rx_qs); + num_vec) == 0) goto done; - } } return; done: - adapter->msix_enabled = true; + adapter->num_msix_vec = num_vec; + return; } static void be_sriov_enable(struct be_adapter *adapter) @@ -1930,7 +1948,20 @@ static void be_sriov_enable(struct be_adapter *adapter) be_check_sriov_fn_type(adapter); #ifdef CONFIG_PCI_IOV if (be_physfn(adapter) && num_vfs) { - int status; + int status, pos; + u16 nvfs; + + pos = pci_find_ext_capability(adapter->pdev, + PCI_EXT_CAP_ID_SRIOV); + pci_read_config_word(adapter->pdev, + pos + PCI_SRIOV_TOTAL_VF, &nvfs); + + if (num_vfs > nvfs) { + dev_info(&adapter->pdev->dev, + "Device supports %d VFs and not %d\n", + nvfs, num_vfs); + num_vfs = nvfs; + } status = pci_enable_sriov(adapter->pdev, num_vfs); adapter->sriov_enabled = status ? false : true; @@ -2003,8 +2034,7 @@ err_msix: err: dev_warn(&adapter->pdev->dev, "MSIX Request IRQ failed - err %d\n", status); - pci_disable_msix(adapter->pdev); - adapter->msix_enabled = false; + be_msix_disable(adapter); return status; } @@ -2013,7 +2043,7 @@ static int be_irq_register(struct be_adapter *adapter) struct net_device *netdev = adapter->netdev; int status; - if (adapter->msix_enabled) { + if (msix_enabled(adapter)) { status = be_msix_register(adapter); if (status == 0) goto done; @@ -2046,7 +2076,7 @@ static void be_irq_unregister(struct be_adapter *adapter) return; /* INTx */ - if (!adapter->msix_enabled) { + if (!msix_enabled(adapter)) { free_irq(netdev->irq, adapter); goto done; } @@ -2088,7 +2118,7 @@ static int be_close(struct net_device *netdev) be_cq_notify(adapter, rxo->cq.id, false, 0); } - if (adapter->msix_enabled) { + if (msix_enabled(adapter)) { vec = be_msix_vec_get(adapter, tx_eq); synchronize_irq(vec); @@ -2261,7 +2291,7 @@ static int be_setup(struct be_adapter *adapter) BE_IF_FLAGS_PASS_L3L4_ERRORS; en_flags |= BE_IF_FLAGS_PASS_L3L4_ERRORS; - if (be_multi_rxq(adapter)) { + if (adapter->function_caps & BE_FUNCTION_CAPS_RSS) { cap_flags |= BE_IF_FLAGS_RSS; en_flags |= BE_IF_FLAGS_RSS; } @@ -2318,7 +2348,6 @@ static int be_setup(struct be_adapter *adapter) return 0; - be_mcc_queues_destroy(adapter); rx_qs_destroy: be_rx_queues_destroy(adapter); tx_qs_destroy: @@ -2599,10 +2628,14 @@ static void be_netdev_init(struct net_device *netdev) struct be_rx_obj *rxo; int i; - netdev->features |= NETIF_F_SG | NETIF_F_HW_VLAN_RX | NETIF_F_TSO | - NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | - NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | - NETIF_F_GRO | NETIF_F_TSO6; + netdev->hw_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM | + NETIF_F_HW_VLAN_TX; + if (be_multi_rxq(adapter)) + netdev->hw_features |= NETIF_F_RXHASH; + + netdev->features |= netdev->hw_features | + NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; netdev->vlan_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; @@ -2612,8 +2645,6 @@ static void be_netdev_init(struct net_device *netdev) netdev->flags |= IFF_MULTICAST; - adapter->rx_csum = true; - /* Default settings for Rx and Tx flow control */ adapter->rx_fc = true; adapter->tx_fc = true; @@ -2807,6 +2838,7 @@ static void __devexit be_remove(struct pci_dev *pdev) be_ctrl_cleanup(adapter); + kfree(adapter->vf_cfg); be_sriov_disable(adapter); be_msix_disable(adapter); @@ -2991,16 +3023,23 @@ static int __devinit be_probe(struct pci_dev *pdev, } be_sriov_enable(adapter); + if (adapter->sriov_enabled) { + adapter->vf_cfg = kcalloc(num_vfs, + sizeof(struct be_vf_cfg), GFP_KERNEL); + + if (!adapter->vf_cfg) + goto free_netdev; + } status = be_ctrl_init(adapter); if (status) - goto free_netdev; + goto free_vf_cfg; if (lancer_chip(adapter)) { status = lancer_test_and_set_rdy_state(adapter); if (status) { dev_err(&pdev->dev, "Adapter in non recoverable error\n"); - goto free_netdev; + goto ctrl_clean; } } @@ -3062,6 +3101,8 @@ stats_clean: be_stats_cleanup(adapter); ctrl_clean: be_ctrl_cleanup(adapter); +free_vf_cfg: + kfree(adapter->vf_cfg); free_netdev: be_sriov_disable(adapter); free_netdev(netdev); @@ -3146,16 +3187,15 @@ static void be_shutdown(struct pci_dev *pdev) if (!adapter) return; - if (netif_running(adapter->netdev)) - cancel_delayed_work_sync(&adapter->work); + cancel_delayed_work_sync(&adapter->work); netif_device_detach(adapter->netdev); - be_cmd_reset_function(adapter); - if (adapter->wol) be_setup_wol(adapter, true); + be_cmd_reset_function(adapter); + pci_disable_device(pdev); } @@ -3267,13 +3307,6 @@ static int __init be_init_module(void) rx_frag_size = 2048; } - if (num_vfs > 32) { - printk(KERN_WARNING DRV_NAME - " : Module param num_vfs must not be greater than 32." - "Using 32\n"); - num_vfs = 32; - } - return pci_register_driver(&be_driver); } module_init(be_init_module); diff --git a/drivers/net/bna/bfa_ioc.c b/drivers/net/bna/bfa_ioc.c index 7581518ecfa2..ba2a4e13cf4f 100644 --- a/drivers/net/bna/bfa_ioc.c +++ b/drivers/net/bna/bfa_ioc.c @@ -1274,13 +1274,12 @@ bfa_ioc_lpu_stop(struct bfa_ioc *ioc) void bfa_nw_ioc_fwver_get(struct bfa_ioc *ioc, struct bfi_ioc_image_hdr *fwhdr) { - u32 pgnum, pgoff; + u32 pgnum; u32 loff = 0; int i; u32 *fwsig = (u32 *) fwhdr; pgnum = bfa_ioc_smem_pgnum(ioc, loff); - pgoff = bfa_ioc_smem_pgoff(ioc, loff); writel(pgnum, ioc->ioc_regs.host_page_num_fn); for (i = 0; i < (sizeof(struct bfi_ioc_image_hdr) / sizeof(u32)); @@ -1514,7 +1513,7 @@ bfa_ioc_download_fw(struct bfa_ioc *ioc, u32 boot_type, u32 boot_env) { u32 *fwimg; - u32 pgnum, pgoff; + u32 pgnum; u32 loff = 0; u32 chunkno = 0; u32 i; @@ -1527,7 +1526,6 @@ bfa_ioc_download_fw(struct bfa_ioc *ioc, u32 boot_type, fwimg = bfa_cb_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), chunkno); pgnum = bfa_ioc_smem_pgnum(ioc, loff); - pgoff = bfa_ioc_smem_pgoff(ioc, loff); writel(pgnum, ioc->ioc_regs.host_page_num_fn); diff --git a/drivers/net/bna/bna_ctrl.c b/drivers/net/bna/bna_ctrl.c index e1527472b961..53b14169e363 100644 --- a/drivers/net/bna/bna_ctrl.c +++ b/drivers/net/bna/bna_ctrl.c @@ -246,7 +246,6 @@ static void bna_mbox_flush_q(struct bna *bna, struct list_head *q) { struct bna_mbox_qe *mb_qe = NULL; - struct bfi_mhdr *cmd_h; struct list_head *mb_q; void (*cbfn)(void *arg, int status); void *cbarg; @@ -260,7 +259,6 @@ bna_mbox_flush_q(struct bna *bna, struct list_head *q) bfa_q_qe_init(mb_qe); bna->mbox_mod.msg_pending--; - cmd_h = (struct bfi_mhdr *)(&mb_qe->cmd.msg[0]); if (cbfn) cbfn(cbarg, BNA_CB_NOT_EXEC); } @@ -2774,23 +2772,6 @@ bna_rit_mod_init(struct bna_rit_mod *rit_mod, } } -static void -bna_rit_mod_uninit(struct bna_rit_mod *rit_mod) -{ - struct bna_rit_segment *rit_segment; - struct list_head *qe; - int i; - int j; - - for (i = 0; i < BFI_RIT_SEG_TOTAL_POOLS; i++) { - j = 0; - list_for_each(qe, &rit_mod->rit_seg_pool[i]) { - rit_segment = (struct bna_rit_segment *)qe; - j++; - } - } -} - /* * Public functions */ @@ -2977,8 +2958,6 @@ bna_uninit(struct bna *bna) bna_ucam_mod_uninit(&bna->ucam_mod); - bna_rit_mod_uninit(&bna->rit_mod); - bna_ib_mod_uninit(&bna->ib_mod); bna_rx_mod_uninit(&bna->rx_mod); diff --git a/drivers/net/bna/bna_txrx.c b/drivers/net/bna/bna_txrx.c index 58c7664040dc..380085cc3088 100644 --- a/drivers/net/bna/bna_txrx.c +++ b/drivers/net/bna/bna_txrx.c @@ -2229,14 +2229,11 @@ void bna_rit_create(struct bna_rx *rx) { struct list_head *qe_rxp; - struct bna *bna; struct bna_rxp *rxp; struct bna_rxq *q0 = NULL; struct bna_rxq *q1 = NULL; int offset; - bna = rx->bna; - offset = 0; list_for_each(qe_rxp, &rx->rxp_q) { rxp = (struct bna_rxp *)qe_rxp; @@ -2830,7 +2827,7 @@ bna_rx_create(struct bna *bna, struct bnad *bnad, struct bna_mem_descr *dsqpt_mem; /* s/w qpt for data */ struct bna_mem_descr *hpage_mem; /* hdr page mem */ struct bna_mem_descr *dpage_mem; /* data page mem */ - int i, cpage_idx = 0, dpage_idx = 0, hpage_idx = 0, ret; + int i, cpage_idx = 0, dpage_idx = 0, hpage_idx = 0; int dpage_count, hpage_count, rcb_idx; struct bna_ib_config ibcfg; /* Fail if we don't have enough RXPs, RXQs */ @@ -2924,7 +2921,7 @@ bna_rx_create(struct bna *bna, struct bnad *bnad, ibcfg.interpkt_timeo = BFI_RX_INTERPKT_TIMEO; ibcfg.ctrl_flags = BFI_IB_CF_INT_ENABLE; - ret = bna_ib_config(rxp->cq.ib, &ibcfg); + bna_ib_config(rxp->cq.ib, &ibcfg); /* Link rxqs to rxp */ _rxp_add_rxqs(rxp, q0, q1); diff --git a/drivers/net/bna/bnad.c b/drivers/net/bna/bnad.c index 8e6ceab9f4d8..e588511f47fb 100644 --- a/drivers/net/bna/bnad.c +++ b/drivers/net/bna/bnad.c @@ -501,7 +501,7 @@ bnad_poll_cq(struct bnad *bnad, struct bna_ccb *ccb, int budget) skb_put(skb, ntohs(cmpl->length)); if (likely - (bnad->rx_csum && + ((bnad->netdev->features & NETIF_F_RXCSUM) && (((flags & BNA_CQ_EF_IPV4) && (flags & BNA_CQ_EF_L3_CKSUM_OK)) || (flags & BNA_CQ_EF_IPV6)) && @@ -2902,23 +2902,20 @@ bnad_netdev_init(struct bnad *bnad, bool using_dac) { struct net_device *netdev = bnad->netdev; - netdev->features |= NETIF_F_IPV6_CSUM; - netdev->features |= NETIF_F_TSO; - netdev->features |= NETIF_F_TSO6; + netdev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_HW_VLAN_TX; - netdev->features |= NETIF_F_GRO; - pr_warn("bna: GRO enabled, using kernel stack GRO\n"); + netdev->vlan_features = NETIF_F_SG | NETIF_F_HIGHDMA | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_TSO | NETIF_F_TSO6; - netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; + netdev->features |= netdev->hw_features | + NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; if (using_dac) netdev->features |= NETIF_F_HIGHDMA; - netdev->features |= - NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | - NETIF_F_HW_VLAN_FILTER; - - netdev->vlan_features = netdev->features; netdev->mem_start = bnad->mmio_start; netdev->mem_end = bnad->mmio_start + bnad->mmio_len - 1; @@ -2969,7 +2966,6 @@ bnad_init(struct bnad *bnad, bnad->txq_depth = BNAD_TXQ_DEPTH; bnad->rxq_depth = BNAD_RXQ_DEPTH; - bnad->rx_csum = true; bnad->tx_coalescing_timeo = BFI_TX_COALESCING_TIMEO; bnad->rx_coalescing_timeo = BFI_RX_COALESCING_TIMEO; diff --git a/drivers/net/bna/bnad.h b/drivers/net/bna/bnad.h index a89117fa4970..ccdabad0a40c 100644 --- a/drivers/net/bna/bnad.h +++ b/drivers/net/bna/bnad.h @@ -237,8 +237,6 @@ struct bnad { struct bna_rx_config rx_config[BNAD_MAX_RXS]; struct bna_tx_config tx_config[BNAD_MAX_TXS]; - u32 rx_csum; - void __iomem *bar0; /* BAR0 address */ struct bna bna; diff --git a/drivers/net/bna/bnad_ethtool.c b/drivers/net/bna/bnad_ethtool.c index 142d6047da27..c51e078e8f0d 100644 --- a/drivers/net/bna/bnad_ethtool.c +++ b/drivers/net/bna/bnad_ethtool.c @@ -806,61 +806,6 @@ bnad_set_pauseparam(struct net_device *netdev, return 0; } -static u32 -bnad_get_rx_csum(struct net_device *netdev) -{ - u32 rx_csum; - struct bnad *bnad = netdev_priv(netdev); - - rx_csum = bnad->rx_csum; - return rx_csum; -} - -static int -bnad_set_rx_csum(struct net_device *netdev, u32 rx_csum) -{ - struct bnad *bnad = netdev_priv(netdev); - - mutex_lock(&bnad->conf_mutex); - bnad->rx_csum = rx_csum; - mutex_unlock(&bnad->conf_mutex); - return 0; -} - -static int -bnad_set_tx_csum(struct net_device *netdev, u32 tx_csum) -{ - struct bnad *bnad = netdev_priv(netdev); - - mutex_lock(&bnad->conf_mutex); - if (tx_csum) { - netdev->features |= NETIF_F_IP_CSUM; - netdev->features |= NETIF_F_IPV6_CSUM; - } else { - netdev->features &= ~NETIF_F_IP_CSUM; - netdev->features &= ~NETIF_F_IPV6_CSUM; - } - mutex_unlock(&bnad->conf_mutex); - return 0; -} - -static int -bnad_set_tso(struct net_device *netdev, u32 tso) -{ - struct bnad *bnad = netdev_priv(netdev); - - mutex_lock(&bnad->conf_mutex); - if (tso) { - netdev->features |= NETIF_F_TSO; - netdev->features |= NETIF_F_TSO6; - } else { - netdev->features &= ~NETIF_F_TSO; - netdev->features &= ~NETIF_F_TSO6; - } - mutex_unlock(&bnad->conf_mutex); - return 0; -} - static void bnad_get_strings(struct net_device *netdev, u32 stringset, u8 * string) { @@ -1256,14 +1201,6 @@ static struct ethtool_ops bnad_ethtool_ops = { .set_ringparam = bnad_set_ringparam, .get_pauseparam = bnad_get_pauseparam, .set_pauseparam = bnad_set_pauseparam, - .get_rx_csum = bnad_get_rx_csum, - .set_rx_csum = bnad_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = bnad_set_tx_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, - .set_tso = bnad_set_tso, .get_strings = bnad_get_strings, .get_ethtool_stats = bnad_get_ethtool_stats, .get_sset_count = bnad_get_sset_count diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 8e6d618b5305..bf729ee6acbd 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -3174,7 +3174,7 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) } skb_checksum_none_assert(skb); - if (bp->rx_csum && + if ((bp->dev->features & NETIF_F_RXCSUM) && (status & (L2_FHDR_STATUS_TCP_SEGMENT | L2_FHDR_STATUS_UDP_DATAGRAM))) { @@ -7189,38 +7189,6 @@ bnx2_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause) return 0; } -static u32 -bnx2_get_rx_csum(struct net_device *dev) -{ - struct bnx2 *bp = netdev_priv(dev); - - return bp->rx_csum; -} - -static int -bnx2_set_rx_csum(struct net_device *dev, u32 data) -{ - struct bnx2 *bp = netdev_priv(dev); - - bp->rx_csum = data; - return 0; -} - -static int -bnx2_set_tso(struct net_device *dev, u32 data) -{ - struct bnx2 *bp = netdev_priv(dev); - - if (data) { - dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN; - if (CHIP_NUM(bp) == CHIP_NUM_5709) - dev->features |= NETIF_F_TSO6; - } else - dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6 | - NETIF_F_TSO_ECN); - return 0; -} - static struct { char string[ETH_GSTRING_LEN]; } bnx2_stats_str_arr[] = { @@ -7495,82 +7463,74 @@ bnx2_get_ethtool_stats(struct net_device *dev, } static int -bnx2_phys_id(struct net_device *dev, u32 data) +bnx2_set_phys_id(struct net_device *dev, enum ethtool_phys_id_state state) { struct bnx2 *bp = netdev_priv(dev); - int i; - u32 save; - bnx2_set_power_state(bp, PCI_D0); + switch (state) { + case ETHTOOL_ID_ACTIVE: + bnx2_set_power_state(bp, PCI_D0); + + bp->leds_save = REG_RD(bp, BNX2_MISC_CFG); + REG_WR(bp, BNX2_MISC_CFG, BNX2_MISC_CFG_LEDMODE_MAC); + return 1; /* cycle on/off once per second */ + + case ETHTOOL_ID_ON: + REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE | + BNX2_EMAC_LED_1000MB_OVERRIDE | + BNX2_EMAC_LED_100MB_OVERRIDE | + BNX2_EMAC_LED_10MB_OVERRIDE | + BNX2_EMAC_LED_TRAFFIC_OVERRIDE | + BNX2_EMAC_LED_TRAFFIC); + break; - if (data == 0) - data = 2; + case ETHTOOL_ID_OFF: + REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE); + break; - save = REG_RD(bp, BNX2_MISC_CFG); - REG_WR(bp, BNX2_MISC_CFG, BNX2_MISC_CFG_LEDMODE_MAC); + case ETHTOOL_ID_INACTIVE: + REG_WR(bp, BNX2_EMAC_LED, 0); + REG_WR(bp, BNX2_MISC_CFG, bp->leds_save); - for (i = 0; i < (data * 2); i++) { - if ((i % 2) == 0) { - REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE); - } - else { - REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE | - BNX2_EMAC_LED_1000MB_OVERRIDE | - BNX2_EMAC_LED_100MB_OVERRIDE | - BNX2_EMAC_LED_10MB_OVERRIDE | - BNX2_EMAC_LED_TRAFFIC_OVERRIDE | - BNX2_EMAC_LED_TRAFFIC); - } - msleep_interruptible(500); - if (signal_pending(current)) - break; + if (!netif_running(dev)) + bnx2_set_power_state(bp, PCI_D3hot); + break; } - REG_WR(bp, BNX2_EMAC_LED, 0); - REG_WR(bp, BNX2_MISC_CFG, save); - - if (!netif_running(dev)) - bnx2_set_power_state(bp, PCI_D3hot); return 0; } -static int -bnx2_set_tx_csum(struct net_device *dev, u32 data) +static u32 +bnx2_fix_features(struct net_device *dev, u32 features) { struct bnx2 *bp = netdev_priv(dev); - if (CHIP_NUM(bp) == CHIP_NUM_5709) - return ethtool_op_set_tx_ipv6_csum(dev, data); - else - return ethtool_op_set_tx_csum(dev, data); + if (!(bp->flags & BNX2_FLAG_CAN_KEEP_VLAN)) + features |= NETIF_F_HW_VLAN_RX; + + return features; } static int -bnx2_set_flags(struct net_device *dev, u32 data) +bnx2_set_features(struct net_device *dev, u32 features) { struct bnx2 *bp = netdev_priv(dev); - int rc; - - if (!(bp->flags & BNX2_FLAG_CAN_KEEP_VLAN) && - !(data & ETH_FLAG_RXVLAN)) - return -EINVAL; /* TSO with VLAN tag won't work with current firmware */ - if (!(data & ETH_FLAG_TXVLAN)) - return -EINVAL; - - rc = ethtool_op_set_flags(dev, data, ETH_FLAG_RXHASH | ETH_FLAG_RXVLAN | - ETH_FLAG_TXVLAN); - if (rc) - return rc; + if (features & NETIF_F_HW_VLAN_TX) + dev->vlan_features |= (dev->hw_features & NETIF_F_ALL_TSO); + else + dev->vlan_features &= ~NETIF_F_ALL_TSO; - if ((!!(data & ETH_FLAG_RXVLAN) != + if ((!!(features & NETIF_F_HW_VLAN_RX) != !!(bp->rx_mode & BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG)) && netif_running(dev)) { bnx2_netif_stop(bp, false); + dev->features = features; bnx2_set_rx_mode(dev); bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_KEEP_VLAN_UPDATE, 0, 1); bnx2_netif_start(bp, false); + return 1; } return 0; @@ -7595,18 +7555,11 @@ static const struct ethtool_ops bnx2_ethtool_ops = { .set_ringparam = bnx2_set_ringparam, .get_pauseparam = bnx2_get_pauseparam, .set_pauseparam = bnx2_set_pauseparam, - .get_rx_csum = bnx2_get_rx_csum, - .set_rx_csum = bnx2_set_rx_csum, - .set_tx_csum = bnx2_set_tx_csum, - .set_sg = ethtool_op_set_sg, - .set_tso = bnx2_set_tso, .self_test = bnx2_self_test, .get_strings = bnx2_get_strings, - .phys_id = bnx2_phys_id, + .set_phys_id = bnx2_set_phys_id, .get_ethtool_stats = bnx2_get_ethtool_stats, .get_sset_count = bnx2_get_sset_count, - .set_flags = bnx2_set_flags, - .get_flags = ethtool_op_get_flags, }; /* Called with rtnl_lock */ @@ -8118,8 +8071,6 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) bp->tx_ring_size = MAX_TX_DESC_CNT; bnx2_set_rx_ring_size(bp, 255); - bp->rx_csum = 1; - bp->tx_quick_cons_trip_int = 2; bp->tx_quick_cons_trip = 20; bp->tx_ticks_int = 18; @@ -8311,17 +8262,14 @@ static const struct net_device_ops bnx2_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = bnx2_change_mac_addr, .ndo_change_mtu = bnx2_change_mtu, + .ndo_fix_features = bnx2_fix_features, + .ndo_set_features = bnx2_set_features, .ndo_tx_timeout = bnx2_tx_timeout, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = poll_bnx2, #endif }; -static inline void vlan_features_add(struct net_device *dev, u32 flags) -{ - dev->vlan_features |= flags; -} - static int __devinit bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -8361,20 +8309,17 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) memcpy(dev->dev_addr, bp->mac_addr, 6); memcpy(dev->perm_addr, bp->mac_addr, 6); - dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_GRO | - NETIF_F_RXHASH; - vlan_features_add(dev, NETIF_F_IP_CSUM | NETIF_F_SG); - if (CHIP_NUM(bp) == CHIP_NUM_5709) { - dev->features |= NETIF_F_IPV6_CSUM; - vlan_features_add(dev, NETIF_F_IPV6_CSUM); - } - dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN; - vlan_features_add(dev, NETIF_F_TSO | NETIF_F_TSO_ECN); - if (CHIP_NUM(bp) == CHIP_NUM_5709) { - dev->features |= NETIF_F_TSO6; - vlan_features_add(dev, NETIF_F_TSO6); - } + dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG | + NETIF_F_TSO | NETIF_F_TSO_ECN | + NETIF_F_RXHASH | NETIF_F_RXCSUM; + + if (CHIP_NUM(bp) == CHIP_NUM_5709) + dev->hw_features |= NETIF_F_IPV6_CSUM | NETIF_F_TSO6; + + dev->vlan_features = dev->hw_features; + dev->hw_features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + dev->features |= dev->hw_features; + if ((rc = register_netdev(dev))) { dev_err(&pdev->dev, "Cannot register net device\n"); goto error; diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index 68020451dc4f..bf371f6fe154 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -6754,8 +6754,6 @@ struct bnx2 { u32 rx_max_ring_idx; u32 rx_max_pg_ring_idx; - u32 rx_csum; - /* TX constants */ int tx_ring_size; u32 tx_wake_thresh; @@ -6922,6 +6920,7 @@ struct bnx2 { u8 num_tx_rings; u8 num_rx_rings; + u32 leds_save; u32 idle_chk_status_idx; #ifdef BCM_CNIC diff --git a/drivers/net/bnx2x/bnx2x.h b/drivers/net/bnx2x/bnx2x.h index e0fca701d2f3..9e87417f6ec7 100644 --- a/drivers/net/bnx2x/bnx2x.h +++ b/drivers/net/bnx2x/bnx2x.h @@ -918,7 +918,6 @@ struct bnx2x { int tx_ring_size; - u32 rx_csum; /* L2 header size + 2*VLANs (8 bytes) + LLC SNAP (8 bytes) */ #define ETH_OVREHEAD (ETH_HLEN + 8 + 8) #define ETH_MIN_PACKET_SIZE 60 diff --git a/drivers/net/bnx2x/bnx2x_cmn.c b/drivers/net/bnx2x/bnx2x_cmn.c index e83ac6dd6fc0..bec33a87bcdc 100644 --- a/drivers/net/bnx2x/bnx2x_cmn.c +++ b/drivers/net/bnx2x/bnx2x_cmn.c @@ -640,7 +640,7 @@ reuse_rx: skb_checksum_none_assert(skb); - if (bp->rx_csum) { + if (bp->dev->features & NETIF_F_RXCSUM) { if (likely(BNX2X_RX_CSUM_OK(cqe))) skb->ip_summed = CHECKSUM_UNNECESSARY; else @@ -2443,11 +2443,21 @@ alloc_err: } +static int bnx2x_reload_if_running(struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + + if (unlikely(!netif_running(dev))) + return 0; + + bnx2x_nic_unload(bp, UNLOAD_NORMAL); + return bnx2x_nic_load(bp, LOAD_NORMAL); +} + /* called with rtnl_lock */ int bnx2x_change_mtu(struct net_device *dev, int new_mtu) { struct bnx2x *bp = netdev_priv(dev); - int rc = 0; if (bp->recovery_state != BNX2X_RECOVERY_DONE) { printk(KERN_ERR "Handling parity error recovery. Try again later\n"); @@ -2464,12 +2474,39 @@ int bnx2x_change_mtu(struct net_device *dev, int new_mtu) */ dev->mtu = new_mtu; - if (netif_running(dev)) { - bnx2x_nic_unload(bp, UNLOAD_NORMAL); - rc = bnx2x_nic_load(bp, LOAD_NORMAL); + return bnx2x_reload_if_running(dev); +} + +u32 bnx2x_fix_features(struct net_device *dev, u32 features) +{ + struct bnx2x *bp = netdev_priv(dev); + + /* TPA requires Rx CSUM offloading */ + if (!(features & NETIF_F_RXCSUM) || bp->disable_tpa) + features &= ~NETIF_F_LRO; + + return features; +} + +int bnx2x_set_features(struct net_device *dev, u32 features) +{ + struct bnx2x *bp = netdev_priv(dev); + u32 flags = bp->flags; + + if (features & NETIF_F_LRO) + flags |= TPA_ENABLE_FLAG; + else + flags &= ~TPA_ENABLE_FLAG; + + if (flags ^ bp->flags) { + bp->flags = flags; + + if (bp->recovery_state == BNX2X_RECOVERY_DONE) + return bnx2x_reload_if_running(dev); + /* else: bnx2x_nic_load() will be called at end of recovery */ } - return rc; + return 0; } void bnx2x_tx_timeout(struct net_device *dev) diff --git a/drivers/net/bnx2x/bnx2x_cmn.h b/drivers/net/bnx2x/bnx2x_cmn.h index ef37b98d6146..1cdab69b2a51 100644 --- a/drivers/net/bnx2x/bnx2x_cmn.h +++ b/drivers/net/bnx2x/bnx2x_cmn.h @@ -431,6 +431,9 @@ void bnx2x_free_mem_bp(struct bnx2x *bp); */ int bnx2x_change_mtu(struct net_device *dev, int new_mtu); +u32 bnx2x_fix_features(struct net_device *dev, u32 features); +int bnx2x_set_features(struct net_device *dev, u32 features); + /** * tx timeout netdev callback * @@ -1041,12 +1044,23 @@ static inline void storm_memset_cmng(struct bnx2x *bp, struct cmng_struct_per_port *cmng, u8 port) { - size_t size = sizeof(struct cmng_struct_per_port); + size_t size = + sizeof(struct rate_shaping_vars_per_port) + + sizeof(struct fairness_vars_per_port) + + sizeof(struct safc_struct_per_port) + + sizeof(struct pfc_struct_per_port); u32 addr = BAR_XSTRORM_INTMEM + XSTORM_CMNG_PER_PORT_VARS_OFFSET(port); __storm_memset_struct(bp, addr, size, (u32 *)cmng); + + addr += size + 4 /* SKIP DCB+LLFC */; + size = sizeof(struct cmng_struct_per_port) - + size /* written */ - 4 /*skipped*/; + + __storm_memset_struct(bp, addr, size, + (u32 *)(cmng->traffic_type_to_priority_cos)); } /* HW Lock for shared dual port PHYs */ diff --git a/drivers/net/bnx2x/bnx2x_dcb.c b/drivers/net/bnx2x/bnx2x_dcb.c index 9a24d79c71d9..1214907d00d9 100644 --- a/drivers/net/bnx2x/bnx2x_dcb.c +++ b/drivers/net/bnx2x/bnx2x_dcb.c @@ -571,6 +571,28 @@ void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state) { switch (state) { case BNX2X_DCBX_STATE_NEG_RECEIVED: +#ifdef BCM_CNIC + if (bp->state != BNX2X_STATE_OPENING_WAIT4_LOAD) { + struct cnic_ops *c_ops; + struct cnic_eth_dev *cp = &bp->cnic_eth_dev; + bp->flags |= NO_ISCSI_OOO_FLAG | NO_ISCSI_FLAG; + cp->drv_state |= CNIC_DRV_STATE_NO_ISCSI_OOO; + cp->drv_state |= CNIC_DRV_STATE_NO_ISCSI; + + rcu_read_lock(); + c_ops = rcu_dereference(bp->cnic_ops); + if (c_ops) { + bnx2x_cnic_notify(bp, CNIC_CTL_STOP_ISCSI_CMD); + rcu_read_unlock(); + return; + } + rcu_read_unlock(); + } + + /* fall through if no CNIC initialized */ + case BNX2X_DCBX_STATE_ISCSI_STOPPED: +#endif + { DP(NETIF_MSG_LINK, "BNX2X_DCBX_STATE_NEG_RECEIVED\n"); #ifdef BCM_DCBNL diff --git a/drivers/net/bnx2x/bnx2x_dcb.h b/drivers/net/bnx2x/bnx2x_dcb.h index 71b8eda43bd0..1e14775a18cb 100644 --- a/drivers/net/bnx2x/bnx2x_dcb.h +++ b/drivers/net/bnx2x/bnx2x_dcb.h @@ -183,9 +183,13 @@ void bnx2x_dcbx_set_state(struct bnx2x *bp, bool dcb_on, u32 dcbx_enabled); enum { BNX2X_DCBX_STATE_NEG_RECEIVED = 0x1, - BNX2X_DCBX_STATE_TX_PAUSED = 0x2, - BNX2X_DCBX_STATE_TX_RELEASED = 0x4 +#ifdef BCM_CNIC + BNX2X_DCBX_STATE_ISCSI_STOPPED, +#endif + BNX2X_DCBX_STATE_TX_PAUSED, + BNX2X_DCBX_STATE_TX_RELEASED }; + void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state); /* DCB netlink */ diff --git a/drivers/net/bnx2x/bnx2x_ethtool.c b/drivers/net/bnx2x/bnx2x_ethtool.c index 89cb977898cb..4f42c314986c 100644 --- a/drivers/net/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/bnx2x/bnx2x_ethtool.c @@ -167,6 +167,7 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct bnx2x *bp = netdev_priv(dev); int cfg_idx = bnx2x_get_link_cfg_idx(bp); + /* Dual Media boards present all available port types */ cmd->supported = bp->port.supported[cfg_idx] | (bp->port.supported[cfg_idx ^ 1] & @@ -176,16 +177,16 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) if ((bp->state == BNX2X_STATE_OPEN) && !(bp->flags & MF_FUNC_DIS) && (bp->link_vars.link_up)) { - cmd->speed = bp->link_vars.line_speed; + ethtool_cmd_speed_set(cmd, bp->link_vars.line_speed); cmd->duplex = bp->link_vars.duplex; } else { - - cmd->speed = bp->link_params.req_line_speed[cfg_idx]; + ethtool_cmd_speed_set( + cmd, bp->link_params.req_line_speed[cfg_idx]); cmd->duplex = bp->link_params.req_duplex[cfg_idx]; } if (IS_MF(bp)) - cmd->speed = bnx2x_get_mf_speed(bp); + ethtool_cmd_speed_set(cmd, bnx2x_get_mf_speed(bp)); if (bp->port.supported[cfg_idx] & SUPPORTED_TP) cmd->port = PORT_TP; @@ -206,10 +207,11 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->maxrxpkt = 0; DP(NETIF_MSG_LINK, "ethtool_cmd: cmd %d\n" - DP_LEVEL " supported 0x%x advertising 0x%x speed %d\n" + DP_LEVEL " supported 0x%x advertising 0x%x speed %u\n" DP_LEVEL " duplex %d port %d phy_address %d transceiver %d\n" DP_LEVEL " autoneg %d maxtxpkt %d maxrxpkt %d\n", - cmd->cmd, cmd->supported, cmd->advertising, cmd->speed, + cmd->cmd, cmd->supported, cmd->advertising, + ethtool_cmd_speed(cmd), cmd->duplex, cmd->port, cmd->phy_address, cmd->transceiver, cmd->autoneg, cmd->maxtxpkt, cmd->maxrxpkt); @@ -226,16 +228,15 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) return 0; DP(NETIF_MSG_LINK, "ethtool_cmd: cmd %d\n" - " supported 0x%x advertising 0x%x speed %d speed_hi %d\n" + " supported 0x%x advertising 0x%x speed %u\n" " duplex %d port %d phy_address %d transceiver %d\n" " autoneg %d maxtxpkt %d maxrxpkt %d\n", - cmd->cmd, cmd->supported, cmd->advertising, cmd->speed, - cmd->speed_hi, + cmd->cmd, cmd->supported, cmd->advertising, + ethtool_cmd_speed(cmd), cmd->duplex, cmd->port, cmd->phy_address, cmd->transceiver, cmd->autoneg, cmd->maxtxpkt, cmd->maxrxpkt); - speed = cmd->speed; - speed |= (cmd->speed_hi << 16); + speed = ethtool_cmd_speed(cmd); if (IS_MF_SI(bp)) { u32 part; @@ -439,7 +440,7 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) break; default: - DP(NETIF_MSG_LINK, "Unsupported speed %d\n", speed); + DP(NETIF_MSG_LINK, "Unsupported speed %u\n", speed); return -EINVAL; } @@ -1299,91 +1300,6 @@ static int bnx2x_set_pauseparam(struct net_device *dev, return 0; } -static int bnx2x_set_flags(struct net_device *dev, u32 data) -{ - struct bnx2x *bp = netdev_priv(dev); - int changed = 0; - int rc = 0; - - if (bp->recovery_state != BNX2X_RECOVERY_DONE) { - printk(KERN_ERR "Handling parity error recovery. Try again later\n"); - return -EAGAIN; - } - - if (!(data & ETH_FLAG_RXVLAN)) - return -EINVAL; - - if ((data & ETH_FLAG_LRO) && bp->rx_csum && bp->disable_tpa) - return -EINVAL; - - rc = ethtool_op_set_flags(dev, data, ETH_FLAG_LRO | ETH_FLAG_RXVLAN | - ETH_FLAG_TXVLAN | ETH_FLAG_RXHASH); - if (rc) - return rc; - - /* TPA requires Rx CSUM offloading */ - if ((data & ETH_FLAG_LRO) && bp->rx_csum) { - if (!(bp->flags & TPA_ENABLE_FLAG)) { - bp->flags |= TPA_ENABLE_FLAG; - changed = 1; - } - } else if (bp->flags & TPA_ENABLE_FLAG) { - dev->features &= ~NETIF_F_LRO; - bp->flags &= ~TPA_ENABLE_FLAG; - changed = 1; - } - - if (changed && netif_running(dev)) { - bnx2x_nic_unload(bp, UNLOAD_NORMAL); - rc = bnx2x_nic_load(bp, LOAD_NORMAL); - } - - return rc; -} - -static u32 bnx2x_get_rx_csum(struct net_device *dev) -{ - struct bnx2x *bp = netdev_priv(dev); - - return bp->rx_csum; -} - -static int bnx2x_set_rx_csum(struct net_device *dev, u32 data) -{ - struct bnx2x *bp = netdev_priv(dev); - int rc = 0; - - if (bp->recovery_state != BNX2X_RECOVERY_DONE) { - printk(KERN_ERR "Handling parity error recovery. Try again later\n"); - return -EAGAIN; - } - - bp->rx_csum = data; - - /* Disable TPA, when Rx CSUM is disabled. Otherwise all - TPA'ed packets will be discarded due to wrong TCP CSUM */ - if (!data) { - u32 flags = ethtool_op_get_flags(dev); - - rc = bnx2x_set_flags(dev, (flags & ~ETH_FLAG_LRO)); - } - - return rc; -} - -static int bnx2x_set_tso(struct net_device *dev, u32 data) -{ - if (data) { - dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN); - dev->features |= NETIF_F_TSO6; - } else { - dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO_ECN); - dev->features &= ~NETIF_F_TSO6; - } - - return 0; -} - static const struct { char string[ETH_GSTRING_LEN]; } bnx2x_tests_str_arr[BNX2X_NUM_TESTS] = { @@ -2097,35 +2013,37 @@ static void bnx2x_get_ethtool_stats(struct net_device *dev, } } -static int bnx2x_phys_id(struct net_device *dev, u32 data) +static int bnx2x_set_phys_id(struct net_device *dev, + enum ethtool_phys_id_state state) { struct bnx2x *bp = netdev_priv(dev); - int i; if (!netif_running(dev)) - return 0; + return -EAGAIN; if (!bp->port.pmf) - return 0; + return -EOPNOTSUPP; - if (data == 0) - data = 2; + switch (state) { + case ETHTOOL_ID_ACTIVE: + return 1; /* cycle on/off once per second */ - for (i = 0; i < (data * 2); i++) { - if ((i % 2) == 0) - bnx2x_set_led(&bp->link_params, &bp->link_vars, - LED_MODE_ON, SPEED_1000); - else - bnx2x_set_led(&bp->link_params, &bp->link_vars, - LED_MODE_FRONT_PANEL_OFF, 0); + case ETHTOOL_ID_ON: + bnx2x_set_led(&bp->link_params, &bp->link_vars, + LED_MODE_ON, SPEED_1000); + break; - msleep_interruptible(500); - if (signal_pending(current)) - break; - } + case ETHTOOL_ID_OFF: + bnx2x_set_led(&bp->link_params, &bp->link_vars, + LED_MODE_FRONT_PANEL_OFF, 0); + + break; - bnx2x_set_led(&bp->link_params, &bp->link_vars, - LED_MODE_OPER, bp->link_vars.line_speed); + case ETHTOOL_ID_INACTIVE: + bnx2x_set_led(&bp->link_params, &bp->link_vars, + LED_MODE_OPER, + bp->link_vars.line_speed); + } return 0; } @@ -2204,20 +2122,10 @@ static const struct ethtool_ops bnx2x_ethtool_ops = { .set_ringparam = bnx2x_set_ringparam, .get_pauseparam = bnx2x_get_pauseparam, .set_pauseparam = bnx2x_set_pauseparam, - .get_rx_csum = bnx2x_get_rx_csum, - .set_rx_csum = bnx2x_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_hw_csum, - .set_flags = bnx2x_set_flags, - .get_flags = ethtool_op_get_flags, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, - .set_tso = bnx2x_set_tso, .self_test = bnx2x_self_test, .get_sset_count = bnx2x_get_sset_count, .get_strings = bnx2x_get_strings, - .phys_id = bnx2x_phys_id, + .set_phys_id = bnx2x_set_phys_id, .get_ethtool_stats = bnx2x_get_ethtool_stats, .get_rxnfc = bnx2x_get_rxnfc, .get_rxfh_indir = bnx2x_get_rxfh_indir, diff --git a/drivers/net/bnx2x/bnx2x_hsi.h b/drivers/net/bnx2x/bnx2x_hsi.h index dac1bf9cbbfa..2b5940af5d1b 100644 --- a/drivers/net/bnx2x/bnx2x_hsi.h +++ b/drivers/net/bnx2x/bnx2x_hsi.h @@ -1929,7 +1929,7 @@ struct host_func_stats { #define BCM_5710_FW_MAJOR_VERSION 6 #define BCM_5710_FW_MINOR_VERSION 2 -#define BCM_5710_FW_REVISION_VERSION 5 +#define BCM_5710_FW_REVISION_VERSION 9 #define BCM_5710_FW_ENGINEERING_VERSION 0 #define BCM_5710_FW_COMPILE_FLAGS 1 diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c index a97a4a1c344f..bfd7ac98248b 100644 --- a/drivers/net/bnx2x/bnx2x_main.c +++ b/drivers/net/bnx2x/bnx2x_main.c @@ -3904,10 +3904,9 @@ static void bnx2x_timer(unsigned long data) if (poll) { struct bnx2x_fastpath *fp = &bp->fp[0]; - int rc; bnx2x_tx_int(fp); - rc = bnx2x_rx_int(fp, 1000); + bnx2x_rx_int(fp, 1000); } if (!BP_NOMCP(bp)) { @@ -4062,7 +4061,6 @@ static void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid, struct hc_status_block_data_e2 sb_data_e2; struct hc_status_block_data_e1x sb_data_e1x; struct hc_status_block_sm *hc_sm_p; - struct hc_index_data *hc_index_p; int data_size; u32 *sb_data_p; @@ -4083,7 +4081,6 @@ static void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid, sb_data_e2.common.host_sb_addr.hi = U64_HI(mapping); sb_data_e2.common.host_sb_addr.lo = U64_LO(mapping); hc_sm_p = sb_data_e2.common.state_machine; - hc_index_p = sb_data_e2.index_data; sb_data_p = (u32 *)&sb_data_e2; data_size = sizeof(struct hc_status_block_data_e2)/sizeof(u32); } else { @@ -4097,7 +4094,6 @@ static void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid, sb_data_e1x.common.host_sb_addr.hi = U64_HI(mapping); sb_data_e1x.common.host_sb_addr.lo = U64_LO(mapping); hc_sm_p = sb_data_e1x.common.state_machine; - hc_index_p = sb_data_e1x.index_data; sb_data_p = (u32 *)&sb_data_e1x; data_size = sizeof(struct hc_status_block_data_e1x)/sizeof(u32); } @@ -8635,7 +8631,7 @@ static void __devinit bnx2x_get_mac_hwinfo(struct bnx2x *bp) static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp) { int /*abs*/func = BP_ABS_FUNC(bp); - int vn, port; + int vn; u32 val = 0; int rc = 0; @@ -8670,7 +8666,6 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp) bp->mf_ov = 0; bp->mf_mode = 0; vn = BP_E1HVN(bp); - port = BP_PORT(bp); if (!CHIP_IS_E1(bp) && !BP_NOMCP(bp)) { DP(NETIF_MSG_PROBE, @@ -8904,8 +8899,6 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp) bp->multi_mode = multi_mode; bp->int_mode = int_mode; - bp->dev->features |= NETIF_F_GRO; - /* Set TPA flags */ if (disable_tpa) { bp->flags &= ~TPA_ENABLE_FLAG; @@ -8925,8 +8918,6 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp) bp->tx_ring_size = MAX_TX_AVAIL; - bp->rx_csum = 1; - /* make sure that the numbers are in the right granularity */ bp->tx_ticks = (50 / BNX2X_BTR) * BNX2X_BTR; bp->rx_ticks = (25 / BNX2X_BTR) * BNX2X_BTR; @@ -9304,6 +9295,8 @@ static const struct net_device_ops bnx2x_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_do_ioctl = bnx2x_ioctl, .ndo_change_mtu = bnx2x_change_mtu, + .ndo_fix_features = bnx2x_fix_features, + .ndo_set_features = bnx2x_set_features, .ndo_tx_timeout = bnx2x_tx_timeout, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = poll_bnx2x, @@ -9430,20 +9423,17 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev, dev->netdev_ops = &bnx2x_netdev_ops; bnx2x_set_ethtool_ops(dev); - dev->features |= NETIF_F_SG; - dev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; - if (bp->flags & USING_DAC_FLAG) - dev->features |= NETIF_F_HIGHDMA; - dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN); - dev->features |= NETIF_F_TSO6; - dev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX); - dev->vlan_features |= NETIF_F_SG; - dev->vlan_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6 | + NETIF_F_RXCSUM | NETIF_F_LRO | NETIF_F_HW_VLAN_TX; + + dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_HIGHDMA; + + dev->features |= dev->hw_features | NETIF_F_HW_VLAN_RX; if (bp->flags & USING_DAC_FLAG) - dev->vlan_features |= NETIF_F_HIGHDMA; - dev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO_ECN); - dev->vlan_features |= NETIF_F_TSO6; + dev->features |= NETIF_F_HIGHDMA; #ifdef BCM_DCBNL dev->dcbnl_ops = &bnx2x_dcbnl_ops; @@ -10342,6 +10332,11 @@ static int bnx2x_drv_ctl(struct net_device *dev, struct drv_ctl_info *ctl) break; } + case DRV_CTL_ISCSI_STOPPED_CMD: { + bnx2x_dcbx_set_params(bp, BNX2X_DCBX_STATE_ISCSI_STOPPED); + break; + } + default: BNX2X_ERR("unknown command %x\n", ctl->cmd); rc = -EINVAL; diff --git a/drivers/net/bonding/Makefile b/drivers/net/bonding/Makefile index 3c5c014e82b2..4c21bf6b8b2f 100644 --- a/drivers/net/bonding/Makefile +++ b/drivers/net/bonding/Makefile @@ -9,6 +9,3 @@ bonding-objs := bond_main.o bond_3ad.o bond_alb.o bond_sysfs.o bond_debugfs.o proc-$(CONFIG_PROC_FS) += bond_procfs.o bonding-objs += $(proc-y) -ipv6-$(subst m,y,$(CONFIG_IPV6)) += bond_ipv6.o -bonding-objs += $(ipv6-y) - diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 494bf960442d..123dd602261f 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -716,11 +716,9 @@ static void __set_agg_ports_ready(struct aggregator *aggregator, int val) static u32 __get_agg_bandwidth(struct aggregator *aggregator) { u32 bandwidth = 0; - u32 basic_speed; if (aggregator->num_of_ports) { - basic_speed = __get_link_speed(aggregator->lag_ports); - switch (basic_speed) { + switch (__get_link_speed(aggregator->lag_ports)) { case AD_LINK_SPEED_BITMASK_1MBPS: bandwidth = aggregator->num_of_ports; break; diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 16d6fe954695..4ce14bdf96dd 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -89,8 +89,6 @@ static int max_bonds = BOND_DEFAULT_MAX_BONDS; static int tx_queues = BOND_DEFAULT_TX_QUEUES; -static int num_grat_arp = 1; -static int num_unsol_na = 1; static int miimon = BOND_LINK_MON_INTERV; static int updelay; static int downdelay; @@ -113,10 +111,6 @@ module_param(max_bonds, int, 0); MODULE_PARM_DESC(max_bonds, "Max number of bonded devices"); module_param(tx_queues, int, 0); MODULE_PARM_DESC(tx_queues, "Max number of transmit queues (default = 16)"); -module_param(num_grat_arp, int, 0644); -MODULE_PARM_DESC(num_grat_arp, "Number of gratuitous ARP packets to send on failover event"); -module_param(num_unsol_na, int, 0644); -MODULE_PARM_DESC(num_unsol_na, "Number of unsolicited IPv6 Neighbor Advertisements packets to send on failover event"); module_param(miimon, int, 0); MODULE_PARM_DESC(miimon, "Link check interval in milliseconds"); module_param(updelay, int, 0); @@ -234,7 +228,6 @@ struct bond_parm_tbl ad_select_tbl[] = { /*-------------------------- Forward declarations ---------------------------*/ -static void bond_send_gratuitous_arp(struct bonding *bond); static int bond_init(struct net_device *bond_dev); static void bond_uninit(struct net_device *bond_dev); @@ -631,7 +624,8 @@ down: static int bond_update_speed_duplex(struct slave *slave) { struct net_device *slave_dev = slave->dev; - struct ethtool_cmd etool; + struct ethtool_cmd etool = { .cmd = ETHTOOL_GSET }; + u32 slave_speed; int res; /* Fake speed and duplex */ @@ -645,7 +639,8 @@ static int bond_update_speed_duplex(struct slave *slave) if (res < 0) return -1; - switch (etool.speed) { + slave_speed = ethtool_cmd_speed(&etool); + switch (slave_speed) { case SPEED_10: case SPEED_100: case SPEED_1000: @@ -663,7 +658,7 @@ static int bond_update_speed_duplex(struct slave *slave) return -1; } - slave->speed = etool.speed; + slave->speed = slave_speed; slave->duplex = etool.duplex; return 0; @@ -1160,14 +1155,6 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) bond_do_fail_over_mac(bond, new_active, old_active); - if (netif_running(bond->dev)) { - bond->send_grat_arp = bond->params.num_grat_arp; - bond_send_gratuitous_arp(bond); - - bond->send_unsol_na = bond->params.num_unsol_na; - bond_send_unsolicited_na(bond); - } - write_unlock_bh(&bond->curr_slave_lock); read_unlock(&bond->lock); @@ -1407,7 +1394,7 @@ static int bond_compute_features(struct bonding *bond) int i; features &= ~(NETIF_F_ALL_CSUM | BOND_VLAN_FEATURES); - features |= NETIF_F_GSO_MASK | NETIF_F_NO_CSUM; + features |= NETIF_F_GSO_MASK | NETIF_F_NO_CSUM | NETIF_F_NOCACHE_COPY; if (!bond->first_slave) goto done; @@ -2493,7 +2480,7 @@ static void bond_miimon_commit(struct bonding *bond) bond_update_speed_duplex(slave); - pr_info("%s: link status definitely up for interface %s, %d Mbps %s duplex.\n", + pr_info("%s: link status definitely up for interface %s, %u Mbps %s duplex.\n", bond->dev->name, slave->dev->name, slave->speed, slave->duplex ? "full" : "half"); @@ -2578,18 +2565,6 @@ void bond_mii_monitor(struct work_struct *work) if (bond->slave_cnt == 0) goto re_arm; - if (bond->send_grat_arp) { - read_lock(&bond->curr_slave_lock); - bond_send_gratuitous_arp(bond); - read_unlock(&bond->curr_slave_lock); - } - - if (bond->send_unsol_na) { - read_lock(&bond->curr_slave_lock); - bond_send_unsolicited_na(bond); - read_unlock(&bond->curr_slave_lock); - } - if (bond_miimon_inspect(bond)) { read_unlock(&bond->lock); rtnl_lock(); @@ -2751,44 +2726,6 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) } } -/* - * Kick out a gratuitous ARP for an IP on the bonding master plus one - * for each VLAN above us. - * - * Caller must hold curr_slave_lock for read or better - */ -static void bond_send_gratuitous_arp(struct bonding *bond) -{ - struct slave *slave = bond->curr_active_slave; - struct vlan_entry *vlan; - struct net_device *vlan_dev; - - pr_debug("bond_send_grat_arp: bond %s slave %s\n", - bond->dev->name, slave ? slave->dev->name : "NULL"); - - if (!slave || !bond->send_grat_arp || - test_bit(__LINK_STATE_LINKWATCH_PENDING, &slave->dev->state)) - return; - - bond->send_grat_arp--; - - if (bond->master_ip) { - bond_arp_send(slave->dev, ARPOP_REPLY, bond->master_ip, - bond->master_ip, 0); - } - - if (!bond->vlgrp) - return; - - list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { - vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id); - if (vlan->vlan_ip) { - bond_arp_send(slave->dev, ARPOP_REPLY, vlan->vlan_ip, - vlan->vlan_ip, vlan->vlan_id); - } - } -} - static void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32 sip, __be32 tip) { int i; @@ -3255,18 +3192,6 @@ void bond_activebackup_arp_mon(struct work_struct *work) if (bond->slave_cnt == 0) goto re_arm; - if (bond->send_grat_arp) { - read_lock(&bond->curr_slave_lock); - bond_send_gratuitous_arp(bond); - read_unlock(&bond->curr_slave_lock); - } - - if (bond->send_unsol_na) { - read_lock(&bond->curr_slave_lock); - bond_send_unsolicited_na(bond); - read_unlock(&bond->curr_slave_lock); - } - if (bond_ab_arp_inspect(bond, delta_in_ticks)) { read_unlock(&bond->lock); rtnl_lock(); @@ -3339,8 +3264,8 @@ static int bond_slave_netdev_event(unsigned long event, slave = bond_get_slave_by_dev(bond, slave_dev); if (slave) { - u16 old_speed = slave->speed; - u16 old_duplex = slave->duplex; + u32 old_speed = slave->speed; + u8 old_duplex = slave->duplex; bond_update_speed_duplex(slave); @@ -3645,9 +3570,6 @@ static int bond_close(struct net_device *bond_dev) write_lock_bh(&bond->lock); - bond->send_grat_arp = 0; - bond->send_unsol_na = 0; - /* signal timers not to re-arm */ bond->kill_timers = 1; @@ -4357,9 +4279,9 @@ static u16 bond_select_queue(struct net_device *dev, struct sk_buff *skb) u16 txq = skb_rx_queue_recorded(skb) ? skb_get_rx_queue(skb) : 0; if (unlikely(txq >= dev->real_num_tx_queues)) { - do + do { txq -= dev->real_num_tx_queues; - while (txq >= dev->real_num_tx_queues); + } while (txq >= dev->real_num_tx_queues); } return txq; } @@ -4724,18 +4646,6 @@ static int bond_check_params(struct bond_params *params) use_carrier = 1; } - if (num_grat_arp < 0 || num_grat_arp > 255) { - pr_warning("Warning: num_grat_arp (%d) not in range 0-255 so it was reset to 1\n", - num_grat_arp); - num_grat_arp = 1; - } - - if (num_unsol_na < 0 || num_unsol_na > 255) { - pr_warning("Warning: num_unsol_na (%d) not in range 0-255 so it was reset to 1\n", - num_unsol_na); - num_unsol_na = 1; - } - /* reset values for 802.3ad */ if (bond_mode == BOND_MODE_8023AD) { if (!miimon) { @@ -4925,8 +4835,6 @@ static int bond_check_params(struct bond_params *params) params->mode = bond_mode; params->xmit_policy = xmit_hashtype; params->miimon = miimon; - params->num_grat_arp = num_grat_arp; - params->num_unsol_na = num_unsol_na; params->arp_interval = arp_interval; params->arp_validate = arp_validate_value; params->updelay = updelay; @@ -5121,7 +5029,6 @@ static int __init bonding_init(void) register_netdevice_notifier(&bond_netdev_notifier); register_inetaddr_notifier(&bond_inetaddr_notifier); - bond_register_ipv6_notifier(); out: return res; err: @@ -5136,7 +5043,6 @@ static void __exit bonding_exit(void) { unregister_netdevice_notifier(&bond_netdev_notifier); unregister_inetaddr_notifier(&bond_inetaddr_notifier); - bond_unregister_ipv6_notifier(); bond_destroy_sysfs(); bond_destroy_debugfs(); diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c index c32ff55a34c1..c97307ddd1c9 100644 --- a/drivers/net/bonding/bond_procfs.c +++ b/drivers/net/bonding/bond_procfs.c @@ -4,8 +4,6 @@ #include "bonding.h" -extern const char *bond_mode_name(int mode); - static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos) __acquires(RCU) __acquires(&bond->lock) diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index de87aea6d01a..259ff32cd573 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -874,84 +874,6 @@ static DEVICE_ATTR(ad_select, S_IRUGO | S_IWUSR, bonding_show_ad_select, bonding_store_ad_select); /* - * Show and set the number of grat ARP to send after a failover event. - */ -static ssize_t bonding_show_n_grat_arp(struct device *d, - struct device_attribute *attr, - char *buf) -{ - struct bonding *bond = to_bond(d); - - return sprintf(buf, "%d\n", bond->params.num_grat_arp); -} - -static ssize_t bonding_store_n_grat_arp(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - int new_value, ret = count; - struct bonding *bond = to_bond(d); - - if (sscanf(buf, "%d", &new_value) != 1) { - pr_err("%s: no num_grat_arp value specified.\n", - bond->dev->name); - ret = -EINVAL; - goto out; - } - if (new_value < 0 || new_value > 255) { - pr_err("%s: Invalid num_grat_arp value %d not in range 0-255; rejected.\n", - bond->dev->name, new_value); - ret = -EINVAL; - goto out; - } else { - bond->params.num_grat_arp = new_value; - } -out: - return ret; -} -static DEVICE_ATTR(num_grat_arp, S_IRUGO | S_IWUSR, - bonding_show_n_grat_arp, bonding_store_n_grat_arp); - -/* - * Show and set the number of unsolicited NA's to send after a failover event. - */ -static ssize_t bonding_show_n_unsol_na(struct device *d, - struct device_attribute *attr, - char *buf) -{ - struct bonding *bond = to_bond(d); - - return sprintf(buf, "%d\n", bond->params.num_unsol_na); -} - -static ssize_t bonding_store_n_unsol_na(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - int new_value, ret = count; - struct bonding *bond = to_bond(d); - - if (sscanf(buf, "%d", &new_value) != 1) { - pr_err("%s: no num_unsol_na value specified.\n", - bond->dev->name); - ret = -EINVAL; - goto out; - } - - if (new_value < 0 || new_value > 255) { - pr_err("%s: Invalid num_unsol_na value %d not in range 0-255; rejected.\n", - bond->dev->name, new_value); - ret = -EINVAL; - goto out; - } else - bond->params.num_unsol_na = new_value; -out: - return ret; -} -static DEVICE_ATTR(num_unsol_na, S_IRUGO | S_IWUSR, - bonding_show_n_unsol_na, bonding_store_n_unsol_na); - -/* * Show and set the MII monitor interval. There are two tricky bits * here. First, if MII monitoring is activated, then we must disable * ARP monitoring. Second, if the timer isn't running, we must @@ -1650,8 +1572,6 @@ static struct attribute *per_bond_attrs[] = { &dev_attr_lacp_rate.attr, &dev_attr_ad_select.attr, &dev_attr_xmit_hash_policy.attr, - &dev_attr_num_grat_arp.attr, - &dev_attr_num_unsol_na.attr, &dev_attr_miimon.attr, &dev_attr_primary.attr, &dev_attr_primary_reselect.attr, diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 90736cb4d975..6126c6a13a74 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -149,8 +149,6 @@ struct bond_params { int mode; int xmit_policy; int miimon; - int num_grat_arp; - int num_unsol_na; int arp_interval; int arp_validate; int use_carrier; @@ -178,9 +176,6 @@ struct vlan_entry { struct list_head vlan_list; __be32 vlan_ip; unsigned short vlan_id; -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - struct in6_addr vlan_ipv6; -#endif }; struct slave { @@ -196,12 +191,12 @@ struct slave { u8 backup:1, /* indicates backup slave. Value corresponds with BOND_STATE_ACTIVE and BOND_STATE_BACKUP */ inactive:1; /* indicates inactive slave */ + u8 duplex; u32 original_mtu; u32 link_failure_count; - u8 perm_hwaddr[ETH_ALEN]; - u16 speed; - u8 duplex; + u32 speed; u16 queue_id; + u8 perm_hwaddr[ETH_ALEN]; struct ad_slave_info ad_info; /* HUGE - better to dynamically alloc */ struct tlb_slave_info tlb_info; #ifdef CONFIG_NET_POLL_CONTROLLER @@ -234,8 +229,6 @@ struct bonding { rwlock_t lock; rwlock_t curr_slave_lock; s8 kill_timers; - s8 send_grat_arp; - s8 send_unsol_na; s8 setup_by_slave; s8 igmp_retrans; #ifdef CONFIG_PROC_FS @@ -260,9 +253,6 @@ struct bonding { struct delayed_work alb_work; struct delayed_work ad_work; struct delayed_work mcast_work; -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - struct in6_addr master_ipv6; -#endif #ifdef CONFIG_DEBUG_FS /* debugging suport via debugfs */ struct dentry *debug_dir; @@ -416,6 +406,7 @@ void bond_destroy_debugfs(void); void bond_debug_register(struct bonding *bond); void bond_debug_unregister(struct bonding *bond); void bond_debug_reregister(struct bonding *bond); +const char *bond_mode_name(int mode); struct bond_net { struct net * net; /* Associated network namespace */ @@ -459,23 +450,4 @@ extern const struct bond_parm_tbl fail_over_mac_tbl[]; extern const struct bond_parm_tbl pri_reselect_tbl[]; extern struct bond_parm_tbl ad_select_tbl[]; -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) -void bond_send_unsolicited_na(struct bonding *bond); -void bond_register_ipv6_notifier(void); -void bond_unregister_ipv6_notifier(void); -#else -static inline void bond_send_unsolicited_na(struct bonding *bond) -{ - return; -} -static inline void bond_register_ipv6_notifier(void) -{ - return; -} -static inline void bond_unregister_ipv6_notifier(void) -{ - return; -} -#endif - #endif /* _LINUX_BONDING_H */ diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h index 092f31a126e6..c26d863e1697 100644 --- a/drivers/net/chelsio/common.h +++ b/drivers/net/chelsio/common.h @@ -264,11 +264,6 @@ struct adapter { enum { /* adapter flags */ FULL_INIT_DONE = 1 << 0, - TSO_CAPABLE = 1 << 2, - TCP_CSUM_CAPABLE = 1 << 3, - UDP_CSUM_CAPABLE = 1 << 4, - VLAN_ACCEL_CAPABLE = 1 << 5, - RX_CSUM_ENABLED = 1 << 6, }; struct mdio_ops; diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c index 0f71304e0542..5f82c9c34978 100644 --- a/drivers/net/chelsio/cxgb2.c +++ b/drivers/net/chelsio/cxgb2.c @@ -192,10 +192,8 @@ static void link_start(struct port_info *p) static void enable_hw_csum(struct adapter *adapter) { - if (adapter->flags & TSO_CAPABLE) + if (adapter->port[0].dev->hw_features & NETIF_F_TSO) t1_tp_set_ip_checksum_offload(adapter->tp, 1); /* for TSO only */ - if (adapter->flags & UDP_CSUM_CAPABLE) - t1_tp_set_udp_checksum_offload(adapter->tp, 1); t1_tp_set_tcp_checksum_offload(adapter->tp, 1); } @@ -705,33 +703,6 @@ static int set_pauseparam(struct net_device *dev, return 0; } -static u32 get_rx_csum(struct net_device *dev) -{ - struct adapter *adapter = dev->ml_priv; - - return (adapter->flags & RX_CSUM_ENABLED) != 0; -} - -static int set_rx_csum(struct net_device *dev, u32 data) -{ - struct adapter *adapter = dev->ml_priv; - - if (data) - adapter->flags |= RX_CSUM_ENABLED; - else - adapter->flags &= ~RX_CSUM_ENABLED; - return 0; -} - -static int set_tso(struct net_device *dev, u32 value) -{ - struct adapter *adapter = dev->ml_priv; - - if (!(adapter->flags & TSO_CAPABLE)) - return value ? -EOPNOTSUPP : 0; - return ethtool_op_set_tso(dev, value); -} - static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e) { struct adapter *adapter = dev->ml_priv; @@ -831,17 +802,12 @@ static const struct ethtool_ops t1_ethtool_ops = { .get_eeprom = get_eeprom, .get_pauseparam = get_pauseparam, .set_pauseparam = set_pauseparam, - .get_rx_csum = get_rx_csum, - .set_rx_csum = set_rx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, - .set_sg = ethtool_op_set_sg, .get_link = ethtool_op_get_link, .get_strings = get_strings, .get_sset_count = get_sset_count, .get_ethtool_stats = get_stats, .get_regs_len = get_regs_len, .get_regs = get_regs, - .set_tso = set_tso, }; static int t1_ioctl(struct net_device *dev, struct ifreq *req, int cmd) @@ -1105,28 +1071,28 @@ static int __devinit init_one(struct pci_dev *pdev, netdev->mem_start = mmio_start; netdev->mem_end = mmio_start + mmio_len - 1; netdev->ml_priv = adapter; - netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; - netdev->features |= NETIF_F_LLTX; + netdev->hw_features |= NETIF_F_SG | NETIF_F_IP_CSUM | + NETIF_F_RXCSUM; + netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | + NETIF_F_RXCSUM | NETIF_F_LLTX; - adapter->flags |= RX_CSUM_ENABLED | TCP_CSUM_CAPABLE; if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; if (vlan_tso_capable(adapter)) { #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) - adapter->flags |= VLAN_ACCEL_CAPABLE; netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; #endif /* T204: disable TSO */ if (!(is_T2(adapter)) || bi->port_number != 4) { - adapter->flags |= TSO_CAPABLE; + netdev->hw_features |= NETIF_F_TSO; netdev->features |= NETIF_F_TSO; } } netdev->netdev_ops = &cxgb_netdev_ops; - netdev->hard_header_len += (adapter->flags & TSO_CAPABLE) ? + netdev->hard_header_len += (netdev->hw_features & NETIF_F_TSO) ? sizeof(struct cpl_tx_pkt_lso) : sizeof(struct cpl_tx_pkt); netif_napi_add(netdev, &adapter->napi, t1_poll, 64); diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c index 8754d4473042..b948ea737550 100644 --- a/drivers/net/chelsio/sge.c +++ b/drivers/net/chelsio/sge.c @@ -929,7 +929,7 @@ void t1_sge_intr_enable(struct sge *sge) u32 en = SGE_INT_ENABLE; u32 val = readl(sge->adapter->regs + A_PL_ENABLE); - if (sge->adapter->flags & TSO_CAPABLE) + if (sge->adapter->port[0].dev->hw_features & NETIF_F_TSO) en &= ~F_PACKET_TOO_BIG; writel(en, sge->adapter->regs + A_SG_INT_ENABLE); writel(val | SGE_PL_INTR_MASK, sge->adapter->regs + A_PL_ENABLE); @@ -952,7 +952,7 @@ int t1_sge_intr_error_handler(struct sge *sge) struct adapter *adapter = sge->adapter; u32 cause = readl(adapter->regs + A_SG_INT_CAUSE); - if (adapter->flags & TSO_CAPABLE) + if (adapter->port[0].dev->hw_features & NETIF_F_TSO) cause &= ~F_PACKET_TOO_BIG; if (cause & F_RESPQ_EXHAUSTED) sge->stats.respQ_empty++; @@ -1369,6 +1369,7 @@ static void sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len) const struct cpl_rx_pkt *p; struct adapter *adapter = sge->adapter; struct sge_port_stats *st; + struct net_device *dev; skb = get_packet(adapter->pdev, fl, len - sge->rx_pkt_pad); if (unlikely(!skb)) { @@ -1384,9 +1385,10 @@ static void sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len) __skb_pull(skb, sizeof(*p)); st = this_cpu_ptr(sge->port_stats[p->iff]); + dev = adapter->port[p->iff].dev; - skb->protocol = eth_type_trans(skb, adapter->port[p->iff].dev); - if ((adapter->flags & RX_CSUM_ENABLED) && p->csum == 0xffff && + skb->protocol = eth_type_trans(skb, dev); + if ((dev->features & NETIF_F_RXCSUM) && p->csum == 0xffff && skb->protocol == htons(ETH_P_IP) && (skb->data[9] == IPPROTO_TCP || skb->data[9] == IPPROTO_UDP)) { ++st->rx_cso_good; @@ -1838,8 +1840,7 @@ netdev_tx_t t1_start_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } - if (!(adapter->flags & UDP_CSUM_CAPABLE) && - skb->ip_summed == CHECKSUM_PARTIAL && + if (skb->ip_summed == CHECKSUM_PARTIAL && ip_hdr(skb)->protocol == IPPROTO_UDP) { if (unlikely(skb_checksum_help(skb))) { pr_debug("%s: unable to do udp checksum\n", dev->name); diff --git a/drivers/net/chelsio/tp.c b/drivers/net/chelsio/tp.c index 6222d585e447..8bed4a59e65f 100644 --- a/drivers/net/chelsio/tp.c +++ b/drivers/net/chelsio/tp.c @@ -152,11 +152,6 @@ void t1_tp_set_ip_checksum_offload(struct petp *tp, int enable) set_csum_offload(tp, F_IP_CSUM, enable); } -void t1_tp_set_udp_checksum_offload(struct petp *tp, int enable) -{ - set_csum_offload(tp, F_UDP_CSUM, enable); -} - void t1_tp_set_tcp_checksum_offload(struct petp *tp, int enable) { set_csum_offload(tp, F_TCP_CSUM, enable); diff --git a/drivers/net/chelsio/tp.h b/drivers/net/chelsio/tp.h index 32fc71e58913..dfd8ce25106a 100644 --- a/drivers/net/chelsio/tp.h +++ b/drivers/net/chelsio/tp.h @@ -65,7 +65,6 @@ void t1_tp_intr_clear(struct petp *tp); int t1_tp_intr_handler(struct petp *tp); void t1_tp_get_mib_statistics(adapter_t *adap, struct tp_mib_statistics *tps); -void t1_tp_set_udp_checksum_offload(struct petp *tp, int enable); void t1_tp_set_tcp_checksum_offload(struct petp *tp, int enable); void t1_tp_set_ip_checksum_offload(struct petp *tp, int enable); int t1_tp_set_coalescing_size(struct petp *tp, unsigned int size); diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c index 8cca60e43444..cde59b4e5ef8 100644 --- a/drivers/net/cnic.c +++ b/drivers/net/cnic.c @@ -2966,31 +2966,36 @@ static int cnic_service_bnx2x(void *data, void *status_blk) return 0; } -static void cnic_ulp_stop(struct cnic_dev *dev) +static void cnic_ulp_stop_one(struct cnic_local *cp, int if_type) { - struct cnic_local *cp = dev->cnic_priv; - int if_type; - - cnic_send_nlmsg(cp, ISCSI_KEVENT_IF_DOWN, NULL); + struct cnic_ulp_ops *ulp_ops; - for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) { - struct cnic_ulp_ops *ulp_ops; + if (if_type == CNIC_ULP_ISCSI) + cnic_send_nlmsg(cp, ISCSI_KEVENT_IF_DOWN, NULL); - mutex_lock(&cnic_lock); - ulp_ops = rcu_dereference_protected(cp->ulp_ops[if_type], - lockdep_is_held(&cnic_lock)); - if (!ulp_ops) { - mutex_unlock(&cnic_lock); - continue; - } - set_bit(ULP_F_CALL_PENDING, &cp->ulp_flags[if_type]); + mutex_lock(&cnic_lock); + ulp_ops = rcu_dereference_protected(cp->ulp_ops[if_type], + lockdep_is_held(&cnic_lock)); + if (!ulp_ops) { mutex_unlock(&cnic_lock); + return; + } + set_bit(ULP_F_CALL_PENDING, &cp->ulp_flags[if_type]); + mutex_unlock(&cnic_lock); - if (test_and_clear_bit(ULP_F_START, &cp->ulp_flags[if_type])) - ulp_ops->cnic_stop(cp->ulp_handle[if_type]); + if (test_and_clear_bit(ULP_F_START, &cp->ulp_flags[if_type])) + ulp_ops->cnic_stop(cp->ulp_handle[if_type]); - clear_bit(ULP_F_CALL_PENDING, &cp->ulp_flags[if_type]); - } + clear_bit(ULP_F_CALL_PENDING, &cp->ulp_flags[if_type]); +} + +static void cnic_ulp_stop(struct cnic_dev *dev) +{ + struct cnic_local *cp = dev->cnic_priv; + int if_type; + + for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) + cnic_ulp_stop_one(cp, if_type); } static void cnic_ulp_start(struct cnic_dev *dev) @@ -3039,6 +3044,12 @@ static int cnic_ctl(void *data, struct cnic_ctl_info *info) cnic_put(dev); break; + case CNIC_CTL_STOP_ISCSI_CMD: { + struct cnic_local *cp = dev->cnic_priv; + set_bit(CNIC_LCL_FL_STOP_ISCSI, &cp->cnic_local_flags); + queue_delayed_work(cnic_wq, &cp->delete_task, 0); + break; + } case CNIC_CTL_COMPLETION_CMD: { u32 cid = BNX2X_SW_CID(info->data.comp.cid); u32 l5_cid; @@ -3562,8 +3573,12 @@ static void cnic_init_csk_state(struct cnic_sock *csk) static int cnic_cm_connect(struct cnic_sock *csk, struct cnic_sockaddr *saddr) { + struct cnic_local *cp = csk->dev->cnic_priv; int err = 0; + if (cp->ethdev->drv_state & CNIC_DRV_STATE_NO_ISCSI) + return -EOPNOTSUPP; + if (!cnic_in_use(csk)) return -EINVAL; @@ -3965,6 +3980,15 @@ static void cnic_delete_task(struct work_struct *work) cp = container_of(work, struct cnic_local, delete_task.work); dev = cp->dev; + if (test_and_clear_bit(CNIC_LCL_FL_STOP_ISCSI, &cp->cnic_local_flags)) { + struct drv_ctl_info info; + + cnic_ulp_stop_one(cp, CNIC_ULP_ISCSI); + + info.cmd = DRV_CTL_ISCSI_STOPPED_CMD; + cp->ethdev->drv_ctl(dev->netdev, &info); + } + for (i = 0; i < cp->max_cid_space; i++) { struct cnic_context *ctx = &cp->ctx_tbl[i]; diff --git a/drivers/net/cnic.h b/drivers/net/cnic.h index 4456260c653c..3367a6d3a774 100644 --- a/drivers/net/cnic.h +++ b/drivers/net/cnic.h @@ -226,6 +226,7 @@ struct cnic_local { #define CNIC_LCL_FL_KWQ_INIT 0x0 #define CNIC_LCL_FL_L2_WAIT 0x1 #define CNIC_LCL_FL_RINGS_INITED 0x2 +#define CNIC_LCL_FL_STOP_ISCSI 0x4 struct cnic_dev *dev; diff --git a/drivers/net/cnic_if.h b/drivers/net/cnic_if.h index e01b49ee3591..fdd8e46a9050 100644 --- a/drivers/net/cnic_if.h +++ b/drivers/net/cnic_if.h @@ -12,8 +12,8 @@ #ifndef CNIC_IF_H #define CNIC_IF_H -#define CNIC_MODULE_VERSION "2.2.13" -#define CNIC_MODULE_RELDATE "Jan 31, 2011" +#define CNIC_MODULE_VERSION "2.2.14" +#define CNIC_MODULE_RELDATE "Mar 30, 2011" #define CNIC_ULP_RDMA 0 #define CNIC_ULP_ISCSI 1 @@ -85,6 +85,7 @@ struct kcqe { #define CNIC_CTL_STOP_CMD 1 #define CNIC_CTL_START_CMD 2 #define CNIC_CTL_COMPLETION_CMD 3 +#define CNIC_CTL_STOP_ISCSI_CMD 4 #define DRV_CTL_IO_WR_CMD 0x101 #define DRV_CTL_IO_RD_CMD 0x102 @@ -94,6 +95,7 @@ struct kcqe { #define DRV_CTL_START_L2_CMD 0x106 #define DRV_CTL_STOP_L2_CMD 0x107 #define DRV_CTL_RET_L2_SPQ_CREDIT_CMD 0x10c +#define DRV_CTL_ISCSI_STOPPED_CMD 0x10d struct cnic_ctl_completion { u32 cid; diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c index 9d267d3a6892..e66aceb57cef 100644 --- a/drivers/net/cris/eth_v10.c +++ b/drivers/net/cris/eth_v10.c @@ -491,8 +491,8 @@ e100_open(struct net_device *dev) /* allocate the irq corresponding to the receiving DMA */ - if (request_irq(NETWORK_DMA_RX_IRQ_NBR, e100rxtx_interrupt, - IRQF_SAMPLE_RANDOM, cardname, (void *)dev)) { + if (request_irq(NETWORK_DMA_RX_IRQ_NBR, e100rxtx_interrupt, 0, cardname, + (void *)dev)) { goto grace_exit0; } diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h index ef67be59680f..7300de5a1426 100644 --- a/drivers/net/cxgb3/adapter.h +++ b/drivers/net/cxgb3/adapter.h @@ -50,11 +50,6 @@ struct adapter; struct sge_qset; struct port_info; -enum { /* rx_offload flags */ - T3_RX_CSUM = 1 << 0, - T3_LRO = 1 << 1, -}; - enum mac_idx_types { LAN_MAC_IDX = 0, SAN_MAC_IDX, @@ -74,7 +69,6 @@ struct port_info { struct vlan_group *vlan_grp; struct sge_qset *qs; u8 port_id; - u8 rx_offload; u8 nqsets; u8 first_qset; struct cphy phy; @@ -212,7 +206,6 @@ struct sge_qset { /* an SGE queue set */ struct sge_fl fl[SGE_RXQ_PER_SET]; struct sge_txq txq[SGE_TXQ_PER_SET]; int nomem; - int lro_enabled; void *lro_va; struct net_device *netdev; struct netdev_queue *tx_q; /* associated netdev TX queue */ diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h index 5ccb77d078aa..056ee8c831f1 100644 --- a/drivers/net/cxgb3/common.h +++ b/drivers/net/cxgb3/common.h @@ -317,7 +317,6 @@ struct tp_params { struct qset_params { /* SGE queue set parameters */ unsigned int polling; /* polling/interrupt service for rspq */ - unsigned int lro; /* large receive offload */ unsigned int coalesce_usecs; /* irq coalescing timer */ unsigned int rspq_size; /* # of entries in response queue */ unsigned int fl_size; /* # of entries in regular free list */ diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 910893143295..040491804efb 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -644,26 +644,6 @@ static void enable_all_napi(struct adapter *adap) } /** - * set_qset_lro - Turn a queue set's LRO capability on and off - * @dev: the device the qset is attached to - * @qset_idx: the queue set index - * @val: the LRO switch - * - * Sets LRO on or off for a particular queue set. - * the device's features flag is updated to reflect the LRO - * capability when all queues belonging to the device are - * in the same state. - */ -static void set_qset_lro(struct net_device *dev, int qset_idx, int val) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - - adapter->params.sge.qset[qset_idx].lro = !!val; - adapter->sge.qs[qset_idx].lro_enabled = !!val; -} - -/** * setup_sge_qsets - configure SGE Tx/Rx/response queues * @adap: the adapter * @@ -685,7 +665,6 @@ static int setup_sge_qsets(struct adapter *adap) pi->qs = &adap->sge.qs[pi->first_qset]; for (j = 0; j < pi->nqsets; ++j, ++qset_idx) { - set_qset_lro(dev, qset_idx, pi->rx_offload & T3_LRO); err = t3_sge_alloc_qset(adap, qset_idx, 1, (adap->flags & USING_MSIX) ? qset_idx + 1 : irq_idx, @@ -1749,23 +1728,26 @@ static int restart_autoneg(struct net_device *dev) return 0; } -static int cxgb3_phys_id(struct net_device *dev, u32 data) +static int set_phys_id(struct net_device *dev, + enum ethtool_phys_id_state state) { struct port_info *pi = netdev_priv(dev); struct adapter *adapter = pi->adapter; - int i; - if (data == 0) - data = 2; + switch (state) { + case ETHTOOL_ID_ACTIVE: + return 1; /* cycle on/off once per second */ - for (i = 0; i < data * 2; i++) { + case ETHTOOL_ID_OFF: + t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL, 0); + break; + + case ETHTOOL_ID_ON: + case ETHTOOL_ID_INACTIVE: t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL, - (i & 1) ? F_GPIO0_OUT_VAL : 0); - if (msleep_interruptible(500)) - break; - } - t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL, F_GPIO0_OUT_VAL); + } + return 0; } @@ -1907,29 +1889,6 @@ static int set_pauseparam(struct net_device *dev, return 0; } -static u32 get_rx_csum(struct net_device *dev) -{ - struct port_info *p = netdev_priv(dev); - - return p->rx_offload & T3_RX_CSUM; -} - -static int set_rx_csum(struct net_device *dev, u32 data) -{ - struct port_info *p = netdev_priv(dev); - - if (data) { - p->rx_offload |= T3_RX_CSUM; - } else { - int i; - - p->rx_offload &= ~(T3_RX_CSUM | T3_LRO); - for (i = p->first_qset; i < p->first_qset + p->nqsets; i++) - set_qset_lro(dev, i, 0); - } - return 0; -} - static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e) { struct port_info *pi = netdev_priv(dev); @@ -2101,20 +2060,15 @@ static const struct ethtool_ops cxgb_ethtool_ops = { .set_eeprom = set_eeprom, .get_pauseparam = get_pauseparam, .set_pauseparam = set_pauseparam, - .get_rx_csum = get_rx_csum, - .set_rx_csum = set_rx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, - .set_sg = ethtool_op_set_sg, .get_link = ethtool_op_get_link, .get_strings = get_strings, - .phys_id = cxgb3_phys_id, + .set_phys_id = set_phys_id, .nway_reset = restart_autoneg, .get_sset_count = get_sset_count, .get_ethtool_stats = get_stats, .get_regs_len = get_regs_len, .get_regs = get_regs, .get_wol = get_wol, - .set_tso = ethtool_op_set_tso, }; static int in_range(int val, int lo, int hi) @@ -2162,15 +2116,6 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) MAX_RSPQ_ENTRIES)) return -EINVAL; - if ((adapter->flags & FULL_INIT_DONE) && t.lro > 0) - for_each_port(adapter, i) { - pi = adap2pinfo(adapter, i); - if (t.qset_idx >= pi->first_qset && - t.qset_idx < pi->first_qset + pi->nqsets && - !(pi->rx_offload & T3_RX_CSUM)) - return -EINVAL; - } - if ((adapter->flags & FULL_INIT_DONE) && (t.rspq_size >= 0 || t.fl_size[0] >= 0 || t.fl_size[1] >= 0 || t.txq_size[0] >= 0 || @@ -2231,8 +2176,14 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) } } } - if (t.lro >= 0) - set_qset_lro(dev, t.qset_idx, t.lro); + + if (t.lro >= 0) { + if (t.lro) + dev->wanted_features |= NETIF_F_GRO; + else + dev->wanted_features &= ~NETIF_F_GRO; + netdev_update_features(dev); + } break; } @@ -2266,7 +2217,7 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) t.fl_size[0] = q->fl_size; t.fl_size[1] = q->jumbo_size; t.polling = q->polling; - t.lro = q->lro; + t.lro = !!(dev->features & NETIF_F_GRO); t.intr_lat = q->coalesce_usecs; t.cong_thres = q->cong_thres; t.qnum = q1; @@ -3304,18 +3255,18 @@ static int __devinit init_one(struct pci_dev *pdev, adapter->port[i] = netdev; pi = netdev_priv(netdev); pi->adapter = adapter; - pi->rx_offload = T3_RX_CSUM | T3_LRO; pi->port_id = i; netif_carrier_off(netdev); netdev->irq = pdev->irq; netdev->mem_start = mmio_start; netdev->mem_end = mmio_start + mmio_len - 1; - netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO; - netdev->features |= NETIF_F_GRO; + netdev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | + NETIF_F_TSO | NETIF_F_RXCSUM; + netdev->features |= netdev->hw_features | + NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; - netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; netdev->netdev_ops = &cxgb_netdev_ops; SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops); } diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index bfa2d56af1ee..cba1401377ab 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -2019,7 +2019,7 @@ static void rx_eth(struct adapter *adap, struct sge_rspq *rq, skb_pull(skb, sizeof(*p) + pad); skb->protocol = eth_type_trans(skb, adap->port[p->iff]); pi = netdev_priv(skb->dev); - if ((pi->rx_offload & T3_RX_CSUM) && p->csum_valid && + if ((skb->dev->features & NETIF_F_RXCSUM) && p->csum_valid && p->csum == htons(0xffff) && !p->fragment) { qs->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++; skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -2120,7 +2120,7 @@ static void lro_add_page(struct adapter *adap, struct sge_qset *qs, offset = 2 + sizeof(struct cpl_rx_pkt); cpl = qs->lro_va = sd->pg_chunk.va + 2; - if ((pi->rx_offload & T3_RX_CSUM) && + if ((qs->netdev->features & NETIF_F_RXCSUM) && cpl->csum_valid && cpl->csum == htons(0xffff)) { skb->ip_summed = CHECKSUM_UNNECESSARY; qs->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++; @@ -2285,7 +2285,8 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs, q->next_holdoff = q->holdoff_tmr; while (likely(budget_left && is_new_response(r, q))) { - int packet_complete, eth, ethpad = 2, lro = qs->lro_enabled; + int packet_complete, eth, ethpad = 2; + int lro = !!(qs->netdev->features & NETIF_F_GRO); struct sk_buff *skb = NULL; u32 len, flags; __be32 rss_hi, rss_lo; diff --git a/drivers/net/cxgb4/cxgb4.h b/drivers/net/cxgb4/cxgb4.h index 01d49eaa44d2..bc9982a4c1f4 100644 --- a/drivers/net/cxgb4/cxgb4.h +++ b/drivers/net/cxgb4/cxgb4.h @@ -290,7 +290,6 @@ struct port_info { u8 port_id; u8 tx_chan; u8 lport; /* associated offload logical port */ - u8 rx_offload; /* CSO, etc */ u8 nqsets; /* # of qsets */ u8 first_qset; /* index of first qset */ u8 rss_mode; @@ -298,11 +297,6 @@ struct port_info { u16 *rss; }; -/* port_info.rx_offload flags */ -enum { - RX_CSO = 1 << 0, -}; - struct dentry; struct work_struct; diff --git a/drivers/net/cxgb4/cxgb4_main.c b/drivers/net/cxgb4/cxgb4_main.c index 5352c8a23f4d..bdc868ca47ec 100644 --- a/drivers/net/cxgb4/cxgb4_main.c +++ b/drivers/net/cxgb4/cxgb4_main.c @@ -1336,15 +1336,20 @@ static int restart_autoneg(struct net_device *dev) return 0; } -static int identify_port(struct net_device *dev, u32 data) +static int identify_port(struct net_device *dev, + enum ethtool_phys_id_state state) { + unsigned int val; struct adapter *adap = netdev2adap(dev); - if (data == 0) - data = 2; /* default to 2 seconds */ + if (state == ETHTOOL_ID_ACTIVE) + val = 0xffff; + else if (state == ETHTOOL_ID_INACTIVE) + val = 0; + else + return -EINVAL; - return t4_identify_port(adap, adap->fn, netdev2pinfo(dev)->viid, - data * 5); + return t4_identify_port(adap, adap->fn, netdev2pinfo(dev)->viid, val); } static unsigned int from_fw_linkcaps(unsigned int type, unsigned int caps) @@ -1526,24 +1531,6 @@ static int set_pauseparam(struct net_device *dev, return 0; } -static u32 get_rx_csum(struct net_device *dev) -{ - struct port_info *p = netdev_priv(dev); - - return p->rx_offload & RX_CSO; -} - -static int set_rx_csum(struct net_device *dev, u32 data) -{ - struct port_info *p = netdev_priv(dev); - - if (data) - p->rx_offload |= RX_CSO; - else - p->rx_offload &= ~RX_CSO; - return 0; -} - static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e) { const struct port_info *pi = netdev_priv(dev); @@ -1865,36 +1852,20 @@ static int set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) return err; } -#define TSO_FLAGS (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN) - -static int set_tso(struct net_device *dev, u32 value) -{ - if (value) - dev->features |= TSO_FLAGS; - else - dev->features &= ~TSO_FLAGS; - return 0; -} - -static int set_flags(struct net_device *dev, u32 flags) +static int cxgb_set_features(struct net_device *dev, u32 features) { + const struct port_info *pi = netdev_priv(dev); + u32 changed = dev->features ^ features; int err; - unsigned long old_feat = dev->features; - err = ethtool_op_set_flags(dev, flags, ETH_FLAG_RXHASH | - ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN); - if (err) - return err; - - if ((old_feat ^ dev->features) & NETIF_F_HW_VLAN_RX) { - const struct port_info *pi = netdev_priv(dev); + if (!(changed & NETIF_F_HW_VLAN_RX)) + return 0; - err = t4_set_rxmode(pi->adapter, pi->adapter->fn, pi->viid, -1, - -1, -1, -1, !!(flags & ETH_FLAG_RXVLAN), - true); - if (err) - dev->features = old_feat; - } + err = t4_set_rxmode(pi->adapter, pi->adapter->fn, pi->viid, -1, + -1, -1, -1, + !!(features & NETIF_F_HW_VLAN_RX), true); + if (unlikely(err)) + dev->features = features ^ NETIF_F_HW_VLAN_RX; return err; } @@ -2005,13 +1976,9 @@ static struct ethtool_ops cxgb_ethtool_ops = { .set_eeprom = set_eeprom, .get_pauseparam = get_pauseparam, .set_pauseparam = set_pauseparam, - .get_rx_csum = get_rx_csum, - .set_rx_csum = set_rx_csum, - .set_tx_csum = ethtool_op_set_tx_ipv6_csum, - .set_sg = ethtool_op_set_sg, .get_link = ethtool_op_get_link, .get_strings = get_strings, - .phys_id = identify_port, + .set_phys_id = identify_port, .nway_reset = restart_autoneg, .get_sset_count = get_sset_count, .get_ethtool_stats = get_stats, @@ -2019,8 +1986,6 @@ static struct ethtool_ops cxgb_ethtool_ops = { .get_regs = get_regs, .get_wol = get_wol, .set_wol = set_wol, - .set_tso = set_tso, - .set_flags = set_flags, .get_rxnfc = get_rxnfc, .get_rxfh_indir = get_rss_table, .set_rxfh_indir = set_rss_table, @@ -2877,6 +2842,7 @@ static const struct net_device_ops cxgb4_netdev_ops = { .ndo_get_stats64 = cxgb_get_stats, .ndo_set_rx_mode = cxgb_set_rxmode, .ndo_set_mac_address = cxgb_set_mac_addr, + .ndo_set_features = cxgb_set_features, .ndo_validate_addr = eth_validate_addr, .ndo_do_ioctl = cxgb_ioctl, .ndo_change_mtu = cxgb_change_mtu, @@ -3559,6 +3525,7 @@ static void free_some_resources(struct adapter *adapter) t4_fw_bye(adapter, adapter->fn); } +#define TSO_FLAGS (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN) #define VLAN_FEAT (NETIF_F_SG | NETIF_F_IP_CSUM | TSO_FLAGS | \ NETIF_F_IPV6_CSUM | NETIF_F_HIGHDMA) @@ -3660,14 +3627,14 @@ static int __devinit init_one(struct pci_dev *pdev, pi = netdev_priv(netdev); pi->adapter = adapter; pi->xact_addr_filt = -1; - pi->rx_offload = RX_CSO; pi->port_id = i; netdev->irq = pdev->irq; - netdev->features |= NETIF_F_SG | TSO_FLAGS; - netdev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; - netdev->features |= NETIF_F_GRO | NETIF_F_RXHASH | highdma; - netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + netdev->hw_features = NETIF_F_SG | TSO_FLAGS | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_RXCSUM | NETIF_F_RXHASH | + NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + netdev->features |= netdev->hw_features | highdma; netdev->vlan_features = netdev->features & VLAN_FEAT; netdev->netdev_ops = &cxgb4_netdev_ops; diff --git a/drivers/net/cxgb4/sge.c b/drivers/net/cxgb4/sge.c index 311471b439a8..75a4b0fa19ee 100644 --- a/drivers/net/cxgb4/sge.c +++ b/drivers/net/cxgb4/sge.c @@ -1556,7 +1556,6 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp, { bool csum_ok; struct sk_buff *skb; - struct port_info *pi; const struct cpl_rx_pkt *pkt; struct sge_eth_rxq *rxq = container_of(q, struct sge_eth_rxq, rspq); @@ -1584,10 +1583,9 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp, if (skb->dev->features & NETIF_F_RXHASH) skb->rxhash = (__force u32)pkt->rsshdr.hash_val; - pi = netdev_priv(skb->dev); rxq->stats.pkts++; - if (csum_ok && (pi->rx_offload & RX_CSO) && + if (csum_ok && (q->netdev->features & NETIF_F_RXCSUM) && (pkt->l2info & htonl(RXF_UDP | RXF_TCP))) { if (!pkt->ip_frag) { skb->ip_summed = CHECKSUM_UNNECESSARY; diff --git a/drivers/net/cxgb4vf/adapter.h b/drivers/net/cxgb4vf/adapter.h index 4766b4116b41..4fd821aadc8a 100644 --- a/drivers/net/cxgb4vf/adapter.h +++ b/drivers/net/cxgb4vf/adapter.h @@ -97,17 +97,11 @@ struct port_info { u16 rss_size; /* size of VI's RSS table slice */ u8 pidx; /* index into adapter port[] */ u8 port_id; /* physical port ID */ - u8 rx_offload; /* CSO, etc. */ u8 nqsets; /* # of "Queue Sets" */ u8 first_qset; /* index of first "Queue Set" */ struct link_config link_cfg; /* physical port configuration */ }; -/* port_info.rx_offload flags */ -enum { - RX_CSO = 1 << 0, -}; - /* * Scatter Gather Engine resources for the "adapter". Our ingress and egress * queues are organized into "Queue Sets" with one ingress and one egress diff --git a/drivers/net/cxgb4vf/cxgb4vf_main.c b/drivers/net/cxgb4vf/cxgb4vf_main.c index 4661cbbd9bd9..8cf9890cafaf 100644 --- a/drivers/net/cxgb4vf/cxgb4vf_main.c +++ b/drivers/net/cxgb4vf/cxgb4vf_main.c @@ -1326,37 +1326,22 @@ static void cxgb4vf_get_pauseparam(struct net_device *dev, } /* - * Return whether RX Checksum Offloading is currently enabled for the device. - */ -static u32 cxgb4vf_get_rx_csum(struct net_device *dev) -{ - struct port_info *pi = netdev_priv(dev); - - return (pi->rx_offload & RX_CSO) != 0; -} - -/* - * Turn RX Checksum Offloading on or off for the device. + * Identify the port by blinking the port's LED. */ -static int cxgb4vf_set_rx_csum(struct net_device *dev, u32 csum) +static int cxgb4vf_phys_id(struct net_device *dev, + enum ethtool_phys_id_state state) { + unsigned int val; struct port_info *pi = netdev_priv(dev); - if (csum) - pi->rx_offload |= RX_CSO; + if (state == ETHTOOL_ID_ACTIVE) + val = 0xffff; + else if (state == ETHTOOL_ID_INACTIVE) + val = 0; else - pi->rx_offload &= ~RX_CSO; - return 0; -} - -/* - * Identify the port by blinking the port's LED. - */ -static int cxgb4vf_phys_id(struct net_device *dev, u32 id) -{ - struct port_info *pi = netdev_priv(dev); + return -EINVAL; - return t4vf_identify_port(pi->adapter, pi->viid, 5); + return t4vf_identify_port(pi->adapter, pi->viid, val); } /* @@ -1560,18 +1545,6 @@ static void cxgb4vf_get_wol(struct net_device *dev, */ #define TSO_FLAGS (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN) -/* - * Set TCP Segmentation Offloading feature capabilities. - */ -static int cxgb4vf_set_tso(struct net_device *dev, u32 tso) -{ - if (tso) - dev->features |= TSO_FLAGS; - else - dev->features &= ~TSO_FLAGS; - return 0; -} - static struct ethtool_ops cxgb4vf_ethtool_ops = { .get_settings = cxgb4vf_get_settings, .get_drvinfo = cxgb4vf_get_drvinfo, @@ -1582,19 +1555,14 @@ static struct ethtool_ops cxgb4vf_ethtool_ops = { .get_coalesce = cxgb4vf_get_coalesce, .set_coalesce = cxgb4vf_set_coalesce, .get_pauseparam = cxgb4vf_get_pauseparam, - .get_rx_csum = cxgb4vf_get_rx_csum, - .set_rx_csum = cxgb4vf_set_rx_csum, - .set_tx_csum = ethtool_op_set_tx_ipv6_csum, - .set_sg = ethtool_op_set_sg, .get_link = ethtool_op_get_link, .get_strings = cxgb4vf_get_strings, - .phys_id = cxgb4vf_phys_id, + .set_phys_id = cxgb4vf_phys_id, .get_sset_count = cxgb4vf_get_sset_count, .get_ethtool_stats = cxgb4vf_get_ethtool_stats, .get_regs_len = cxgb4vf_get_regs_len, .get_regs = cxgb4vf_get_regs, .get_wol = cxgb4vf_get_wol, - .set_tso = cxgb4vf_set_tso, }; /* @@ -2629,19 +2597,19 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev, * it. */ pi->xact_addr_filt = -1; - pi->rx_offload = RX_CSO; netif_carrier_off(netdev); netdev->irq = pdev->irq; - netdev->features = (NETIF_F_SG | TSO_FLAGS | - NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | - NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | - NETIF_F_GRO); + netdev->hw_features = NETIF_F_SG | TSO_FLAGS | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_HW_VLAN_TX | NETIF_F_RXCSUM; + netdev->vlan_features = NETIF_F_SG | TSO_FLAGS | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_HIGHDMA; + netdev->features = netdev->hw_features | + NETIF_F_HW_VLAN_RX; if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; - netdev->vlan_features = - (netdev->features & - ~(NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX)); #ifdef HAVE_NET_DEVICE_OPS netdev->netdev_ops = &cxgb4vf_netdev_ops; diff --git a/drivers/net/cxgb4vf/sge.c b/drivers/net/cxgb4vf/sge.c index bb65121f581c..5182960e29fd 100644 --- a/drivers/net/cxgb4vf/sge.c +++ b/drivers/net/cxgb4vf/sge.c @@ -1555,8 +1555,8 @@ int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp, pi = netdev_priv(skb->dev); rxq->stats.pkts++; - if (csum_ok && (pi->rx_offload & RX_CSO) && !pkt->err_vec && - (be32_to_cpu(pkt->l2info) & (RXF_UDP|RXF_TCP))) { + if (csum_ok && (rspq->netdev->features & NETIF_F_RXCSUM) && + !pkt->err_vec && (be32_to_cpu(pkt->l2info) & (RXF_UDP|RXF_TCP))) { if (!pkt->ip_frag) skb->ip_summed = CHECKSUM_UNNECESSARY; else { diff --git a/drivers/net/depca.c b/drivers/net/depca.c index 8b0084d17c8c..17654059922d 100644 --- a/drivers/net/depca.c +++ b/drivers/net/depca.c @@ -331,18 +331,18 @@ static struct { "DE422",\ ""} -static char* __initdata depca_signature[] = DEPCA_SIGNATURE; +static const char* const depca_signature[] __devinitconst = DEPCA_SIGNATURE; enum depca_type { DEPCA, de100, de101, de200, de201, de202, de210, de212, de422, unknown }; -static char depca_string[] = "depca"; +static const char depca_string[] = "depca"; static int depca_device_remove (struct device *device); #ifdef CONFIG_EISA -static struct eisa_device_id depca_eisa_ids[] = { +static const struct eisa_device_id depca_eisa_ids[] __devinitconst = { { "DEC4220", de422 }, { "" } }; @@ -367,19 +367,19 @@ static struct eisa_driver depca_eisa_driver = { #define DE210_ID 0x628d #define DE212_ID 0x6def -static short depca_mca_adapter_ids[] = { +static const short depca_mca_adapter_ids[] __devinitconst = { DE210_ID, DE212_ID, 0x0000 }; -static char *depca_mca_adapter_name[] = { +static const char *depca_mca_adapter_name[] = { "DEC EtherWORKS MC Adapter (DE210)", "DEC EtherWORKS MC Adapter (DE212)", NULL }; -static enum depca_type depca_mca_adapter_type[] = { +static const enum depca_type depca_mca_adapter_type[] = { de210, de212, 0 @@ -541,10 +541,9 @@ static void SetMulticastFilter(struct net_device *dev); static int load_packet(struct net_device *dev, struct sk_buff *skb); static void depca_dbg_open(struct net_device *dev); -static u_char de1xx_irq[] __initdata = { 2, 3, 4, 5, 7, 9, 0 }; -static u_char de2xx_irq[] __initdata = { 5, 9, 10, 11, 15, 0 }; -static u_char de422_irq[] __initdata = { 5, 9, 10, 11, 0 }; -static u_char *depca_irq; +static const u_char de1xx_irq[] __devinitconst = { 2, 3, 4, 5, 7, 9, 0 }; +static const u_char de2xx_irq[] __devinitconst = { 5, 9, 10, 11, 15, 0 }; +static const u_char de422_irq[] __devinitconst = { 5, 9, 10, 11, 0 }; static int irq; static int io; @@ -580,7 +579,7 @@ static const struct net_device_ops depca_netdev_ops = { .ndo_validate_addr = eth_validate_addr, }; -static int __init depca_hw_init (struct net_device *dev, struct device *device) +static int __devinit depca_hw_init (struct net_device *dev, struct device *device) { struct depca_private *lp; int i, j, offset, netRAM, mem_len, status = 0; @@ -748,6 +747,7 @@ static int __init depca_hw_init (struct net_device *dev, struct device *device) if (dev->irq < 2) { unsigned char irqnum; unsigned long irq_mask, delay; + const u_char *depca_irq; irq_mask = probe_irq_on(); @@ -770,6 +770,7 @@ static int __init depca_hw_init (struct net_device *dev, struct device *device) break; default: + depca_irq = NULL; break; /* Not reached */ } @@ -1302,7 +1303,7 @@ static void SetMulticastFilter(struct net_device *dev) } } -static int __init depca_common_init (u_long ioaddr, struct net_device **devp) +static int __devinit depca_common_init (u_long ioaddr, struct net_device **devp) { int status = 0; @@ -1333,7 +1334,7 @@ static int __init depca_common_init (u_long ioaddr, struct net_device **devp) /* ** Microchannel bus I/O device probe */ -static int __init depca_mca_probe(struct device *device) +static int __devinit depca_mca_probe(struct device *device) { unsigned char pos[2]; unsigned char where; @@ -1457,7 +1458,7 @@ static int __init depca_mca_probe(struct device *device) ** ISA bus I/O device probe */ -static void __init depca_platform_probe (void) +static void __devinit depca_platform_probe (void) { int i; struct platform_device *pldev; @@ -1497,7 +1498,7 @@ static void __init depca_platform_probe (void) } } -static enum depca_type __init depca_shmem_probe (ulong *mem_start) +static enum depca_type __devinit depca_shmem_probe (ulong *mem_start) { u_long mem_base[] = DEPCA_RAM_BASE_ADDRESSES; enum depca_type adapter = unknown; @@ -1558,7 +1559,7 @@ static int __devinit depca_isa_probe (struct platform_device *device) */ #ifdef CONFIG_EISA -static int __init depca_eisa_probe (struct device *device) +static int __devinit depca_eisa_probe (struct device *device) { enum depca_type adapter = unknown; struct eisa_device *edev; @@ -1629,7 +1630,7 @@ static int __devexit depca_device_remove (struct device *device) ** and Boot (readb) ROM. This will also give us a clue to the network RAM ** base address. */ -static int __init DepcaSignature(char *name, u_long base_addr) +static int __devinit DepcaSignature(char *name, u_long base_addr) { u_int i, j, k; void __iomem *ptr; diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index b7af5bab9937..fbaff3584bd4 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -131,8 +131,6 @@ typedef struct board_info { u32 msg_enable; u32 wake_state; - int rx_csum; - int can_csum; int ip_summed; } board_info_t; @@ -470,47 +468,20 @@ static int dm9000_nway_reset(struct net_device *dev) return mii_nway_restart(&dm->mii); } -static uint32_t dm9000_get_rx_csum(struct net_device *dev) +static int dm9000_set_features(struct net_device *dev, u32 features) { board_info_t *dm = to_dm9000_board(dev); - return dm->rx_csum; -} - -static int dm9000_set_rx_csum_unlocked(struct net_device *dev, uint32_t data) -{ - board_info_t *dm = to_dm9000_board(dev); - - if (dm->can_csum) { - dm->rx_csum = data; - iow(dm, DM9000_RCSR, dm->rx_csum ? RCSR_CSUM : 0); + u32 changed = dev->features ^ features; + unsigned long flags; + if (!(changed & NETIF_F_RXCSUM)) return 0; - } - - return -EOPNOTSUPP; -} - -static int dm9000_set_rx_csum(struct net_device *dev, uint32_t data) -{ - board_info_t *dm = to_dm9000_board(dev); - unsigned long flags; - int ret; spin_lock_irqsave(&dm->lock, flags); - ret = dm9000_set_rx_csum_unlocked(dev, data); + iow(dm, DM9000_RCSR, (features & NETIF_F_RXCSUM) ? RCSR_CSUM : 0); spin_unlock_irqrestore(&dm->lock, flags); - return ret; -} - -static int dm9000_set_tx_csum(struct net_device *dev, uint32_t data) -{ - board_info_t *dm = to_dm9000_board(dev); - int ret = -EOPNOTSUPP; - - if (dm->can_csum) - ret = ethtool_op_set_tx_csum(dev, data); - return ret; + return 0; } static u32 dm9000_get_link(struct net_device *dev) @@ -643,10 +614,6 @@ static const struct ethtool_ops dm9000_ethtool_ops = { .get_eeprom_len = dm9000_get_eeprom_len, .get_eeprom = dm9000_get_eeprom, .set_eeprom = dm9000_set_eeprom, - .get_rx_csum = dm9000_get_rx_csum, - .set_rx_csum = dm9000_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = dm9000_set_tx_csum, }; static void dm9000_show_carrier(board_info_t *db, @@ -800,7 +767,9 @@ dm9000_init_dm9000(struct net_device *dev) db->io_mode = ior(db, DM9000_ISR) >> 6; /* ISR bit7:6 keeps I/O mode */ /* Checksum mode */ - dm9000_set_rx_csum_unlocked(dev, db->rx_csum); + if (dev->hw_features & NETIF_F_RXCSUM) + iow(db, DM9000_RCSR, + (dev->features & NETIF_F_RXCSUM) ? RCSR_CSUM : 0); iow(db, DM9000_GPCR, GPCR_GEP_CNTL); /* Let GPIO0 output */ @@ -1049,7 +1018,7 @@ dm9000_rx(struct net_device *dev) /* Pass to upper layer */ skb->protocol = eth_type_trans(skb, dev); - if (db->rx_csum) { + if (dev->features & NETIF_F_RXCSUM) { if ((((rxbyte & 0x1c) << 3) & rxbyte) == 0) skb->ip_summed = CHECKSUM_UNNECESSARY; else @@ -1358,6 +1327,7 @@ static const struct net_device_ops dm9000_netdev_ops = { .ndo_set_multicast_list = dm9000_hash_table, .ndo_do_ioctl = dm9000_ioctl, .ndo_change_mtu = eth_change_mtu, + .ndo_set_features = dm9000_set_features, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = eth_mac_addr, #ifdef CONFIG_NET_POLL_CONTROLLER @@ -1551,9 +1521,8 @@ dm9000_probe(struct platform_device *pdev) /* dm9000a/b are capable of hardware checksum offload */ if (db->type == TYPE_DM9000A || db->type == TYPE_DM9000B) { - db->can_csum = 1; - db->rx_csum = 1; - ndev->features |= NETIF_F_IP_CSUM; + ndev->hw_features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM; + ndev->features |= ndev->hw_features; } /* from this point we assume that we have found a DM9000 */ diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c index 89a69035e538..ae07d37903ba 100644 --- a/drivers/net/e1000e/82571.c +++ b/drivers/net/e1000e/82571.c @@ -431,9 +431,6 @@ static s32 e1000_get_variants_82571(struct e1000_adapter *adapter) case e1000_82573: case e1000_82574: case e1000_82583: - /* Disable ASPM L0s due to hardware errata */ - e1000e_disable_aspm(adapter->pdev, PCIE_LINK_STATE_L0S); - if (pdev->device == E1000_DEV_ID_82573L) { adapter->flags |= FLAG_HAS_JUMBO_FRAMES; adapter->max_hw_frame_size = DEFAULT_JUMBO; @@ -594,7 +591,7 @@ static s32 e1000_get_hw_semaphore_82573(struct e1000_hw *hw) extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP; - msleep(2); + usleep_range(2000, 4000); i++; } while (i < MDIO_OWNERSHIP_TIMEOUT); @@ -816,7 +813,7 @@ static s32 e1000_update_nvm_checksum_82571(struct e1000_hw *hw) /* Check for pending operations. */ for (i = 0; i < E1000_FLASH_UPDATES; i++) { - msleep(1); + usleep_range(1000, 2000); if ((er32(EECD) & E1000_EECD_FLUPD) == 0) break; } @@ -840,7 +837,7 @@ static s32 e1000_update_nvm_checksum_82571(struct e1000_hw *hw) ew32(EECD, eecd); for (i = 0; i < E1000_FLASH_UPDATES; i++) { - msleep(1); + usleep_range(1000, 2000); if ((er32(EECD) & E1000_EECD_FLUPD) == 0) break; } @@ -930,7 +927,7 @@ static s32 e1000_get_cfg_done_82571(struct e1000_hw *hw) if (er32(EEMNGCTL) & E1000_NVM_CFG_DONE_PORT_0) break; - msleep(1); + usleep_range(1000, 2000); timeout--; } if (!timeout) { @@ -1037,7 +1034,7 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw) ew32(TCTL, E1000_TCTL_PSP); e1e_flush(); - msleep(10); + usleep_range(10000, 20000); /* * Must acquire the MDIO ownership before MAC reset. @@ -2066,7 +2063,8 @@ struct e1000_info e1000_82573_info = { | FLAG_HAS_SMART_POWER_DOWN | FLAG_HAS_AMT | FLAG_HAS_SWSM_ON_LOAD, - .flags2 = FLAG2_DISABLE_ASPM_L1, + .flags2 = FLAG2_DISABLE_ASPM_L1 + | FLAG2_DISABLE_ASPM_L0S, .pba = 20, .max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN, .get_variants = e1000_get_variants_82571, @@ -2086,7 +2084,8 @@ struct e1000_info e1000_82574_info = { | FLAG_HAS_SMART_POWER_DOWN | FLAG_HAS_AMT | FLAG_HAS_CTRLEXT_ON_LOAD, - .flags2 = FLAG2_CHECK_PHY_HANG, + .flags2 = FLAG2_CHECK_PHY_HANG + | FLAG2_DISABLE_ASPM_L0S, .pba = 32, .max_hw_frame_size = DEFAULT_JUMBO, .get_variants = e1000_get_variants_82571, @@ -2104,6 +2103,7 @@ struct e1000_info e1000_82583_info = { | FLAG_HAS_SMART_POWER_DOWN | FLAG_HAS_AMT | FLAG_HAS_CTRLEXT_ON_LOAD, + .flags2 = FLAG2_DISABLE_ASPM_L0S, .pba = 32, .max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN, .get_variants = e1000_get_variants_82571, diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h index 00bf595ebd67..3be5478dfdf1 100644 --- a/drivers/net/e1000e/e1000.h +++ b/drivers/net/e1000e/e1000.h @@ -31,6 +31,7 @@ #ifndef _E1000_H_ #define _E1000_H_ +#include <linux/bitops.h> #include <linux/types.h> #include <linux/timer.h> #include <linux/workqueue.h> @@ -39,6 +40,7 @@ #include <linux/pci.h> #include <linux/pci-aspm.h> #include <linux/crc32.h> +#include <linux/if_vlan.h> #include "hw.h" @@ -280,7 +282,7 @@ struct e1000_adapter { const struct e1000_info *ei; - struct vlan_group *vlgrp; + unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; u32 bd_number; u32 rx_buffer_len; u16 mng_vlan_id; @@ -456,6 +458,7 @@ struct e1000_info { #define FLAG2_HAS_PHY_STATS (1 << 4) #define FLAG2_HAS_EEE (1 << 5) #define FLAG2_DMA_BURST (1 << 6) +#define FLAG2_DISABLE_ASPM_L0S (1 << 7) #define FLAG2_DISABLE_AIM (1 << 8) #define FLAG2_CHECK_PHY_HANG (1 << 9) @@ -502,7 +505,6 @@ extern void e1000e_set_interrupt_capability(struct e1000_adapter *adapter); extern void e1000e_reset_interrupt_capability(struct e1000_adapter *adapter); extern void e1000e_get_hw_control(struct e1000_adapter *adapter); extern void e1000e_release_hw_control(struct e1000_adapter *adapter); -extern void e1000e_disable_aspm(struct pci_dev *pdev, u16 state); extern unsigned int copybreak; diff --git a/drivers/net/e1000e/es2lan.c b/drivers/net/e1000e/es2lan.c index 2fefa820302b..0279695b6942 100644 --- a/drivers/net/e1000e/es2lan.c +++ b/drivers/net/e1000e/es2lan.c @@ -612,7 +612,7 @@ static s32 e1000_get_cfg_done_80003es2lan(struct e1000_hw *hw) while (timeout) { if (er32(EEMNGCTL) & mask) break; - msleep(1); + usleep_range(1000, 2000); timeout--; } if (!timeout) { @@ -802,7 +802,7 @@ static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw) ew32(TCTL, E1000_TCTL_PSP); e1e_flush(); - msleep(10); + usleep_range(10000, 20000); ctrl = er32(CTRL); diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index 07f09e96e453..a31d280ffb6d 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c @@ -253,7 +253,7 @@ static int e1000_set_settings(struct net_device *netdev, } while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) - msleep(1); + usleep_range(1000, 2000); if (ecmd->autoneg == AUTONEG_ENABLE) { hw->mac.autoneg = 1; @@ -317,7 +317,7 @@ static int e1000_set_pauseparam(struct net_device *netdev, adapter->fc_autoneg = pause->autoneg; while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) - msleep(1); + usleep_range(1000, 2000); if (adapter->fc_autoneg == AUTONEG_ENABLE) { hw->fc.requested_mode = e1000_fc_default; @@ -673,7 +673,7 @@ static int e1000_set_ringparam(struct net_device *netdev, return -EINVAL; while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) - msleep(1); + usleep_range(1000, 2000); if (netif_running(adapter->netdev)) e1000e_down(adapter); @@ -952,7 +952,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) /* Disable all the interrupts */ ew32(IMC, 0xFFFFFFFF); - msleep(10); + usleep_range(10000, 20000); /* Test each interrupt */ for (i = 0; i < 10; i++) { @@ -984,7 +984,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) adapter->test_icr = 0; ew32(IMC, mask); ew32(ICS, mask); - msleep(10); + usleep_range(10000, 20000); if (adapter->test_icr & mask) { *data = 3; @@ -1002,7 +1002,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) adapter->test_icr = 0; ew32(IMS, mask); ew32(ICS, mask); - msleep(10); + usleep_range(10000, 20000); if (!(adapter->test_icr & mask)) { *data = 4; @@ -1020,7 +1020,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) adapter->test_icr = 0; ew32(IMC, ~mask & 0x00007FFF); ew32(ICS, ~mask & 0x00007FFF); - msleep(10); + usleep_range(10000, 20000); if (adapter->test_icr) { *data = 5; @@ -1031,7 +1031,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) /* Disable all the interrupts */ ew32(IMC, 0xFFFFFFFF); - msleep(10); + usleep_range(10000, 20000); /* Unhook test interrupt handler */ free_irq(irq, netdev); @@ -1406,7 +1406,7 @@ static int e1000_set_82571_fiber_loopback(struct e1000_adapter *adapter) */ #define E1000_SERDES_LB_ON 0x410 ew32(SCTL, E1000_SERDES_LB_ON); - msleep(10); + usleep_range(10000, 20000); return 0; } @@ -1501,7 +1501,7 @@ static void e1000_loopback_cleanup(struct e1000_adapter *adapter) hw->phy.media_type == e1000_media_type_internal_serdes) { #define E1000_SERDES_LB_OFF 0x400 ew32(SCTL, E1000_SERDES_LB_OFF); - msleep(10); + usleep_range(10000, 20000); break; } /* Fall Through */ @@ -2020,6 +2020,31 @@ static void e1000_get_strings(struct net_device *netdev, u32 stringset, } } +static int e1000e_set_flags(struct net_device *netdev, u32 data) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + bool need_reset = false; + int rc; + + need_reset = (data & ETH_FLAG_RXVLAN) != + (netdev->features & NETIF_F_HW_VLAN_RX); + + rc = ethtool_op_set_flags(netdev, data, ETH_FLAG_RXVLAN | + ETH_FLAG_TXVLAN); + + if (rc) + return rc; + + if (need_reset) { + if (netif_running(netdev)) + e1000e_reinit_locked(adapter); + else + e1000e_reset(adapter); + } + + return 0; +} + static const struct ethtool_ops e1000_ethtool_ops = { .get_settings = e1000_get_settings, .set_settings = e1000_set_settings, @@ -2055,6 +2080,7 @@ static const struct ethtool_ops e1000_ethtool_ops = { .get_coalesce = e1000_get_coalesce, .set_coalesce = e1000_set_coalesce, .get_flags = ethtool_op_get_flags, + .set_flags = e1000e_set_flags, }; void e1000e_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c index ce1dbfdca112..06ff884bc2c7 100644 --- a/drivers/net/e1000e/ich8lan.c +++ b/drivers/net/e1000e/ich8lan.c @@ -338,7 +338,7 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw) /* Ungate automatic PHY configuration on non-managed 82579 */ if ((hw->mac.type == e1000_pch2lan) && !(fwsm & E1000_ICH_FWSM_FW_VALID)) { - msleep(10); + usleep_range(10000, 20000); e1000_gate_hw_phy_config_ich8lan(hw, false); } @@ -427,7 +427,7 @@ static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw) phy->id = 0; while ((e1000_phy_unknown == e1000e_get_phy_type_from_id(phy->id)) && (i++ < 100)) { - msleep(1); + usleep_range(1000, 2000); ret_val = e1000e_get_phy_id(hw); if (ret_val) return ret_val; @@ -1704,7 +1704,7 @@ static s32 e1000_post_phy_reset_ich8lan(struct e1000_hw *hw) goto out; /* Allow time for h/w to get to quiescent state after reset */ - msleep(10); + usleep_range(10000, 20000); /* Perform any necessary post-reset workarounds */ switch (hw->mac.type) { @@ -1737,7 +1737,7 @@ static s32 e1000_post_phy_reset_ich8lan(struct e1000_hw *hw) if (hw->mac.type == e1000_pch2lan) { /* Ungate automatic PHY configuration on non-managed 82579 */ if (!(er32(FWSM) & E1000_ICH_FWSM_FW_VALID)) { - msleep(10); + usleep_range(10000, 20000); e1000_gate_hw_phy_config_ich8lan(hw, false); } @@ -2532,7 +2532,7 @@ release: */ if (!ret_val) { e1000e_reload_nvm(hw); - msleep(10); + usleep_range(10000, 20000); } out: @@ -3009,7 +3009,7 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) ew32(TCTL, E1000_TCTL_PSP); e1e_flush(); - msleep(10); + usleep_range(10000, 20000); /* Workaround for ICH8 bit corruption issue in FIFO memory */ if (hw->mac.type == e1000_ich8lan) { diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c index 96921de5df2e..30ef8fa4968c 100644 --- a/drivers/net/e1000e/lib.c +++ b/drivers/net/e1000e/lib.c @@ -868,7 +868,7 @@ static s32 e1000_poll_fiber_serdes_link_generic(struct e1000_hw *hw) * milliseconds even if the other end is doing it in SW). */ for (i = 0; i < FIBER_LINK_UP_LIMIT; i++) { - msleep(10); + usleep_range(10000, 20000); status = er32(STATUS); if (status & E1000_STATUS_LU) break; @@ -930,7 +930,7 @@ s32 e1000e_setup_fiber_serdes_link(struct e1000_hw *hw) ew32(CTRL, ctrl); e1e_flush(); - msleep(1); + usleep_range(1000, 2000); /* * For these adapters, the SW definable pin 1 is set when the optics @@ -1385,7 +1385,7 @@ s32 e1000e_get_auto_rd_done(struct e1000_hw *hw) while (i < AUTO_READ_DONE_TIMEOUT) { if (er32(EECD) & E1000_EECD_AUTO_RD) break; - msleep(1); + usleep_range(1000, 2000); i++; } @@ -2087,8 +2087,6 @@ s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) if (ret_val) return ret_val; - msleep(10); - while (widx < words) { u8 write_opcode = NVM_WRITE_OPCODE_SPI; @@ -2132,7 +2130,7 @@ s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) } } - msleep(10); + usleep_range(10000, 20000); nvm->ops.release(hw); return 0; } diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 506a0a0043b3..4deb67d98e36 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -58,6 +58,8 @@ char e1000e_driver_name[] = "e1000e"; const char e1000e_driver_version[] = DRV_VERSION; +static void e1000e_disable_aspm(struct pci_dev *pdev, u16 state); + static const struct e1000_info *e1000_info_tbl[] = { [board_82571] = &e1000_82571_info, [board_82572] = &e1000_82572_info, @@ -459,13 +461,13 @@ static void e1000_receive_skb(struct e1000_adapter *adapter, struct net_device *netdev, struct sk_buff *skb, u8 status, __le16 vlan) { + u16 tag = le16_to_cpu(vlan); skb->protocol = eth_type_trans(skb, netdev); - if (adapter->vlgrp && (status & E1000_RXD_STAT_VP)) - vlan_gro_receive(&adapter->napi, adapter->vlgrp, - le16_to_cpu(vlan), skb); - else - napi_gro_receive(&adapter->napi, skb); + if (status & E1000_RXD_STAT_VP) + __vlan_hwaccel_put_tag(skb, tag); + + napi_gro_receive(&adapter->napi, skb); } /** @@ -2433,6 +2435,8 @@ static void e1000_vlan_rx_add_vid(struct net_device *netdev, u16 vid) vfta |= (1 << (vid & 0x1F)); hw->mac.ops.write_vfta(hw, index, vfta); } + + set_bit(vid, adapter->active_vlans); } static void e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) @@ -2441,13 +2445,6 @@ static void e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) struct e1000_hw *hw = &adapter->hw; u32 vfta, index; - if (!test_bit(__E1000_DOWN, &adapter->state)) - e1000_irq_disable(adapter); - vlan_group_set_device(adapter->vlgrp, vid, NULL); - - if (!test_bit(__E1000_DOWN, &adapter->state)) - e1000_irq_enable(adapter); - if ((adapter->hw.mng_cookie.status & E1000_MNG_DHCP_COOKIE_STATUS_VLAN) && (vid == adapter->mng_vlan_id)) { @@ -2463,93 +2460,105 @@ static void e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) vfta &= ~(1 << (vid & 0x1F)); hw->mac.ops.write_vfta(hw, index, vfta); } + + clear_bit(vid, adapter->active_vlans); } -static void e1000_update_mng_vlan(struct e1000_adapter *adapter) +/** + * e1000e_vlan_filter_disable - helper to disable hw VLAN filtering + * @adapter: board private structure to initialize + **/ +static void e1000e_vlan_filter_disable(struct e1000_adapter *adapter) { struct net_device *netdev = adapter->netdev; - u16 vid = adapter->hw.mng_cookie.vlan_id; - u16 old_vid = adapter->mng_vlan_id; - - if (!adapter->vlgrp) - return; + struct e1000_hw *hw = &adapter->hw; + u32 rctl; - if (!vlan_group_get_device(adapter->vlgrp, vid)) { - adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; - if (adapter->hw.mng_cookie.status & - E1000_MNG_DHCP_COOKIE_STATUS_VLAN) { - e1000_vlan_rx_add_vid(netdev, vid); - adapter->mng_vlan_id = vid; + if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) { + /* disable VLAN receive filtering */ + rctl = er32(RCTL); + rctl &= ~(E1000_RCTL_VFE | E1000_RCTL_CFIEN); + ew32(RCTL, rctl); + + if (adapter->mng_vlan_id != (u16)E1000_MNG_VLAN_NONE) { + e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id); + adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; } - - if ((old_vid != (u16)E1000_MNG_VLAN_NONE) && - (vid != old_vid) && - !vlan_group_get_device(adapter->vlgrp, old_vid)) - e1000_vlan_rx_kill_vid(netdev, old_vid); - } else { - adapter->mng_vlan_id = vid; } } +/** + * e1000e_vlan_filter_enable - helper to enable HW VLAN filtering + * @adapter: board private structure to initialize + **/ +static void e1000e_vlan_filter_enable(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 rctl; -static void e1000_vlan_rx_register(struct net_device *netdev, - struct vlan_group *grp) + if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) { + /* enable VLAN receive filtering */ + rctl = er32(RCTL); + rctl |= E1000_RCTL_VFE; + rctl &= ~E1000_RCTL_CFIEN; + ew32(RCTL, rctl); + } +} + +/** + * e1000e_vlan_strip_enable - helper to disable HW VLAN stripping + * @adapter: board private structure to initialize + **/ +static void e1000e_vlan_strip_disable(struct e1000_adapter *adapter) { - struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - u32 ctrl, rctl; + u32 ctrl; - if (!test_bit(__E1000_DOWN, &adapter->state)) - e1000_irq_disable(adapter); - adapter->vlgrp = grp; + /* disable VLAN tag insert/strip */ + ctrl = er32(CTRL); + ctrl &= ~E1000_CTRL_VME; + ew32(CTRL, ctrl); +} - if (grp) { - /* enable VLAN tag insert/strip */ - ctrl = er32(CTRL); - ctrl |= E1000_CTRL_VME; - ew32(CTRL, ctrl); +/** + * e1000e_vlan_strip_enable - helper to enable HW VLAN stripping + * @adapter: board private structure to initialize + **/ +static void e1000e_vlan_strip_enable(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 ctrl; - if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) { - /* enable VLAN receive filtering */ - rctl = er32(RCTL); - rctl &= ~E1000_RCTL_CFIEN; - ew32(RCTL, rctl); - e1000_update_mng_vlan(adapter); - } - } else { - /* disable VLAN tag insert/strip */ - ctrl = er32(CTRL); - ctrl &= ~E1000_CTRL_VME; - ew32(CTRL, ctrl); + /* enable VLAN tag insert/strip */ + ctrl = er32(CTRL); + ctrl |= E1000_CTRL_VME; + ew32(CTRL, ctrl); +} - if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) { - if (adapter->mng_vlan_id != - (u16)E1000_MNG_VLAN_NONE) { - e1000_vlan_rx_kill_vid(netdev, - adapter->mng_vlan_id); - adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; - } - } +static void e1000_update_mng_vlan(struct e1000_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + u16 vid = adapter->hw.mng_cookie.vlan_id; + u16 old_vid = adapter->mng_vlan_id; + + if (adapter->hw.mng_cookie.status & + E1000_MNG_DHCP_COOKIE_STATUS_VLAN) { + e1000_vlan_rx_add_vid(netdev, vid); + adapter->mng_vlan_id = vid; } - if (!test_bit(__E1000_DOWN, &adapter->state)) - e1000_irq_enable(adapter); + if ((old_vid != (u16)E1000_MNG_VLAN_NONE) && (vid != old_vid)) + e1000_vlan_rx_kill_vid(netdev, old_vid); } static void e1000_restore_vlan(struct e1000_adapter *adapter) { u16 vid; - e1000_vlan_rx_register(adapter->netdev, adapter->vlgrp); - - if (!adapter->vlgrp) - return; + e1000_vlan_rx_add_vid(adapter->netdev, 0); - for (vid = 0; vid < VLAN_N_VID; vid++) { - if (!vlan_group_get_device(adapter->vlgrp, vid)) - continue; + for_each_set_bit(vid, adapter->active_vlans, VLAN_N_VID) e1000_vlan_rx_add_vid(adapter->netdev, vid); - } } static void e1000_init_manageability_pt(struct e1000_adapter *adapter) @@ -2902,7 +2911,7 @@ static void e1000_configure_rx(struct e1000_adapter *adapter) rctl = er32(RCTL); ew32(RCTL, rctl & ~E1000_RCTL_EN); e1e_flush(); - msleep(10); + usleep_range(10000, 20000); if (adapter->flags2 & FLAG2_DMA_BURST) { /* @@ -3039,6 +3048,8 @@ static void e1000_set_multi(struct net_device *netdev) if (netdev->flags & IFF_PROMISC) { rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE); rctl &= ~E1000_RCTL_VFE; + /* Do not hardware filter VLANs in promisc mode */ + e1000e_vlan_filter_disable(adapter); } else { if (netdev->flags & IFF_ALLMULTI) { rctl |= E1000_RCTL_MPE; @@ -3046,8 +3057,7 @@ static void e1000_set_multi(struct net_device *netdev) } else { rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE); } - if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) - rctl |= E1000_RCTL_VFE; + e1000e_vlan_filter_enable(adapter); } ew32(RCTL, rctl); @@ -3072,6 +3082,11 @@ static void e1000_set_multi(struct net_device *netdev) */ e1000_update_mc_addr_list(hw, NULL, 0); } + + if (netdev->features & NETIF_F_HW_VLAN_RX) + e1000e_vlan_strip_enable(adapter); + else + e1000e_vlan_strip_disable(adapter); } /** @@ -3383,7 +3398,7 @@ void e1000e_down(struct e1000_adapter *adapter) ew32(TCTL, tctl); /* flush both disables and wait for them to finish */ e1e_flush(); - msleep(10); + usleep_range(10000, 20000); napi_disable(&adapter->napi); e1000_irq_disable(adapter); @@ -3418,7 +3433,7 @@ void e1000e_reinit_locked(struct e1000_adapter *adapter) { might_sleep(); while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) - msleep(1); + usleep_range(1000, 2000); e1000e_down(adapter); e1000e_up(adapter); clear_bit(__E1000_RESETTING, &adapter->state); @@ -3721,10 +3736,8 @@ static int e1000_close(struct net_device *netdev) * kill manageability vlan ID if supported, but not if a vlan with * the same ID is registered on the host OS (let 8021q kill it) */ - if ((adapter->hw.mng_cookie.status & - E1000_MNG_DHCP_COOKIE_STATUS_VLAN) && - !(adapter->vlgrp && - vlan_group_get_device(adapter->vlgrp, adapter->mng_vlan_id))) + if (adapter->hw.mng_cookie.status & + E1000_MNG_DHCP_COOKIE_STATUS_VLAN) e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id); /* @@ -4328,7 +4341,6 @@ static void e1000_watchdog_task(struct work_struct *work) link_up: spin_lock(&adapter->stats64_lock); e1000e_update_stats(adapter); - spin_unlock(&adapter->stats64_lock); mac->tx_packet_delta = adapter->stats.tpt - adapter->tpt_old; adapter->tpt_old = adapter->stats.tpt; @@ -4339,6 +4351,7 @@ link_up: adapter->gorc_old = adapter->stats.gorc; adapter->gotc = adapter->stats.gotc - adapter->gotc_old; adapter->gotc_old = adapter->stats.gotc; + spin_unlock(&adapter->stats64_lock); e1000e_update_adaptive(&adapter->hw); @@ -5028,7 +5041,7 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) } while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) - msleep(1); + usleep_range(1000, 2000); /* e1000e_down -> e1000e_reset dependent on max_frame_size & mtu */ adapter->max_frame_size = max_frame; e_info("changing MTU from %d to %d\n", netdev->mtu, new_mtu); @@ -5373,7 +5386,7 @@ static void __e1000e_disable_aspm(struct pci_dev *pdev, u16 state) pci_write_config_word(pdev->bus->self, pos + PCI_EXP_LNKCTL, reg16); } #endif -void e1000e_disable_aspm(struct pci_dev *pdev, u16 state) +static void e1000e_disable_aspm(struct pci_dev *pdev, u16 state) { dev_info(&pdev->dev, "Disabling ASPM %s %s\n", (state & PCIE_LINK_STATE_L0S) ? "L0s" : "", @@ -5393,13 +5406,19 @@ static int __e1000_resume(struct pci_dev *pdev) struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; + u16 aspm_disable_flag = 0; u32 err; + if (adapter->flags2 & FLAG2_DISABLE_ASPM_L0S) + aspm_disable_flag = PCIE_LINK_STATE_L0S; + if (adapter->flags2 & FLAG2_DISABLE_ASPM_L1) + aspm_disable_flag |= PCIE_LINK_STATE_L1; + if (aspm_disable_flag) + e1000e_disable_aspm(pdev, aspm_disable_flag); + pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); pci_save_state(pdev); - if (adapter->flags2 & FLAG2_DISABLE_ASPM_L1) - e1000e_disable_aspm(pdev, PCIE_LINK_STATE_L1); e1000e_set_interrupt_capability(adapter); if (netif_running(netdev)) { @@ -5643,11 +5662,17 @@ static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev) struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; + u16 aspm_disable_flag = 0; int err; pci_ers_result_t result; + if (adapter->flags2 & FLAG2_DISABLE_ASPM_L0S) + aspm_disable_flag = PCIE_LINK_STATE_L0S; if (adapter->flags2 & FLAG2_DISABLE_ASPM_L1) - e1000e_disable_aspm(pdev, PCIE_LINK_STATE_L1); + aspm_disable_flag |= PCIE_LINK_STATE_L1; + if (aspm_disable_flag) + e1000e_disable_aspm(pdev, aspm_disable_flag); + err = pci_enable_device_mem(pdev); if (err) { dev_err(&pdev->dev, @@ -5714,7 +5739,7 @@ static void e1000_print_device_info(struct e1000_adapter *adapter) u8 pba_str[E1000_PBANUM_LENGTH]; /* print bus type/speed/width info */ - e_info("(PCI Express:2.5GB/s:%s) %pM\n", + e_info("(PCI Express:2.5GT/s:%s) %pM\n", /* bus width */ ((hw->bus.width == e1000_bus_width_pcie_x4) ? "Width x4" : "Width x1"), @@ -5759,7 +5784,6 @@ static const struct net_device_ops e1000e_netdev_ops = { .ndo_tx_timeout = e1000_tx_timeout, .ndo_validate_addr = eth_validate_addr, - .ndo_vlan_rx_register = e1000_vlan_rx_register, .ndo_vlan_rx_add_vid = e1000_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = e1000_vlan_rx_kill_vid, #ifdef CONFIG_NET_POLL_CONTROLLER @@ -5789,12 +5813,17 @@ static int __devinit e1000_probe(struct pci_dev *pdev, resource_size_t flash_start, flash_len; static int cards_found; + u16 aspm_disable_flag = 0; int i, err, pci_using_dac; u16 eeprom_data = 0; u16 eeprom_apme_mask = E1000_EEPROM_APME; + if (ei->flags2 & FLAG2_DISABLE_ASPM_L0S) + aspm_disable_flag = PCIE_LINK_STATE_L0S; if (ei->flags2 & FLAG2_DISABLE_ASPM_L1) - e1000e_disable_aspm(pdev, PCIE_LINK_STATE_L1); + aspm_disable_flag |= PCIE_LINK_STATE_L1; + if (aspm_disable_flag) + e1000e_disable_aspm(pdev, aspm_disable_flag); err = pci_enable_device_mem(pdev); if (err) diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c index 6ae31fcfb629..484774c13c21 100644 --- a/drivers/net/e1000e/phy.c +++ b/drivers/net/e1000e/phy.c @@ -2372,7 +2372,7 @@ s32 e1000e_determine_phy_address(struct e1000_hw *hw) ret_val = 0; goto out; } - msleep(1); + usleep_range(1000, 2000); i++; } while (i < 10); } @@ -2740,7 +2740,7 @@ void e1000_power_down_phy_copper(struct e1000_hw *hw) e1e_rphy(hw, PHY_CONTROL, &mii_reg); mii_reg |= MII_CR_POWER_DOWN; e1e_wphy(hw, PHY_CONTROL, mii_reg); - msleep(1); + usleep_range(1000, 2000); } /** diff --git a/drivers/net/ehea/ehea_ethtool.c b/drivers/net/ehea/ehea_ethtool.c index 3e2e734fecb7..5f13491cf2a9 100644 --- a/drivers/net/ehea/ehea_ethtool.c +++ b/drivers/net/ehea/ehea_ethtool.c @@ -162,11 +162,6 @@ static void ehea_set_msglevel(struct net_device *dev, u32 value) port->msg_enable = value; } -static u32 ehea_get_rx_csum(struct net_device *dev) -{ - return 1; -} - static char ehea_ethtool_stats_keys[][ETH_GSTRING_LEN] = { {"sig_comp_iv"}, {"swqe_refill_th"}, @@ -263,34 +258,16 @@ static void ehea_get_ethtool_stats(struct net_device *dev, } -static int ehea_set_flags(struct net_device *dev, u32 data) -{ - /* Avoid changing the VLAN flags */ - if ((data & (ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN)) != - (ethtool_op_get_flags(dev) & (ETH_FLAG_RXVLAN | - ETH_FLAG_TXVLAN))){ - return -EINVAL; - } - - return ethtool_op_set_flags(dev, data, ETH_FLAG_LRO - | ETH_FLAG_TXVLAN - | ETH_FLAG_RXVLAN); -} - const struct ethtool_ops ehea_ethtool_ops = { .get_settings = ehea_get_settings, .get_drvinfo = ehea_get_drvinfo, .get_msglevel = ehea_get_msglevel, .set_msglevel = ehea_set_msglevel, .get_link = ethtool_op_get_link, - .set_tso = ethtool_op_set_tso, .get_strings = ehea_get_strings, .get_sset_count = ehea_get_sset_count, .get_ethtool_stats = ehea_get_ethtool_stats, - .get_rx_csum = ehea_get_rx_csum, .set_settings = ehea_set_settings, - .get_flags = ethtool_op_get_flags, - .set_flags = ehea_set_flags, .nway_reset = ehea_nway_reset, /* Restart autonegotiation */ }; diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index f75d3144b8a5..ce2f0ca61d9a 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -3262,10 +3262,12 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter, dev->netdev_ops = &ehea_netdev_ops; ehea_set_ethtool_ops(dev); + dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO + | NETIF_F_IP_CSUM | NETIF_F_HW_VLAN_TX | NETIF_F_LRO; dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO | NETIF_F_HIGHDMA | NETIF_F_IP_CSUM | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER - | NETIF_F_LLTX; + | NETIF_F_LLTX | NETIF_F_RXCSUM; dev->watchdog_timeo = EHEA_WATCH_DOG_TIMEOUT; if (use_lro) diff --git a/drivers/net/enic/Makefile b/drivers/net/enic/Makefile index 2e573be16c13..9d4974bba247 100644 --- a/drivers/net/enic/Makefile +++ b/drivers/net/enic/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_ENIC) := enic.o enic-y := enic_main.o vnic_cq.o vnic_intr.o vnic_wq.o \ - enic_res.o enic_dev.o vnic_dev.o vnic_rq.o vnic_vic.o + enic_res.o enic_dev.o enic_pp.o vnic_dev.o vnic_rq.o vnic_vic.o diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h index 3a3c3c8a3a9b..38b351c7b979 100644 --- a/drivers/net/enic/enic.h +++ b/drivers/net/enic/enic.h @@ -32,7 +32,7 @@ #define DRV_NAME "enic" #define DRV_DESCRIPTION "Cisco VIC Ethernet NIC Driver" -#define DRV_VERSION "2.1.1.12" +#define DRV_VERSION "2.1.1.13" #define DRV_COPYRIGHT "Copyright 2008-2011 Cisco Systems, Inc" #define ENIC_BARS_MAX 6 @@ -84,7 +84,6 @@ struct enic { unsigned int flags; unsigned int mc_count; unsigned int uc_count; - int csum_rx_enabled; u32 port_mtu; u32 rx_coalesce_usecs; u32 tx_coalesce_usecs; @@ -120,4 +119,6 @@ static inline struct device *enic_get_dev(struct enic *enic) return &(enic->pdev->dev); } +void enic_reset_addr_lists(struct enic *enic); + #endif /* _ENIC_H_ */ diff --git a/drivers/net/enic/enic_dev.c b/drivers/net/enic/enic_dev.c index 37ad3a1c82ee..90687b14e60f 100644 --- a/drivers/net/enic/enic_dev.c +++ b/drivers/net/enic/enic_dev.c @@ -177,24 +177,24 @@ int enic_vnic_dev_deinit(struct enic *enic) return err; } -int enic_dev_init_prov(struct enic *enic, struct vic_provinfo *vp) +int enic_dev_init_prov2(struct enic *enic, struct vic_provinfo *vp) { int err; spin_lock(&enic->devcmd_lock); - err = vnic_dev_init_prov(enic->vdev, + err = vnic_dev_init_prov2(enic->vdev, (u8 *)vp, vic_provinfo_size(vp)); spin_unlock(&enic->devcmd_lock); return err; } -int enic_dev_init_done(struct enic *enic, int *done, int *error) +int enic_dev_deinit_done(struct enic *enic, int *status) { int err; spin_lock(&enic->devcmd_lock); - err = vnic_dev_init_done(enic->vdev, done, error); + err = vnic_dev_deinit_done(enic->vdev, status); spin_unlock(&enic->devcmd_lock); return err; @@ -219,3 +219,57 @@ void enic_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) enic_del_vlan(enic, vid); spin_unlock(&enic->devcmd_lock); } + +int enic_dev_enable2(struct enic *enic, int active) +{ + int err; + + spin_lock(&enic->devcmd_lock); + err = vnic_dev_enable2(enic->vdev, active); + spin_unlock(&enic->devcmd_lock); + + return err; +} + +int enic_dev_enable2_done(struct enic *enic, int *status) +{ + int err; + + spin_lock(&enic->devcmd_lock); + err = vnic_dev_enable2_done(enic->vdev, status); + spin_unlock(&enic->devcmd_lock); + + return err; +} + +int enic_dev_status_to_errno(int devcmd_status) +{ + switch (devcmd_status) { + case ERR_SUCCESS: + return 0; + case ERR_EINVAL: + return -EINVAL; + case ERR_EFAULT: + return -EFAULT; + case ERR_EPERM: + return -EPERM; + case ERR_EBUSY: + return -EBUSY; + case ERR_ECMDUNKNOWN: + case ERR_ENOTSUPPORTED: + return -EOPNOTSUPP; + case ERR_EBADSTATE: + return -EINVAL; + case ERR_ENOMEM: + return -ENOMEM; + case ERR_ETIMEDOUT: + return -ETIMEDOUT; + case ERR_ELINKDOWN: + return -ENETDOWN; + case ERR_EINPROGRESS: + return -EINPROGRESS; + case ERR_EMAXRES: + default: + return (devcmd_status < 0) ? devcmd_status : -1; + } +} diff --git a/drivers/net/enic/enic_dev.h b/drivers/net/enic/enic_dev.h index 495f57fcb887..d5f681337626 100644 --- a/drivers/net/enic/enic_dev.h +++ b/drivers/net/enic/enic_dev.h @@ -35,7 +35,10 @@ int enic_dev_set_ig_vlan_rewrite_mode(struct enic *enic); int enic_dev_enable(struct enic *enic); int enic_dev_disable(struct enic *enic); int enic_vnic_dev_deinit(struct enic *enic); -int enic_dev_init_prov(struct enic *enic, struct vic_provinfo *vp); -int enic_dev_init_done(struct enic *enic, int *done, int *error); +int enic_dev_init_prov2(struct enic *enic, struct vic_provinfo *vp); +int enic_dev_deinit_done(struct enic *enic, int *status); +int enic_dev_enable2(struct enic *enic, int arg); +int enic_dev_enable2_done(struct enic *enic, int *status); +int enic_dev_status_to_errno(int devcmd_status); #endif /* _ENIC_DEV_H_ */ diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 8b9cad5e9712..b2245511c51a 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -45,6 +45,7 @@ #include "enic_res.h" #include "enic.h" #include "enic_dev.h" +#include "enic_pp.h" #define ENIC_NOTIFY_TIMER_PERIOD (2 * HZ) #define WQ_ENET_MAX_DESC_LEN (1 << WQ_ENET_LEN_BITS) @@ -250,56 +251,6 @@ static void enic_get_ethtool_stats(struct net_device *netdev, *(data++) = ((u64 *)&vstats->rx)[enic_rx_stats[i].offset]; } -static u32 enic_get_rx_csum(struct net_device *netdev) -{ - struct enic *enic = netdev_priv(netdev); - return enic->csum_rx_enabled; -} - -static int enic_set_rx_csum(struct net_device *netdev, u32 data) -{ - struct enic *enic = netdev_priv(netdev); - - if (data && !ENIC_SETTING(enic, RXCSUM)) - return -EINVAL; - - enic->csum_rx_enabled = !!data; - - return 0; -} - -static int enic_set_tx_csum(struct net_device *netdev, u32 data) -{ - struct enic *enic = netdev_priv(netdev); - - if (data && !ENIC_SETTING(enic, TXCSUM)) - return -EINVAL; - - if (data) - netdev->features |= NETIF_F_HW_CSUM; - else - netdev->features &= ~NETIF_F_HW_CSUM; - - return 0; -} - -static int enic_set_tso(struct net_device *netdev, u32 data) -{ - struct enic *enic = netdev_priv(netdev); - - if (data && !ENIC_SETTING(enic, TSO)) - return -EINVAL; - - if (data) - netdev->features |= - NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN; - else - netdev->features &= - ~(NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN); - - return 0; -} - static u32 enic_get_msglevel(struct net_device *netdev) { struct enic *enic = netdev_priv(netdev); @@ -387,17 +338,8 @@ static const struct ethtool_ops enic_ethtool_ops = { .get_strings = enic_get_strings, .get_sset_count = enic_get_sset_count, .get_ethtool_stats = enic_get_ethtool_stats, - .get_rx_csum = enic_get_rx_csum, - .set_rx_csum = enic_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = enic_set_tx_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, - .set_tso = enic_set_tso, .get_coalesce = enic_get_coalesce, .set_coalesce = enic_set_coalesce, - .get_flags = ethtool_op_get_flags, }; static void enic_free_wq_buf(struct vnic_wq *wq, struct vnic_wq_buf *buf) @@ -874,7 +816,7 @@ static struct net_device_stats *enic_get_stats(struct net_device *netdev) return net_stats; } -static void enic_reset_addr_lists(struct enic *enic) +void enic_reset_addr_lists(struct enic *enic) { enic->mc_count = 0; enic->uc_count = 0; @@ -1112,157 +1054,77 @@ static int enic_set_vf_mac(struct net_device *netdev, int vf, u8 *mac) return -EINVAL; } -static int enic_set_port_profile(struct enic *enic, u8 *mac) -{ - struct vic_provinfo *vp; - u8 oui[3] = VIC_PROVINFO_CISCO_OUI; - u16 os_type = VIC_GENERIC_PROV_OS_TYPE_LINUX; - char uuid_str[38]; - char client_mac_str[18]; - u8 *client_mac; - int err; - - err = enic_vnic_dev_deinit(enic); - if (err) - return err; - - enic_reset_addr_lists(enic); - - switch (enic->pp.request) { - - case PORT_REQUEST_ASSOCIATE: - - if (!(enic->pp.set & ENIC_SET_NAME) || !strlen(enic->pp.name)) - return -EINVAL; - - if (!is_valid_ether_addr(mac)) - return -EADDRNOTAVAIL; - - vp = vic_provinfo_alloc(GFP_KERNEL, oui, - VIC_PROVINFO_GENERIC_TYPE); - if (!vp) - return -ENOMEM; - - vic_provinfo_add_tlv(vp, - VIC_GENERIC_PROV_TLV_PORT_PROFILE_NAME_STR, - strlen(enic->pp.name) + 1, enic->pp.name); - - if (!is_zero_ether_addr(enic->pp.mac_addr)) - client_mac = enic->pp.mac_addr; - else - client_mac = mac; - - vic_provinfo_add_tlv(vp, - VIC_GENERIC_PROV_TLV_CLIENT_MAC_ADDR, - ETH_ALEN, client_mac); - - sprintf(client_mac_str, "%pM", client_mac); - vic_provinfo_add_tlv(vp, - VIC_GENERIC_PROV_TLV_CLUSTER_PORT_UUID_STR, - sizeof(client_mac_str), client_mac_str); - - if (enic->pp.set & ENIC_SET_INSTANCE) { - sprintf(uuid_str, "%pUB", enic->pp.instance_uuid); - vic_provinfo_add_tlv(vp, - VIC_GENERIC_PROV_TLV_CLIENT_UUID_STR, - sizeof(uuid_str), uuid_str); - } - - if (enic->pp.set & ENIC_SET_HOST) { - sprintf(uuid_str, "%pUB", enic->pp.host_uuid); - vic_provinfo_add_tlv(vp, - VIC_GENERIC_PROV_TLV_HOST_UUID_STR, - sizeof(uuid_str), uuid_str); - } - - os_type = htons(os_type); - vic_provinfo_add_tlv(vp, - VIC_GENERIC_PROV_TLV_OS_TYPE, - sizeof(os_type), &os_type); - - err = enic_dev_init_prov(enic, vp); - vic_provinfo_free(vp); - if (err) - return err; - break; - - case PORT_REQUEST_DISASSOCIATE: - break; - - default: - return -EINVAL; - } - - /* Set flag to indicate that the port assoc/disassoc - * request has been sent out to fw - */ - enic->pp.set |= ENIC_PORT_REQUEST_APPLIED; - - return 0; -} - static int enic_set_vf_port(struct net_device *netdev, int vf, struct nlattr *port[]) { struct enic *enic = netdev_priv(netdev); - struct enic_port_profile new_pp; - int err = 0; + struct enic_port_profile prev_pp; + int err = 0, restore_pp = 1; - memset(&new_pp, 0, sizeof(new_pp)); + /* don't support VFs, yet */ + if (vf != PORT_SELF_VF) + return -EOPNOTSUPP; - if (port[IFLA_PORT_REQUEST]) { - new_pp.set |= ENIC_SET_REQUEST; - new_pp.request = nla_get_u8(port[IFLA_PORT_REQUEST]); - } + if (!port[IFLA_PORT_REQUEST]) + return -EOPNOTSUPP; + + memcpy(&prev_pp, &enic->pp, sizeof(enic->pp)); + memset(&enic->pp, 0, sizeof(enic->pp)); + + enic->pp.set |= ENIC_SET_REQUEST; + enic->pp.request = nla_get_u8(port[IFLA_PORT_REQUEST]); if (port[IFLA_PORT_PROFILE]) { - new_pp.set |= ENIC_SET_NAME; - memcpy(new_pp.name, nla_data(port[IFLA_PORT_PROFILE]), + enic->pp.set |= ENIC_SET_NAME; + memcpy(enic->pp.name, nla_data(port[IFLA_PORT_PROFILE]), PORT_PROFILE_MAX); } if (port[IFLA_PORT_INSTANCE_UUID]) { - new_pp.set |= ENIC_SET_INSTANCE; - memcpy(new_pp.instance_uuid, + enic->pp.set |= ENIC_SET_INSTANCE; + memcpy(enic->pp.instance_uuid, nla_data(port[IFLA_PORT_INSTANCE_UUID]), PORT_UUID_MAX); } if (port[IFLA_PORT_HOST_UUID]) { - new_pp.set |= ENIC_SET_HOST; - memcpy(new_pp.host_uuid, + enic->pp.set |= ENIC_SET_HOST; + memcpy(enic->pp.host_uuid, nla_data(port[IFLA_PORT_HOST_UUID]), PORT_UUID_MAX); } - /* don't support VFs, yet */ - if (vf != PORT_SELF_VF) - return -EOPNOTSUPP; - - if (!(new_pp.set & ENIC_SET_REQUEST)) - return -EOPNOTSUPP; - - if (new_pp.request == PORT_REQUEST_ASSOCIATE) { - /* Special case handling */ - if (!is_zero_ether_addr(enic->pp.vf_mac)) - memcpy(new_pp.mac_addr, enic->pp.vf_mac, ETH_ALEN); + /* Special case handling: mac came from IFLA_VF_MAC */ + if (!is_zero_ether_addr(prev_pp.vf_mac)) + memcpy(enic->pp.mac_addr, prev_pp.vf_mac, ETH_ALEN); if (is_zero_ether_addr(netdev->dev_addr)) random_ether_addr(netdev->dev_addr); - } - memcpy(&enic->pp, &new_pp, sizeof(struct enic_port_profile)); + err = enic_process_set_pp_request(enic, &prev_pp, &restore_pp); + if (err) { + if (restore_pp) { + /* Things are still the way they were: Implicit + * DISASSOCIATE failed + */ + memcpy(&enic->pp, &prev_pp, sizeof(enic->pp)); + } else { + memset(&enic->pp, 0, sizeof(enic->pp)); + memset(netdev->dev_addr, 0, ETH_ALEN); + } + } else { + /* Set flag to indicate that the port assoc/disassoc + * request has been sent out to fw + */ + enic->pp.set |= ENIC_PORT_REQUEST_APPLIED; - err = enic_set_port_profile(enic, netdev->dev_addr); - if (err) - goto set_port_profile_cleanup; + /* If DISASSOCIATE, clean up all assigned/saved macaddresses */ + if (enic->pp.request == PORT_REQUEST_DISASSOCIATE) { + memset(enic->pp.mac_addr, 0, ETH_ALEN); + memset(netdev->dev_addr, 0, ETH_ALEN); + } + } -set_port_profile_cleanup: memset(enic->pp.vf_mac, 0, ETH_ALEN); - if (err || enic->pp.request == PORT_REQUEST_DISASSOCIATE) { - memset(netdev->dev_addr, 0, ETH_ALEN); - memset(enic->pp.mac_addr, 0, ETH_ALEN); - } - return err; } @@ -1270,34 +1132,15 @@ static int enic_get_vf_port(struct net_device *netdev, int vf, struct sk_buff *skb) { struct enic *enic = netdev_priv(netdev); - int err, error, done; u16 response = PORT_PROFILE_RESPONSE_SUCCESS; + int err; if (!(enic->pp.set & ENIC_PORT_REQUEST_APPLIED)) return -ENODATA; - err = enic_dev_init_done(enic, &done, &error); + err = enic_process_get_pp_request(enic, enic->pp.request, &response); if (err) - error = err; - - switch (error) { - case ERR_SUCCESS: - if (!done) - response = PORT_PROFILE_RESPONSE_INPROGRESS; - break; - case ERR_EINVAL: - response = PORT_PROFILE_RESPONSE_INVALID; - break; - case ERR_EBADSTATE: - response = PORT_PROFILE_RESPONSE_BADSTATE; - break; - case ERR_ENOMEM: - response = PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES; - break; - default: - response = PORT_PROFILE_RESPONSE_ERROR; - break; - } + return err; NLA_PUT_U16(skb, IFLA_PORT_REQUEST, enic->pp.request); NLA_PUT_U16(skb, IFLA_PORT_RESPONSE, response); @@ -1407,7 +1250,7 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq, skb_put(skb, bytes_written); skb->protocol = eth_type_trans(skb, netdev); - if (enic->csum_rx_enabled && !csum_not_calc) { + if ((netdev->features & NETIF_F_RXCSUM) && !csum_not_calc) { skb->csum = htons(checksum); skb->ip_summed = CHECKSUM_COMPLETE; } @@ -2536,17 +2379,18 @@ static int __devinit enic_probe(struct pci_dev *pdev, dev_info(dev, "loopback tag=0x%04x\n", enic->loop_tag); } if (ENIC_SETTING(enic, TXCSUM)) - netdev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; + netdev->hw_features |= NETIF_F_SG | NETIF_F_HW_CSUM; if (ENIC_SETTING(enic, TSO)) - netdev->features |= NETIF_F_TSO | + netdev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN; - if (ENIC_SETTING(enic, LRO)) - netdev->features |= NETIF_F_GRO; + if (ENIC_SETTING(enic, RXCSUM)) + netdev->hw_features |= NETIF_F_RXCSUM; + + netdev->features |= netdev->hw_features; + if (using_dac) netdev->features |= NETIF_F_HIGHDMA; - enic->csum_rx_enabled = ENIC_SETTING(enic, RXCSUM); - err = register_netdev(netdev); if (err) { dev_err(dev, "Cannot register net device, aborting\n"); diff --git a/drivers/net/enic/enic_pp.c b/drivers/net/enic/enic_pp.c new file mode 100644 index 000000000000..ffaa75dd1ded --- /dev/null +++ b/drivers/net/enic/enic_pp.c @@ -0,0 +1,264 @@ +/* + * Copyright 2011 Cisco Systems, Inc. All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/types.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/rtnetlink.h> +#include <net/ip.h> + +#include "vnic_vic.h" +#include "enic_res.h" +#include "enic.h" +#include "enic_dev.h" + +static int enic_set_port_profile(struct enic *enic) +{ + struct net_device *netdev = enic->netdev; + struct vic_provinfo *vp; + const u8 oui[3] = VIC_PROVINFO_CISCO_OUI; + const u16 os_type = htons(VIC_GENERIC_PROV_OS_TYPE_LINUX); + char uuid_str[38]; + char client_mac_str[18]; + u8 *client_mac; + int err; + + if (!(enic->pp.set & ENIC_SET_NAME) || !strlen(enic->pp.name)) + return -EINVAL; + + vp = vic_provinfo_alloc(GFP_KERNEL, oui, + VIC_PROVINFO_GENERIC_TYPE); + if (!vp) + return -ENOMEM; + + VIC_PROVINFO_ADD_TLV(vp, + VIC_GENERIC_PROV_TLV_PORT_PROFILE_NAME_STR, + strlen(enic->pp.name) + 1, enic->pp.name); + + if (!is_zero_ether_addr(enic->pp.mac_addr)) + client_mac = enic->pp.mac_addr; + else + client_mac = netdev->dev_addr; + + VIC_PROVINFO_ADD_TLV(vp, + VIC_GENERIC_PROV_TLV_CLIENT_MAC_ADDR, + ETH_ALEN, client_mac); + + snprintf(client_mac_str, sizeof(client_mac_str), "%pM", client_mac); + VIC_PROVINFO_ADD_TLV(vp, + VIC_GENERIC_PROV_TLV_CLUSTER_PORT_UUID_STR, + sizeof(client_mac_str), client_mac_str); + + if (enic->pp.set & ENIC_SET_INSTANCE) { + sprintf(uuid_str, "%pUB", enic->pp.instance_uuid); + VIC_PROVINFO_ADD_TLV(vp, + VIC_GENERIC_PROV_TLV_CLIENT_UUID_STR, + sizeof(uuid_str), uuid_str); + } + + if (enic->pp.set & ENIC_SET_HOST) { + sprintf(uuid_str, "%pUB", enic->pp.host_uuid); + VIC_PROVINFO_ADD_TLV(vp, + VIC_GENERIC_PROV_TLV_HOST_UUID_STR, + sizeof(uuid_str), uuid_str); + } + + VIC_PROVINFO_ADD_TLV(vp, + VIC_GENERIC_PROV_TLV_OS_TYPE, + sizeof(os_type), &os_type); + + err = enic_dev_status_to_errno(enic_dev_init_prov2(enic, vp)); + +add_tlv_failure: + vic_provinfo_free(vp); + + return err; +} + +static int enic_unset_port_profile(struct enic *enic) +{ + int err; + + err = enic_vnic_dev_deinit(enic); + if (err) + return enic_dev_status_to_errno(err); + + enic_reset_addr_lists(enic); + + return 0; +} + +static int enic_are_pp_different(struct enic_port_profile *pp1, + struct enic_port_profile *pp2) +{ + return strcmp(pp1->name, pp2->name) | !!memcmp(pp1->instance_uuid, + pp2->instance_uuid, PORT_UUID_MAX) | + !!memcmp(pp1->host_uuid, pp2->host_uuid, PORT_UUID_MAX) | + !!memcmp(pp1->mac_addr, pp2->mac_addr, ETH_ALEN); +} + +static int enic_pp_preassociate(struct enic *enic, + struct enic_port_profile *prev_pp, int *restore_pp); +static int enic_pp_disassociate(struct enic *enic, + struct enic_port_profile *prev_pp, int *restore_pp); +static int enic_pp_preassociate_rr(struct enic *enic, + struct enic_port_profile *prev_pp, int *restore_pp); +static int enic_pp_associate(struct enic *enic, + struct enic_port_profile *prev_pp, int *restore_pp); + +static int (*enic_pp_handlers[])(struct enic *enic, + struct enic_port_profile *prev_state, int *restore_pp) = { + [PORT_REQUEST_PREASSOCIATE] = enic_pp_preassociate, + [PORT_REQUEST_PREASSOCIATE_RR] = enic_pp_preassociate_rr, + [PORT_REQUEST_ASSOCIATE] = enic_pp_associate, + [PORT_REQUEST_DISASSOCIATE] = enic_pp_disassociate, +}; + +static const int enic_pp_handlers_count = + sizeof(enic_pp_handlers)/sizeof(*enic_pp_handlers); + +static int enic_pp_preassociate(struct enic *enic, + struct enic_port_profile *prev_pp, int *restore_pp) +{ + return -EOPNOTSUPP; +} + +static int enic_pp_disassociate(struct enic *enic, + struct enic_port_profile *prev_pp, int *restore_pp) +{ + return enic_unset_port_profile(enic); +} + +static int enic_pp_preassociate_rr(struct enic *enic, + struct enic_port_profile *prev_pp, int *restore_pp) +{ + int err; + int active = 0; + + if (enic->pp.request != PORT_REQUEST_ASSOCIATE) { + /* If pre-associate is not part of an associate. + We always disassociate first */ + err = enic_pp_handlers[PORT_REQUEST_DISASSOCIATE](enic, + prev_pp, restore_pp); + if (err) + return err; + + *restore_pp = 0; + } + + *restore_pp = 0; + + err = enic_set_port_profile(enic); + if (err) + return err; + + /* If pre-associate is not part of an associate. */ + if (enic->pp.request != PORT_REQUEST_ASSOCIATE) + err = enic_dev_status_to_errno(enic_dev_enable2(enic, active)); + + return err; +} + +static int enic_pp_associate(struct enic *enic, + struct enic_port_profile *prev_pp, int *restore_pp) +{ + int err; + int active = 1; + + /* Check if a pre-associate was called before */ + if (prev_pp->request != PORT_REQUEST_PREASSOCIATE_RR || + (prev_pp->request == PORT_REQUEST_PREASSOCIATE_RR && + enic_are_pp_different(prev_pp, &enic->pp))) { + err = enic_pp_handlers[PORT_REQUEST_DISASSOCIATE]( + enic, prev_pp, restore_pp); + if (err) + return err; + + *restore_pp = 0; + } + + err = enic_pp_handlers[PORT_REQUEST_PREASSOCIATE_RR]( + enic, prev_pp, restore_pp); + if (err) + return err; + + *restore_pp = 0; + + return enic_dev_status_to_errno(enic_dev_enable2(enic, active)); +} + +int enic_process_set_pp_request(struct enic *enic, + struct enic_port_profile *prev_pp, int *restore_pp) +{ + if (enic->pp.request < enic_pp_handlers_count + && enic_pp_handlers[enic->pp.request]) + return enic_pp_handlers[enic->pp.request](enic, + prev_pp, restore_pp); + else + return -EOPNOTSUPP; +} + +int enic_process_get_pp_request(struct enic *enic, int request, + u16 *response) +{ + int err, status = ERR_SUCCESS; + + switch (request) { + + case PORT_REQUEST_PREASSOCIATE_RR: + case PORT_REQUEST_ASSOCIATE: + err = enic_dev_enable2_done(enic, &status); + break; + + case PORT_REQUEST_DISASSOCIATE: + err = enic_dev_deinit_done(enic, &status); + break; + + default: + return -EINVAL; + } + + if (err) + status = err; + + switch (status) { + case ERR_SUCCESS: + *response = PORT_PROFILE_RESPONSE_SUCCESS; + break; + case ERR_EINVAL: + *response = PORT_PROFILE_RESPONSE_INVALID; + break; + case ERR_EBADSTATE: + *response = PORT_PROFILE_RESPONSE_BADSTATE; + break; + case ERR_ENOMEM: + *response = PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES; + break; + case ERR_EINPROGRESS: + *response = PORT_PROFILE_RESPONSE_INPROGRESS; + break; + default: + *response = PORT_PROFILE_RESPONSE_ERROR; + break; + } + + return 0; +} diff --git a/drivers/net/enic/enic_pp.h b/drivers/net/enic/enic_pp.h new file mode 100644 index 000000000000..699e365a944d --- /dev/null +++ b/drivers/net/enic/enic_pp.h @@ -0,0 +1,27 @@ +/* + * Copyright 2011 Cisco Systems, Inc. All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _ENIC_PP_H_ +#define _ENIC_PP_H_ + +int enic_process_set_pp_request(struct enic *enic, + struct enic_port_profile *prev_pp, int *restore_pp); +int enic_process_get_pp_request(struct enic *enic, int request, + u16 *response); + +#endif /* _ENIC_PP_H_ */ diff --git a/drivers/net/enic/enic_res.c b/drivers/net/enic/enic_res.c index f111a37419ce..6e5c6356e7df 100644 --- a/drivers/net/enic/enic_res.c +++ b/drivers/net/enic/enic_res.c @@ -98,9 +98,9 @@ int enic_get_vnic_config(struct enic *enic) "vNIC MAC addr %pM wq/rq %d/%d mtu %d\n", enic->mac_addr, c->wq_desc_count, c->rq_desc_count, c->mtu); dev_info(enic_get_dev(enic), "vNIC csum tx/rx %d/%d " - "tso/lro %d/%d intr timer %d usec rss %d\n", + "tso %d intr timer %d usec rss %d\n", ENIC_SETTING(enic, TXCSUM), ENIC_SETTING(enic, RXCSUM), - ENIC_SETTING(enic, TSO), ENIC_SETTING(enic, LRO), + ENIC_SETTING(enic, TSO), c->intr_timer_usec, ENIC_SETTING(enic, RSS)); return 0; diff --git a/drivers/net/enic/vnic_dev.c b/drivers/net/enic/vnic_dev.c index c089b362a36f..68f24ae860ae 100644 --- a/drivers/net/enic/vnic_dev.c +++ b/drivers/net/enic/vnic_dev.c @@ -786,48 +786,6 @@ int vnic_dev_init(struct vnic_dev *vdev, int arg) return r; } -int vnic_dev_init_done(struct vnic_dev *vdev, int *done, int *err) -{ - u64 a0 = 0, a1 = 0; - int wait = 1000; - int ret; - - *done = 0; - - ret = vnic_dev_cmd(vdev, CMD_INIT_STATUS, &a0, &a1, wait); - if (ret) - return ret; - - *done = (a0 == 0); - - *err = (a0 == 0) ? (int)a1:0; - - return 0; -} - -int vnic_dev_init_prov(struct vnic_dev *vdev, u8 *buf, u32 len) -{ - u64 a0, a1 = len; - int wait = 1000; - dma_addr_t prov_pa; - void *prov_buf; - int ret; - - prov_buf = pci_alloc_consistent(vdev->pdev, len, &prov_pa); - if (!prov_buf) - return -ENOMEM; - - memcpy(prov_buf, buf, len); - - a0 = prov_pa; - - ret = vnic_dev_cmd(vdev, CMD_INIT_PROV_INFO, &a0, &a1, wait); - - pci_free_consistent(vdev->pdev, len, prov_buf, prov_pa); - - return ret; -} - int vnic_dev_deinit(struct vnic_dev *vdev) { u64 a0 = 0, a1 = 0; @@ -927,4 +885,59 @@ err_out: return NULL; } +int vnic_dev_init_prov2(struct vnic_dev *vdev, u8 *buf, u32 len) +{ + u64 a0, a1 = len; + int wait = 1000; + dma_addr_t prov_pa; + void *prov_buf; + int ret; + + prov_buf = pci_alloc_consistent(vdev->pdev, len, &prov_pa); + if (!prov_buf) + return -ENOMEM; + memcpy(prov_buf, buf, len); + + a0 = prov_pa; + + ret = vnic_dev_cmd(vdev, CMD_INIT_PROV_INFO2, &a0, &a1, wait); + + pci_free_consistent(vdev->pdev, len, prov_buf, prov_pa); + + return ret; +} + +int vnic_dev_enable2(struct vnic_dev *vdev, int active) +{ + u64 a0, a1 = 0; + int wait = 1000; + + a0 = (active ? CMD_ENABLE2_ACTIVE : 0); + + return vnic_dev_cmd(vdev, CMD_ENABLE2, &a0, &a1, wait); +} + +static int vnic_dev_cmd_status(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, + int *status) +{ + u64 a0 = cmd, a1 = 0; + int wait = 1000; + int ret; + + ret = vnic_dev_cmd(vdev, CMD_STATUS, &a0, &a1, wait); + if (!ret) + *status = (int)a0; + + return ret; +} + +int vnic_dev_enable2_done(struct vnic_dev *vdev, int *status) +{ + return vnic_dev_cmd_status(vdev, CMD_ENABLE2, status); +} + +int vnic_dev_deinit_done(struct vnic_dev *vdev, int *status) +{ + return vnic_dev_cmd_status(vdev, CMD_DEINIT, status); +} diff --git a/drivers/net/enic/vnic_dev.h b/drivers/net/enic/vnic_dev.h index e837546213a8..cf482a2c9dd9 100644 --- a/drivers/net/enic/vnic_dev.h +++ b/drivers/net/enic/vnic_dev.h @@ -108,8 +108,6 @@ int vnic_dev_disable(struct vnic_dev *vdev); int vnic_dev_open(struct vnic_dev *vdev, int arg); int vnic_dev_open_done(struct vnic_dev *vdev, int *done); int vnic_dev_init(struct vnic_dev *vdev, int arg); -int vnic_dev_init_done(struct vnic_dev *vdev, int *done, int *err); -int vnic_dev_init_prov(struct vnic_dev *vdev, u8 *buf, u32 len); int vnic_dev_deinit(struct vnic_dev *vdev); int vnic_dev_hang_reset(struct vnic_dev *vdev, int arg); int vnic_dev_hang_reset_done(struct vnic_dev *vdev, int *done); @@ -122,5 +120,9 @@ int vnic_dev_set_ig_vlan_rewrite_mode(struct vnic_dev *vdev, struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev, void *priv, struct pci_dev *pdev, struct vnic_dev_bar *bar, unsigned int num_bars); +int vnic_dev_init_prov2(struct vnic_dev *vdev, u8 *buf, u32 len); +int vnic_dev_enable2(struct vnic_dev *vdev, int active); +int vnic_dev_enable2_done(struct vnic_dev *vdev, int *status); +int vnic_dev_deinit_done(struct vnic_dev *vdev, int *status); #endif /* _VNIC_DEV_H_ */ diff --git a/drivers/net/enic/vnic_devcmd.h b/drivers/net/enic/vnic_devcmd.h index d833a071bac5..c5569bfb47ac 100644 --- a/drivers/net/enic/vnic_devcmd.h +++ b/drivers/net/enic/vnic_devcmd.h @@ -267,17 +267,62 @@ enum vnic_devcmd_cmd { /* * As for BY_BDF except a0 is index of hvnlink subordinate vnic - * or SR-IOV virtual vnic */ + * or SR-IOV virtual vnic + */ CMD_PROXY_BY_INDEX = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 43), /* - * in: (u64)a0=paddr of buffer to put latest VIC VIF-CONFIG-INFO TLV in - * (u32)a1=length of buffer in a0 - * out: (u64)a0=paddr of buffer with latest VIC VIF-CONFIG-INFO TLV - * (u32)a1=actual length of latest VIC VIF-CONFIG-INFO TLV */ + * For HPP toggle: + * adapter-info-get + * in: (u64)a0=phsical address of buffer passed in from caller. + * (u16)a1=size of buffer specified in a0. + * out: (u64)a0=phsical address of buffer passed in from caller. + * (u16)a1=actual bytes from VIF-CONFIG-INFO TLV, or + * 0 if no VIF-CONFIG-INFO TLV was ever received. */ CMD_CONFIG_INFO_GET = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 44), + + /* init_prov_info2: + * Variant of CMD_INIT_PROV_INFO, where it will not try to enable + * the vnic until CMD_ENABLE2 is issued. + * (u64)a0=paddr of vnic_devcmd_provinfo + * (u32)a1=sizeof provision info */ + CMD_INIT_PROV_INFO2 = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 47), + + /* enable2: + * (u32)a0=0 ==> standby + * =CMD_ENABLE2_ACTIVE ==> active + */ + CMD_ENABLE2 = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 48), + + /* + * cmd_status: + * Returns the status of the specified command + * Input: + * a0 = command for which status is being queried. + * Possible values are: + * CMD_SOFT_RESET + * CMD_HANG_RESET + * CMD_OPEN + * CMD_INIT + * CMD_INIT_PROV_INFO + * CMD_DEINIT + * CMD_INIT_PROV_INFO2 + * CMD_ENABLE2 + * Output: + * if status == STAT_ERROR + * a0 = ERR_ENOTSUPPORTED - status for command in a0 is + * not supported + * if status == STAT_NONE + * a0 = status of the devcmd specified in a0 as follows. + * ERR_SUCCESS - command in a0 completed successfully + * ERR_EINPROGRESS - command in a0 is still in progress + */ + CMD_STATUS = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 49), }; +/* CMD_ENABLE2 flags */ +#define CMD_ENABLE2_ACTIVE 0x1 + /* flags for CMD_OPEN */ #define CMD_OPENF_OPROM 0x1 /* open coming from option rom */ @@ -315,6 +360,8 @@ enum vnic_devcmd_error { ERR_ETIMEDOUT = 8, ERR_ELINKDOWN = 9, ERR_EMAXRES = 10, + ERR_ENOTSUPPORTED = 11, + ERR_EINPROGRESS = 12, }; /* diff --git a/drivers/net/enic/vnic_vic.c b/drivers/net/enic/vnic_vic.c index 4725b79de0ef..24ef8cd40545 100644 --- a/drivers/net/enic/vnic_vic.c +++ b/drivers/net/enic/vnic_vic.c @@ -23,7 +23,8 @@ #include "vnic_vic.h" -struct vic_provinfo *vic_provinfo_alloc(gfp_t flags, u8 *oui, u8 type) +struct vic_provinfo *vic_provinfo_alloc(gfp_t flags, const u8 *oui, + const u8 type) { struct vic_provinfo *vp; @@ -47,7 +48,7 @@ void vic_provinfo_free(struct vic_provinfo *vp) } int vic_provinfo_add_tlv(struct vic_provinfo *vp, u16 type, u16 length, - void *value) + const void *value) { struct vic_provinfo_tlv *tlv; diff --git a/drivers/net/enic/vnic_vic.h b/drivers/net/enic/vnic_vic.h index f700f5d9e81d..9ef81f148351 100644 --- a/drivers/net/enic/vnic_vic.h +++ b/drivers/net/enic/vnic_vic.h @@ -47,6 +47,7 @@ enum vic_generic_prov_os_type { VIC_GENERIC_PROV_OS_TYPE_ESX = 1, VIC_GENERIC_PROV_OS_TYPE_LINUX = 2, VIC_GENERIC_PROV_OS_TYPE_WINDOWS = 3, + VIC_GENERIC_PROV_OS_TYPE_SOLARIS = 4, }; struct vic_provinfo { @@ -61,14 +62,22 @@ struct vic_provinfo { } tlv[0]; } __packed; +#define VIC_PROVINFO_ADD_TLV(vp, tlvtype, tlvlen, data) \ + do { \ + err = vic_provinfo_add_tlv(vp, tlvtype, tlvlen, data); \ + if (err) \ + goto add_tlv_failure; \ + } while (0) + #define VIC_PROVINFO_MAX_DATA 1385 #define VIC_PROVINFO_MAX_TLV_DATA (VIC_PROVINFO_MAX_DATA - \ sizeof(struct vic_provinfo)) -struct vic_provinfo *vic_provinfo_alloc(gfp_t flags, u8 *oui, u8 type); +struct vic_provinfo *vic_provinfo_alloc(gfp_t flags, const u8 *oui, + const u8 type); void vic_provinfo_free(struct vic_provinfo *vp); int vic_provinfo_add_tlv(struct vic_provinfo *vp, u16 type, u16 length, - void *value); + const void *value); size_t vic_provinfo_size(struct vic_provinfo *vp); #endif /* _VNIC_VIC_H_ */ diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c index 380d0614a89a..17b6027d8be8 100644 --- a/drivers/net/ewrk3.c +++ b/drivers/net/ewrk3.c @@ -1604,55 +1604,47 @@ static u32 ewrk3_get_link(struct net_device *dev) return !(cmr & CMR_LINK); } -static int ewrk3_phys_id(struct net_device *dev, u32 data) +static int ewrk3_set_phys_id(struct net_device *dev, + enum ethtool_phys_id_state state) { struct ewrk3_private *lp = netdev_priv(dev); unsigned long iobase = dev->base_addr; - unsigned long flags; u8 cr; - int count; - - /* Toggle LED 4x per second */ - count = data << 2; - spin_lock_irqsave(&lp->hw_lock, flags); - - /* Bail if a PHYS_ID is already in progress */ - if (lp->led_mask == 0) { - spin_unlock_irqrestore(&lp->hw_lock, flags); - return -EBUSY; - } + spin_lock_irq(&lp->hw_lock); - /* Prevent ISR from twiddling the LED */ - lp->led_mask = 0; + switch (state) { + case ETHTOOL_ID_ACTIVE: + /* Prevent ISR from twiddling the LED */ + lp->led_mask = 0; + spin_unlock_irq(&lp->hw_lock); + return 2; /* cycle on/off twice per second */ - while (count--) { - /* Toggle the LED */ + case ETHTOOL_ID_ON: cr = inb(EWRK3_CR); - outb(cr ^ CR_LED, EWRK3_CR); + outb(cr | CR_LED, EWRK3_CR); + break; - /* Wait a little while */ - spin_unlock_irqrestore(&lp->hw_lock, flags); - msleep(250); - spin_lock_irqsave(&lp->hw_lock, flags); + case ETHTOOL_ID_OFF: + cr = inb(EWRK3_CR); + outb(cr & ~CR_LED, EWRK3_CR); + break; - /* Exit if we got a signal */ - if (signal_pending(current)) - break; + case ETHTOOL_ID_INACTIVE: + lp->led_mask = CR_LED; + cr = inb(EWRK3_CR); + outb(cr & ~CR_LED, EWRK3_CR); } + spin_unlock_irq(&lp->hw_lock); - lp->led_mask = CR_LED; - cr = inb(EWRK3_CR); - outb(cr & ~CR_LED, EWRK3_CR); - spin_unlock_irqrestore(&lp->hw_lock, flags); - return signal_pending(current) ? -ERESTARTSYS : 0; + return 0; } static const struct ethtool_ops ethtool_ops_203 = { .get_drvinfo = ewrk3_get_drvinfo, .get_settings = ewrk3_get_settings, .set_settings = ewrk3_set_settings, - .phys_id = ewrk3_phys_id, + .set_phys_id = ewrk3_set_phys_id, }; static const struct ethtool_ops ethtool_ops = { @@ -1660,7 +1652,7 @@ static const struct ethtool_ops ethtool_ops = { .get_settings = ewrk3_get_settings, .set_settings = ewrk3_set_settings, .get_link = ewrk3_get_link, - .phys_id = ewrk3_phys_id, + .set_phys_id = ewrk3_set_phys_id, }; /* diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index d5ab4dad5051..ec9a32d01e61 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -774,7 +774,6 @@ struct fe_priv { u32 driver_data; u32 device_id; u32 register_size; - int rx_csum; u32 mac_in_use; int mgmt_version; int mgmt_sema; @@ -4480,58 +4479,36 @@ static int nv_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam* return 0; } -static u32 nv_get_rx_csum(struct net_device *dev) +static u32 nv_fix_features(struct net_device *dev, u32 features) { - struct fe_priv *np = netdev_priv(dev); - return np->rx_csum != 0; + /* vlan is dependent on rx checksum offload */ + if (features & (NETIF_F_HW_VLAN_TX|NETIF_F_HW_VLAN_RX)) + features |= NETIF_F_RXCSUM; + + return features; } -static int nv_set_rx_csum(struct net_device *dev, u32 data) +static int nv_set_features(struct net_device *dev, u32 features) { struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); - int retcode = 0; + u32 changed = dev->features ^ features; - if (np->driver_data & DEV_HAS_CHECKSUM) { - if (data) { - np->rx_csum = 1; - np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK; - } else { - np->rx_csum = 0; - /* vlan is dependent on rx checksum offload */ - if (!(np->vlanctl_bits & NVREG_VLANCONTROL_ENABLE)) - np->txrxctl_bits &= ~NVREG_TXRXCTL_RXCHECK; - } - if (netif_running(dev)) { - spin_lock_irq(&np->lock); - writel(np->txrxctl_bits, base + NvRegTxRxControl); - spin_unlock_irq(&np->lock); - } - } else { - return -EINVAL; - } - - return retcode; -} + if (changed & NETIF_F_RXCSUM) { + spin_lock_irq(&np->lock); -static int nv_set_tx_csum(struct net_device *dev, u32 data) -{ - struct fe_priv *np = netdev_priv(dev); + if (features & NETIF_F_RXCSUM) + np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK; + else + np->txrxctl_bits &= ~NVREG_TXRXCTL_RXCHECK; - if (np->driver_data & DEV_HAS_CHECKSUM) - return ethtool_op_set_tx_csum(dev, data); - else - return -EOPNOTSUPP; -} + if (netif_running(dev)) + writel(np->txrxctl_bits, base + NvRegTxRxControl); -static int nv_set_sg(struct net_device *dev, u32 data) -{ - struct fe_priv *np = netdev_priv(dev); + spin_unlock_irq(&np->lock); + } - if (np->driver_data & DEV_HAS_CHECKSUM) - return ethtool_op_set_sg(dev, data); - else - return -EOPNOTSUPP; + return 0; } static int nv_get_sset_count(struct net_device *dev, int sset) @@ -4896,15 +4873,10 @@ static const struct ethtool_ops ops = { .get_regs_len = nv_get_regs_len, .get_regs = nv_get_regs, .nway_reset = nv_nway_reset, - .set_tso = nv_set_tso, .get_ringparam = nv_get_ringparam, .set_ringparam = nv_set_ringparam, .get_pauseparam = nv_get_pauseparam, .set_pauseparam = nv_set_pauseparam, - .get_rx_csum = nv_get_rx_csum, - .set_rx_csum = nv_set_rx_csum, - .set_tx_csum = nv_set_tx_csum, - .set_sg = nv_set_sg, .get_strings = nv_get_strings, .get_ethtool_stats = nv_get_ethtool_stats, .get_sset_count = nv_get_sset_count, @@ -5235,6 +5207,8 @@ static const struct net_device_ops nv_netdev_ops = { .ndo_start_xmit = nv_start_xmit, .ndo_tx_timeout = nv_tx_timeout, .ndo_change_mtu = nv_change_mtu, + .ndo_fix_features = nv_fix_features, + .ndo_set_features = nv_set_features, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = nv_set_mac_address, .ndo_set_multicast_list = nv_set_multicast, @@ -5251,6 +5225,8 @@ static const struct net_device_ops nv_netdev_ops_optimized = { .ndo_start_xmit = nv_start_xmit_optimized, .ndo_tx_timeout = nv_tx_timeout, .ndo_change_mtu = nv_change_mtu, + .ndo_fix_features = nv_fix_features, + .ndo_set_features = nv_set_features, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = nv_set_mac_address, .ndo_set_multicast_list = nv_set_multicast, @@ -5364,11 +5340,10 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i np->pkt_limit = NV_PKTLIMIT_2; if (id->driver_data & DEV_HAS_CHECKSUM) { - np->rx_csum = 1; np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK; - dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; - dev->features |= NETIF_F_TSO; - dev->features |= NETIF_F_GRO; + dev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_SG | + NETIF_F_TSO | NETIF_F_RXCSUM; + dev->features |= dev->hw_features; } np->vlanctl_bits = 0; @@ -5384,7 +5359,6 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i np->pause_flags |= NV_PAUSEFRAME_TX_CAPABLE | NV_PAUSEFRAME_TX_REQ; } - err = -ENOMEM; np->base = ioremap(addr, np->register_size); if (!np->base) diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index 24cb953900dd..a9388944f1d3 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -956,8 +956,6 @@ static const struct ethtool_ops fs_ethtool_ops = { .get_link = ethtool_op_get_link, .get_msglevel = fs_get_msglevel, .set_msglevel = fs_set_msglevel, - .set_tx_csum = ethtool_op_set_tx_csum, /* local! */ - .set_sg = ethtool_op_set_sg, .get_regs = fs_get_regs, }; diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 2a0ad9a501bb..ff60b23a5b74 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -365,7 +365,7 @@ static void gfar_init_mac(struct net_device *ndev) gfar_write(®s->rir0, DEFAULT_RIR0); } - if (priv->rx_csum_enable) + if (ndev->features & NETIF_F_RXCSUM) rctrl |= RCTRL_CHECKSUMMING; if (priv->extended_hash) { @@ -463,6 +463,7 @@ static const struct net_device_ops gfar_netdev_ops = { .ndo_start_xmit = gfar_start_xmit, .ndo_stop = gfar_close, .ndo_change_mtu = gfar_change_mtu, + .ndo_set_features = gfar_set_features, .ndo_set_multicast_list = gfar_set_multi, .ndo_tx_timeout = gfar_timeout, .ndo_do_ioctl = gfar_ioctl, @@ -513,7 +514,7 @@ void unlock_tx_qs(struct gfar_private *priv) /* Returns 1 if incoming frames use an FCB */ static inline int gfar_uses_fcb(struct gfar_private *priv) { - return priv->vlgrp || priv->rx_csum_enable || + return priv->vlgrp || (priv->ndev->features & NETIF_F_RXCSUM) || (priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER); } @@ -1030,10 +1031,11 @@ static int gfar_probe(struct platform_device *ofdev) netif_napi_add(dev, &priv->gfargrp[i].napi, gfar_poll, GFAR_DEV_WEIGHT); if (priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) { - priv->rx_csum_enable = 1; - dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_HIGHDMA; - } else - priv->rx_csum_enable = 0; + dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG | + NETIF_F_RXCSUM; + dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG | + NETIF_F_RXCSUM | NETIF_F_HIGHDMA; + } priv->vlgrp = NULL; @@ -2697,7 +2699,7 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, if (priv->padding) skb_pull(skb, priv->padding); - if (priv->rx_csum_enable) + if (dev->features & NETIF_F_RXCSUM) gfar_rx_checksum(skb, fcb); /* Tell the skb what kind of packet this is */ diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index b2fe7edefad9..fc86f5195445 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -382,23 +382,6 @@ extern const char gfar_driver_version[]; #define BD_LFLAG(flags) ((flags) << 16) #define BD_LENGTH_MASK 0x0000ffff -#define CLASS_CODE_UNRECOG 0x00 -#define CLASS_CODE_DUMMY1 0x01 -#define CLASS_CODE_ETHERTYPE1 0x02 -#define CLASS_CODE_ETHERTYPE2 0x03 -#define CLASS_CODE_USER_PROG1 0x04 -#define CLASS_CODE_USER_PROG2 0x05 -#define CLASS_CODE_USER_PROG3 0x06 -#define CLASS_CODE_USER_PROG4 0x07 -#define CLASS_CODE_TCP_IPV4 0x08 -#define CLASS_CODE_UDP_IPV4 0x09 -#define CLASS_CODE_AH_ESP_IPV4 0x0a -#define CLASS_CODE_SCTP_IPV4 0x0b -#define CLASS_CODE_TCP_IPV6 0x0c -#define CLASS_CODE_UDP_IPV6 0x0d -#define CLASS_CODE_AH_ESP_IPV6 0x0e -#define CLASS_CODE_SCTP_IPV6 0x0f - #define FPR_FILER_MASK 0xFFFFFFFF #define MAX_FILER_IDX 0xFF @@ -1100,7 +1083,7 @@ struct gfar_private { struct device_node *phy_node; struct device_node *tbi_node; u32 device_flags; - unsigned char rx_csum_enable:1, + unsigned char extended_hash:1, bd_stash_en:1, rx_filer_enable:1, @@ -1170,6 +1153,7 @@ extern void gfar_phy_test(struct mii_bus *bus, struct phy_device *phydev, extern void gfar_configure_coalescing(struct gfar_private *priv, unsigned long tx_mask, unsigned long rx_mask); void gfar_init_sysfs(struct net_device *dev); +int gfar_set_features(struct net_device *dev, u32 features); extern const struct ethtool_ops gfar_ethtool_ops; diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c index 3bc8e276ba4d..493d743839d9 100644 --- a/drivers/net/gianfar_ethtool.c +++ b/drivers/net/gianfar_ethtool.c @@ -517,15 +517,15 @@ static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rva return err; } -static int gfar_set_rx_csum(struct net_device *dev, uint32_t data) +int gfar_set_features(struct net_device *dev, u32 features) { struct gfar_private *priv = netdev_priv(dev); unsigned long flags; int err = 0, i = 0; + u32 changed = dev->features ^ features; - if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM)) - return -EOPNOTSUPP; - + if (!(changed & NETIF_F_RXCSUM)) + return 0; if (dev->flags & IFF_UP) { /* Halt TX and RX, and process the frames which @@ -546,58 +546,15 @@ static int gfar_set_rx_csum(struct net_device *dev, uint32_t data) /* Now we take down the rings to rebuild them */ stop_gfar(dev); - } - spin_lock_irqsave(&priv->bflock, flags); - priv->rx_csum_enable = data; - spin_unlock_irqrestore(&priv->bflock, flags); + dev->features = features; - if (dev->flags & IFF_UP) { err = startup_gfar(dev); netif_tx_wake_all_queues(dev); } return err; } -static uint32_t gfar_get_rx_csum(struct net_device *dev) -{ - struct gfar_private *priv = netdev_priv(dev); - - if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM)) - return 0; - - return priv->rx_csum_enable; -} - -static int gfar_set_tx_csum(struct net_device *dev, uint32_t data) -{ - struct gfar_private *priv = netdev_priv(dev); - - if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM)) - return -EOPNOTSUPP; - - netif_tx_lock_bh(dev); - - if (data) - dev->features |= NETIF_F_IP_CSUM; - else - dev->features &= ~NETIF_F_IP_CSUM; - - netif_tx_unlock_bh(dev); - - return 0; -} - -static uint32_t gfar_get_tx_csum(struct net_device *dev) -{ - struct gfar_private *priv = netdev_priv(dev); - - if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM)) - return 0; - - return (dev->features & NETIF_F_IP_CSUM) != 0; -} - static uint32_t gfar_get_msglevel(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); @@ -645,42 +602,6 @@ static int gfar_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) } #endif -static int gfar_ethflow_to_class(int flow_type, u64 *class) -{ - switch (flow_type) { - case TCP_V4_FLOW: - *class = CLASS_CODE_TCP_IPV4; - break; - case UDP_V4_FLOW: - *class = CLASS_CODE_UDP_IPV4; - break; - case AH_V4_FLOW: - case ESP_V4_FLOW: - *class = CLASS_CODE_AH_ESP_IPV4; - break; - case SCTP_V4_FLOW: - *class = CLASS_CODE_SCTP_IPV4; - break; - case TCP_V6_FLOW: - *class = CLASS_CODE_TCP_IPV6; - break; - case UDP_V6_FLOW: - *class = CLASS_CODE_UDP_IPV6; - break; - case AH_V6_FLOW: - case ESP_V6_FLOW: - *class = CLASS_CODE_AH_ESP_IPV6; - break; - case SCTP_V6_FLOW: - *class = CLASS_CODE_SCTP_IPV6; - break; - default: - return 0; - } - - return 1; -} - static void ethflow_to_filer_rules (struct gfar_private *priv, u64 ethflow) { u32 fcr = 0x0, fpr = FPR_FILER_MASK; @@ -778,11 +699,6 @@ static int gfar_ethflow_to_filer_table(struct gfar_private *priv, u64 ethflow, u case UDP_V6_FLOW: cmp_rqfpr = RQFPR_IPV6 |RQFPR_UDP; break; - case IPV4_FLOW: - cmp_rqfpr = RQFPR_IPV4; - case IPV6_FLOW: - cmp_rqfpr = RQFPR_IPV6; - break; default: printk(KERN_ERR "Right now this class is not supported\n"); return 0; @@ -848,18 +764,9 @@ static int gfar_ethflow_to_filer_table(struct gfar_private *priv, u64 ethflow, u static int gfar_set_hash_opts(struct gfar_private *priv, struct ethtool_rxnfc *cmd) { - u64 class; - - if (!gfar_ethflow_to_class(cmd->flow_type, &class)) - return -EINVAL; - - if (class < CLASS_CODE_USER_PROG1 || - class > CLASS_CODE_SCTP_IPV6) - return -EINVAL; - /* write the filer rules here */ if (!gfar_ethflow_to_filer_table(priv, cmd->data, cmd->flow_type)) - return -1; + return -EINVAL; return 0; } @@ -894,11 +801,6 @@ const struct ethtool_ops gfar_ethtool_ops = { .get_strings = gfar_gstrings, .get_sset_count = gfar_sset_count, .get_ethtool_stats = gfar_fill_stats, - .get_rx_csum = gfar_get_rx_csum, - .get_tx_csum = gfar_get_tx_csum, - .set_rx_csum = gfar_set_rx_csum, - .set_tx_csum = gfar_set_tx_csum, - .set_sg = ethtool_op_set_sg, .get_msglevel = gfar_get_msglevel, .set_msglevel = gfar_set_msglevel, #ifdef CONFIG_PM diff --git a/drivers/net/greth.c b/drivers/net/greth.c index 396ff7d785d1..f181304a7ab6 100644 --- a/drivers/net/greth.c +++ b/drivers/net/greth.c @@ -901,7 +901,7 @@ static int greth_rx_gbit(struct net_device *dev, int limit) skb_put(skb, pkt_len); - if (greth->flags & GRETH_FLAG_RX_CSUM && hw_checksummed(status)) + if (dev->features & NETIF_F_RXCSUM && hw_checksummed(status)) skb->ip_summed = CHECKSUM_UNNECESSARY; else skb_checksum_none_assert(skb); @@ -1142,41 +1142,6 @@ static void greth_get_regs(struct net_device *dev, struct ethtool_regs *regs, vo buff[i] = greth_read_bd(&greth_regs[i]); } -static u32 greth_get_rx_csum(struct net_device *dev) -{ - struct greth_private *greth = netdev_priv(dev); - return (greth->flags & GRETH_FLAG_RX_CSUM) != 0; -} - -static int greth_set_rx_csum(struct net_device *dev, u32 data) -{ - struct greth_private *greth = netdev_priv(dev); - - spin_lock_bh(&greth->devlock); - - if (data) - greth->flags |= GRETH_FLAG_RX_CSUM; - else - greth->flags &= ~GRETH_FLAG_RX_CSUM; - - spin_unlock_bh(&greth->devlock); - - return 0; -} - -static u32 greth_get_tx_csum(struct net_device *dev) -{ - return (dev->features & NETIF_F_IP_CSUM) != 0; -} - -static int greth_set_tx_csum(struct net_device *dev, u32 data) -{ - netif_tx_lock_bh(dev); - ethtool_op_set_tx_csum(dev, data); - netif_tx_unlock_bh(dev); - return 0; -} - static const struct ethtool_ops greth_ethtool_ops = { .get_msglevel = greth_get_msglevel, .set_msglevel = greth_set_msglevel, @@ -1185,10 +1150,6 @@ static const struct ethtool_ops greth_ethtool_ops = { .get_drvinfo = greth_get_drvinfo, .get_regs_len = greth_get_regs_len, .get_regs = greth_get_regs, - .get_rx_csum = greth_get_rx_csum, - .set_rx_csum = greth_set_rx_csum, - .get_tx_csum = greth_get_tx_csum, - .set_tx_csum = greth_set_tx_csum, .get_link = ethtool_op_get_link, }; @@ -1570,9 +1531,10 @@ static int __devinit greth_of_probe(struct platform_device *ofdev) GRETH_REGSAVE(regs->status, 0xFF); if (greth->gbit_mac) { - dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_HIGHDMA; + dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | + NETIF_F_RXCSUM; + dev->features = dev->hw_features | NETIF_F_HIGHDMA; greth_netdev_ops.ndo_start_xmit = greth_start_xmit_gbit; - greth->flags = GRETH_FLAG_RX_CSUM; } if (greth->multicast) { diff --git a/drivers/net/greth.h b/drivers/net/greth.h index be0f2062bd14..9a0040dee4da 100644 --- a/drivers/net/greth.h +++ b/drivers/net/greth.h @@ -77,9 +77,6 @@ */ #define MAX_FRAME_SIZE 1520 -/* Flags */ -#define GRETH_FLAG_RX_CSUM 0x1 - /* GRETH APB registers */ struct greth_regs { u32 control; @@ -133,7 +130,6 @@ struct greth_private { unsigned int duplex; u32 msg_enable; - u32 flags; u8 phyaddr; u8 multicast; diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index 8e10d2f6a5ad..c52a1df5d922 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -188,14 +188,14 @@ struct hp100_private { * variables */ #ifdef CONFIG_ISA -static const char *hp100_isa_tbl[] = { +static const char *const hp100_isa_tbl[] __devinitconst = { "HWPF150", /* HP J2573 rev A */ "HWP1950", /* HP J2573 */ }; #endif #ifdef CONFIG_EISA -static struct eisa_device_id hp100_eisa_tbl[] = { +static const struct eisa_device_id hp100_eisa_tbl[] __devinitconst = { { "HWPF180" }, /* HP J2577 rev A */ { "HWP1920" }, /* HP 27248B */ { "HWP1940" }, /* HP J2577 */ @@ -336,7 +336,7 @@ static __devinit const char *hp100_read_id(int ioaddr) } #ifdef CONFIG_ISA -static __init int hp100_isa_probe1(struct net_device *dev, int ioaddr) +static __devinit int hp100_isa_probe1(struct net_device *dev, int ioaddr) { const char *sig; int i; @@ -372,7 +372,7 @@ static __init int hp100_isa_probe1(struct net_device *dev, int ioaddr) * EISA and PCI are handled by device infrastructure. */ -static int __init hp100_isa_probe(struct net_device *dev, int addr) +static int __devinit hp100_isa_probe(struct net_device *dev, int addr) { int err = -ENODEV; @@ -396,7 +396,7 @@ static int __init hp100_isa_probe(struct net_device *dev, int addr) #endif /* CONFIG_ISA */ #if !defined(MODULE) && defined(CONFIG_ISA) -struct net_device * __init hp100_probe(int unit) +struct net_device * __devinit hp100_probe(int unit) { struct net_device *dev = alloc_etherdev(sizeof(struct hp100_private)); int err; @@ -2843,7 +2843,7 @@ static void cleanup_dev(struct net_device *d) } #ifdef CONFIG_EISA -static int __init hp100_eisa_probe (struct device *gendev) +static int __devinit hp100_eisa_probe (struct device *gendev) { struct net_device *dev = alloc_etherdev(sizeof(struct hp100_private)); struct eisa_device *edev = to_eisa_device(gendev); diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index 3bb990b6651a..079450fe5e96 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c @@ -2053,13 +2053,6 @@ static void emac_ethtool_get_pauseparam(struct net_device *ndev, mutex_unlock(&dev->link_lock); } -static u32 emac_ethtool_get_rx_csum(struct net_device *ndev) -{ - struct emac_instance *dev = netdev_priv(ndev); - - return dev->tah_dev != NULL; -} - static int emac_get_regs_len(struct emac_instance *dev) { if (emac_has_feature(dev, EMAC_FTR_EMAC4)) @@ -2203,15 +2196,11 @@ static const struct ethtool_ops emac_ethtool_ops = { .get_ringparam = emac_ethtool_get_ringparam, .get_pauseparam = emac_ethtool_get_pauseparam, - .get_rx_csum = emac_ethtool_get_rx_csum, - .get_strings = emac_ethtool_get_strings, .get_sset_count = emac_ethtool_get_sset_count, .get_ethtool_stats = emac_ethtool_get_ethtool_stats, .get_link = ethtool_op_get_link, - .get_tx_csum = ethtool_op_get_tx_csum, - .get_sg = ethtool_op_get_sg, }; static int emac_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) @@ -2859,8 +2848,10 @@ static int __devinit emac_probe(struct platform_device *ofdev) if (err != 0) goto err_detach_tah; - if (dev->tah_dev) - ndev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; + if (dev->tah_dev) { + ndev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG; + ndev->features |= ndev->hw_features | NETIF_F_RXCSUM; + } ndev->watchdog_timeo = 5 * HZ; if (emac_phy_supports_gige(dev->phy_mode)) { ndev->netdev_ops = &emac_gige_netdev_ops; diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c index 8ff68ae6b520..136d7544cc33 100644 --- a/drivers/net/ibmlana.c +++ b/drivers/net/ibmlana.c @@ -782,7 +782,8 @@ static int ibmlana_open(struct net_device *dev) /* register resources - only necessary for IRQ */ - result = request_irq(priv->realirq, irq_handler, IRQF_SHARED | IRQF_SAMPLE_RANDOM, dev->name, dev); + result = request_irq(priv->realirq, irq_handler, IRQF_SHARED, + dev->name, dev); if (result != 0) { printk(KERN_ERR "%s: failed to register irq %d\n", dev->name, dev->irq); return result; @@ -894,12 +895,12 @@ static int ibmlana_irq; static int ibmlana_io; static int startslot; /* counts through slots when probing multiple devices */ -static short ibmlana_adapter_ids[] __initdata = { +static const short ibmlana_adapter_ids[] __devinitconst = { IBM_LANA_ID, 0x0000 }; -static char *ibmlana_adapter_names[] __devinitdata = { +static const char *const ibmlana_adapter_names[] __devinitconst = { "IBM LAN Adapter/A", NULL }; diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c index 6b256c275e10..0cd41c49bc17 100644 --- a/drivers/net/igb/e1000_82575.c +++ b/drivers/net/igb/e1000_82575.c @@ -1877,7 +1877,7 @@ static s32 igb_validate_nvm_checksum_82580(struct e1000_hw *hw) } if (nvm_data & NVM_COMPATIBILITY_BIT_MASK) { - /* if chekcsums compatibility bit is set validate checksums + /* if checksums compatibility bit is set validate checksums * for all 4 ports. */ eeprom_regions_count = 4; } @@ -1988,6 +1988,7 @@ static s32 igb_update_nvm_checksum_i350(struct e1000_hw *hw) out: return ret_val; } + /** * igb_set_eee_i350 - Enable/disable EEE support * @hw: pointer to the HW structure diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 0dfd1b93829e..cdfd57271051 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -3532,6 +3532,25 @@ bool igb_has_link(struct igb_adapter *adapter) return link_active; } +static bool igb_thermal_sensor_event(struct e1000_hw *hw, u32 event) +{ + bool ret = false; + u32 ctrl_ext, thstat; + + /* check for thermal sensor event on i350, copper only */ + if (hw->mac.type == e1000_i350) { + thstat = rd32(E1000_THSTAT); + ctrl_ext = rd32(E1000_CTRL_EXT); + + if ((hw->phy.media_type == e1000_media_type_copper) && + !(ctrl_ext & E1000_CTRL_EXT_LINK_MODE_SGMII)) { + ret = !!(thstat & event); + } + } + + return ret; +} + /** * igb_watchdog - Timer Call-back * @data: pointer to adapter cast into an unsigned long @@ -3550,7 +3569,7 @@ static void igb_watchdog_task(struct work_struct *work) watchdog_task); struct e1000_hw *hw = &adapter->hw; struct net_device *netdev = adapter->netdev; - u32 link, ctrl_ext, thstat; + u32 link; int i; link = igb_has_link(adapter); @@ -3574,25 +3593,14 @@ static void igb_watchdog_task(struct work_struct *work) ((ctrl & E1000_CTRL_RFCE) ? "RX" : ((ctrl & E1000_CTRL_TFCE) ? "TX" : "None"))); - /* check for thermal sensor event on i350, - * copper only */ - if (hw->mac.type == e1000_i350) { - thstat = rd32(E1000_THSTAT); - ctrl_ext = rd32(E1000_CTRL_EXT); - if ((hw->phy.media_type == - e1000_media_type_copper) && !(ctrl_ext & - E1000_CTRL_EXT_LINK_MODE_SGMII)) { - if (thstat & - E1000_THSTAT_LINK_THROTTLE) { - printk(KERN_INFO "igb: %s The " - "network adapter link " - "speed was downshifted " - "because it " - "overheated.\n", - netdev->name); - } - } + /* check for thermal sensor event */ + if (igb_thermal_sensor_event(hw, E1000_THSTAT_LINK_THROTTLE)) { + printk(KERN_INFO "igb: %s The network adapter " + "link speed was downshifted " + "because it overheated.\n", + netdev->name); } + /* adjust timeout factor according to speed/duplex */ adapter->tx_timeout_factor = 1; switch (adapter->link_speed) { @@ -3618,22 +3626,15 @@ static void igb_watchdog_task(struct work_struct *work) if (netif_carrier_ok(netdev)) { adapter->link_speed = 0; adapter->link_duplex = 0; - /* check for thermal sensor event on i350 - * copper only*/ - if (hw->mac.type == e1000_i350) { - thstat = rd32(E1000_THSTAT); - ctrl_ext = rd32(E1000_CTRL_EXT); - if ((hw->phy.media_type == - e1000_media_type_copper) && !(ctrl_ext & - E1000_CTRL_EXT_LINK_MODE_SGMII)) { - if (thstat & E1000_THSTAT_PWR_DOWN) { - printk(KERN_ERR "igb: %s The " - "network adapter was stopped " - "because it overheated.\n", + + /* check for thermal sensor event */ + if (igb_thermal_sensor_event(hw, E1000_THSTAT_PWR_DOWN)) { + printk(KERN_ERR "igb: %s The network adapter " + "was stopped because it " + "overheated.\n", netdev->name); - } - } } + /* Links status message must follow this format */ printk(KERN_INFO "igb: %s NIC Link is Down\n", netdev->name); diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index c8ee8d28767b..96c95617195f 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c @@ -90,8 +90,6 @@ struct ioc3_private { u32 emcr, ehar_h, ehar_l; spinlock_t ioc3_lock; struct mii_if_info mii; - unsigned long flags; -#define IOC3_FLAG_RX_CHECKSUMS 1 struct pci_dev *pdev; @@ -609,7 +607,7 @@ static inline void ioc3_rx(struct net_device *dev) goto next; } - if (likely(ip->flags & IOC3_FLAG_RX_CHECKSUMS)) + if (likely(dev->features & NETIF_F_RXCSUM)) ioc3_tcpudp_checksum(skb, w0 & ERXBUF_IPCKSUM_MASK, len); @@ -1328,6 +1326,7 @@ static int __devinit ioc3_probe(struct pci_dev *pdev, dev->watchdog_timeo = 5 * HZ; dev->netdev_ops = &ioc3_netdev_ops; dev->ethtool_ops = &ioc3_ethtool_ops; + dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM; dev->features = NETIF_F_IP_CSUM; sw_physid1 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID1); @@ -1618,37 +1617,12 @@ static u32 ioc3_get_link(struct net_device *dev) return rc; } -static u32 ioc3_get_rx_csum(struct net_device *dev) -{ - struct ioc3_private *ip = netdev_priv(dev); - - return ip->flags & IOC3_FLAG_RX_CHECKSUMS; -} - -static int ioc3_set_rx_csum(struct net_device *dev, u32 data) -{ - struct ioc3_private *ip = netdev_priv(dev); - - spin_lock_bh(&ip->ioc3_lock); - if (data) - ip->flags |= IOC3_FLAG_RX_CHECKSUMS; - else - ip->flags &= ~IOC3_FLAG_RX_CHECKSUMS; - spin_unlock_bh(&ip->ioc3_lock); - - return 0; -} - static const struct ethtool_ops ioc3_ethtool_ops = { .get_drvinfo = ioc3_get_drvinfo, .get_settings = ioc3_get_settings, .set_settings = ioc3_set_settings, .nway_reset = ioc3_nway_reset, .get_link = ioc3_get_link, - .get_rx_csum = ioc3_get_rx_csum, - .set_rx_csum = ioc3_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_csum }; static int ioc3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index 8800e1fe4129..69b5707db369 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -222,19 +222,19 @@ static void smsc_ircc_set_transceiver_for_speed(struct smsc_ircc_cb *self, u32 s static void smsc_ircc_sir_wait_hw_transmitter_finish(struct smsc_ircc_cb *self); /* Probing */ -static int __init smsc_ircc_look_for_chips(void); -static const struct smsc_chip * __init smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type); -static int __init smsc_superio_flat(const struct smsc_chip *chips, unsigned short cfg_base, char *type); -static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned short cfg_base, char *type); -static int __init smsc_superio_fdc(unsigned short cfg_base); -static int __init smsc_superio_lpc(unsigned short cfg_base); +static int smsc_ircc_look_for_chips(void); +static const struct smsc_chip * smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type); +static int smsc_superio_flat(const struct smsc_chip *chips, unsigned short cfg_base, char *type); +static int smsc_superio_paged(const struct smsc_chip *chips, unsigned short cfg_base, char *type); +static int smsc_superio_fdc(unsigned short cfg_base); +static int smsc_superio_lpc(unsigned short cfg_base); #ifdef CONFIG_PCI -static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf); -static int __init preconfigure_through_82801(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); -static void __init preconfigure_ali_port(struct pci_dev *dev, +static int preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf); +static int preconfigure_through_82801(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); +static void preconfigure_ali_port(struct pci_dev *dev, unsigned short port); -static int __init preconfigure_through_ali(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); -static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, +static int preconfigure_through_ali(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); +static int smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, unsigned short ircc_fir, unsigned short ircc_sir, unsigned char ircc_dma, @@ -366,7 +366,7 @@ static inline void register_bank(int iobase, int bank) } /* PNP hotplug support */ -static const struct pnp_device_id smsc_ircc_pnp_table[] = { +static const struct pnp_device_id smsc_ircc_pnp_table[] __devinitconst = { { .id = "SMCf010", .driver_data = 0 }, /* and presumably others */ { } @@ -515,7 +515,7 @@ static const struct net_device_ops smsc_ircc_netdev_ops = { * Try to open driver instance * */ -static int __init smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u8 dma, u8 irq) +static int __devinit smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u8 dma, u8 irq) { struct smsc_ircc_cb *self; struct net_device *dev; @@ -2273,7 +2273,7 @@ static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned sho } -static int __init smsc_access(unsigned short cfg_base, unsigned char reg) +static int __devinit smsc_access(unsigned short cfg_base, unsigned char reg) { IRDA_DEBUG(1, "%s\n", __func__); @@ -2281,7 +2281,7 @@ static int __init smsc_access(unsigned short cfg_base, unsigned char reg) return inb(cfg_base) != reg ? -1 : 0; } -static const struct smsc_chip * __init smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type) +static const struct smsc_chip * __devinit smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type) { u8 devid, xdevid, rev; @@ -2406,7 +2406,7 @@ static int __init smsc_superio_lpc(unsigned short cfg_base) #ifdef CONFIG_PCI #define PCIID_VENDOR_INTEL 0x8086 #define PCIID_VENDOR_ALI 0x10b9 -static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __initdata = { +static const struct smsc_ircc_subsystem_configuration subsystem_configurations[] __devinitconst = { /* * Subsystems needing entries: * 0x10b9:0x1533 0x103c:0x0850 HP nx9010 family @@ -2532,7 +2532,7 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __ini * (FIR port, SIR port, FIR DMA, FIR IRQ) * through the chip configuration port. */ -static int __init preconfigure_smsc_chip(struct +static int __devinit preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf) { @@ -2633,7 +2633,7 @@ static int __init preconfigure_smsc_chip(struct * or Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge. * They all work the same way! */ -static int __init preconfigure_through_82801(struct pci_dev *dev, +static int __devinit preconfigure_through_82801(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf) @@ -2786,7 +2786,7 @@ static int __init preconfigure_through_82801(struct pci_dev *dev, * This is based on reverse-engineering since ALi does not * provide any data sheet for the 1533 chip. */ -static void __init preconfigure_ali_port(struct pci_dev *dev, +static void __devinit preconfigure_ali_port(struct pci_dev *dev, unsigned short port) { unsigned char reg; @@ -2824,7 +2824,7 @@ static void __init preconfigure_ali_port(struct pci_dev *dev, IRDA_MESSAGE("Activated ALi 1533 ISA bridge port 0x%04x.\n", port); } -static int __init preconfigure_through_ali(struct pci_dev *dev, +static int __devinit preconfigure_through_ali(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf) @@ -2837,7 +2837,7 @@ static int __init preconfigure_through_ali(struct pci_dev *dev, return preconfigure_smsc_chip(conf); } -static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, +static int __devinit smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, unsigned short ircc_fir, unsigned short ircc_sir, unsigned char ircc_dma, @@ -2849,7 +2849,7 @@ static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, int ret = 0; for_each_pci_dev(dev) { - struct smsc_ircc_subsystem_configuration *conf; + const struct smsc_ircc_subsystem_configuration *conf; /* * Cache the subsystem vendor/device: diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c index 845c679c8b87..7a64f50435cf 100644 --- a/drivers/net/ixgbe/ixgbe_82598.c +++ b/drivers/net/ixgbe/ixgbe_82598.c @@ -37,6 +37,7 @@ #define IXGBE_82598_RAR_ENTRIES 16 #define IXGBE_82598_MC_TBL_SIZE 128 #define IXGBE_82598_VFT_TBL_SIZE 128 +#define IXGBE_82598_RX_PB_SIZE 512 static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw, ixgbe_link_speed speed, @@ -197,14 +198,35 @@ out: * @hw: pointer to hardware structure * * Starts the hardware using the generic start_hw function. - * Then set pcie completion timeout + * Disables relaxed ordering Then set pcie completion timeout + * **/ static s32 ixgbe_start_hw_82598(struct ixgbe_hw *hw) { + u32 regval; + u32 i; s32 ret_val = 0; ret_val = ixgbe_start_hw_generic(hw); + /* Disable relaxed ordering */ + for (i = 0; ((i < hw->mac.max_tx_queues) && + (i < IXGBE_DCA_MAX_QUEUES_82598)); i++) { + regval = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(i)); + regval &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN; + IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(i), regval); + } + + for (i = 0; ((i < hw->mac.max_rx_queues) && + (i < IXGBE_DCA_MAX_QUEUES_82598)); i++) { + regval = IXGBE_READ_REG(hw, IXGBE_DCA_RXCTRL(i)); + regval &= ~(IXGBE_DCA_RXCTRL_DESC_WRO_EN | + IXGBE_DCA_RXCTRL_DESC_HSRO_EN); + IXGBE_WRITE_REG(hw, IXGBE_DCA_RXCTRL(i), regval); + } + + hw->mac.rx_pb_size = IXGBE_82598_RX_PB_SIZE; + /* set the completion timeout for interface */ if (ret_val == 0) ixgbe_set_pcie_completion_timeout(hw); @@ -1064,7 +1086,7 @@ static s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset, sfp_stat = sfp_stat & IXGBE_I2C_EEPROM_STATUS_MASK; if (sfp_stat != IXGBE_I2C_EEPROM_STATUS_IN_PROGRESS) break; - msleep(10); + usleep_range(10000, 20000); } if (sfp_stat != IXGBE_I2C_EEPROM_STATUS_PASS) { @@ -1188,6 +1210,38 @@ out: return physical_layer; } +/** + * ixgbe_set_lan_id_multi_port_pcie_82598 - Set LAN id for PCIe multiple + * port devices. + * @hw: pointer to the HW structure + * + * Calls common function and corrects issue with some single port devices + * that enable LAN1 but not LAN0. + **/ +static void ixgbe_set_lan_id_multi_port_pcie_82598(struct ixgbe_hw *hw) +{ + struct ixgbe_bus_info *bus = &hw->bus; + u16 pci_gen = 0; + u16 pci_ctrl2 = 0; + + ixgbe_set_lan_id_multi_port_pcie(hw); + + /* check if LAN0 is disabled */ + hw->eeprom.ops.read(hw, IXGBE_PCIE_GENERAL_PTR, &pci_gen); + if ((pci_gen != 0) && (pci_gen != 0xFFFF)) { + + hw->eeprom.ops.read(hw, pci_gen + IXGBE_PCIE_CTRL2, &pci_ctrl2); + + /* if LAN0 is completely disabled force function to 0 */ + if ((pci_ctrl2 & IXGBE_PCIE_CTRL2_LAN_DISABLE) && + !(pci_ctrl2 & IXGBE_PCIE_CTRL2_DISABLE_SELECT) && + !(pci_ctrl2 & IXGBE_PCIE_CTRL2_DUMMY_ENABLE)) { + + bus->func = 0; + } + } +} + static struct ixgbe_mac_operations mac_ops_82598 = { .init_hw = &ixgbe_init_hw_generic, .reset_hw = &ixgbe_reset_hw_82598, @@ -1199,7 +1253,7 @@ static struct ixgbe_mac_operations mac_ops_82598 = { .get_mac_addr = &ixgbe_get_mac_addr_generic, .stop_adapter = &ixgbe_stop_adapter_generic, .get_bus_info = &ixgbe_get_bus_info_generic, - .set_lan_id = &ixgbe_set_lan_id_multi_port_pcie, + .set_lan_id = &ixgbe_set_lan_id_multi_port_pcie_82598, .read_analog_reg8 = &ixgbe_read_analog_reg8_82598, .write_analog_reg8 = &ixgbe_write_analog_reg8_82598, .setup_link = &ixgbe_setup_mac_link_82598, diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index 00aeba385a2f..b341ed8ef84f 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -38,6 +38,7 @@ #define IXGBE_82599_RAR_ENTRIES 128 #define IXGBE_82599_MC_TBL_SIZE 128 #define IXGBE_82599_VFT_TBL_SIZE 128 +#define IXGBE_82599_RX_PB_SIZE 512 static void ixgbe_disable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw); static void ixgbe_enable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw); @@ -61,6 +62,7 @@ static s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw, bool autoneg, bool autoneg_wait_to_complete); static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw); +static bool ixgbe_verify_lesm_fw_enabled_82599(struct ixgbe_hw *hw); static void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw) { @@ -86,7 +88,8 @@ static void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw) if ((mac->ops.get_media_type(hw) == ixgbe_media_type_backplane) && (hw->phy.smart_speed == ixgbe_smart_speed_auto || - hw->phy.smart_speed == ixgbe_smart_speed_on)) + hw->phy.smart_speed == ixgbe_smart_speed_on) && + !ixgbe_verify_lesm_fw_enabled_82599(hw)) mac->ops.setup_link = &ixgbe_setup_mac_link_smartspeed; else mac->ops.setup_link = &ixgbe_setup_mac_link_82599; @@ -128,8 +131,12 @@ static s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw) /* Release the semaphore */ ixgbe_release_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM); - /* Delay obtaining semaphore again to allow FW access */ - msleep(hw->eeprom.semaphore_delay); + /* + * Delay obtaining semaphore again to allow FW access, + * semaphore_delay is in ms usleep_range needs us. + */ + usleep_range(hw->eeprom.semaphore_delay * 1000, + hw->eeprom.semaphore_delay * 2000); /* Now restart DSP by setting Restart_AN and clearing LMS */ IXGBE_WRITE_REG(hw, IXGBE_AUTOC, ((IXGBE_READ_REG(hw, @@ -138,7 +145,7 @@ static s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw) /* Wait for AN to leave state 0 */ for (i = 0; i < 10; i++) { - msleep(4); + usleep_range(4000, 8000); reg_anlp1 = IXGBE_READ_REG(hw, IXGBE_ANLP1); if (reg_anlp1 & IXGBE_ANLP1_AN_STATE_MASK) break; @@ -353,6 +360,7 @@ static enum ixgbe_media_type ixgbe_get_media_type_82599(struct ixgbe_hw *hw) case IXGBE_DEV_ID_82599_SFP: case IXGBE_DEV_ID_82599_SFP_FCOE: case IXGBE_DEV_ID_82599_SFP_EM: + case IXGBE_DEV_ID_82599_SFP_SF2: media_type = ixgbe_media_type_fiber; break; case IXGBE_DEV_ID_82599_CX4: @@ -1176,7 +1184,7 @@ s32 ixgbe_init_fdir_signature_82599(struct ixgbe_hw *hw, u32 pballoc) if (IXGBE_READ_REG(hw, IXGBE_FDIRCTRL) & IXGBE_FDIRCTRL_INIT_DONE) break; - msleep(1); + usleep_range(1000, 2000); } if (i >= IXGBE_FDIR_INIT_DONE_POLL) hw_dbg(hw, "Flow Director Signature poll time exceeded!\n"); @@ -1271,7 +1279,7 @@ s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 pballoc) if (IXGBE_READ_REG(hw, IXGBE_FDIRCTRL) & IXGBE_FDIRCTRL_INIT_DONE) break; - msleep(1); + usleep_range(1000, 2000); } if (i >= IXGBE_FDIR_INIT_DONE_POLL) hw_dbg(hw, "Flow Director Perfect poll time exceeded!\n"); @@ -1740,30 +1748,29 @@ static s32 ixgbe_write_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 val) * ixgbe_start_hw_82599 - Prepare hardware for Tx/Rx * @hw: pointer to hardware structure * - * Starts the hardware using the generic start_hw function. - * Then performs device-specific: - * Clears the rate limiter registers. + * Starts the hardware using the generic start_hw function + * and the generation start_hw function. + * Then performs revision-specific operations, if any. **/ static s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw) { - u32 q_num; - s32 ret_val; + s32 ret_val = 0; ret_val = ixgbe_start_hw_generic(hw); + if (ret_val != 0) + goto out; - /* Clear the rate limiters */ - for (q_num = 0; q_num < hw->mac.max_tx_queues; q_num++) { - IXGBE_WRITE_REG(hw, IXGBE_RTTDQSEL, q_num); - IXGBE_WRITE_REG(hw, IXGBE_RTTBCNRC, 0); - } - IXGBE_WRITE_FLUSH(hw); + ret_val = ixgbe_start_hw_gen2(hw); + if (ret_val != 0) + goto out; /* We need to run link autotry after the driver loads */ hw->mac.autotry_restart = true; + hw->mac.rx_pb_size = IXGBE_82599_RX_PB_SIZE; if (ret_val == 0) ret_val = ixgbe_verify_fw_version_82599(hw); - +out: return ret_val; } @@ -1775,7 +1782,7 @@ static s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw) * If PHY already detected, maintains current PHY type in hw struct, * otherwise executes the PHY detection routine. **/ -s32 ixgbe_identify_phy_82599(struct ixgbe_hw *hw) +static s32 ixgbe_identify_phy_82599(struct ixgbe_hw *hw) { s32 status = IXGBE_ERR_PHY_ADDR_INVALID; @@ -1968,21 +1975,6 @@ static s32 ixgbe_enable_rx_dma_82599(struct ixgbe_hw *hw, u32 regval) } /** - * ixgbe_get_device_caps_82599 - Get additional device capabilities - * @hw: pointer to hardware structure - * @device_caps: the EEPROM word with the extra device capabilities - * - * This function will read the EEPROM location for the device capabilities, - * and return the word through device_caps. - **/ -static s32 ixgbe_get_device_caps_82599(struct ixgbe_hw *hw, u16 *device_caps) -{ - hw->eeprom.ops.read(hw, IXGBE_DEVICE_CAPS, device_caps); - - return 0; -} - -/** * ixgbe_verify_fw_version_82599 - verify fw version for 82599 * @hw: pointer to hardware structure * @@ -2030,6 +2022,48 @@ fw_version_out: return status; } +/** + * ixgbe_verify_lesm_fw_enabled_82599 - Checks LESM FW module state. + * @hw: pointer to hardware structure + * + * Returns true if the LESM FW module is present and enabled. Otherwise + * returns false. Smart Speed must be disabled if LESM FW module is enabled. + **/ +static bool ixgbe_verify_lesm_fw_enabled_82599(struct ixgbe_hw *hw) +{ + bool lesm_enabled = false; + u16 fw_offset, fw_lesm_param_offset, fw_lesm_state; + s32 status; + + /* get the offset to the Firmware Module block */ + status = hw->eeprom.ops.read(hw, IXGBE_FW_PTR, &fw_offset); + + if ((status != 0) || + (fw_offset == 0) || (fw_offset == 0xFFFF)) + goto out; + + /* get the offset to the LESM Parameters block */ + status = hw->eeprom.ops.read(hw, (fw_offset + + IXGBE_FW_LESM_PARAMETERS_PTR), + &fw_lesm_param_offset); + + if ((status != 0) || + (fw_lesm_param_offset == 0) || (fw_lesm_param_offset == 0xFFFF)) + goto out; + + /* get the lesm state word */ + status = hw->eeprom.ops.read(hw, (fw_lesm_param_offset + + IXGBE_FW_LESM_STATE_1), + &fw_lesm_state); + + if ((status == 0) && + (fw_lesm_state & IXGBE_FW_LESM_STATE_ENABLED)) + lesm_enabled = true; + +out: + return lesm_enabled; +} + static struct ixgbe_mac_operations mac_ops_82599 = { .init_hw = &ixgbe_init_hw_generic, .reset_hw = &ixgbe_reset_hw_82599, @@ -2040,7 +2074,7 @@ static struct ixgbe_mac_operations mac_ops_82599 = { .enable_rx_dma = &ixgbe_enable_rx_dma_82599, .get_mac_addr = &ixgbe_get_mac_addr_generic, .get_san_mac_addr = &ixgbe_get_san_mac_addr_generic, - .get_device_caps = &ixgbe_get_device_caps_82599, + .get_device_caps = &ixgbe_get_device_caps_generic, .get_wwn_prefix = &ixgbe_get_wwn_prefix_generic, .stop_adapter = &ixgbe_stop_adapter_generic, .get_bus_info = &ixgbe_get_bus_info_generic, diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c index bcd952916eb2..cb2e8e18dd39 100644 --- a/drivers/net/ixgbe/ixgbe_common.c +++ b/drivers/net/ixgbe/ixgbe_common.c @@ -54,6 +54,7 @@ static s32 ixgbe_device_supports_autoneg_fc(struct ixgbe_hw *hw); static s32 ixgbe_negotiate_fc(struct ixgbe_hw *hw, u32 adv_reg, u32 lp_reg, u32 adv_sym, u32 adv_asm, u32 lp_sym, u32 lp_asm); static s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num); +static s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg); /** * ixgbe_start_hw_generic - Prepare hardware for Tx/Rx @@ -96,6 +97,45 @@ s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw) } /** + * ixgbe_start_hw_gen2 - Init sequence for common device family + * @hw: pointer to hw structure + * + * Performs the init sequence common to the second generation + * of 10 GbE devices. + * Devices in the second generation: + * 82599 + * X540 + **/ +s32 ixgbe_start_hw_gen2(struct ixgbe_hw *hw) +{ + u32 i; + u32 regval; + + /* Clear the rate limiters */ + for (i = 0; i < hw->mac.max_tx_queues; i++) { + IXGBE_WRITE_REG(hw, IXGBE_RTTDQSEL, i); + IXGBE_WRITE_REG(hw, IXGBE_RTTBCNRC, 0); + } + IXGBE_WRITE_FLUSH(hw); + + /* Disable relaxed ordering */ + for (i = 0; i < hw->mac.max_tx_queues; i++) { + regval = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL_82599(i)); + regval &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN; + IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL_82599(i), regval); + } + + for (i = 0; i < hw->mac.max_rx_queues; i++) { + regval = IXGBE_READ_REG(hw, IXGBE_DCA_RXCTRL(i)); + regval &= ~(IXGBE_DCA_RXCTRL_DESC_WRO_EN | + IXGBE_DCA_RXCTRL_DESC_HSRO_EN); + IXGBE_WRITE_REG(hw, IXGBE_DCA_RXCTRL(i), regval); + } + + return 0; +} + +/** * ixgbe_init_hw_generic - Generic hardware initialization * @hw: pointer to hardware structure * @@ -464,7 +504,7 @@ s32 ixgbe_stop_adapter_generic(struct ixgbe_hw *hw) reg_val &= ~(IXGBE_RXCTRL_RXEN); IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, reg_val); IXGBE_WRITE_FLUSH(hw); - msleep(2); + usleep_range(2000, 4000); /* Clear interrupt mask to stop from interrupts being generated */ IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_IRQ_CLEAR_MASK); @@ -739,6 +779,47 @@ out: } /** + * ixgbe_write_eewr_generic - Write EEPROM word using EEWR + * @hw: pointer to hardware structure + * @offset: offset of word in the EEPROM to write + * @data: word write to the EEPROM + * + * Write a 16 bit word to the EEPROM using the EEWR register. + **/ +s32 ixgbe_write_eewr_generic(struct ixgbe_hw *hw, u16 offset, u16 data) +{ + u32 eewr; + s32 status; + + hw->eeprom.ops.init_params(hw); + + if (offset >= hw->eeprom.word_size) { + status = IXGBE_ERR_EEPROM; + goto out; + } + + eewr = (offset << IXGBE_EEPROM_RW_ADDR_SHIFT) | + (data << IXGBE_EEPROM_RW_REG_DATA) | IXGBE_EEPROM_RW_REG_START; + + status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE); + if (status != 0) { + hw_dbg(hw, "Eeprom write EEWR timed out\n"); + goto out; + } + + IXGBE_WRITE_REG(hw, IXGBE_EEWR, eewr); + + status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE); + if (status != 0) { + hw_dbg(hw, "Eeprom write EEWR timed out\n"); + goto out; + } + +out: + return status; +} + +/** * ixgbe_poll_eerd_eewr_done - Poll EERD read or EEWR write status * @hw: pointer to hardware structure * @ee_reg: EEPROM flag for polling @@ -746,7 +827,7 @@ out: * Polls the status bit (bit 1) of the EERD or EEWR to determine when the * read or write is done respectively. **/ -s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg) +static s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg) { u32 i; u32 reg; @@ -1112,8 +1193,12 @@ static void ixgbe_release_eeprom(struct ixgbe_hw *hw) hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); - /* Delay before attempt to obtain semaphore again to allow FW access */ - msleep(hw->eeprom.semaphore_delay); + /* + * Delay before attempt to obtain semaphore again to allow FW + * access. semaphore_delay is in ms we need us for usleep_range + */ + usleep_range(hw->eeprom.semaphore_delay * 1000, + hw->eeprom.semaphore_delay * 2000); } /** @@ -2189,7 +2274,7 @@ s32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u16 mask) * thread currently using resource (swmask) */ ixgbe_release_eeprom_semaphore(hw); - msleep(5); + usleep_range(5000, 10000); timeout--; } @@ -2263,7 +2348,7 @@ s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index) autoc_reg |= IXGBE_AUTOC_AN_RESTART; autoc_reg |= IXGBE_AUTOC_FLU; IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); - msleep(10); + usleep_range(10000, 20000); } led_reg &= ~IXGBE_LED_MODE_MASK(index); @@ -2883,3 +2968,18 @@ void ixgbe_set_vlan_anti_spoofing(struct ixgbe_hw *hw, bool enable, int vf) pfvfspoof &= ~(1 << vf_target_shift); IXGBE_WRITE_REG(hw, IXGBE_PFVFSPOOF(vf_target_reg), pfvfspoof); } + +/** + * ixgbe_get_device_caps_generic - Get additional device capabilities + * @hw: pointer to hardware structure + * @device_caps: the EEPROM word with the extra device capabilities + * + * This function will read the EEPROM location for the device capabilities, + * and return the word through device_caps. + **/ +s32 ixgbe_get_device_caps_generic(struct ixgbe_hw *hw, u16 *device_caps) +{ + hw->eeprom.ops.read(hw, IXGBE_DEVICE_CAPS, device_caps); + + return 0; +} diff --git a/drivers/net/ixgbe/ixgbe_common.h b/drivers/net/ixgbe/ixgbe_common.h index 508f635fc2ca..e850adbb32a1 100644 --- a/drivers/net/ixgbe/ixgbe_common.h +++ b/drivers/net/ixgbe/ixgbe_common.h @@ -35,6 +35,7 @@ u32 ixgbe_get_pcie_msix_count_generic(struct ixgbe_hw *hw); s32 ixgbe_init_ops_generic(struct ixgbe_hw *hw); s32 ixgbe_init_hw_generic(struct ixgbe_hw *hw); s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw); +s32 ixgbe_start_hw_gen2(struct ixgbe_hw *hw); s32 ixgbe_clear_hw_cntrs_generic(struct ixgbe_hw *hw); s32 ixgbe_read_pba_string_generic(struct ixgbe_hw *hw, u8 *pba_num, u32 pba_num_size); @@ -49,13 +50,13 @@ s32 ixgbe_led_off_generic(struct ixgbe_hw *hw, u32 index); s32 ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw); s32 ixgbe_write_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 data); s32 ixgbe_read_eerd_generic(struct ixgbe_hw *hw, u16 offset, u16 *data); +s32 ixgbe_write_eewr_generic(struct ixgbe_hw *hw, u16 offset, u16 data); s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, u16 *data); u16 ixgbe_calc_eeprom_checksum_generic(struct ixgbe_hw *hw); s32 ixgbe_validate_eeprom_checksum_generic(struct ixgbe_hw *hw, u16 *checksum_val); s32 ixgbe_update_eeprom_checksum_generic(struct ixgbe_hw *hw); -s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg); s32 ixgbe_set_rar_generic(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vmdq, u32 enable_addr); @@ -89,6 +90,7 @@ s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index); s32 ixgbe_blink_led_stop_generic(struct ixgbe_hw *hw, u32 index); void ixgbe_set_mac_anti_spoofing(struct ixgbe_hw *hw, bool enable, int pf); void ixgbe_set_vlan_anti_spoofing(struct ixgbe_hw *hw, bool enable, int vf); +s32 ixgbe_get_device_caps_generic(struct ixgbe_hw *hw, u16 *device_caps); #define IXGBE_WRITE_REG(a, reg, value) writel((value), ((a)->hw_addr + (reg))) diff --git a/drivers/net/ixgbe/ixgbe_dcb_82599.c b/drivers/net/ixgbe/ixgbe_dcb_82599.c index 025af8c53ddb..d50cf78c234d 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_82599.c +++ b/drivers/net/ixgbe/ixgbe_dcb_82599.c @@ -39,36 +39,52 @@ */ static s32 ixgbe_dcb_config_packet_buffers_82599(struct ixgbe_hw *hw, u8 rx_pba) { - s32 ret_val = 0; - u32 value = IXGBE_RXPBSIZE_64KB; + int num_tcs = IXGBE_MAX_PACKET_BUFFERS; + u32 rx_pb_size = hw->mac.rx_pb_size << IXGBE_RXPBSIZE_SHIFT; + u32 rxpktsize; + u32 txpktsize; + u32 txpbthresh; u8 i = 0; - /* Setup Rx packet buffer sizes */ - switch (rx_pba) { - case pba_80_48: - /* Setup the first four at 80KB */ - value = IXGBE_RXPBSIZE_80KB; - for (; i < 4; i++) - IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), value); - /* Setup the last four at 48KB...don't re-init i */ - value = IXGBE_RXPBSIZE_48KB; - /* Fall Through */ - case pba_equal: - default: - for (; i < IXGBE_MAX_PACKET_BUFFERS; i++) - IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), value); - - /* Setup Tx packet buffer sizes */ - for (i = 0; i < IXGBE_MAX_PACKET_BUFFERS; i++) { - IXGBE_WRITE_REG(hw, IXGBE_TXPBSIZE(i), - IXGBE_TXPBSIZE_20KB); - IXGBE_WRITE_REG(hw, IXGBE_TXPBTHRESH(i), - IXGBE_TXPBTHRESH_DCB); - } - break; + /* + * This really means configure the first half of the TCs + * (Traffic Classes) to use 5/8 of the Rx packet buffer + * space. To determine the size of the buffer for each TC, + * we are multiplying the average size by 5/4 and applying + * it to half of the traffic classes. + */ + if (rx_pba == pba_80_48) { + rxpktsize = (rx_pb_size * 5) / (num_tcs * 4); + rx_pb_size -= rxpktsize * (num_tcs / 2); + for (; i < (num_tcs / 2); i++) + IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), rxpktsize); + } + + /* Divide the remaining Rx packet buffer evenly among the TCs */ + rxpktsize = rx_pb_size / (num_tcs - i); + for (; i < num_tcs; i++) + IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), rxpktsize); + + /* + * Setup Tx packet buffer and threshold equally for all TCs + * TXPBTHRESH register is set in K so divide by 1024 and subtract + * 10 since the largest packet we support is just over 9K. + */ + txpktsize = IXGBE_TXPBSIZE_MAX / num_tcs; + txpbthresh = (txpktsize / 1024) - IXGBE_TXPKT_SIZE_MAX; + for (i = 0; i < num_tcs; i++) { + IXGBE_WRITE_REG(hw, IXGBE_TXPBSIZE(i), txpktsize); + IXGBE_WRITE_REG(hw, IXGBE_TXPBTHRESH(i), txpbthresh); + } + + /* Clear unused TCs, if any, to zero buffer size*/ + for (; i < MAX_TRAFFIC_CLASS; i++) { + IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), 0); + IXGBE_WRITE_REG(hw, IXGBE_TXPBSIZE(i), 0); + IXGBE_WRITE_REG(hw, IXGBE_TXPBTHRESH(i), 0); } - return ret_val; + return 0; } /** @@ -285,12 +301,17 @@ s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw, u8 pfc_en) IXGBE_WRITE_REG(hw, IXGBE_FCCFG, reg); /* * Enable Receive PFC - * We will always honor XOFF frames we receive when - * we are in PFC mode. + * 82599 will always honor XOFF frames we receive when + * we are in PFC mode however X540 only honors enabled + * traffic classes. */ reg = IXGBE_READ_REG(hw, IXGBE_MFLCN); reg &= ~IXGBE_MFLCN_RFCE; reg |= IXGBE_MFLCN_RPFCE | IXGBE_MFLCN_DPF; + + if (hw->mac.type == ixgbe_mac_X540) + reg |= pfc_en << IXGBE_MFLCN_RPFCE_SHIFT; + IXGBE_WRITE_REG(hw, IXGBE_MFLCN, reg); } else { diff --git a/drivers/net/ixgbe/ixgbe_dcb_82599.h b/drivers/net/ixgbe/ixgbe_dcb_82599.h index 148fd8b477a9..2de71a503153 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_82599.h +++ b/drivers/net/ixgbe/ixgbe_dcb_82599.h @@ -92,8 +92,10 @@ #define IXGBE_RXPBSIZE_64KB 0x00010000 /* 64KB Packet Buffer */ #define IXGBE_RXPBSIZE_80KB 0x00014000 /* 80KB Packet Buffer */ #define IXGBE_RXPBSIZE_128KB 0x00020000 /* 128KB Packet Buffer */ +#define IXGBE_TXPBSIZE_MAX 0x00028000 /* 160KB Packet Buffer*/ #define IXGBE_TXPBTHRESH_DCB 0xA /* THRESH value for DCB mode */ +#define IXGBE_TXPKT_SIZE_MAX 0xA /* Max Tx Packet size */ /* SECTXMINIFG DCB */ #define IXGBE_SECTX_DCB 0x00001F00 /* DCB TX Buffer IFG */ diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c index 327c8614198c..5e7ed225851a 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_nl.c +++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c @@ -347,18 +347,28 @@ static void ixgbe_dcbnl_get_pfc_cfg(struct net_device *netdev, int priority, static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) { struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct dcb_app app = { + .selector = DCB_APP_IDTYPE_ETHTYPE, + .protocol = ETH_P_FCOE, + }; + u8 up = dcb_getapp(netdev, &app); int ret; - if (!adapter->dcb_set_bitmap || - !(adapter->dcbx_cap & DCB_CAP_DCBX_VER_CEE)) - return DCB_NO_HW_CHG; - ret = ixgbe_copy_dcb_cfg(&adapter->temp_dcb_cfg, &adapter->dcb_cfg, MAX_TRAFFIC_CLASS); - if (ret) return DCB_NO_HW_CHG; + /* In IEEE mode app data must be parsed into DCBX format for + * hardware routines. + */ + if (adapter->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) + up = (1 << up); + +#ifdef IXGBE_FCOE + if (up && (up != (1 << adapter->fcoe.up))) + adapter->dcb_set_bitmap |= BIT_APP_UPCHG; + /* * Only take down the adapter if an app change occurred. FCoE * may shuffle tx rings in this case and this can not be done @@ -366,12 +376,15 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) */ if (adapter->dcb_set_bitmap & BIT_APP_UPCHG) { while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) - msleep(1); + usleep_range(1000, 2000); + + ixgbe_fcoe_setapp(adapter, up); if (netif_running(netdev)) netdev->netdev_ops->ndo_stop(netdev); ixgbe_clear_interrupt_scheme(adapter); } +#endif if (adapter->dcb_cfg.pfc_mode_enable) { switch (adapter->hw.mac.type) { @@ -399,12 +412,14 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) } } +#ifdef IXGBE_FCOE if (adapter->dcb_set_bitmap & BIT_APP_UPCHG) { ixgbe_init_interrupt_scheme(adapter); if (netif_running(netdev)) netdev->netdev_ops->ndo_open(netdev); ret = DCB_HW_CHG_RST; } +#endif if (adapter->dcb_set_bitmap & BIT_PFC) { u8 pfc_en; @@ -558,68 +573,6 @@ static u8 ixgbe_dcbnl_getapp(struct net_device *netdev, u8 idtype, u16 id) return dcb_getapp(netdev, &app); } -/** - * ixgbe_dcbnl_setapp - set the DCBX application user priority - * @netdev : the corresponding netdev - * @idtype : identifies the id as ether type or TCP/UDP port number - * @id: id is either ether type or TCP/UDP port number - * @up: the 802.1p user priority bitmap - * - * Returns : 0 on success or 1 on error - */ -static u8 ixgbe_dcbnl_setapp(struct net_device *netdev, - u8 idtype, u16 id, u8 up) -{ - struct ixgbe_adapter *adapter = netdev_priv(netdev); - u8 rval = 1; - struct dcb_app app = { - .selector = idtype, - .protocol = id, - .priority = up - }; - - if (!(adapter->dcbx_cap & DCB_CAP_DCBX_VER_CEE)) - return rval; - - rval = dcb_setapp(netdev, &app); - - switch (idtype) { - case DCB_APP_IDTYPE_ETHTYPE: -#ifdef IXGBE_FCOE - if (id == ETH_P_FCOE) { - u8 old_tc; - - /* Get current programmed tc */ - old_tc = adapter->fcoe.tc; - rval = ixgbe_fcoe_setapp(adapter, up); - - if (rval || - !(adapter->flags & IXGBE_FLAG_DCB_ENABLED) || - !(adapter->flags & IXGBE_FLAG_FCOE_ENABLED)) - break; - - /* The FCoE application priority may be changed multiple - * times in quick succession with switches that build up - * TLVs. To avoid creating uneeded device resets this - * checks the actual HW configuration and clears - * BIT_APP_UPCHG if a HW configuration change is not - * need - */ - if (old_tc == adapter->fcoe.tc) - adapter->dcb_set_bitmap &= ~BIT_APP_UPCHG; - else - adapter->dcb_set_bitmap |= BIT_APP_UPCHG; - } -#endif - break; - case DCB_APP_IDTYPE_PORTNUM: - break; - default: - break; - } - return rval; -} - static int ixgbe_dcbnl_ieee_getets(struct net_device *dev, struct ieee_ets *ets) { @@ -745,25 +698,14 @@ static int ixgbe_dcbnl_ieee_setapp(struct net_device *dev, if (!(adapter->dcbx_cap & DCB_CAP_DCBX_VER_IEEE)) return -EINVAL; -#ifdef IXGBE_FCOE - if (app->selector == 1 && app->protocol == ETH_P_FCOE) { - if (adapter->fcoe.tc == app->priority) - goto setapp; - /* In IEEE mode map up to tc 1:1 */ - adapter->fcoe.tc = app->priority; - adapter->fcoe.up = app->priority; + dcb_setapp(dev, app); - /* Force hardware reset required to push FCoE - * setup on {tx|rx}_rings - */ - adapter->dcb_set_bitmap |= BIT_APP_UPCHG; +#ifdef IXGBE_FCOE + if (app->selector == 1 && app->protocol == ETH_P_FCOE && + adapter->fcoe.tc == app->priority) ixgbe_dcbnl_set_all(dev); - } - -setapp: #endif - dcb_setapp(dev, app); return 0; } @@ -838,7 +780,6 @@ const struct dcbnl_rtnl_ops dcbnl_ops = { .getpfcstate = ixgbe_dcbnl_getpfcstate, .setpfcstate = ixgbe_dcbnl_setpfcstate, .getapp = ixgbe_dcbnl_getapp, - .setapp = ixgbe_dcbnl_setapp, .getdcbx = ixgbe_dcbnl_getdcbx, .setdcbx = ixgbe_dcbnl_setdcbx, }; diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 76380a2b35aa..5005a36f8593 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -931,7 +931,7 @@ static int ixgbe_set_ringparam(struct net_device *netdev, } while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) - msleep(1); + usleep_range(1000, 2000); if (!netif_running(adapter->netdev)) { for (i = 0; i < adapter->num_tx_queues; i++) @@ -1417,7 +1417,7 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data) /* Disable all the interrupts */ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFFFFFF); - msleep(10); + usleep_range(10000, 20000); /* Test each interrupt */ for (; i < 10; i++) { @@ -1437,7 +1437,7 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data) ~mask & 0x00007FFF); IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, ~mask & 0x00007FFF); - msleep(10); + usleep_range(10000, 20000); if (adapter->test_icr & mask) { *data = 3; @@ -1454,7 +1454,7 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data) adapter->test_icr = 0; IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask); IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, mask); - msleep(10); + usleep_range(10000, 20000); if (!(adapter->test_icr &mask)) { *data = 4; @@ -1474,7 +1474,7 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data) ~mask & 0x00007FFF); IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, ~mask & 0x00007FFF); - msleep(10); + usleep_range(10000, 20000); if (adapter->test_icr) { *data = 5; @@ -1485,7 +1485,7 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data) /* Disable all the interrupts */ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFFFFFF); - msleep(10); + usleep_range(10000, 20000); /* Unhook test interrupt handler */ free_irq(irq, netdev); @@ -1613,7 +1613,7 @@ static int ixgbe_setup_loopback_test(struct ixgbe_adapter *adapter) reg_data |= IXGBE_AUTOC_LMS_10G_LINK_NO_AN | IXGBE_AUTOC_FLU; IXGBE_WRITE_REG(&adapter->hw, IXGBE_AUTOC, reg_data); IXGBE_WRITE_FLUSH(&adapter->hw); - msleep(10); + usleep_range(10000, 20000); /* Disable Atlas Tx lanes; re-enabled in reset path */ if (hw->mac.type == ixgbe_mac_82598EB) { diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 6f8adc7f5d7c..200ae7e60ba0 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -51,8 +51,12 @@ char ixgbe_driver_name[] = "ixgbe"; static const char ixgbe_driver_string[] = "Intel(R) 10 Gigabit PCI Express Network Driver"; - -#define DRV_VERSION "3.2.9-k2" +#define MAJ 3 +#define MIN 2 +#define BUILD 9 +#define KFIX 2 +#define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) "." \ + __stringify(BUILD) "-k" __stringify(KFIX) const char ixgbe_driver_version[] = DRV_VERSION; static const char ixgbe_copyright[] = "Copyright (c) 1999-2011 Intel Corporation."; @@ -120,6 +124,8 @@ static DEFINE_PCI_DEVICE_TABLE(ixgbe_pci_tbl) = { board_82599 }, {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X540T), board_X540 }, + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP_SF2), + board_82599 }, /* required last entry */ {0, } @@ -943,8 +949,6 @@ static void ixgbe_update_rx_dca(struct ixgbe_adapter *adapter, rxctrl |= IXGBE_DCA_RXCTRL_DESC_DCA_EN; rxctrl |= IXGBE_DCA_RXCTRL_HEAD_DCA_EN; rxctrl &= ~(IXGBE_DCA_RXCTRL_DESC_RRO_EN); - rxctrl &= ~(IXGBE_DCA_RXCTRL_DESC_WRO_EN | - IXGBE_DCA_RXCTRL_DESC_HSRO_EN); IXGBE_WRITE_REG(hw, IXGBE_DCA_RXCTRL(reg_idx), rxctrl); } @@ -962,7 +966,6 @@ static void ixgbe_update_tx_dca(struct ixgbe_adapter *adapter, txctrl &= ~IXGBE_DCA_TXCTRL_CPUID_MASK; txctrl |= dca3_get_tag(&adapter->pdev->dev, cpu); txctrl |= IXGBE_DCA_TXCTRL_DESC_DCA_EN; - txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN; IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(reg_idx), txctrl); break; case ixgbe_mac_82599EB: @@ -972,7 +975,6 @@ static void ixgbe_update_tx_dca(struct ixgbe_adapter *adapter, txctrl |= (dca3_get_tag(&adapter->pdev->dev, cpu) << IXGBE_DCA_TXCTRL_CPUID_SHIFT_82599); txctrl |= IXGBE_DCA_TXCTRL_DESC_DCA_EN; - txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN; IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL_82599(reg_idx), txctrl); break; default: @@ -2731,7 +2733,7 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter, /* poll to verify queue is enabled */ do { - msleep(1); + usleep_range(1000, 2000); txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(reg_idx)); } while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE)); if (!wait_loop) @@ -3023,7 +3025,7 @@ static void ixgbe_rx_desc_queue_enable(struct ixgbe_adapter *adapter, return; do { - msleep(1); + usleep_range(1000, 2000); rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(reg_idx)); } while (--wait_loop && !(rxdctl & IXGBE_RXDCTL_ENABLE)); @@ -3945,7 +3947,7 @@ void ixgbe_reinit_locked(struct ixgbe_adapter *adapter) { WARN_ON(in_interrupt()); while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) - msleep(1); + usleep_range(1000, 2000); ixgbe_down(adapter); /* * If SR-IOV enabled then wait a bit before bringing the adapter @@ -4150,7 +4152,7 @@ void ixgbe_down(struct ixgbe_adapter *adapter) /* this call also flushes the previous write */ ixgbe_disable_rx_queue(adapter, adapter->rx_ring[i]); - msleep(10); + usleep_range(10000, 20000); netif_tx_stop_all_queues(netdev); diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c index df5b8aa4795d..fd381ea17e99 100644 --- a/drivers/net/ixgbe/ixgbe_phy.c +++ b/drivers/net/ixgbe/ixgbe_phy.c @@ -449,7 +449,8 @@ s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw) MDIO_MMD_AN, &autoneg_reg); - autoneg_reg &= ~ADVERTISE_100FULL; + autoneg_reg &= ~(ADVERTISE_100FULL | + ADVERTISE_100HALF); if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL) autoneg_reg |= ADVERTISE_100FULL; @@ -753,7 +754,7 @@ s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw) &phy_data); if ((phy_data & MDIO_CTRL1_RESET) == 0) break; - msleep(10); + usleep_range(10000, 20000); } if ((phy_data & MDIO_CTRL1_RESET) != 0) { @@ -782,7 +783,7 @@ s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw) case IXGBE_DELAY_NL: data_offset++; hw_dbg(hw, "DELAY: %d MS\n", edata); - msleep(edata); + usleep_range(edata * 1000, edata * 2000); break; case IXGBE_DATA_NL: hw_dbg(hw, "DATA:\n"); diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index 25c1fb7eda06..f5bec9754c00 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -58,6 +58,7 @@ #define IXGBE_DEV_ID_82599_SFP_FCOE 0x1529 #define IXGBE_SUBDEV_ID_82599_SFP 0x11A9 #define IXGBE_DEV_ID_82599_SFP_EM 0x1507 +#define IXGBE_DEV_ID_82599_SFP_SF2 0x154D #define IXGBE_DEV_ID_82599_XAUI_LOM 0x10FC #define IXGBE_DEV_ID_82599_COMBO_BACKPLANE 0x10F8 #define IXGBE_SUBDEV_ID_82599_KX4_KR_MEZZ 0x000C @@ -1616,10 +1617,18 @@ #define IXGBE_FLUDONE_ATTEMPTS 20000 #endif +#define IXGBE_PCIE_CTRL2 0x5 /* PCIe Control 2 Offset */ +#define IXGBE_PCIE_CTRL2_DUMMY_ENABLE 0x8 /* Dummy Function Enable */ +#define IXGBE_PCIE_CTRL2_LAN_DISABLE 0x2 /* LAN PCI Disable */ +#define IXGBE_PCIE_CTRL2_DISABLE_SELECT 0x1 /* LAN Disable Select */ + #define IXGBE_SAN_MAC_ADDR_PORT0_OFFSET 0x0 #define IXGBE_SAN_MAC_ADDR_PORT1_OFFSET 0x3 #define IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP 0x1 #define IXGBE_DEVICE_CAPS_FCOE_OFFLOADS 0x2 +#define IXGBE_FW_LESM_PARAMETERS_PTR 0x2 +#define IXGBE_FW_LESM_STATE_1 0x1 +#define IXGBE_FW_LESM_STATE_ENABLED 0x8000 /* LESM Enable bit */ #define IXGBE_FW_PASSTHROUGH_PATCH_CONFIG_PTR 0x4 #define IXGBE_FW_PATCH_VERSION_4 0x7 @@ -1719,6 +1728,8 @@ #define IXGBE_MFLCN_RPFCE 0x00000004 /* Receive Priority FC Enable */ #define IXGBE_MFLCN_RFCE 0x00000008 /* Receive FC Enable */ +#define IXGBE_MFLCN_RPFCE_SHIFT 4 + /* Multiple Receive Queue Control */ #define IXGBE_MRQC_RSSEN 0x00000001 /* RSS Enable */ #define IXGBE_MRQC_MRQE_MASK 0xF /* Bits 3:0 */ @@ -2597,6 +2608,7 @@ struct ixgbe_mac_info { u32 vft_size; u32 num_rar_entries; u32 rar_highwater; + u32 rx_pb_size; u32 max_tx_queues; u32 max_rx_queues; u32 max_msix_vectors; diff --git a/drivers/net/ixgbe/ixgbe_x540.c b/drivers/net/ixgbe/ixgbe_x540.c index d9323c08f5c7..932394fce439 100644 --- a/drivers/net/ixgbe/ixgbe_x540.c +++ b/drivers/net/ixgbe/ixgbe_x540.c @@ -37,6 +37,7 @@ #define IXGBE_X540_RAR_ENTRIES 128 #define IXGBE_X540_MC_TBL_SIZE 128 #define IXGBE_X540_VFT_TBL_SIZE 128 +#define IXGBE_X540_RX_PB_SIZE 384 static s32 ixgbe_update_flash_X540(struct ixgbe_hw *hw); static s32 ixgbe_poll_flash_update_done_X540(struct ixgbe_hw *hw); @@ -226,6 +227,28 @@ mac_reset_top: } /** + * ixgbe_start_hw_X540 - Prepare hardware for Tx/Rx + * @hw: pointer to hardware structure + * + * Starts the hardware using the generic start_hw function + * and the generation start_hw function. + * Then performs revision-specific operations, if any. + **/ +static s32 ixgbe_start_hw_X540(struct ixgbe_hw *hw) +{ + s32 ret_val = 0; + + ret_val = ixgbe_start_hw_generic(hw); + if (ret_val != 0) + goto out; + + ret_val = ixgbe_start_hw_gen2(hw); + hw->mac.rx_pb_size = IXGBE_X540_RX_PB_SIZE; +out: + return ret_val; +} + +/** * ixgbe_get_supported_physical_layer_X540 - Returns physical layer type * @hw: pointer to hardware structure * @@ -300,55 +323,33 @@ static s32 ixgbe_read_eerd_X540(struct ixgbe_hw *hw, u16 offset, u16 *data) } /** - * ixgbe_write_eewr_X540 - Write EEPROM word using EEWR - * @hw: pointer to hardware structure - * @offset: offset of word in the EEPROM to write - * @data: word write to the EEPROM + * ixgbe_write_eewr_X540 - Write EEPROM word using EEWR + * @hw: pointer to hardware structure + * @offset: offset of word in the EEPROM to write + * @data: word write to the EEPROM * - * Write a 16 bit word to the EEPROM using the EEWR register. + * Write a 16 bit word to the EEPROM using the EEWR register. **/ static s32 ixgbe_write_eewr_X540(struct ixgbe_hw *hw, u16 offset, u16 data) { - u32 eewr; - s32 status; - - hw->eeprom.ops.init_params(hw); - - if (offset >= hw->eeprom.word_size) { - status = IXGBE_ERR_EEPROM; - goto out; - } - - eewr = (offset << IXGBE_EEPROM_RW_ADDR_SHIFT) | - (data << IXGBE_EEPROM_RW_REG_DATA) | - IXGBE_EEPROM_RW_REG_START; - - if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == 0) { - status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE); - if (status != 0) { - hw_dbg(hw, "Eeprom write EEWR timed out\n"); - goto out; - } - - IXGBE_WRITE_REG(hw, IXGBE_EEWR, eewr); + s32 status = 0; - status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE); - if (status != 0) { - hw_dbg(hw, "Eeprom write EEWR timed out\n"); - goto out; - } - } else { + if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == 0) + status = ixgbe_write_eewr_generic(hw, offset, data); + else status = IXGBE_ERR_SWFW_SYNC; - } -out: - ixgbe_release_swfw_sync_X540(hw, IXGBE_GSSR_EEP_SM); + hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); return status; } /** - * ixgbe_calc_eeprom_checksum_X540 - Calculates and returns the checksum - * @hw: pointer to hardware structure + * ixgbe_calc_eeprom_checksum_X540 - Calculates and returns the checksum + * + * This function does not use synchronization for EERD and EEWR. It can + * be used internally by function which utilize ixgbe_acquire_swfw_sync_X540. + * + * @hw: pointer to hardware structure **/ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw) { @@ -359,9 +360,15 @@ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw) u16 pointer = 0; u16 word = 0; + /* + * Do not use hw->eeprom.ops.read because we do not want to take + * the synchronization semaphores here. Instead use + * ixgbe_read_eerd_generic + */ + /* Include 0x0-0x3F in the checksum */ for (i = 0; i < IXGBE_EEPROM_CHECKSUM; i++) { - if (hw->eeprom.ops.read(hw, i, &word) != 0) { + if (ixgbe_read_eerd_generic(hw, i, &word) != 0) { hw_dbg(hw, "EEPROM read failed\n"); break; } @@ -376,7 +383,7 @@ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw) if (i == IXGBE_PHY_PTR || i == IXGBE_OPTION_ROM_PTR) continue; - if (hw->eeprom.ops.read(hw, i, &pointer) != 0) { + if (ixgbe_read_eerd_generic(hw, i, &pointer) != 0) { hw_dbg(hw, "EEPROM read failed\n"); break; } @@ -386,7 +393,7 @@ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw) pointer >= hw->eeprom.word_size) continue; - if (hw->eeprom.ops.read(hw, pointer, &length) != 0) { + if (ixgbe_read_eerd_generic(hw, pointer, &length) != 0) { hw_dbg(hw, "EEPROM read failed\n"); break; } @@ -397,7 +404,7 @@ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw) continue; for (j = pointer+1; j <= pointer+length; j++) { - if (hw->eeprom.ops.read(hw, j, &word) != 0) { + if (ixgbe_read_eerd_generic(hw, j, &word) != 0) { hw_dbg(hw, "EEPROM read failed\n"); break; } @@ -411,6 +418,62 @@ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw) } /** + * ixgbe_validate_eeprom_checksum_X540 - Validate EEPROM checksum + * @hw: pointer to hardware structure + * @checksum_val: calculated checksum + * + * Performs checksum calculation and validates the EEPROM checksum. If the + * caller does not need checksum_val, the value can be NULL. + **/ +static s32 ixgbe_validate_eeprom_checksum_X540(struct ixgbe_hw *hw, + u16 *checksum_val) +{ + s32 status; + u16 checksum; + u16 read_checksum = 0; + + /* + * Read the first word from the EEPROM. If this times out or fails, do + * not continue or we could be in for a very long wait while every + * EEPROM read fails + */ + status = hw->eeprom.ops.read(hw, 0, &checksum); + + if (status != 0) { + hw_dbg(hw, "EEPROM read failed\n"); + goto out; + } + + if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == 0) { + checksum = hw->eeprom.ops.calc_checksum(hw); + + /* + * Do not use hw->eeprom.ops.read because we do not want to take + * the synchronization semaphores twice here. + */ + ixgbe_read_eerd_generic(hw, IXGBE_EEPROM_CHECKSUM, + &read_checksum); + + /* + * Verify read checksum from EEPROM is the same as + * calculated checksum + */ + if (read_checksum != checksum) + status = IXGBE_ERR_EEPROM_CHECKSUM; + + /* If the user cares, return the calculated checksum */ + if (checksum_val) + *checksum_val = checksum; + } else { + status = IXGBE_ERR_SWFW_SYNC; + } + + hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); +out: + return status; +} + +/** * ixgbe_update_eeprom_checksum_X540 - Updates the EEPROM checksum and flash * @hw: pointer to hardware structure * @@ -421,11 +484,35 @@ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw) static s32 ixgbe_update_eeprom_checksum_X540(struct ixgbe_hw *hw) { s32 status; + u16 checksum; + + /* + * Read the first word from the EEPROM. If this times out or fails, do + * not continue or we could be in for a very long wait while every + * EEPROM read fails + */ + status = hw->eeprom.ops.read(hw, 0, &checksum); - status = ixgbe_update_eeprom_checksum_generic(hw); + if (status != 0) + hw_dbg(hw, "EEPROM read failed\n"); - if (status) + if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == 0) { + checksum = hw->eeprom.ops.calc_checksum(hw); + + /* + * Do not use hw->eeprom.ops.write because we do not want to + * take the synchronization semaphores twice here. + */ + status = ixgbe_write_eewr_generic(hw, IXGBE_EEPROM_CHECKSUM, + checksum); + + if (status == 0) status = ixgbe_update_flash_X540(hw); + else + status = IXGBE_ERR_SWFW_SYNC; + } + + hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); return status; } @@ -452,7 +539,7 @@ static s32 ixgbe_update_flash_X540(struct ixgbe_hw *hw) IXGBE_WRITE_REG(hw, IXGBE_EEC, flup); status = ixgbe_poll_flash_update_done_X540(hw); - if (status) + if (status == 0) hw_dbg(hw, "Flash update complete\n"); else hw_dbg(hw, "Flash update time out\n"); @@ -466,11 +553,10 @@ static s32 ixgbe_update_flash_X540(struct ixgbe_hw *hw) } status = ixgbe_poll_flash_update_done_X540(hw); - if (status) + if (status == 0) hw_dbg(hw, "Flash update complete\n"); else hw_dbg(hw, "Flash update time out\n"); - } out: return status; @@ -542,7 +628,7 @@ static s32 ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u16 mask) * resource (swmask) */ ixgbe_release_swfw_sync_semaphore(hw); - msleep(5); + usleep_range(5000, 10000); } } @@ -564,7 +650,7 @@ static s32 ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u16 mask) } } - msleep(5); + usleep_range(5000, 10000); return 0; } @@ -588,7 +674,7 @@ static void ixgbe_release_swfw_sync_X540(struct ixgbe_hw *hw, u16 mask) IXGBE_WRITE_REG(hw, IXGBE_SWFW_SYNC, swfw_sync); ixgbe_release_swfw_sync_semaphore(hw); - msleep(5); + usleep_range(5000, 10000); } /** @@ -661,7 +747,7 @@ static void ixgbe_release_swfw_sync_semaphore(struct ixgbe_hw *hw) static struct ixgbe_mac_operations mac_ops_X540 = { .init_hw = &ixgbe_init_hw_generic, .reset_hw = &ixgbe_reset_hw_X540, - .start_hw = &ixgbe_start_hw_generic, + .start_hw = &ixgbe_start_hw_X540, .clear_hw_cntrs = &ixgbe_clear_hw_cntrs_generic, .get_media_type = &ixgbe_get_media_type_X540, .get_supported_physical_layer = @@ -669,7 +755,7 @@ static struct ixgbe_mac_operations mac_ops_X540 = { .enable_rx_dma = &ixgbe_enable_rx_dma_generic, .get_mac_addr = &ixgbe_get_mac_addr_generic, .get_san_mac_addr = &ixgbe_get_san_mac_addr_generic, - .get_device_caps = NULL, + .get_device_caps = &ixgbe_get_device_caps_generic, .get_wwn_prefix = &ixgbe_get_wwn_prefix_generic, .stop_adapter = &ixgbe_stop_adapter_generic, .get_bus_info = &ixgbe_get_bus_info_generic, @@ -707,7 +793,7 @@ static struct ixgbe_eeprom_operations eeprom_ops_X540 = { .read = &ixgbe_read_eerd_X540, .write = &ixgbe_write_eewr_X540, .calc_checksum = &ixgbe_calc_eeprom_checksum_X540, - .validate_checksum = &ixgbe_validate_eeprom_checksum_generic, + .validate_checksum = &ixgbe_validate_eeprom_checksum_X540, .update_checksum = &ixgbe_update_eeprom_checksum_X540, }; diff --git a/drivers/net/jme.c b/drivers/net/jme.c index 994c80939c7a..be4773f54a24 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -2230,17 +2230,9 @@ jme_change_mtu(struct net_device *netdev, int new_mtu) jme_restart_rx_engine(jme); } - if (new_mtu > 1900) { - netdev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | - NETIF_F_TSO | NETIF_F_TSO6); - } else { - if (test_bit(JME_FLAG_TXCSUM, &jme->flags)) - netdev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; - if (test_bit(JME_FLAG_TSO, &jme->flags)) - netdev->features |= NETIF_F_TSO | NETIF_F_TSO6; - } - netdev->mtu = new_mtu; + netdev_update_features(netdev); + jme_reset_link(jme); return 0; @@ -2640,19 +2632,20 @@ jme_set_msglevel(struct net_device *netdev, u32 value) } static u32 -jme_get_rx_csum(struct net_device *netdev) +jme_fix_features(struct net_device *netdev, u32 features) { - struct jme_adapter *jme = netdev_priv(netdev); - return jme->reg_rxmcs & RXMCS_CHECKSUM; + if (netdev->mtu > 1900) + features &= ~(NETIF_F_ALL_TSO | NETIF_F_ALL_CSUM); + return features; } static int -jme_set_rx_csum(struct net_device *netdev, u32 on) +jme_set_features(struct net_device *netdev, u32 features) { struct jme_adapter *jme = netdev_priv(netdev); spin_lock_bh(&jme->rxmcs_lock); - if (on) + if (features & NETIF_F_RXCSUM) jme->reg_rxmcs |= RXMCS_CHECKSUM; else jme->reg_rxmcs &= ~RXMCS_CHECKSUM; @@ -2663,42 +2656,6 @@ jme_set_rx_csum(struct net_device *netdev, u32 on) } static int -jme_set_tx_csum(struct net_device *netdev, u32 on) -{ - struct jme_adapter *jme = netdev_priv(netdev); - - if (on) { - set_bit(JME_FLAG_TXCSUM, &jme->flags); - if (netdev->mtu <= 1900) - netdev->features |= - NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; - } else { - clear_bit(JME_FLAG_TXCSUM, &jme->flags); - netdev->features &= - ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); - } - - return 0; -} - -static int -jme_set_tso(struct net_device *netdev, u32 on) -{ - struct jme_adapter *jme = netdev_priv(netdev); - - if (on) { - set_bit(JME_FLAG_TSO, &jme->flags); - if (netdev->mtu <= 1900) - netdev->features |= NETIF_F_TSO | NETIF_F_TSO6; - } else { - clear_bit(JME_FLAG_TSO, &jme->flags); - netdev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); - } - - return 0; -} - -static int jme_nway_reset(struct net_device *netdev) { struct jme_adapter *jme = netdev_priv(netdev); @@ -2839,11 +2796,6 @@ static const struct ethtool_ops jme_ethtool_ops = { .get_link = jme_get_link, .get_msglevel = jme_get_msglevel, .set_msglevel = jme_set_msglevel, - .get_rx_csum = jme_get_rx_csum, - .set_rx_csum = jme_set_rx_csum, - .set_tx_csum = jme_set_tx_csum, - .set_tso = jme_set_tso, - .set_sg = ethtool_op_set_sg, .nway_reset = jme_nway_reset, .get_eeprom_len = jme_get_eeprom_len, .get_eeprom = jme_get_eeprom, @@ -2903,6 +2855,8 @@ static const struct net_device_ops jme_netdev_ops = { .ndo_change_mtu = jme_change_mtu, .ndo_tx_timeout = jme_tx_timeout, .ndo_vlan_rx_register = jme_vlan_rx_register, + .ndo_fix_features = jme_fix_features, + .ndo_set_features = jme_set_features, }; static int __devinit @@ -2957,6 +2911,12 @@ jme_init_one(struct pci_dev *pdev, netdev->netdev_ops = &jme_netdev_ops; netdev->ethtool_ops = &jme_ethtool_ops; netdev->watchdog_timeo = TX_TIMEOUT; + netdev->hw_features = NETIF_F_IP_CSUM | + NETIF_F_IPV6_CSUM | + NETIF_F_SG | + NETIF_F_TSO | + NETIF_F_TSO6 | + NETIF_F_RXCSUM; netdev->features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_SG | @@ -3040,8 +3000,9 @@ jme_init_one(struct pci_dev *pdev, jme->reg_txpfc = 0; jme->reg_pmcs = PMCS_MFEN; jme->reg_gpreg1 = GPREG1_DEFAULT; - set_bit(JME_FLAG_TXCSUM, &jme->flags); - set_bit(JME_FLAG_TSO, &jme->flags); + + if (jme->reg_rxmcs & RXMCS_CHECKSUM) + netdev->features |= NETIF_F_RXCSUM; /* * Get Max Read Req Size from PCI Config Space diff --git a/drivers/net/jme.h b/drivers/net/jme.h index 8bf30451e821..e9aaeca96abc 100644 --- a/drivers/net/jme.h +++ b/drivers/net/jme.h @@ -468,8 +468,6 @@ struct jme_adapter { enum jme_flags_bits { JME_FLAG_MSI = 1, JME_FLAG_SSET = 2, - JME_FLAG_TXCSUM = 3, - JME_FLAG_TSO = 4, JME_FLAG_POLL = 5, JME_FLAG_SHUTDOWN = 6, }; diff --git a/drivers/net/ksz884x.c b/drivers/net/ksz884x.c index 7f7d5708a658..2c37a3804303 100644 --- a/drivers/net/ksz884x.c +++ b/drivers/net/ksz884x.c @@ -1221,7 +1221,6 @@ struct ksz_port_info { #define LINK_INT_WORKING (1 << 0) #define SMALL_PACKET_TX_BUG (1 << 1) #define HALF_DUPLEX_SIGNAL_BUG (1 << 2) -#define IPV6_CSUM_GEN_HACK (1 << 3) #define RX_HUGE_FRAME (1 << 4) #define STP_SUPPORT (1 << 8) @@ -3748,7 +3747,6 @@ static int hw_init(struct ksz_hw *hw) if (1 == rc) hw->features |= HALF_DUPLEX_SIGNAL_BUG; } - hw->features |= IPV6_CSUM_GEN_HACK; return rc; } @@ -4887,8 +4885,7 @@ static netdev_tx_t netdev_tx(struct sk_buff *skb, struct net_device *dev) left = hw_alloc_pkt(hw, skb->len, num); if (left) { if (left < num || - ((hw->features & IPV6_CSUM_GEN_HACK) && - (CHECKSUM_PARTIAL == skb->ip_summed) && + ((CHECKSUM_PARTIAL == skb->ip_summed) && (ETH_P_IPV6 == htons(skb->protocol)))) { struct sk_buff *org_skb = skb; @@ -6583,57 +6580,33 @@ static void netdev_get_ethtool_stats(struct net_device *dev, } /** - * netdev_get_rx_csum - get receive checksum support + * netdev_set_features - set receive checksum support * @dev: Network device. - * - * This function gets receive checksum support setting. - * - * Return true if receive checksum is enabled; false otherwise. - */ -static u32 netdev_get_rx_csum(struct net_device *dev) -{ - struct dev_priv *priv = netdev_priv(dev); - struct dev_info *hw_priv = priv->adapter; - struct ksz_hw *hw = &hw_priv->hw; - - return hw->rx_cfg & - (DMA_RX_CSUM_UDP | - DMA_RX_CSUM_TCP | - DMA_RX_CSUM_IP); -} - -/** - * netdev_set_rx_csum - set receive checksum support - * @dev: Network device. - * @data: Zero to disable receive checksum support. + * @features: New device features (offloads). * * This function sets receive checksum support setting. * * Return 0 if successful; otherwise an error code. */ -static int netdev_set_rx_csum(struct net_device *dev, u32 data) +static int netdev_set_features(struct net_device *dev, u32 features) { struct dev_priv *priv = netdev_priv(dev); struct dev_info *hw_priv = priv->adapter; struct ksz_hw *hw = &hw_priv->hw; - u32 new_setting = hw->rx_cfg; - if (data) - new_setting |= - (DMA_RX_CSUM_UDP | DMA_RX_CSUM_TCP | - DMA_RX_CSUM_IP); - else - new_setting &= - ~(DMA_RX_CSUM_UDP | DMA_RX_CSUM_TCP | - DMA_RX_CSUM_IP); - new_setting &= ~DMA_RX_CSUM_UDP; mutex_lock(&hw_priv->lock); - if (new_setting != hw->rx_cfg) { - hw->rx_cfg = new_setting; - if (hw->enabled) - writel(hw->rx_cfg, hw->io + KS_DMA_RX_CTRL); - } + + /* see note in hw_setup() */ + if (features & NETIF_F_RXCSUM) + hw->rx_cfg |= DMA_RX_CSUM_TCP | DMA_RX_CSUM_IP; + else + hw->rx_cfg &= ~(DMA_RX_CSUM_TCP | DMA_RX_CSUM_IP); + + if (hw->enabled) + writel(hw->rx_cfg, hw->io + KS_DMA_RX_CTRL); + mutex_unlock(&hw_priv->lock); + return 0; } @@ -6658,12 +6631,6 @@ static struct ethtool_ops netdev_ethtool_ops = { .get_strings = netdev_get_strings, .get_sset_count = netdev_get_sset_count, .get_ethtool_stats = netdev_get_ethtool_stats, - .get_rx_csum = netdev_get_rx_csum, - .set_rx_csum = netdev_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, }; /* @@ -6828,14 +6795,15 @@ static int __init netdev_init(struct net_device *dev) /* 500 ms timeout */ dev->watchdog_timeo = HZ / 2; - dev->features |= NETIF_F_IP_CSUM; + dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_RXCSUM; /* * Hardware does not really support IPv6 checksum generation, but - * driver actually runs faster with this on. Refer IPV6_CSUM_GEN_HACK. + * driver actually runs faster with this on. */ - dev->features |= NETIF_F_IPV6_CSUM; - dev->features |= NETIF_F_SG; + dev->hw_features |= NETIF_F_IPV6_CSUM; + + dev->features |= dev->hw_features; sema_init(&priv->proc_sem, 1); @@ -6860,6 +6828,7 @@ static const struct net_device_ops netdev_ops = { .ndo_start_xmit = netdev_tx, .ndo_tx_timeout = netdev_tx_timeout, .ndo_change_mtu = netdev_change_mtu, + .ndo_set_features = netdev_set_features, .ndo_set_mac_address = netdev_set_mac_address, .ndo_validate_addr = eth_validate_addr, .ndo_do_ioctl = netdev_ioctl, diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 79ccb54ab00c..629bd2649c0c 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -576,6 +576,11 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id) * add that if/when we get our hands on a full-blown MII PHY. */ + if (status & MACB_BIT(ISR_ROVR)) { + /* We missed at least one packet */ + bp->hw_stats.rx_overruns++; + } + if (status & MACB_BIT(HRESP)) { /* * TODO: Reset the hardware, and maybe move the printk @@ -1024,7 +1029,8 @@ static struct net_device_stats *macb_get_stats(struct net_device *dev) hwstat->rx_jabbers + hwstat->rx_undersize_pkts + hwstat->rx_length_mismatch); - nstat->rx_over_errors = hwstat->rx_resource_errors; + nstat->rx_over_errors = hwstat->rx_resource_errors + + hwstat->rx_overruns; nstat->rx_crc_errors = hwstat->rx_fcs_errors; nstat->rx_frame_errors = hwstat->rx_align_errors; nstat->rx_fifo_errors = hwstat->rx_overruns; @@ -1171,8 +1177,7 @@ static int __init macb_probe(struct platform_device *pdev) } dev->irq = platform_get_irq(pdev, 0); - err = request_irq(dev->irq, macb_interrupt, IRQF_SAMPLE_RANDOM, - dev->name, dev); + err = request_irq(dev->irq, macb_interrupt, 0, dev->name, dev); if (err) { printk(KERN_ERR "%s: Unable to request IRQ %d (error %d)\n", diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 78e34e9e4f00..3ad5425b82dd 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -415,7 +415,7 @@ static struct lock_class_key macvlan_netdev_addr_lock_key; #define MACVLAN_FEATURES \ (NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \ NETIF_F_GSO | NETIF_F_TSO | NETIF_F_UFO | NETIF_F_GSO_ROBUST | \ - NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_GRO) + NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_GRO | NETIF_F_RXCSUM) #define MACVLAN_STATE_MASK \ ((1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT)) @@ -517,12 +517,6 @@ static void macvlan_ethtool_get_drvinfo(struct net_device *dev, snprintf(drvinfo->version, 32, "0.1"); } -static u32 macvlan_ethtool_get_rx_csum(struct net_device *dev) -{ - const struct macvlan_dev *vlan = netdev_priv(dev); - return dev_ethtool_get_rx_csum(vlan->lowerdev); -} - static int macvlan_ethtool_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { @@ -530,18 +524,10 @@ static int macvlan_ethtool_get_settings(struct net_device *dev, return dev_ethtool_get_settings(vlan->lowerdev, cmd); } -static u32 macvlan_ethtool_get_flags(struct net_device *dev) -{ - const struct macvlan_dev *vlan = netdev_priv(dev); - return dev_ethtool_get_flags(vlan->lowerdev); -} - static const struct ethtool_ops macvlan_ethtool_ops = { .get_link = ethtool_op_get_link, .get_settings = macvlan_ethtool_get_settings, - .get_rx_csum = macvlan_ethtool_get_rx_csum, .get_drvinfo = macvlan_ethtool_get_drvinfo, - .get_flags = macvlan_ethtool_get_flags, }; static const struct net_device_ops macvlan_netdev_ops = { diff --git a/drivers/net/mlx4/en_ethtool.c b/drivers/net/mlx4/en_ethtool.c index d54b7abf0225..da1b64d68607 100644 --- a/drivers/net/mlx4/en_ethtool.c +++ b/drivers/net/mlx4/en_ethtool.c @@ -57,37 +57,6 @@ mlx4_en_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) drvinfo->eedump_len = 0; } -static u32 mlx4_en_get_tso(struct net_device *dev) -{ - return (dev->features & NETIF_F_TSO) != 0; -} - -static int mlx4_en_set_tso(struct net_device *dev, u32 data) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - - if (data) { - if (!priv->mdev->LSO_support) - return -EPERM; - dev->features |= (NETIF_F_TSO | NETIF_F_TSO6); - } else - dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); - return 0; -} - -static u32 mlx4_en_get_rx_csum(struct net_device *dev) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - return priv->rx_csum; -} - -static int mlx4_en_set_rx_csum(struct net_device *dev, u32 data) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - priv->rx_csum = (data != 0); - return 0; -} - static const char main_strings[][ETH_GSTRING_LEN] = { "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors", "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions", @@ -483,17 +452,7 @@ const struct ethtool_ops mlx4_en_ethtool_ops = { .get_drvinfo = mlx4_en_get_drvinfo, .get_settings = mlx4_en_get_settings, .set_settings = mlx4_en_set_settings, -#ifdef NETIF_F_TSO - .get_tso = mlx4_en_get_tso, - .set_tso = mlx4_en_set_tso, -#endif - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, .get_link = ethtool_op_get_link, - .get_rx_csum = mlx4_en_get_rx_csum, - .set_rx_csum = mlx4_en_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_ipv6_csum, .get_strings = mlx4_en_get_strings, .get_sset_count = mlx4_en_get_sset_count, .get_ethtool_stats = mlx4_en_get_ethtool_stats, @@ -508,7 +467,6 @@ const struct ethtool_ops mlx4_en_ethtool_ops = { .set_pauseparam = mlx4_en_set_pauseparam, .get_ringparam = mlx4_en_get_ringparam, .set_ringparam = mlx4_en_set_ringparam, - .get_flags = ethtool_op_get_flags, }; diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c index 77063f91c564..61850adae6f7 100644 --- a/drivers/net/mlx4/en_netdev.c +++ b/drivers/net/mlx4/en_netdev.c @@ -1083,7 +1083,6 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, priv->prof = prof; priv->port = port; priv->port_up = false; - priv->rx_csum = 1; priv->flags = prof->flags; priv->tx_ring_num = prof->tx_ring_num; priv->rx_ring_num = prof->rx_ring_num; @@ -1141,21 +1140,16 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, /* * Set driver features */ - dev->features |= NETIF_F_SG; - dev->vlan_features |= NETIF_F_SG; - dev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; - dev->vlan_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; - dev->features |= NETIF_F_HIGHDMA; - dev->features |= NETIF_F_HW_VLAN_TX | - NETIF_F_HW_VLAN_RX | - NETIF_F_HW_VLAN_FILTER; - dev->features |= NETIF_F_GRO; - if (mdev->LSO_support) { - dev->features |= NETIF_F_TSO; - dev->features |= NETIF_F_TSO6; - dev->vlan_features |= NETIF_F_TSO; - dev->vlan_features |= NETIF_F_TSO6; - } + dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + if (mdev->LSO_support) + dev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6; + + dev->vlan_features = dev->hw_features; + + dev->hw_features |= NETIF_F_RXCSUM; + dev->features = dev->hw_features | NETIF_F_HIGHDMA | + NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | + NETIF_F_HW_VLAN_FILTER; mdev->pndev[port] = dev; diff --git a/drivers/net/mlx4/en_rx.c b/drivers/net/mlx4/en_rx.c index 62dd21b06df4..277215fb9d72 100644 --- a/drivers/net/mlx4/en_rx.c +++ b/drivers/net/mlx4/en_rx.c @@ -584,7 +584,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud ring->bytes += length; ring->packets++; - if (likely(priv->rx_csum)) { + if (likely(dev->features & NETIF_F_RXCSUM)) { if ((cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPOK)) && (cqe->checksum == cpu_to_be16(0xffff))) { priv->port_stats.rx_chksum_good++; diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h index e30f6099c0de..0b5150df0585 100644 --- a/drivers/net/mlx4/mlx4_en.h +++ b/drivers/net/mlx4/mlx4_en.h @@ -451,7 +451,6 @@ struct mlx4_en_priv { int registered; int allocated; int stride; - int rx_csum; u64 mac; int mac_index; unsigned max_mtu; diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 34425b94452f..29605a34d4c1 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -1575,18 +1575,12 @@ mv643xx_eth_set_ringparam(struct net_device *dev, struct ethtool_ringparam *er) return 0; } -static u32 -mv643xx_eth_get_rx_csum(struct net_device *dev) -{ - struct mv643xx_eth_private *mp = netdev_priv(dev); - - return !!(rdlp(mp, PORT_CONFIG) & 0x02000000); -} static int -mv643xx_eth_set_rx_csum(struct net_device *dev, u32 rx_csum) +mv643xx_eth_set_features(struct net_device *dev, u32 features) { struct mv643xx_eth_private *mp = netdev_priv(dev); + u32 rx_csum = features & NETIF_F_RXCSUM; wrlp(mp, PORT_CONFIG, rx_csum ? 0x02000000 : 0x00000000); @@ -1634,11 +1628,6 @@ static void mv643xx_eth_get_ethtool_stats(struct net_device *dev, } } -static int mv643xx_eth_set_flags(struct net_device *dev, u32 data) -{ - return ethtool_op_set_flags(dev, data, ETH_FLAG_LRO); -} - static int mv643xx_eth_get_sset_count(struct net_device *dev, int sset) { if (sset == ETH_SS_STATS) @@ -1657,14 +1646,8 @@ static const struct ethtool_ops mv643xx_eth_ethtool_ops = { .set_coalesce = mv643xx_eth_set_coalesce, .get_ringparam = mv643xx_eth_get_ringparam, .set_ringparam = mv643xx_eth_set_ringparam, - .get_rx_csum = mv643xx_eth_get_rx_csum, - .set_rx_csum = mv643xx_eth_set_rx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, - .set_sg = ethtool_op_set_sg, .get_strings = mv643xx_eth_get_strings, .get_ethtool_stats = mv643xx_eth_get_ethtool_stats, - .get_flags = ethtool_op_get_flags, - .set_flags = mv643xx_eth_set_flags, .get_sset_count = mv643xx_eth_get_sset_count, }; @@ -2264,7 +2247,7 @@ static void port_start(struct mv643xx_eth_private *mp) * frames to RX queue #0, and include the pseudo-header when * calculating receive checksums. */ - wrlp(mp, PORT_CONFIG, 0x02000000); + mv643xx_eth_set_features(dev, dev->features); /* * Treat BPDUs as normal multicasts, and disable partition mode. @@ -2848,6 +2831,7 @@ static const struct net_device_ops mv643xx_eth_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_do_ioctl = mv643xx_eth_ioctl, .ndo_change_mtu = mv643xx_eth_change_mtu, + .ndo_set_features = mv643xx_eth_set_features, .ndo_tx_timeout = mv643xx_eth_tx_timeout, .ndo_get_stats = mv643xx_eth_get_stats, #ifdef CONFIG_NET_POLL_CONTROLLER @@ -2930,7 +2914,9 @@ static int mv643xx_eth_probe(struct platform_device *pdev) dev->watchdog_timeo = 2 * HZ; dev->base_addr = 0; - dev->features = NETIF_F_SG | NETIF_F_IP_CSUM; + dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | + NETIF_F_RXCSUM | NETIF_F_LRO; + dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM; dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM; SET_NETDEV_DEV(dev, &pdev->dev); diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 1446de59ae53..e7f801643c12 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -205,7 +205,6 @@ struct myri10ge_priv { int tx_boundary; /* boundary transmits cannot cross */ int num_slices; int running; /* running? */ - int csum_flag; /* rx_csums? */ int small_bytes; int big_bytes; int max_intr_slots; @@ -1386,7 +1385,7 @@ myri10ge_rx_done(struct myri10ge_slice_state *ss, int len, __wsum csum, skb->protocol = eth_type_trans(skb, dev); skb_record_rx_queue(skb, ss - &mgp->ss[0]); - if (mgp->csum_flag) { + if (dev->features & NETIF_F_RXCSUM) { if ((skb->protocol == htons(ETH_P_IP)) || (skb->protocol == htons(ETH_P_IPV6))) { skb->csum = csum; @@ -1757,43 +1756,6 @@ myri10ge_get_ringparam(struct net_device *netdev, ring->tx_pending = ring->tx_max_pending; } -static u32 myri10ge_get_rx_csum(struct net_device *netdev) -{ - struct myri10ge_priv *mgp = netdev_priv(netdev); - - if (mgp->csum_flag) - return 1; - else - return 0; -} - -static int myri10ge_set_rx_csum(struct net_device *netdev, u32 csum_enabled) -{ - struct myri10ge_priv *mgp = netdev_priv(netdev); - int err = 0; - - if (csum_enabled) - mgp->csum_flag = MXGEFW_FLAGS_CKSUM; - else { - netdev->features &= ~NETIF_F_LRO; - mgp->csum_flag = 0; - - } - return err; -} - -static int myri10ge_set_tso(struct net_device *netdev, u32 tso_enabled) -{ - struct myri10ge_priv *mgp = netdev_priv(netdev); - u32 flags = mgp->features & (NETIF_F_TSO6 | NETIF_F_TSO); - - if (tso_enabled) - netdev->features |= flags; - else - netdev->features &= ~flags; - return 0; -} - static const char myri10ge_gstrings_main_stats[][ETH_GSTRING_LEN] = { "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors", "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions", @@ -1944,11 +1906,6 @@ static u32 myri10ge_get_msglevel(struct net_device *netdev) return mgp->msg_enable; } -static int myri10ge_set_flags(struct net_device *netdev, u32 value) -{ - return ethtool_op_set_flags(netdev, value, ETH_FLAG_LRO); -} - static const struct ethtool_ops myri10ge_ethtool_ops = { .get_settings = myri10ge_get_settings, .get_drvinfo = myri10ge_get_drvinfo, @@ -1957,19 +1914,12 @@ static const struct ethtool_ops myri10ge_ethtool_ops = { .get_pauseparam = myri10ge_get_pauseparam, .set_pauseparam = myri10ge_set_pauseparam, .get_ringparam = myri10ge_get_ringparam, - .get_rx_csum = myri10ge_get_rx_csum, - .set_rx_csum = myri10ge_set_rx_csum, - .set_tx_csum = ethtool_op_set_tx_hw_csum, - .set_sg = ethtool_op_set_sg, - .set_tso = myri10ge_set_tso, .get_link = ethtool_op_get_link, .get_strings = myri10ge_get_strings, .get_sset_count = myri10ge_get_sset_count, .get_ethtool_stats = myri10ge_get_ethtool_stats, .set_msglevel = myri10ge_set_msglevel, .get_msglevel = myri10ge_get_msglevel, - .get_flags = ethtool_op_get_flags, - .set_flags = myri10ge_set_flags }; static int myri10ge_allocate_rings(struct myri10ge_slice_state *ss) @@ -3136,6 +3086,14 @@ static int myri10ge_set_mac_address(struct net_device *dev, void *addr) return 0; } +static u32 myri10ge_fix_features(struct net_device *dev, u32 features) +{ + if (!(features & NETIF_F_RXCSUM)) + features &= ~NETIF_F_LRO; + + return features; +} + static int myri10ge_change_mtu(struct net_device *dev, int new_mtu) { struct myri10ge_priv *mgp = netdev_priv(dev); @@ -3834,6 +3792,7 @@ static const struct net_device_ops myri10ge_netdev_ops = { .ndo_get_stats = myri10ge_get_stats, .ndo_validate_addr = eth_validate_addr, .ndo_change_mtu = myri10ge_change_mtu, + .ndo_fix_features = myri10ge_fix_features, .ndo_set_multicast_list = myri10ge_set_multicast_list, .ndo_set_mac_address = myri10ge_set_mac_address, }; @@ -3860,7 +3819,6 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) mgp = netdev_priv(netdev); mgp->dev = netdev; mgp->pdev = pdev; - mgp->csum_flag = MXGEFW_FLAGS_CKSUM; mgp->pause = myri10ge_flow_control; mgp->intr_coal_delay = myri10ge_intr_coal_delay; mgp->msg_enable = netif_msg_init(myri10ge_debug, MYRI10GE_MSG_DEFAULT); @@ -3976,11 +3934,11 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->netdev_ops = &myri10ge_netdev_ops; netdev->mtu = myri10ge_initial_mtu; netdev->base_addr = mgp->iomem_base; - netdev->features = mgp->features; + netdev->hw_features = mgp->features | NETIF_F_LRO | NETIF_F_RXCSUM; + netdev->features = netdev->hw_features; if (dac_enabled) netdev->features |= NETIF_F_HIGHDMA; - netdev->features |= NETIF_F_LRO; netdev->vlan_features |= mgp->features; if (mgp->fw_ver_tiny < 37) diff --git a/drivers/net/ne3210.c b/drivers/net/ne3210.c index 243ed2aee88e..e8984b0ca521 100644 --- a/drivers/net/ne3210.c +++ b/drivers/net/ne3210.c @@ -80,17 +80,20 @@ static void ne3210_block_output(struct net_device *dev, int count, const unsigne #define NE3210_DEBUG 0x0 -static unsigned char irq_map[] __initdata = {15, 12, 11, 10, 9, 7, 5, 3}; -static unsigned int shmem_map[] __initdata = {0xff0, 0xfe0, 0xfff0, 0xd8, 0xffe0, 0xffc0, 0xd0, 0x0}; -static const char *ifmap[] __initdata = {"UTP", "?", "BNC", "AUI"}; -static int ifmap_val[] __initdata = { +static const unsigned char irq_map[] __devinitconst = + { 15, 12, 11, 10, 9, 7, 5, 3 }; +static const unsigned int shmem_map[] __devinitconst = + { 0xff0, 0xfe0, 0xfff0, 0xd8, 0xffe0, 0xffc0, 0xd0, 0x0 }; +static const char *const ifmap[] __devinitconst = + { "UTP", "?", "BNC", "AUI" }; +static const int ifmap_val[] __devinitconst = { IF_PORT_10BASET, IF_PORT_UNKNOWN, IF_PORT_10BASE2, IF_PORT_AUI, }; -static int __init ne3210_eisa_probe (struct device *device) +static int __devinit ne3210_eisa_probe (struct device *device) { unsigned long ioaddr, phys_mem; int i, retval, port_index; @@ -313,7 +316,7 @@ static void ne3210_block_output(struct net_device *dev, int count, memcpy_toio(shmem, buf, count); } -static struct eisa_device_id ne3210_ids[] = { +static const struct eisa_device_id ne3210_ids[] __devinitconst = { { "EGL0101" }, { "NVL1801" }, { "" }, diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 679dc8519c5b..77220687b92a 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -1177,7 +1177,7 @@ struct netxen_adapter { u8 max_sds_rings; u8 driver_mismatch; u8 msix_supported; - u8 rx_csum; + u8 __pad; u8 pci_using_dac; u8 portnum; u8 physical_port; diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index 3bdcc803ec68..29f90baaa79b 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -676,62 +676,6 @@ netxen_nic_get_ethtool_stats(struct net_device *dev, } } -static u32 netxen_nic_get_tx_csum(struct net_device *dev) -{ - return dev->features & NETIF_F_IP_CSUM; -} - -static u32 netxen_nic_get_rx_csum(struct net_device *dev) -{ - struct netxen_adapter *adapter = netdev_priv(dev); - return adapter->rx_csum; -} - -static int netxen_nic_set_rx_csum(struct net_device *dev, u32 data) -{ - struct netxen_adapter *adapter = netdev_priv(dev); - - if (data) { - adapter->rx_csum = data; - return 0; - } - - if (dev->features & NETIF_F_LRO) { - if (netxen_config_hw_lro(adapter, NETXEN_NIC_LRO_DISABLED)) - return -EIO; - - dev->features &= ~NETIF_F_LRO; - netxen_send_lro_cleanup(adapter); - netdev_info(dev, "disabling LRO as rx_csum is off\n"); - } - adapter->rx_csum = data; - return 0; -} - -static u32 netxen_nic_get_tso(struct net_device *dev) -{ - struct netxen_adapter *adapter = netdev_priv(dev); - - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) - return (dev->features & (NETIF_F_TSO | NETIF_F_TSO6)) != 0; - - return (dev->features & NETIF_F_TSO) != 0; -} - -static int netxen_nic_set_tso(struct net_device *dev, u32 data) -{ - if (data) { - struct netxen_adapter *adapter = netdev_priv(dev); - - dev->features |= NETIF_F_TSO; - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) - dev->features |= NETIF_F_TSO6; - } else - dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); - - return 0; -} - static void netxen_nic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { @@ -866,43 +810,6 @@ static int netxen_get_intr_coalesce(struct net_device *netdev, return 0; } -static int netxen_nic_set_flags(struct net_device *netdev, u32 data) -{ - struct netxen_adapter *adapter = netdev_priv(netdev); - int hw_lro; - - if (ethtool_invalid_flags(netdev, data, ETH_FLAG_LRO)) - return -EINVAL; - - if (!(adapter->capabilities & NX_FW_CAPABILITY_HW_LRO)) - return -EINVAL; - - if (!adapter->rx_csum) { - netdev_info(netdev, "rx csum is off, cannot toggle LRO\n"); - return -EINVAL; - } - - if (!!(data & ETH_FLAG_LRO) == !!(netdev->features & NETIF_F_LRO)) - return 0; - - if (data & ETH_FLAG_LRO) { - hw_lro = NETXEN_NIC_LRO_ENABLED; - netdev->features |= NETIF_F_LRO; - } else { - hw_lro = NETXEN_NIC_LRO_DISABLED; - netdev->features &= ~NETIF_F_LRO; - } - - if (netxen_config_hw_lro(adapter, hw_lro)) - return -EIO; - - if ((hw_lro == 0) && netxen_send_lro_cleanup(adapter)) - return -EIO; - - - return 0; -} - const struct ethtool_ops netxen_nic_ethtool_ops = { .get_settings = netxen_nic_get_settings, .set_settings = netxen_nic_set_settings, @@ -916,21 +823,12 @@ const struct ethtool_ops netxen_nic_ethtool_ops = { .set_ringparam = netxen_nic_set_ringparam, .get_pauseparam = netxen_nic_get_pauseparam, .set_pauseparam = netxen_nic_set_pauseparam, - .get_tx_csum = netxen_nic_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, - .set_sg = ethtool_op_set_sg, - .get_tso = netxen_nic_get_tso, - .set_tso = netxen_nic_set_tso, .get_wol = netxen_nic_get_wol, .set_wol = netxen_nic_set_wol, .self_test = netxen_nic_diag_test, .get_strings = netxen_nic_get_strings, .get_ethtool_stats = netxen_nic_get_ethtool_stats, .get_sset_count = netxen_get_sset_count, - .get_rx_csum = netxen_nic_get_rx_csum, - .set_rx_csum = netxen_nic_set_rx_csum, .get_coalesce = netxen_get_intr_coalesce, .set_coalesce = netxen_set_intr_coalesce, - .get_flags = ethtool_op_get_flags, - .set_flags = netxen_nic_set_flags, }; diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 731077d8d962..7f999671c7b2 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -1483,7 +1483,8 @@ static struct sk_buff *netxen_process_rxbuf(struct netxen_adapter *adapter, if (!skb) goto no_skb; - if (likely(adapter->rx_csum && cksum == STATUS_CKSUM_OK)) { + if (likely((adapter->netdev->features & NETIF_F_RXCSUM) + && cksum == STATUS_CKSUM_OK)) { adapter->stats.csummed++; skb->ip_summed = CHECKSUM_UNNECESSARY; } else diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index e8a4b6655999..b644383017f9 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -485,6 +485,37 @@ static void netxen_set_multicast_list(struct net_device *dev) adapter->set_multi(dev); } +static u32 netxen_fix_features(struct net_device *dev, u32 features) +{ + if (!(features & NETIF_F_RXCSUM)) { + netdev_info(dev, "disabling LRO as RXCSUM is off\n"); + + features &= ~NETIF_F_LRO; + } + + return features; +} + +static int netxen_set_features(struct net_device *dev, u32 features) +{ + struct netxen_adapter *adapter = netdev_priv(dev); + int hw_lro; + + if (!((dev->features ^ features) & NETIF_F_LRO)) + return 0; + + hw_lro = (features & NETIF_F_LRO) ? NETXEN_NIC_LRO_ENABLED + : NETXEN_NIC_LRO_DISABLED; + + if (netxen_config_hw_lro(adapter, hw_lro)) + return -EIO; + + if (!(features & NETIF_F_LRO) && netxen_send_lro_cleanup(adapter)) + return -EIO; + + return 0; +} + static const struct net_device_ops netxen_netdev_ops = { .ndo_open = netxen_nic_open, .ndo_stop = netxen_nic_close, @@ -495,6 +526,8 @@ static const struct net_device_ops netxen_netdev_ops = { .ndo_set_mac_address = netxen_nic_set_mac, .ndo_change_mtu = netxen_nic_change_mtu, .ndo_tx_timeout = netxen_tx_timeout, + .ndo_fix_features = netxen_fix_features, + .ndo_set_features = netxen_set_features, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = netxen_nic_poll_controller, #endif @@ -905,7 +938,7 @@ netxen_nic_request_irq(struct netxen_adapter *adapter) struct nx_host_sds_ring *sds_ring; int err, ring; - unsigned long flags = IRQF_SAMPLE_RANDOM; + unsigned long flags = 0; struct net_device *netdev = adapter->netdev; struct netxen_recv_context *recv_ctx = &adapter->recv_ctx; @@ -1196,7 +1229,6 @@ netxen_setup_netdev(struct netxen_adapter *adapter, int err = 0; struct pci_dev *pdev = adapter->pdev; - adapter->rx_csum = 1; adapter->mc_enabled = 0; if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) adapter->max_mc_count = 38; @@ -1210,14 +1242,13 @@ netxen_setup_netdev(struct netxen_adapter *adapter, SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops); - netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO); - netdev->features |= (NETIF_F_GRO); - netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO); + netdev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO | + NETIF_F_RXCSUM; - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { - netdev->features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6); - netdev->vlan_features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6); - } + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) + netdev->hw_features |= NETIF_F_IPV6_CSUM | NETIF_F_TSO6; + + netdev->vlan_features |= netdev->hw_features; if (adapter->pci_using_dac) { netdev->features |= NETIF_F_HIGHDMA; @@ -1225,10 +1256,12 @@ netxen_setup_netdev(struct netxen_adapter *adapter, } if (adapter->capabilities & NX_FW_CAPABILITY_FVLANTX) - netdev->features |= (NETIF_F_HW_VLAN_TX); + netdev->hw_features |= NETIF_F_HW_VLAN_TX; if (adapter->capabilities & NX_FW_CAPABILITY_HW_LRO) - netdev->features |= NETIF_F_LRO; + netdev->hw_features |= NETIF_F_LRO; + + netdev->features |= netdev->hw_features; netdev->irq = adapter->msix_entries[0].vector; diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 32678b6c6b39..a7072174ffa7 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -1233,7 +1233,7 @@ static int link_status_1g_rgmii(struct niu *np, int *link_up_p) bmsr = err; if (bmsr & BMSR_LSTATUS) { - u16 adv, lpa, common, estat; + u16 adv, lpa; err = mii_read(np, np->phy_addr, MII_ADVERTISE); if (err < 0) @@ -1245,12 +1245,9 @@ static int link_status_1g_rgmii(struct niu *np, int *link_up_p) goto out; lpa = err; - common = adv & lpa; - err = mii_read(np, np->phy_addr, MII_ESTATUS); if (err < 0) goto out; - estat = err; link_up = 1; current_speed = SPEED_1000; current_duplex = DUPLEX_FULL; @@ -1650,7 +1647,7 @@ static int xcvr_init_10g(struct niu *np) break; } - return 0; + return err; } static int mii_reset(struct niu *np) @@ -2381,17 +2378,14 @@ static int serdes_init_10g_serdes(struct niu *np) struct niu_link_config *lp = &np->link_config; unsigned long ctrl_reg, test_cfg_reg, pll_cfg, i; u64 ctrl_val, test_cfg_val, sig, mask, val; - u64 reset_val; switch (np->port) { case 0: - reset_val = ENET_SERDES_RESET_0; ctrl_reg = ENET_SERDES_0_CTRL_CFG; test_cfg_reg = ENET_SERDES_0_TEST_CFG; pll_cfg = ENET_SERDES_0_PLL_CFG; break; case 1: - reset_val = ENET_SERDES_RESET_1; ctrl_reg = ENET_SERDES_1_CTRL_CFG; test_cfg_reg = ENET_SERDES_1_TEST_CFG; pll_cfg = ENET_SERDES_1_PLL_CFG; @@ -6071,8 +6065,7 @@ static int niu_request_irq(struct niu *np) for (i = 0; i < np->num_ldg; i++) { struct niu_ldg *lp = &np->ldg[i]; - err = request_irq(lp->irq, niu_interrupt, - IRQF_SHARED | IRQF_SAMPLE_RANDOM, + err = request_irq(lp->irq, niu_interrupt, IRQF_SHARED, np->irq_name[i], lp); if (err) goto out_free_irqs; @@ -7023,6 +7016,7 @@ static int niu_ethflow_to_class(int flow_type, u64 *class) case UDP_V4_FLOW: *class = CLASS_CODE_UDP_IPV4; break; + case AH_ESP_V4_FLOW: case AH_V4_FLOW: case ESP_V4_FLOW: *class = CLASS_CODE_AH_ESP_IPV4; @@ -7036,6 +7030,7 @@ static int niu_ethflow_to_class(int flow_type, u64 *class) case UDP_V6_FLOW: *class = CLASS_CODE_UDP_IPV6; break; + case AH_ESP_V6_FLOW: case AH_V6_FLOW: case ESP_V6_FLOW: *class = CLASS_CODE_AH_ESP_IPV6; @@ -7889,37 +7884,35 @@ static void niu_force_led(struct niu *np, int on) nw64_mac(reg, val); } -static int niu_phys_id(struct net_device *dev, u32 data) +static int niu_set_phys_id(struct net_device *dev, + enum ethtool_phys_id_state state) + { struct niu *np = netdev_priv(dev); - u64 orig_led_state; - int i; if (!netif_running(dev)) return -EAGAIN; - if (data == 0) - data = 2; + switch (state) { + case ETHTOOL_ID_ACTIVE: + np->orig_led_state = niu_led_state_save(np); + return 1; /* cycle on/off once per second */ - orig_led_state = niu_led_state_save(np); - for (i = 0; i < (data * 2); i++) { - int on = ((i % 2) == 0); + case ETHTOOL_ID_ON: + niu_force_led(np, 1); + break; - niu_force_led(np, on); + case ETHTOOL_ID_OFF: + niu_force_led(np, 0); + break; - if (msleep_interruptible(500)) - break; + case ETHTOOL_ID_INACTIVE: + niu_led_state_restore(np, np->orig_led_state); } - niu_led_state_restore(np, orig_led_state); return 0; } -static int niu_set_flags(struct net_device *dev, u32 data) -{ - return ethtool_op_set_flags(dev, data, ETH_FLAG_RXHASH); -} - static const struct ethtool_ops niu_ethtool_ops = { .get_drvinfo = niu_get_drvinfo, .get_link = ethtool_op_get_link, @@ -7933,11 +7926,9 @@ static const struct ethtool_ops niu_ethtool_ops = { .get_strings = niu_get_strings, .get_sset_count = niu_get_sset_count, .get_ethtool_stats = niu_get_ethtool_stats, - .phys_id = niu_phys_id, + .set_phys_id = niu_set_phys_id, .get_rxnfc = niu_get_nfc, .set_rxnfc = niu_set_nfc, - .set_flags = niu_set_flags, - .get_flags = ethtool_op_get_flags, }; static int niu_ldg_assign_ldn(struct niu *np, struct niu_parent *parent, @@ -8131,7 +8122,7 @@ static int __devinit niu_pci_vpd_scan_props(struct niu *np, netif_printk(np, probe, KERN_DEBUG, np->dev, "VPD_SCAN: start[%x] end[%x]\n", start, end); while (start < end) { - int len, err, instance, type, prop_len; + int len, err, prop_len; char namebuf[64]; u8 *prop_buf; int max_len; @@ -8147,8 +8138,6 @@ static int __devinit niu_pci_vpd_scan_props(struct niu *np, len = err; start += 3; - instance = niu_pci_eeprom_read(np, start); - type = niu_pci_eeprom_read(np, start + 3); prop_len = niu_pci_eeprom_read(np, start + 4); err = niu_pci_vpd_get_propname(np, start + 5, namebuf, 64); if (err < 0) @@ -9768,8 +9757,8 @@ static void __devinit niu_device_announce(struct niu *np) static void __devinit niu_set_basic_features(struct net_device *dev) { - dev->features |= (NETIF_F_SG | NETIF_F_HW_CSUM | - NETIF_F_GRO | NETIF_F_RXHASH); + dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_RXHASH; + dev->features |= dev->hw_features | NETIF_F_RXCSUM; } static int __devinit niu_pci_init_one(struct pci_dev *pdev, diff --git a/drivers/net/niu.h b/drivers/net/niu.h index a41fa8ebe05f..51e177e1860d 100644 --- a/drivers/net/niu.h +++ b/drivers/net/niu.h @@ -3279,6 +3279,7 @@ struct niu { unsigned long xpcs_off; struct timer_list timer; + u64 orig_led_state; const struct niu_phy_ops *phy_ops; int phy_addr; diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 768037602dff..0a1efbae1bc0 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -295,12 +295,14 @@ struct pcnet32_private { struct net_device *next; struct mii_if_info mii_if; struct timer_list watchdog_timer; - struct timer_list blink_timer; u32 msg_enable; /* debug message level */ /* each bit indicates an available PHY */ u32 phymask; unsigned short chip_version; /* which variant this is */ + + /* saved registers during ethtool blink */ + u16 save_regs[4]; }; static int pcnet32_probe_pci(struct pci_dev *, const struct pci_device_id *); @@ -324,8 +326,6 @@ static void pcnet32_restart(struct net_device *dev, unsigned int csr0_bits); static void pcnet32_ethtool_test(struct net_device *dev, struct ethtool_test *eth_test, u64 * data); static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1); -static int pcnet32_phys_id(struct net_device *dev, u32 data); -static void pcnet32_led_blink_callback(struct net_device *dev); static int pcnet32_get_regs_len(struct net_device *dev); static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *ptr); @@ -1022,7 +1022,8 @@ clean_up: return rc; } /* end pcnet32_loopback_test */ -static void pcnet32_led_blink_callback(struct net_device *dev) +static int pcnet32_set_phys_id(struct net_device *dev, + enum ethtool_phys_id_state state) { struct pcnet32_private *lp = netdev_priv(dev); struct pcnet32_access *a = &lp->a; @@ -1030,50 +1031,31 @@ static void pcnet32_led_blink_callback(struct net_device *dev) unsigned long flags; int i; - spin_lock_irqsave(&lp->lock, flags); - for (i = 4; i < 8; i++) - a->write_bcr(ioaddr, i, a->read_bcr(ioaddr, i) ^ 0x4000); - spin_unlock_irqrestore(&lp->lock, flags); - - mod_timer(&lp->blink_timer, PCNET32_BLINK_TIMEOUT); -} + switch (state) { + case ETHTOOL_ID_ACTIVE: + /* Save the current value of the bcrs */ + spin_lock_irqsave(&lp->lock, flags); + for (i = 4; i < 8; i++) + lp->save_regs[i - 4] = a->read_bcr(ioaddr, i); + spin_unlock_irqrestore(&lp->lock, flags); + return 2; /* cycle on/off twice per second */ -static int pcnet32_phys_id(struct net_device *dev, u32 data) -{ - struct pcnet32_private *lp = netdev_priv(dev); - struct pcnet32_access *a = &lp->a; - ulong ioaddr = dev->base_addr; - unsigned long flags; - int i, regs[4]; + case ETHTOOL_ID_ON: + case ETHTOOL_ID_OFF: + /* Blink the led */ + spin_lock_irqsave(&lp->lock, flags); + for (i = 4; i < 8; i++) + a->write_bcr(ioaddr, i, a->read_bcr(ioaddr, i) ^ 0x4000); + spin_unlock_irqrestore(&lp->lock, flags); + break; - if (!lp->blink_timer.function) { - init_timer(&lp->blink_timer); - lp->blink_timer.function = (void *)pcnet32_led_blink_callback; - lp->blink_timer.data = (unsigned long)dev; + case ETHTOOL_ID_INACTIVE: + /* Restore the original value of the bcrs */ + spin_lock_irqsave(&lp->lock, flags); + for (i = 4; i < 8; i++) + a->write_bcr(ioaddr, i, lp->save_regs[i - 4]); + spin_unlock_irqrestore(&lp->lock, flags); } - - /* Save the current value of the bcrs */ - spin_lock_irqsave(&lp->lock, flags); - for (i = 4; i < 8; i++) - regs[i - 4] = a->read_bcr(ioaddr, i); - spin_unlock_irqrestore(&lp->lock, flags); - - mod_timer(&lp->blink_timer, jiffies); - set_current_state(TASK_INTERRUPTIBLE); - - /* AV: the limit here makes no sense whatsoever */ - if ((!data) || (data > (u32) (MAX_SCHEDULE_TIMEOUT / HZ))) - data = (u32) (MAX_SCHEDULE_TIMEOUT / HZ); - - msleep_interruptible(data * 1000); - del_timer_sync(&lp->blink_timer); - - /* Restore the original value of the bcrs */ - spin_lock_irqsave(&lp->lock, flags); - for (i = 4; i < 8; i++) - a->write_bcr(ioaddr, i, regs[i - 4]); - spin_unlock_irqrestore(&lp->lock, flags); - return 0; } @@ -1450,7 +1432,7 @@ static const struct ethtool_ops pcnet32_ethtool_ops = { .set_ringparam = pcnet32_set_ringparam, .get_strings = pcnet32_get_strings, .self_test = pcnet32_ethtool_test, - .phys_id = pcnet32_phys_id, + .set_phys_id = pcnet32_set_phys_id, .get_regs_len = pcnet32_get_regs_len, .get_regs = pcnet32_get_regs, .get_sset_count = pcnet32_get_sset_count, diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index ffdf7349ef7a..4383ed21813e 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c @@ -951,7 +951,7 @@ static void gelic_net_pass_skb_up(struct gelic_descr *descr, skb->protocol = eth_type_trans(skb, netdev); /* checksum offload */ - if (card->rx_csum) { + if (netdev->features & NETIF_F_RXCSUM) { if ((data_status & GELIC_DESCR_DATA_STATUS_CHK_MASK) && (!(data_error & GELIC_DESCR_DATA_ERROR_CHK_MASK))) skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -1312,21 +1312,6 @@ static int gelic_ether_set_settings(struct net_device *netdev, return 0; } -u32 gelic_net_get_rx_csum(struct net_device *netdev) -{ - struct gelic_card *card = netdev_card(netdev); - - return card->rx_csum; -} - -int gelic_net_set_rx_csum(struct net_device *netdev, u32 data) -{ - struct gelic_card *card = netdev_card(netdev); - - card->rx_csum = data; - return 0; -} - static void gelic_net_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) { @@ -1411,10 +1396,6 @@ static const struct ethtool_ops gelic_ether_ethtool_ops = { .get_settings = gelic_ether_get_settings, .set_settings = gelic_ether_set_settings, .get_link = ethtool_op_get_link, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, - .get_rx_csum = gelic_net_get_rx_csum, - .set_rx_csum = gelic_net_set_rx_csum, .get_wol = gelic_net_get_wol, .set_wol = gelic_net_set_wol, }; @@ -1512,7 +1493,11 @@ int __devinit gelic_net_setup_netdev(struct net_device *netdev, int status; u64 v1, v2; + netdev->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM; + netdev->features = NETIF_F_IP_CSUM; + if (GELIC_CARD_RX_CSUM_DEFAULT) + netdev->features |= NETIF_F_RXCSUM; status = lv1_net_control(bus_id(card), dev_id(card), GELIC_LV1_GET_MAC_ADDRESS, @@ -1756,7 +1741,6 @@ static int __devinit ps3_gelic_driver_probe(struct ps3_system_bus_device *dev) /* setup card structure */ card->irq_mask = GELIC_CARD_RXINT | GELIC_CARD_TXINT | GELIC_CARD_PORT_STATUS_CHANGED; - card->rx_csum = GELIC_CARD_RX_CSUM_DEFAULT; if (gelic_card_init_chain(card, &card->tx_chain, diff --git a/drivers/net/ps3_gelic_net.h b/drivers/net/ps3_gelic_net.h index fadadf9097a3..d9a55b93898b 100644 --- a/drivers/net/ps3_gelic_net.h +++ b/drivers/net/ps3_gelic_net.h @@ -290,7 +290,6 @@ struct gelic_card { struct gelic_descr_chain tx_chain; struct gelic_descr_chain rx_chain; int rx_dma_restart_required; - int rx_csum; /* * tx_lock guards tx descriptor list and * tx_dma_progress. @@ -377,8 +376,6 @@ extern int gelic_net_setup_netdev(struct net_device *netdev, /* shared ethtool ops */ extern void gelic_net_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info); -extern u32 gelic_net_get_rx_csum(struct net_device *netdev); -extern int gelic_net_set_rx_csum(struct net_device *netdev, u32 data); extern void gelic_net_poll_controller(struct net_device *netdev); #endif /* _GELIC_NET_H */ diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c index b5ae29d20f2e..2e62938c0f82 100644 --- a/drivers/net/ps3_gelic_wireless.c +++ b/drivers/net/ps3_gelic_wireless.c @@ -2581,10 +2581,6 @@ static const struct net_device_ops gelic_wl_netdevice_ops = { static const struct ethtool_ops gelic_wl_ethtool_ops = { .get_drvinfo = gelic_net_get_drvinfo, .get_link = gelic_wl_get_link, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, - .get_rx_csum = gelic_net_get_rx_csum, - .set_rx_csum = gelic_net_set_rx_csum, }; static void __devinit gelic_wl_setup_netdev_ops(struct net_device *netdev) diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index 348b4f1367c9..f3f737b91248 100644 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -3468,7 +3468,7 @@ static int ql_adapter_up(struct ql3_adapter *qdev) { struct net_device *ndev = qdev->ndev; int err; - unsigned long irq_flags = IRQF_SAMPLE_RANDOM | IRQF_SHARED; + unsigned long irq_flags = IRQF_SHARED; unsigned long hw_flags; if (ql_alloc_mem_resources(qdev)) { diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index b0dead00b2d1..e5d30538f373 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -29,13 +29,15 @@ #include <linux/io.h> #include <asm/byteorder.h> +#include <linux/bitops.h> +#include <linux/if_vlan.h> #include "qlcnic_hdr.h" #define _QLCNIC_LINUX_MAJOR 5 #define _QLCNIC_LINUX_MINOR 0 -#define _QLCNIC_LINUX_SUBVERSION 15 -#define QLCNIC_LINUX_VERSIONID "5.0.15" +#define _QLCNIC_LINUX_SUBVERSION 16 +#define QLCNIC_LINUX_VERSIONID "5.0.16" #define QLCNIC_DRV_IDC_VER 0x01 #define QLCNIC_DRIVER_VERSION ((_QLCNIC_LINUX_MAJOR << 16) |\ (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION)) @@ -93,8 +95,6 @@ #define TX_IP_PKT 0x04 #define TX_TCP_LSO 0x05 #define TX_TCP_LSO6 0x06 -#define TX_IPSEC 0x07 -#define TX_IPSEC_CMD 0x0a #define TX_TCPV6_PKT 0x0b #define TX_UDPV6_PKT 0x0c @@ -201,7 +201,7 @@ struct rcv_desc { __le16 reserved; __le32 buffer_length; /* allocated buffer length (usually 2K) */ __le64 addr_buffer; -}; +} __packed; /* opcode field in status_desc */ #define QLCNIC_SYN_OFFLOAD 0x03 @@ -293,6 +293,7 @@ struct uni_data_desc{ /* Flash Defines and Structures */ #define QLCNIC_FLT_LOCATION 0x3F1000 #define QLCNIC_FW_IMAGE_REGION 0x74 +#define QLCNIC_BOOTLD_REGION 0X72 struct qlcnic_flt_header { u16 version; u16 len; @@ -307,7 +308,7 @@ struct qlcnic_flt_entry { u8 reserved1; u32 size; u32 start_addr; - u32 end_add; + u32 end_addr; }; /* Magic number to let user know flash is programmed */ @@ -366,12 +367,6 @@ struct qlcnic_skb_frag { u64 length; }; -struct qlcnic_recv_crb { - u32 crb_rcv_producer[NUM_RCV_DESC_RINGS]; - u32 crb_sts_consumer[NUM_STS_DESC_RINGS]; - u32 sw_int_mask[NUM_STS_DESC_RINGS]; -}; - /* Following defines are for the state of the buffers */ #define QLCNIC_BUFFER_FREE 0 #define QLCNIC_BUFFER_BUSY 1 @@ -388,10 +383,10 @@ struct qlcnic_cmd_buffer { /* In rx_buffer, we do not need multiple fragments as is a single buffer */ struct qlcnic_rx_buffer { - struct list_head list; + u16 ref_handle; struct sk_buff *skb; + struct list_head list; u64 dma; - u16 ref_handle; }; /* Board types */ @@ -399,6 +394,25 @@ struct qlcnic_rx_buffer { #define QLCNIC_XGBE 0x02 /* + * Interrupt coalescing defaults. The defaults are for 1500 MTU. It is + * adjusted based on configured MTU. + */ +#define QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US 3 +#define QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS 256 + +#define QLCNIC_INTR_DEFAULT 0x04 +#define QLCNIC_CONFIG_INTR_COALESCE 3 + +struct qlcnic_nic_intr_coalesce { + u8 type; + u8 sts_ring_mask; + u16 rx_packets; + u16 rx_time_us; + u16 flag; + u32 timer_out; +}; + +/* * One hardware_context{} per adapter * contains interrupt info as well shared hardware info. */ @@ -416,6 +430,8 @@ struct qlcnic_hardware_context { u8 linkup; u16 port_type; u16 board_type; + + struct qlcnic_nic_intr_coalesce coal; }; struct qlcnic_adapter_stats { @@ -443,50 +459,49 @@ struct qlcnic_adapter_stats { * be one Rcv Descriptor for normal packets, one for jumbo and may be others. */ struct qlcnic_host_rds_ring { - u32 producer; + void __iomem *crb_rcv_producer; + struct rcv_desc *desc_head; + struct qlcnic_rx_buffer *rx_buf_arr; u32 num_desc; + u32 producer; u32 dma_size; u32 skb_size; u32 flags; - void __iomem *crb_rcv_producer; - struct rcv_desc *desc_head; - struct qlcnic_rx_buffer *rx_buf_arr; struct list_head free_list; spinlock_t lock; dma_addr_t phys_addr; -}; +} ____cacheline_internodealigned_in_smp; struct qlcnic_host_sds_ring { u32 consumer; u32 num_desc; void __iomem *crb_sts_consumer; - void __iomem *crb_intr_mask; struct status_desc *desc_head; struct qlcnic_adapter *adapter; struct napi_struct napi; struct list_head free_list[NUM_RCV_DESC_RINGS]; + void __iomem *crb_intr_mask; int irq; dma_addr_t phys_addr; char name[IFNAMSIZ+4]; -}; +} ____cacheline_internodealigned_in_smp; struct qlcnic_host_tx_ring { u32 producer; - __le32 *hw_consumer; u32 sw_consumer; - void __iomem *crb_cmd_producer; u32 num_desc; - - struct netdev_queue *txq; - - struct qlcnic_cmd_buffer *cmd_buf_arr; + void __iomem *crb_cmd_producer; struct cmd_desc_type0 *desc_head; + struct qlcnic_cmd_buffer *cmd_buf_arr; + __le32 *hw_consumer; + dma_addr_t phys_addr; dma_addr_t hw_cons_phys_addr; -}; + struct netdev_queue *txq; +} ____cacheline_internodealigned_in_smp; /* * Receive context. There is one such structure per instance of the @@ -495,12 +510,12 @@ struct qlcnic_host_tx_ring { * present elsewhere. */ struct qlcnic_recv_context { + struct qlcnic_host_rds_ring *rds_rings; + struct qlcnic_host_sds_ring *sds_rings; u32 state; u16 context_id; u16 virt_port; - struct qlcnic_host_rds_ring *rds_rings; - struct qlcnic_host_sds_ring *sds_rings; }; /* HW context creation */ @@ -539,9 +554,6 @@ struct qlcnic_recv_context { #define QLCNIC_CDRP_CMD_DESTROY_RX_CTX 0x00000008 #define QLCNIC_CDRP_CMD_CREATE_TX_CTX 0x00000009 #define QLCNIC_CDRP_CMD_DESTROY_TX_CTX 0x0000000a -#define QLCNIC_CDRP_CMD_SETUP_STATISTICS 0x0000000e -#define QLCNIC_CDRP_CMD_GET_STATISTICS 0x0000000f -#define QLCNIC_CDRP_CMD_DELETE_STATISTICS 0x00000010 #define QLCNIC_CDRP_CMD_SET_MTU 0x00000012 #define QLCNIC_CDRP_CMD_READ_PHY 0x00000013 #define QLCNIC_CDRP_CMD_WRITE_PHY 0x00000014 @@ -550,17 +562,11 @@ struct qlcnic_recv_context { #define QLCNIC_CDRP_CMD_SET_FLOW_CTL 0x00000017 #define QLCNIC_CDRP_CMD_READ_MAX_MTU 0x00000018 #define QLCNIC_CDRP_CMD_READ_MAX_LRO 0x00000019 -#define QLCNIC_CDRP_CMD_CONFIGURE_TOE 0x0000001a -#define QLCNIC_CDRP_CMD_FUNC_ATTRIB 0x0000001b -#define QLCNIC_CDRP_CMD_READ_PEXQ_PARAMETERS 0x0000001c -#define QLCNIC_CDRP_CMD_GET_LIC_CAPABILITIES 0x0000001d -#define QLCNIC_CDRP_CMD_READ_MAX_LRO_PER_BOARD 0x0000001e #define QLCNIC_CDRP_CMD_MAC_ADDRESS 0x0000001f #define QLCNIC_CDRP_CMD_GET_PCI_INFO 0x00000020 #define QLCNIC_CDRP_CMD_GET_NIC_INFO 0x00000021 #define QLCNIC_CDRP_CMD_SET_NIC_INFO 0x00000022 -#define QLCNIC_CDRP_CMD_RESET_NPAR 0x00000023 #define QLCNIC_CDRP_CMD_GET_ESWITCH_CAPABILITY 0x00000024 #define QLCNIC_CDRP_CMD_TOGGLE_ESWITCH 0x00000025 #define QLCNIC_CDRP_CMD_GET_ESWITCH_STATUS 0x00000026 @@ -598,14 +604,14 @@ struct qlcnic_hostrq_sds_ring { __le32 ring_size; /* Ring entries */ __le16 msi_index; __le16 rsvd; /* Padding */ -}; +} __packed; struct qlcnic_hostrq_rds_ring { __le64 host_phys_addr; /* Ring base addr */ __le64 buff_size; /* Packet buffer size */ __le32 ring_size; /* Ring entries */ __le32 ring_kind; /* Class of ring */ -}; +} __packed; struct qlcnic_hostrq_rx_ctx { __le64 host_rsp_dma_addr; /* Response dma'd here */ @@ -626,17 +632,17 @@ struct qlcnic_hostrq_rx_ctx { - N hostrq_rds_rings - N hostrq_sds_rings */ char data[0]; -}; +} __packed; struct qlcnic_cardrsp_rds_ring{ __le32 host_producer_crb; /* Crb to use */ __le32 rsvd1; /* Padding */ -}; +} __packed; struct qlcnic_cardrsp_sds_ring { __le32 host_consumer_crb; /* Crb to use */ __le32 interrupt_crb; /* Crb to use */ -}; +} __packed; struct qlcnic_cardrsp_rx_ctx { /* These ring offsets are relative to data[0] below */ @@ -655,7 +661,7 @@ struct qlcnic_cardrsp_rx_ctx { - N cardrsp_rds_rings - N cardrs_sds_rings */ char data[0]; -}; +} __packed; #define SIZEOF_HOSTRQ_RX(HOSTRQ_RX, rds_rings, sds_rings) \ (sizeof(HOSTRQ_RX) + \ @@ -675,7 +681,7 @@ struct qlcnic_hostrq_cds_ring { __le64 host_phys_addr; /* Ring base addr */ __le32 ring_size; /* Ring entries */ __le32 rsvd; /* Padding */ -}; +} __packed; struct qlcnic_hostrq_tx_ctx { __le64 host_rsp_dma_addr; /* Response dma'd here */ @@ -690,12 +696,12 @@ struct qlcnic_hostrq_tx_ctx { __le16 rsvd3; /* Padding */ struct qlcnic_hostrq_cds_ring cds_ring; /* Desc of cds ring */ u8 reserved[128]; /* future expansion */ -}; +} __packed; struct qlcnic_cardrsp_cds_ring { __le32 host_producer_crb; /* Crb to use */ __le32 interrupt_crb; /* Crb to use */ -}; +} __packed; struct qlcnic_cardrsp_tx_ctx { __le32 host_ctx_state; /* Starting state */ @@ -704,7 +710,7 @@ struct qlcnic_cardrsp_tx_ctx { u8 virt_port; /* Virtual/Logical id of port */ struct qlcnic_cardrsp_cds_ring cds_ring; /* Card cds settings */ u8 reserved[128]; /* future expansion */ -}; +} __packed; #define SIZEOF_HOSTRQ_TX(HOSTRQ_TX) (sizeof(HOSTRQ_TX)) #define SIZEOF_CARDRSP_TX(CARDRSP_TX) (sizeof(CARDRSP_TX)) @@ -738,40 +744,6 @@ struct qlcnic_mac_list_s { uint8_t mac_addr[ETH_ALEN+2]; }; -/* - * Interrupt coalescing defaults. The defaults are for 1500 MTU. It is - * adjusted based on configured MTU. - */ -#define QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US 3 -#define QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS 256 -#define QLCNIC_DEFAULT_INTR_COALESCE_TX_PACKETS 64 -#define QLCNIC_DEFAULT_INTR_COALESCE_TX_TIME_US 4 - -#define QLCNIC_INTR_DEFAULT 0x04 - -union qlcnic_nic_intr_coalesce_data { - struct { - u16 rx_packets; - u16 rx_time_us; - u16 tx_packets; - u16 tx_time_us; - } data; - u64 word; -}; - -struct qlcnic_nic_intr_coalesce { - u16 stats_time_us; - u16 rate_sample_time; - u16 flags; - u16 rsvd_1; - u32 low_threshold; - u32 high_threshold; - union qlcnic_nic_intr_coalesce_data normal; - union qlcnic_nic_intr_coalesce_data low; - union qlcnic_nic_intr_coalesce_data high; - union qlcnic_nic_intr_coalesce_data irq; -}; - #define QLCNIC_HOST_REQUEST 0x13 #define QLCNIC_REQUEST 0x14 @@ -783,50 +755,20 @@ struct qlcnic_nic_intr_coalesce { /* * Driver --> Firmware */ -#define QLCNIC_H2C_OPCODE_START 0 -#define QLCNIC_H2C_OPCODE_CONFIG_RSS 1 -#define QLCNIC_H2C_OPCODE_CONFIG_RSS_TBL 2 -#define QLCNIC_H2C_OPCODE_CONFIG_INTR_COALESCE 3 -#define QLCNIC_H2C_OPCODE_CONFIG_LED 4 -#define QLCNIC_H2C_OPCODE_CONFIG_PROMISCUOUS 5 -#define QLCNIC_H2C_OPCODE_CONFIG_L2_MAC 6 -#define QLCNIC_H2C_OPCODE_LRO_REQUEST 7 -#define QLCNIC_H2C_OPCODE_GET_SNMP_STATS 8 -#define QLCNIC_H2C_OPCODE_PROXY_START_REQUEST 9 -#define QLCNIC_H2C_OPCODE_PROXY_STOP_REQUEST 10 -#define QLCNIC_H2C_OPCODE_PROXY_SET_MTU 11 -#define QLCNIC_H2C_OPCODE_PROXY_SET_VPORT_MISS_MODE 12 -#define QLCNIC_H2C_OPCODE_GET_FINGER_PRINT_REQUEST 13 -#define QLCNIC_H2C_OPCODE_INSTALL_LICENSE_REQUEST 14 -#define QLCNIC_H2C_OPCODE_GET_LICENSE_CAPABILITY_REQUEST 15 -#define QLCNIC_H2C_OPCODE_GET_NET_STATS 16 -#define QLCNIC_H2C_OPCODE_PROXY_UPDATE_P2V 17 -#define QLCNIC_H2C_OPCODE_CONFIG_IPADDR 18 -#define QLCNIC_H2C_OPCODE_PROXY_STOP_DONE 20 -#define QLCNIC_H2C_OPCODE_GET_LINKEVENT 21 -#define QLCNIC_C2C_OPCODE 22 -#define QLCNIC_H2C_OPCODE_CONFIG_BRIDGING 23 -#define QLCNIC_H2C_OPCODE_CONFIG_HW_LRO 24 -#define QLCNIC_H2C_OPCODE_LAST 25 +#define QLCNIC_H2C_OPCODE_CONFIG_RSS 0x1 +#define QLCNIC_H2C_OPCODE_CONFIG_INTR_COALESCE 0x3 +#define QLCNIC_H2C_OPCODE_CONFIG_LED 0x4 +#define QLCNIC_H2C_OPCODE_LRO_REQUEST 0x7 +#define QLCNIC_H2C_OPCODE_SET_MAC_RECEIVE_MODE 0xc +#define QLCNIC_H2C_OPCODE_CONFIG_IPADDR 0x12 +#define QLCNIC_H2C_OPCODE_GET_LINKEVENT 0x15 +#define QLCNIC_H2C_OPCODE_CONFIG_BRIDGING 0x17 +#define QLCNIC_H2C_OPCODE_CONFIG_HW_LRO 0x18 /* * Firmware --> Driver */ -#define QLCNIC_C2H_OPCODE_START 128 -#define QLCNIC_C2H_OPCODE_CONFIG_RSS_RESPONSE 129 -#define QLCNIC_C2H_OPCODE_CONFIG_RSS_TBL_RESPONSE 130 -#define QLCNIC_C2H_OPCODE_CONFIG_MAC_RESPONSE 131 -#define QLCNIC_C2H_OPCODE_CONFIG_PROMISCUOUS_RESPONSE 132 -#define QLCNIC_C2H_OPCODE_CONFIG_L2_MAC_RESPONSE 133 -#define QLCNIC_C2H_OPCODE_LRO_DELETE_RESPONSE 134 -#define QLCNIC_C2H_OPCODE_LRO_ADD_FAILURE_RESPONSE 135 -#define QLCNIC_C2H_OPCODE_GET_SNMP_STATS 136 -#define QLCNIC_C2H_OPCODE_GET_FINGER_PRINT_REPLY 137 -#define QLCNIC_C2H_OPCODE_INSTALL_LICENSE_REPLY 138 -#define QLCNIC_C2H_OPCODE_GET_LICENSE_CAPABILITIES_REPLY 139 -#define QLCNIC_C2H_OPCODE_GET_NET_STATS_RESPONSE 140 #define QLCNIC_C2H_OPCODE_GET_LINKEVENT_RESPONSE 141 -#define QLCNIC_C2H_OPCODE_LAST 142 #define VPORT_MISS_MODE_DROP 0 /* drop all unmatched */ #define VPORT_MISS_MODE_ACCEPT_ALL 1 /* accept all packets */ @@ -895,7 +837,7 @@ struct qlcnic_nic_req { __le64 qhdr; __le64 req_hdr; __le64 words[6]; -}; +} __packed; struct qlcnic_mac_req { u8 op; @@ -906,7 +848,7 @@ struct qlcnic_mac_req { struct qlcnic_vlan_req { __le16 vlan_id; __le16 rsvd[3]; -}; +} __packed; struct qlcnic_ipaddr { __be32 ipv4; @@ -965,14 +907,15 @@ struct qlcnic_filter_hash { }; struct qlcnic_adapter { - struct qlcnic_hardware_context ahw; - + struct qlcnic_hardware_context *ahw; + struct qlcnic_recv_context *recv_ctx; + struct qlcnic_host_tx_ring *tx_ring; struct net_device *netdev; struct pci_dev *pdev; - struct list_head mac_list; - spinlock_t tx_clean_lock; - spinlock_t mac_learn_lock; + bool blink_was_down; + unsigned long state; + u32 flags; u16 num_txd; u16 num_rxd; @@ -990,7 +933,6 @@ struct qlcnic_adapter { u8 mc_enabled; u8 max_mc_count; - u8 rss_supported; u8 fw_wait_cnt; u8 fw_fail_cnt; u8 tx_timeo_cnt; @@ -1015,7 +957,6 @@ struct qlcnic_adapter { u32 fw_hal_version; u32 capabilities; - u32 flags; u32 irq; u32 temp; @@ -1033,16 +974,14 @@ struct qlcnic_adapter { u8 mac_addr[ETH_ALEN]; u64 dev_rst_time; + unsigned long vlans[BITS_TO_LONGS(VLAN_N_VID)]; - struct vlan_group *vlgrp; struct qlcnic_npar_info *npars; struct qlcnic_eswitch *eswitch; struct qlcnic_nic_template *nic_ops; struct qlcnic_adapter_stats stats; - - struct qlcnic_recv_context recv_ctx; - struct qlcnic_host_tx_ring *tx_ring; + struct list_head mac_list; void __iomem *tgt_mask_reg; void __iomem *tgt_status_reg; @@ -1053,11 +992,11 @@ struct qlcnic_adapter { struct delayed_work fw_work; - struct qlcnic_nic_intr_coalesce coal; struct qlcnic_filter_hash fhash; - unsigned long state; + spinlock_t tx_clean_lock; + spinlock_t mac_learn_lock; __le32 file_prd_off; /*File fw product offset*/ u32 fw_version; const struct firmware *fw; @@ -1079,7 +1018,7 @@ struct qlcnic_info { __le16 min_tx_bw; __le16 max_tx_bw; u8 reserved2[104]; -}; +} __packed; struct qlcnic_pci_info { __le16 id; /* pci function id */ @@ -1093,7 +1032,7 @@ struct qlcnic_pci_info { u8 mac[ETH_ALEN]; u8 reserved2[106]; -}; +} __packed; struct qlcnic_npar_info { u16 pvid; @@ -1210,7 +1149,7 @@ struct __qlcnic_esw_statistics { __le64 local_frames; __le64 numbytes; __le64 rsvd[3]; -}; +} __packed; struct qlcnic_esw_statistics { struct __qlcnic_esw_statistics rx; @@ -1294,7 +1233,7 @@ void qlcnic_release_tx_buffers(struct qlcnic_adapter *adapter); int qlcnic_check_fw_status(struct qlcnic_adapter *adapter); void qlcnic_watchdog_task(struct work_struct *work); -void qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter, u32 ringid, +void qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter, struct qlcnic_host_rds_ring *rds_ring); int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max); void qlcnic_set_multi(struct net_device *netdev); @@ -1379,8 +1318,7 @@ static const struct qlcnic_brdinfo qlcnic_boards[] = { static inline u32 qlcnic_tx_avail(struct qlcnic_host_tx_ring *tx_ring) { - smp_mb(); - if (tx_ring->producer < tx_ring->sw_consumer) + if (likely(tx_ring->producer < tx_ring->sw_consumer)) return tx_ring->sw_consumer - tx_ring->producer; else return tx_ring->sw_consumer + tx_ring->num_desc - diff --git a/drivers/net/qlcnic/qlcnic_ctx.c b/drivers/net/qlcnic/qlcnic_ctx.c index 27631f23b3fd..050fa5a99ff7 100644 --- a/drivers/net/qlcnic/qlcnic_ctx.c +++ b/drivers/net/qlcnic/qlcnic_ctx.c @@ -67,11 +67,11 @@ qlcnic_issue_cmd(struct qlcnic_adapter *adapter, int qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu) { - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; if (recv_ctx->state == QLCNIC_HOST_CTX_STATE_ACTIVE) { if (qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, recv_ctx->context_id, mtu, @@ -102,12 +102,12 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter) dma_addr_t hostrq_phys_addr, cardrsp_phys_addr; u64 phys_addr; - int i, nrds_rings, nsds_rings; + u8 i, nrds_rings, nsds_rings; size_t rq_size, rsp_size; u32 cap, reg, val, reg2; int err; - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; nrds_rings = adapter->max_rds_rings; nsds_rings = adapter->max_sds_rings; @@ -119,14 +119,14 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter) SIZEOF_CARDRSP_RX(struct qlcnic_cardrsp_rx_ctx, nrds_rings, nsds_rings); - addr = pci_alloc_consistent(adapter->pdev, - rq_size, &hostrq_phys_addr); + addr = dma_alloc_coherent(&adapter->pdev->dev, rq_size, + &hostrq_phys_addr, GFP_KERNEL); if (addr == NULL) return -ENOMEM; prq = (struct qlcnic_hostrq_rx_ctx *)addr; - addr = pci_alloc_consistent(adapter->pdev, - rsp_size, &cardrsp_phys_addr); + addr = dma_alloc_coherent(&adapter->pdev->dev, rsp_size, + &cardrsp_phys_addr, GFP_KERNEL); if (addr == NULL) { err = -ENOMEM; goto out_free_rq; @@ -151,7 +151,7 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter) prq->num_rds_rings = cpu_to_le16(nrds_rings); prq->num_sds_rings = cpu_to_le16(nsds_rings); - prq->rds_ring_offset = cpu_to_le32(0); + prq->rds_ring_offset = 0; val = le32_to_cpu(prq->rds_ring_offset) + (sizeof(struct qlcnic_hostrq_rds_ring) * nrds_rings); @@ -187,7 +187,7 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter) phys_addr = hostrq_phys_addr; err = qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, (u32)(phys_addr >> 32), (u32)(phys_addr & 0xffffffff), @@ -207,7 +207,7 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter) rds_ring = &recv_ctx->rds_rings[i]; reg = le32_to_cpu(prsp_rds[i].host_producer_crb); - rds_ring->crb_rcv_producer = adapter->ahw.pci_base0 + reg; + rds_ring->crb_rcv_producer = adapter->ahw->pci_base0 + reg; } prsp_sds = ((struct qlcnic_cardrsp_sds_ring *) @@ -219,8 +219,8 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter) reg = le32_to_cpu(prsp_sds[i].host_consumer_crb); reg2 = le32_to_cpu(prsp_sds[i].interrupt_crb); - sds_ring->crb_sts_consumer = adapter->ahw.pci_base0 + reg; - sds_ring->crb_intr_mask = adapter->ahw.pci_base0 + reg2; + sds_ring->crb_sts_consumer = adapter->ahw->pci_base0 + reg; + sds_ring->crb_intr_mask = adapter->ahw->pci_base0 + reg2; } recv_ctx->state = le32_to_cpu(prsp->host_ctx_state); @@ -228,19 +228,20 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter) recv_ctx->virt_port = prsp->virt_port; out_free_rsp: - pci_free_consistent(adapter->pdev, rsp_size, prsp, cardrsp_phys_addr); + dma_free_coherent(&adapter->pdev->dev, rsp_size, prsp, + cardrsp_phys_addr); out_free_rq: - pci_free_consistent(adapter->pdev, rq_size, prq, hostrq_phys_addr); + dma_free_coherent(&adapter->pdev->dev, rq_size, prq, hostrq_phys_addr); return err; } static void qlcnic_fw_cmd_destroy_rx_ctx(struct qlcnic_adapter *adapter) { - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; if (qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, recv_ctx->context_id, QLCNIC_DESTROY_CTX_RESET, @@ -274,14 +275,14 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter) *(tx_ring->hw_consumer) = 0; rq_size = SIZEOF_HOSTRQ_TX(struct qlcnic_hostrq_tx_ctx); - rq_addr = pci_alloc_consistent(adapter->pdev, - rq_size, &rq_phys_addr); + rq_addr = dma_alloc_coherent(&adapter->pdev->dev, rq_size, + &rq_phys_addr, GFP_KERNEL); if (!rq_addr) return -ENOMEM; rsp_size = SIZEOF_CARDRSP_TX(struct qlcnic_cardrsp_tx_ctx); - rsp_addr = pci_alloc_consistent(adapter->pdev, - rsp_size, &rsp_phys_addr); + rsp_addr = dma_alloc_coherent(&adapter->pdev->dev, rsp_size, + &rsp_phys_addr, GFP_KERNEL); if (!rsp_addr) { err = -ENOMEM; goto out_free_rq; @@ -313,7 +314,7 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter) phys_addr = rq_phys_addr; err = qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, (u32)(phys_addr >> 32), ((u32)phys_addr & 0xffffffff), @@ -322,7 +323,7 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter) if (err == QLCNIC_RCODE_SUCCESS) { temp = le32_to_cpu(prsp->cds_ring.host_producer_crb); - tx_ring->crb_cmd_producer = adapter->ahw.pci_base0 + temp; + tx_ring->crb_cmd_producer = adapter->ahw->pci_base0 + temp; adapter->tx_context_id = le16_to_cpu(prsp->context_id); @@ -332,10 +333,11 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter) err = -EIO; } - pci_free_consistent(adapter->pdev, rsp_size, rsp_addr, rsp_phys_addr); + dma_free_coherent(&adapter->pdev->dev, rsp_size, rsp_addr, + rsp_phys_addr); out_free_rq: - pci_free_consistent(adapter->pdev, rq_size, rq_addr, rq_phys_addr); + dma_free_coherent(&adapter->pdev->dev, rq_size, rq_addr, rq_phys_addr); return err; } @@ -344,7 +346,7 @@ static void qlcnic_fw_cmd_destroy_tx_ctx(struct qlcnic_adapter *adapter) { if (qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, adapter->tx_context_id, QLCNIC_DESTROY_CTX_RESET, @@ -361,7 +363,7 @@ qlcnic_fw_cmd_query_phy(struct qlcnic_adapter *adapter, u32 reg, u32 *val) { if (qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, reg, 0, @@ -378,7 +380,7 @@ int qlcnic_fw_cmd_set_phy(struct qlcnic_adapter *adapter, u32 reg, u32 val) { return qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, reg, val, @@ -398,20 +400,19 @@ int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter) struct pci_dev *pdev = adapter->pdev; - recv_ctx = &adapter->recv_ctx; + recv_ctx = adapter->recv_ctx; tx_ring = adapter->tx_ring; - tx_ring->hw_consumer = (__le32 *)pci_alloc_consistent(pdev, sizeof(u32), - &tx_ring->hw_cons_phys_addr); + tx_ring->hw_consumer = (__le32 *) dma_alloc_coherent(&pdev->dev, + sizeof(u32), &tx_ring->hw_cons_phys_addr, GFP_KERNEL); if (tx_ring->hw_consumer == NULL) { dev_err(&pdev->dev, "failed to allocate tx consumer\n"); return -ENOMEM; } - *(tx_ring->hw_consumer) = 0; /* cmd desc ring */ - addr = pci_alloc_consistent(pdev, TX_DESC_RINGSIZE(tx_ring), - &tx_ring->phys_addr); + addr = dma_alloc_coherent(&pdev->dev, TX_DESC_RINGSIZE(tx_ring), + &tx_ring->phys_addr, GFP_KERNEL); if (addr == NULL) { dev_err(&pdev->dev, "failed to allocate tx desc ring\n"); @@ -423,9 +424,9 @@ int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter) for (ring = 0; ring < adapter->max_rds_rings; ring++) { rds_ring = &recv_ctx->rds_rings[ring]; - addr = pci_alloc_consistent(adapter->pdev, + addr = dma_alloc_coherent(&adapter->pdev->dev, RCV_DESC_RINGSIZE(rds_ring), - &rds_ring->phys_addr); + &rds_ring->phys_addr, GFP_KERNEL); if (addr == NULL) { dev_err(&pdev->dev, "failed to allocate rds ring [%d]\n", ring); @@ -439,9 +440,9 @@ int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter) for (ring = 0; ring < adapter->max_sds_rings; ring++) { sds_ring = &recv_ctx->sds_rings[ring]; - addr = pci_alloc_consistent(adapter->pdev, + addr = dma_alloc_coherent(&adapter->pdev->dev, STATUS_DESC_RINGSIZE(sds_ring), - &sds_ring->phys_addr); + &sds_ring->phys_addr, GFP_KERNEL); if (addr == NULL) { dev_err(&pdev->dev, "failed to allocate sds ring [%d]\n", ring); @@ -501,11 +502,11 @@ void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter) struct qlcnic_host_tx_ring *tx_ring; int ring; - recv_ctx = &adapter->recv_ctx; + recv_ctx = adapter->recv_ctx; tx_ring = adapter->tx_ring; if (tx_ring->hw_consumer != NULL) { - pci_free_consistent(adapter->pdev, + dma_free_coherent(&adapter->pdev->dev, sizeof(u32), tx_ring->hw_consumer, tx_ring->hw_cons_phys_addr); @@ -513,7 +514,7 @@ void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter) } if (tx_ring->desc_head != NULL) { - pci_free_consistent(adapter->pdev, + dma_free_coherent(&adapter->pdev->dev, TX_DESC_RINGSIZE(tx_ring), tx_ring->desc_head, tx_ring->phys_addr); tx_ring->desc_head = NULL; @@ -523,7 +524,7 @@ void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter) rds_ring = &recv_ctx->rds_rings[ring]; if (rds_ring->desc_head != NULL) { - pci_free_consistent(adapter->pdev, + dma_free_coherent(&adapter->pdev->dev, RCV_DESC_RINGSIZE(rds_ring), rds_ring->desc_head, rds_ring->phys_addr); @@ -535,7 +536,7 @@ void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter) sds_ring = &recv_ctx->sds_rings[ring]; if (sds_ring->desc_head != NULL) { - pci_free_consistent(adapter->pdev, + dma_free_coherent(&adapter->pdev->dev, STATUS_DESC_RINGSIZE(sds_ring), sds_ring->desc_head, sds_ring->phys_addr); @@ -551,9 +552,9 @@ int qlcnic_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac) int err; u32 arg1; - arg1 = adapter->ahw.pci_func | BIT_8; + arg1 = adapter->ahw->pci_func | BIT_8; err = qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, arg1, 0, @@ -582,15 +583,15 @@ int qlcnic_get_nic_info(struct qlcnic_adapter *adapter, void *nic_info_addr; size_t nic_size = sizeof(struct qlcnic_info); - nic_info_addr = pci_alloc_consistent(adapter->pdev, - nic_size, &nic_dma_t); + nic_info_addr = dma_alloc_coherent(&adapter->pdev->dev, nic_size, + &nic_dma_t, GFP_KERNEL); if (!nic_info_addr) return -ENOMEM; memset(nic_info_addr, 0, nic_size); nic_info = (struct qlcnic_info *) nic_info_addr; err = qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, MSD(nic_dma_t), LSD(nic_dma_t), @@ -623,7 +624,8 @@ int qlcnic_get_nic_info(struct qlcnic_adapter *adapter, err = -EIO; } - pci_free_consistent(adapter->pdev, nic_size, nic_info_addr, nic_dma_t); + dma_free_coherent(&adapter->pdev->dev, nic_size, nic_info_addr, + nic_dma_t); return err; } @@ -639,8 +641,8 @@ int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic) if (adapter->op_mode != QLCNIC_MGMT_FUNC) return err; - nic_info_addr = pci_alloc_consistent(adapter->pdev, nic_size, - &nic_dma_t); + nic_info_addr = dma_alloc_coherent(&adapter->pdev->dev, nic_size, + &nic_dma_t, GFP_KERNEL); if (!nic_info_addr) return -ENOMEM; @@ -659,7 +661,7 @@ int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic) nic_info->max_tx_bw = cpu_to_le16(nic->max_tx_bw); err = qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, MSD(nic_dma_t), LSD(nic_dma_t), @@ -672,7 +674,8 @@ int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic) err = -EIO; } - pci_free_consistent(adapter->pdev, nic_size, nic_info_addr, nic_dma_t); + dma_free_coherent(&adapter->pdev->dev, nic_size, nic_info_addr, + nic_dma_t); return err; } @@ -687,15 +690,15 @@ int qlcnic_get_pci_info(struct qlcnic_adapter *adapter, size_t npar_size = sizeof(struct qlcnic_pci_info); size_t pci_size = npar_size * QLCNIC_MAX_PCI_FUNC; - pci_info_addr = pci_alloc_consistent(adapter->pdev, pci_size, - &pci_info_dma_t); + pci_info_addr = dma_alloc_coherent(&adapter->pdev->dev, pci_size, + &pci_info_dma_t, GFP_KERNEL); if (!pci_info_addr) return -ENOMEM; memset(pci_info_addr, 0, pci_size); npar = (struct qlcnic_pci_info *) pci_info_addr; err = qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, MSD(pci_info_dma_t), LSD(pci_info_dma_t), @@ -721,7 +724,7 @@ int qlcnic_get_pci_info(struct qlcnic_adapter *adapter, err = -EIO; } - pci_free_consistent(adapter->pdev, pci_size, pci_info_addr, + dma_free_coherent(&adapter->pdev->dev, pci_size, pci_info_addr, pci_info_dma_t); return err; } @@ -741,7 +744,7 @@ int qlcnic_config_port_mirroring(struct qlcnic_adapter *adapter, u8 id, arg1 |= pci_func << 8; err = qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, arg1, 0, @@ -775,14 +778,14 @@ int qlcnic_get_port_stats(struct qlcnic_adapter *adapter, const u8 func, return -ENOMEM; if (adapter->op_mode != QLCNIC_MGMT_FUNC && - func != adapter->ahw.pci_func) { + func != adapter->ahw->pci_func) { dev_err(&adapter->pdev->dev, "Not privilege to query stats for func=%d", func); return -EIO; } - stats_addr = pci_alloc_consistent(adapter->pdev, stats_size, - &stats_dma_t); + stats_addr = dma_alloc_coherent(&adapter->pdev->dev, stats_size, + &stats_dma_t, GFP_KERNEL); if (!stats_addr) { dev_err(&adapter->pdev->dev, "Unable to allocate memory\n"); return -ENOMEM; @@ -793,7 +796,7 @@ int qlcnic_get_port_stats(struct qlcnic_adapter *adapter, const u8 func, arg1 |= rx_tx << 15 | stats_size << 16; err = qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, arg1, MSD(stats_dma_t), @@ -816,7 +819,7 @@ int qlcnic_get_port_stats(struct qlcnic_adapter *adapter, const u8 func, esw_stats->numbytes = le64_to_cpu(stats->numbytes); } - pci_free_consistent(adapter->pdev, stats_size, stats_addr, + dma_free_coherent(&adapter->pdev->dev, stats_size, stats_addr, stats_dma_t); return err; } @@ -900,7 +903,7 @@ int qlcnic_clear_esw_stats(struct qlcnic_adapter *adapter, const u8 func_esw, arg1 |= BIT_14 | rx_tx << 15; return qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, arg1, 0, @@ -921,7 +924,7 @@ __qlcnic_get_eswitch_port_config(struct qlcnic_adapter *adapter, u8 pci_func; pci_func = (*arg1 >> 8); err = qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, *arg1, 0, @@ -999,7 +1002,7 @@ int qlcnic_config_switch_port(struct qlcnic_adapter *adapter, } err = qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, arg1, arg2, diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c index 45b2755d6cba..3cd8a169694a 100644 --- a/drivers/net/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/qlcnic/qlcnic_ethtool.c @@ -150,10 +150,10 @@ qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) { struct qlcnic_adapter *adapter = netdev_priv(dev); int check_sfp_module = 0; - u16 pcifn = adapter->ahw.pci_func; + u16 pcifn = adapter->ahw->pci_func; /* read which mode */ - if (adapter->ahw.port_type == QLCNIC_GBE) { + if (adapter->ahw->port_type == QLCNIC_GBE) { ecmd->supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | @@ -170,7 +170,7 @@ qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) ecmd->duplex = adapter->link_duplex; ecmd->autoneg = adapter->link_autoneg; - } else if (adapter->ahw.port_type == QLCNIC_XGBE) { + } else if (adapter->ahw->port_type == QLCNIC_XGBE) { u32 val; val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR); @@ -201,7 +201,7 @@ skip: ecmd->phy_address = adapter->physical_port; ecmd->transceiver = XCVR_EXTERNAL; - switch (adapter->ahw.board_type) { + switch (adapter->ahw->board_type) { case QLCNIC_BRDTYPE_P3P_REF_QG: case QLCNIC_BRDTYPE_P3P_4_GB: case QLCNIC_BRDTYPE_P3P_4_GB_MM: @@ -238,7 +238,7 @@ skip: ecmd->autoneg = AUTONEG_DISABLE; break; case QLCNIC_BRDTYPE_P3P_10G_TP: - if (adapter->ahw.port_type == QLCNIC_XGBE) { + if (adapter->ahw->port_type == QLCNIC_XGBE) { ecmd->autoneg = AUTONEG_DISABLE; ecmd->supported |= (SUPPORTED_FIBRE | SUPPORTED_TP); ecmd->advertising |= @@ -256,7 +256,7 @@ skip: break; default: dev_err(&adapter->pdev->dev, "Unsupported board model %d\n", - adapter->ahw.board_type); + adapter->ahw->board_type); return -EIO; } @@ -288,7 +288,7 @@ qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) __u32 status; /* read which mode */ - if (adapter->ahw.port_type == QLCNIC_GBE) { + if (adapter->ahw->port_type == QLCNIC_GBE) { /* autonegotiation */ if (qlcnic_fw_cmd_set_phy(adapter, QLCNIC_NIU_GB_MII_MGMT_ADDR_AUTONEG, @@ -340,14 +340,14 @@ static void qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p) { struct qlcnic_adapter *adapter = netdev_priv(dev); - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; struct qlcnic_host_sds_ring *sds_ring; u32 *regs_buff = p; int ring, i = 0, j = 0; memset(p, 0, qlcnic_get_regs_len(dev)); regs->version = (QLCNIC_ETHTOOL_REGS_VER << 24) | - (adapter->ahw.revision_id << 16) | (adapter->pdev)->device; + (adapter->ahw->revision_id << 16) | (adapter->pdev)->device; regs_buff[0] = (0xcafe0000 | (QLCNIC_DEV_INFO_SIZE & 0xffff)); regs_buff[1] = QLCNIC_MGMT_API_VERSION; @@ -382,7 +382,7 @@ static u32 qlcnic_test_link(struct net_device *dev) u32 val; val = QLCRD32(adapter, CRB_XG_STATE_P3P); - val = XG_LINK_STATE_P3P(adapter->ahw.pci_func, val); + val = XG_LINK_STATE_P3P(adapter->ahw->pci_func, val); return (val == XG_LINK_UP_P3P) ? 0 : 1; } @@ -482,7 +482,7 @@ qlcnic_get_pauseparam(struct net_device *netdev, int port = adapter->physical_port; __u32 val; - if (adapter->ahw.port_type == QLCNIC_GBE) { + if (adapter->ahw->port_type == QLCNIC_GBE) { if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS)) return; /* get flow control settings */ @@ -504,7 +504,7 @@ qlcnic_get_pauseparam(struct net_device *netdev, pause->tx_pause = !(qlcnic_gb_get_gb3_mask(val)); break; } - } else if (adapter->ahw.port_type == QLCNIC_XGBE) { + } else if (adapter->ahw->port_type == QLCNIC_XGBE) { if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS)) return; pause->rx_pause = 1; @@ -515,7 +515,7 @@ qlcnic_get_pauseparam(struct net_device *netdev, pause->tx_pause = !(qlcnic_xg_get_xg1_mask(val)); } else { dev_err(&netdev->dev, "Unknown board type: %x\n", - adapter->ahw.port_type); + adapter->ahw->port_type); } } @@ -528,7 +528,7 @@ qlcnic_set_pauseparam(struct net_device *netdev, __u32 val; /* read mode */ - if (adapter->ahw.port_type == QLCNIC_GBE) { + if (adapter->ahw->port_type == QLCNIC_GBE) { if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS)) return -EIO; /* set flow control */ @@ -571,7 +571,7 @@ qlcnic_set_pauseparam(struct net_device *netdev, break; } QLCWR32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, val); - } else if (adapter->ahw.port_type == QLCNIC_XGBE) { + } else if (adapter->ahw->port_type == QLCNIC_XGBE) { if (!pause->rx_pause || pause->autoneg) return -EOPNOTSUPP; @@ -593,7 +593,7 @@ qlcnic_set_pauseparam(struct net_device *netdev, QLCWR32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, val); } else { dev_err(&netdev->dev, "Unknown board type: %x\n", - adapter->ahw.port_type); + adapter->ahw->port_type); } return 0; } @@ -639,8 +639,8 @@ static int qlcnic_irq_test(struct net_device *netdev) goto clear_it; adapter->diag_cnt = 0; - ret = qlcnic_issue_cmd(adapter, adapter->ahw.pci_func, - adapter->fw_hal_version, adapter->portnum, + ret = qlcnic_issue_cmd(adapter, adapter->ahw->pci_func, + adapter->fw_hal_version, adapter->ahw->pci_func, 0, 0, 0x00000011); if (ret) goto done; @@ -749,14 +749,14 @@ qlcnic_get_ethtool_stats(struct net_device *dev, return; memset(&port_stats, 0, sizeof(struct qlcnic_esw_statistics)); - ret = qlcnic_get_port_stats(adapter, adapter->ahw.pci_func, + ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func, QLCNIC_QUERY_RX_COUNTER, &port_stats.rx); if (ret) return; qlcnic_fill_device_stats(&index, data, &port_stats.rx); - ret = qlcnic_get_port_stats(adapter, adapter->ahw.pci_func, + ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func, QLCNIC_QUERY_TX_COUNTER, &port_stats.tx); if (ret) return; @@ -831,48 +831,51 @@ static int qlcnic_set_tso(struct net_device *dev, u32 data) return 0; } -static int qlcnic_blink_led(struct net_device *dev, u32 val) +static int qlcnic_set_led(struct net_device *dev, + enum ethtool_phys_id_state state) { struct qlcnic_adapter *adapter = netdev_priv(dev); int max_sds_rings = adapter->max_sds_rings; - int dev_down = 0; - int ret; - - if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) { - dev_down = 1; - if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) - return -EIO; - ret = qlcnic_diag_alloc_res(dev, QLCNIC_LED_TEST); - if (ret) { - clear_bit(__QLCNIC_RESETTING, &adapter->state); - return ret; + switch (state) { + case ETHTOOL_ID_ACTIVE: + adapter->blink_was_down = false; + if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) { + if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) + return -EIO; + + if (qlcnic_diag_alloc_res(dev, QLCNIC_LED_TEST)) { + clear_bit(__QLCNIC_RESETTING, &adapter->state); + return -EIO; + } + adapter->blink_was_down = true; } - } - ret = adapter->nic_ops->config_led(adapter, 1, 0xf); - if (ret) { + if (adapter->nic_ops->config_led(adapter, 1, 0xf) == 0) + return 0; + dev_err(&adapter->pdev->dev, "Failed to set LED blink state.\n"); - goto done; - } + break; - msleep_interruptible(val * 1000); + case ETHTOOL_ID_INACTIVE: + if (adapter->nic_ops->config_led(adapter, 0, 0xf) == 0) + return 0; - ret = adapter->nic_ops->config_led(adapter, 0, 0xf); - if (ret) { dev_err(&adapter->pdev->dev, "Failed to reset LED blink state.\n"); - goto done; + break; + + default: + return -EINVAL; } -done: - if (dev_down) { + if (adapter->blink_was_down) { qlcnic_diag_free_res(dev, max_sds_rings); clear_bit(__QLCNIC_RESETTING, &adapter->state); } - return ret; + return -EIO; } static void @@ -936,8 +939,8 @@ static int qlcnic_set_intr_coalesce(struct net_device *netdev, */ if (ethcoal->rx_coalesce_usecs > 0xffff || ethcoal->rx_max_coalesced_frames > 0xffff || - ethcoal->tx_coalesce_usecs > 0xffff || - ethcoal->tx_max_coalesced_frames > 0xffff || + ethcoal->tx_coalesce_usecs || + ethcoal->tx_max_coalesced_frames || ethcoal->rx_coalesce_usecs_irq || ethcoal->rx_max_coalesced_frames_irq || ethcoal->tx_coalesce_usecs_irq || @@ -959,21 +962,17 @@ static int qlcnic_set_intr_coalesce(struct net_device *netdev, if (!ethcoal->rx_coalesce_usecs || !ethcoal->rx_max_coalesced_frames) { - adapter->coal.flags = QLCNIC_INTR_DEFAULT; - adapter->coal.normal.data.rx_time_us = + adapter->ahw->coal.flag = QLCNIC_INTR_DEFAULT; + adapter->ahw->coal.rx_time_us = QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US; - adapter->coal.normal.data.rx_packets = + adapter->ahw->coal.rx_packets = QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS; } else { - adapter->coal.flags = 0; - adapter->coal.normal.data.rx_time_us = - ethcoal->rx_coalesce_usecs; - adapter->coal.normal.data.rx_packets = - ethcoal->rx_max_coalesced_frames; + adapter->ahw->coal.flag = 0; + adapter->ahw->coal.rx_time_us = ethcoal->rx_coalesce_usecs; + adapter->ahw->coal.rx_packets = + ethcoal->rx_max_coalesced_frames; } - adapter->coal.normal.data.tx_time_us = ethcoal->tx_coalesce_usecs; - adapter->coal.normal.data.tx_packets = - ethcoal->tx_max_coalesced_frames; qlcnic_config_intr_coalesce(adapter); @@ -988,12 +987,8 @@ static int qlcnic_get_intr_coalesce(struct net_device *netdev, if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) return -EINVAL; - ethcoal->rx_coalesce_usecs = adapter->coal.normal.data.rx_time_us; - ethcoal->tx_coalesce_usecs = adapter->coal.normal.data.tx_time_us; - ethcoal->rx_max_coalesced_frames = - adapter->coal.normal.data.rx_packets; - ethcoal->tx_max_coalesced_frames = - adapter->coal.normal.data.tx_packets; + ethcoal->rx_coalesce_usecs = adapter->ahw->coal.rx_time_us; + ethcoal->rx_max_coalesced_frames = adapter->ahw->coal.rx_packets; return 0; } @@ -1006,22 +1001,28 @@ static int qlcnic_set_flags(struct net_device *netdev, u32 data) if (ethtool_invalid_flags(netdev, data, ETH_FLAG_LRO)) return -EINVAL; - if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)) - return -EINVAL; + if (data & ETH_FLAG_LRO) { - if (!adapter->rx_csum) { - dev_info(&adapter->pdev->dev, "rx csum is off, " - "cannot toggle lro\n"); - return -EINVAL; - } + if (netdev->features & NETIF_F_LRO) + return 0; - if ((data & ETH_FLAG_LRO) && (netdev->features & NETIF_F_LRO)) - return 0; + if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)) + return -EINVAL; + + if (!adapter->rx_csum) { + dev_info(&adapter->pdev->dev, "rx csum is off, " + "cannot toggle lro\n"); + return -EINVAL; + } - if (data & ETH_FLAG_LRO) { hw_lro = QLCNIC_LRO_ENABLED; netdev->features |= NETIF_F_LRO; + } else { + + if (!(netdev->features & NETIF_F_LRO)) + return 0; + hw_lro = 0; netdev->features &= ~NETIF_F_LRO; } @@ -1080,7 +1081,7 @@ const struct ethtool_ops qlcnic_ethtool_ops = { .set_coalesce = qlcnic_set_intr_coalesce, .get_flags = ethtool_op_get_flags, .set_flags = qlcnic_set_flags, - .phys_id = qlcnic_blink_led, + .set_phys_id = qlcnic_set_led, .set_msglevel = qlcnic_set_msglevel, .get_msglevel = qlcnic_get_msglevel, }; diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c index 616940f0a8d0..498cca92126a 100644 --- a/drivers/net/qlcnic/qlcnic_hw.c +++ b/drivers/net/qlcnic/qlcnic_hw.c @@ -457,7 +457,7 @@ int qlcnic_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode) req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); - word = QLCNIC_H2C_OPCODE_PROXY_SET_VPORT_MISS_MODE | + word = QLCNIC_H2C_OPCODE_SET_MAC_RECEIVE_MODE | ((u64)adapter->portnum << 16); req.req_hdr = cpu_to_le64(word); @@ -532,33 +532,31 @@ void qlcnic_delete_lb_filters(struct qlcnic_adapter *adapter) } } -#define QLCNIC_CONFIG_INTR_COALESCE 3 - /* * Send the interrupt coalescing parameter set by ethtool to the card. */ int qlcnic_config_intr_coalesce(struct qlcnic_adapter *adapter) { struct qlcnic_nic_req req; - u64 word[6]; - int rv, i; + int rv; memset(&req, 0, sizeof(struct qlcnic_nic_req)); req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); - word[0] = QLCNIC_CONFIG_INTR_COALESCE | ((u64)adapter->portnum << 16); - req.req_hdr = cpu_to_le64(word[0]); - - memcpy(&word[0], &adapter->coal, sizeof(adapter->coal)); - for (i = 0; i < 6; i++) - req.words[i] = cpu_to_le64(word[i]); + req.req_hdr = cpu_to_le64(QLCNIC_CONFIG_INTR_COALESCE | + ((u64) adapter->portnum << 16)); + req.words[0] = cpu_to_le64(((u64) adapter->ahw->coal.flag) << 32); + req.words[2] = cpu_to_le64(adapter->ahw->coal.rx_packets | + ((u64) adapter->ahw->coal.rx_time_us) << 16); + req.words[5] = cpu_to_le64(adapter->ahw->coal.timer_out | + ((u64) adapter->ahw->coal.type) << 32 | + ((u64) adapter->ahw->coal.sts_ring_mask) << 40); rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); if (rv != 0) dev_err(&adapter->netdev->dev, "Could not send interrupt coalescing parameters\n"); - return rv; } @@ -568,6 +566,9 @@ int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable) u64 word; int rv; + if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) + return 0; + memset(&req, 0, sizeof(struct qlcnic_nic_req)); req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); @@ -713,6 +714,9 @@ int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter) u64 word; int rv; + if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) + return 0; + memset(&req, 0, sizeof(struct qlcnic_nic_req)); req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); @@ -780,7 +784,7 @@ qlcnic_pci_get_crb_addr_2M(struct qlcnic_adapter *adapter, m = &crb_128M_2M_map[CRB_BLK(off)].sub_block[CRB_SUBBLK(off)]; if (m->valid && (m->start_128M <= off) && (m->end_128M > off)) { - *addr = adapter->ahw.pci_base0 + m->start_2M + + *addr = adapter->ahw->pci_base0 + m->start_2M + (off - m->start_128M); return 0; } @@ -788,7 +792,7 @@ qlcnic_pci_get_crb_addr_2M(struct qlcnic_adapter *adapter, /* * Not in direct map, use crb window */ - *addr = adapter->ahw.pci_base0 + CRB_INDIRECT_2M + (off & MASK(16)); + *addr = adapter->ahw->pci_base0 + CRB_INDIRECT_2M + (off & MASK(16)); return 1; } @@ -801,7 +805,7 @@ static int qlcnic_pci_set_crbwindow_2M(struct qlcnic_adapter *adapter, ulong off) { u32 window; - void __iomem *addr = adapter->ahw.pci_base0 + CRB_WINDOW_2M; + void __iomem *addr = adapter->ahw->pci_base0 + CRB_WINDOW_2M; off -= QLCNIC_PCI_CRBSPACE; @@ -838,13 +842,13 @@ qlcnic_hw_write_wx_2M(struct qlcnic_adapter *adapter, ulong off, u32 data) if (rv > 0) { /* indirect access */ - write_lock_irqsave(&adapter->ahw.crb_lock, flags); + write_lock_irqsave(&adapter->ahw->crb_lock, flags); crb_win_lock(adapter); rv = qlcnic_pci_set_crbwindow_2M(adapter, off); if (!rv) writel(data, addr); crb_win_unlock(adapter); - write_unlock_irqrestore(&adapter->ahw.crb_lock, flags); + write_unlock_irqrestore(&adapter->ahw->crb_lock, flags); return rv; } @@ -869,12 +873,12 @@ qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off) if (rv > 0) { /* indirect access */ - write_lock_irqsave(&adapter->ahw.crb_lock, flags); + write_lock_irqsave(&adapter->ahw->crb_lock, flags); crb_win_lock(adapter); if (!qlcnic_pci_set_crbwindow_2M(adapter, off)) data = readl(addr); crb_win_unlock(adapter); - write_unlock_irqrestore(&adapter->ahw.crb_lock, flags); + write_unlock_irqrestore(&adapter->ahw->crb_lock, flags); return data; } @@ -904,9 +908,9 @@ qlcnic_pci_set_window_2M(struct qlcnic_adapter *adapter, window = OCM_WIN_P3P(addr); - writel(window, adapter->ahw.ocm_win_crb); + writel(window, adapter->ahw->ocm_win_crb); /* read back to flush */ - readl(adapter->ahw.ocm_win_crb); + readl(adapter->ahw->ocm_win_crb); *start = QLCNIC_PCI_OCM0_2M + GET_MEM_OFFS_2M(addr); return 0; @@ -920,13 +924,13 @@ qlcnic_pci_mem_access_direct(struct qlcnic_adapter *adapter, u64 off, int ret; u32 start; - mutex_lock(&adapter->ahw.mem_lock); + mutex_lock(&adapter->ahw->mem_lock); ret = qlcnic_pci_set_window_2M(adapter, off, &start); if (ret != 0) goto unlock; - addr = adapter->ahw.pci_base0 + start; + addr = adapter->ahw->pci_base0 + start; if (op == 0) /* read */ *data = readq(addr); @@ -934,7 +938,7 @@ qlcnic_pci_mem_access_direct(struct qlcnic_adapter *adapter, u64 off, writeq(*data, addr); unlock: - mutex_unlock(&adapter->ahw.mem_lock); + mutex_unlock(&adapter->ahw->mem_lock); return ret; } @@ -942,23 +946,23 @@ unlock: void qlcnic_pci_camqm_read_2M(struct qlcnic_adapter *adapter, u64 off, u64 *data) { - void __iomem *addr = adapter->ahw.pci_base0 + + void __iomem *addr = adapter->ahw->pci_base0 + QLCNIC_PCI_CAMQM_2M_BASE + (off - QLCNIC_PCI_CAMQM); - mutex_lock(&adapter->ahw.mem_lock); + mutex_lock(&adapter->ahw->mem_lock); *data = readq(addr); - mutex_unlock(&adapter->ahw.mem_lock); + mutex_unlock(&adapter->ahw->mem_lock); } void qlcnic_pci_camqm_write_2M(struct qlcnic_adapter *adapter, u64 off, u64 data) { - void __iomem *addr = adapter->ahw.pci_base0 + + void __iomem *addr = adapter->ahw->pci_base0 + QLCNIC_PCI_CAMQM_2M_BASE + (off - QLCNIC_PCI_CAMQM); - mutex_lock(&adapter->ahw.mem_lock); + mutex_lock(&adapter->ahw->mem_lock); writeq(data, addr); - mutex_unlock(&adapter->ahw.mem_lock); + mutex_unlock(&adapter->ahw->mem_lock); } #define MAX_CTL_CHECK 1000 @@ -997,7 +1001,7 @@ qlcnic_pci_mem_write_2M(struct qlcnic_adapter *adapter, correct: off8 = off & ~0xf; - mutex_lock(&adapter->ahw.mem_lock); + mutex_lock(&adapter->ahw->mem_lock); writel(off8, (mem_crb + MIU_TEST_AGT_ADDR_LO)); writel(0, (mem_crb + MIU_TEST_AGT_ADDR_HI)); @@ -1049,7 +1053,7 @@ correct: ret = 0; done: - mutex_unlock(&adapter->ahw.mem_lock); + mutex_unlock(&adapter->ahw->mem_lock); return ret; } @@ -1091,7 +1095,7 @@ qlcnic_pci_mem_read_2M(struct qlcnic_adapter *adapter, correct: off8 = off & ~0xf; - mutex_lock(&adapter->ahw.mem_lock); + mutex_lock(&adapter->ahw->mem_lock); writel(off8, (mem_crb + MIU_TEST_AGT_ADDR_LO)); writel(0, (mem_crb + MIU_TEST_AGT_ADDR_HI)); @@ -1121,7 +1125,7 @@ correct: ret = 0; } - mutex_unlock(&adapter->ahw.mem_lock); + mutex_unlock(&adapter->ahw->mem_lock); return ret; } @@ -1145,7 +1149,7 @@ int qlcnic_get_board_info(struct qlcnic_adapter *adapter) if (qlcnic_rom_fast_read(adapter, offset, &board_type)) return -EIO; - adapter->ahw.board_type = board_type; + adapter->ahw->board_type = board_type; if (board_type == QLCNIC_BRDTYPE_P3P_4_GB_MM) { u32 gpio = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_PAD_GPIO_I); @@ -1164,20 +1168,20 @@ int qlcnic_get_board_info(struct qlcnic_adapter *adapter) case QLCNIC_BRDTYPE_P3P_10G_SFP_QT: case QLCNIC_BRDTYPE_P3P_10G_XFP: case QLCNIC_BRDTYPE_P3P_10000_BASE_T: - adapter->ahw.port_type = QLCNIC_XGBE; + adapter->ahw->port_type = QLCNIC_XGBE; break; case QLCNIC_BRDTYPE_P3P_REF_QG: case QLCNIC_BRDTYPE_P3P_4_GB: case QLCNIC_BRDTYPE_P3P_4_GB_MM: - adapter->ahw.port_type = QLCNIC_GBE; + adapter->ahw->port_type = QLCNIC_GBE; break; case QLCNIC_BRDTYPE_P3P_10G_TP: - adapter->ahw.port_type = (adapter->portnum < 2) ? + adapter->ahw->port_type = (adapter->portnum < 2) ? QLCNIC_XGBE : QLCNIC_GBE; break; default: dev_err(&pdev->dev, "unknown board type %x\n", board_type); - adapter->ahw.port_type = QLCNIC_XGBE; + adapter->ahw->port_type = QLCNIC_XGBE; break; } diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c index a7f1d5b7e811..4ec0eeb6bff9 100644 --- a/drivers/net/qlcnic/qlcnic_init.c +++ b/drivers/net/qlcnic/qlcnic_init.c @@ -94,7 +94,7 @@ void qlcnic_release_rx_buffers(struct qlcnic_adapter *adapter) struct qlcnic_rx_buffer *rx_buf; int i, ring; - recv_ctx = &adapter->recv_ctx; + recv_ctx = adapter->recv_ctx; for (ring = 0; ring < adapter->max_rds_rings; ring++) { rds_ring = &recv_ctx->rds_rings[ring]; for (i = 0; i < rds_ring->num_desc; ++i) { @@ -119,7 +119,7 @@ void qlcnic_reset_rx_buffers_list(struct qlcnic_adapter *adapter) struct qlcnic_rx_buffer *rx_buf; int i, ring; - recv_ctx = &adapter->recv_ctx; + recv_ctx = adapter->recv_ctx; for (ring = 0; ring < adapter->max_rds_rings; ring++) { rds_ring = &recv_ctx->rds_rings[ring]; @@ -173,7 +173,7 @@ void qlcnic_free_sw_resources(struct qlcnic_adapter *adapter) struct qlcnic_host_tx_ring *tx_ring; int ring; - recv_ctx = &adapter->recv_ctx; + recv_ctx = adapter->recv_ctx; if (recv_ctx->rds_rings == NULL) goto skip_rds; @@ -226,7 +226,7 @@ int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter) } tx_ring->cmd_buf_arr = cmd_buf_arr; - recv_ctx = &adapter->recv_ctx; + recv_ctx = adapter->recv_ctx; size = adapter->max_rds_rings * sizeof(struct qlcnic_host_rds_ring); rds_ring = kzalloc(size, GFP_KERNEL); @@ -864,7 +864,7 @@ nomn: for (i = 0; i < entries; i++) { __le32 flags, file_chiprev, offs; - u8 chiprev = adapter->ahw.revision_id; + u8 chiprev = adapter->ahw->revision_id; u32 flagbit; offs = cpu_to_le32(ptab_descr->findex) + @@ -1130,9 +1130,20 @@ qlcnic_load_firmware(struct qlcnic_adapter *adapter) } else { u64 data; u32 hi, lo; - - size = (QLCNIC_IMAGE_START - QLCNIC_BOOTLD_START) / 8; - flashaddr = QLCNIC_BOOTLD_START; + int ret; + struct qlcnic_flt_entry bootld_entry; + + ret = qlcnic_get_flt_entry(adapter, QLCNIC_BOOTLD_REGION, + &bootld_entry); + if (!ret) { + size = bootld_entry.size / 8; + flashaddr = bootld_entry.start_addr; + } else { + size = (QLCNIC_IMAGE_START - QLCNIC_BOOTLD_START) / 8; + flashaddr = QLCNIC_BOOTLD_START; + dev_info(&pdev->dev, + "using legacy method to get flash fw region"); + } for (i = 0; i < size; i++) { if (qlcnic_rom_fast_read(adapter, @@ -1394,7 +1405,7 @@ static struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter, return skb; } -static int +static inline int qlcnic_check_rx_tagging(struct qlcnic_adapter *adapter, struct sk_buff *skb, u16 *vlan_tag) { @@ -1425,7 +1436,7 @@ qlcnic_process_rcv(struct qlcnic_adapter *adapter, int ring, u64 sts_data0) { struct net_device *netdev = adapter->netdev; - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; struct qlcnic_rx_buffer *buffer; struct sk_buff *skb; struct qlcnic_host_rds_ring *rds_ring; @@ -1467,10 +1478,10 @@ qlcnic_process_rcv(struct qlcnic_adapter *adapter, skb->protocol = eth_type_trans(skb, netdev); - if ((vid != 0xffff) && adapter->vlgrp) - vlan_gro_receive(&sds_ring->napi, adapter->vlgrp, vid, skb); - else - napi_gro_receive(&sds_ring->napi, skb); + if (vid != 0xffff) + __vlan_hwaccel_put_tag(skb, vid); + + napi_gro_receive(&sds_ring->napi, skb); adapter->stats.rx_pkts++; adapter->stats.rxbytes += length; @@ -1488,7 +1499,7 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter, int ring, u64 sts_data0, u64 sts_data1) { struct net_device *netdev = adapter->netdev; - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; struct qlcnic_rx_buffer *buffer; struct sk_buff *skb; struct qlcnic_host_rds_ring *rds_ring; @@ -1552,10 +1563,9 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter, length = skb->len; - if ((vid != 0xffff) && adapter->vlgrp) - vlan_hwaccel_receive_skb(skb, adapter->vlgrp, vid); - else - netif_receive_skb(skb); + if (vid != 0xffff) + __vlan_hwaccel_put_tag(skb, vid); + netif_receive_skb(skb); adapter->stats.lro_pkts++; adapter->stats.lrobytes += length; @@ -1625,7 +1635,7 @@ skip: for (ring = 0; ring < adapter->max_rds_rings; ring++) { struct qlcnic_host_rds_ring *rds_ring = - &adapter->recv_ctx.rds_rings[ring]; + &adapter->recv_ctx->rds_rings[ring]; if (!list_empty(&sds_ring->free_list[ring])) { list_for_each(cur, &sds_ring->free_list[ring]) { @@ -1651,12 +1661,13 @@ skip: } void -qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter, u32 ringid, +qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter, struct qlcnic_host_rds_ring *rds_ring) { struct rcv_desc *pdesc; struct qlcnic_rx_buffer *buffer; - int producer, count = 0; + int count = 0; + u32 producer; struct list_head *head; producer = rds_ring->producer; @@ -1696,7 +1707,8 @@ qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter, { struct rcv_desc *pdesc; struct qlcnic_rx_buffer *buffer; - int producer, count = 0; + int count = 0; + uint32_t producer; struct list_head *head; if (!spin_trylock(&rds_ring->lock)) diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index cb1a1ef36c0a..e9e9ba6efc5f 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -13,7 +13,6 @@ #include <linux/swab.h> #include <linux/dma-mapping.h> -#include <linux/if_vlan.h> #include <net/ip.h> #include <linux/ipv6.h> #include <linux/inetdevice.h> @@ -98,6 +97,9 @@ static int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *, u32); static int qlcnicvf_start_firmware(struct qlcnic_adapter *); static void qlcnic_set_netdev_features(struct qlcnic_adapter *, struct qlcnic_esw_func_cfg *); +static void qlcnic_vlan_rx_add(struct net_device *, u16); +static void qlcnic_vlan_rx_del(struct net_device *, u16); + /* PCI Device ID Table */ #define ENTRY(device) \ {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, (device)), \ @@ -113,7 +115,7 @@ static DEFINE_PCI_DEVICE_TABLE(qlcnic_pci_tbl) = { MODULE_DEVICE_TABLE(pci, qlcnic_pci_tbl); -void +inline void qlcnic_update_cmd_producer(struct qlcnic_adapter *adapter, struct qlcnic_host_tx_ring *tx_ring) { @@ -169,7 +171,7 @@ qlcnic_napi_add(struct qlcnic_adapter *adapter, struct net_device *netdev) { int ring; struct qlcnic_host_sds_ring *sds_ring; - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; if (qlcnic_alloc_sds_rings(recv_ctx, adapter->max_sds_rings)) return -ENOMEM; @@ -193,14 +195,14 @@ qlcnic_napi_del(struct qlcnic_adapter *adapter) { int ring; struct qlcnic_host_sds_ring *sds_ring; - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; for (ring = 0; ring < adapter->max_sds_rings; ring++) { sds_ring = &recv_ctx->sds_rings[ring]; netif_napi_del(&sds_ring->napi); } - qlcnic_free_sds_rings(&adapter->recv_ctx); + qlcnic_free_sds_rings(adapter->recv_ctx); } static void @@ -208,7 +210,7 @@ qlcnic_napi_enable(struct qlcnic_adapter *adapter) { int ring; struct qlcnic_host_sds_ring *sds_ring; - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) return; @@ -225,7 +227,7 @@ qlcnic_napi_disable(struct qlcnic_adapter *adapter) { int ring; struct qlcnic_host_sds_ring *sds_ring; - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) return; @@ -317,13 +319,6 @@ static int qlcnic_set_mac(struct net_device *netdev, void *p) return 0; } -static void qlcnic_vlan_rx_register(struct net_device *netdev, - struct vlan_group *grp) -{ - struct qlcnic_adapter *adapter = netdev_priv(netdev); - adapter->vlgrp = grp; -} - static const struct net_device_ops qlcnic_netdev_ops = { .ndo_open = qlcnic_open, .ndo_stop = qlcnic_close, @@ -334,7 +329,8 @@ static const struct net_device_ops qlcnic_netdev_ops = { .ndo_set_mac_address = qlcnic_set_mac, .ndo_change_mtu = qlcnic_change_mtu, .ndo_tx_timeout = qlcnic_tx_timeout, - .ndo_vlan_rx_register = qlcnic_vlan_rx_register, + .ndo_vlan_rx_add_vid = qlcnic_vlan_rx_add, + .ndo_vlan_rx_kill_vid = qlcnic_vlan_rx_del, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = qlcnic_poll_controller, #endif @@ -359,7 +355,7 @@ qlcnic_setup_intr(struct qlcnic_adapter *adapter) struct pci_dev *pdev = adapter->pdev; int err, num_msix; - if (adapter->rss_supported) { + if (adapter->msix_supported) { num_msix = (num_online_cpus() >= MSIX_ENTRIES_PER_ADAPTER) ? MSIX_ENTRIES_PER_ADAPTER : 2; } else @@ -369,7 +365,7 @@ qlcnic_setup_intr(struct qlcnic_adapter *adapter) adapter->flags &= ~(QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED); - legacy_intrp = &legacy_intr[adapter->ahw.pci_func]; + legacy_intrp = &legacy_intr[adapter->ahw->pci_func]; adapter->int_vec_bit = legacy_intrp->int_vec_bit; adapter->tgt_status_reg = qlcnic_get_ioaddr(adapter, @@ -391,8 +387,7 @@ qlcnic_setup_intr(struct qlcnic_adapter *adapter) adapter->flags |= QLCNIC_MSIX_ENABLED; qlcnic_set_msix_bit(pdev, 1); - if (adapter->rss_supported) - adapter->max_sds_rings = num_msix; + adapter->max_sds_rings = num_msix; dev_info(&pdev->dev, "using msi-x interrupts\n"); return; @@ -407,7 +402,7 @@ qlcnic_setup_intr(struct qlcnic_adapter *adapter) if (use_msi && !pci_enable_msi(pdev)) { adapter->flags |= QLCNIC_MSI_ENABLED; adapter->tgt_status_reg = qlcnic_get_ioaddr(adapter, - msi_tgt_status[adapter->ahw.pci_func]); + msi_tgt_status[adapter->ahw->pci_func]); dev_info(&pdev->dev, "using msi interrupts\n"); adapter->msix_entries[0].vector = pdev->irq; return; @@ -429,8 +424,8 @@ qlcnic_teardown_intr(struct qlcnic_adapter *adapter) static void qlcnic_cleanup_pci_map(struct qlcnic_adapter *adapter) { - if (adapter->ahw.pci_base0 != NULL) - iounmap(adapter->ahw.pci_base0); + if (adapter->ahw->pci_base0 != NULL) + iounmap(adapter->ahw->pci_base0); } static int @@ -464,8 +459,10 @@ qlcnic_init_pci_info(struct qlcnic_adapter *adapter) for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) { pfn = pci_info[i].id; - if (pfn > QLCNIC_MAX_PCI_FUNC) - return QL_STATUS_INVALID_PARAM; + if (pfn > QLCNIC_MAX_PCI_FUNC) { + ret = QL_STATUS_INVALID_PARAM; + goto err_eswitch; + } adapter->npars[pfn].active = (u8)pci_info[i].active; adapter->npars[pfn].type = (u8)pci_info[i].type; adapter->npars[pfn].phy_port = (u8)pci_info[i].default_port; @@ -498,7 +495,7 @@ qlcnic_set_function_modes(struct qlcnic_adapter *adapter) u32 ref_count; int i, ret = 1; u32 data = QLCNIC_MGMT_FUNC; - void __iomem *priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE; + void __iomem *priv_op = adapter->ahw->pci_base0 + QLCNIC_DRV_OP_MODE; /* If other drivers are not in use set their privilege level */ ref_count = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE); @@ -510,16 +507,16 @@ qlcnic_set_function_modes(struct qlcnic_adapter *adapter) for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) { id = i; if (adapter->npars[i].type != QLCNIC_TYPE_NIC || - id == adapter->ahw.pci_func) + id == adapter->ahw->pci_func) continue; data |= (qlcnic_config_npars & QLC_DEV_SET_DRV(0xf, id)); } } else { data = readl(priv_op); - data = (data & ~QLC_DEV_SET_DRV(0xf, adapter->ahw.pci_func)) | + data = (data & ~QLC_DEV_SET_DRV(0xf, adapter->ahw->pci_func)) | (QLC_DEV_SET_DRV(QLCNIC_MGMT_FUNC, - adapter->ahw.pci_func)); + adapter->ahw->pci_func)); } writel(data, priv_op); qlcnic_api_unlock(adapter); @@ -537,22 +534,23 @@ qlcnic_check_vf(struct qlcnic_adapter *adapter) u32 op_mode, priv_level; /* Determine FW API version */ - adapter->fw_hal_version = readl(adapter->ahw.pci_base0 + QLCNIC_FW_API); + adapter->fw_hal_version = readl(adapter->ahw->pci_base0 + + QLCNIC_FW_API); /* Find PCI function number */ pci_read_config_dword(adapter->pdev, QLCNIC_MSIX_TABLE_OFFSET, &func); - msix_base_addr = adapter->ahw.pci_base0 + QLCNIC_MSIX_BASE; + msix_base_addr = adapter->ahw->pci_base0 + QLCNIC_MSIX_BASE; msix_base = readl(msix_base_addr); func = (func - msix_base)/QLCNIC_MSIX_TBL_PGSIZE; - adapter->ahw.pci_func = func; + adapter->ahw->pci_func = func; /* Determine function privilege level */ - priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE; + priv_op = adapter->ahw->pci_base0 + QLCNIC_DRV_OP_MODE; op_mode = readl(priv_op); if (op_mode == QLC_DEV_DRV_DEFAULT) priv_level = QLCNIC_MGMT_FUNC; else - priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw.pci_func); + priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw->pci_func); if (priv_level == QLCNIC_NON_PRIV_FUNC) { adapter->op_mode = QLCNIC_NON_PRIV_FUNC; @@ -591,13 +589,14 @@ qlcnic_setup_pci_map(struct qlcnic_adapter *adapter) dev_info(&pdev->dev, "%dMB memory map\n", (int)(mem_len>>20)); - adapter->ahw.pci_base0 = mem_ptr0; - adapter->ahw.pci_len0 = pci_len0; + adapter->ahw->pci_base0 = mem_ptr0; + adapter->ahw->pci_len0 = pci_len0; qlcnic_check_vf(adapter); - adapter->ahw.ocm_win_crb = qlcnic_get_ioaddr(adapter, - QLCNIC_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(adapter->ahw.pci_func))); + adapter->ahw->ocm_win_crb = qlcnic_get_ioaddr(adapter, + QLCNIC_PCIX_PS_REG(PCIX_OCM_WINDOW_REG( + adapter->ahw->pci_func))); return 0; } @@ -639,7 +638,7 @@ qlcnic_check_options(struct qlcnic_adapter *adapter) dev_info(&pdev->dev, "firmware v%d.%d.%d\n", fw_major, fw_minor, fw_build); - if (adapter->ahw.port_type == QLCNIC_XGBE) { + if (adapter->ahw->port_type == QLCNIC_XGBE) { if (adapter->flags & QLCNIC_ESWITCH_ENABLED) { adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_VF; adapter->max_rxd = MAX_RCV_DESCRIPTORS_VF; @@ -651,7 +650,7 @@ qlcnic_check_options(struct qlcnic_adapter *adapter) adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G; adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G; - } else if (adapter->ahw.port_type == QLCNIC_GBE) { + } else if (adapter->ahw->port_type == QLCNIC_GBE) { adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_1G; adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G; adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G; @@ -659,7 +658,6 @@ qlcnic_check_options(struct qlcnic_adapter *adapter) } adapter->msix_supported = !!use_msi_x; - adapter->rss_supported = !!use_msi_x; adapter->num_txd = MAX_CMD_DESCRIPTORS; @@ -672,7 +670,7 @@ qlcnic_initialize_nic(struct qlcnic_adapter *adapter) int err; struct qlcnic_info nic_info; - err = qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw.pci_func); + err = qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw->pci_func); if (err) return err; @@ -708,6 +706,22 @@ qlcnic_set_vlan_config(struct qlcnic_adapter *adapter, } static void +qlcnic_vlan_rx_add(struct net_device *netdev, u16 vid) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + set_bit(vid, adapter->vlans); +} + +static void +qlcnic_vlan_rx_del(struct net_device *netdev, u16 vid) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + + qlcnic_restore_indev_addr(netdev, NETDEV_DOWN); + clear_bit(vid, adapter->vlans); +} + +static void qlcnic_set_eswitch_port_features(struct qlcnic_adapter *adapter, struct qlcnic_esw_func_cfg *esw_cfg) { @@ -734,7 +748,7 @@ qlcnic_set_eswitch_port_config(struct qlcnic_adapter *adapter) if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) return 0; - esw_cfg.pci_func = adapter->ahw.pci_func; + esw_cfg.pci_func = adapter->ahw->pci_func; if (qlcnic_get_eswitch_port_config(adapter, &esw_cfg)) return -EIO; qlcnic_set_vlan_config(adapter, &esw_cfg); @@ -753,13 +767,14 @@ qlcnic_set_netdev_features(struct qlcnic_adapter *adapter, features = (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_GRO); vlan_features = (NETIF_F_SG | NETIF_F_IP_CSUM | - NETIF_F_IPV6_CSUM); + NETIF_F_IPV6_CSUM | NETIF_F_HW_VLAN_FILTER); if (adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO) { features |= (NETIF_F_TSO | NETIF_F_TSO6); vlan_features |= (NETIF_F_TSO | NETIF_F_TSO6); } - if (adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO) + + if (netdev->features & NETIF_F_LRO) features |= NETIF_F_LRO; if (esw_cfg->offload_flags & BIT_0) { @@ -791,14 +806,14 @@ qlcnic_check_eswitch_mode(struct qlcnic_adapter *adapter) if (adapter->flags & QLCNIC_ADAPTER_INITIALIZED) return 0; - priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE; + priv_op = adapter->ahw->pci_base0 + QLCNIC_DRV_OP_MODE; op_mode = readl(priv_op); - priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw.pci_func); + priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw->pci_func); if (op_mode == QLC_DEV_DRV_DEFAULT) priv_level = QLCNIC_MGMT_FUNC; else - priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw.pci_func); + priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw->pci_func); if (adapter->flags & QLCNIC_ESWITCH_ENABLED) { if (priv_level == QLCNIC_MGMT_FUNC) { @@ -1038,7 +1053,7 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter) unsigned long flags = 0; struct net_device *netdev = adapter->netdev; - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) { handler = qlcnic_tmp_intr; @@ -1075,7 +1090,7 @@ qlcnic_free_irq(struct qlcnic_adapter *adapter) int ring; struct qlcnic_host_sds_ring *sds_ring; - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; for (ring = 0; ring < adapter->max_sds_rings; ring++) { sds_ring = &recv_ctx->sds_rings[ring]; @@ -1083,20 +1098,6 @@ qlcnic_free_irq(struct qlcnic_adapter *adapter) } } -static void -qlcnic_init_coalesce_defaults(struct qlcnic_adapter *adapter) -{ - adapter->coal.flags = QLCNIC_INTR_DEFAULT; - adapter->coal.normal.data.rx_time_us = - QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US; - adapter->coal.normal.data.rx_packets = - QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS; - adapter->coal.normal.data.tx_time_us = - QLCNIC_DEFAULT_INTR_COALESCE_TX_TIME_US; - adapter->coal.normal.data.tx_packets = - QLCNIC_DEFAULT_INTR_COALESCE_TX_PACKETS; -} - static int __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev) { @@ -1115,14 +1116,14 @@ __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev) return -EIO; for (ring = 0; ring < adapter->max_rds_rings; ring++) { - rds_ring = &adapter->recv_ctx.rds_rings[ring]; - qlcnic_post_rx_buffers(adapter, ring, rds_ring); + rds_ring = &adapter->recv_ctx->rds_rings[ring]; + qlcnic_post_rx_buffers(adapter, rds_ring); } qlcnic_set_multi(netdev); qlcnic_fw_cmd_set_mtu(adapter, netdev->mtu); - adapter->ahw.linkup = 0; + adapter->ahw->linkup = 0; if (adapter->max_sds_rings > 1) qlcnic_config_rss(adapter, 1); @@ -1230,8 +1231,6 @@ qlcnic_attach(struct qlcnic_adapter *adapter) goto err_out_free_hw; } - qlcnic_init_coalesce_defaults(adapter); - qlcnic_create_sysfs_entries(adapter); adapter->is_up = QLCNIC_ADAPTER_UP_MAGIC; @@ -1272,7 +1271,7 @@ void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings) clear_bit(__QLCNIC_DEV_UP, &adapter->state); if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) { for (ring = 0; ring < adapter->max_sds_rings; ring++) { - sds_ring = &adapter->recv_ctx.sds_rings[ring]; + sds_ring = &adapter->recv_ctx->sds_rings[ring]; qlcnic_disable_int(sds_ring); } } @@ -1293,6 +1292,44 @@ out: netif_device_attach(netdev); } +static int qlcnic_alloc_adapter_resources(struct qlcnic_adapter *adapter) +{ + int err = 0; + adapter->ahw = kzalloc(sizeof(struct qlcnic_hardware_context), + GFP_KERNEL); + if (!adapter->ahw) { + dev_err(&adapter->pdev->dev, + "Failed to allocate recv ctx resources for adapter\n"); + err = -ENOMEM; + goto err_out; + } + adapter->recv_ctx = kzalloc(sizeof(struct qlcnic_recv_context), + GFP_KERNEL); + if (!adapter->recv_ctx) { + dev_err(&adapter->pdev->dev, + "Failed to allocate recv ctx resources for adapter\n"); + kfree(adapter->ahw); + adapter->ahw = NULL; + err = -ENOMEM; + goto err_out; + } + /* Initialize interrupt coalesce parameters */ + adapter->ahw->coal.flag = QLCNIC_INTR_DEFAULT; + adapter->ahw->coal.rx_time_us = QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US; + adapter->ahw->coal.rx_packets = QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS; +err_out: + return err; +} + +static void qlcnic_free_adapter_resources(struct qlcnic_adapter *adapter) +{ + kfree(adapter->recv_ctx); + adapter->recv_ctx = NULL; + + kfree(adapter->ahw); + adapter->ahw = NULL; +} + int qlcnic_diag_alloc_res(struct net_device *netdev, int test) { struct qlcnic_adapter *adapter = netdev_priv(netdev); @@ -1325,13 +1362,13 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test) } for (ring = 0; ring < adapter->max_rds_rings; ring++) { - rds_ring = &adapter->recv_ctx.rds_rings[ring]; - qlcnic_post_rx_buffers(adapter, ring, rds_ring); + rds_ring = &adapter->recv_ctx->rds_rings[ring]; + qlcnic_post_rx_buffers(adapter, rds_ring); } if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) { for (ring = 0; ring < adapter->max_sds_rings; ring++) { - sds_ring = &adapter->recv_ctx.sds_rings[ring]; + sds_ring = &adapter->recv_ctx->sds_rings[ring]; qlcnic_enable_int(sds_ring); } } @@ -1413,7 +1450,7 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter, netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_GRO | NETIF_F_HW_VLAN_RX); netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM | - NETIF_F_IPV6_CSUM); + NETIF_F_IPV6_CSUM | NETIF_F_HW_VLAN_FILTER); if (adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO) { netdev->features |= (NETIF_F_TSO | NETIF_F_TSO6); @@ -1501,23 +1538,26 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) adapter = netdev_priv(netdev); adapter->netdev = netdev; adapter->pdev = pdev; - adapter->dev_rst_time = jiffies; + if (qlcnic_alloc_adapter_resources(adapter)) + goto err_out_free_netdev; + + adapter->dev_rst_time = jiffies; revision_id = pdev->revision; - adapter->ahw.revision_id = revision_id; + adapter->ahw->revision_id = revision_id; - rwlock_init(&adapter->ahw.crb_lock); - mutex_init(&adapter->ahw.mem_lock); + rwlock_init(&adapter->ahw->crb_lock); + mutex_init(&adapter->ahw->mem_lock); spin_lock_init(&adapter->tx_clean_lock); INIT_LIST_HEAD(&adapter->mac_list); err = qlcnic_setup_pci_map(adapter); if (err) - goto err_out_free_netdev; + goto err_out_free_hw; /* This will be reset for mezz cards */ - adapter->portnum = adapter->ahw.pci_func; + adapter->portnum = adapter->ahw->pci_func; err = qlcnic_get_board_info(adapter); if (err) { @@ -1545,7 +1585,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pr_info("%s: %s Board Chip rev 0x%x\n", module_name(THIS_MODULE), - brd_name, adapter->ahw.revision_id); + brd_name, adapter->ahw->revision_id); } qlcnic_clear_stats(adapter); @@ -1560,7 +1600,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY); - switch (adapter->ahw.port_type) { + switch (adapter->ahw->port_type) { case QLCNIC_GBE: dev_info(&adapter->pdev->dev, "%s: GbE port initialized\n", adapter->netdev->name); @@ -1585,6 +1625,9 @@ err_out_decr_ref: err_out_iounmap: qlcnic_cleanup_pci_map(adapter); +err_out_free_hw: + qlcnic_free_adapter_resources(adapter); + err_out_free_netdev: free_netdev(netdev); @@ -1638,6 +1681,7 @@ static void __devexit qlcnic_remove(struct pci_dev *pdev) pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); + qlcnic_free_adapter_resources(adapter); free_netdev(netdev); } static int __qlcnic_shutdown(struct pci_dev *pdev) @@ -1819,6 +1863,7 @@ static void qlcnic_change_filter(struct qlcnic_adapter *adapter, vlan_req->vlan_id = vlan_id; tx_ring->producer = get_next_index(producer, tx_ring->num_desc); + smp_mb(); } #define QLCNIC_MAC_HASH(MAC)\ @@ -1879,58 +1924,122 @@ qlcnic_send_filter(struct qlcnic_adapter *adapter, spin_unlock(&adapter->mac_learn_lock); } -static void -qlcnic_tso_check(struct net_device *netdev, - struct qlcnic_host_tx_ring *tx_ring, +static int +qlcnic_tx_pkt(struct qlcnic_adapter *adapter, struct cmd_desc_type0 *first_desc, struct sk_buff *skb) { - u8 opcode = TX_ETHER_PKT; - __be16 protocol = skb->protocol; - u16 flags = 0; - int copied, offset, copy_len, hdr_len = 0, tso = 0; + u8 opcode = 0, hdr_len = 0; + u16 flags = 0, vlan_tci = 0; + int copied, offset, copy_len; struct cmd_desc_type0 *hwdesc; struct vlan_ethhdr *vh; - struct qlcnic_adapter *adapter = netdev_priv(netdev); + struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring; + u16 protocol = ntohs(skb->protocol); u32 producer = tx_ring->producer; - __le16 vlan_oob = first_desc->flags_opcode & - cpu_to_le16(FLAGS_VLAN_OOB); + + if (protocol == ETH_P_8021Q) { + vh = (struct vlan_ethhdr *)skb->data; + flags = FLAGS_VLAN_TAGGED; + vlan_tci = vh->h_vlan_TCI; + } else if (vlan_tx_tag_present(skb)) { + flags = FLAGS_VLAN_OOB; + vlan_tci = vlan_tx_tag_get(skb); + } + if (unlikely(adapter->pvid)) { + if (vlan_tci && !(adapter->flags & QLCNIC_TAGGING_ENABLED)) + return -EIO; + if (vlan_tci && (adapter->flags & QLCNIC_TAGGING_ENABLED)) + goto set_flags; + + flags = FLAGS_VLAN_OOB; + vlan_tci = adapter->pvid; + } +set_flags: + qlcnic_set_tx_vlan_tci(first_desc, vlan_tci); + qlcnic_set_tx_flags_opcode(first_desc, flags, opcode); if (*(skb->data) & BIT_0) { flags |= BIT_0; memcpy(&first_desc->eth_addr, skb->data, ETH_ALEN); } - - if ((netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) && + opcode = TX_ETHER_PKT; + if ((adapter->netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) && skb_shinfo(skb)->gso_size > 0) { hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size); first_desc->total_hdr_length = hdr_len; - if (vlan_oob) { + + opcode = (protocol == ETH_P_IPV6) ? TX_TCP_LSO6 : TX_TCP_LSO; + + /* For LSO, we need to copy the MAC/IP/TCP headers into + * the descriptor ring */ + copied = 0; + offset = 2; + + if (flags & FLAGS_VLAN_OOB) { first_desc->total_hdr_length += VLAN_HLEN; first_desc->tcp_hdr_offset = VLAN_HLEN; first_desc->ip_hdr_offset = VLAN_HLEN; /* Only in case of TSO on vlan device */ flags |= FLAGS_VLAN_TAGGED; + + /* Create a TSO vlan header template for firmware */ + + hwdesc = &tx_ring->desc_head[producer]; + tx_ring->cmd_buf_arr[producer].skb = NULL; + + copy_len = min((int)sizeof(struct cmd_desc_type0) - + offset, hdr_len + VLAN_HLEN); + + vh = (struct vlan_ethhdr *)((char *) hwdesc + 2); + skb_copy_from_linear_data(skb, vh, 12); + vh->h_vlan_proto = htons(ETH_P_8021Q); + vh->h_vlan_TCI = htons(vlan_tci); + + skb_copy_from_linear_data_offset(skb, 12, + (char *)vh + 16, copy_len - 16); + + copied = copy_len - VLAN_HLEN; + offset = 0; + + producer = get_next_index(producer, tx_ring->num_desc); } - opcode = (protocol == cpu_to_be16(ETH_P_IPV6)) ? - TX_TCP_LSO6 : TX_TCP_LSO; - tso = 1; + while (copied < hdr_len) { + + copy_len = min((int)sizeof(struct cmd_desc_type0) - + offset, (hdr_len - copied)); + + hwdesc = &tx_ring->desc_head[producer]; + tx_ring->cmd_buf_arr[producer].skb = NULL; + + skb_copy_from_linear_data_offset(skb, copied, + (char *) hwdesc + offset, copy_len); + + copied += copy_len; + offset = 0; + + producer = get_next_index(producer, tx_ring->num_desc); + } + + tx_ring->producer = producer; + smp_mb(); + adapter->stats.lso_frames++; } else if (skb->ip_summed == CHECKSUM_PARTIAL) { u8 l4proto; - if (protocol == cpu_to_be16(ETH_P_IP)) { + if (protocol == ETH_P_IP) { l4proto = ip_hdr(skb)->protocol; if (l4proto == IPPROTO_TCP) opcode = TX_TCP_PKT; else if (l4proto == IPPROTO_UDP) opcode = TX_UDP_PKT; - } else if (protocol == cpu_to_be16(ETH_P_IPV6)) { + } else if (protocol == ETH_P_IPV6) { l4proto = ipv6_hdr(skb)->nexthdr; if (l4proto == IPPROTO_TCP) @@ -1939,63 +2048,11 @@ qlcnic_tso_check(struct net_device *netdev, opcode = TX_UDPV6_PKT; } } - first_desc->tcp_hdr_offset += skb_transport_offset(skb); first_desc->ip_hdr_offset += skb_network_offset(skb); qlcnic_set_tx_flags_opcode(first_desc, flags, opcode); - if (!tso) - return; - - /* For LSO, we need to copy the MAC/IP/TCP headers into - * the descriptor ring - */ - copied = 0; - offset = 2; - - if (vlan_oob) { - /* Create a TSO vlan header template for firmware */ - - hwdesc = &tx_ring->desc_head[producer]; - tx_ring->cmd_buf_arr[producer].skb = NULL; - - copy_len = min((int)sizeof(struct cmd_desc_type0) - offset, - hdr_len + VLAN_HLEN); - - vh = (struct vlan_ethhdr *)((char *)hwdesc + 2); - skb_copy_from_linear_data(skb, vh, 12); - vh->h_vlan_proto = htons(ETH_P_8021Q); - vh->h_vlan_TCI = (__be16)swab16((u16)first_desc->vlan_TCI); - - skb_copy_from_linear_data_offset(skb, 12, - (char *)vh + 16, copy_len - 16); - - copied = copy_len - VLAN_HLEN; - offset = 0; - - producer = get_next_index(producer, tx_ring->num_desc); - } - - while (copied < hdr_len) { - - copy_len = min((int)sizeof(struct cmd_desc_type0) - offset, - (hdr_len - copied)); - - hwdesc = &tx_ring->desc_head[producer]; - tx_ring->cmd_buf_arr[producer].skb = NULL; - - skb_copy_from_linear_data_offset(skb, copied, - (char *)hwdesc + offset, copy_len); - - copied += copy_len; - offset = 0; - - producer = get_next_index(producer, tx_ring->num_desc); - } - - tx_ring->producer = producer; - barrier(); - adapter->stats.lso_frames++; + return 0; } static int @@ -2046,39 +2103,21 @@ out_err: return -ENOMEM; } -static int -qlcnic_check_tx_tagging(struct qlcnic_adapter *adapter, - struct sk_buff *skb, - struct cmd_desc_type0 *first_desc) +static void +qlcnic_unmap_buffers(struct pci_dev *pdev, struct sk_buff *skb, + struct qlcnic_cmd_buffer *pbuf) { - u8 opcode = 0; - u16 flags = 0; - __be16 protocol = skb->protocol; - struct vlan_ethhdr *vh; + struct qlcnic_skb_frag *nf = &pbuf->frag_array[0]; + int nr_frags = skb_shinfo(skb)->nr_frags; + int i; - if (protocol == cpu_to_be16(ETH_P_8021Q)) { - vh = (struct vlan_ethhdr *)skb->data; - protocol = vh->h_vlan_encapsulated_proto; - flags = FLAGS_VLAN_TAGGED; - qlcnic_set_tx_vlan_tci(first_desc, ntohs(vh->h_vlan_TCI)); - } else if (vlan_tx_tag_present(skb)) { - flags = FLAGS_VLAN_OOB; - qlcnic_set_tx_vlan_tci(first_desc, vlan_tx_tag_get(skb)); + for (i = 0; i < nr_frags; i++) { + nf = &pbuf->frag_array[i+1]; + pci_unmap_page(pdev, nf->dma, nf->length, PCI_DMA_TODEVICE); } - if (unlikely(adapter->pvid)) { - if (first_desc->vlan_TCI && - !(adapter->flags & QLCNIC_TAGGING_ENABLED)) - return -EIO; - if (first_desc->vlan_TCI && - (adapter->flags & QLCNIC_TAGGING_ENABLED)) - goto set_flags; - flags = FLAGS_VLAN_OOB; - qlcnic_set_tx_vlan_tci(first_desc, adapter->pvid); - } -set_flags: - qlcnic_set_tx_flags_opcode(first_desc, flags, opcode); - return 0; + nf = &pbuf->frag_array[0]; + pci_unmap_single(pdev, nf->dma, skb_headlen(skb), PCI_DMA_TODEVICE); } static inline void @@ -2103,7 +2142,7 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) int i, k; u32 producer; - int frag_count, no_of_desc; + int frag_count; u32 num_txd = tx_ring->num_desc; if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) { @@ -2133,12 +2172,8 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) frag_count = 1 + skb_shinfo(skb)->nr_frags; } - /* 4 fragments per cmd des */ - no_of_desc = (frag_count + 3) >> 2; - if (unlikely(qlcnic_tx_avail(tx_ring) <= TX_STOP_THRESH)) { netif_stop_queue(netdev); - smp_mb(); if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) netif_start_queue(netdev); else { @@ -2155,9 +2190,6 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) first_desc = hwdesc = &tx_ring->desc_head[producer]; qlcnic_clear_cmddesc((u64 *)hwdesc); - if (qlcnic_check_tx_tagging(adapter, skb, first_desc)) - goto drop_packet; - if (qlcnic_map_tx_skb(pdev, skb, pbuf)) { adapter->stats.tx_dma_map_error++; goto drop_packet; @@ -2201,8 +2233,10 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) } tx_ring->producer = get_next_index(producer, num_txd); + smp_mb(); - qlcnic_tso_check(netdev, tx_ring, first_desc, skb); + if (unlikely(qlcnic_tx_pkt(adapter, first_desc, skb))) + goto unwind_buff; if (qlcnic_mac_learn) qlcnic_send_filter(adapter, tx_ring, first_desc, skb); @@ -2214,6 +2248,8 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) return NETDEV_TX_OK; +unwind_buff: + qlcnic_unmap_buffers(pdev, skb, pbuf); drop_packet: adapter->stats.txdropped++; dev_kfree_skb_any(skb); @@ -2260,16 +2296,16 @@ void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup) { struct net_device *netdev = adapter->netdev; - if (adapter->ahw.linkup && !linkup) { + if (adapter->ahw->linkup && !linkup) { netdev_info(netdev, "NIC Link is down\n"); - adapter->ahw.linkup = 0; + adapter->ahw->linkup = 0; if (netif_running(netdev)) { netif_carrier_off(netdev); netif_stop_queue(netdev); } - } else if (!adapter->ahw.linkup && linkup) { + } else if (!adapter->ahw->linkup && linkup) { netdev_info(netdev, "NIC Link is up\n"); - adapter->ahw.linkup = 1; + adapter->ahw->linkup = 1; if (netif_running(netdev)) { netif_carrier_on(netdev); netif_wake_queue(netdev); @@ -2505,7 +2541,7 @@ static void qlcnic_poll_controller(struct net_device *netdev) int ring; struct qlcnic_host_sds_ring *sds_ring; struct qlcnic_adapter *adapter = netdev_priv(netdev); - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; disable_irq(adapter->irq); for (ring = 0; ring < adapter->max_sds_rings; ring++) { @@ -3515,7 +3551,7 @@ validate_esw_config(struct qlcnic_adapter *adapter, u8 pci_func; int i; - op_mode = readl(adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE); + op_mode = readl(adapter->ahw->pci_base0 + QLCNIC_DRV_OP_MODE); for (i = 0; i < count; i++) { pci_func = esw_cfg[i].pci_func; @@ -3581,13 +3617,13 @@ qlcnic_sysfs_write_esw_config(struct file *file, struct kobject *kobj, if (qlcnic_config_switch_port(adapter, &esw_cfg[i])) return QL_STATUS_INVALID_PARAM; - if (adapter->ahw.pci_func != esw_cfg[i].pci_func) + if (adapter->ahw->pci_func != esw_cfg[i].pci_func) continue; op_mode = esw_cfg[i].op_mode; qlcnic_get_eswitch_port_config(adapter, &esw_cfg[i]); esw_cfg[i].op_mode = op_mode; - esw_cfg[i].pci_func = adapter->ahw.pci_func; + esw_cfg[i].pci_func = adapter->ahw->pci_func; switch (esw_cfg[i].op_mode) { case QLCNIC_PORT_DEFAULTS: @@ -3968,14 +4004,14 @@ qlcnic_create_diag_entries(struct qlcnic_adapter *adapter) dev_info(dev, "failed to create crb sysfs entry\n"); if (device_create_bin_file(dev, &bin_attr_mem)) dev_info(dev, "failed to create mem sysfs entry\n"); + if (device_create_bin_file(dev, &bin_attr_pci_config)) + dev_info(dev, "failed to create pci config sysfs entry"); if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) return; if (device_create_bin_file(dev, &bin_attr_esw_config)) dev_info(dev, "failed to create esw config sysfs entry"); if (adapter->op_mode != QLCNIC_MGMT_FUNC) return; - if (device_create_bin_file(dev, &bin_attr_pci_config)) - dev_info(dev, "failed to create pci config sysfs entry"); if (device_create_bin_file(dev, &bin_attr_npar_config)) dev_info(dev, "failed to create npar config sysfs entry"); if (device_create_bin_file(dev, &bin_attr_pm_config)) @@ -3996,12 +4032,12 @@ qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter) device_remove_file(dev, &dev_attr_diag_mode); device_remove_bin_file(dev, &bin_attr_crb); device_remove_bin_file(dev, &bin_attr_mem); + device_remove_bin_file(dev, &bin_attr_pci_config); if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) return; device_remove_bin_file(dev, &bin_attr_esw_config); if (adapter->op_mode != QLCNIC_MGMT_FUNC) return; - device_remove_bin_file(dev, &bin_attr_pci_config); device_remove_bin_file(dev, &bin_attr_npar_config); device_remove_bin_file(dev, &bin_attr_pm_config); device_remove_bin_file(dev, &bin_attr_esw_stats); @@ -4048,14 +4084,10 @@ qlcnic_restore_indev_addr(struct net_device *netdev, unsigned long event) qlcnic_config_indev_addr(adapter, netdev, event); - if (!adapter->vlgrp) - return; - - for (vid = 0; vid < VLAN_N_VID; vid++) { - dev = vlan_group_get_device(adapter->vlgrp, vid); + for_each_set_bit(vid, adapter->vlans, VLAN_N_VID) { + dev = vlan_find_dev(netdev, vid); if (!dev) continue; - qlcnic_config_indev_addr(adapter, dev, event); } } diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index 4757c59a07a2..d32850715f5c 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -2134,7 +2134,7 @@ struct ql_adapter { struct delayed_work mpi_idc_work; struct delayed_work mpi_core_to_log; struct completion ide_completion; - struct nic_operations *nic_ops; + const struct nic_operations *nic_ops; u16 device_id; struct timer_list timer; atomic_t lb_count; diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/qlge/qlge_ethtool.c index 8149cc9de4ca..78dc40c18c60 100644 --- a/drivers/net/qlge/qlge_ethtool.c +++ b/drivers/net/qlge/qlge_ethtool.c @@ -412,31 +412,31 @@ static int ql_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol) return 0; } -static int ql_phys_id(struct net_device *ndev, u32 data) +static int ql_set_phys_id(struct net_device *ndev, + enum ethtool_phys_id_state state) + { struct ql_adapter *qdev = netdev_priv(ndev); - u32 led_reg, i; - int status; - - /* Save the current LED settings */ - status = ql_mb_get_led_cfg(qdev); - if (status) - return status; - led_reg = qdev->led_config; - /* Start blinking the led */ - if (!data || data > 300) - data = 300; + switch (state) { + case ETHTOOL_ID_ACTIVE: + /* Save the current LED settings */ + if (ql_mb_get_led_cfg(qdev)) + return -EIO; - for (i = 0; i < (data * 10); i++) + /* Start blinking */ ql_mb_set_led_cfg(qdev, QL_LED_BLINK); + return 0; - /* Restore LED settings */ - status = ql_mb_set_led_cfg(qdev, led_reg); - if (status) - return status; + case ETHTOOL_ID_INACTIVE: + /* Restore LED settings */ + if (ql_mb_set_led_cfg(qdev, qdev->led_config)) + return -EIO; + return 0; - return 0; + default: + return -EINVAL; + } } static int ql_start_loopback(struct ql_adapter *qdev) @@ -655,32 +655,6 @@ static int ql_set_pauseparam(struct net_device *netdev, return status; } -static u32 ql_get_rx_csum(struct net_device *netdev) -{ - struct ql_adapter *qdev = netdev_priv(netdev); - return qdev->rx_csum; -} - -static int ql_set_rx_csum(struct net_device *netdev, uint32_t data) -{ - struct ql_adapter *qdev = netdev_priv(netdev); - qdev->rx_csum = data; - return 0; -} - -static int ql_set_tso(struct net_device *ndev, uint32_t data) -{ - - if (data) { - ndev->features |= NETIF_F_TSO; - ndev->features |= NETIF_F_TSO6; - } else { - ndev->features &= ~NETIF_F_TSO; - ndev->features &= ~NETIF_F_TSO6; - } - return 0; -} - static u32 ql_get_msglevel(struct net_device *ndev) { struct ql_adapter *qdev = netdev_priv(ndev); @@ -703,18 +677,10 @@ const struct ethtool_ops qlge_ethtool_ops = { .get_msglevel = ql_get_msglevel, .set_msglevel = ql_set_msglevel, .get_link = ethtool_op_get_link, - .phys_id = ql_phys_id, + .set_phys_id = ql_set_phys_id, .self_test = ql_self_test, .get_pauseparam = ql_get_pauseparam, .set_pauseparam = ql_set_pauseparam, - .get_rx_csum = ql_get_rx_csum, - .set_rx_csum = ql_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, - .set_tso = ql_set_tso, .get_coalesce = ql_get_coalesce, .set_coalesce = ql_set_coalesce, .get_sset_count = ql_get_sset_count, diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 5bb311945436..6c9d124cfc76 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -1571,7 +1571,7 @@ static void ql_process_mac_rx_page(struct ql_adapter *qdev, skb->protocol = eth_type_trans(skb, ndev); skb_checksum_none_assert(skb); - if (qdev->rx_csum && + if ((ndev->features & NETIF_F_RXCSUM) && !(ib_mac_rsp->flags1 & IB_MAC_CSUM_ERR_MASK)) { /* TCP frame. */ if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T) { @@ -1684,7 +1684,7 @@ static void ql_process_mac_rx_skb(struct ql_adapter *qdev, /* If rx checksum is on, and there are no * csum or frame errors. */ - if (qdev->rx_csum && + if ((ndev->features & NETIF_F_RXCSUM) && !(ib_mac_rsp->flags1 & IB_MAC_CSUM_ERR_MASK)) { /* TCP frame. */ if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T) { @@ -2004,7 +2004,7 @@ static void ql_process_mac_split_rx_intr(struct ql_adapter *qdev, /* If rx checksum is on, and there are no * csum or frame errors. */ - if (qdev->rx_csum && + if ((ndev->features & NETIF_F_RXCSUM) && !(ib_mac_rsp->flags1 & IB_MAC_CSUM_ERR_MASK)) { /* TCP frame. */ if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T) { @@ -4412,12 +4412,12 @@ error: rtnl_unlock(); } -static struct nic_operations qla8012_nic_ops = { +static const struct nic_operations qla8012_nic_ops = { .get_flash = ql_get_8012_flash_params, .port_initialize = ql_8012_port_initialize, }; -static struct nic_operations qla8000_nic_ops = { +static const struct nic_operations qla8000_nic_ops = { .get_flash = ql_get_8000_flash_params, .port_initialize = ql_8000_port_initialize, }; @@ -4621,7 +4621,6 @@ static int __devinit ql_init_device(struct pci_dev *pdev, /* * Set up the operating parameters. */ - qdev->rx_csum = 1; qdev->workqueue = create_singlethread_workqueue(ndev->name); INIT_DELAYED_WORK(&qdev->asic_reset_work, ql_asic_reset_work); INIT_DELAYED_WORK(&qdev->mpi_reset_work, ql_mpi_reset_work); @@ -4695,15 +4694,11 @@ static int __devinit qlge_probe(struct pci_dev *pdev, qdev = netdev_priv(ndev); SET_NETDEV_DEV(ndev, &pdev->dev); - ndev->features = (0 - | NETIF_F_IP_CSUM - | NETIF_F_SG - | NETIF_F_TSO - | NETIF_F_TSO6 - | NETIF_F_TSO_ECN - | NETIF_F_HW_VLAN_TX - | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER); - ndev->features |= NETIF_F_GRO; + ndev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | + NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN | + NETIF_F_HW_VLAN_TX | NETIF_F_RXCSUM; + ndev->features = ndev->hw_features | + NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; if (test_bit(QL_DMA64, &qdev->flags)) ndev->features |= NETIF_F_HIGHDMA; diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 493b0de3848b..fb03e6ff3716 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -37,6 +37,8 @@ #define FIRMWARE_8168D_1 "rtl_nic/rtl8168d-1.fw" #define FIRMWARE_8168D_2 "rtl_nic/rtl8168d-2.fw" +#define FIRMWARE_8168E_1 "rtl_nic/rtl8168e-1.fw" +#define FIRMWARE_8168E_2 "rtl_nic/rtl8168e-2.fw" #define FIRMWARE_8105E_1 "rtl_nic/rtl8105e-1.fw" #ifdef RTL8169_DEBUG @@ -127,46 +129,57 @@ enum mac_version { RTL_GIGA_MAC_VER_28 = 0x1c, // 8168DP RTL_GIGA_MAC_VER_29 = 0x1d, // 8105E RTL_GIGA_MAC_VER_30 = 0x1e, // 8105E + RTL_GIGA_MAC_VER_31 = 0x1f, // 8168DP + RTL_GIGA_MAC_VER_32 = 0x20, // 8168E + RTL_GIGA_MAC_VER_33 = 0x21, // 8168E }; -#define _R(NAME,MAC,MASK) \ - { .name = NAME, .mac_version = MAC, .RxConfigMask = MASK } +enum rtl_tx_desc_version { + RTL_TD_0 = 0, + RTL_TD_1 = 1, +}; + +#define _R(NAME,MAC,TD) \ + { .name = NAME, .mac_version = MAC, .txd_version = TD } static const struct { const char *name; u8 mac_version; - u32 RxConfigMask; /* Clears the bits supported by this chip */ + enum rtl_tx_desc_version txd_version; } rtl_chip_info[] = { - _R("RTL8169", RTL_GIGA_MAC_VER_01, 0xff7e1880), // 8169 - _R("RTL8169s", RTL_GIGA_MAC_VER_02, 0xff7e1880), // 8169S - _R("RTL8110s", RTL_GIGA_MAC_VER_03, 0xff7e1880), // 8110S - _R("RTL8169sb/8110sb", RTL_GIGA_MAC_VER_04, 0xff7e1880), // 8169SB - _R("RTL8169sc/8110sc", RTL_GIGA_MAC_VER_05, 0xff7e1880), // 8110SCd - _R("RTL8169sc/8110sc", RTL_GIGA_MAC_VER_06, 0xff7e1880), // 8110SCe - _R("RTL8102e", RTL_GIGA_MAC_VER_07, 0xff7e1880), // PCI-E - _R("RTL8102e", RTL_GIGA_MAC_VER_08, 0xff7e1880), // PCI-E - _R("RTL8102e", RTL_GIGA_MAC_VER_09, 0xff7e1880), // PCI-E - _R("RTL8101e", RTL_GIGA_MAC_VER_10, 0xff7e1880), // PCI-E - _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_11, 0xff7e1880), // PCI-E - _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_12, 0xff7e1880), // PCI-E - _R("RTL8101e", RTL_GIGA_MAC_VER_13, 0xff7e1880), // PCI-E 8139 - _R("RTL8100e", RTL_GIGA_MAC_VER_14, 0xff7e1880), // PCI-E 8139 - _R("RTL8100e", RTL_GIGA_MAC_VER_15, 0xff7e1880), // PCI-E 8139 - _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_17, 0xff7e1880), // PCI-E - _R("RTL8101e", RTL_GIGA_MAC_VER_16, 0xff7e1880), // PCI-E - _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_18, 0xff7e1880), // PCI-E - _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_19, 0xff7e1880), // PCI-E - _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_20, 0xff7e1880), // PCI-E - _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_21, 0xff7e1880), // PCI-E - _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_22, 0xff7e1880), // PCI-E - _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_23, 0xff7e1880), // PCI-E - _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_24, 0xff7e1880), // PCI-E - _R("RTL8168d/8111d", RTL_GIGA_MAC_VER_25, 0xff7e1880), // PCI-E - _R("RTL8168d/8111d", RTL_GIGA_MAC_VER_26, 0xff7e1880), // PCI-E - _R("RTL8168dp/8111dp", RTL_GIGA_MAC_VER_27, 0xff7e1880), // PCI-E - _R("RTL8168dp/8111dp", RTL_GIGA_MAC_VER_28, 0xff7e1880), // PCI-E - _R("RTL8105e", RTL_GIGA_MAC_VER_29, 0xff7e1880), // PCI-E - _R("RTL8105e", RTL_GIGA_MAC_VER_30, 0xff7e1880) // PCI-E + _R("RTL8169", RTL_GIGA_MAC_VER_01, RTL_TD_0), // 8169 + _R("RTL8169s", RTL_GIGA_MAC_VER_02, RTL_TD_0), // 8169S + _R("RTL8110s", RTL_GIGA_MAC_VER_03, RTL_TD_0), // 8110S + _R("RTL8169sb/8110sb", RTL_GIGA_MAC_VER_04, RTL_TD_0), // 8169SB + _R("RTL8169sc/8110sc", RTL_GIGA_MAC_VER_05, RTL_TD_0), // 8110SCd + _R("RTL8169sc/8110sc", RTL_GIGA_MAC_VER_06, RTL_TD_0), // 8110SCe + _R("RTL8102e", RTL_GIGA_MAC_VER_07, RTL_TD_1), // PCI-E + _R("RTL8102e", RTL_GIGA_MAC_VER_08, RTL_TD_1), // PCI-E + _R("RTL8102e", RTL_GIGA_MAC_VER_09, RTL_TD_1), // PCI-E + _R("RTL8101e", RTL_GIGA_MAC_VER_10, RTL_TD_0), // PCI-E + _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_11, RTL_TD_0), // PCI-E + _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_12, RTL_TD_0), // PCI-E + _R("RTL8101e", RTL_GIGA_MAC_VER_13, RTL_TD_0), // PCI-E 8139 + _R("RTL8100e", RTL_GIGA_MAC_VER_14, RTL_TD_0), // PCI-E 8139 + _R("RTL8100e", RTL_GIGA_MAC_VER_15, RTL_TD_0), // PCI-E 8139 + _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_17, RTL_TD_0), // PCI-E + _R("RTL8101e", RTL_GIGA_MAC_VER_16, RTL_TD_0), // PCI-E + _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_18, RTL_TD_1), // PCI-E + _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_19, RTL_TD_1), // PCI-E + _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_20, RTL_TD_1), // PCI-E + _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_21, RTL_TD_1), // PCI-E + _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_22, RTL_TD_1), // PCI-E + _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_23, RTL_TD_1), // PCI-E + _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_24, RTL_TD_1), // PCI-E + _R("RTL8168d/8111d", RTL_GIGA_MAC_VER_25, RTL_TD_1), // PCI-E + _R("RTL8168d/8111d", RTL_GIGA_MAC_VER_26, RTL_TD_1), // PCI-E + _R("RTL8168dp/8111dp", RTL_GIGA_MAC_VER_27, RTL_TD_1), // PCI-E + _R("RTL8168dp/8111dp", RTL_GIGA_MAC_VER_28, RTL_TD_1), // PCI-E + _R("RTL8105e", RTL_GIGA_MAC_VER_29, RTL_TD_1), // PCI-E + _R("RTL8105e", RTL_GIGA_MAC_VER_30, RTL_TD_1), // PCI-E + _R("RTL8168dp/8111dp", RTL_GIGA_MAC_VER_31, RTL_TD_1), // PCI-E + _R("RTL8168e/8111e", RTL_GIGA_MAC_VER_32, RTL_TD_1), // PCI-E + _R("RTL8168e/8111e", RTL_GIGA_MAC_VER_33, RTL_TD_1) // PCI-E }; #undef _R @@ -222,6 +235,9 @@ enum rtl_registers { IntrStatus = 0x3e, TxConfig = 0x40, RxConfig = 0x44, + +#define RTL_RX_CONFIG_MASK 0xff7e1880u + RxMissed = 0x4c, Cfg9346 = 0x50, Config0 = 0x51, @@ -315,7 +331,9 @@ enum rtl8168_registers { #define OCPAR_FLAG 0x80000000 #define OCPAR_GPHY_WRITE_CMD 0x8000f060 #define OCPAR_GPHY_READ_CMD 0x0000f060 - RDSAR1 = 0xd0 /* 8168c only. Undocumented on 8168dp */ + RDSAR1 = 0xd0, /* 8168c only. Undocumented on 8168dp */ + MISC = 0xf0, /* 8168e only. */ + txpla_rst = (1 << 29) }; enum rtl_register_content { @@ -393,6 +411,7 @@ enum rtl_register_content { BWF = (1 << 6), /* Accept Broadcast wakeup frame */ MWF = (1 << 5), /* Accept Multicast wakeup frame */ UWF = (1 << 4), /* Accept Unicast wakeup frame */ + spi_en = (1 << 3), LanWake = (1 << 1), /* LanWake enable/disable */ PMEStatus = (1 << 0), /* PME status can be reset by PCI RST# */ @@ -441,21 +460,69 @@ enum rtl_register_content { CounterDump = 0x8, }; -enum desc_status_bit { +enum rtl_desc_bit { + /* First doubleword. */ DescOwn = (1 << 31), /* Descriptor is owned by NIC */ RingEnd = (1 << 30), /* End of descriptor ring */ FirstFrag = (1 << 29), /* First segment of a packet */ LastFrag = (1 << 28), /* Final segment of a packet */ +}; + +/* Generic case. */ +enum rtl_tx_desc_bit { + /* First doubleword. */ + TD_LSO = (1 << 27), /* Large Send Offload */ +#define TD_MSS_MAX 0x07ffu /* MSS value */ - /* Tx private */ - LargeSend = (1 << 27), /* TCP Large Send Offload (TSO) */ - MSSShift = 16, /* MSS value position */ - MSSMask = 0xfff, /* MSS value + LargeSend bit: 12 bits */ - IPCS = (1 << 18), /* Calculate IP checksum */ - UDPCS = (1 << 17), /* Calculate UDP/IP checksum */ - TCPCS = (1 << 16), /* Calculate TCP/IP checksum */ - TxVlanTag = (1 << 17), /* Add VLAN tag */ + /* Second doubleword. */ + TxVlanTag = (1 << 17), /* Add VLAN tag */ +}; + +/* 8169, 8168b and 810x except 8102e. */ +enum rtl_tx_desc_bit_0 { + /* First doubleword. */ +#define TD0_MSS_SHIFT 16 /* MSS position (11 bits) */ + TD0_TCP_CS = (1 << 16), /* Calculate TCP/IP checksum */ + TD0_UDP_CS = (1 << 17), /* Calculate UDP/IP checksum */ + TD0_IP_CS = (1 << 18), /* Calculate IP checksum */ +}; + +/* 8102e, 8168c and beyond. */ +enum rtl_tx_desc_bit_1 { + /* Second doubleword. */ +#define TD1_MSS_SHIFT 18 /* MSS position (11 bits) */ + TD1_IP_CS = (1 << 29), /* Calculate IP checksum */ + TD1_TCP_CS = (1 << 30), /* Calculate TCP/IP checksum */ + TD1_UDP_CS = (1 << 31), /* Calculate UDP/IP checksum */ +}; + +static const struct rtl_tx_desc_info { + struct { + u32 udp; + u32 tcp; + } checksum; + u16 mss_shift; + u16 opts_offset; +} tx_desc_info [] = { + [RTL_TD_0] = { + .checksum = { + .udp = TD0_IP_CS | TD0_UDP_CS, + .tcp = TD0_IP_CS | TD0_TCP_CS + }, + .mss_shift = TD0_MSS_SHIFT, + .opts_offset = 0 + }, + [RTL_TD_1] = { + .checksum = { + .udp = TD1_IP_CS | TD1_UDP_CS, + .tcp = TD1_IP_CS | TD1_TCP_CS + }, + .mss_shift = TD1_MSS_SHIFT, + .opts_offset = 1 + } +}; +enum rtl_rx_desc_bit { /* Rx private */ PID1 = (1 << 18), /* Protocol ID bit 1/2 */ PID0 = (1 << 17), /* Protocol ID bit 2/2 */ @@ -520,8 +587,8 @@ struct rtl8169_private { struct napi_struct napi; spinlock_t lock; /* spin lock flag */ u32 msg_enable; - int chipset; - int mac_version; + u16 txd_version; + u16 mac_version; u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */ u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */ u32 dirty_rx; @@ -577,6 +644,8 @@ MODULE_LICENSE("GPL"); MODULE_VERSION(RTL8169_VERSION); MODULE_FIRMWARE(FIRMWARE_8168D_1); MODULE_FIRMWARE(FIRMWARE_8168D_2); +MODULE_FIRMWARE(FIRMWARE_8168E_1); +MODULE_FIRMWARE(FIRMWARE_8168E_2); MODULE_FIRMWARE(FIRMWARE_8105E_1); static int rtl8169_open(struct net_device *dev); @@ -651,12 +720,18 @@ static void rtl8168_oob_notify(struct rtl8169_private *tp, u8 cmd) static void rtl8168_driver_start(struct rtl8169_private *tp) { int i; + u32 reg; rtl8168_oob_notify(tp, OOB_CMD_DRIVER_START); + if (tp->mac_version == RTL_GIGA_MAC_VER_31) + reg = 0xb8; + else + reg = 0x10; + for (i = 0; i < 10; i++) { msleep(10); - if (ocp_read(tp, 0x0f, 0x0010) & 0x00000800) + if (ocp_read(tp, 0x0f, reg) & 0x00000800) break; } } @@ -664,16 +739,36 @@ static void rtl8168_driver_start(struct rtl8169_private *tp) static void rtl8168_driver_stop(struct rtl8169_private *tp) { int i; + u32 reg; rtl8168_oob_notify(tp, OOB_CMD_DRIVER_STOP); + if (tp->mac_version == RTL_GIGA_MAC_VER_31) + reg = 0xb8; + else + reg = 0x10; + for (i = 0; i < 10; i++) { msleep(10); - if ((ocp_read(tp, 0x0f, 0x0010) & 0x00000800) == 0) + if ((ocp_read(tp, 0x0f, reg) & 0x00000800) == 0) break; } } +static int r8168dp_check_dash(struct rtl8169_private *tp) +{ + u32 reg; + + if (tp->mac_version == RTL_GIGA_MAC_VER_31) + reg = 0xb8; + else + reg = 0x10; + + if (ocp_read(tp, 0xF, reg) & 0x00008000) + return 1; + else + return 0; +} static void r8169_mdio_write(void __iomem *ioaddr, int reg_addr, int value) { @@ -1247,14 +1342,15 @@ static int rtl8169_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) return ret; } -static u32 rtl8169_get_rx_csum(struct net_device *dev) +static u32 rtl8169_fix_features(struct net_device *dev, u32 features) { - struct rtl8169_private *tp = netdev_priv(dev); + if (dev->mtu > TD_MSS_MAX) + features &= ~NETIF_F_ALL_TSO; - return tp->cp_cmd & RxChkSum; + return features; } -static int rtl8169_set_rx_csum(struct net_device *dev, u32 data) +static int rtl8169_set_features(struct net_device *dev, u32 features) { struct rtl8169_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; @@ -1262,11 +1358,16 @@ static int rtl8169_set_rx_csum(struct net_device *dev, u32 data) spin_lock_irqsave(&tp->lock, flags); - if (data) + if (features & NETIF_F_RXCSUM) tp->cp_cmd |= RxChkSum; else tp->cp_cmd &= ~RxChkSum; + if (dev->features & NETIF_F_HW_VLAN_RX) + tp->cp_cmd |= RxVlan; + else + tp->cp_cmd &= ~RxVlan; + RTL_W16(CPlusCmd, tp->cp_cmd); RTL_R16(CPlusCmd); @@ -1282,27 +1383,6 @@ static inline u32 rtl8169_tx_vlan_tag(struct rtl8169_private *tp, TxVlanTag | swab16(vlan_tx_tag_get(skb)) : 0x00; } -#define NETIF_F_HW_VLAN_TX_RX (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX) - -static void rtl8169_vlan_mode(struct net_device *dev) -{ - struct rtl8169_private *tp = netdev_priv(dev); - void __iomem *ioaddr = tp->mmio_addr; - unsigned long flags; - - spin_lock_irqsave(&tp->lock, flags); - if (dev->features & NETIF_F_HW_VLAN_RX) - tp->cp_cmd |= RxVlan; - else - tp->cp_cmd &= ~RxVlan; - RTL_W16(CPlusCmd, tp->cp_cmd); - /* PCI commit */ - RTL_R16(CPlusCmd); - spin_unlock_irqrestore(&tp->lock, flags); - - dev->vlan_features = dev->features &~ NETIF_F_HW_VLAN_TX_RX; -} - static void rtl8169_rx_vlan_tag(struct RxDesc *desc, struct sk_buff *skb) { u32 opts2 = le32_to_cpu(desc->opts2); @@ -1483,28 +1563,6 @@ static void rtl8169_get_strings(struct net_device *dev, u32 stringset, u8 *data) } } -static int rtl8169_set_flags(struct net_device *dev, u32 data) -{ - struct rtl8169_private *tp = netdev_priv(dev); - unsigned long old_feat = dev->features; - int rc; - - if ((tp->mac_version == RTL_GIGA_MAC_VER_05) && - !(data & ETH_FLAG_RXVLAN)) { - netif_info(tp, drv, dev, "8110SCd requires hardware Rx VLAN\n"); - return -EINVAL; - } - - rc = ethtool_op_set_flags(dev, data, ETH_FLAG_TXVLAN | ETH_FLAG_RXVLAN); - if (rc) - return rc; - - if ((old_feat ^ dev->features) & NETIF_F_HW_VLAN_RX) - rtl8169_vlan_mode(dev); - - return 0; -} - static const struct ethtool_ops rtl8169_ethtool_ops = { .get_drvinfo = rtl8169_get_drvinfo, .get_regs_len = rtl8169_get_regs_len, @@ -1513,19 +1571,12 @@ static const struct ethtool_ops rtl8169_ethtool_ops = { .set_settings = rtl8169_set_settings, .get_msglevel = rtl8169_get_msglevel, .set_msglevel = rtl8169_set_msglevel, - .get_rx_csum = rtl8169_get_rx_csum, - .set_rx_csum = rtl8169_set_rx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, - .set_sg = ethtool_op_set_sg, - .set_tso = ethtool_op_set_tso, .get_regs = rtl8169_get_regs, .get_wol = rtl8169_get_wol, .set_wol = rtl8169_set_wol, .get_strings = rtl8169_get_strings, .get_sset_count = rtl8169_get_sset_count, .get_ethtool_stats = rtl8169_get_ethtool_stats, - .set_flags = rtl8169_set_flags, - .get_flags = ethtool_op_get_flags, }; static void rtl8169_get_mac_version(struct rtl8169_private *tp, @@ -1547,6 +1598,11 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp, u32 val; int mac_version; } mac_info[] = { + /* 8168E family. */ + { 0x7cf00000, 0x2c200000, RTL_GIGA_MAC_VER_33 }, + { 0x7cf00000, 0x2c100000, RTL_GIGA_MAC_VER_32 }, + { 0x7c800000, 0x2c000000, RTL_GIGA_MAC_VER_33 }, + /* 8168D family. */ { 0x7cf00000, 0x28300000, RTL_GIGA_MAC_VER_26 }, { 0x7cf00000, 0x28100000, RTL_GIGA_MAC_VER_25 }, @@ -1555,6 +1611,7 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp, /* 8168DP family. */ { 0x7cf00000, 0x28800000, RTL_GIGA_MAC_VER_27 }, { 0x7cf00000, 0x28a00000, RTL_GIGA_MAC_VER_28 }, + { 0x7cf00000, 0x28b00000, RTL_GIGA_MAC_VER_31 }, /* 8168C family. */ { 0x7cf00000, 0x3cb00000, RTL_GIGA_MAC_VER_24 }, @@ -1574,6 +1631,7 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp, { 0x7c800000, 0x30000000, RTL_GIGA_MAC_VER_11 }, /* 8101 family. */ + { 0x7cf00000, 0x40b00000, RTL_GIGA_MAC_VER_30 }, { 0x7cf00000, 0x40a00000, RTL_GIGA_MAC_VER_30 }, { 0x7cf00000, 0x40900000, RTL_GIGA_MAC_VER_29 }, { 0x7c800000, 0x40800000, RTL_GIGA_MAC_VER_30 }, @@ -2436,6 +2494,93 @@ static void rtl8168d_4_hw_phy_config(struct rtl8169_private *tp) rtl_patchphy(tp, 0x0d, 1 << 5); } +static void rtl8168e_hw_phy_config(struct rtl8169_private *tp) +{ + static const struct phy_reg phy_reg_init[] = { + /* Enable Delay cap */ + { 0x1f, 0x0005 }, + { 0x05, 0x8b80 }, + { 0x06, 0xc896 }, + { 0x1f, 0x0000 }, + + /* Channel estimation fine tune */ + { 0x1f, 0x0001 }, + { 0x0b, 0x6c20 }, + { 0x07, 0x2872 }, + { 0x1c, 0xefff }, + { 0x1f, 0x0003 }, + { 0x14, 0x6420 }, + { 0x1f, 0x0000 }, + + /* Update PFM & 10M TX idle timer */ + { 0x1f, 0x0007 }, + { 0x1e, 0x002f }, + { 0x15, 0x1919 }, + { 0x1f, 0x0000 }, + + { 0x1f, 0x0007 }, + { 0x1e, 0x00ac }, + { 0x18, 0x0006 }, + { 0x1f, 0x0000 } + }; + + rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init)); + + /* DCO enable for 10M IDLE Power */ + rtl_writephy(tp, 0x1f, 0x0007); + rtl_writephy(tp, 0x1e, 0x0023); + rtl_w1w0_phy(tp, 0x17, 0x0006, 0x0000); + rtl_writephy(tp, 0x1f, 0x0000); + + /* For impedance matching */ + rtl_writephy(tp, 0x1f, 0x0002); + rtl_w1w0_phy(tp, 0x08, 0x8000, 0x7f00); + rtl_writephy(tp, 0x1F, 0x0000); + + /* PHY auto speed down */ + rtl_writephy(tp, 0x1f, 0x0007); + rtl_writephy(tp, 0x1e, 0x002d); + rtl_w1w0_phy(tp, 0x18, 0x0050, 0x0000); + rtl_writephy(tp, 0x1f, 0x0000); + rtl_w1w0_phy(tp, 0x14, 0x8000, 0x0000); + + rtl_writephy(tp, 0x1f, 0x0005); + rtl_writephy(tp, 0x05, 0x8b86); + rtl_w1w0_phy(tp, 0x06, 0x0001, 0x0000); + rtl_writephy(tp, 0x1f, 0x0000); + + rtl_writephy(tp, 0x1f, 0x0005); + rtl_writephy(tp, 0x05, 0x8b85); + rtl_w1w0_phy(tp, 0x06, 0x0000, 0x2000); + rtl_writephy(tp, 0x1f, 0x0007); + rtl_writephy(tp, 0x1e, 0x0020); + rtl_w1w0_phy(tp, 0x15, 0x0000, 0x1100); + rtl_writephy(tp, 0x1f, 0x0006); + rtl_writephy(tp, 0x00, 0x5a00); + rtl_writephy(tp, 0x1f, 0x0000); + rtl_writephy(tp, 0x0d, 0x0007); + rtl_writephy(tp, 0x0e, 0x003c); + rtl_writephy(tp, 0x0d, 0x4007); + rtl_writephy(tp, 0x0e, 0x0000); + rtl_writephy(tp, 0x0d, 0x0000); +} + +static void rtl8168e_1_hw_phy_config(struct rtl8169_private *tp) +{ + if (rtl_apply_firmware(tp, FIRMWARE_8168E_1) < 0) + netif_warn(tp, probe, tp->dev, "unable to apply firmware patch\n"); + + rtl8168e_hw_phy_config(tp); +} + +static void rtl8168e_2_hw_phy_config(struct rtl8169_private *tp) +{ + if (rtl_apply_firmware(tp, FIRMWARE_8168E_2) < 0) + netif_warn(tp, probe, tp->dev, "unable to apply firmware patch\n"); + + rtl8168e_hw_phy_config(tp); +} + static void rtl8102e_hw_phy_config(struct rtl8169_private *tp) { static const struct phy_reg phy_reg_init[] = { @@ -2551,6 +2696,12 @@ static void rtl_hw_phy_config(struct net_device *dev) case RTL_GIGA_MAC_VER_30: rtl8105e_hw_phy_config(tp); break; + case RTL_GIGA_MAC_VER_32: + rtl8168e_1_hw_phy_config(tp); + break; + case RTL_GIGA_MAC_VER_33: + rtl8168e_2_hw_phy_config(tp); + break; default: break; @@ -2840,6 +2991,8 @@ static const struct net_device_ops rtl8169_netdev_ops = { .ndo_tx_timeout = rtl8169_tx_timeout, .ndo_validate_addr = eth_validate_addr, .ndo_change_mtu = rtl8169_change_mtu, + .ndo_fix_features = rtl8169_fix_features, + .ndo_set_features = rtl8169_set_features, .ndo_set_mac_address = rtl_set_mac_address, .ndo_do_ioctl = rtl8169_ioctl, .ndo_set_multicast_list = rtl_set_rx_mode, @@ -2859,6 +3012,7 @@ static void __devinit rtl_init_mdio_ops(struct rtl8169_private *tp) ops->read = r8168dp_1_mdio_read; break; case RTL_GIGA_MAC_VER_28: + case RTL_GIGA_MAC_VER_31: ops->write = r8168dp_2_mdio_write; ops->read = r8168dp_2_mdio_read; break; @@ -2900,15 +3054,59 @@ static void r810x_pll_power_up(struct rtl8169_private *tp) static void r8168_phy_power_up(struct rtl8169_private *tp) { rtl_writephy(tp, 0x1f, 0x0000); - rtl_writephy(tp, 0x0e, 0x0000); + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_11: + case RTL_GIGA_MAC_VER_12: + case RTL_GIGA_MAC_VER_17: + case RTL_GIGA_MAC_VER_18: + case RTL_GIGA_MAC_VER_19: + case RTL_GIGA_MAC_VER_20: + case RTL_GIGA_MAC_VER_21: + case RTL_GIGA_MAC_VER_22: + case RTL_GIGA_MAC_VER_23: + case RTL_GIGA_MAC_VER_24: + case RTL_GIGA_MAC_VER_25: + case RTL_GIGA_MAC_VER_26: + case RTL_GIGA_MAC_VER_27: + case RTL_GIGA_MAC_VER_28: + case RTL_GIGA_MAC_VER_31: + rtl_writephy(tp, 0x0e, 0x0000); + break; + default: + break; + } rtl_writephy(tp, MII_BMCR, BMCR_ANENABLE); } static void r8168_phy_power_down(struct rtl8169_private *tp) { rtl_writephy(tp, 0x1f, 0x0000); - rtl_writephy(tp, 0x0e, 0x0200); - rtl_writephy(tp, MII_BMCR, BMCR_PDOWN); + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_32: + case RTL_GIGA_MAC_VER_33: + rtl_writephy(tp, MII_BMCR, BMCR_ANENABLE | BMCR_PDOWN); + break; + + case RTL_GIGA_MAC_VER_11: + case RTL_GIGA_MAC_VER_12: + case RTL_GIGA_MAC_VER_17: + case RTL_GIGA_MAC_VER_18: + case RTL_GIGA_MAC_VER_19: + case RTL_GIGA_MAC_VER_20: + case RTL_GIGA_MAC_VER_21: + case RTL_GIGA_MAC_VER_22: + case RTL_GIGA_MAC_VER_23: + case RTL_GIGA_MAC_VER_24: + case RTL_GIGA_MAC_VER_25: + case RTL_GIGA_MAC_VER_26: + case RTL_GIGA_MAC_VER_27: + case RTL_GIGA_MAC_VER_28: + case RTL_GIGA_MAC_VER_31: + rtl_writephy(tp, 0x0e, 0x0200); + default: + rtl_writephy(tp, MII_BMCR, BMCR_PDOWN); + break; + } } static void r8168_pll_power_down(struct rtl8169_private *tp) @@ -2916,8 +3114,9 @@ static void r8168_pll_power_down(struct rtl8169_private *tp) void __iomem *ioaddr = tp->mmio_addr; if (((tp->mac_version == RTL_GIGA_MAC_VER_27) || - (tp->mac_version == RTL_GIGA_MAC_VER_28)) && - (ocp_read(tp, 0x0f, 0x0010) & 0x00008000)) { + (tp->mac_version == RTL_GIGA_MAC_VER_28) || + (tp->mac_version == RTL_GIGA_MAC_VER_31)) && + r8168dp_check_dash(tp)) { return; } @@ -2927,6 +3126,10 @@ static void r8168_pll_power_down(struct rtl8169_private *tp) return; } + if (tp->mac_version == RTL_GIGA_MAC_VER_32 || + tp->mac_version == RTL_GIGA_MAC_VER_33) + rtl_ephy_write(ioaddr, 0x19, 0xff64); + if (__rtl8169_get_wol(tp) & WAKE_ANY) { rtl_writephy(tp, 0x1f, 0x0000); rtl_writephy(tp, MII_BMCR, 0x0000); @@ -2943,6 +3146,9 @@ static void r8168_pll_power_down(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_26: case RTL_GIGA_MAC_VER_27: case RTL_GIGA_MAC_VER_28: + case RTL_GIGA_MAC_VER_31: + case RTL_GIGA_MAC_VER_32: + case RTL_GIGA_MAC_VER_33: RTL_W8(PMCH, RTL_R8(PMCH) & ~0x80); break; } @@ -2953,8 +3159,9 @@ static void r8168_pll_power_up(struct rtl8169_private *tp) void __iomem *ioaddr = tp->mmio_addr; if (((tp->mac_version == RTL_GIGA_MAC_VER_27) || - (tp->mac_version == RTL_GIGA_MAC_VER_28)) && - (ocp_read(tp, 0x0f, 0x0010) & 0x00008000)) { + (tp->mac_version == RTL_GIGA_MAC_VER_28) || + (tp->mac_version == RTL_GIGA_MAC_VER_31)) && + r8168dp_check_dash(tp)) { return; } @@ -2963,6 +3170,9 @@ static void r8168_pll_power_up(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_26: case RTL_GIGA_MAC_VER_27: case RTL_GIGA_MAC_VER_28: + case RTL_GIGA_MAC_VER_31: + case RTL_GIGA_MAC_VER_32: + case RTL_GIGA_MAC_VER_33: RTL_W8(PMCH, RTL_R8(PMCH) | 0x80); break; } @@ -3017,6 +3227,9 @@ static void __devinit rtl_init_pll_power_ops(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_26: case RTL_GIGA_MAC_VER_27: case RTL_GIGA_MAC_VER_28: + case RTL_GIGA_MAC_VER_31: + case RTL_GIGA_MAC_VER_32: + case RTL_GIGA_MAC_VER_33: ops->down = r8168_pll_power_down; ops->up = r8168_pll_power_up; break; @@ -3037,7 +3250,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) struct mii_if_info *mii; struct net_device *dev; void __iomem *ioaddr; - unsigned int i; + int chipset, i; int rc; if (netif_msg_drv(&debug)) { @@ -3179,7 +3392,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) "driver bug, MAC version not found in rtl_chip_info\n"); goto err_out_msi_4; } - tp->chipset = i; + chipset = i; + tp->txd_version = rtl_chip_info[chipset].txd_version; RTL_W8(Cfg9346, Cfg9346_Unlock); RTL_W8(Config1, RTL_R8(Config1) | PMEnable); @@ -3226,7 +3440,19 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) netif_napi_add(dev, &tp->napi, rtl8169_poll, R8169_NAPI_WEIGHT); - dev->features |= NETIF_F_HW_VLAN_TX_RX | NETIF_F_GRO; + /* don't enable SG, IP_CSUM and TSO by default - it might not work + * properly for all devices */ + dev->features |= NETIF_F_RXCSUM | + NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + + dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO | + NETIF_F_RXCSUM | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO | + NETIF_F_HIGHDMA; + + if (tp->mac_version == RTL_GIGA_MAC_VER_05) + /* 8110SCd requires hardware Rx VLAN - disallow toggling */ + dev->hw_features &= ~NETIF_F_HW_VLAN_RX; tp->intr_mask = 0xffff; tp->hw_start = cfg->hw_start; @@ -3244,12 +3470,12 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_drvdata(pdev, dev); netif_info(tp, probe, dev, "%s at 0x%lx, %pM, XID %08x IRQ %d\n", - rtl_chip_info[tp->chipset].name, - dev->base_addr, dev->dev_addr, + rtl_chip_info[chipset].name, dev->base_addr, dev->dev_addr, (u32)(RTL_R32(TxConfig) & 0x9cf0f8ff), dev->irq); if ((tp->mac_version == RTL_GIGA_MAC_VER_27) || - (tp->mac_version == RTL_GIGA_MAC_VER_28)) { + (tp->mac_version == RTL_GIGA_MAC_VER_28) || + (tp->mac_version == RTL_GIGA_MAC_VER_31)) { rtl8168_driver_start(tp); } @@ -3282,7 +3508,8 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev) struct rtl8169_private *tp = netdev_priv(dev); if ((tp->mac_version == RTL_GIGA_MAC_VER_27) || - (tp->mac_version == RTL_GIGA_MAC_VER_28)) { + (tp->mac_version == RTL_GIGA_MAC_VER_28) || + (tp->mac_version == RTL_GIGA_MAC_VER_31)) { rtl8168_driver_stop(tp); } @@ -3344,7 +3571,7 @@ static int rtl8169_open(struct net_device *dev) rtl8169_init_phy(dev, tp); - rtl8169_vlan_mode(dev); + rtl8169_set_features(dev, dev->features); rtl_pll_power_up(tp); @@ -3382,7 +3609,8 @@ static void rtl8169_hw_reset(struct rtl8169_private *tp) rtl8169_irq_mask_and_ack(ioaddr); if (tp->mac_version == RTL_GIGA_MAC_VER_27 || - tp->mac_version == RTL_GIGA_MAC_VER_28) { + tp->mac_version == RTL_GIGA_MAC_VER_28 || + tp->mac_version == RTL_GIGA_MAC_VER_31) { while (RTL_R8(TxPoll) & NPQ) udelay(20); @@ -3400,7 +3628,7 @@ static void rtl_set_rx_tx_config_registers(struct rtl8169_private *tp) void __iomem *ioaddr = tp->mmio_addr; u32 cfg = rtl8169_rx_config; - cfg |= (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask); + cfg |= (RTL_R32(RxConfig) & RTL_RX_CONFIG_MASK); RTL_W32(RxConfig, cfg); /* Set DMA burst size and Interframe Gap Time */ @@ -3779,6 +4007,17 @@ static void rtl_hw_start_8168d(void __iomem *ioaddr, struct pci_dev *pdev) RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK); } +static void rtl_hw_start_8168dp(void __iomem *ioaddr, struct pci_dev *pdev) +{ + rtl_csi_access_enable_1(ioaddr); + + rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); + + RTL_W8(MaxTxPacketSize, TxPacketMax); + + rtl_disable_clock_request(pdev); +} + static void rtl_hw_start_8168d_4(void __iomem *ioaddr, struct pci_dev *pdev) { static const struct ephy_info e_info_8168d_4[] = { @@ -3805,6 +4044,41 @@ static void rtl_hw_start_8168d_4(void __iomem *ioaddr, struct pci_dev *pdev) rtl_enable_clock_request(pdev); } +static void rtl_hw_start_8168e(void __iomem *ioaddr, struct pci_dev *pdev) +{ + static const struct ephy_info e_info_8168e[] = { + { 0x00, 0x0200, 0x0100 }, + { 0x00, 0x0000, 0x0004 }, + { 0x06, 0x0002, 0x0001 }, + { 0x06, 0x0000, 0x0030 }, + { 0x07, 0x0000, 0x2000 }, + { 0x00, 0x0000, 0x0020 }, + { 0x03, 0x5800, 0x2000 }, + { 0x03, 0x0000, 0x0001 }, + { 0x01, 0x0800, 0x1000 }, + { 0x07, 0x0000, 0x4000 }, + { 0x1e, 0x0000, 0x2000 }, + { 0x19, 0xffff, 0xfe6c }, + { 0x0a, 0x0000, 0x0040 } + }; + + rtl_csi_access_enable_2(ioaddr); + + rtl_ephy_init(ioaddr, e_info_8168e, ARRAY_SIZE(e_info_8168e)); + + rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); + + RTL_W8(MaxTxPacketSize, TxPacketMax); + + rtl_disable_clock_request(pdev); + + /* Reset tx FIFO pointer */ + RTL_W32(MISC, RTL_R32(MISC) | txpla_rst); + RTL_W32(MISC, RTL_R32(MISC) & ~txpla_rst); + + RTL_W8(Config5, RTL_R8(Config5) & ~spi_en); +} + static void rtl_hw_start_8168(struct net_device *dev) { struct rtl8169_private *tp = netdev_priv(dev); @@ -3842,55 +4116,63 @@ static void rtl_hw_start_8168(struct net_device *dev) switch (tp->mac_version) { case RTL_GIGA_MAC_VER_11: rtl_hw_start_8168bb(ioaddr, pdev); - break; + break; case RTL_GIGA_MAC_VER_12: case RTL_GIGA_MAC_VER_17: rtl_hw_start_8168bef(ioaddr, pdev); - break; + break; case RTL_GIGA_MAC_VER_18: rtl_hw_start_8168cp_1(ioaddr, pdev); - break; + break; case RTL_GIGA_MAC_VER_19: rtl_hw_start_8168c_1(ioaddr, pdev); - break; + break; case RTL_GIGA_MAC_VER_20: rtl_hw_start_8168c_2(ioaddr, pdev); - break; + break; case RTL_GIGA_MAC_VER_21: rtl_hw_start_8168c_3(ioaddr, pdev); - break; + break; case RTL_GIGA_MAC_VER_22: rtl_hw_start_8168c_4(ioaddr, pdev); - break; + break; case RTL_GIGA_MAC_VER_23: rtl_hw_start_8168cp_2(ioaddr, pdev); - break; + break; case RTL_GIGA_MAC_VER_24: rtl_hw_start_8168cp_3(ioaddr, pdev); - break; + break; case RTL_GIGA_MAC_VER_25: case RTL_GIGA_MAC_VER_26: case RTL_GIGA_MAC_VER_27: rtl_hw_start_8168d(ioaddr, pdev); - break; + break; case RTL_GIGA_MAC_VER_28: rtl_hw_start_8168d_4(ioaddr, pdev); - break; + break; + case RTL_GIGA_MAC_VER_31: + rtl_hw_start_8168dp(ioaddr, pdev); + break; + + case RTL_GIGA_MAC_VER_32: + case RTL_GIGA_MAC_VER_33: + rtl_hw_start_8168e(ioaddr, pdev); + break; default: printk(KERN_ERR PFX "%s: unknown chipset (mac_version = %d).\n", dev->name, tp->mac_version); - break; + break; } RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); @@ -4062,6 +4344,8 @@ static int rtl8169_change_mtu(struct net_device *dev, int new_mtu) return -EINVAL; dev->mtu = new_mtu; + netdev_update_features(dev); + return 0; } @@ -4336,7 +4620,7 @@ static void rtl8169_tx_timeout(struct net_device *dev) } static int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb, - u32 opts1) + u32 *opts) { struct skb_shared_info *info = skb_shinfo(skb); unsigned int cur_frag, entry; @@ -4364,9 +4648,11 @@ static int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb, } /* anti gcc 2.95.3 bugware (sic) */ - status = opts1 | len | (RingEnd * !((entry + 1) % NUM_TX_DESC)); + status = opts[0] | len | + (RingEnd * !((entry + 1) % NUM_TX_DESC)); txd->opts1 = cpu_to_le32(status); + txd->opts2 = cpu_to_le32(opts[1]); txd->addr = cpu_to_le64(mapping); tp->tx_skb[entry].len = len; @@ -4384,24 +4670,26 @@ err_out: return -EIO; } -static inline u32 rtl8169_tso_csum(struct sk_buff *skb, struct net_device *dev) +static inline void rtl8169_tso_csum(struct rtl8169_private *tp, + struct sk_buff *skb, u32 *opts) { - if (dev->features & NETIF_F_TSO) { - u32 mss = skb_shinfo(skb)->gso_size; + const struct rtl_tx_desc_info *info = tx_desc_info + tp->txd_version; + u32 mss = skb_shinfo(skb)->gso_size; + int offset = info->opts_offset; - if (mss) - return LargeSend | ((mss & MSSMask) << MSSShift); - } - if (skb->ip_summed == CHECKSUM_PARTIAL) { + if (mss) { + opts[0] |= TD_LSO; + opts[offset] |= min(mss, TD_MSS_MAX) << info->mss_shift; + } else if (skb->ip_summed == CHECKSUM_PARTIAL) { const struct iphdr *ip = ip_hdr(skb); if (ip->protocol == IPPROTO_TCP) - return IPCS | TCPCS; + opts[offset] |= info->checksum.tcp; else if (ip->protocol == IPPROTO_UDP) - return IPCS | UDPCS; - WARN_ON(1); /* we need a WARN() */ + opts[offset] |= info->checksum.udp; + else + WARN_ON_ONCE(1); } - return 0; } static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, @@ -4414,7 +4702,7 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, struct device *d = &tp->pci_dev->dev; dma_addr_t mapping; u32 status, len; - u32 opts1; + u32 opts[2]; int frags; if (unlikely(TX_BUFFS_AVAIL(tp) < skb_shinfo(skb)->nr_frags)) { @@ -4435,24 +4723,28 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, tp->tx_skb[entry].len = len; txd->addr = cpu_to_le64(mapping); - txd->opts2 = cpu_to_le32(rtl8169_tx_vlan_tag(tp, skb)); - opts1 = DescOwn | rtl8169_tso_csum(skb, dev); + opts[1] = cpu_to_le32(rtl8169_tx_vlan_tag(tp, skb)); + opts[0] = DescOwn; + + rtl8169_tso_csum(tp, skb, opts); - frags = rtl8169_xmit_frags(tp, skb, opts1); + frags = rtl8169_xmit_frags(tp, skb, opts); if (frags < 0) goto err_dma_1; else if (frags) - opts1 |= FirstFrag; + opts[0] |= FirstFrag; else { - opts1 |= FirstFrag | LastFrag; + opts[0] |= FirstFrag | LastFrag; tp->tx_skb[entry].skb = skb; } + txd->opts2 = cpu_to_le32(opts[1]); + wmb(); /* anti gcc 2.95.3 bugware (sic) */ - status = opts1 | len | (RingEnd * !((entry + 1) % NUM_TX_DESC)); + status = opts[0] | len | (RingEnd * !((entry + 1) % NUM_TX_DESC)); txd->opts1 = cpu_to_le32(status); tp->cur_tx += frags + 1; @@ -4755,6 +5047,7 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance) case RTL_GIGA_MAC_VER_24: case RTL_GIGA_MAC_VER_27: case RTL_GIGA_MAC_VER_28: + case RTL_GIGA_MAC_VER_31: /* Experimental science. Pktgen proof. */ case RTL_GIGA_MAC_VER_12: case RTL_GIGA_MAC_VER_25: @@ -4939,7 +5232,7 @@ static void rtl_set_rx_mode(struct net_device *dev) spin_lock_irqsave(&tp->lock, flags); tmp = rtl8169_rx_config | rx_mode | - (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask); + (RTL_R32(RxConfig) & RTL_RX_CONFIG_MASK); if (tp->mac_version > RTL_GIGA_MAC_VER_06) { u32 data = mc_filter[0]; diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 337bdcd5abc9..58b78f46e54f 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -2244,13 +2244,12 @@ static int verify_xena_quiescence(struct s2io_nic *sp) static void fix_mac_address(struct s2io_nic *sp) { struct XENA_dev_config __iomem *bar0 = sp->bar0; - u64 val64; int i = 0; while (fix_mac[i] != END_SIGN) { writeq(fix_mac[i++], &bar0->gpio_control); udelay(10); - val64 = readq(&bar0->gpio_control); + (void) readq(&bar0->gpio_control); } } @@ -2727,7 +2726,6 @@ static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk) int j; struct sk_buff *skb; struct RxD_t *rxdp; - struct buffAdd *ba; struct RxD1 *rxdp1; struct RxD3 *rxdp3; struct mac_info *mac_control = &sp->mac_control; @@ -2751,7 +2749,6 @@ static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk) memset(rxdp, 0, sizeof(struct RxD1)); } else if (sp->rxd_mode == RXD_MODE_3B) { rxdp3 = (struct RxD3 *)rxdp; - ba = &mac_control->rings[ring_no].ba[blk][j]; pci_unmap_single(sp->pdev, (dma_addr_t)rxdp3->Buffer0_ptr, BUF0_LEN, @@ -5484,83 +5481,79 @@ static void s2io_ethtool_gregs(struct net_device *dev, } } -/** - * s2io_phy_id - timer function that alternates adapter LED. - * @data : address of the private member of the device structure, which - * is a pointer to the s2io_nic structure, provided as an u32. - * Description: This is actually the timer function that alternates the - * adapter LED bit of the adapter control bit to set/reset every time on - * invocation. The timer is set for 1/2 a second, hence tha NIC blinks - * once every second. +/* + * s2io_set_led - control NIC led */ -static void s2io_phy_id(unsigned long data) +static void s2io_set_led(struct s2io_nic *sp, bool on) { - struct s2io_nic *sp = (struct s2io_nic *)data; struct XENA_dev_config __iomem *bar0 = sp->bar0; - u64 val64 = 0; - u16 subid; + u16 subid = sp->pdev->subsystem_device; + u64 val64; - subid = sp->pdev->subsystem_device; if ((sp->device_type == XFRAME_II_DEVICE) || ((subid & 0xFF) >= 0x07)) { val64 = readq(&bar0->gpio_control); - val64 ^= GPIO_CTRL_GPIO_0; + if (on) + val64 |= GPIO_CTRL_GPIO_0; + else + val64 &= ~GPIO_CTRL_GPIO_0; + writeq(val64, &bar0->gpio_control); } else { val64 = readq(&bar0->adapter_control); - val64 ^= ADAPTER_LED_ON; + if (on) + val64 |= ADAPTER_LED_ON; + else + val64 &= ~ADAPTER_LED_ON; + writeq(val64, &bar0->adapter_control); } - mod_timer(&sp->id_timer, jiffies + HZ / 2); } /** - * s2io_ethtool_idnic - To physically identify the nic on the system. - * @sp : private member of the device structure, which is a pointer to the - * s2io_nic structure. - * @id : pointer to the structure with identification parameters given by - * ethtool. + * s2io_ethtool_set_led - To physically identify the nic on the system. + * @dev : network device + * @state: led setting + * * Description: Used to physically identify the NIC on the system. * The Link LED will blink for a time specified by the user for * identification. * NOTE: The Link has to be Up to be able to blink the LED. Hence * identification is possible only if it's link is up. - * Return value: - * int , returns 0 on success */ -static int s2io_ethtool_idnic(struct net_device *dev, u32 data) +static int s2io_ethtool_set_led(struct net_device *dev, + enum ethtool_phys_id_state state) { - u64 val64 = 0, last_gpio_ctrl_val; struct s2io_nic *sp = netdev_priv(dev); struct XENA_dev_config __iomem *bar0 = sp->bar0; - u16 subid; + u16 subid = sp->pdev->subsystem_device; - subid = sp->pdev->subsystem_device; - last_gpio_ctrl_val = readq(&bar0->gpio_control); if ((sp->device_type == XFRAME_I_DEVICE) && ((subid & 0xFF) < 0x07)) { - val64 = readq(&bar0->adapter_control); + u64 val64 = readq(&bar0->adapter_control); if (!(val64 & ADAPTER_CNTL_EN)) { pr_err("Adapter Link down, cannot blink LED\n"); - return -EFAULT; + return -EAGAIN; } } - if (sp->id_timer.function == NULL) { - init_timer(&sp->id_timer); - sp->id_timer.function = s2io_phy_id; - sp->id_timer.data = (unsigned long)sp; - } - mod_timer(&sp->id_timer, jiffies); - if (data) - msleep_interruptible(data * HZ); - else - msleep_interruptible(MAX_FLICKER_TIME); - del_timer_sync(&sp->id_timer); - if (CARDS_WITH_FAULTY_LINK_INDICATORS(sp->device_type, subid)) { - writeq(last_gpio_ctrl_val, &bar0->gpio_control); - last_gpio_ctrl_val = readq(&bar0->gpio_control); + switch (state) { + case ETHTOOL_ID_ACTIVE: + sp->adapt_ctrl_org = readq(&bar0->gpio_control); + return 1; /* cycle on/off once per second */ + + case ETHTOOL_ID_ON: + s2io_set_led(sp, true); + break; + + case ETHTOOL_ID_OFF: + s2io_set_led(sp, false); + break; + + case ETHTOOL_ID_INACTIVE: + if (CARDS_WITH_FAULTY_LINK_INDICATORS(sp->device_type, subid)) + writeq(sp->adapt_ctrl_org, &bar0->gpio_control); } return 0; @@ -6625,25 +6618,6 @@ static int s2io_ethtool_get_regs_len(struct net_device *dev) } -static u32 s2io_ethtool_get_rx_csum(struct net_device *dev) -{ - struct s2io_nic *sp = netdev_priv(dev); - - return sp->rx_csum; -} - -static int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data) -{ - struct s2io_nic *sp = netdev_priv(dev); - - if (data) - sp->rx_csum = 1; - else - sp->rx_csum = 0; - - return 0; -} - static int s2io_get_eeprom_len(struct net_device *dev) { return XENA_EEPROM_SPACE; @@ -6695,61 +6669,27 @@ static void s2io_ethtool_get_strings(struct net_device *dev, } } -static int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data) -{ - if (data) - dev->features |= NETIF_F_IP_CSUM; - else - dev->features &= ~NETIF_F_IP_CSUM; - - return 0; -} - -static u32 s2io_ethtool_op_get_tso(struct net_device *dev) -{ - return (dev->features & NETIF_F_TSO) != 0; -} - -static int s2io_ethtool_op_set_tso(struct net_device *dev, u32 data) -{ - if (data) - dev->features |= (NETIF_F_TSO | NETIF_F_TSO6); - else - dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); - - return 0; -} - -static int s2io_ethtool_set_flags(struct net_device *dev, u32 data) +static int s2io_set_features(struct net_device *dev, u32 features) { struct s2io_nic *sp = netdev_priv(dev); - int rc = 0; - int changed = 0; - - if (ethtool_invalid_flags(dev, data, ETH_FLAG_LRO)) - return -EINVAL; - - if (data & ETH_FLAG_LRO) { - if (!(dev->features & NETIF_F_LRO)) { - dev->features |= NETIF_F_LRO; - changed = 1; - } - } else if (dev->features & NETIF_F_LRO) { - dev->features &= ~NETIF_F_LRO; - changed = 1; - } + u32 changed = (features ^ dev->features) & NETIF_F_LRO; if (changed && netif_running(dev)) { + int rc; + s2io_stop_all_tx_queue(sp); s2io_card_down(sp); + dev->features = features; rc = s2io_card_up(sp); if (rc) s2io_reset(sp); else s2io_start_all_tx_queue(sp); + + return rc ? rc : 1; } - return rc; + return 0; } static const struct ethtool_ops netdev_ethtool_ops = { @@ -6765,18 +6705,9 @@ static const struct ethtool_ops netdev_ethtool_ops = { .get_ringparam = s2io_ethtool_gringparam, .get_pauseparam = s2io_ethtool_getpause_data, .set_pauseparam = s2io_ethtool_setpause_data, - .get_rx_csum = s2io_ethtool_get_rx_csum, - .set_rx_csum = s2io_ethtool_set_rx_csum, - .set_tx_csum = s2io_ethtool_op_set_tx_csum, - .set_flags = s2io_ethtool_set_flags, - .get_flags = ethtool_op_get_flags, - .set_sg = ethtool_op_set_sg, - .get_tso = s2io_ethtool_op_get_tso, - .set_tso = s2io_ethtool_op_set_tso, - .set_ufo = ethtool_op_set_ufo, .self_test = s2io_ethtool_test, .get_strings = s2io_ethtool_get_strings, - .phys_id = s2io_ethtool_idnic, + .set_phys_id = s2io_ethtool_set_led, .get_ethtool_stats = s2io_get_ethtool_stats, .get_sset_count = s2io_get_sset_count, }; @@ -7545,7 +7476,7 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && ((!ring_data->lro) || (ring_data->lro && (!(rxdp->Control_1 & RXD_FRAME_IP_FRAG)))) && - (sp->rx_csum)) { + (dev->features & NETIF_F_RXCSUM)) { l3_csum = RXD_GET_L3_CKSUM(rxdp->Control_1); l4_csum = RXD_GET_L4_CKSUM(rxdp->Control_1); if ((l3_csum == L3_CKSUM_OK) && (l4_csum == L4_CKSUM_OK)) { @@ -7806,6 +7737,7 @@ static const struct net_device_ops s2io_netdev_ops = { .ndo_do_ioctl = s2io_ioctl, .ndo_set_mac_address = s2io_set_mac_addr, .ndo_change_mtu = s2io_change_mtu, + .ndo_set_features = s2io_set_features, .ndo_vlan_rx_register = s2io_vlan_rx_register, .ndo_vlan_rx_kill_vid = s2io_vlan_rx_kill_vid, .ndo_tx_timeout = s2io_tx_watchdog, @@ -8047,17 +7979,18 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) /* Driver entry points */ dev->netdev_ops = &s2io_netdev_ops; SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); - dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - dev->features |= NETIF_F_LRO; - dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; + dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | + NETIF_F_TSO | NETIF_F_TSO6 | + NETIF_F_RXCSUM | NETIF_F_LRO; + dev->features |= dev->hw_features | + NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + if (sp->device_type & XFRAME_II_DEVICE) { + dev->hw_features |= NETIF_F_UFO; + if (ufo) + dev->features |= NETIF_F_UFO; + } if (sp->high_dma_flag == true) dev->features |= NETIF_F_HIGHDMA; - dev->features |= NETIF_F_TSO; - dev->features |= NETIF_F_TSO6; - if ((sp->device_type & XFRAME_II_DEVICE) && (ufo)) { - dev->features |= NETIF_F_UFO; - dev->features |= NETIF_F_HW_CSUM; - } dev->watchdog_timeo = WATCH_DOG_TIMEOUT; INIT_WORK(&sp->rst_timer_task, s2io_restart_nic); INIT_WORK(&sp->set_link_task, s2io_set_link); diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 2d144979f6f8..800b3a44e653 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -893,9 +893,6 @@ struct s2io_nic { u16 all_multi_pos; u16 promisc_flg; - /* Id timer, used to blink NIC to physically identify NIC. */ - struct timer_list id_timer; - /* Restart timer, used to restart NIC if the device is stuck and * a schedule task that will set the correct Link state once the * NIC's PHY has stabilized after a state change. @@ -1005,18 +1002,16 @@ static inline void writeq(u64 val, void __iomem *addr) #define LF 2 static inline void SPECIAL_REG_WRITE(u64 val, void __iomem *addr, int order) { - u32 ret; - if (order == LF) { writel((u32) (val), addr); - ret = readl(addr); + (void) readl(addr); writel((u32) (val >> 32), (addr + 4)); - ret = readl(addr + 4); + (void) readl(addr + 4); } else { writel((u32) (val >> 32), (addr + 4)); - ret = readl(addr + 4); + (void) readl(addr + 4); writel((u32) (val), addr); - ret = readl(addr); + (void) readl(addr); } } diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index a3c2aab53de8..38a55e9e89e4 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -1876,6 +1876,17 @@ static void efx_set_multicast_list(struct net_device *net_dev) /* Otherwise efx_start_port() will do this */ } +static int efx_set_features(struct net_device *net_dev, u32 data) +{ + struct efx_nic *efx = netdev_priv(net_dev); + + /* If disabling RX n-tuple filtering, clear existing filters */ + if (net_dev->features & ~data & NETIF_F_NTUPLE) + efx_filter_clear_rx(efx, EFX_FILTER_PRI_MANUAL); + + return 0; +} + static const struct net_device_ops efx_netdev_ops = { .ndo_open = efx_net_open, .ndo_stop = efx_net_stop, @@ -1887,6 +1898,7 @@ static const struct net_device_ops efx_netdev_ops = { .ndo_change_mtu = efx_change_mtu, .ndo_set_mac_address = efx_set_mac_address, .ndo_set_multicast_list = efx_set_multicast_list, + .ndo_set_features = efx_set_features, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = efx_netpoll, #endif @@ -2235,7 +2247,7 @@ static bool efx_port_dummy_op_poll(struct efx_nic *efx) return false; } -static struct efx_phy_operations efx_dummy_phy_operations = { +static const struct efx_phy_operations efx_dummy_phy_operations = { .init = efx_port_dummy_op_int, .reconfigure = efx_port_dummy_op_int, .poll = efx_port_dummy_op_poll, @@ -2251,7 +2263,7 @@ static struct efx_phy_operations efx_dummy_phy_operations = { /* This zeroes out and then fills in the invariants in a struct * efx_nic (including all sub-structures). */ -static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, +static int efx_init_struct(struct efx_nic *efx, const struct efx_nic_type *type, struct pci_dev *pci_dev, struct net_device *net_dev) { int i; @@ -2271,7 +2283,6 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, strlcpy(efx->name, pci_name(pci_dev), sizeof(efx->name)); efx->net_dev = net_dev; - efx->rx_checksum_enabled = true; spin_lock_init(&efx->stats_lock); mutex_init(&efx->mac_lock); efx->mac_op = type->default_mac_ops; @@ -2442,7 +2453,7 @@ static int efx_pci_probe_main(struct efx_nic *efx) static int __devinit efx_pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *entry) { - struct efx_nic_type *type = (struct efx_nic_type *) entry->driver_data; + const struct efx_nic_type *type = (const struct efx_nic_type *) entry->driver_data; struct net_device *net_dev; struct efx_nic *efx; int i, rc; @@ -2454,12 +2465,15 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev, return -ENOMEM; net_dev->features |= (type->offload_features | NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_TSO | - NETIF_F_GRO); + NETIF_F_RXCSUM); if (type->offload_features & NETIF_F_V6_CSUM) net_dev->features |= NETIF_F_TSO6; /* Mask for features that also apply to VLAN devices */ net_dev->vlan_features |= (NETIF_F_ALL_CSUM | NETIF_F_SG | - NETIF_F_HIGHDMA | NETIF_F_TSO); + NETIF_F_HIGHDMA | NETIF_F_ALL_TSO | + NETIF_F_RXCSUM); + /* All offloads can be toggled */ + net_dev->hw_features = net_dev->features & ~NETIF_F_HIGHDMA; efx = netdev_priv(net_dev); pci_set_drvdata(pci_dev, efx); SET_NETDEV_DEV(net_dev, &pci_dev->dev); diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 807178ef65ad..5d8468fc5804 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -178,19 +178,27 @@ static struct efx_ethtool_stat efx_ethtool_stats[] = { */ /* Identify device by flashing LEDs */ -static int efx_ethtool_phys_id(struct net_device *net_dev, u32 count) +static int efx_ethtool_phys_id(struct net_device *net_dev, + enum ethtool_phys_id_state state) { struct efx_nic *efx = netdev_priv(net_dev); + enum efx_led_mode mode = EFX_LED_DEFAULT; - do { - efx->type->set_id_led(efx, EFX_LED_ON); - schedule_timeout_interruptible(HZ / 2); - - efx->type->set_id_led(efx, EFX_LED_OFF); - schedule_timeout_interruptible(HZ / 2); - } while (!signal_pending(current) && --count != 0); + switch (state) { + case ETHTOOL_ID_ON: + mode = EFX_LED_ON; + break; + case ETHTOOL_ID_OFF: + mode = EFX_LED_OFF; + break; + case ETHTOOL_ID_INACTIVE: + mode = EFX_LED_DEFAULT; + break; + case ETHTOOL_ID_ACTIVE: + return 1; /* cycle on/off once per second */ + } - efx->type->set_id_led(efx, EFX_LED_DEFAULT); + efx->type->set_id_led(efx, mode); return 0; } @@ -518,72 +526,6 @@ static void efx_ethtool_get_stats(struct net_device *net_dev, } } -static int efx_ethtool_set_tso(struct net_device *net_dev, u32 enable) -{ - struct efx_nic *efx __attribute__ ((unused)) = netdev_priv(net_dev); - u32 features; - - features = NETIF_F_TSO; - if (efx->type->offload_features & NETIF_F_V6_CSUM) - features |= NETIF_F_TSO6; - - if (enable) - net_dev->features |= features; - else - net_dev->features &= ~features; - - return 0; -} - -static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable) -{ - struct efx_nic *efx = netdev_priv(net_dev); - u32 features = efx->type->offload_features & NETIF_F_ALL_CSUM; - - if (enable) - net_dev->features |= features; - else - net_dev->features &= ~features; - - return 0; -} - -static int efx_ethtool_set_rx_csum(struct net_device *net_dev, u32 enable) -{ - struct efx_nic *efx = netdev_priv(net_dev); - - /* No way to stop the hardware doing the checks; we just - * ignore the result. - */ - efx->rx_checksum_enabled = !!enable; - - return 0; -} - -static u32 efx_ethtool_get_rx_csum(struct net_device *net_dev) -{ - struct efx_nic *efx = netdev_priv(net_dev); - - return efx->rx_checksum_enabled; -} - -static int efx_ethtool_set_flags(struct net_device *net_dev, u32 data) -{ - struct efx_nic *efx = netdev_priv(net_dev); - u32 supported = (efx->type->offload_features & - (ETH_FLAG_RXHASH | ETH_FLAG_NTUPLE)); - int rc; - - rc = ethtool_op_set_flags(net_dev, data, supported); - if (rc) - return rc; - - if (!(data & ETH_FLAG_NTUPLE)) - efx_filter_clear_rx(efx, EFX_FILTER_PRI_MANUAL); - - return 0; -} - static void efx_ethtool_self_test(struct net_device *net_dev, struct ethtool_test *test, u64 *data) { @@ -1070,22 +1012,10 @@ const struct ethtool_ops efx_ethtool_ops = { .set_ringparam = efx_ethtool_set_ringparam, .get_pauseparam = efx_ethtool_get_pauseparam, .set_pauseparam = efx_ethtool_set_pauseparam, - .get_rx_csum = efx_ethtool_get_rx_csum, - .set_rx_csum = efx_ethtool_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - /* Need to enable/disable IPv6 too */ - .set_tx_csum = efx_ethtool_set_tx_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, - /* Need to enable/disable TSO-IPv6 too */ - .set_tso = efx_ethtool_set_tso, - .get_flags = ethtool_op_get_flags, - .set_flags = efx_ethtool_set_flags, .get_sset_count = efx_ethtool_get_sset_count, .self_test = efx_ethtool_self_test, .get_strings = efx_ethtool_get_strings, - .phys_id = efx_ethtool_phys_id, + .set_phys_id = efx_ethtool_phys_id, .get_ethtool_stats = efx_ethtool_get_stats, .get_wol = efx_ethtool_get_wol, .set_wol = efx_ethtool_set_wol, diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index d96b23769bd1..60176e873d62 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -1703,7 +1703,7 @@ static int falcon_set_wol(struct efx_nic *efx, u32 type) ************************************************************************** */ -struct efx_nic_type falcon_a1_nic_type = { +const struct efx_nic_type falcon_a1_nic_type = { .probe = falcon_probe_nic, .remove = falcon_remove_nic, .init = falcon_init_nic, @@ -1744,7 +1744,7 @@ struct efx_nic_type falcon_a1_nic_type = { .reset_world_flags = ETH_RESET_IRQ, }; -struct efx_nic_type falcon_b0_nic_type = { +const struct efx_nic_type falcon_b0_nic_type = { .probe = falcon_probe_nic, .remove = falcon_remove_nic, .init = falcon_init_nic, diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c index 2c9ee5db3bf7..9516452c079c 100644 --- a/drivers/net/sfc/falcon_xmac.c +++ b/drivers/net/sfc/falcon_xmac.c @@ -362,7 +362,7 @@ void falcon_poll_xmac(struct efx_nic *efx) falcon_ack_status_intr(efx); } -struct efx_mac_operations falcon_xmac_operations = { +const struct efx_mac_operations falcon_xmac_operations = { .reconfigure = falcon_reconfigure_xmac, .update_stats = falcon_update_stats_xmac, .check_fault = falcon_xmac_check_fault, diff --git a/drivers/net/sfc/mac.h b/drivers/net/sfc/mac.h index 6886cdf87c12..d6a255d0856b 100644 --- a/drivers/net/sfc/mac.h +++ b/drivers/net/sfc/mac.h @@ -13,8 +13,8 @@ #include "net_driver.h" -extern struct efx_mac_operations falcon_xmac_operations; -extern struct efx_mac_operations efx_mcdi_mac_operations; +extern const struct efx_mac_operations falcon_xmac_operations; +extern const struct efx_mac_operations efx_mcdi_mac_operations; extern int efx_mcdi_mac_stats(struct efx_nic *efx, dma_addr_t dma_addr, u32 dma_len, int enable, int clear); diff --git a/drivers/net/sfc/mcdi_mac.c b/drivers/net/sfc/mcdi_mac.c index 33f7294edb47..50c20777a564 100644 --- a/drivers/net/sfc/mcdi_mac.c +++ b/drivers/net/sfc/mcdi_mac.c @@ -138,7 +138,7 @@ static bool efx_mcdi_mac_check_fault(struct efx_nic *efx) } -struct efx_mac_operations efx_mcdi_mac_operations = { +const struct efx_mac_operations efx_mcdi_mac_operations = { .reconfigure = efx_mcdi_mac_reconfigure, .update_stats = efx_port_dummy_op_void, .check_fault = efx_mcdi_mac_check_fault, diff --git a/drivers/net/sfc/mcdi_phy.c b/drivers/net/sfc/mcdi_phy.c index 7e3c65b0c99f..1fcda2d82399 100644 --- a/drivers/net/sfc/mcdi_phy.c +++ b/drivers/net/sfc/mcdi_phy.c @@ -739,7 +739,7 @@ static const char *efx_mcdi_phy_test_name(struct efx_nic *efx, return NULL; } -struct efx_phy_operations efx_mcdi_phy_ops = { +const struct efx_phy_operations efx_mcdi_phy_ops = { .probe = efx_mcdi_phy_probe, .init = efx_port_dummy_op_int, .reconfigure = efx_mcdi_phy_reconfigure, diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 191a311da2dc..5718260298c4 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -679,7 +679,6 @@ struct efx_filter_state; * @port_inhibited: If set, the netif_carrier is always off. Hold the mac_lock * @port_initialized: Port initialized? * @net_dev: Operating system network device. Consider holding the rtnl lock - * @rx_checksum_enabled: RX checksumming enabled * @stats_buffer: DMA buffer for statistics * @mac_op: MAC interface * @phy_type: PHY type @@ -769,14 +768,13 @@ struct efx_nic { bool port_initialized; struct net_device *net_dev; - bool rx_checksum_enabled; struct efx_buffer stats_buffer; - struct efx_mac_operations *mac_op; + const struct efx_mac_operations *mac_op; unsigned int phy_type; - struct efx_phy_operations *phy_op; + const struct efx_phy_operations *phy_op; void *phy_data; struct mdio_if_info mdio; unsigned int mdio_bus; @@ -897,7 +895,7 @@ struct efx_nic_type { void (*resume_wol)(struct efx_nic *efx); int (*test_registers)(struct efx_nic *efx); int (*test_nvram)(struct efx_nic *efx); - struct efx_mac_operations *default_mac_ops; + const struct efx_mac_operations *default_mac_ops; int revision; unsigned int mem_map_size; diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c index 10f1cb79c147..5ac9fa2cd3bc 100644 --- a/drivers/net/sfc/nic.c +++ b/drivers/net/sfc/nic.c @@ -852,7 +852,6 @@ efx_handle_rx_event(struct efx_channel *channel, const efx_qword_t *event) unsigned expected_ptr; bool rx_ev_pkt_ok, discard = false, checksummed; struct efx_rx_queue *rx_queue; - struct efx_nic *efx = channel->efx; /* Basic packet information */ rx_ev_byte_cnt = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_BYTE_CNT); @@ -875,9 +874,8 @@ efx_handle_rx_event(struct efx_channel *channel, const efx_qword_t *event) * UDP/IP, then we can rely on the hardware checksum. */ checksummed = - likely(efx->rx_checksum_enabled) && - (rx_ev_hdr_type == FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_TCP || - rx_ev_hdr_type == FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_UDP); + rx_ev_hdr_type == FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_TCP || + rx_ev_hdr_type == FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_UDP; } else { efx_handle_rx_not_ok(rx_queue, event, &rx_ev_pkt_ok, &discard); checksummed = false; diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h index a42db6e35be3..7443f99c977f 100644 --- a/drivers/net/sfc/nic.h +++ b/drivers/net/sfc/nic.h @@ -150,9 +150,9 @@ struct siena_nic_data { int wol_filter_id; }; -extern struct efx_nic_type falcon_a1_nic_type; -extern struct efx_nic_type falcon_b0_nic_type; -extern struct efx_nic_type siena_a0_nic_type; +extern const struct efx_nic_type falcon_a1_nic_type; +extern const struct efx_nic_type falcon_b0_nic_type; +extern const struct efx_nic_type siena_a0_nic_type; /************************************************************************** * diff --git a/drivers/net/sfc/phy.h b/drivers/net/sfc/phy.h index b3b79472421e..11d148cd8441 100644 --- a/drivers/net/sfc/phy.h +++ b/drivers/net/sfc/phy.h @@ -13,14 +13,14 @@ /**************************************************************************** * 10Xpress (SFX7101) PHY */ -extern struct efx_phy_operations falcon_sfx7101_phy_ops; +extern const struct efx_phy_operations falcon_sfx7101_phy_ops; extern void tenxpress_set_id_led(struct efx_nic *efx, enum efx_led_mode mode); /**************************************************************************** * AMCC/Quake QT202x PHYs */ -extern struct efx_phy_operations falcon_qt202x_phy_ops; +extern const struct efx_phy_operations falcon_qt202x_phy_ops; /* These PHYs provide various H/W control states for LEDs */ #define QUAKE_LED_LINK_INVAL (0) @@ -39,7 +39,7 @@ extern void falcon_qt202x_set_led(struct efx_nic *p, int led, int state); /**************************************************************************** * Transwitch CX4 retimer */ -extern struct efx_phy_operations falcon_txc_phy_ops; +extern const struct efx_phy_operations falcon_txc_phy_ops; #define TXC_GPIO_DIR_INPUT 0 #define TXC_GPIO_DIR_OUTPUT 1 @@ -50,7 +50,7 @@ extern void falcon_txc_set_gpio_val(struct efx_nic *efx, int pin, int val); /**************************************************************************** * Siena managed PHYs */ -extern struct efx_phy_operations efx_mcdi_phy_ops; +extern const struct efx_phy_operations efx_mcdi_phy_ops; extern int efx_mcdi_mdio_read(struct efx_nic *efx, unsigned int bus, unsigned int prtad, unsigned int devad, diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c index 55f90924247e..7ad97e397406 100644 --- a/drivers/net/sfc/qt202x_phy.c +++ b/drivers/net/sfc/qt202x_phy.c @@ -449,7 +449,7 @@ static void qt202x_phy_remove(struct efx_nic *efx) efx->phy_data = NULL; } -struct efx_phy_operations falcon_qt202x_phy_ops = { +const struct efx_phy_operations falcon_qt202x_phy_ops = { .probe = qt202x_phy_probe, .init = qt202x_phy_init, .reconfigure = qt202x_phy_reconfigure, diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c index c0fdb59030fb..b7dc891b4461 100644 --- a/drivers/net/sfc/rx.c +++ b/drivers/net/sfc/rx.c @@ -605,6 +605,9 @@ void __efx_rx_packet(struct efx_channel *channel, skb_record_rx_queue(skb, channel->channel); } + if (unlikely(!(efx->net_dev->features & NETIF_F_RXCSUM))) + checksummed = false; + if (likely(checksummed || rx_buf->is_page)) { efx_rx_packet_gro(channel, rx_buf, eh, checksummed); return; diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c index e4dd8986b1fe..ceac1c9907f0 100644 --- a/drivers/net/sfc/siena.c +++ b/drivers/net/sfc/siena.c @@ -581,7 +581,7 @@ static void siena_init_wol(struct efx_nic *efx) ************************************************************************** */ -struct efx_nic_type siena_a0_nic_type = { +const struct efx_nic_type siena_a0_nic_type = { .probe = siena_probe_nic, .remove = siena_remove_nic, .init = siena_init_nic, diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index efdceb35aaae..204ecdaac9ab 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -478,7 +478,7 @@ static void sfx7101_set_npage_adv(struct efx_nic *efx, u32 advertising) advertising & ADVERTISED_10000baseT_Full); } -struct efx_phy_operations falcon_sfx7101_phy_ops = { +const struct efx_phy_operations falcon_sfx7101_phy_ops = { .probe = tenxpress_phy_probe, .init = tenxpress_phy_init, .reconfigure = tenxpress_phy_reconfigure, diff --git a/drivers/net/sfc/txc43128_phy.c b/drivers/net/sfc/txc43128_phy.c index d9886addcc99..7c21b334a75b 100644 --- a/drivers/net/sfc/txc43128_phy.c +++ b/drivers/net/sfc/txc43128_phy.c @@ -545,7 +545,7 @@ static void txc43128_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) mdio45_ethtool_gset(&efx->mdio, ecmd); } -struct efx_phy_operations falcon_txc_phy_ops = { +const struct efx_phy_operations falcon_txc_phy_ops = { .probe = txc43128_phy_probe, .init = txc43128_phy_init, .reconfigure = txc43128_phy_reconfigure, diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 35b28f42d208..176d784cbb54 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -537,46 +537,6 @@ static int skge_nway_reset(struct net_device *dev) return 0; } -static int skge_set_sg(struct net_device *dev, u32 data) -{ - struct skge_port *skge = netdev_priv(dev); - struct skge_hw *hw = skge->hw; - - if (hw->chip_id == CHIP_ID_GENESIS && data) - return -EOPNOTSUPP; - return ethtool_op_set_sg(dev, data); -} - -static int skge_set_tx_csum(struct net_device *dev, u32 data) -{ - struct skge_port *skge = netdev_priv(dev); - struct skge_hw *hw = skge->hw; - - if (hw->chip_id == CHIP_ID_GENESIS && data) - return -EOPNOTSUPP; - - return ethtool_op_set_tx_csum(dev, data); -} - -static u32 skge_get_rx_csum(struct net_device *dev) -{ - struct skge_port *skge = netdev_priv(dev); - - return skge->rx_csum; -} - -/* Only Yukon supports checksum offload. */ -static int skge_set_rx_csum(struct net_device *dev, u32 data) -{ - struct skge_port *skge = netdev_priv(dev); - - if (skge->hw->chip_id == CHIP_ID_GENESIS && data) - return -EOPNOTSUPP; - - skge->rx_csum = data; - return 0; -} - static void skge_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *ecmd) { @@ -786,28 +746,27 @@ static void skge_led(struct skge_port *skge, enum led_mode mode) } /* blink LED's for finding board */ -static int skge_phys_id(struct net_device *dev, u32 data) +static int skge_set_phys_id(struct net_device *dev, + enum ethtool_phys_id_state state) { struct skge_port *skge = netdev_priv(dev); - unsigned long ms; - enum led_mode mode = LED_MODE_TST; - if (!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ)) - ms = jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT / HZ) * 1000; - else - ms = data * 1000; + switch (state) { + case ETHTOOL_ID_ACTIVE: + return 2; /* cycle on/off twice per second */ - while (ms > 0) { - skge_led(skge, mode); - mode ^= LED_MODE_TST; + case ETHTOOL_ID_ON: + skge_led(skge, LED_MODE_TST); + break; - if (msleep_interruptible(BLINK_MS)) - break; - ms -= BLINK_MS; - } + case ETHTOOL_ID_OFF: + skge_led(skge, LED_MODE_OFF); + break; - /* back to regular LED state */ - skge_led(skge, netif_running(dev) ? LED_MODE_ON : LED_MODE_OFF); + case ETHTOOL_ID_INACTIVE: + /* back to regular LED state */ + skge_led(skge, netif_running(dev) ? LED_MODE_ON : LED_MODE_OFF); + } return 0; } @@ -925,12 +884,8 @@ static const struct ethtool_ops skge_ethtool_ops = { .set_pauseparam = skge_set_pauseparam, .get_coalesce = skge_get_coalesce, .set_coalesce = skge_set_coalesce, - .set_sg = skge_set_sg, - .set_tx_csum = skge_set_tx_csum, - .get_rx_csum = skge_get_rx_csum, - .set_rx_csum = skge_set_rx_csum, .get_strings = skge_get_strings, - .phys_id = skge_phys_id, + .set_phys_id = skge_set_phys_id, .get_sset_count = skge_get_sset_count, .get_ethtool_stats = skge_get_ethtool_stats, }; @@ -3085,7 +3040,8 @@ static struct sk_buff *skge_rx_get(struct net_device *dev, } skb_put(skb, len); - if (skge->rx_csum) { + + if (dev->features & NETIF_F_RXCSUM) { skb->csum = csum; skb->ip_summed = CHECKSUM_COMPLETE; } @@ -3847,10 +3803,10 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, setup_timer(&skge->link_timer, xm_link_timer, (unsigned long) skge); if (hw->chip_id != CHIP_ID_GENESIS) { - dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; - skge->rx_csum = 1; + dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG | + NETIF_F_RXCSUM; + dev->features |= dev->hw_features; } - dev->features |= NETIF_F_GRO; /* read the mac address */ memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port*8, ETH_ALEN); diff --git a/drivers/net/skge.h b/drivers/net/skge.h index 51c0214ac25c..598bf7a1a55e 100644 --- a/drivers/net/skge.h +++ b/drivers/net/skge.h @@ -2460,7 +2460,6 @@ struct skge_port { struct timer_list link_timer; enum pause_control flow_control; enum pause_status flow_status; - u8 rx_csum; u8 blink_on; u8 wol; u8 autoneg; /* AUTONEG_ENABLE, AUTONEG_DISABLE */ diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index ff8d262dc276..c8d045114c66 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1198,12 +1198,12 @@ static void rx_set_checksum(struct sky2_port *sky2) sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR), - (sky2->flags & SKY2_FLAG_RX_CHECKSUM) + (sky2->netdev->features & NETIF_F_RXCSUM) ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM); } /* Enable/disable receive hash calculation (RSS) */ -static void rx_set_rss(struct net_device *dev) +static void rx_set_rss(struct net_device *dev, u32 features) { struct sky2_port *sky2 = netdev_priv(dev); struct sky2_hw *hw = sky2->hw; @@ -1216,7 +1216,7 @@ static void rx_set_rss(struct net_device *dev) } /* Program RSS initial values */ - if (dev->features & NETIF_F_RXHASH) { + if (features & NETIF_F_RXHASH) { u32 key[nkeys]; get_random_bytes(key, nkeys * sizeof(u32)); @@ -1322,32 +1322,32 @@ static int sky2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return err; } -#define NETIF_F_ALL_VLAN (NETIF_F_HW_VLAN_TX|NETIF_F_HW_VLAN_RX) +#define SKY2_VLAN_OFFLOADS (NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO) -static void sky2_vlan_mode(struct net_device *dev) +static void sky2_vlan_mode(struct net_device *dev, u32 features) { struct sky2_port *sky2 = netdev_priv(dev); struct sky2_hw *hw = sky2->hw; u16 port = sky2->port; - if (dev->features & NETIF_F_HW_VLAN_RX) + if (features & NETIF_F_HW_VLAN_RX) sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), RX_VLAN_STRIP_ON); else sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), RX_VLAN_STRIP_OFF); - dev->vlan_features = dev->features &~ NETIF_F_ALL_VLAN; - if (dev->features & NETIF_F_HW_VLAN_TX) + if (features & NETIF_F_HW_VLAN_TX) { sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_VLAN_TAG_ON); - else { + + dev->vlan_features |= SKY2_VLAN_OFFLOADS; + } else { sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_VLAN_TAG_OFF); /* Can't do transmit offload of vlan without hw vlan */ - dev->vlan_features &= ~(NETIF_F_TSO | NETIF_F_SG - | NETIF_F_ALL_CSUM); + dev->vlan_features &= ~SKY2_VLAN_OFFLOADS; } } @@ -1463,7 +1463,7 @@ static void sky2_rx_start(struct sky2_port *sky2) rx_set_checksum(sky2); if (!(hw->flags & SKY2_HW_RSS_BROKEN)) - rx_set_rss(sky2->netdev); + rx_set_rss(sky2->netdev, sky2->netdev->features); /* submit Rx ring */ for (i = 0; i < sky2->rx_pending; i++) { @@ -1626,7 +1626,8 @@ static void sky2_hw_up(struct sky2_port *sky2) sky2_prefetch_init(hw, txqaddr[port], sky2->tx_le_map, sky2->tx_ring_size - 1); - sky2_vlan_mode(sky2->netdev); + sky2_vlan_mode(sky2->netdev, sky2->netdev->features); + netdev_update_features(sky2->netdev); sky2_rx_start(sky2); } @@ -2261,12 +2262,9 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu) hw->chip_id == CHIP_ID_YUKON_FE_P)) return -EINVAL; - /* TSO, etc on Yukon Ultra and MTU > 1500 not supported */ - if (new_mtu > ETH_DATA_LEN && hw->chip_id == CHIP_ID_YUKON_EC_U) - dev->features &= ~(NETIF_F_TSO|NETIF_F_SG|NETIF_F_ALL_CSUM); - if (!netif_running(dev)) { dev->mtu = new_mtu; + netdev_update_features(dev); return 0; } @@ -2288,6 +2286,7 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu) sky2_rx_clean(sky2); dev->mtu = new_mtu; + netdev_update_features(dev); mode = DATA_BLIND_VAL(DATA_BLIND_DEF) | GM_SMOD_VLAN_ENA | IPG_DATA_VAL(IPG_DATA_DEF); @@ -2535,8 +2534,11 @@ static void sky2_rx_checksum(struct sky2_port *sky2, u32 status) "%s: receive checksum problem (status = %#x)\n", sky2->netdev->name, status); - /* Disable checksum offload */ - sky2->flags &= ~SKY2_FLAG_RX_CHECKSUM; + /* Disable checksum offload + * It will be reenabled on next ndo_set_features, but if it's + * really broken, will get disabled again + */ + sky2->netdev->features &= ~NETIF_F_RXCSUM; sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR), BMU_DIS_RX_CHKSUM); } @@ -2591,7 +2593,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) /* This chip reports checksum status differently */ if (hw->flags & SKY2_HW_NEW_LE) { - if ((sky2->flags & SKY2_FLAG_RX_CHECKSUM) && + if ((dev->features & NETIF_F_RXCSUM) && (le->css & (CSS_ISIPV4 | CSS_ISIPV6)) && (le->css & CSS_TCPUDPCSOK)) skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -2616,7 +2618,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) sky2->rx_tag = length; /* fall through */ case OP_RXCHKS: - if (likely(sky2->flags & SKY2_FLAG_RX_CHECKSUM)) + if (likely(dev->features & NETIF_F_RXCSUM)) sky2_rx_checksum(sky2, status); break; @@ -3552,28 +3554,6 @@ static const struct sky2_stat { { "tx_fifo_underrun", GM_TXE_FIFO_UR }, }; -static u32 sky2_get_rx_csum(struct net_device *dev) -{ - struct sky2_port *sky2 = netdev_priv(dev); - - return !!(sky2->flags & SKY2_FLAG_RX_CHECKSUM); -} - -static int sky2_set_rx_csum(struct net_device *dev, u32 data) -{ - struct sky2_port *sky2 = netdev_priv(dev); - - if (data) - sky2->flags |= SKY2_FLAG_RX_CHECKSUM; - else - sky2->flags &= ~SKY2_FLAG_RX_CHECKSUM; - - sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR), - data ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM); - - return 0; -} - static u32 sky2_get_msglevel(struct net_device *netdev) { struct sky2_port *sky2 = netdev_priv(netdev); @@ -3826,23 +3806,24 @@ static void sky2_led(struct sky2_port *sky2, enum led_mode mode) } /* blink LED's for finding board */ -static int sky2_phys_id(struct net_device *dev, u32 data) +static int sky2_set_phys_id(struct net_device *dev, + enum ethtool_phys_id_state state) { struct sky2_port *sky2 = netdev_priv(dev); - unsigned int i; - - if (data == 0) - data = UINT_MAX; - for (i = 0; i < data; i++) { + switch (state) { + case ETHTOOL_ID_ACTIVE: + return 1; /* cycle on/off once per second */ + case ETHTOOL_ID_INACTIVE: + sky2_led(sky2, MO_LED_NORM); + break; + case ETHTOOL_ID_ON: sky2_led(sky2, MO_LED_ON); - if (msleep_interruptible(500)) - break; + break; + case ETHTOOL_ID_OFF: sky2_led(sky2, MO_LED_OFF); - if (msleep_interruptible(500)) - break; + break; } - sky2_led(sky2, MO_LED_NORM); return 0; } @@ -4083,34 +4064,6 @@ static void sky2_get_regs(struct net_device *dev, struct ethtool_regs *regs, } } -/* In order to do Jumbo packets on these chips, need to turn off the - * transmit store/forward. Therefore checksum offload won't work. - */ -static int no_tx_offload(struct net_device *dev) -{ - const struct sky2_port *sky2 = netdev_priv(dev); - const struct sky2_hw *hw = sky2->hw; - - return dev->mtu > ETH_DATA_LEN && hw->chip_id == CHIP_ID_YUKON_EC_U; -} - -static int sky2_set_tx_csum(struct net_device *dev, u32 data) -{ - if (data && no_tx_offload(dev)) - return -EINVAL; - - return ethtool_op_set_tx_csum(dev, data); -} - - -static int sky2_set_tso(struct net_device *dev, u32 data) -{ - if (data && no_tx_offload(dev)) - return -EINVAL; - - return ethtool_op_set_tso(dev, data); -} - static int sky2_get_eeprom_len(struct net_device *dev) { struct sky2_port *sky2 = netdev_priv(dev); @@ -4213,31 +4166,36 @@ static int sky2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom return sky2_vpd_write(sky2->hw, cap, data, eeprom->offset, eeprom->len); } -static int sky2_set_flags(struct net_device *dev, u32 data) +static u32 sky2_fix_features(struct net_device *dev, u32 features) { - struct sky2_port *sky2 = netdev_priv(dev); - unsigned long old_feat = dev->features; - u32 supported = 0; - int rc; + const struct sky2_port *sky2 = netdev_priv(dev); + const struct sky2_hw *hw = sky2->hw; - if (!(sky2->hw->flags & SKY2_HW_RSS_BROKEN)) - supported |= ETH_FLAG_RXHASH; + /* In order to do Jumbo packets on these chips, need to turn off the + * transmit store/forward. Therefore checksum offload won't work. + */ + if (dev->mtu > ETH_DATA_LEN && hw->chip_id == CHIP_ID_YUKON_EC_U) + features &= ~(NETIF_F_TSO|NETIF_F_SG|NETIF_F_ALL_CSUM); - if (!(sky2->hw->flags & SKY2_HW_VLAN_BROKEN)) - supported |= ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN; + return features; +} - printk(KERN_DEBUG "sky2 set_flags: supported %x data %x\n", - supported, data); +static int sky2_set_features(struct net_device *dev, u32 features) +{ + struct sky2_port *sky2 = netdev_priv(dev); + u32 changed = dev->features ^ features; - rc = ethtool_op_set_flags(dev, data, supported); - if (rc) - return rc; + if (changed & NETIF_F_RXCSUM) { + u32 on = features & NETIF_F_RXCSUM; + sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR), + on ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM); + } - if ((old_feat ^ dev->features) & NETIF_F_RXHASH) - rx_set_rss(dev); + if (changed & NETIF_F_RXHASH) + rx_set_rss(dev, features); - if ((old_feat ^ dev->features) & NETIF_F_ALL_VLAN) - sky2_vlan_mode(dev); + if (changed & (NETIF_F_HW_VLAN_TX|NETIF_F_HW_VLAN_RX)) + sky2_vlan_mode(dev, features); return 0; } @@ -4257,11 +4215,6 @@ static const struct ethtool_ops sky2_ethtool_ops = { .get_eeprom_len = sky2_get_eeprom_len, .get_eeprom = sky2_get_eeprom, .set_eeprom = sky2_set_eeprom, - .set_sg = ethtool_op_set_sg, - .set_tx_csum = sky2_set_tx_csum, - .set_tso = sky2_set_tso, - .get_rx_csum = sky2_get_rx_csum, - .set_rx_csum = sky2_set_rx_csum, .get_strings = sky2_get_strings, .get_coalesce = sky2_get_coalesce, .set_coalesce = sky2_set_coalesce, @@ -4269,11 +4222,9 @@ static const struct ethtool_ops sky2_ethtool_ops = { .set_ringparam = sky2_set_ringparam, .get_pauseparam = sky2_get_pauseparam, .set_pauseparam = sky2_set_pauseparam, - .phys_id = sky2_phys_id, + .set_phys_id = sky2_set_phys_id, .get_sset_count = sky2_get_sset_count, .get_ethtool_stats = sky2_get_ethtool_stats, - .set_flags = sky2_set_flags, - .get_flags = ethtool_op_get_flags, }; #ifdef CONFIG_SKY2_DEBUG @@ -4553,6 +4504,8 @@ static const struct net_device_ops sky2_netdev_ops[2] = { .ndo_set_mac_address = sky2_set_mac_address, .ndo_set_multicast_list = sky2_set_multicast, .ndo_change_mtu = sky2_change_mtu, + .ndo_fix_features = sky2_fix_features, + .ndo_set_features = sky2_set_features, .ndo_tx_timeout = sky2_tx_timeout, .ndo_get_stats64 = sky2_get_stats, #ifdef CONFIG_NET_POLL_CONTROLLER @@ -4568,6 +4521,8 @@ static const struct net_device_ops sky2_netdev_ops[2] = { .ndo_set_mac_address = sky2_set_mac_address, .ndo_set_multicast_list = sky2_set_multicast, .ndo_change_mtu = sky2_change_mtu, + .ndo_fix_features = sky2_fix_features, + .ndo_set_features = sky2_set_features, .ndo_tx_timeout = sky2_tx_timeout, .ndo_get_stats64 = sky2_get_stats, }, @@ -4600,7 +4555,7 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, /* Auto speed and flow control */ sky2->flags = SKY2_FLAG_AUTO_SPEED | SKY2_FLAG_AUTO_PAUSE; if (hw->chip_id != CHIP_ID_YUKON_XL) - sky2->flags |= SKY2_FLAG_RX_CHECKSUM; + dev->hw_features |= NETIF_F_RXCSUM; sky2->flow_mode = FC_BOTH; @@ -4619,18 +4574,21 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, sky2->port = port; - dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG - | NETIF_F_TSO | NETIF_F_GRO; + dev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO; if (highmem) dev->features |= NETIF_F_HIGHDMA; /* Enable receive hashing unless hardware is known broken */ if (!(hw->flags & SKY2_HW_RSS_BROKEN)) - dev->features |= NETIF_F_RXHASH; + dev->hw_features |= NETIF_F_RXHASH; + + if (!(hw->flags & SKY2_HW_VLAN_BROKEN)) { + dev->hw_features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + dev->vlan_features |= SKY2_VLAN_OFFLOADS; + } - if (!(hw->flags & SKY2_HW_VLAN_BROKEN)) - dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + dev->features |= dev->hw_features; /* read the mac address */ memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port * 8, ETH_ALEN); diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 0c6d10c5f053..318c9ae7bf91 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -2254,7 +2254,6 @@ struct sky2_port { u8 wol; /* WAKE_ bits */ u8 duplex; /* DUPLEX_HALF, DUPLEX_FULL */ u16 flags; -#define SKY2_FLAG_RX_CHECKSUM 0x0001 #define SKY2_FLAG_AUTO_SPEED 0x0002 #define SKY2_FLAG_AUTO_PAUSE 0x0004 diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c index d07c39cb4daf..0f29f261fcfe 100644 --- a/drivers/net/smc-mca.c +++ b/drivers/net/smc-mca.c @@ -156,7 +156,7 @@ static const struct { { 14, 15 } }; -static short smc_mca_adapter_ids[] __initdata = { +static const short smc_mca_adapter_ids[] __devinitconst = { 0x61c8, 0x61c9, 0x6fc0, @@ -168,7 +168,7 @@ static short smc_mca_adapter_ids[] __initdata = { 0x0000 }; -static char *smc_mca_adapter_names[] __initdata = { +static const char *const smc_mca_adapter_names[] __devinitconst = { "SMC Ethercard PLUS Elite/A BNC/AUI (WD8013EP/A)", "SMC Ethercard PLUS Elite/A UTP/AUI (WD8013WP/A)", "WD Ethercard PLUS/A (WD8003E/A or WD8003ET/A)", @@ -199,7 +199,7 @@ static const struct net_device_ops ultramca_netdev_ops = { #endif }; -static int __init ultramca_probe(struct device *gen_dev) +static int __devinit ultramca_probe(struct device *gen_dev) { unsigned short ioaddr; struct net_device *dev; diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c index 4b42ecc63dcf..c6d47d10590c 100644 --- a/drivers/net/smsc911x.c +++ b/drivers/net/smsc911x.c @@ -29,6 +29,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/crc32.h> #include <linux/delay.h> #include <linux/errno.h> @@ -69,6 +71,17 @@ static int debug = 3; module_param(debug, int, 0); MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); +struct smsc911x_data; + +struct smsc911x_ops { + u32 (*reg_read)(struct smsc911x_data *pdata, u32 reg); + void (*reg_write)(struct smsc911x_data *pdata, u32 reg, u32 val); + void (*rx_readfifo)(struct smsc911x_data *pdata, + unsigned int *buf, unsigned int wordcount); + void (*tx_writefifo)(struct smsc911x_data *pdata, + unsigned int *buf, unsigned int wordcount); +}; + struct smsc911x_data { void __iomem *ioaddr; @@ -116,8 +129,14 @@ struct smsc911x_data { unsigned int clear_bits_mask; unsigned int hashhi; unsigned int hashlo; + + /* register access functions */ + const struct smsc911x_ops *ops; }; +/* Easy access to information */ +#define __smsc_shift(pdata, reg) ((reg) << ((pdata)->config.shift)) + static inline u32 __smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg) { if (pdata->config.flags & SMSC911X_USE_32BIT) @@ -131,13 +150,29 @@ static inline u32 __smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg) return 0; } +static inline u32 +__smsc911x_reg_read_shift(struct smsc911x_data *pdata, u32 reg) +{ + if (pdata->config.flags & SMSC911X_USE_32BIT) + return readl(pdata->ioaddr + __smsc_shift(pdata, reg)); + + if (pdata->config.flags & SMSC911X_USE_16BIT) + return (readw(pdata->ioaddr + + __smsc_shift(pdata, reg)) & 0xFFFF) | + ((readw(pdata->ioaddr + + __smsc_shift(pdata, reg + 2)) & 0xFFFF) << 16); + + BUG(); + return 0; +} + static inline u32 smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg) { u32 data; unsigned long flags; spin_lock_irqsave(&pdata->dev_lock, flags); - data = __smsc911x_reg_read(pdata, reg); + data = pdata->ops->reg_read(pdata, reg); spin_unlock_irqrestore(&pdata->dev_lock, flags); return data; @@ -160,13 +195,32 @@ static inline void __smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg, BUG(); } +static inline void +__smsc911x_reg_write_shift(struct smsc911x_data *pdata, u32 reg, u32 val) +{ + if (pdata->config.flags & SMSC911X_USE_32BIT) { + writel(val, pdata->ioaddr + __smsc_shift(pdata, reg)); + return; + } + + if (pdata->config.flags & SMSC911X_USE_16BIT) { + writew(val & 0xFFFF, + pdata->ioaddr + __smsc_shift(pdata, reg)); + writew((val >> 16) & 0xFFFF, + pdata->ioaddr + __smsc_shift(pdata, reg + 2)); + return; + } + + BUG(); +} + static inline void smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg, u32 val) { unsigned long flags; spin_lock_irqsave(&pdata->dev_lock, flags); - __smsc911x_reg_write(pdata, reg, val); + pdata->ops->reg_write(pdata, reg, val); spin_unlock_irqrestore(&pdata->dev_lock, flags); } @@ -202,6 +256,40 @@ out: spin_unlock_irqrestore(&pdata->dev_lock, flags); } +/* Writes a packet to the TX_DATA_FIFO - shifted version */ +static inline void +smsc911x_tx_writefifo_shift(struct smsc911x_data *pdata, unsigned int *buf, + unsigned int wordcount) +{ + unsigned long flags; + + spin_lock_irqsave(&pdata->dev_lock, flags); + + if (pdata->config.flags & SMSC911X_SWAP_FIFO) { + while (wordcount--) + __smsc911x_reg_write_shift(pdata, TX_DATA_FIFO, + swab32(*buf++)); + goto out; + } + + if (pdata->config.flags & SMSC911X_USE_32BIT) { + writesl(pdata->ioaddr + __smsc_shift(pdata, + TX_DATA_FIFO), buf, wordcount); + goto out; + } + + if (pdata->config.flags & SMSC911X_USE_16BIT) { + while (wordcount--) + __smsc911x_reg_write_shift(pdata, + TX_DATA_FIFO, *buf++); + goto out; + } + + BUG(); +out: + spin_unlock_irqrestore(&pdata->dev_lock, flags); +} + /* Reads a packet out of the RX_DATA_FIFO */ static inline void smsc911x_rx_readfifo(struct smsc911x_data *pdata, unsigned int *buf, @@ -234,6 +322,40 @@ out: spin_unlock_irqrestore(&pdata->dev_lock, flags); } +/* Reads a packet out of the RX_DATA_FIFO - shifted version */ +static inline void +smsc911x_rx_readfifo_shift(struct smsc911x_data *pdata, unsigned int *buf, + unsigned int wordcount) +{ + unsigned long flags; + + spin_lock_irqsave(&pdata->dev_lock, flags); + + if (pdata->config.flags & SMSC911X_SWAP_FIFO) { + while (wordcount--) + *buf++ = swab32(__smsc911x_reg_read_shift(pdata, + RX_DATA_FIFO)); + goto out; + } + + if (pdata->config.flags & SMSC911X_USE_32BIT) { + readsl(pdata->ioaddr + __smsc_shift(pdata, + RX_DATA_FIFO), buf, wordcount); + goto out; + } + + if (pdata->config.flags & SMSC911X_USE_16BIT) { + while (wordcount--) + *buf++ = __smsc911x_reg_read_shift(pdata, + RX_DATA_FIFO); + goto out; + } + + BUG(); +out: + spin_unlock_irqrestore(&pdata->dev_lock, flags); +} + /* waits for MAC not busy, with timeout. Only called by smsc911x_mac_read * and smsc911x_mac_write, so assumes mac_lock is held */ static int smsc911x_mac_complete(struct smsc911x_data *pdata) @@ -248,8 +370,8 @@ static int smsc911x_mac_complete(struct smsc911x_data *pdata) if (!(val & MAC_CSR_CMD_CSR_BUSY_)) return 0; } - SMSC_WARNING(HW, "Timed out waiting for MAC not BUSY. " - "MAC_CSR_CMD: 0x%08X", val); + SMSC_WARN(pdata, hw, "Timed out waiting for MAC not BUSY. " + "MAC_CSR_CMD: 0x%08X", val); return -EIO; } @@ -262,7 +384,7 @@ static u32 smsc911x_mac_read(struct smsc911x_data *pdata, unsigned int offset) temp = smsc911x_reg_read(pdata, MAC_CSR_CMD); if (unlikely(temp & MAC_CSR_CMD_CSR_BUSY_)) { - SMSC_WARNING(HW, "MAC busy at entry"); + SMSC_WARN(pdata, hw, "MAC busy at entry"); return 0xFFFFFFFF; } @@ -277,7 +399,7 @@ static u32 smsc911x_mac_read(struct smsc911x_data *pdata, unsigned int offset) if (likely(smsc911x_mac_complete(pdata) == 0)) return smsc911x_reg_read(pdata, MAC_CSR_DATA); - SMSC_WARNING(HW, "MAC busy after read"); + SMSC_WARN(pdata, hw, "MAC busy after read"); return 0xFFFFFFFF; } @@ -291,8 +413,8 @@ static void smsc911x_mac_write(struct smsc911x_data *pdata, temp = smsc911x_reg_read(pdata, MAC_CSR_CMD); if (unlikely(temp & MAC_CSR_CMD_CSR_BUSY_)) { - SMSC_WARNING(HW, - "smsc911x_mac_write failed, MAC busy at entry"); + SMSC_WARN(pdata, hw, + "smsc911x_mac_write failed, MAC busy at entry"); return; } @@ -310,8 +432,7 @@ static void smsc911x_mac_write(struct smsc911x_data *pdata, if (likely(smsc911x_mac_complete(pdata) == 0)) return; - SMSC_WARNING(HW, - "smsc911x_mac_write failed, MAC busy after write"); + SMSC_WARN(pdata, hw, "smsc911x_mac_write failed, MAC busy after write"); } /* Get a phy register */ @@ -326,8 +447,7 @@ static int smsc911x_mii_read(struct mii_bus *bus, int phyaddr, int regidx) /* Confirm MII not busy */ if (unlikely(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) { - SMSC_WARNING(HW, - "MII is busy in smsc911x_mii_read???"); + SMSC_WARN(pdata, hw, "MII is busy in smsc911x_mii_read???"); reg = -EIO; goto out; } @@ -343,7 +463,7 @@ static int smsc911x_mii_read(struct mii_bus *bus, int phyaddr, int regidx) goto out; } - SMSC_WARNING(HW, "Timed out waiting for MII read to finish"); + SMSC_WARN(pdata, hw, "Timed out waiting for MII read to finish"); reg = -EIO; out: @@ -364,8 +484,7 @@ static int smsc911x_mii_write(struct mii_bus *bus, int phyaddr, int regidx, /* Confirm MII not busy */ if (unlikely(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) { - SMSC_WARNING(HW, - "MII is busy in smsc911x_mii_write???"); + SMSC_WARN(pdata, hw, "MII is busy in smsc911x_mii_write???"); reg = -EIO; goto out; } @@ -385,7 +504,7 @@ static int smsc911x_mii_write(struct mii_bus *bus, int phyaddr, int regidx, goto out; } - SMSC_WARNING(HW, "Timed out waiting for MII write to finish"); + SMSC_WARN(pdata, hw, "Timed out waiting for MII write to finish"); reg = -EIO; out: @@ -426,18 +545,20 @@ static void smsc911x_phy_initialise_external(struct smsc911x_data *pdata) unsigned int hwcfg = smsc911x_reg_read(pdata, HW_CFG); if (pdata->config.flags & SMSC911X_FORCE_INTERNAL_PHY) { - SMSC_TRACE(HW, "Forcing internal PHY"); + SMSC_TRACE(pdata, hw, "Forcing internal PHY"); pdata->using_extphy = 0; } else if (pdata->config.flags & SMSC911X_FORCE_EXTERNAL_PHY) { - SMSC_TRACE(HW, "Forcing external PHY"); + SMSC_TRACE(pdata, hw, "Forcing external PHY"); smsc911x_phy_enable_external(pdata); pdata->using_extphy = 1; } else if (hwcfg & HW_CFG_EXT_PHY_DET_) { - SMSC_TRACE(HW, "HW_CFG EXT_PHY_DET set, using external PHY"); + SMSC_TRACE(pdata, hw, + "HW_CFG EXT_PHY_DET set, using external PHY"); smsc911x_phy_enable_external(pdata); pdata->using_extphy = 1; } else { - SMSC_TRACE(HW, "HW_CFG EXT_PHY_DET clear, using internal PHY"); + SMSC_TRACE(pdata, hw, + "HW_CFG EXT_PHY_DET clear, using internal PHY"); pdata->using_extphy = 0; } } @@ -499,7 +620,7 @@ static int smsc911x_phy_check_loopbackpkt(struct smsc911x_data *pdata) wrsz += (u32)((ulong)pdata->loopback_tx_pkt & 0x3); wrsz >>= 2; - smsc911x_tx_writefifo(pdata, (unsigned int *)bufp, wrsz); + pdata->ops->tx_writefifo(pdata, (unsigned int *)bufp, wrsz); /* Wait till transmit is done */ i = 60; @@ -509,13 +630,13 @@ static int smsc911x_phy_check_loopbackpkt(struct smsc911x_data *pdata) } while ((i--) && (!status)); if (!status) { - SMSC_WARNING(HW, "Failed to transmit " - "during loopback test"); + SMSC_WARN(pdata, hw, + "Failed to transmit during loopback test"); continue; } if (status & TX_STS_ES_) { - SMSC_WARNING(HW, "Transmit encountered " - "errors during loopback test"); + SMSC_WARN(pdata, hw, + "Transmit encountered errors during loopback test"); continue; } @@ -527,13 +648,13 @@ static int smsc911x_phy_check_loopbackpkt(struct smsc911x_data *pdata) } while ((i--) && (!status)); if (!status) { - SMSC_WARNING(HW, - "Failed to receive during loopback test"); + SMSC_WARN(pdata, hw, + "Failed to receive during loopback test"); continue; } if (status & RX_STS_ES_) { - SMSC_WARNING(HW, "Receive encountered " - "errors during loopback test"); + SMSC_WARN(pdata, hw, + "Receive encountered errors during loopback test"); continue; } @@ -543,12 +664,12 @@ static int smsc911x_phy_check_loopbackpkt(struct smsc911x_data *pdata) rdsz += (u32)((ulong)pdata->loopback_rx_pkt & 0x3); rdsz >>= 2; - smsc911x_rx_readfifo(pdata, (unsigned int *)bufp, rdsz); + pdata->ops->rx_readfifo(pdata, (unsigned int *)bufp, rdsz); if (pktlength != (MIN_PACKET_SIZE + 4)) { - SMSC_WARNING(HW, "Unexpected packet size " - "during loop back test, size=%d, will retry", - pktlength); + SMSC_WARN(pdata, hw, "Unexpected packet size " + "during loop back test, size=%d, will retry", + pktlength); } else { unsigned int j; int mismatch = 0; @@ -560,12 +681,12 @@ static int smsc911x_phy_check_loopbackpkt(struct smsc911x_data *pdata) } } if (!mismatch) { - SMSC_TRACE(HW, "Successfully verified " + SMSC_TRACE(pdata, hw, "Successfully verified " "loopback packet"); return 0; } else { - SMSC_WARNING(HW, "Data mismatch " - "during loop back test, will retry"); + SMSC_WARN(pdata, hw, "Data mismatch " + "during loop back test, will retry"); } } } @@ -582,7 +703,7 @@ static int smsc911x_phy_reset(struct smsc911x_data *pdata) BUG_ON(!phy_dev); BUG_ON(!phy_dev->bus); - SMSC_TRACE(HW, "Performing PHY BCR Reset"); + SMSC_TRACE(pdata, hw, "Performing PHY BCR Reset"); smsc911x_mii_write(phy_dev->bus, phy_dev->addr, MII_BMCR, BMCR_RESET); do { msleep(1); @@ -591,7 +712,7 @@ static int smsc911x_phy_reset(struct smsc911x_data *pdata) } while ((i--) && (temp & BMCR_RESET)); if (temp & BMCR_RESET) { - SMSC_WARNING(HW, "PHY reset failed to complete."); + SMSC_WARN(pdata, hw, "PHY reset failed to complete"); return -EIO; } /* Extra delay required because the phy may not be completed with @@ -695,11 +816,11 @@ static void smsc911x_phy_update_flowcontrol(struct smsc911x_data *pdata) else afc &= ~0xF; - SMSC_TRACE(HW, "rx pause %s, tx pause %s", - (cap & FLOW_CTRL_RX ? "enabled" : "disabled"), - (cap & FLOW_CTRL_TX ? "enabled" : "disabled")); + SMSC_TRACE(pdata, hw, "rx pause %s, tx pause %s", + (cap & FLOW_CTRL_RX ? "enabled" : "disabled"), + (cap & FLOW_CTRL_TX ? "enabled" : "disabled")); } else { - SMSC_TRACE(HW, "half duplex"); + SMSC_TRACE(pdata, hw, "half duplex"); flow = 0; afc |= 0xF; } @@ -722,17 +843,17 @@ static void smsc911x_phy_adjust_link(struct net_device *dev) if (phy_dev->duplex != pdata->last_duplex) { unsigned int mac_cr; - SMSC_TRACE(HW, "duplex state has changed"); + SMSC_TRACE(pdata, hw, "duplex state has changed"); spin_lock_irqsave(&pdata->mac_lock, flags); mac_cr = smsc911x_mac_read(pdata, MAC_CR); if (phy_dev->duplex) { - SMSC_TRACE(HW, - "configuring for full duplex mode"); + SMSC_TRACE(pdata, hw, + "configuring for full duplex mode"); mac_cr |= MAC_CR_FDPX_; } else { - SMSC_TRACE(HW, - "configuring for half duplex mode"); + SMSC_TRACE(pdata, hw, + "configuring for half duplex mode"); mac_cr &= ~MAC_CR_FDPX_; } smsc911x_mac_write(pdata, MAC_CR, mac_cr); @@ -744,9 +865,9 @@ static void smsc911x_phy_adjust_link(struct net_device *dev) carrier = netif_carrier_ok(dev); if (carrier != pdata->last_carrier) { - SMSC_TRACE(HW, "carrier state has changed"); + SMSC_TRACE(pdata, hw, "carrier state has changed"); if (carrier) { - SMSC_TRACE(HW, "configuring for carrier OK"); + SMSC_TRACE(pdata, hw, "configuring for carrier OK"); if ((pdata->gpio_orig_setting & GPIO_CFG_LED1_EN_) && (!pdata->using_extphy)) { /* Restore original GPIO configuration */ @@ -755,7 +876,7 @@ static void smsc911x_phy_adjust_link(struct net_device *dev) pdata->gpio_setting); } } else { - SMSC_TRACE(HW, "configuring for no carrier"); + SMSC_TRACE(pdata, hw, "configuring for no carrier"); /* Check global setting that LED1 * usage is 10/100 indicator */ pdata->gpio_setting = smsc911x_reg_read(pdata, @@ -787,25 +908,25 @@ static int smsc911x_mii_probe(struct net_device *dev) /* find the first phy */ phydev = phy_find_first(pdata->mii_bus); if (!phydev) { - pr_err("%s: no PHY found\n", dev->name); + netdev_err(dev, "no PHY found\n"); return -ENODEV; } - SMSC_TRACE(PROBE, "PHY: addr %d, phy_id 0x%08X", - phydev->addr, phydev->phy_id); + SMSC_TRACE(pdata, probe, "PHY: addr %d, phy_id 0x%08X", + phydev->addr, phydev->phy_id); ret = phy_connect_direct(dev, phydev, &smsc911x_phy_adjust_link, 0, pdata->config.phy_interface); if (ret) { - pr_err("%s: Could not attach to PHY\n", dev->name); + netdev_err(dev, "Could not attach to PHY\n"); return ret; } - pr_info("%s: attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n", - dev->name, phydev->drv->name, - dev_name(&phydev->dev), phydev->irq); + netdev_info(dev, + "attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n", + phydev->drv->name, dev_name(&phydev->dev), phydev->irq); /* mask with MAC supported features */ phydev->supported &= (PHY_BASIC_FEATURES | SUPPORTED_Pause | @@ -818,13 +939,13 @@ static int smsc911x_mii_probe(struct net_device *dev) #ifdef USE_PHY_WORK_AROUND if (smsc911x_phy_loopbacktest(dev) < 0) { - SMSC_WARNING(HW, "Failed Loop Back Test"); + SMSC_WARN(pdata, hw, "Failed Loop Back Test"); return -ENODEV; } - SMSC_TRACE(HW, "Passed Loop Back Test"); + SMSC_TRACE(pdata, hw, "Passed Loop Back Test"); #endif /* USE_PHY_WORK_AROUND */ - SMSC_TRACE(HW, "phy initialised successfully"); + SMSC_TRACE(pdata, hw, "phy initialised successfully"); return 0; } @@ -860,8 +981,8 @@ static int __devinit smsc911x_mii_init(struct platform_device *pdev, smsc911x_phy_initialise_external(pdata); break; default: - SMSC_TRACE(HW, "External PHY is not supported, " - "using internal PHY"); + SMSC_TRACE(pdata, hw, "External PHY is not supported, " + "using internal PHY"); pdata->using_extphy = 0; break; } @@ -872,12 +993,12 @@ static int __devinit smsc911x_mii_init(struct platform_device *pdev, } if (mdiobus_register(pdata->mii_bus)) { - SMSC_WARNING(PROBE, "Error registering mii bus"); + SMSC_WARN(pdata, probe, "Error registering mii bus"); goto err_out_free_bus_2; } if (smsc911x_mii_probe(dev) < 0) { - SMSC_WARNING(PROBE, "Error registering mii bus"); + SMSC_WARN(pdata, probe, "Error registering mii bus"); goto err_out_unregister_bus_3; } @@ -913,8 +1034,7 @@ static void smsc911x_tx_update_txcounters(struct net_device *dev) * does not reference a hardware defined reserved bit * but rather a driver defined one. */ - SMSC_WARNING(HW, - "Packet tag reserved bit is high"); + SMSC_WARN(pdata, hw, "Packet tag reserved bit is high"); } else { if (unlikely(tx_stat & TX_STS_ES_)) { dev->stats.tx_errors++; @@ -977,8 +1097,8 @@ smsc911x_rx_fastforward(struct smsc911x_data *pdata, unsigned int pktbytes) } while ((val & RX_DP_CTRL_RX_FFWD_) && --timeout); if (unlikely(timeout == 0)) - SMSC_WARNING(HW, "Timed out waiting for " - "RX FFWD to finish, RX_DP_CTRL: 0x%08X", val); + SMSC_WARN(pdata, hw, "Timed out waiting for " + "RX FFWD to finish, RX_DP_CTRL: 0x%08X", val); } else { unsigned int temp; while (pktwords--) @@ -1021,8 +1141,8 @@ static int smsc911x_poll(struct napi_struct *napi, int budget) smsc911x_rx_counterrors(dev, rxstat); if (unlikely(rxstat & RX_STS_ES_)) { - SMSC_WARNING(RX_ERR, - "Discarding packet with error bit set"); + SMSC_WARN(pdata, rx_err, + "Discarding packet with error bit set"); /* Packet has an error, discard it and continue with * the next */ smsc911x_rx_fastforward(pdata, pktwords); @@ -1032,8 +1152,8 @@ static int smsc911x_poll(struct napi_struct *napi, int budget) skb = netdev_alloc_skb(dev, pktlength + NET_IP_ALIGN); if (unlikely(!skb)) { - SMSC_WARNING(RX_ERR, - "Unable to allocate skb for rx packet"); + SMSC_WARN(pdata, rx_err, + "Unable to allocate skb for rx packet"); /* Drop the packet and stop this polling iteration */ smsc911x_rx_fastforward(pdata, pktwords); dev->stats.rx_dropped++; @@ -1046,8 +1166,8 @@ static int smsc911x_poll(struct napi_struct *napi, int budget) /* Align IP on 16B boundary */ skb_reserve(skb, NET_IP_ALIGN); skb_put(skb, pktlength - 4); - smsc911x_rx_readfifo(pdata, (unsigned int *)skb->head, - pktwords); + pdata->ops->rx_readfifo(pdata, + (unsigned int *)skb->head, pktwords); skb->protocol = eth_type_trans(skb, dev); skb_checksum_none_assert(skb); netif_receive_skb(skb); @@ -1083,8 +1203,8 @@ static void smsc911x_rx_multicast_update(struct smsc911x_data *pdata) smsc911x_mac_write(pdata, MAC_CR, mac_cr); smsc911x_mac_write(pdata, HASHH, pdata->hashhi); smsc911x_mac_write(pdata, HASHL, pdata->hashlo); - SMSC_TRACE(HW, "maccr 0x%08X, HASHH 0x%08X, HASHL 0x%08X", - mac_cr, pdata->hashhi, pdata->hashlo); + SMSC_TRACE(pdata, hw, "maccr 0x%08X, HASHH 0x%08X, HASHL 0x%08X", + mac_cr, pdata->hashhi, pdata->hashlo); } static void smsc911x_rx_multicast_update_workaround(struct smsc911x_data *pdata) @@ -1102,7 +1222,7 @@ static void smsc911x_rx_multicast_update_workaround(struct smsc911x_data *pdata) /* Check Rx has stopped */ if (smsc911x_mac_read(pdata, MAC_CR) & MAC_CR_RXEN_) - SMSC_WARNING(DRV, "Rx not stopped"); + SMSC_WARN(pdata, drv, "Rx not stopped"); /* Perform the update - safe to do now Rx has stopped */ smsc911x_rx_multicast_update(pdata); @@ -1131,7 +1251,7 @@ static int smsc911x_soft_reset(struct smsc911x_data *pdata) } while ((--timeout) && (temp & HW_CFG_SRST_)); if (unlikely(temp & HW_CFG_SRST_)) { - SMSC_WARNING(DRV, "Failed to complete reset"); + SMSC_WARN(pdata, drv, "Failed to complete reset"); return -EIO; } return 0; @@ -1160,18 +1280,18 @@ static int smsc911x_open(struct net_device *dev) /* if the phy is not yet registered, retry later*/ if (!pdata->phy_dev) { - SMSC_WARNING(HW, "phy_dev is NULL"); + SMSC_WARN(pdata, hw, "phy_dev is NULL"); return -EAGAIN; } if (!is_valid_ether_addr(dev->dev_addr)) { - SMSC_WARNING(HW, "dev_addr is not a valid MAC address"); + SMSC_WARN(pdata, hw, "dev_addr is not a valid MAC address"); return -EADDRNOTAVAIL; } /* Reset the LAN911x */ if (smsc911x_soft_reset(pdata)) { - SMSC_WARNING(HW, "soft reset failed"); + SMSC_WARN(pdata, hw, "soft reset failed"); return -EIO; } @@ -1191,8 +1311,8 @@ static int smsc911x_open(struct net_device *dev) } if (unlikely(timeout == 0)) - SMSC_WARNING(IFUP, - "Timed out waiting for EEPROM busy bit to clear"); + SMSC_WARN(pdata, ifup, + "Timed out waiting for EEPROM busy bit to clear"); smsc911x_reg_write(pdata, GPIO_CFG, 0x70070000); @@ -1210,22 +1330,22 @@ static int smsc911x_open(struct net_device *dev) intcfg = ((10 << 24) | INT_CFG_IRQ_EN_); if (pdata->config.irq_polarity) { - SMSC_TRACE(IFUP, "irq polarity: active high"); + SMSC_TRACE(pdata, ifup, "irq polarity: active high"); intcfg |= INT_CFG_IRQ_POL_; } else { - SMSC_TRACE(IFUP, "irq polarity: active low"); + SMSC_TRACE(pdata, ifup, "irq polarity: active low"); } if (pdata->config.irq_type) { - SMSC_TRACE(IFUP, "irq type: push-pull"); + SMSC_TRACE(pdata, ifup, "irq type: push-pull"); intcfg |= INT_CFG_IRQ_TYPE_; } else { - SMSC_TRACE(IFUP, "irq type: open drain"); + SMSC_TRACE(pdata, ifup, "irq type: open drain"); } smsc911x_reg_write(pdata, INT_CFG, intcfg); - SMSC_TRACE(IFUP, "Testing irq handler using IRQ %d", dev->irq); + SMSC_TRACE(pdata, ifup, "Testing irq handler using IRQ %d", dev->irq); pdata->software_irq_signal = 0; smp_wmb(); @@ -1241,14 +1361,15 @@ static int smsc911x_open(struct net_device *dev) } if (!pdata->software_irq_signal) { - dev_warn(&dev->dev, "ISR failed signaling test (IRQ %d)\n", - dev->irq); + netdev_warn(dev, "ISR failed signaling test (IRQ %d)\n", + dev->irq); return -ENODEV; } - SMSC_TRACE(IFUP, "IRQ handler passed test using IRQ %d", dev->irq); + SMSC_TRACE(pdata, ifup, "IRQ handler passed test using IRQ %d", + dev->irq); - dev_info(&dev->dev, "SMSC911x/921x identified at %#08lx, IRQ: %d\n", - (unsigned long)pdata->ioaddr, dev->irq); + netdev_info(dev, "SMSC911x/921x identified at %#08lx, IRQ: %d\n", + (unsigned long)pdata->ioaddr, dev->irq); /* Reset the last known duplex and carrier */ pdata->last_duplex = -1; @@ -1313,7 +1434,7 @@ static int smsc911x_stop(struct net_device *dev) if (pdata->phy_dev) phy_stop(pdata->phy_dev); - SMSC_TRACE(IFDOWN, "Interface stopped"); + SMSC_TRACE(pdata, ifdown, "Interface stopped"); return 0; } @@ -1331,8 +1452,8 @@ static int smsc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) freespace = smsc911x_reg_read(pdata, TX_FIFO_INF) & TX_FIFO_INF_TDFREE_; if (unlikely(freespace < TX_FIFO_LOW_THRESHOLD)) - SMSC_WARNING(TX_ERR, - "Tx data fifo low, space available: %d", freespace); + SMSC_WARN(pdata, tx_err, + "Tx data fifo low, space available: %d", freespace); /* Word alignment adjustment */ tx_cmd_a = (u32)((ulong)skb->data & 0x03) << 16; @@ -1350,7 +1471,7 @@ static int smsc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) wrsz += (u32)((ulong)skb->data & 0x3); wrsz >>= 2; - smsc911x_tx_writefifo(pdata, (unsigned int *)bufp, wrsz); + pdata->ops->tx_writefifo(pdata, (unsigned int *)bufp, wrsz); freespace -= (skb->len + 32); dev_kfree_skb(skb); @@ -1432,7 +1553,7 @@ static void smsc911x_set_multicast_list(struct net_device *dev) * receiving data */ if (!pdata->multicast_update_pending) { unsigned int temp; - SMSC_TRACE(HW, "scheduling mcast update"); + SMSC_TRACE(pdata, hw, "scheduling mcast update"); pdata->multicast_update_pending = 1; /* Request the hardware to stop, then perform the @@ -1474,7 +1595,7 @@ static irqreturn_t smsc911x_irqhandler(int irq, void *dev_id) if (unlikely(intsts & inten & INT_STS_RXSTOP_INT_)) { /* Called when there is a multicast update scheduled and * it is now safe to complete the update */ - SMSC_TRACE(INTR, "RX Stop interrupt"); + SMSC_TRACE(pdata, intr, "RX Stop interrupt"); smsc911x_reg_write(pdata, INT_STS, INT_STS_RXSTOP_INT_); if (pdata->multicast_update_pending) smsc911x_rx_multicast_update_workaround(pdata); @@ -1491,7 +1612,7 @@ static irqreturn_t smsc911x_irqhandler(int irq, void *dev_id) } if (unlikely(intsts & inten & INT_STS_RXE_)) { - SMSC_TRACE(INTR, "RX Error interrupt"); + SMSC_TRACE(pdata, intr, "RX Error interrupt"); smsc911x_reg_write(pdata, INT_STS, INT_STS_RXE_); serviced = IRQ_HANDLED; } @@ -1505,8 +1626,7 @@ static irqreturn_t smsc911x_irqhandler(int irq, void *dev_id) /* Schedule a NAPI poll */ __napi_schedule(&pdata->napi); } else { - SMSC_WARNING(RX_ERR, - "napi_schedule_prep failed"); + SMSC_WARN(pdata, rx_err, "napi_schedule_prep failed"); } serviced = IRQ_HANDLED; } @@ -1543,7 +1663,7 @@ static int smsc911x_set_mac_address(struct net_device *dev, void *p) smsc911x_set_hw_mac_address(pdata, dev->dev_addr); spin_unlock_irq(&pdata->mac_lock); - dev_info(&dev->dev, "MAC Address: %pM\n", dev->dev_addr); + netdev_info(dev, "MAC Address: %pM\n", dev->dev_addr); return 0; } @@ -1649,9 +1769,9 @@ static int smsc911x_eeprom_send_cmd(struct smsc911x_data *pdata, u32 op) int timeout = 100; u32 e2cmd; - SMSC_TRACE(DRV, "op 0x%08x", op); + SMSC_TRACE(pdata, drv, "op 0x%08x", op); if (smsc911x_reg_read(pdata, E2P_CMD) & E2P_CMD_EPC_BUSY_) { - SMSC_WARNING(DRV, "Busy at start"); + SMSC_WARN(pdata, drv, "Busy at start"); return -EBUSY; } @@ -1664,12 +1784,12 @@ static int smsc911x_eeprom_send_cmd(struct smsc911x_data *pdata, u32 op) } while ((e2cmd & E2P_CMD_EPC_BUSY_) && (--timeout)); if (!timeout) { - SMSC_TRACE(DRV, "TIMED OUT"); + SMSC_TRACE(pdata, drv, "TIMED OUT"); return -EAGAIN; } if (e2cmd & E2P_CMD_EPC_TIMEOUT_) { - SMSC_TRACE(DRV, "Error occurred during eeprom operation"); + SMSC_TRACE(pdata, drv, "Error occurred during eeprom operation"); return -EINVAL; } @@ -1682,7 +1802,7 @@ static int smsc911x_eeprom_read_location(struct smsc911x_data *pdata, u32 op = E2P_CMD_EPC_CMD_READ_ | address; int ret; - SMSC_TRACE(DRV, "address 0x%x", address); + SMSC_TRACE(pdata, drv, "address 0x%x", address); ret = smsc911x_eeprom_send_cmd(pdata, op); if (!ret) @@ -1698,7 +1818,7 @@ static int smsc911x_eeprom_write_location(struct smsc911x_data *pdata, u32 temp; int ret; - SMSC_TRACE(DRV, "address 0x%x, data 0x%x", address, data); + SMSC_TRACE(pdata, drv, "address 0x%x, data 0x%x", address, data); ret = smsc911x_eeprom_send_cmd(pdata, op); if (!ret) { @@ -1811,26 +1931,26 @@ static int __devinit smsc911x_init(struct net_device *dev) struct smsc911x_data *pdata = netdev_priv(dev); unsigned int byte_test; - SMSC_TRACE(PROBE, "Driver Parameters:"); - SMSC_TRACE(PROBE, "LAN base: 0x%08lX", - (unsigned long)pdata->ioaddr); - SMSC_TRACE(PROBE, "IRQ: %d", dev->irq); - SMSC_TRACE(PROBE, "PHY will be autodetected."); + SMSC_TRACE(pdata, probe, "Driver Parameters:"); + SMSC_TRACE(pdata, probe, "LAN base: 0x%08lX", + (unsigned long)pdata->ioaddr); + SMSC_TRACE(pdata, probe, "IRQ: %d", dev->irq); + SMSC_TRACE(pdata, probe, "PHY will be autodetected."); spin_lock_init(&pdata->dev_lock); spin_lock_init(&pdata->mac_lock); if (pdata->ioaddr == 0) { - SMSC_WARNING(PROBE, "pdata->ioaddr: 0x00000000"); + SMSC_WARN(pdata, probe, "pdata->ioaddr: 0x00000000"); return -ENODEV; } /* Check byte ordering */ byte_test = smsc911x_reg_read(pdata, BYTE_TEST); - SMSC_TRACE(PROBE, "BYTE_TEST: 0x%08X", byte_test); + SMSC_TRACE(pdata, probe, "BYTE_TEST: 0x%08X", byte_test); if (byte_test == 0x43218765) { - SMSC_TRACE(PROBE, "BYTE_TEST looks swapped, " - "applying WORD_SWAP"); + SMSC_TRACE(pdata, probe, "BYTE_TEST looks swapped, " + "applying WORD_SWAP"); smsc911x_reg_write(pdata, WORD_SWAP, 0xffffffff); /* 1 dummy read of BYTE_TEST is needed after a write to @@ -1841,12 +1961,13 @@ static int __devinit smsc911x_init(struct net_device *dev) } if (byte_test != 0x87654321) { - SMSC_WARNING(DRV, "BYTE_TEST: 0x%08X", byte_test); + SMSC_WARN(pdata, drv, "BYTE_TEST: 0x%08X", byte_test); if (((byte_test >> 16) & 0xFFFF) == (byte_test & 0xFFFF)) { - SMSC_WARNING(PROBE, - "top 16 bits equal to bottom 16 bits"); - SMSC_TRACE(PROBE, "This may mean the chip is set " - "for 32 bit while the bus is reading 16 bit"); + SMSC_WARN(pdata, probe, + "top 16 bits equal to bottom 16 bits"); + SMSC_TRACE(pdata, probe, + "This may mean the chip is set " + "for 32 bit while the bus is reading 16 bit"); } return -ENODEV; } @@ -1881,17 +2002,18 @@ static int __devinit smsc911x_init(struct net_device *dev) break; default: - SMSC_WARNING(PROBE, "LAN911x not identified, idrev: 0x%08X", - pdata->idrev); + SMSC_WARN(pdata, probe, "LAN911x not identified, idrev: 0x%08X", + pdata->idrev); return -ENODEV; } - SMSC_TRACE(PROBE, "LAN911x identified, idrev: 0x%08X, generation: %d", - pdata->idrev, pdata->generation); + SMSC_TRACE(pdata, probe, + "LAN911x identified, idrev: 0x%08X, generation: %d", + pdata->idrev, pdata->generation); if (pdata->generation == 0) - SMSC_WARNING(PROBE, - "This driver is not intended for this chip revision"); + SMSC_WARN(pdata, probe, + "This driver is not intended for this chip revision"); /* workaround for platforms without an eeprom, where the mac address * is stored elsewhere and set by the bootloader. This saves the @@ -1931,7 +2053,7 @@ static int __devexit smsc911x_drv_remove(struct platform_device *pdev) BUG_ON(!pdata->ioaddr); BUG_ON(!pdata->phy_dev); - SMSC_TRACE(IFDOWN, "Stopping driver."); + SMSC_TRACE(pdata, ifdown, "Stopping driver"); phy_disconnect(pdata->phy_dev); pdata->phy_dev = NULL; @@ -1955,6 +2077,22 @@ static int __devexit smsc911x_drv_remove(struct platform_device *pdev) return 0; } +/* standard register acces */ +static const struct smsc911x_ops standard_smsc911x_ops = { + .reg_read = __smsc911x_reg_read, + .reg_write = __smsc911x_reg_write, + .rx_readfifo = smsc911x_rx_readfifo, + .tx_writefifo = smsc911x_tx_writefifo, +}; + +/* shifted register access */ +static const struct smsc911x_ops shifted_smsc911x_ops = { + .reg_read = __smsc911x_reg_read_shift, + .reg_write = __smsc911x_reg_write_shift, + .rx_readfifo = smsc911x_rx_readfifo_shift, + .tx_writefifo = smsc911x_tx_writefifo_shift, +}; + static int __devinit smsc911x_drv_probe(struct platform_device *pdev) { struct net_device *dev; @@ -1965,11 +2103,11 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) int res_size, irq_flags; int retval; - pr_info("%s: Driver version %s.\n", SMSC_CHIPNAME, SMSC_DRV_VERSION); + pr_info("Driver version %s\n", SMSC_DRV_VERSION); /* platform data specifies irq & dynamic bus configuration */ if (!pdev->dev.platform_data) { - pr_warning("%s: platform_data not provided\n", SMSC_CHIPNAME); + pr_warn("platform_data not provided\n"); retval = -ENODEV; goto out_0; } @@ -1979,8 +2117,7 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) if (!res) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { - pr_warning("%s: Could not allocate resource.\n", - SMSC_CHIPNAME); + pr_warn("Could not allocate resource\n"); retval = -ENODEV; goto out_0; } @@ -1988,8 +2125,7 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!irq_res) { - pr_warning("%s: Could not allocate irq resource.\n", - SMSC_CHIPNAME); + pr_warn("Could not allocate irq resource\n"); retval = -ENODEV; goto out_0; } @@ -2001,7 +2137,7 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) dev = alloc_etherdev(sizeof(struct smsc911x_data)); if (!dev) { - pr_warning("%s: Could not allocate device.\n", SMSC_CHIPNAME); + pr_warn("Could not allocate device\n"); retval = -ENOMEM; goto out_release_io_1; } @@ -2021,12 +2157,17 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) pdata->msg_enable = ((1 << debug) - 1); if (pdata->ioaddr == NULL) { - SMSC_WARNING(PROBE, - "Error smsc911x base address invalid"); + SMSC_WARN(pdata, probe, "Error smsc911x base address invalid"); retval = -ENOMEM; goto out_free_netdev_2; } + /* assume standard, non-shifted, access to HW registers */ + pdata->ops = &standard_smsc911x_ops; + /* apply the right access if shifting is needed */ + if (config->shift) + pdata->ops = &shifted_smsc911x_ops; + retval = smsc911x_init(dev); if (retval < 0) goto out_unmap_io_3; @@ -2047,8 +2188,8 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) retval = request_irq(dev->irq, smsc911x_irqhandler, irq_flags | IRQF_SHARED, dev->name, dev); if (retval) { - SMSC_WARNING(PROBE, - "Unable to claim requested irq: %d", dev->irq); + SMSC_WARN(pdata, probe, + "Unable to claim requested irq: %d", dev->irq); goto out_unmap_io_3; } @@ -2056,17 +2197,16 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) retval = register_netdev(dev); if (retval) { - SMSC_WARNING(PROBE, - "Error %i registering device", retval); + SMSC_WARN(pdata, probe, "Error %i registering device", retval); goto out_unset_drvdata_4; } else { - SMSC_TRACE(PROBE, "Network interface: \"%s\"", dev->name); + SMSC_TRACE(pdata, probe, + "Network interface: \"%s\"", dev->name); } retval = smsc911x_mii_init(pdev, dev); if (retval) { - SMSC_WARNING(PROBE, - "Error %i initialising mii", retval); + SMSC_WARN(pdata, probe, "Error %i initialising mii", retval); goto out_unregister_netdev_5; } @@ -2075,10 +2215,12 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) /* Check if mac address has been specified when bringing interface up */ if (is_valid_ether_addr(dev->dev_addr)) { smsc911x_set_hw_mac_address(pdata, dev->dev_addr); - SMSC_TRACE(PROBE, "MAC Address is specified by configuration"); + SMSC_TRACE(pdata, probe, + "MAC Address is specified by configuration"); } else if (is_valid_ether_addr(pdata->config.mac)) { memcpy(dev->dev_addr, pdata->config.mac, 6); - SMSC_TRACE(PROBE, "MAC Address specified by platform data"); + SMSC_TRACE(pdata, probe, + "MAC Address specified by platform data"); } else { /* Try reading mac address from device. if EEPROM is present * it will already have been set */ @@ -2086,20 +2228,20 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) if (is_valid_ether_addr(dev->dev_addr)) { /* eeprom values are valid so use them */ - SMSC_TRACE(PROBE, - "Mac Address is read from LAN911x EEPROM"); + SMSC_TRACE(pdata, probe, + "Mac Address is read from LAN911x EEPROM"); } else { /* eeprom values are invalid, generate random MAC */ random_ether_addr(dev->dev_addr); smsc911x_set_hw_mac_address(pdata, dev->dev_addr); - SMSC_TRACE(PROBE, - "MAC Address is set to random_ether_addr"); + SMSC_TRACE(pdata, probe, + "MAC Address is set to random_ether_addr"); } } spin_unlock_irq(&pdata->mac_lock); - dev_info(&dev->dev, "MAC Address: %pM\n", dev->dev_addr); + netdev_info(dev, "MAC Address: %pM\n", dev->dev_addr); return 0; diff --git a/drivers/net/smsc911x.h b/drivers/net/smsc911x.h index 50f712e99e96..8d67aacf8867 100644 --- a/drivers/net/smsc911x.h +++ b/drivers/net/smsc911x.h @@ -33,25 +33,21 @@ * can be successfully looped back */ #define USE_PHY_WORK_AROUND -#define DPRINTK(nlevel, klevel, fmt, args...) \ - ((void)((NETIF_MSG_##nlevel & pdata->msg_enable) && \ - printk(KERN_##klevel "%s: %s: " fmt "\n", \ - pdata->dev->name, __func__, ## args))) - #if USE_DEBUG >= 1 -#define SMSC_WARNING(nlevel, fmt, args...) \ - DPRINTK(nlevel, WARNING, fmt, ## args) +#define SMSC_WARN(pdata, nlevel, fmt, args...) \ + netif_warn(pdata, nlevel, (pdata)->dev, \ + "%s: " fmt "\n", __func__, ##args) #else -#define SMSC_WARNING(nlevel, fmt, args...) \ - ({ do {} while (0); 0; }) +#define SMSC_WARN(pdata, nlevel, fmt, args...) \ + no_printk(fmt "\n", ##args) #endif #if USE_DEBUG >= 2 -#define SMSC_TRACE(nlevel, fmt, args...) \ - DPRINTK(nlevel, INFO, fmt, ## args) +#define SMSC_TRACE(pdata, nlevel, fmt, args...) \ + netif_info(pdata, nlevel, pdata->dev, fmt "\n", ##args) #else -#define SMSC_TRACE(nlevel, fmt, args...) \ - ({ do {} while (0); 0; }) +#define SMSC_TRACE(pdata, nlevel, fmt, args...) \ + no_printk(fmt "\n", ##args) #endif #ifdef CONFIG_DEBUG_SPINLOCK diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index cb6bcca9d541..949f124e1278 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -994,15 +994,13 @@ spider_net_pass_skb_up(struct spider_net_descr *descr, skb->protocol = eth_type_trans(skb, netdev); /* checksum offload */ - if (card->options.rx_csum) { + skb_checksum_none_assert(skb); + if (netdev->features & NETIF_F_RXCSUM) { if ( ( (data_status & SPIDER_NET_DATA_STATUS_CKSUM_MASK) == SPIDER_NET_DATA_STATUS_CKSUM_MASK) && !(data_error & SPIDER_NET_DATA_ERR_CKSUM_MASK)) skb->ip_summed = CHECKSUM_UNNECESSARY; - else - skb_checksum_none_assert(skb); - } else - skb_checksum_none_assert(skb); + } if (data_status & SPIDER_NET_VLAN_PACKET) { /* further enhancements: HW-accel VLAN @@ -2322,14 +2320,15 @@ spider_net_setup_netdev(struct spider_net_card *card) card->aneg_timer.function = spider_net_link_phy; card->aneg_timer.data = (unsigned long) card; - card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT; - netif_napi_add(netdev, &card->napi, spider_net_poll, SPIDER_NET_NAPI_WEIGHT); spider_net_setup_netdev_ops(netdev); - netdev->features = NETIF_F_IP_CSUM | NETIF_F_LLTX; + netdev->hw_features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM; + if (SPIDER_NET_RX_CSUM_DEFAULT) + netdev->features |= NETIF_F_RXCSUM; + netdev->features |= NETIF_F_IP_CSUM | NETIF_F_LLTX; /* some time: NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | * NETIF_F_HW_VLAN_FILTER */ diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h index 05f74cbdd617..020f64a8fcf7 100644 --- a/drivers/net/spider_net.h +++ b/drivers/net/spider_net.h @@ -429,12 +429,6 @@ struct spider_net_descr_chain { * 701b8000 would be correct, but every packets gets that flag */ #define SPIDER_NET_DESTROY_RX_FLAGS 0x700b8000 -/* this will be bigger some time */ -struct spider_net_options { - int rx_csum; /* for rx: if 0 ip_summed=NONE, - if 1 and hw has verified, ip_summed=UNNECESSARY */ -}; - #define SPIDER_NET_DEFAULT_MSG ( NETIF_MSG_DRV | \ NETIF_MSG_PROBE | \ NETIF_MSG_LINK | \ @@ -487,7 +481,6 @@ struct spider_net_card { /* for ethtool */ int msg_enable; struct spider_net_extra_stats spider_stats; - struct spider_net_options options; /* Must be last item in struct */ struct spider_net_descr darray[0]; diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c index 5bae728c3820..d723fca872ce 100644 --- a/drivers/net/spider_net_ethtool.c +++ b/drivers/net/spider_net_ethtool.c @@ -115,24 +115,6 @@ spider_net_ethtool_nway_reset(struct net_device *netdev) return 0; } -static u32 -spider_net_ethtool_get_rx_csum(struct net_device *netdev) -{ - struct spider_net_card *card = netdev_priv(netdev); - - return card->options.rx_csum; -} - -static int -spider_net_ethtool_set_rx_csum(struct net_device *netdev, u32 n) -{ - struct spider_net_card *card = netdev_priv(netdev); - - card->options.rx_csum = n; - return 0; -} - - static void spider_net_ethtool_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ering) @@ -189,9 +171,6 @@ const struct ethtool_ops spider_net_ethtool_ops = { .set_msglevel = spider_net_ethtool_set_msglevel, .get_link = ethtool_op_get_link, .nway_reset = spider_net_ethtool_nway_reset, - .get_rx_csum = spider_net_ethtool_get_rx_csum, - .set_rx_csum = spider_net_ethtool_set_rx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, .get_ringparam = spider_net_ethtool_get_ringparam, .get_strings = spider_net_get_strings, .get_sset_count = spider_net_get_sset_count, diff --git a/drivers/net/stmmac/dwmac1000_core.c b/drivers/net/stmmac/dwmac1000_core.c index 6ae4c3f4c63c..f20455cbfbbc 100644 --- a/drivers/net/stmmac/dwmac1000_core.c +++ b/drivers/net/stmmac/dwmac1000_core.c @@ -178,10 +178,11 @@ static void dwmac1000_pmt(void __iomem *ioaddr, unsigned long mode) { unsigned int pmt = 0; - if (mode == WAKE_MAGIC) { + if (mode & WAKE_MAGIC) { CHIP_DBG(KERN_DEBUG "GMAC: WOL Magic frame\n"); pmt |= power_down | magic_pkt_en; - } else if (mode == WAKE_UCAST) { + } + if (mode & WAKE_UCAST) { CHIP_DBG(KERN_DEBUG "GMAC: WOL on global unicast\n"); pmt |= global_unicast; } diff --git a/drivers/net/stmmac/stmmac_ethtool.c b/drivers/net/stmmac/stmmac_ethtool.c index fd719edc7f7c..0e61ac8707cb 100644 --- a/drivers/net/stmmac/stmmac_ethtool.c +++ b/drivers/net/stmmac/stmmac_ethtool.c @@ -197,13 +197,6 @@ static void stmmac_ethtool_gregs(struct net_device *dev, } } -static u32 stmmac_ethtool_get_rx_csum(struct net_device *dev) -{ - struct stmmac_priv *priv = netdev_priv(dev); - - return priv->rx_coe; -} - static void stmmac_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) @@ -315,7 +308,7 @@ static void stmmac_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) spin_lock_irq(&priv->lock); if (device_can_wakeup(priv->device)) { - wol->supported = WAKE_MAGIC; + wol->supported = WAKE_MAGIC | WAKE_UCAST; wol->wolopts = priv->wolopts; } spin_unlock_irq(&priv->lock); @@ -324,7 +317,7 @@ static void stmmac_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { struct stmmac_priv *priv = netdev_priv(dev); - u32 support = WAKE_MAGIC; + u32 support = WAKE_MAGIC | WAKE_UCAST; if (!device_can_wakeup(priv->device)) return -EINVAL; @@ -358,11 +351,6 @@ static struct ethtool_ops stmmac_ethtool_ops = { .get_regs = stmmac_ethtool_gregs, .get_regs_len = stmmac_ethtool_get_regs_len, .get_link = ethtool_op_get_link, - .get_rx_csum = stmmac_ethtool_get_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_ipv6_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, .get_pauseparam = stmmac_get_pauseparam, .set_pauseparam = stmmac_set_pauseparam, .get_ethtool_stats = stmmac_get_ethtool_stats, @@ -370,8 +358,6 @@ static struct ethtool_ops stmmac_ethtool_ops = { .get_wol = stmmac_get_wol, .set_wol = stmmac_set_wol, .get_sset_count = stmmac_get_sset_count, - .get_tso = ethtool_op_get_tso, - .set_tso = ethtool_op_set_tso, }; void stmmac_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/stmmac/stmmac_main.c index cc973fc38405..ba9daeccb8af 100644 --- a/drivers/net/stmmac/stmmac_main.c +++ b/drivers/net/stmmac/stmmac_main.c @@ -139,7 +139,6 @@ static const u32 default_msg_level = (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_IFDOWN | NETIF_MSG_TIMER); static irqreturn_t stmmac_interrupt(int irq, void *dev_id); -static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev); /** * stmmac_verify_args - verify the driver parameters. @@ -831,6 +830,7 @@ static int stmmac_open(struct net_device *dev) pr_info("stmmac: Rx Checksum Offload Engine supported\n"); if (priv->plat->tx_coe) pr_info("\tTX Checksum insertion supported\n"); + netdev_update_features(dev); /* Initialise the MMC (if present) to disable all interrupts. */ writel(0xffffffff, priv->ioaddr + MMC_HIGH_INTR_MASK); @@ -934,46 +934,6 @@ static int stmmac_release(struct net_device *dev) return 0; } -/* - * To perform emulated hardware segmentation on skb. - */ -static int stmmac_sw_tso(struct stmmac_priv *priv, struct sk_buff *skb) -{ - struct sk_buff *segs, *curr_skb; - int gso_segs = skb_shinfo(skb)->gso_segs; - - /* Estimate the number of fragments in the worst case */ - if (unlikely(stmmac_tx_avail(priv) < gso_segs)) { - netif_stop_queue(priv->dev); - TX_DBG(KERN_ERR "%s: TSO BUG! Tx Ring full when queue awake\n", - __func__); - if (stmmac_tx_avail(priv) < gso_segs) - return NETDEV_TX_BUSY; - - netif_wake_queue(priv->dev); - } - TX_DBG("\tstmmac_sw_tso: segmenting: skb %p (len %d)\n", - skb, skb->len); - - segs = skb_gso_segment(skb, priv->dev->features & ~NETIF_F_TSO); - if (IS_ERR(segs)) - goto sw_tso_end; - - do { - curr_skb = segs; - segs = segs->next; - TX_DBG("\t\tcurrent skb->len: %d, *curr %p," - "*next %p\n", curr_skb->len, curr_skb, segs); - curr_skb->next = NULL; - stmmac_xmit(curr_skb, priv->dev); - } while (segs); - -sw_tso_end: - dev_kfree_skb(skb); - - return NETDEV_TX_OK; -} - static unsigned int stmmac_handle_jumbo_frames(struct sk_buff *skb, struct net_device *dev, int csum_insertion) @@ -1051,16 +1011,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) !skb_is_gso(skb) ? "isn't" : "is"); #endif - if (unlikely(skb_is_gso(skb))) - return stmmac_sw_tso(priv, skb); - - if (likely((skb->ip_summed == CHECKSUM_PARTIAL))) { - if (unlikely((!priv->plat->tx_coe) || - (priv->no_csum_insertion))) - skb_checksum_help(skb); - else - csum_insertion = 1; - } + csum_insertion = (skb->ip_summed == CHECKSUM_PARTIAL); desc = priv->dma_tx + entry; first = desc; @@ -1380,18 +1331,29 @@ static int stmmac_change_mtu(struct net_device *dev, int new_mtu) return -EINVAL; } + dev->mtu = new_mtu; + netdev_update_features(dev); + + return 0; +} + +static u32 stmmac_fix_features(struct net_device *dev, u32 features) +{ + struct stmmac_priv *priv = netdev_priv(dev); + + if (!priv->rx_coe) + features &= ~NETIF_F_RXCSUM; + if (!priv->plat->tx_coe) + features &= ~NETIF_F_ALL_CSUM; + /* Some GMAC devices have a bugged Jumbo frame support that * needs to have the Tx COE disabled for oversized frames * (due to limited buffer sizes). In this case we disable * the TX csum insertionin the TDES and not use SF. */ - if ((priv->plat->bugged_jumbo) && (priv->dev->mtu > ETH_DATA_LEN)) - priv->no_csum_insertion = 1; - else - priv->no_csum_insertion = 0; + if (priv->plat->bugged_jumbo && (dev->mtu > ETH_DATA_LEN)) + features &= ~NETIF_F_ALL_CSUM; - dev->mtu = new_mtu; - - return 0; + return features; } static irqreturn_t stmmac_interrupt(int irq, void *dev_id) @@ -1471,6 +1433,7 @@ static const struct net_device_ops stmmac_netdev_ops = { .ndo_start_xmit = stmmac_xmit, .ndo_stop = stmmac_release, .ndo_change_mtu = stmmac_change_mtu, + .ndo_fix_features = stmmac_fix_features, .ndo_set_multicast_list = stmmac_multicast_list, .ndo_tx_timeout = stmmac_tx_timeout, .ndo_do_ioctl = stmmac_ioctl, @@ -1501,8 +1464,8 @@ static int stmmac_probe(struct net_device *dev) dev->netdev_ops = &stmmac_netdev_ops; stmmac_set_ethtool_ops(dev); - dev->features |= NETIF_F_SG | NETIF_F_HIGHDMA | - NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + dev->features |= dev->hw_features | NETIF_F_HIGHDMA; dev->watchdog_timeo = msecs_to_jiffies(watchdog); #ifdef STMMAC_VLAN_TAG_USED /* Both mac100 and gmac support receive VLAN tag detection */ diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index d3be735c4719..81b6eb8ed4d7 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -3146,7 +3146,8 @@ static int __devinit gem_init_one(struct pci_dev *pdev, gp->phy_mii.def ? gp->phy_mii.def->name : "no"); /* GEM can do it all... */ - dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_LLTX; + dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM; + dev->features |= dev->hw_features | NETIF_F_RXCSUM | NETIF_F_LLTX; if (pci_using_dac) dev->features |= NETIF_F_HIGHDMA; diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index eb4f59fb01e9..80e907df36b4 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -2788,7 +2788,8 @@ static int __devinit happy_meal_sbus_probe_one(struct platform_device *op, int i dev->ethtool_ops = &hme_ethtool_ops; /* Happy Meal can do it all... */ - dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; + dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM; + dev->features |= dev->hw_features | NETIF_F_RXCSUM; dev->irq = op->archdata.irqs[0]; @@ -3113,7 +3114,8 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, dev->dma = 0; /* Happy Meal can do it all... */ - dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; + dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM; + dev->features |= dev->hw_features | NETIF_F_RXCSUM; #if defined(CONFIG_SBUS) && defined(CONFIG_PCI) /* Hook up PCI register/descriptor accessors. */ diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c index 8564ec5cfb7f..8be71de725e5 100644 --- a/drivers/net/tehuti.c +++ b/drivers/net/tehuti.c @@ -2017,9 +2017,11 @@ bdx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ndev->irq = pdev->irq; ndev->features = NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | - NETIF_F_HW_VLAN_FILTER + NETIF_F_HW_VLAN_FILTER | NETIF_F_RXCSUM /*| NETIF_F_FRAGLIST */ ; + ndev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG | + NETIF_F_TSO | NETIF_F_HW_VLAN_TX; if (pci_using_dac) ndev->features |= NETIF_F_HIGHDMA; @@ -2188,24 +2190,6 @@ bdx_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) } /* - * bdx_get_rx_csum - report whether receive checksums are turned on or off - * @netdev - */ -static u32 bdx_get_rx_csum(struct net_device *netdev) -{ - return 1; /* always on */ -} - -/* - * bdx_get_tx_csum - report whether transmit checksums are turned on or off - * @netdev - */ -static u32 bdx_get_tx_csum(struct net_device *netdev) -{ - return (netdev->features & NETIF_F_IP_CSUM) != 0; -} - -/* * bdx_get_coalesce - get interrupt coalescing parameters * @netdev * @ecoal @@ -2424,10 +2408,6 @@ static void bdx_set_ethtool_ops(struct net_device *netdev) .set_coalesce = bdx_set_coalesce, .get_ringparam = bdx_get_ringparam, .set_ringparam = bdx_set_ringparam, - .get_rx_csum = bdx_get_rx_csum, - .get_tx_csum = bdx_get_tx_csum, - .get_sg = ethtool_op_get_sg, - .get_tso = ethtool_op_get_tso, .get_strings = bdx_get_strings, .get_sset_count = bdx_get_sset_count, .get_ethtool_stats = bdx_get_ethtool_stats, diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index b8c5f35577e4..9915734ac3e9 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -97,14 +97,12 @@ * them in the NIC onboard memory. */ #define TG3_RX_STD_RING_SIZE(tp) \ - ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || \ - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) ? \ - RX_STD_MAX_SIZE_5717 : 512) + ((tp->tg3_flags3 & TG3_FLG3_LRG_PROD_RING_CAP) ? \ + TG3_RX_STD_MAX_SIZE_5717 : TG3_RX_STD_MAX_SIZE_5700) #define TG3_DEF_RX_RING_PENDING 200 #define TG3_RX_JMB_RING_SIZE(tp) \ - ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || \ - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) ? \ - 1024 : 256) + ((tp->tg3_flags3 & TG3_FLG3_LRG_PROD_RING_CAP) ? \ + TG3_RX_JMB_MAX_SIZE_5717 : TG3_RX_JMB_MAX_SIZE_5700) #define TG3_DEF_RX_JUMBO_RING_PENDING 100 #define TG3_RSS_INDIR_TBL_SIZE 128 @@ -167,11 +165,6 @@ #define TG3_RAW_IP_ALIGN 2 -/* number of ETHTOOL_GSTATS u64's */ -#define TG3_NUM_STATS (sizeof(struct tg3_ethtool_stats)/sizeof(u64)) - -#define TG3_NUM_TEST 6 - #define TG3_FW_UPDATE_TIMEOUT_SEC 5 #define FIRMWARE_TG3 "tigon/tg3.bin" @@ -266,6 +259,7 @@ static DEFINE_PCI_DEVICE_TABLE(tg3_pci_tbl) = { {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57791)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57795)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5719)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5720)}, {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)}, {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX)}, {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000)}, @@ -280,7 +274,7 @@ MODULE_DEVICE_TABLE(pci, tg3_pci_tbl); static const struct { const char string[ETH_GSTRING_LEN]; -} ethtool_stats_keys[TG3_NUM_STATS] = { +} ethtool_stats_keys[] = { { "rx_octets" }, { "rx_fragments" }, { "rx_ucast_packets" }, @@ -359,9 +353,12 @@ static const struct { { "nic_tx_threshold_hit" } }; +#define TG3_NUM_STATS ARRAY_SIZE(ethtool_stats_keys) + + static const struct { const char string[ETH_GSTRING_LEN]; -} ethtool_test_keys[TG3_NUM_TEST] = { +} ethtool_test_keys[] = { { "nvram test (online) " }, { "link test (online) " }, { "register test (offline)" }, @@ -370,6 +367,9 @@ static const struct { { "interrupt test (offline)" }, }; +#define TG3_NUM_TEST ARRAY_SIZE(ethtool_test_keys) + + static void tg3_write32(struct tg3 *tp, u32 off, u32 val) { writel(val, tp->regs + off); @@ -1044,8 +1044,7 @@ static int tg3_mdio_init(struct tg3 *tp) u32 reg; struct phy_device *phydev; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) { + if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) { u32 is_serdes; tp->phy_addr = PCI_FUNC(tp->pdev->devfn) + 1; @@ -1623,8 +1622,7 @@ static void tg3_phy_toggle_apd(struct tg3 *tp, bool enable) u32 reg; if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) || - ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) && + ((tp->tg3_flags3 & TG3_FLG3_5717_PLUS) && (tp->phy_flags & TG3_PHYFLG_MII_SERDES))) return; @@ -2047,8 +2045,7 @@ static int tg3_phy_reset(struct tg3 *tp) } } - if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) && + if ((tp->tg3_flags3 & TG3_FLG3_5717_PLUS) && (tp->phy_flags & TG3_PHYFLG_MII_SERDES)) return 0; @@ -2130,7 +2127,8 @@ static void tg3_frob_aux_power(struct tg3 *tp) if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) && + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) && tp->pdev_peer != tp->pdev) { struct net_device *dev_peer; @@ -4394,6 +4392,7 @@ static void tg3_serdes_parallel_detect(struct tg3 *tp) static int tg3_setup_phy(struct tg3 *tp, int force_reset) { + u32 val; int err; if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) @@ -4404,7 +4403,7 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset) err = tg3_setup_copper_phy(tp, force_reset); if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX) { - u32 val, scale; + u32 scale; val = tr32(TG3_CPMU_CLCK_STAT) & CPMU_CLCK_STAT_MAC_CLCK_MASK; if (val == CPMU_CLCK_STAT_MAC_CLCK_62_5) @@ -4419,17 +4418,20 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset) tw32(GRC_MISC_CFG, val); } + val = (2 << TX_LENGTHS_IPG_CRS_SHIFT) | + (6 << TX_LENGTHS_IPG_SHIFT); + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) + val |= tr32(MAC_TX_LENGTHS) & + (TX_LENGTHS_JMB_FRM_LEN_MSK | + TX_LENGTHS_CNT_DWN_VAL_MSK); + if (tp->link_config.active_speed == SPEED_1000 && tp->link_config.active_duplex == DUPLEX_HALF) - tw32(MAC_TX_LENGTHS, - ((2 << TX_LENGTHS_IPG_CRS_SHIFT) | - (6 << TX_LENGTHS_IPG_SHIFT) | - (0xff << TX_LENGTHS_SLOT_TIME_SHIFT))); + tw32(MAC_TX_LENGTHS, val | + (0xff << TX_LENGTHS_SLOT_TIME_SHIFT)); else - tw32(MAC_TX_LENGTHS, - ((2 << TX_LENGTHS_IPG_CRS_SHIFT) | - (6 << TX_LENGTHS_IPG_SHIFT) | - (32 << TX_LENGTHS_SLOT_TIME_SHIFT))); + tw32(MAC_TX_LENGTHS, val | + (32 << TX_LENGTHS_SLOT_TIME_SHIFT)); if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { if (netif_carrier_ok(tp->dev)) { @@ -4441,7 +4443,7 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset) } if (tp->tg3_flags & TG3_FLAG_ASPM_WORKAROUND) { - u32 val = tr32(PCIE_PWR_MGMT_THRESH); + val = tr32(PCIE_PWR_MGMT_THRESH); if (!netif_carrier_ok(tp->dev)) val = (val & ~PCIE_PWR_MGMT_L1_THRESH_MSK) | tp->pwrmgmt_thresh; @@ -4458,6 +4460,123 @@ static inline int tg3_irq_sync(struct tg3 *tp) return tp->irq_sync; } +static inline void tg3_rd32_loop(struct tg3 *tp, u32 *dst, u32 off, u32 len) +{ + int i; + + dst = (u32 *)((u8 *)dst + off); + for (i = 0; i < len; i += sizeof(u32)) + *dst++ = tr32(off + i); +} + +static void tg3_dump_legacy_regs(struct tg3 *tp, u32 *regs) +{ + tg3_rd32_loop(tp, regs, TG3PCI_VENDOR, 0xb0); + tg3_rd32_loop(tp, regs, MAILBOX_INTERRUPT_0, 0x200); + tg3_rd32_loop(tp, regs, MAC_MODE, 0x4f0); + tg3_rd32_loop(tp, regs, SNDDATAI_MODE, 0xe0); + tg3_rd32_loop(tp, regs, SNDDATAC_MODE, 0x04); + tg3_rd32_loop(tp, regs, SNDBDS_MODE, 0x80); + tg3_rd32_loop(tp, regs, SNDBDI_MODE, 0x48); + tg3_rd32_loop(tp, regs, SNDBDC_MODE, 0x04); + tg3_rd32_loop(tp, regs, RCVLPC_MODE, 0x20); + tg3_rd32_loop(tp, regs, RCVLPC_SELLST_BASE, 0x15c); + tg3_rd32_loop(tp, regs, RCVDBDI_MODE, 0x0c); + tg3_rd32_loop(tp, regs, RCVDBDI_JUMBO_BD, 0x3c); + tg3_rd32_loop(tp, regs, RCVDBDI_BD_PROD_IDX_0, 0x44); + tg3_rd32_loop(tp, regs, RCVDCC_MODE, 0x04); + tg3_rd32_loop(tp, regs, RCVBDI_MODE, 0x20); + tg3_rd32_loop(tp, regs, RCVCC_MODE, 0x14); + tg3_rd32_loop(tp, regs, RCVLSC_MODE, 0x08); + tg3_rd32_loop(tp, regs, MBFREE_MODE, 0x08); + tg3_rd32_loop(tp, regs, HOSTCC_MODE, 0x100); + + if (tp->tg3_flags & TG3_FLAG_SUPPORT_MSIX) + tg3_rd32_loop(tp, regs, HOSTCC_RXCOL_TICKS_VEC1, 0x180); + + tg3_rd32_loop(tp, regs, MEMARB_MODE, 0x10); + tg3_rd32_loop(tp, regs, BUFMGR_MODE, 0x58); + tg3_rd32_loop(tp, regs, RDMAC_MODE, 0x08); + tg3_rd32_loop(tp, regs, WDMAC_MODE, 0x08); + tg3_rd32_loop(tp, regs, RX_CPU_MODE, 0x04); + tg3_rd32_loop(tp, regs, RX_CPU_STATE, 0x04); + tg3_rd32_loop(tp, regs, RX_CPU_PGMCTR, 0x04); + tg3_rd32_loop(tp, regs, RX_CPU_HWBKPT, 0x04); + + if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { + tg3_rd32_loop(tp, regs, TX_CPU_MODE, 0x04); + tg3_rd32_loop(tp, regs, TX_CPU_STATE, 0x04); + tg3_rd32_loop(tp, regs, TX_CPU_PGMCTR, 0x04); + } + + tg3_rd32_loop(tp, regs, GRCMBOX_INTERRUPT_0, 0x110); + tg3_rd32_loop(tp, regs, FTQ_RESET, 0x120); + tg3_rd32_loop(tp, regs, MSGINT_MODE, 0x0c); + tg3_rd32_loop(tp, regs, DMAC_MODE, 0x04); + tg3_rd32_loop(tp, regs, GRC_MODE, 0x4c); + + if (tp->tg3_flags & TG3_FLAG_NVRAM) + tg3_rd32_loop(tp, regs, NVRAM_CMD, 0x24); +} + +static void tg3_dump_state(struct tg3 *tp) +{ + int i; + u32 *regs; + + regs = kzalloc(TG3_REG_BLK_SIZE, GFP_ATOMIC); + if (!regs) { + netdev_err(tp->dev, "Failed allocating register dump buffer\n"); + return; + } + + if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) { + /* Read up to but not including private PCI registers */ + for (i = 0; i < TG3_PCIE_TLDLPL_PORT; i += sizeof(u32)) + regs[i / sizeof(u32)] = tr32(i); + } else + tg3_dump_legacy_regs(tp, regs); + + for (i = 0; i < TG3_REG_BLK_SIZE / sizeof(u32); i += 4) { + if (!regs[i + 0] && !regs[i + 1] && + !regs[i + 2] && !regs[i + 3]) + continue; + + netdev_err(tp->dev, "0x%08x: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", + i * 4, + regs[i + 0], regs[i + 1], regs[i + 2], regs[i + 3]); + } + + kfree(regs); + + for (i = 0; i < tp->irq_cnt; i++) { + struct tg3_napi *tnapi = &tp->napi[i]; + + /* SW status block */ + netdev_err(tp->dev, + "%d: Host status block [%08x:%08x:(%04x:%04x:%04x):(%04x:%04x)]\n", + i, + tnapi->hw_status->status, + tnapi->hw_status->status_tag, + tnapi->hw_status->rx_jumbo_consumer, + tnapi->hw_status->rx_consumer, + tnapi->hw_status->rx_mini_consumer, + tnapi->hw_status->idx[0].rx_producer, + tnapi->hw_status->idx[0].tx_consumer); + + netdev_err(tp->dev, + "%d: NAPI info [%08x:%08x:(%04x:%04x:%04x):%04x:(%04x:%04x:%04x:%04x)]\n", + i, + tnapi->last_tag, tnapi->last_irq_tag, + tnapi->tx_prod, tnapi->tx_cons, tnapi->tx_pending, + tnapi->rx_rcb_ptr, + tnapi->prodring.rx_std_prod_idx, + tnapi->prodring.rx_std_cons_idx, + tnapi->prodring.rx_jmb_prod_idx, + tnapi->prodring.rx_jmb_cons_idx); + } +} + /* This is called whenever we suspect that the system chipset is re- * ordering the sequence of MMIO to the tx send mailbox. The symptom * is bogus tx completions. We try to recover by setting the @@ -4815,7 +4934,7 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget) skb = copy_skb; } - if ((tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) && + if ((tp->dev->features & NETIF_F_RXCSUM) && (desc->type_flags & RXD_FLAG_TCPUDP_CSUM) && (((desc->ip_tcp_csum & RXD_TCPCSUM_MASK) >> RXD_TCPCSUM_SHIFT) == 0xffff)) @@ -5141,6 +5260,40 @@ tx_recovery: return work_done; } +static void tg3_process_error(struct tg3 *tp) +{ + u32 val; + bool real_error = false; + + if (tp->tg3_flags & TG3_FLAG_ERROR_PROCESSED) + return; + + /* Check Flow Attention register */ + val = tr32(HOSTCC_FLOW_ATTN); + if (val & ~HOSTCC_FLOW_ATTN_MBUF_LWM) { + netdev_err(tp->dev, "FLOW Attention error. Resetting chip.\n"); + real_error = true; + } + + if (tr32(MSGINT_STATUS) & ~MSGINT_STATUS_MSI_REQ) { + netdev_err(tp->dev, "MSI Status error. Resetting chip.\n"); + real_error = true; + } + + if (tr32(RDMAC_STATUS) || tr32(WDMAC_STATUS)) { + netdev_err(tp->dev, "DMA Status error. Resetting chip.\n"); + real_error = true; + } + + if (!real_error) + return; + + tg3_dump_state(tp); + + tp->tg3_flags |= TG3_FLAG_ERROR_PROCESSED; + schedule_work(&tp->reset_task); +} + static int tg3_poll(struct napi_struct *napi, int budget) { struct tg3_napi *tnapi = container_of(napi, struct tg3_napi, napi); @@ -5149,6 +5302,9 @@ static int tg3_poll(struct napi_struct *napi, int budget) struct tg3_hw_status *sblk = tnapi->hw_status; while (1) { + if (sblk->status & SD_STATUS_ERROR) + tg3_process_error(tp); + tg3_poll_link(tp); work_done = tg3_poll_work(tnapi, work_done, budget); @@ -5515,21 +5671,13 @@ out: tg3_phy_start(tp); } -static void tg3_dump_short_state(struct tg3 *tp) -{ - netdev_err(tp->dev, "DEBUG: MAC_TX_STATUS[%08x] MAC_RX_STATUS[%08x]\n", - tr32(MAC_TX_STATUS), tr32(MAC_RX_STATUS)); - netdev_err(tp->dev, "DEBUG: RDMAC_STATUS[%08x] WDMAC_STATUS[%08x]\n", - tr32(RDMAC_STATUS), tr32(WDMAC_STATUS)); -} - static void tg3_tx_timeout(struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); if (netif_msg_tx_err(tp)) { netdev_err(dev, "transmit timed out, resetting\n"); - tg3_dump_short_state(tp); + tg3_dump_state(tp); } schedule_work(&tp->reset_task); @@ -6126,6 +6274,16 @@ dma_error: return NETDEV_TX_OK; } +static u32 tg3_fix_features(struct net_device *dev, u32 features) +{ + struct tg3 *tp = netdev_priv(dev); + + if (dev->mtu > ETH_DATA_LEN && (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) + features &= ~NETIF_F_ALL_TSO; + + return features; +} + static inline void tg3_set_mtu(struct net_device *dev, struct tg3 *tp, int new_mtu) { @@ -6133,14 +6291,16 @@ static inline void tg3_set_mtu(struct net_device *dev, struct tg3 *tp, if (new_mtu > ETH_DATA_LEN) { if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) { + netdev_update_features(dev); tp->tg3_flags2 &= ~TG3_FLG2_TSO_CAPABLE; - ethtool_op_set_tso(dev, 0); } else { tp->tg3_flags |= TG3_FLAG_JUMBO_RING_ENABLE; } } else { - if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) + if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) { tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE; + netdev_update_features(dev); + } tp->tg3_flags &= ~TG3_FLAG_JUMBO_RING_ENABLE; } } @@ -7097,7 +7257,7 @@ static int tg3_chip_reset(struct tg3 *tp) if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) { /* Force PCIe 1.0a mode */ if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 && - !(tp->tg3_flags3 & TG3_FLG3_5717_PLUS) && + !(tp->tg3_flags3 & TG3_FLG3_57765_PLUS) && tr32(TG3_PCIE_PHY_TSTCTL) == (TG3_PCIE_PHY_TSTCTL_PCIE10 | TG3_PCIE_PHY_TSTCTL_PSCRAM)) tw32(TG3_PCIE_PHY_TSTCTL, TG3_PCIE_PHY_TSTCTL_PSCRAM); @@ -7194,7 +7354,8 @@ static int tg3_chip_reset(struct tg3 *tp) tg3_restore_pci_state(tp); - tp->tg3_flags &= ~TG3_FLAG_CHIP_RESETTING; + tp->tg3_flags &= ~(TG3_FLAG_CHIP_RESETTING | + TG3_FLAG_ERROR_PROCESSED); val = 0; if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) @@ -7250,12 +7411,17 @@ static int tg3_chip_reset(struct tg3 *tp) if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) && tp->pci_chip_rev_id != CHIPREV_ID_5750_A0 && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 && - !(tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) { + !(tp->tg3_flags3 & TG3_FLG3_57765_PLUS)) { val = tr32(0x7c00); tw32(0x7c00, val | (1 << 25)); } + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) { + val = tr32(TG3_CPMU_CLCK_ORIDE); + tw32(TG3_CPMU_CLCK_ORIDE, val & ~CPMU_CLCK_ORIDE_MAC_ORIDE_EN); + } + /* Reprobe ASF enable state. */ tp->tg3_flags &= ~TG3_FLAG_ENABLE_ASF; tp->tg3_flags2 &= ~TG3_FLG2_ASF_NEW_HANDSHAKE; @@ -7673,8 +7839,7 @@ static void tg3_rings_reset(struct tg3 *tp) /* Disable all transmit rings but the first. */ if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE * 16; - else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) + else if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE * 4; else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE * 2; @@ -7688,8 +7853,7 @@ static void tg3_rings_reset(struct tg3 *tp) /* Disable all receive return rings but the first. */ - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) + if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 17; else if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 16; @@ -7960,7 +8124,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) if (err) return err; - if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) { + if (tp->tg3_flags3 & TG3_FLG3_57765_PLUS) { val = tr32(TG3PCI_DMA_RW_CTRL) & ~DMA_RWCTRL_DIS_CACHE_ALIGNMENT; if (tp->pci_chip_rev_id == CHIPREV_ID_57765_A0) @@ -8091,8 +8255,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) ((u64) tpr->rx_std_mapping >> 32)); tw32(RCVDBDI_STD_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW, ((u64) tpr->rx_std_mapping & 0xffffffff)); - if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5719) + if (!(tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) tw32(RCVDBDI_STD_BD + TG3_BDINFO_NIC_ADDR, NIC_SRAM_RX_BUFFER_DESC); @@ -8115,9 +8278,10 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) ((u64) tpr->rx_jmb_mapping >> 32)); tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW, ((u64) tpr->rx_jmb_mapping & 0xffffffff)); + val = TG3_RX_JMB_RING_SIZE(tp) << + BDINFO_FLAGS_MAXLEN_SHIFT; tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_MAXLEN_FLAGS, - (RX_JUMBO_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT) | - BDINFO_FLAGS_USE_EXT_RECV); + val | BDINFO_FLAGS_USE_EXT_RECV); if (!(tp->tg3_flags3 & TG3_FLG3_USE_JUMBO_BDFLAG) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_NIC_ADDR, @@ -8127,17 +8291,17 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) BDINFO_FLAGS_DISABLED); } - if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) { + if (tp->tg3_flags3 & TG3_FLG3_57765_PLUS) { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) - val = RX_STD_MAX_SIZE_5705; + val = TG3_RX_STD_MAX_SIZE_5700; else - val = RX_STD_MAX_SIZE_5717; + val = TG3_RX_STD_MAX_SIZE_5717; val <<= BDINFO_FLAGS_MAXLEN_SHIFT; val |= (TG3_RX_STD_DMA_SZ << 2); } else val = TG3_RX_STD_DMA_SZ << BDINFO_FLAGS_MAXLEN_SHIFT; } else - val = RX_STD_MAX_SIZE_5705 << BDINFO_FLAGS_MAXLEN_SHIFT; + val = TG3_RX_STD_MAX_SIZE_5700 << BDINFO_FLAGS_MAXLEN_SHIFT; tw32(RCVDBDI_STD_BD + TG3_BDINFO_MAXLEN_FLAGS, val); @@ -8148,7 +8312,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tp->rx_jumbo_pending : 0; tw32_rx_mbox(TG3_RX_JMB_PROD_IDX_REG, tpr->rx_jmb_prod_idx); - if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) { + if (tp->tg3_flags3 & TG3_FLG3_57765_PLUS) { tw32(STD_REPLENISH_LWM, 32); tw32(JMB_REPLENISH_LWM, 16); } @@ -8165,10 +8329,16 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) /* The slot time is changed by tg3_setup_phy if we * run at gigabit with half duplex. */ - tw32(MAC_TX_LENGTHS, - (2 << TX_LENGTHS_IPG_CRS_SHIFT) | - (6 << TX_LENGTHS_IPG_SHIFT) | - (32 << TX_LENGTHS_SLOT_TIME_SHIFT)); + val = (2 << TX_LENGTHS_IPG_CRS_SHIFT) | + (6 << TX_LENGTHS_IPG_SHIFT) | + (32 << TX_LENGTHS_SLOT_TIME_SHIFT); + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) + val |= tr32(MAC_TX_LENGTHS) & + (TX_LENGTHS_JMB_FRM_LEN_MSK | + TX_LENGTHS_CNT_DWN_VAL_MSK); + + tw32(MAC_TX_LENGTHS, val); /* Receive rules. */ tw32(MAC_RCV_RULE_CFG, RCV_RULE_CFG_DEFAULT_CLASS); @@ -8215,13 +8385,17 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) rdmac_mode |= RDMAC_MODE_IPV6_LSO_EN; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) + rdmac_mode |= tr32(RDMAC_MODE) & RDMAC_MODE_H2BNC_VLAN_DET; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || - (tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) { + (tp->tg3_flags3 & TG3_FLG3_57765_PLUS)) { val = tr32(TG3_RDMA_RSRVCTRL_REG); - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) { val &= ~(TG3_RDMA_RSRVCTRL_TXMRGN_MASK | TG3_RDMA_RSRVCTRL_FIFO_LWM_MASK | TG3_RDMA_RSRVCTRL_FIFO_HWM_MASK); @@ -8233,7 +8407,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) val | TG3_RDMA_RSRVCTRL_FIFO_OFLW_FIX); } - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) { val = tr32(TG3_LSO_RD_DMA_CRPTEN_CTRL); tw32(TG3_LSO_RD_DMA_CRPTEN_CTRL, val | TG3_LSO_RD_DMA_CRPTEN_CTRL_BLEN_BD_4K | @@ -8421,8 +8596,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(SNDBDC_MODE, SNDBDC_MODE_ENABLE | SNDBDC_MODE_ATTN_ENABLE); tw32(RCVBDI_MODE, RCVBDI_MODE_ENABLE | RCVBDI_MODE_RCB_ATTN_ENAB); val = RCVDBDI_MODE_ENABLE | RCVDBDI_MODE_INV_RING_SZ; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) + if (tp->tg3_flags3 & TG3_FLG3_LRG_PROD_RING_CAP) val |= RCVDBDI_MODE_LRG_RING_SZ; tw32(RCVDBDI_MODE, val); tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE); @@ -8447,9 +8621,17 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) } tp->tx_mode = TX_MODE_ENABLE; + if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) tp->tx_mode |= TX_MODE_MBUF_LOCKUP_FIX; + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) { + val = TX_MODE_JMB_FRM_LEN | TX_MODE_CNT_DN_MODE; + tp->tx_mode &= ~val; + tp->tx_mode |= tr32(MAC_TX_MODE) & val; + } + tw32_f(MAC_TX_MODE, tp->tx_mode); udelay(100); @@ -8839,12 +9021,12 @@ static int tg3_request_irq(struct tg3 *tp, int irq_num) fn = tg3_msi; if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI) fn = tg3_msi_1shot; - flags = IRQF_SAMPLE_RANDOM; + flags = 0; } else { fn = tg3_interrupt; if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) fn = tg3_interrupt_tagged; - flags = IRQF_SHARED | IRQF_SAMPLE_RANDOM; + flags = IRQF_SHARED; } return request_irq(tnapi->irq_vec, fn, flags, name, tnapi); @@ -8868,7 +9050,7 @@ static int tg3_test_interrupt(struct tg3 *tp) * Turn off MSI one shot mode. Otherwise this test has no * observable way to know whether the interrupt was delivered. */ - if ((tp->tg3_flags3 & TG3_FLG3_5717_PLUS) && + if ((tp->tg3_flags3 & TG3_FLG3_57765_PLUS) && (tp->tg3_flags2 & TG3_FLG2_USING_MSI)) { val = tr32(MSGINT_MODE) | MSGINT_MODE_ONE_SHOT_DISABLE; tw32(MSGINT_MODE, val); @@ -8911,7 +9093,7 @@ static int tg3_test_interrupt(struct tg3 *tp) if (intr_ok) { /* Reenable MSI one shot mode. */ - if ((tp->tg3_flags3 & TG3_FLG3_5717_PLUS) && + if ((tp->tg3_flags3 & TG3_FLG3_57765_PLUS) && (tp->tg3_flags2 & TG3_FLG2_USING_MSI)) { val = tr32(MSGINT_MODE) & ~MSGINT_MODE_ONE_SHOT_DISABLE; tw32(MSGINT_MODE, val); @@ -9058,7 +9240,9 @@ static bool tg3_enable_msix(struct tg3 *tp) if (tp->irq_cnt > 1) { tp->tg3_flags3 |= TG3_FLG3_ENABLE_RSS; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) { + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) { tp->tg3_flags3 |= TG3_FLG3_ENABLE_TSS; netif_set_real_num_tx_queues(tp->dev, tp->irq_cnt - 1); } @@ -9214,7 +9398,7 @@ static int tg3_open(struct net_device *dev) goto err_out2; } - if (!(tp->tg3_flags3 & TG3_FLG3_5717_PLUS) && + if (!(tp->tg3_flags3 & TG3_FLG3_57765_PLUS) && (tp->tg3_flags2 & TG3_FLG2_USING_MSI)) { u32 val = tr32(PCIE_TRANSACTION_CFG); @@ -9588,82 +9772,26 @@ static void tg3_set_rx_mode(struct net_device *dev) tg3_full_unlock(tp); } -#define TG3_REGDUMP_LEN (32 * 1024) - static int tg3_get_regs_len(struct net_device *dev) { - return TG3_REGDUMP_LEN; + return TG3_REG_BLK_SIZE; } static void tg3_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p) { - u32 *p = _p; struct tg3 *tp = netdev_priv(dev); - u8 *orig_p = _p; - int i; regs->version = 0; - memset(p, 0, TG3_REGDUMP_LEN); + memset(_p, 0, TG3_REG_BLK_SIZE); if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) return; tg3_full_lock(tp, 0); -#define __GET_REG32(reg) (*(p)++ = tr32(reg)) -#define GET_REG32_LOOP(base, len) \ -do { p = (u32 *)(orig_p + (base)); \ - for (i = 0; i < len; i += 4) \ - __GET_REG32((base) + i); \ -} while (0) -#define GET_REG32_1(reg) \ -do { p = (u32 *)(orig_p + (reg)); \ - __GET_REG32((reg)); \ -} while (0) - - GET_REG32_LOOP(TG3PCI_VENDOR, 0xb0); - GET_REG32_LOOP(MAILBOX_INTERRUPT_0, 0x200); - GET_REG32_LOOP(MAC_MODE, 0x4f0); - GET_REG32_LOOP(SNDDATAI_MODE, 0xe0); - GET_REG32_1(SNDDATAC_MODE); - GET_REG32_LOOP(SNDBDS_MODE, 0x80); - GET_REG32_LOOP(SNDBDI_MODE, 0x48); - GET_REG32_1(SNDBDC_MODE); - GET_REG32_LOOP(RCVLPC_MODE, 0x20); - GET_REG32_LOOP(RCVLPC_SELLST_BASE, 0x15c); - GET_REG32_LOOP(RCVDBDI_MODE, 0x0c); - GET_REG32_LOOP(RCVDBDI_JUMBO_BD, 0x3c); - GET_REG32_LOOP(RCVDBDI_BD_PROD_IDX_0, 0x44); - GET_REG32_1(RCVDCC_MODE); - GET_REG32_LOOP(RCVBDI_MODE, 0x20); - GET_REG32_LOOP(RCVCC_MODE, 0x14); - GET_REG32_LOOP(RCVLSC_MODE, 0x08); - GET_REG32_1(MBFREE_MODE); - GET_REG32_LOOP(HOSTCC_MODE, 0x100); - GET_REG32_LOOP(MEMARB_MODE, 0x10); - GET_REG32_LOOP(BUFMGR_MODE, 0x58); - GET_REG32_LOOP(RDMAC_MODE, 0x08); - GET_REG32_LOOP(WDMAC_MODE, 0x08); - GET_REG32_1(RX_CPU_MODE); - GET_REG32_1(RX_CPU_STATE); - GET_REG32_1(RX_CPU_PGMCTR); - GET_REG32_1(RX_CPU_HWBKPT); - GET_REG32_1(TX_CPU_MODE); - GET_REG32_1(TX_CPU_STATE); - GET_REG32_1(TX_CPU_PGMCTR); - GET_REG32_LOOP(GRCMBOX_INTERRUPT_0, 0x110); - GET_REG32_LOOP(FTQ_RESET, 0x120); - GET_REG32_LOOP(MSGINT_MODE, 0x0c); - GET_REG32_1(DMAC_MODE); - GET_REG32_LOOP(GRC_MODE, 0x4c); - if (tp->tg3_flags & TG3_FLAG_NVRAM) - GET_REG32_LOOP(NVRAM_CMD, 0x24); - -#undef __GET_REG32 -#undef GET_REG32_LOOP -#undef GET_REG32_1 + tg3_dump_legacy_regs(tp, (u32 *)_p); tg3_full_unlock(tp); } @@ -9997,33 +10125,6 @@ static void tg3_set_msglevel(struct net_device *dev, u32 value) tp->msg_enable = value; } -static int tg3_set_tso(struct net_device *dev, u32 value) -{ - struct tg3 *tp = netdev_priv(dev); - - if (!(tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE)) { - if (value) - return -EINVAL; - return 0; - } - if ((dev->features & NETIF_F_IPV6_CSUM) && - ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) || - (tp->tg3_flags2 & TG3_FLG2_HW_TSO_3))) { - if (value) { - dev->features |= NETIF_F_TSO6; - if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_3) || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || - (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 && - GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) - dev->features |= NETIF_F_TSO_ECN; - } else - dev->features &= ~(NETIF_F_TSO6 | NETIF_F_TSO_ECN); - } - return ethtool_op_set_tso(dev, value); -} - static int tg3_nway_reset(struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); @@ -10246,50 +10347,6 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam return err; } -static u32 tg3_get_rx_csum(struct net_device *dev) -{ - struct tg3 *tp = netdev_priv(dev); - return (tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) != 0; -} - -static int tg3_set_rx_csum(struct net_device *dev, u32 data) -{ - struct tg3 *tp = netdev_priv(dev); - - if (tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) { - if (data != 0) - return -EINVAL; - return 0; - } - - spin_lock_bh(&tp->lock); - if (data) - tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS; - else - tp->tg3_flags &= ~TG3_FLAG_RX_CHECKSUMS; - spin_unlock_bh(&tp->lock); - - return 0; -} - -static int tg3_set_tx_csum(struct net_device *dev, u32 data) -{ - struct tg3 *tp = netdev_priv(dev); - - if (tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) { - if (data != 0) - return -EINVAL; - return 0; - } - - if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS) - ethtool_op_set_tx_ipv6_csum(dev, data); - else - ethtool_op_set_tx_csum(dev, data); - - return 0; -} - static int tg3_get_sset_count(struct net_device *dev, int sset) { switch (sset) { @@ -10317,35 +10374,38 @@ static void tg3_get_strings(struct net_device *dev, u32 stringset, u8 *buf) } } -static int tg3_phys_id(struct net_device *dev, u32 data) +static int tg3_set_phys_id(struct net_device *dev, + enum ethtool_phys_id_state state) { struct tg3 *tp = netdev_priv(dev); - int i; if (!netif_running(tp->dev)) return -EAGAIN; - if (data == 0) - data = UINT_MAX / 2; - - for (i = 0; i < (data * 2); i++) { - if ((i % 2) == 0) - tw32(MAC_LED_CTRL, LED_CTRL_LNKLED_OVERRIDE | - LED_CTRL_1000MBPS_ON | - LED_CTRL_100MBPS_ON | - LED_CTRL_10MBPS_ON | - LED_CTRL_TRAFFIC_OVERRIDE | - LED_CTRL_TRAFFIC_BLINK | - LED_CTRL_TRAFFIC_LED); + switch (state) { + case ETHTOOL_ID_ACTIVE: + return 1; /* cycle on/off once per second */ + + case ETHTOOL_ID_ON: + tw32(MAC_LED_CTRL, LED_CTRL_LNKLED_OVERRIDE | + LED_CTRL_1000MBPS_ON | + LED_CTRL_100MBPS_ON | + LED_CTRL_10MBPS_ON | + LED_CTRL_TRAFFIC_OVERRIDE | + LED_CTRL_TRAFFIC_BLINK | + LED_CTRL_TRAFFIC_LED); + break; - else - tw32(MAC_LED_CTRL, LED_CTRL_LNKLED_OVERRIDE | - LED_CTRL_TRAFFIC_OVERRIDE); + case ETHTOOL_ID_OFF: + tw32(MAC_LED_CTRL, LED_CTRL_LNKLED_OVERRIDE | + LED_CTRL_TRAFFIC_OVERRIDE); + break; - if (msleep_interruptible(500)) - break; + case ETHTOOL_ID_INACTIVE: + tw32(MAC_LED_CTRL, tp->led_ctrl); + break; } - tw32(MAC_LED_CTRL, tp->led_ctrl); + return 0; } @@ -10356,6 +10416,81 @@ static void tg3_get_ethtool_stats(struct net_device *dev, memcpy(tmp_stats, tg3_get_estats(tp), sizeof(tp->estats)); } +static __be32 * tg3_vpd_readblock(struct tg3 *tp) +{ + int i; + __be32 *buf; + u32 offset = 0, len = 0; + u32 magic, val; + + if ((tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) || + tg3_nvram_read(tp, 0, &magic)) + return NULL; + + if (magic == TG3_EEPROM_MAGIC) { + for (offset = TG3_NVM_DIR_START; + offset < TG3_NVM_DIR_END; + offset += TG3_NVM_DIRENT_SIZE) { + if (tg3_nvram_read(tp, offset, &val)) + return NULL; + + if ((val >> TG3_NVM_DIRTYPE_SHIFT) == + TG3_NVM_DIRTYPE_EXTVPD) + break; + } + + if (offset != TG3_NVM_DIR_END) { + len = (val & TG3_NVM_DIRTYPE_LENMSK) * 4; + if (tg3_nvram_read(tp, offset + 4, &offset)) + return NULL; + + offset = tg3_nvram_logical_addr(tp, offset); + } + } + + if (!offset || !len) { + offset = TG3_NVM_VPD_OFF; + len = TG3_NVM_VPD_LEN; + } + + buf = kmalloc(len, GFP_KERNEL); + if (buf == NULL) + return NULL; + + if (magic == TG3_EEPROM_MAGIC) { + for (i = 0; i < len; i += 4) { + /* The data is in little-endian format in NVRAM. + * Use the big-endian read routines to preserve + * the byte order as it exists in NVRAM. + */ + if (tg3_nvram_read_be32(tp, offset + i, &buf[i/4])) + goto error; + } + } else { + u8 *ptr; + ssize_t cnt; + unsigned int pos = 0; + + ptr = (u8 *)&buf[0]; + for (i = 0; pos < len && i < 3; i++, pos += cnt, ptr += cnt) { + cnt = pci_read_vpd(tp->pdev, pos, + len - pos, ptr); + if (cnt == -ETIMEDOUT || cnt == -EINTR) + cnt = 0; + else if (cnt < 0) + goto error; + } + if (pos != len) + goto error; + } + + return buf; + +error: + kfree(buf); + return NULL; +} + #define NVRAM_TEST_SIZE 0x100 #define NVRAM_SELFBOOT_FORMAT1_0_SIZE 0x14 #define NVRAM_SELFBOOT_FORMAT1_2_SIZE 0x18 @@ -10495,14 +10630,11 @@ static int tg3_test_nvram(struct tg3 *tp) if (csum != le32_to_cpu(buf[0xfc/4])) goto out; - for (i = 0; i < TG3_NVM_VPD_LEN; i += 4) { - /* The data is in little-endian format in NVRAM. - * Use the big-endian read routines to preserve - * the byte order as it exists in NVRAM. - */ - if (tg3_nvram_read_be32(tp, TG3_NVM_VPD_OFF + i, &buf[i/4])) - goto out; - } + kfree(buf); + + buf = tg3_vpd_readblock(tp); + if (!buf) + return -ENOMEM; i = pci_vpd_find_tag((u8 *)buf, 0, TG3_NVM_VPD_LEN, PCI_VPD_LRDT_RO_DATA); @@ -10850,8 +10982,7 @@ static int tg3_test_memory(struct tg3 *tp) int err = 0; int i; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) + if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) mem_tbl = mem_tbl_5717; else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) mem_tbl = mem_tbl_57765; @@ -10876,7 +11007,7 @@ static int tg3_test_memory(struct tg3 *tp) #define TG3_MAC_LOOPBACK 0 #define TG3_PHY_LOOPBACK 1 -static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) +static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode) { u32 mac_mode, rx_start_idx, rx_idx, tx_idx, opaque_key; u32 desc_idx, coal_now; @@ -10974,7 +11105,7 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) err = -EIO; - tx_len = 1514; + tx_len = pktsz; skb = netdev_alloc_skb(tp->dev, tx_len); if (!skb) return -ENOMEM; @@ -10983,7 +11114,7 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) memcpy(tx_data, tp->dev->dev_addr, 6); memset(tx_data + 6, 0x0, 8); - tw32(MAC_RX_MTU_SIZE, tx_len + 4); + tw32(MAC_RX_MTU_SIZE, tx_len + ETH_FCS_LEN); for (i = 14; i < tx_len; i++) tx_data[i] = (u8) (i & 0xff); @@ -11039,8 +11170,6 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) desc = &rnapi->rx_rcb[rx_start_idx]; desc_idx = desc->opaque & RXD_OPAQUE_INDEX_MASK; opaque_key = desc->opaque & RXD_OPAQUE_RING_MASK; - if (opaque_key != RXD_OPAQUE_RING_STD) - goto out; if ((desc->err_vlan & RXD_ERR_MASK) != 0 && (desc->err_vlan != RXD_ERR_ODD_NIBBLE_RCVD_MII)) @@ -11050,9 +11179,20 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) if (rx_len != tx_len) goto out; - rx_skb = tpr->rx_std_buffers[desc_idx].skb; + if (pktsz <= TG3_RX_STD_DMA_SZ - ETH_FCS_LEN) { + if (opaque_key != RXD_OPAQUE_RING_STD) + goto out; + + rx_skb = tpr->rx_std_buffers[desc_idx].skb; + map = dma_unmap_addr(&tpr->rx_std_buffers[desc_idx], mapping); + } else { + if (opaque_key != RXD_OPAQUE_RING_JUMBO) + goto out; + + rx_skb = tpr->rx_jmb_buffers[desc_idx].skb; + map = dma_unmap_addr(&tpr->rx_jmb_buffers[desc_idx], mapping); + } - map = dma_unmap_addr(&tpr->rx_std_buffers[desc_idx], mapping); pci_dma_sync_single_for_cpu(tp->pdev, map, rx_len, PCI_DMA_FROMDEVICE); for (i = 14; i < tx_len; i++) { @@ -11118,9 +11258,13 @@ static int tg3_test_loopback(struct tg3 *tp) CPMU_CTRL_LINK_AWARE_MODE)); } - if (tg3_run_loopback(tp, TG3_MAC_LOOPBACK)) + if (tg3_run_loopback(tp, ETH_FRAME_LEN, TG3_MAC_LOOPBACK)) err |= TG3_MAC_LOOPBACK_FAILED; + if ((tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) && + tg3_run_loopback(tp, 9000 + ETH_HLEN, TG3_MAC_LOOPBACK)) + err |= (TG3_MAC_LOOPBACK_FAILED << 2); + if (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) { tw32(TG3_CPMU_CTRL, cpmuctrl); @@ -11130,8 +11274,11 @@ static int tg3_test_loopback(struct tg3 *tp) if (!(tp->phy_flags & TG3_PHYFLG_PHY_SERDES) && !(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) { - if (tg3_run_loopback(tp, TG3_PHY_LOOPBACK)) + if (tg3_run_loopback(tp, ETH_FRAME_LEN, TG3_PHY_LOOPBACK)) err |= TG3_PHY_LOOPBACK_FAILED; + if ((tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) && + tg3_run_loopback(tp, 9000 + ETH_HLEN, TG3_PHY_LOOPBACK)) + err |= (TG3_PHY_LOOPBACK_FAILED << 2); } /* Re-enable gphy autopowerdown. */ @@ -11364,14 +11511,9 @@ static const struct ethtool_ops tg3_ethtool_ops = { .set_ringparam = tg3_set_ringparam, .get_pauseparam = tg3_get_pauseparam, .set_pauseparam = tg3_set_pauseparam, - .get_rx_csum = tg3_get_rx_csum, - .set_rx_csum = tg3_set_rx_csum, - .set_tx_csum = tg3_set_tx_csum, - .set_sg = ethtool_op_set_sg, - .set_tso = tg3_set_tso, .self_test = tg3_self_test, .get_strings = tg3_get_strings, - .phys_id = tg3_phys_id, + .set_phys_id = tg3_set_phys_id, .get_ethtool_stats = tg3_get_ethtool_stats, .get_coalesce = tg3_get_coalesce, .set_coalesce = tg3_set_coalesce, @@ -11843,6 +11985,8 @@ static void __devinit tg3_get_5717_nvram_info(struct tg3 *tp) switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) { case FLASH_5717VENDOR_ATMEL_MDB021D: + /* Detect size with tg3_nvram_get_size() */ + break; case FLASH_5717VENDOR_ATMEL_ADB021B: case FLASH_5717VENDOR_ATMEL_ADB021D: tp->nvram_size = TG3_NVRAM_SIZE_256KB; @@ -11868,8 +12012,10 @@ static void __devinit tg3_get_5717_nvram_info(struct tg3 *tp) switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) { case FLASH_5717VENDOR_ST_M_M25PE20: - case FLASH_5717VENDOR_ST_A_M25PE20: case FLASH_5717VENDOR_ST_M_M45PE20: + /* Detect size with tg3_nvram_get_size() */ + break; + case FLASH_5717VENDOR_ST_A_M25PE20: case FLASH_5717VENDOR_ST_A_M45PE20: tp->nvram_size = TG3_NVRAM_SIZE_256KB; break; @@ -11888,6 +12034,118 @@ static void __devinit tg3_get_5717_nvram_info(struct tg3 *tp) tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; } +static void __devinit tg3_get_5720_nvram_info(struct tg3 *tp) +{ + u32 nvcfg1, nvmpinstrp; + + nvcfg1 = tr32(NVRAM_CFG1); + nvmpinstrp = nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK; + + switch (nvmpinstrp) { + case FLASH_5720_EEPROM_HD: + case FLASH_5720_EEPROM_LD: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + + nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS; + tw32(NVRAM_CFG1, nvcfg1); + if (nvmpinstrp == FLASH_5720_EEPROM_HD) + tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE; + else + tp->nvram_pagesize = ATMEL_AT24C02_CHIP_SIZE; + return; + case FLASH_5720VENDOR_M_ATMEL_DB011D: + case FLASH_5720VENDOR_A_ATMEL_DB011B: + case FLASH_5720VENDOR_A_ATMEL_DB011D: + case FLASH_5720VENDOR_M_ATMEL_DB021D: + case FLASH_5720VENDOR_A_ATMEL_DB021B: + case FLASH_5720VENDOR_A_ATMEL_DB021D: + case FLASH_5720VENDOR_M_ATMEL_DB041D: + case FLASH_5720VENDOR_A_ATMEL_DB041B: + case FLASH_5720VENDOR_A_ATMEL_DB041D: + case FLASH_5720VENDOR_M_ATMEL_DB081D: + case FLASH_5720VENDOR_A_ATMEL_DB081D: + case FLASH_5720VENDOR_ATMEL_45USPT: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->tg3_flags2 |= TG3_FLG2_FLASH; + + switch (nvmpinstrp) { + case FLASH_5720VENDOR_M_ATMEL_DB021D: + case FLASH_5720VENDOR_A_ATMEL_DB021B: + case FLASH_5720VENDOR_A_ATMEL_DB021D: + tp->nvram_size = TG3_NVRAM_SIZE_256KB; + break; + case FLASH_5720VENDOR_M_ATMEL_DB041D: + case FLASH_5720VENDOR_A_ATMEL_DB041B: + case FLASH_5720VENDOR_A_ATMEL_DB041D: + tp->nvram_size = TG3_NVRAM_SIZE_512KB; + break; + case FLASH_5720VENDOR_M_ATMEL_DB081D: + case FLASH_5720VENDOR_A_ATMEL_DB081D: + tp->nvram_size = TG3_NVRAM_SIZE_1MB; + break; + default: + tp->nvram_size = TG3_NVRAM_SIZE_128KB; + break; + } + break; + case FLASH_5720VENDOR_M_ST_M25PE10: + case FLASH_5720VENDOR_M_ST_M45PE10: + case FLASH_5720VENDOR_A_ST_M25PE10: + case FLASH_5720VENDOR_A_ST_M45PE10: + case FLASH_5720VENDOR_M_ST_M25PE20: + case FLASH_5720VENDOR_M_ST_M45PE20: + case FLASH_5720VENDOR_A_ST_M25PE20: + case FLASH_5720VENDOR_A_ST_M45PE20: + case FLASH_5720VENDOR_M_ST_M25PE40: + case FLASH_5720VENDOR_M_ST_M45PE40: + case FLASH_5720VENDOR_A_ST_M25PE40: + case FLASH_5720VENDOR_A_ST_M45PE40: + case FLASH_5720VENDOR_M_ST_M25PE80: + case FLASH_5720VENDOR_M_ST_M45PE80: + case FLASH_5720VENDOR_A_ST_M25PE80: + case FLASH_5720VENDOR_A_ST_M45PE80: + case FLASH_5720VENDOR_ST_25USPT: + case FLASH_5720VENDOR_ST_45USPT: + tp->nvram_jedecnum = JEDEC_ST; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->tg3_flags2 |= TG3_FLG2_FLASH; + + switch (nvmpinstrp) { + case FLASH_5720VENDOR_M_ST_M25PE20: + case FLASH_5720VENDOR_M_ST_M45PE20: + case FLASH_5720VENDOR_A_ST_M25PE20: + case FLASH_5720VENDOR_A_ST_M45PE20: + tp->nvram_size = TG3_NVRAM_SIZE_256KB; + break; + case FLASH_5720VENDOR_M_ST_M25PE40: + case FLASH_5720VENDOR_M_ST_M45PE40: + case FLASH_5720VENDOR_A_ST_M25PE40: + case FLASH_5720VENDOR_A_ST_M45PE40: + tp->nvram_size = TG3_NVRAM_SIZE_512KB; + break; + case FLASH_5720VENDOR_M_ST_M25PE80: + case FLASH_5720VENDOR_M_ST_M45PE80: + case FLASH_5720VENDOR_A_ST_M25PE80: + case FLASH_5720VENDOR_A_ST_M45PE80: + tp->nvram_size = TG3_NVRAM_SIZE_1MB; + break; + default: + tp->nvram_size = TG3_NVRAM_SIZE_128KB; + break; + } + break; + default: + tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM; + return; + } + + tg3_nvram_get_pagesize(tp, nvcfg1); + if (tp->nvram_pagesize != 264 && tp->nvram_pagesize != 528) + tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; +} + /* Chips other than 5700/5701 use the NVRAM for fetching info. */ static void __devinit tg3_nvram_init(struct tg3 *tp) { @@ -11935,6 +12193,8 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) tg3_get_5717_nvram_info(tp); + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) + tg3_get_5720_nvram_info(tp); else tg3_get_nvram_info(tp); @@ -12472,7 +12732,7 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) if (cfg2 & (1 << 18)) tp->phy_flags |= TG3_PHYFLG_SERDES_PREEMPHASIS; - if (((tp->tg3_flags3 & TG3_FLG3_5717_PLUS) || + if (((tp->tg3_flags3 & TG3_FLG3_57765_PLUS) || ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 && GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX))) && (cfg2 & NIC_SRAM_DATA_CFG_2_APD_EN)) @@ -12480,7 +12740,7 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 && - !(tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) { + !(tp->tg3_flags3 & TG3_FLG3_57765_PLUS)) { u32 cfg3; tg3_read_mem(tp, NIC_SRAM_DATA_CFG_3, &cfg3); @@ -12717,46 +12977,11 @@ static void __devinit tg3_read_vpd(struct tg3 *tp) u8 *vpd_data; unsigned int block_end, rosize, len; int j, i = 0; - u32 magic; - - if ((tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) || - tg3_nvram_read(tp, 0x0, &magic)) - goto out_no_vpd; - vpd_data = kmalloc(TG3_NVM_VPD_LEN, GFP_KERNEL); + vpd_data = (u8 *)tg3_vpd_readblock(tp); if (!vpd_data) goto out_no_vpd; - if (magic == TG3_EEPROM_MAGIC) { - for (i = 0; i < TG3_NVM_VPD_LEN; i += 4) { - u32 tmp; - - /* The data is in little-endian format in NVRAM. - * Use the big-endian read routines to preserve - * the byte order as it exists in NVRAM. - */ - if (tg3_nvram_read_be32(tp, TG3_NVM_VPD_OFF + i, &tmp)) - goto out_not_found; - - memcpy(&vpd_data[i], &tmp, sizeof(tmp)); - } - } else { - ssize_t cnt; - unsigned int pos = 0; - - for (; pos < TG3_NVM_VPD_LEN && i < 3; i++, pos += cnt) { - cnt = pci_read_vpd(tp->pdev, pos, - TG3_NVM_VPD_LEN - pos, - &vpd_data[pos]); - if (cnt == -ETIMEDOUT || cnt == -EINTR) - cnt = 0; - else if (cnt < 0) - goto out_not_found; - } - if (pos != TG3_NVM_VPD_LEN) - goto out_not_found; - } - i = pci_vpd_find_tag(vpd_data, 0, TG3_NVM_VPD_LEN, PCI_VPD_LRDT_RO_DATA); if (i < 0) @@ -13118,21 +13343,15 @@ done: static struct pci_dev * __devinit tg3_find_peer(struct tg3 *); -static inline void vlan_features_add(struct net_device *dev, unsigned long flags) -{ - dev->vlan_features |= flags; -} - static inline u32 tg3_rx_ret_ring_size(struct tg3 *tp) { - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) - return 4096; + if (tp->tg3_flags3 & TG3_FLG3_LRG_PROD_RING_CAP) + return TG3_RX_RET_MAX_SIZE_5717; else if ((tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) && !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) - return 1024; + return TG3_RX_RET_MAX_SIZE_5700; else - return 512; + return TG3_RX_RET_MAX_SIZE_5705; } static DEFINE_PCI_DEVICE_TABLE(tg3_write_reorder_chipsets) = { @@ -13177,7 +13396,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_5717 || tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718 || - tp->pdev->device == TG3PCI_DEVICE_TIGON3_5719) + tp->pdev->device == TG3PCI_DEVICE_TIGON3_5719 || + tp->pdev->device == TG3PCI_DEVICE_TIGON3_5720) pci_read_config_dword(tp->pdev, TG3PCI_GEN2_PRODID_ASICREV, &prod_id_asic_rev); @@ -13332,14 +13552,19 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) tp->pdev_peer = tg3_find_peer(tp); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) tp->tg3_flags3 |= TG3_FLG3_5717_PLUS; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 || + (tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) + tp->tg3_flags3 |= TG3_FLG3_57765_PLUS; + /* Intentionally exclude ASIC_REV_5906 */ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || @@ -13347,7 +13572,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || - (tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) + (tp->tg3_flags3 & TG3_FLG3_57765_PLUS)) tp->tg3_flags3 |= TG3_FLG3_5755_PLUS; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || @@ -13364,22 +13589,20 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) /* 5700 B0 chips do not support checksumming correctly due * to hardware bugs. */ - if (tp->pci_chip_rev_id == CHIPREV_ID_5700_B0) - tp->tg3_flags |= TG3_FLAG_BROKEN_CHECKSUMS; - else { - unsigned long features = NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_GRO; + if (tp->pci_chip_rev_id != CHIPREV_ID_5700_B0) { + u32 features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM; - tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS; if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS) features |= NETIF_F_IPV6_CSUM; tp->dev->features |= features; - vlan_features_add(tp->dev, features); + tp->dev->hw_features |= features; + tp->dev->vlan_features |= features; } /* Determine TSO capabilities */ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) ; /* Do nothing. HW bug. */ - else if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) + else if (tp->tg3_flags3 & TG3_FLG3_57765_PLUS) tp->tg3_flags2 |= TG3_FLG2_HW_TSO_3; else if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) @@ -13415,7 +13638,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI; } - if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) { + if (tp->tg3_flags3 & TG3_FLG3_57765_PLUS) { tp->tg3_flags |= TG3_FLAG_SUPPORT_MSIX; tp->irq_max = TG3_IRQ_MAX_VECS; } @@ -13430,7 +13653,10 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->tg3_flags3 |= TG3_FLG3_40BIT_DMA_LIMIT_BUG; } - if ((tp->tg3_flags3 & TG3_FLG3_5717_PLUS) && + if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) + tp->tg3_flags3 |= TG3_FLG3_LRG_PROD_RING_CAP; + + if ((tp->tg3_flags3 & TG3_FLG3_57765_PLUS) && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5719) tp->tg3_flags3 |= TG3_FLG3_USE_JUMBO_BDFLAG; @@ -13449,7 +13675,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->tg3_flags2 |= TG3_FLG2_PCI_EXPRESS; tp->pcie_readrq = 4096; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) tp->pcie_readrq = 2048; pcie_set_readrq(tp->pdev, tp->pcie_readrq); @@ -13636,7 +13863,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || - (tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) + (tp->tg3_flags3 & TG3_FLG3_57765_PLUS)) tp->tg3_flags |= TG3_FLAG_CPMU_PRESENT; /* Set up tp->grc_local_ctrl before calling tg_power_up(). @@ -13715,7 +13942,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) !(tp->phy_flags & TG3_PHYFLG_IS_FET) && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57780 && - !(tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) { + !(tp->tg3_flags3 & TG3_FLG3_57765_PLUS)) { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || @@ -13756,7 +13983,15 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) /* Initialize data/descriptor byte/word swapping. */ val = tr32(GRC_MODE); - val &= GRC_MODE_HOST_STACKUP; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) + val &= (GRC_MODE_BYTE_SWAP_B2HRX_DATA | + GRC_MODE_WORD_SWAP_B2HRX_DATA | + GRC_MODE_B2HRX_ENABLE | + GRC_MODE_HTX2B_ENABLE | + GRC_MODE_HOST_STACKUP); + else + val &= GRC_MODE_HOST_STACKUP; + tw32(GRC_MODE, val | tp->grc_mode); tg3_switch_clocks(tp); @@ -13961,8 +14196,7 @@ static int __devinit tg3_get_device_address(struct tg3 *tp) tw32_f(NVRAM_CMD, NVRAM_CMD_RESET); else tg3_nvram_unlock(tp); - } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) { + } else if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) { if (PCI_FUNC(tp->pdev->devfn) & 1) mac_offset = 0xcc; if (PCI_FUNC(tp->pdev->devfn) > 1) @@ -14051,7 +14285,7 @@ static u32 __devinit tg3_calc_dma_bndry(struct tg3 *tp, u32 val) #endif #endif - if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) { + if (tp->tg3_flags3 & TG3_FLG3_57765_PLUS) { val = goal ? 0 : DMA_RWCTRL_DIS_CACHE_ALIGNMENT; goto out; } @@ -14268,7 +14502,7 @@ static int __devinit tg3_test_dma(struct tg3 *tp) tp->dma_rwctrl = tg3_calc_dma_bndry(tp, tp->dma_rwctrl); - if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) + if (tp->tg3_flags3 & TG3_FLG3_57765_PLUS) goto out; if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) { @@ -14443,7 +14677,7 @@ out_nofree: static void __devinit tg3_init_bufmgr_config(struct tg3 *tp) { - if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) { + if (tp->tg3_flags3 & TG3_FLG3_57765_PLUS) { tp->bufmgr_config.mbuf_read_dma_low_water = DEFAULT_MB_RDMA_LOW_WATER_5705; tp->bufmgr_config.mbuf_mac_rx_low_water = @@ -14521,6 +14755,7 @@ static char * __devinit tg3_phy_string(struct tg3 *tp) case TG3_PHY_ID_BCM5718S: return "5718S"; case TG3_PHY_ID_BCM57765: return "57765"; case TG3_PHY_ID_BCM5719C: return "5719C"; + case TG3_PHY_ID_BCM5720C: return "5720C"; case TG3_PHY_ID_BCM8002: return "8002/serdes"; case 0: return "serdes"; default: return "unknown"; @@ -14633,6 +14868,7 @@ static const struct net_device_ops tg3_netdev_ops = { .ndo_do_ioctl = tg3_ioctl, .ndo_tx_timeout = tg3_tx_timeout, .ndo_change_mtu = tg3_change_mtu, + .ndo_fix_features = tg3_fix_features, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = tg3_poll_controller, #endif @@ -14663,6 +14899,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, u32 sndmbx, rcvmbx, intmbx; char str[40]; u64 dma_mask, persist_dma_mask; + u32 hw_features = 0; printk_once(KERN_INFO "%s\n", version); @@ -14759,8 +14996,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, } if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5719) + !(tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) dev->netdev_ops = &tg3_netdev_ops; else dev->netdev_ops = &tg3_netdev_ops_dma_bug; @@ -14824,27 +15060,25 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, * is off by default, but can be enabled using ethtool. */ if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO) && - (dev->features & NETIF_F_IP_CSUM)) { - dev->features |= NETIF_F_TSO; - vlan_features_add(dev, NETIF_F_TSO); - } + (dev->features & NETIF_F_IP_CSUM)) + hw_features |= NETIF_F_TSO; if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) || (tp->tg3_flags2 & TG3_FLG2_HW_TSO_3)) { - if (dev->features & NETIF_F_IPV6_CSUM) { - dev->features |= NETIF_F_TSO6; - vlan_features_add(dev, NETIF_F_TSO6); - } + if (dev->features & NETIF_F_IPV6_CSUM) + hw_features |= NETIF_F_TSO6; if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_3) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 && GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) { - dev->features |= NETIF_F_TSO_ECN; - vlan_features_add(dev, NETIF_F_TSO_ECN); - } + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) + hw_features |= NETIF_F_TSO_ECN; } + dev->hw_features |= hw_features; + dev->features |= hw_features; + dev->vlan_features |= hw_features; + if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A1 && !(tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) && !(tr32(TG3PCI_PCISTATE) & PCISTATE_BUS_SPEED_HIGH)) { @@ -14973,7 +15207,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, } netdev_info(dev, "RXcsums[%d] LinkChgREG[%d] MIirq[%d] ASF[%d] TSOcap[%d]\n", - (tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) != 0, + (dev->features & NETIF_F_RXCSUM) != 0, (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) != 0, (tp->phy_flags & TG3_PHYFLG_USE_MI_INTERRUPT) != 0, (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) != 0, diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 5e96706ad108..224c3e0ec695 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -25,9 +25,13 @@ #define TG3_RX_INTERNAL_RING_SZ_5906 32 -#define RX_STD_MAX_SIZE_5705 512 -#define RX_STD_MAX_SIZE_5717 2048 -#define RX_JUMBO_MAX_SIZE 0xdeadbeef /* XXX */ +#define TG3_RX_STD_MAX_SIZE_5700 512 +#define TG3_RX_STD_MAX_SIZE_5717 2048 +#define TG3_RX_JMB_MAX_SIZE_5700 256 +#define TG3_RX_JMB_MAX_SIZE_5717 1024 +#define TG3_RX_RET_MAX_SIZE_5700 1024 +#define TG3_RX_RET_MAX_SIZE_5705 512 +#define TG3_RX_RET_MAX_SIZE_5717 4096 /* First 256 bytes are a mirror of PCI config space. */ #define TG3PCI_VENDOR 0x00000000 @@ -54,6 +58,7 @@ #define TG3PCI_DEVICE_TIGON3_57791 0x16b2 #define TG3PCI_DEVICE_TIGON3_57795 0x16b6 #define TG3PCI_DEVICE_TIGON3_5719 0x1657 +#define TG3PCI_DEVICE_TIGON3_5720 0x165f /* 0x04 --> 0x2c unused */ #define TG3PCI_SUBVENDOR_ID_BROADCOM PCI_VENDOR_ID_BROADCOM #define TG3PCI_SUBDEVICE_ID_BROADCOM_95700A6 0x1644 @@ -163,6 +168,7 @@ #define ASIC_REV_5717 0x5717 #define ASIC_REV_57765 0x57785 #define ASIC_REV_5719 0x5719 +#define ASIC_REV_5720 0x5720 #define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8) #define CHIPREV_5700_AX 0x70 #define CHIPREV_5700_BX 0x71 @@ -473,6 +479,8 @@ #define TX_MODE_BIG_BCKOFF_ENABLE 0x00000020 #define TX_MODE_LONG_PAUSE_ENABLE 0x00000040 #define TX_MODE_MBUF_LOCKUP_FIX 0x00000100 +#define TX_MODE_JMB_FRM_LEN 0x00400000 +#define TX_MODE_CNT_DN_MODE 0x00800000 #define MAC_TX_STATUS 0x00000460 #define TX_STATUS_XOFFED 0x00000001 #define TX_STATUS_SENT_XOFF 0x00000002 @@ -487,6 +495,8 @@ #define TX_LENGTHS_IPG_SHIFT 8 #define TX_LENGTHS_IPG_CRS_MASK 0x00003000 #define TX_LENGTHS_IPG_CRS_SHIFT 12 +#define TX_LENGTHS_JMB_FRM_LEN_MSK 0x00ff0000 +#define TX_LENGTHS_CNT_DWN_VAL_MSK 0xff000000 #define MAC_RX_MODE 0x00000468 #define RX_MODE_RESET 0x00000001 #define RX_MODE_ENABLE 0x00000002 @@ -1079,6 +1089,9 @@ #define CPMU_HST_ACC_MACCLK_6_25 0x00130000 /* 0x3620 --> 0x3630 unused */ +#define TG3_CPMU_CLCK_ORIDE 0x00003624 +#define CPMU_CLCK_ORIDE_MAC_ORIDE_EN 0x80000000 + #define TG3_CPMU_CLCK_STAT 0x00003630 #define CPMU_CLCK_STAT_MAC_CLCK_MASK 0x001f0000 #define CPMU_CLCK_STAT_MAC_CLCK_62_5 0x00000000 @@ -1188,6 +1201,7 @@ #define HOSTCC_STATS_BLK_NIC_ADDR 0x00003c40 #define HOSTCC_STATUS_BLK_NIC_ADDR 0x00003c44 #define HOSTCC_FLOW_ATTN 0x00003c48 +#define HOSTCC_FLOW_ATTN_MBUF_LWM 0x00000040 /* 0x3c4c --> 0x3c50 unused */ #define HOSTCC_JUMBO_CON_IDX 0x00003c50 #define HOSTCC_STD_CON_IDX 0x00003c54 @@ -1321,6 +1335,7 @@ #define RDMAC_MODE_MULT_DMA_RD_DIS 0x01000000 #define RDMAC_MODE_IPV4_LSO_EN 0x08000000 #define RDMAC_MODE_IPV6_LSO_EN 0x10000000 +#define RDMAC_MODE_H2BNC_VLAN_DET 0x20000000 #define RDMAC_STATUS 0x00004804 #define RDMAC_STATUS_TGTABORT 0x00000004 #define RDMAC_STATUS_MSTABORT 0x00000008 @@ -1597,6 +1612,7 @@ #define MSGINT_MODE_ONE_SHOT_DISABLE 0x00000020 #define MSGINT_MODE_MULTIVEC_EN 0x00000080 #define MSGINT_STATUS 0x00006004 +#define MSGINT_STATUS_MSI_REQ 0x00000001 #define MSGINT_FIFO 0x00006008 /* 0x600c --> 0x6400 unused */ @@ -1613,6 +1629,8 @@ #define GRC_MODE_WSWAP_NONFRM_DATA 0x00000004 #define GRC_MODE_BSWAP_DATA 0x00000010 #define GRC_MODE_WSWAP_DATA 0x00000020 +#define GRC_MODE_BYTE_SWAP_B2HRX_DATA 0x00000040 +#define GRC_MODE_WORD_SWAP_B2HRX_DATA 0x00000080 #define GRC_MODE_SPLITHDR 0x00000100 #define GRC_MODE_NOFRM_CRACKING 0x00000200 #define GRC_MODE_INCL_CRC 0x00000400 @@ -1620,8 +1638,10 @@ #define GRC_MODE_NOIRQ_ON_SENDS 0x00002000 #define GRC_MODE_NOIRQ_ON_RCV 0x00004000 #define GRC_MODE_FORCE_PCI32BIT 0x00008000 +#define GRC_MODE_B2HRX_ENABLE 0x00008000 #define GRC_MODE_HOST_STACKUP 0x00010000 #define GRC_MODE_HOST_SENDBDS 0x00020000 +#define GRC_MODE_HTX2B_ENABLE 0x00040000 #define GRC_MODE_NO_TX_PHDR_CSUM 0x00100000 #define GRC_MODE_NVRAM_WR_ENABLE 0x00200000 #define GRC_MODE_PCIE_TL_SEL 0x00000000 @@ -1818,6 +1838,38 @@ #define FLASH_5717VENDOR_ATMEL_45USPT 0x03400000 #define FLASH_5717VENDOR_ST_25USPT 0x03400002 #define FLASH_5717VENDOR_ST_45USPT 0x03400001 +#define FLASH_5720_EEPROM_HD 0x00000001 +#define FLASH_5720_EEPROM_LD 0x00000003 +#define FLASH_5720VENDOR_M_ATMEL_DB011D 0x01000000 +#define FLASH_5720VENDOR_M_ATMEL_DB021D 0x01000002 +#define FLASH_5720VENDOR_M_ATMEL_DB041D 0x01000001 +#define FLASH_5720VENDOR_M_ATMEL_DB081D 0x01000003 +#define FLASH_5720VENDOR_M_ST_M25PE10 0x02000000 +#define FLASH_5720VENDOR_M_ST_M25PE20 0x02000002 +#define FLASH_5720VENDOR_M_ST_M25PE40 0x02000001 +#define FLASH_5720VENDOR_M_ST_M25PE80 0x02000003 +#define FLASH_5720VENDOR_M_ST_M45PE10 0x03000000 +#define FLASH_5720VENDOR_M_ST_M45PE20 0x03000002 +#define FLASH_5720VENDOR_M_ST_M45PE40 0x03000001 +#define FLASH_5720VENDOR_M_ST_M45PE80 0x03000003 +#define FLASH_5720VENDOR_A_ATMEL_DB011B 0x01800000 +#define FLASH_5720VENDOR_A_ATMEL_DB021B 0x01800002 +#define FLASH_5720VENDOR_A_ATMEL_DB041B 0x01800001 +#define FLASH_5720VENDOR_A_ATMEL_DB011D 0x01c00000 +#define FLASH_5720VENDOR_A_ATMEL_DB021D 0x01c00002 +#define FLASH_5720VENDOR_A_ATMEL_DB041D 0x01c00001 +#define FLASH_5720VENDOR_A_ATMEL_DB081D 0x01c00003 +#define FLASH_5720VENDOR_A_ST_M25PE10 0x02800000 +#define FLASH_5720VENDOR_A_ST_M25PE20 0x02800002 +#define FLASH_5720VENDOR_A_ST_M25PE40 0x02800001 +#define FLASH_5720VENDOR_A_ST_M25PE80 0x02800003 +#define FLASH_5720VENDOR_A_ST_M45PE10 0x02c00000 +#define FLASH_5720VENDOR_A_ST_M45PE20 0x02c00002 +#define FLASH_5720VENDOR_A_ST_M45PE40 0x02c00001 +#define FLASH_5720VENDOR_A_ST_M45PE80 0x02c00003 +#define FLASH_5720VENDOR_ATMEL_45USPT 0x03c00000 +#define FLASH_5720VENDOR_ST_25USPT 0x03c00002 +#define FLASH_5720VENDOR_ST_45USPT 0x03c00001 #define NVRAM_CFG1_5752PAGE_SIZE_MASK 0x70000000 #define FLASH_5752PAGE_SIZE_256 0x00000000 #define FLASH_5752PAGE_SIZE_512 0x10000000 @@ -1904,6 +1956,8 @@ #define TG3_PCIE_PL_LO_PHYCTL5 0x00000014 #define TG3_PCIE_PL_LO_PHYCTL5_DIS_L2CLKREQ 0x80000000 +#define TG3_REG_BLK_SIZE 0x00008000 + /* OTP bit definitions */ #define TG3_OTP_AGCTGT_MASK 0x000000e0 #define TG3_OTP_AGCTGT_SHIFT 1 @@ -1955,7 +2009,9 @@ #define TG3_NVM_DIR_END 0x78 #define TG3_NVM_DIRENT_SIZE 0xc #define TG3_NVM_DIRTYPE_SHIFT 24 +#define TG3_NVM_DIRTYPE_LENMSK 0x003fffff #define TG3_NVM_DIRTYPE_ASFINI 1 +#define TG3_NVM_DIRTYPE_EXTVPD 20 #define TG3_NVM_PTREV_BCVER 0x94 #define TG3_NVM_BCVER_MAJMSK 0x0000ff00 #define TG3_NVM_BCVER_MAJSFT 8 @@ -2833,8 +2889,8 @@ struct tg3 { u32 tg3_flags; #define TG3_FLAG_TAGGED_STATUS 0x00000001 #define TG3_FLAG_TXD_MBOX_HWBUG 0x00000002 -#define TG3_FLAG_RX_CHECKSUMS 0x00000004 #define TG3_FLAG_USE_LINKCHG_REG 0x00000008 +#define TG3_FLAG_ERROR_PROCESSED 0x00000010 #define TG3_FLAG_ENABLE_ASF 0x00000020 #define TG3_FLAG_ASPM_WORKAROUND 0x00000040 #define TG3_FLAG_POLL_SERDES 0x00000080 @@ -2859,7 +2915,6 @@ struct tg3 { #define TG3_FLAG_PAUSE_AUTONEG 0x02000000 #define TG3_FLAG_CPMU_PRESENT 0x04000000 #define TG3_FLAG_40BIT_DMA_BUG 0x08000000 -#define TG3_FLAG_BROKEN_CHECKSUMS 0x10000000 #define TG3_FLAG_JUMBO_CAPABLE 0x20000000 #define TG3_FLAG_CHIP_RESETTING 0x40000000 #define TG3_FLAG_INIT_COMPLETE 0x80000000 @@ -2897,6 +2952,7 @@ struct tg3 { #define TG3_FLG3_5701_DMA_BUG 0x00000008 #define TG3_FLG3_USE_PHYLIB 0x00000010 #define TG3_FLG3_MDIOBUS_INITED 0x00000020 +#define TG3_FLG3_LRG_PROD_RING_CAP 0x00000080 #define TG3_FLG3_RGMII_INBAND_DISABLE 0x00000100 #define TG3_FLG3_RGMII_EXT_IBND_RX_EN 0x00000200 #define TG3_FLG3_RGMII_EXT_IBND_TX_EN 0x00000400 @@ -2910,8 +2966,9 @@ struct tg3 { #define TG3_FLG3_SHORT_DMA_BUG 0x00200000 #define TG3_FLG3_USE_JUMBO_BDFLAG 0x00400000 #define TG3_FLG3_L1PLLPD_EN 0x00800000 -#define TG3_FLG3_5717_PLUS 0x01000000 +#define TG3_FLG3_57765_PLUS 0x01000000 #define TG3_FLG3_APE_HAS_NCSI 0x02000000 +#define TG3_FLG3_5717_PLUS 0x04000000 struct timer_list timer; u16 timer_counter; @@ -2983,6 +3040,7 @@ struct tg3 { #define TG3_PHY_ID_BCM5718S 0xbc050ff0 #define TG3_PHY_ID_BCM57765 0x5c0d8a40 #define TG3_PHY_ID_BCM5719C 0x5c0d8a20 +#define TG3_PHY_ID_BCM5720C 0x5c0d8b60 #define TG3_PHY_ID_BCM5906 0xdc00ac40 #define TG3_PHY_ID_BCM8002 0x60010140 #define TG3_PHY_ID_INVALID 0xffffffff @@ -3049,6 +3107,7 @@ struct tg3 { int nvram_lock_cnt; u32 nvram_size; +#define TG3_NVRAM_SIZE_2KB 0x00000800 #define TG3_NVRAM_SIZE_64KB 0x00010000 #define TG3_NVRAM_SIZE_128KB 0x00020000 #define TG3_NVRAM_SIZE_256KB 0x00040000 @@ -3064,6 +3123,9 @@ struct tg3 { #define JEDEC_SAIFUN 0x4f #define JEDEC_SST 0xbf +#define ATMEL_AT24C02_CHIP_SIZE TG3_NVRAM_SIZE_2KB +#define ATMEL_AT24C02_PAGE_SIZE (8) + #define ATMEL_AT24C64_CHIP_SIZE TG3_NVRAM_SIZE_64KB #define ATMEL_AT24C64_PAGE_SIZE (32) diff --git a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c index 2bedc0ace812..1313aa1315f0 100644 --- a/drivers/net/tokenring/madgemc.c +++ b/drivers/net/tokenring/madgemc.c @@ -727,7 +727,7 @@ static int __devexit madgemc_remove(struct device *device) return 0; } -static short madgemc_adapter_ids[] __initdata = { +static const short madgemc_adapter_ids[] __devinitconst = { 0x002d, 0x0000 }; diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index efaa1d69b720..45144d5bd11b 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -1995,7 +1995,7 @@ SetMulticastFilter(struct net_device *dev) static u_char de4x5_irq[] = EISA_ALLOWED_IRQ_LIST; -static int __init de4x5_eisa_probe (struct device *gendev) +static int __devinit de4x5_eisa_probe (struct device *gendev) { struct eisa_device *edev; u_long iobase; @@ -2097,7 +2097,7 @@ static int __devexit de4x5_eisa_remove (struct device *device) return 0; } -static struct eisa_device_id de4x5_eisa_ids[] = { +static const struct eisa_device_id de4x5_eisa_ids[] __devinitconst = { { "DEC4250", 0 }, /* 0 is the board name index... */ { "" } }; diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 82653cb07857..119c394f71ce 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -1144,28 +1144,6 @@ typhoon_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) return 0; } -static u32 -typhoon_get_rx_csum(struct net_device *dev) -{ - /* For now, we don't allow turning off RX checksums. - */ - return 1; -} - -static int -typhoon_set_flags(struct net_device *dev, u32 data) -{ - /* There's no way to turn off the RX VLAN offloading and stripping - * on the current 3XP firmware -- it does not respect the offload - * settings -- so we only allow the user to toggle the TX processing. - */ - if (!(data & ETH_FLAG_RXVLAN)) - return -EINVAL; - - return ethtool_op_set_flags(dev, data, - ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN); -} - static void typhoon_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering) { @@ -1187,13 +1165,7 @@ static const struct ethtool_ops typhoon_ethtool_ops = { .get_wol = typhoon_get_wol, .set_wol = typhoon_set_wol, .get_link = ethtool_op_get_link, - .get_rx_csum = typhoon_get_rx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, - .set_sg = ethtool_op_set_sg, - .set_tso = ethtool_op_set_tso, .get_ringparam = typhoon_get_ringparam, - .set_flags = typhoon_set_flags, - .get_flags = ethtool_op_get_flags, }; static int @@ -2482,10 +2454,15 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* We can handle scatter gather, up to 16 entries, and * we can do IP checksumming (only version 4, doh...) + * + * There's no way to turn off the RX VLAN offloading and stripping + * on the current 3XP firmware -- it does not respect the offload + * settings -- so we only allow the user to toggle the TX processing. */ - dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; - dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - dev->features |= NETIF_F_TSO; + dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO | + NETIF_F_HW_VLAN_TX; + dev->features = dev->hw_features | + NETIF_F_HW_VLAN_RX | NETIF_F_RXCSUM; if(register_netdev(dev) < 0) { err_msg = "unable to register netdev"; diff --git a/drivers/net/ucc_geth_ethtool.c b/drivers/net/ucc_geth_ethtool.c index 6f92e48f02d3..537fbc0a4401 100644 --- a/drivers/net/ucc_geth_ethtool.c +++ b/drivers/net/ucc_geth_ethtool.c @@ -410,7 +410,6 @@ static const struct ethtool_ops uec_ethtool_ops = { .set_ringparam = uec_set_ringparam, .get_pauseparam = uec_get_pauseparam, .set_pauseparam = uec_set_pauseparam, - .set_sg = ethtool_op_set_sg, .get_sset_count = uec_get_sset_count, .get_strings = uec_get_strings, .get_ethtool_stats = uec_get_ethtool_stats, diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig index 3ec22c307797..9d4f9117260f 100644 --- a/drivers/net/usb/Kconfig +++ b/drivers/net/usb/Kconfig @@ -258,7 +258,7 @@ config USB_NET_NET1080 optionally with LEDs that indicate traffic config USB_NET_PLUSB - tristate "Prolific PL-2301/2302 based cables" + tristate "Prolific PL-2301/2302/25A1 based cables" # if the handshake/init/reset problems, from original 'plusb', # are ever resolved ... then remove "experimental" depends on USB_USBNET && EXPERIMENTAL diff --git a/drivers/net/usb/plusb.c b/drivers/net/usb/plusb.c index 823c53751307..217aec8a768f 100644 --- a/drivers/net/usb/plusb.c +++ b/drivers/net/usb/plusb.c @@ -45,6 +45,14 @@ * seems to get wedged under load. Prolific docs are weak, and * don't identify differences between PL2301 and PL2302, much less * anything to explain the different PL2302 versions observed. + * + * NOTE: pl2501 has several modes, including pl2301 and pl2302 + * compatibility. Some docs suggest the difference between 2301 + * and 2302 is only to make MS-Windows use a different driver... + * + * pl25a1 glue based on patch from Tony Gibbs. Prolific "docs" on + * this chip are as usual incomplete about what control messages + * are supported. */ /* @@ -86,16 +94,20 @@ pl_set_QuickLink_features(struct usbnet *dev, int val) static int pl_reset(struct usbnet *dev) { + int status; + /* some units seem to need this reset, others reject it utterly. * FIXME be more like "naplink" or windows drivers. */ - (void) pl_set_QuickLink_features(dev, + status = pl_set_QuickLink_features(dev, PL_S_EN|PL_RESET_OUT|PL_RESET_IN|PL_PEER_E); + if (status != 0 && netif_msg_probe(dev)) + netif_dbg(dev, link, dev->net, "pl_reset --> %d\n", status); return 0; } static const struct driver_info prolific_info = { - .description = "Prolific PL-2301/PL-2302", + .description = "Prolific PL-2301/PL-2302/PL-25A1", .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT, /* some PL-2302 versions seem to fail usb_set_interface() */ .reset = pl_reset, @@ -111,6 +123,7 @@ static const struct driver_info prolific_info = { static const struct usb_device_id products [] = { +/* full speed cables */ { USB_DEVICE(0x067b, 0x0000), // PL-2301 .driver_info = (unsigned long) &prolific_info, @@ -119,6 +132,15 @@ static const struct usb_device_id products [] = { .driver_info = (unsigned long) &prolific_info, }, +/* high speed cables */ +{ + USB_DEVICE(0x067b, 0x25a1), /* PL-25A1, no eeprom */ + .driver_info = (unsigned long) &prolific_info, +}, { + USB_DEVICE(0x050d, 0x258a), /* Belkin F5U258/F5U279 (PL-25A1) */ + .driver_info = (unsigned long) &prolific_info, +}, + { }, // END }; MODULE_DEVICE_TABLE(usb, products); @@ -134,16 +156,16 @@ static struct usb_driver plusb_driver = { static int __init plusb_init(void) { - return usb_register(&plusb_driver); + return usb_register(&plusb_driver); } module_init(plusb_init); static void __exit plusb_exit(void) { - usb_deregister(&plusb_driver); + usb_deregister(&plusb_driver); } module_exit(plusb_exit); MODULE_AUTHOR("David Brownell"); -MODULE_DESCRIPTION("Prolific PL-2301/2302 USB Host to Host Link Driver"); +MODULE_DESCRIPTION("Prolific PL-2301/2302/25A1 USB Host to Host Link Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c index 5994a25c56ac..255d6a424a6b 100644 --- a/drivers/net/usb/rndis_host.c +++ b/drivers/net/usb/rndis_host.c @@ -104,8 +104,10 @@ static void rndis_msg_indicate(struct usbnet *dev, struct rndis_indicate *msg, int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen) { struct cdc_state *info = (void *) &dev->data; + struct usb_cdc_notification notification; int master_ifnum; int retval; + int partial; unsigned count; __le32 rsp; u32 xid = 0, msg_len, request_id; @@ -133,13 +135,20 @@ int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen) if (unlikely(retval < 0 || xid == 0)) return retval; - // FIXME Seems like some devices discard responses when - // we time out and cancel our "get response" requests... - // so, this is fragile. Probably need to poll for status. + /* Some devices don't respond on the control channel until + * polled on the status channel, so do that first. */ + if (dev->driver_info->data & RNDIS_DRIVER_DATA_POLL_STATUS) { + retval = usb_interrupt_msg( + dev->udev, + usb_rcvintpipe(dev->udev, + dev->status->desc.bEndpointAddress), + ¬ification, sizeof(notification), &partial, + RNDIS_CONTROL_TIMEOUT_MS); + if (unlikely(retval < 0)) + return retval; + } - /* ignore status endpoint, just poll the control channel; - * the request probably completed immediately - */ + /* Poll the control channel; the request probably completed immediately */ rsp = buf->msg_type | RNDIS_MSG_COMPLETION; for (count = 0; count < 10; count++) { memset(buf, 0, CONTROL_BUFFER_SIZE); @@ -581,17 +590,33 @@ static const struct driver_info rndis_info = { .tx_fixup = rndis_tx_fixup, }; +static const struct driver_info rndis_poll_status_info = { + .description = "RNDIS device (poll status before control)", + .flags = FLAG_ETHER | FLAG_POINTTOPOINT | FLAG_FRAMING_RN | FLAG_NO_SETINT, + .data = RNDIS_DRIVER_DATA_POLL_STATUS, + .bind = rndis_bind, + .unbind = rndis_unbind, + .status = rndis_status, + .rx_fixup = rndis_rx_fixup, + .tx_fixup = rndis_tx_fixup, +}; + /*-------------------------------------------------------------------------*/ static const struct usb_device_id products [] = { { + /* 2Wire HomePortal 1000SW */ + USB_DEVICE_AND_INTERFACE_INFO(0x1630, 0x0042, + USB_CLASS_COMM, 2 /* ACM */, 0x0ff), + .driver_info = (unsigned long) &rndis_poll_status_info, +}, { /* RNDIS is MSFT's un-official variant of CDC ACM */ USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff), .driver_info = (unsigned long) &rndis_info, }, { /* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */ USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1), - .driver_info = (unsigned long) &rndis_info, + .driver_info = (unsigned long) &rndis_poll_status_info, }, { /* RNDIS for tethering */ USB_INTERFACE_INFO(USB_CLASS_WIRELESS_CONTROLLER, 1, 3), diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c index 753ee6eb7edd..860a20c938b4 100644 --- a/drivers/net/usb/smsc75xx.c +++ b/drivers/net/usb/smsc75xx.c @@ -65,7 +65,6 @@ struct smsc75xx_priv { struct usbnet *dev; u32 rfe_ctl; u32 multicast_hash_table[DP_SEL_VHF_HASH_LEN]; - bool use_rx_csum; struct mutex dataport_mutex; spinlock_t rfe_ctl_lock; struct work_struct set_multicast; @@ -548,28 +547,6 @@ static void smsc75xx_status(struct usbnet *dev, struct urb *urb) "unexpected interrupt, intdata=0x%08X", intdata); } -/* Enable or disable Rx checksum offload engine */ -static int smsc75xx_set_rx_csum_offload(struct usbnet *dev) -{ - struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); - unsigned long flags; - int ret; - - spin_lock_irqsave(&pdata->rfe_ctl_lock, flags); - - if (pdata->use_rx_csum) - pdata->rfe_ctl |= RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM; - else - pdata->rfe_ctl &= ~(RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM); - - spin_unlock_irqrestore(&pdata->rfe_ctl_lock, flags); - - ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl); - check_warn_return(ret, "Error writing RFE_CTL"); - - return 0; -} - static int smsc75xx_ethtool_get_eeprom_len(struct net_device *net) { return MAX_EEPROM_SIZE; @@ -599,34 +576,6 @@ static int smsc75xx_ethtool_set_eeprom(struct net_device *netdev, return smsc75xx_write_eeprom(dev, ee->offset, ee->len, data); } -static u32 smsc75xx_ethtool_get_rx_csum(struct net_device *netdev) -{ - struct usbnet *dev = netdev_priv(netdev); - struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); - - return pdata->use_rx_csum; -} - -static int smsc75xx_ethtool_set_rx_csum(struct net_device *netdev, u32 val) -{ - struct usbnet *dev = netdev_priv(netdev); - struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); - - pdata->use_rx_csum = !!val; - - return smsc75xx_set_rx_csum_offload(dev); -} - -static int smsc75xx_ethtool_set_tso(struct net_device *netdev, u32 data) -{ - if (data) - netdev->features |= NETIF_F_TSO | NETIF_F_TSO6; - else - netdev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); - - return 0; -} - static const struct ethtool_ops smsc75xx_ethtool_ops = { .get_link = usbnet_get_link, .nway_reset = usbnet_nway_reset, @@ -638,12 +587,6 @@ static const struct ethtool_ops smsc75xx_ethtool_ops = { .get_eeprom_len = smsc75xx_ethtool_get_eeprom_len, .get_eeprom = smsc75xx_ethtool_get_eeprom, .set_eeprom = smsc75xx_ethtool_set_eeprom, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_hw_csum, - .get_rx_csum = smsc75xx_ethtool_get_rx_csum, - .set_rx_csum = smsc75xx_ethtool_set_rx_csum, - .get_tso = ethtool_op_get_tso, - .set_tso = smsc75xx_ethtool_set_tso, }; static int smsc75xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) @@ -782,6 +725,30 @@ static int smsc75xx_change_mtu(struct net_device *netdev, int new_mtu) return usbnet_change_mtu(netdev, new_mtu); } +/* Enable or disable Rx checksum offload engine */ +static int smsc75xx_set_features(struct net_device *netdev, u32 features) +{ + struct usbnet *dev = netdev_priv(netdev); + struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); + unsigned long flags; + int ret; + + spin_lock_irqsave(&pdata->rfe_ctl_lock, flags); + + if (features & NETIF_F_RXCSUM) + pdata->rfe_ctl |= RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM; + else + pdata->rfe_ctl &= ~(RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM); + + spin_unlock_irqrestore(&pdata->rfe_ctl_lock, flags); + /* it's racing here! */ + + ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl); + check_warn_return(ret, "Error writing RFE_CTL"); + + return 0; +} + static int smsc75xx_reset(struct usbnet *dev) { struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); @@ -960,11 +927,7 @@ static int smsc75xx_reset(struct usbnet *dev) netif_dbg(dev, ifup, dev->net, "RFE_CTL set to 0x%08x", pdata->rfe_ctl); /* Enable or disable checksum offload engines */ - ethtool_op_set_tx_hw_csum(dev->net, DEFAULT_TX_CSUM_ENABLE); - ret = smsc75xx_set_rx_csum_offload(dev); - check_warn_return(ret, "Failed to set rx csum offload: %d", ret); - - smsc75xx_ethtool_set_tso(dev->net, DEFAULT_TSO_ENABLE); + smsc75xx_set_features(dev->net, dev->net->features); smsc75xx_set_multicast(dev->net); @@ -1037,6 +1000,7 @@ static const struct net_device_ops smsc75xx_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_do_ioctl = smsc75xx_ioctl, .ndo_set_multicast_list = smsc75xx_set_multicast, + .ndo_set_features = smsc75xx_set_features, }; static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf) @@ -1065,10 +1029,17 @@ static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf) INIT_WORK(&pdata->set_multicast, smsc75xx_deferred_multicast_write); - pdata->use_rx_csum = DEFAULT_RX_CSUM_ENABLE; + if (DEFAULT_TX_CSUM_ENABLE) { + dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + if (DEFAULT_TSO_ENABLE) + dev->net->features |= NETIF_F_SG | + NETIF_F_TSO | NETIF_F_TSO6; + } + if (DEFAULT_RX_CSUM_ENABLE) + dev->net->features |= NETIF_F_RXCSUM; - /* We have to advertise SG otherwise TSO cannot be enabled */ - dev->net->features |= NETIF_F_SG; + dev->net->hw_features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_RXCSUM; /* Init all registers */ ret = smsc75xx_reset(dev); @@ -1091,10 +1062,11 @@ static void smsc75xx_unbind(struct usbnet *dev, struct usb_interface *intf) } } -static void smsc75xx_rx_csum_offload(struct sk_buff *skb, u32 rx_cmd_a, - u32 rx_cmd_b) +static void smsc75xx_rx_csum_offload(struct usbnet *dev, struct sk_buff *skb, + u32 rx_cmd_a, u32 rx_cmd_b) { - if (unlikely(rx_cmd_a & RX_CMD_A_LCSM)) { + if (!(dev->net->features & NETIF_F_RXCSUM) || + unlikely(rx_cmd_a & RX_CMD_A_LCSM)) { skb->ip_summed = CHECKSUM_NONE; } else { skb->csum = ntohs((u16)(rx_cmd_b >> RX_CMD_B_CSUM_SHIFT)); @@ -1104,8 +1076,6 @@ static void smsc75xx_rx_csum_offload(struct sk_buff *skb, u32 rx_cmd_a, static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) { - struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); - while (skb->len > 0) { u32 rx_cmd_a, rx_cmd_b, align_count, size; struct sk_buff *ax_skb; @@ -1145,11 +1115,8 @@ static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) /* last frame in this batch */ if (skb->len == size) { - if (pdata->use_rx_csum) - smsc75xx_rx_csum_offload(skb, rx_cmd_a, - rx_cmd_b); - else - skb->ip_summed = CHECKSUM_NONE; + smsc75xx_rx_csum_offload(dev, skb, rx_cmd_a, + rx_cmd_b); skb_trim(skb, skb->len - 4); /* remove fcs */ skb->truesize = size + sizeof(struct sk_buff); @@ -1167,11 +1134,8 @@ static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) ax_skb->data = packet; skb_set_tail_pointer(ax_skb, size); - if (pdata->use_rx_csum) - smsc75xx_rx_csum_offload(ax_skb, rx_cmd_a, - rx_cmd_b); - else - ax_skb->ip_summed = CHECKSUM_NONE; + smsc75xx_rx_csum_offload(dev, ax_skb, rx_cmd_a, + rx_cmd_b); skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */ ax_skb->truesize = size + sizeof(struct sk_buff); diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index 47a6c870b51f..24f4b3739dd2 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -52,8 +52,6 @@ struct smsc95xx_priv { u32 hash_hi; u32 hash_lo; spinlock_t mac_cr_lock; - bool use_tx_csum; - bool use_rx_csum; }; struct usb_context { @@ -517,22 +515,24 @@ static void smsc95xx_status(struct usbnet *dev, struct urb *urb) } /* Enable or disable Tx & Rx checksum offload engines */ -static int smsc95xx_set_csums(struct usbnet *dev) +static int smsc95xx_set_features(struct net_device *netdev, u32 features) { - struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); + struct usbnet *dev = netdev_priv(netdev); u32 read_buf; - int ret = smsc95xx_read_reg(dev, COE_CR, &read_buf); + int ret; + + ret = smsc95xx_read_reg(dev, COE_CR, &read_buf); if (ret < 0) { netdev_warn(dev->net, "Failed to read COE_CR: %d\n", ret); return ret; } - if (pdata->use_tx_csum) + if (features & NETIF_F_HW_CSUM) read_buf |= Tx_COE_EN_; else read_buf &= ~Tx_COE_EN_; - if (pdata->use_rx_csum) + if (features & NETIF_F_RXCSUM) read_buf |= Rx_COE_EN_; else read_buf &= ~Rx_COE_EN_; @@ -576,43 +576,6 @@ static int smsc95xx_ethtool_set_eeprom(struct net_device *netdev, return smsc95xx_write_eeprom(dev, ee->offset, ee->len, data); } -static u32 smsc95xx_ethtool_get_rx_csum(struct net_device *netdev) -{ - struct usbnet *dev = netdev_priv(netdev); - struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); - - return pdata->use_rx_csum; -} - -static int smsc95xx_ethtool_set_rx_csum(struct net_device *netdev, u32 val) -{ - struct usbnet *dev = netdev_priv(netdev); - struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); - - pdata->use_rx_csum = !!val; - - return smsc95xx_set_csums(dev); -} - -static u32 smsc95xx_ethtool_get_tx_csum(struct net_device *netdev) -{ - struct usbnet *dev = netdev_priv(netdev); - struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); - - return pdata->use_tx_csum; -} - -static int smsc95xx_ethtool_set_tx_csum(struct net_device *netdev, u32 val) -{ - struct usbnet *dev = netdev_priv(netdev); - struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); - - pdata->use_tx_csum = !!val; - - ethtool_op_set_tx_hw_csum(netdev, pdata->use_tx_csum); - return smsc95xx_set_csums(dev); -} - static const struct ethtool_ops smsc95xx_ethtool_ops = { .get_link = usbnet_get_link, .nway_reset = usbnet_nway_reset, @@ -624,10 +587,6 @@ static const struct ethtool_ops smsc95xx_ethtool_ops = { .get_eeprom_len = smsc95xx_ethtool_get_eeprom_len, .get_eeprom = smsc95xx_ethtool_get_eeprom, .set_eeprom = smsc95xx_ethtool_set_eeprom, - .get_tx_csum = smsc95xx_ethtool_get_tx_csum, - .set_tx_csum = smsc95xx_ethtool_set_tx_csum, - .get_rx_csum = smsc95xx_ethtool_get_rx_csum, - .set_rx_csum = smsc95xx_ethtool_set_rx_csum, }; static int smsc95xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) @@ -755,7 +714,6 @@ static int smsc95xx_phy_initialize(struct usbnet *dev) static int smsc95xx_reset(struct usbnet *dev) { struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); - struct net_device *netdev = dev->net; u32 read_buf, write_buf, burst_cap; int ret = 0, timeout; @@ -975,12 +933,7 @@ static int smsc95xx_reset(struct usbnet *dev) } /* Enable or disable checksum offload engines */ - ethtool_op_set_tx_hw_csum(netdev, pdata->use_tx_csum); - ret = smsc95xx_set_csums(dev); - if (ret < 0) { - netdev_warn(dev->net, "Failed to set csum offload: %d\n", ret); - return ret; - } + smsc95xx_set_features(dev->net, dev->net->features); smsc95xx_set_multicast(dev->net); @@ -1019,6 +972,7 @@ static const struct net_device_ops smsc95xx_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_do_ioctl = smsc95xx_ioctl, .ndo_set_multicast_list = smsc95xx_set_multicast, + .ndo_set_features = smsc95xx_set_features, }; static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf) @@ -1045,8 +999,12 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf) spin_lock_init(&pdata->mac_cr_lock); - pdata->use_tx_csum = DEFAULT_TX_CSUM_ENABLE; - pdata->use_rx_csum = DEFAULT_RX_CSUM_ENABLE; + if (DEFAULT_TX_CSUM_ENABLE) + dev->net->features |= NETIF_F_HW_CSUM; + if (DEFAULT_RX_CSUM_ENABLE) + dev->net->features |= NETIF_F_RXCSUM; + + dev->net->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM; smsc95xx_init_mac_address(dev); @@ -1056,7 +1014,7 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf) dev->net->netdev_ops = &smsc95xx_netdev_ops; dev->net->ethtool_ops = &smsc95xx_ethtool_ops; dev->net->flags |= IFF_MULTICAST; - dev->net->hard_header_len += SMSC95XX_TX_OVERHEAD; + dev->net->hard_header_len += SMSC95XX_TX_OVERHEAD_CSUM; return 0; } @@ -1080,8 +1038,6 @@ static void smsc95xx_rx_csum_offload(struct sk_buff *skb) static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) { - struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); - while (skb->len > 0) { u32 header, align_count; struct sk_buff *ax_skb; @@ -1123,7 +1079,7 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) /* last frame in this batch */ if (skb->len == size) { - if (pdata->use_rx_csum) + if (dev->net->features & NETIF_F_RXCSUM) smsc95xx_rx_csum_offload(skb); skb_trim(skb, skb->len - 4); /* remove fcs */ skb->truesize = size + sizeof(struct sk_buff); @@ -1141,7 +1097,7 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) ax_skb->data = packet; skb_set_tail_pointer(ax_skb, size); - if (pdata->use_rx_csum) + if (dev->net->features & NETIF_F_RXCSUM) smsc95xx_rx_csum_offload(ax_skb); skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */ ax_skb->truesize = size + sizeof(struct sk_buff); @@ -1174,8 +1130,7 @@ static u32 smsc95xx_calc_csum_preamble(struct sk_buff *skb) static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) { - struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); - bool csum = pdata->use_tx_csum && (skb->ip_summed == CHECKSUM_PARTIAL); + bool csum = skb->ip_summed == CHECKSUM_PARTIAL; int overhead = csum ? SMSC95XX_TX_OVERHEAD_CSUM : SMSC95XX_TX_OVERHEAD; u32 tx_cmd_a, tx_cmd_b; diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 069c1cf0fdf7..7bc9852bd57c 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1529,9 +1529,9 @@ EXPORT_SYMBOL_GPL(usbnet_resume); static int __init usbnet_init(void) { - /* compiler should optimize this out */ - BUILD_BUG_ON (sizeof (((struct sk_buff *)0)->cb) - < sizeof (struct skb_data)); + /* Compiler should optimize this out. */ + BUILD_BUG_ON( + FIELD_SIZEOF(struct sk_buff, cb) < sizeof(struct skb_data)); random_ether_addr(node_id); return 0; diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 2de9b90c5f8f..654228849951 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -36,7 +36,6 @@ struct veth_net_stats { struct veth_priv { struct net_device *peer; struct veth_net_stats __percpu *stats; - unsigned ip_summed; }; /* @@ -99,47 +98,10 @@ static void veth_get_ethtool_stats(struct net_device *dev, data[0] = priv->peer->ifindex; } -static u32 veth_get_rx_csum(struct net_device *dev) -{ - struct veth_priv *priv; - - priv = netdev_priv(dev); - return priv->ip_summed == CHECKSUM_UNNECESSARY; -} - -static int veth_set_rx_csum(struct net_device *dev, u32 data) -{ - struct veth_priv *priv; - - priv = netdev_priv(dev); - priv->ip_summed = data ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE; - return 0; -} - -static u32 veth_get_tx_csum(struct net_device *dev) -{ - return (dev->features & NETIF_F_NO_CSUM) != 0; -} - -static int veth_set_tx_csum(struct net_device *dev, u32 data) -{ - if (data) - dev->features |= NETIF_F_NO_CSUM; - else - dev->features &= ~NETIF_F_NO_CSUM; - return 0; -} - static const struct ethtool_ops veth_ethtool_ops = { .get_settings = veth_get_settings, .get_drvinfo = veth_get_drvinfo, .get_link = ethtool_op_get_link, - .get_rx_csum = veth_get_rx_csum, - .set_rx_csum = veth_set_rx_csum, - .get_tx_csum = veth_get_tx_csum, - .set_tx_csum = veth_set_tx_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, .get_strings = veth_get_strings, .get_sset_count = veth_get_sset_count, .get_ethtool_stats = veth_get_ethtool_stats, @@ -168,8 +130,9 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev) /* don't change ip_summed == CHECKSUM_PARTIAL, as that will cause bad checksum on forwarded packets */ - if (skb->ip_summed == CHECKSUM_NONE) - skb->ip_summed = rcv_priv->ip_summed; + if (skb->ip_summed == CHECKSUM_NONE && + rcv->features & NETIF_F_RXCSUM) + skb->ip_summed = CHECKSUM_UNNECESSARY; length = skb->len; if (dev_forward_skb(rcv, skb) != NET_RX_SUCCESS) @@ -304,6 +267,8 @@ static void veth_setup(struct net_device *dev) dev->ethtool_ops = &veth_ethtool_ops; dev->features |= NETIF_F_LLTX; dev->destructor = veth_dev_free; + + dev->hw_features = NETIF_F_NO_CSUM | NETIF_F_SG | NETIF_F_RXCSUM; } /* diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index eb5d75df5d5d..7f23ab913fd9 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -29,6 +29,8 @@ */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define DRV_NAME "via-rhine" #define DRV_VERSION "1.5.0" #define DRV_RELDATE "2010-10-09" @@ -37,6 +39,7 @@ /* A few user-configurable values. These may be modified when a driver module is loaded. */ +#define DEBUG static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ static int max_interrupt_work = 20; @@ -111,8 +114,7 @@ static const int multicast_filter_limit = 32; /* These identify the driver base version and may not be removed. */ static const char version[] __devinitconst = - KERN_INFO DRV_NAME ".c:v1.10-LK" DRV_VERSION " " DRV_RELDATE - " Written by Donald Becker\n"; + "v1.10-LK" DRV_VERSION " " DRV_RELDATE " Written by Donald Becker"; /* This driver was written to use PCI memory space. Some early versions of the Rhine may only work correctly with I/O space accesses. */ @@ -495,14 +497,15 @@ static void rhine_set_vlan_cam_mask(void __iomem *ioaddr, u32 mask); static void rhine_init_cam_filter(struct net_device *dev); static void rhine_update_vcam(struct net_device *dev); -#define RHINE_WAIT_FOR(condition) do { \ - int i=1024; \ - while (!(condition) && --i) \ - ; \ - if (debug > 1 && i < 512) \ - printk(KERN_INFO "%s: %4d cycles used @ %s:%d\n", \ - DRV_NAME, 1024-i, __func__, __LINE__); \ -} while(0) +#define RHINE_WAIT_FOR(condition) \ +do { \ + int i = 1024; \ + while (!(condition) && --i) \ + ; \ + if (debug > 1 && i < 512) \ + pr_info("%4d cycles used @ %s:%d\n", \ + 1024 - i, __func__, __LINE__); \ +} while (0) static inline u32 get_intr_status(struct net_device *dev) { @@ -571,8 +574,8 @@ static void rhine_power_init(struct net_device *dev) default: reason = "Unknown"; } - printk(KERN_INFO "%s: Woke system up. Reason: %s.\n", - DRV_NAME, reason); + netdev_info(dev, "Woke system up. Reason: %s\n", + reason); } } } @@ -586,8 +589,7 @@ static void rhine_chip_reset(struct net_device *dev) IOSYNC; if (ioread8(ioaddr + ChipCmd1) & Cmd1Reset) { - printk(KERN_INFO "%s: Reset not complete yet. " - "Trying harder.\n", DRV_NAME); + netdev_info(dev, "Reset not complete yet. Trying harder.\n"); /* Force reset */ if (rp->quirks & rqForceReset) @@ -598,9 +600,9 @@ static void rhine_chip_reset(struct net_device *dev) } if (debug > 1) - printk(KERN_INFO "%s: Reset %s.\n", dev->name, - (ioread8(ioaddr + ChipCmd1) & Cmd1Reset) ? - "failed" : "succeeded"); + netdev_info(dev, "Reset %s\n", + (ioread8(ioaddr + ChipCmd1) & Cmd1Reset) ? + "failed" : "succeeded"); } #ifdef USE_MMIO @@ -728,9 +730,7 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, /* when built into the kernel, we only print version if device is found */ #ifndef MODULE - static int printed_version; - if (!printed_version++) - printk(version); + pr_info_once("%s\n", version); #endif io_size = 256; @@ -765,8 +765,8 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, /* this should always be supported */ rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (rc) { - printk(KERN_ERR "32-bit PCI DMA addresses not supported by " - "the card!?\n"); + dev_err(&pdev->dev, + "32-bit PCI DMA addresses not supported by the card!?\n"); goto err_out; } @@ -774,7 +774,7 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, if ((pci_resource_len(pdev, 0) < io_size) || (pci_resource_len(pdev, 1) < io_size)) { rc = -EIO; - printk(KERN_ERR "Insufficient PCI resources, aborting\n"); + dev_err(&pdev->dev, "Insufficient PCI resources, aborting\n"); goto err_out; } @@ -786,7 +786,7 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, dev = alloc_etherdev(sizeof(struct rhine_private)); if (!dev) { rc = -ENOMEM; - printk(KERN_ERR "alloc_etherdev failed\n"); + dev_err(&pdev->dev, "alloc_etherdev failed\n"); goto err_out; } SET_NETDEV_DEV(dev, &pdev->dev); @@ -804,8 +804,9 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, ioaddr = pci_iomap(pdev, bar, io_size); if (!ioaddr) { rc = -EIO; - printk(KERN_ERR "ioremap failed for device %s, region 0x%X " - "@ 0x%lX\n", pci_name(pdev), io_size, memaddr); + dev_err(&pdev->dev, + "ioremap failed for device %s, region 0x%X @ 0x%lX\n", + pci_name(pdev), io_size, memaddr); goto err_out_free_res; } @@ -820,8 +821,9 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, unsigned char b = readb(ioaddr+reg); if (a != b) { rc = -EIO; - printk(KERN_ERR "MMIO do not match PIO [%02x] " - "(%02x != %02x)\n", reg, a, b); + dev_err(&pdev->dev, + "MMIO do not match PIO [%02x] (%02x != %02x)\n", + reg, a, b); goto err_out_unmap; } } @@ -836,13 +838,15 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, for (i = 0; i < 6; i++) dev->dev_addr[i] = ioread8(ioaddr + StationAddr + i); - memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); - if (!is_valid_ether_addr(dev->perm_addr)) { - rc = -EIO; - printk(KERN_ERR "Invalid MAC address\n"); - goto err_out_unmap; + if (!is_valid_ether_addr(dev->dev_addr)) { + /* Report it and use a random ethernet address instead */ + netdev_err(dev, "Invalid MAC address: %pM\n", dev->dev_addr); + random_ether_addr(dev->dev_addr); + netdev_info(dev, "Using random MAC address: %pM\n", + dev->dev_addr); } + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); /* For Rhine-I/II, phy_id is loaded from EEPROM */ if (!phy_id) @@ -878,14 +882,14 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, if (rc) goto err_out_unmap; - printk(KERN_INFO "%s: VIA %s at 0x%lx, %pM, IRQ %d.\n", - dev->name, name, + netdev_info(dev, "VIA %s at 0x%lx, %pM, IRQ %d\n", + name, #ifdef USE_MMIO - memaddr, + memaddr, #else - (long)ioaddr, + (long)ioaddr, #endif - dev->dev_addr, pdev->irq); + dev->dev_addr, pdev->irq); pci_set_drvdata(pdev, dev); @@ -896,11 +900,11 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, mdio_write(dev, phy_id, MII_BMCR, mii_cmd); if (mii_status != 0xffff && mii_status != 0x0000) { rp->mii_if.advertising = mdio_read(dev, phy_id, 4); - printk(KERN_INFO "%s: MII PHY found at address " - "%d, status 0x%4.4x advertising %4.4x " - "Link %4.4x.\n", dev->name, phy_id, - mii_status, rp->mii_if.advertising, - mdio_read(dev, phy_id, 5)); + netdev_info(dev, + "MII PHY found at address %d, status 0x%04x advertising %04x Link %04x\n", + phy_id, + mii_status, rp->mii_if.advertising, + mdio_read(dev, phy_id, 5)); /* set IFF_RUNNING */ if (mii_status & BMSR_LSTATUS) @@ -912,8 +916,7 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, } rp->mii_if.phy_id = phy_id; if (debug > 1 && avoid_D3) - printk(KERN_INFO "%s: No D3 power state at shutdown.\n", - dev->name); + netdev_info(dev, "No D3 power state at shutdown\n"); return 0; @@ -938,7 +941,7 @@ static int alloc_ring(struct net_device* dev) TX_RING_SIZE * sizeof(struct tx_desc), &ring_dma); if (!ring) { - printk(KERN_ERR "Could not allocate DMA memory.\n"); + netdev_err(dev, "Could not allocate DMA memory\n"); return -ENOMEM; } if (rp->quirks & rqRhineI) { @@ -1098,8 +1101,8 @@ static void rhine_check_media(struct net_device *dev, unsigned int init_media) iowrite8(ioread8(ioaddr + ChipCmd1) & ~Cmd1FDuplex, ioaddr + ChipCmd1); if (debug > 1) - printk(KERN_INFO "%s: force_media %d, carrier %d\n", dev->name, - rp->mii_if.force_media, netif_carrier_ok(dev)); + netdev_info(dev, "force_media %d, carrier %d\n", + rp->mii_if.force_media, netif_carrier_ok(dev)); } /* Called after status of force_media possibly changed */ @@ -1113,9 +1116,8 @@ static void rhine_set_carrier(struct mii_if_info *mii) else /* Let MMI library update carrier status */ rhine_check_media(mii->dev, 0); if (debug > 1) - printk(KERN_INFO "%s: force_media %d, carrier %d\n", - mii->dev->name, mii->force_media, - netif_carrier_ok(mii->dev)); + netdev_info(mii->dev, "force_media %d, carrier %d\n", + mii->force_media, netif_carrier_ok(mii->dev)); } /** @@ -1402,8 +1404,7 @@ static int rhine_open(struct net_device *dev) return rc; if (debug > 1) - printk(KERN_DEBUG "%s: rhine_open() irq %d.\n", - dev->name, rp->pdev->irq); + netdev_dbg(dev, "%s() irq %d\n", __func__, rp->pdev->irq); rc = alloc_ring(dev); if (rc) { @@ -1415,10 +1416,9 @@ static int rhine_open(struct net_device *dev) rhine_chip_reset(dev); init_registers(dev); if (debug > 2) - printk(KERN_DEBUG "%s: Done rhine_open(), status %4.4x " - "MII status: %4.4x.\n", - dev->name, ioread16(ioaddr + ChipCmd), - mdio_read(dev, rp->mii_if.phy_id, MII_BMSR)); + netdev_dbg(dev, "%s() Done - status %04x MII status: %04x\n", + __func__, ioread16(ioaddr + ChipCmd), + mdio_read(dev, rp->mii_if.phy_id, MII_BMSR)); netif_start_queue(dev); @@ -1461,10 +1461,9 @@ static void rhine_tx_timeout(struct net_device *dev) struct rhine_private *rp = netdev_priv(dev); void __iomem *ioaddr = rp->base; - printk(KERN_WARNING "%s: Transmit timed out, status %4.4x, PHY status " - "%4.4x, resetting...\n", - dev->name, ioread16(ioaddr + IntrStatus), - mdio_read(dev, rp->mii_if.phy_id, MII_BMSR)); + netdev_warn(dev, "Transmit timed out, status %04x, PHY status %04x, resetting...\n", + ioread16(ioaddr + IntrStatus), + mdio_read(dev, rp->mii_if.phy_id, MII_BMSR)); schedule_work(&rp->reset_task); } @@ -1551,8 +1550,8 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb, spin_unlock_irqrestore(&rp->lock, flags); if (debug > 4) { - printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n", - dev->name, rp->cur_tx-1, entry); + netdev_dbg(dev, "Transmit frame #%d queued in slot %d\n", + rp->cur_tx-1, entry); } return NETDEV_TX_OK; } @@ -1578,8 +1577,8 @@ static irqreturn_t rhine_interrupt(int irq, void *dev_instance) IOSYNC; if (debug > 4) - printk(KERN_DEBUG "%s: Interrupt, status %8.8x.\n", - dev->name, intr_status); + netdev_dbg(dev, "Interrupt, status %08x\n", + intr_status); if (intr_status & (IntrRxDone | IntrRxErr | IntrRxDropped | IntrRxWakeUp | IntrRxEmpty | IntrRxNoBuf)) { @@ -1597,9 +1596,9 @@ static irqreturn_t rhine_interrupt(int irq, void *dev_instance) RHINE_WAIT_FOR(!(ioread8(ioaddr+ChipCmd) & CmdTxOn)); if (debug > 2 && ioread8(ioaddr+ChipCmd) & CmdTxOn) - printk(KERN_WARNING "%s: " - "rhine_interrupt() Tx engine " - "still on.\n", dev->name); + netdev_warn(dev, + "%s: Tx engine still on\n", + __func__); } rhine_tx(dev); } @@ -1611,16 +1610,15 @@ static irqreturn_t rhine_interrupt(int irq, void *dev_instance) rhine_error(dev, intr_status); if (--boguscnt < 0) { - printk(KERN_WARNING "%s: Too much work at interrupt, " - "status=%#8.8x.\n", - dev->name, intr_status); + netdev_warn(dev, "Too much work at interrupt, status=%#08x\n", + intr_status); break; } } if (debug > 3) - printk(KERN_DEBUG "%s: exiting interrupt, status=%8.8x.\n", - dev->name, ioread16(ioaddr + IntrStatus)); + netdev_dbg(dev, "exiting interrupt, status=%08x\n", + ioread16(ioaddr + IntrStatus)); return IRQ_RETVAL(handled); } @@ -1637,15 +1635,14 @@ static void rhine_tx(struct net_device *dev) while (rp->dirty_tx != rp->cur_tx) { txstatus = le32_to_cpu(rp->tx_ring[entry].tx_status); if (debug > 6) - printk(KERN_DEBUG "Tx scavenge %d status %8.8x.\n", - entry, txstatus); + netdev_dbg(dev, "Tx scavenge %d status %08x\n", + entry, txstatus); if (txstatus & DescOwn) break; if (txstatus & 0x8000) { if (debug > 1) - printk(KERN_DEBUG "%s: Transmit error, " - "Tx status %8.8x.\n", - dev->name, txstatus); + netdev_dbg(dev, "Transmit error, Tx status %08x\n", + txstatus); dev->stats.tx_errors++; if (txstatus & 0x0400) dev->stats.tx_carrier_errors++; @@ -1668,9 +1665,9 @@ static void rhine_tx(struct net_device *dev) else dev->stats.collisions += txstatus & 0x0F; if (debug > 6) - printk(KERN_DEBUG "collisions: %1.1x:%1.1x\n", - (txstatus >> 3) & 0xF, - txstatus & 0xF); + netdev_dbg(dev, "collisions: %1.1x:%1.1x\n", + (txstatus >> 3) & 0xF, + txstatus & 0xF); dev->stats.tx_bytes += rp->tx_skbuff[entry]->len; dev->stats.tx_packets++; } @@ -1703,7 +1700,7 @@ static void rhine_tx(struct net_device *dev) static inline u16 rhine_get_vlan_tci(struct sk_buff *skb, int data_size) { u8 *trailer = (u8 *)skb->data + ((data_size + 3) & ~3) + 2; - return ntohs(*(u16 *)trailer); + return be16_to_cpup((__be16 *)trailer); } /* Process up to limit frames from receive ring */ @@ -1714,9 +1711,9 @@ static int rhine_rx(struct net_device *dev, int limit) int entry = rp->cur_rx % RX_RING_SIZE; if (debug > 4) { - printk(KERN_DEBUG "%s: rhine_rx(), entry %d status %8.8x.\n", - dev->name, entry, - le32_to_cpu(rp->rx_head_desc->rx_status)); + netdev_dbg(dev, "%s(), entry %d status %08x\n", + __func__, entry, + le32_to_cpu(rp->rx_head_desc->rx_status)); } /* If EOP is set on the next entry, it's a new packet. Send it up. */ @@ -1730,26 +1727,26 @@ static int rhine_rx(struct net_device *dev, int limit) break; if (debug > 4) - printk(KERN_DEBUG "rhine_rx() status is %8.8x.\n", - desc_status); + netdev_dbg(dev, "%s() status is %08x\n", + __func__, desc_status); if ((desc_status & (RxWholePkt | RxErr)) != RxWholePkt) { if ((desc_status & RxWholePkt) != RxWholePkt) { - printk(KERN_WARNING "%s: Oversized Ethernet " - "frame spanned multiple buffers, entry " - "%#x length %d status %8.8x!\n", - dev->name, entry, data_size, - desc_status); - printk(KERN_WARNING "%s: Oversized Ethernet " - "frame %p vs %p.\n", dev->name, - rp->rx_head_desc, &rp->rx_ring[entry]); + netdev_warn(dev, + "Oversized Ethernet frame spanned multiple buffers, " + "entry %#x length %d status %08x!\n", + entry, data_size, + desc_status); + netdev_warn(dev, + "Oversized Ethernet frame %p vs %p\n", + rp->rx_head_desc, + &rp->rx_ring[entry]); dev->stats.rx_length_errors++; } else if (desc_status & RxErr) { /* There was a error. */ if (debug > 2) - printk(KERN_DEBUG "rhine_rx() Rx " - "error was %8.8x.\n", - desc_status); + netdev_dbg(dev, "%s() Rx error was %08x\n", + __func__, desc_status); dev->stats.rx_errors++; if (desc_status & 0x0030) dev->stats.rx_length_errors++; @@ -1791,9 +1788,7 @@ static int rhine_rx(struct net_device *dev, int limit) } else { skb = rp->rx_skbuff[entry]; if (skb == NULL) { - printk(KERN_ERR "%s: Inconsistent Rx " - "descriptor chain.\n", - dev->name); + netdev_err(dev, "Inconsistent Rx descriptor chain\n"); break; } rp->rx_skbuff[entry] = NULL; @@ -1886,9 +1881,8 @@ static void rhine_restart_tx(struct net_device *dev) { else { /* This should never happen */ if (debug > 1) - printk(KERN_WARNING "%s: rhine_restart_tx() " - "Another error occurred %8.8x.\n", - dev->name, intr_status); + netdev_warn(dev, "%s() Another error occurred %08x\n", + __func__, intr_status); } } @@ -1909,21 +1903,19 @@ static void rhine_error(struct net_device *dev, int intr_status) } if (intr_status & IntrTxAborted) { if (debug > 1) - printk(KERN_INFO "%s: Abort %8.8x, frame dropped.\n", - dev->name, intr_status); + netdev_info(dev, "Abort %08x, frame dropped\n", + intr_status); } if (intr_status & IntrTxUnderrun) { if (rp->tx_thresh < 0xE0) BYTE_REG_BITS_SET((rp->tx_thresh += 0x20), 0x80, ioaddr + TxConfig); if (debug > 1) - printk(KERN_INFO "%s: Transmitter underrun, Tx " - "threshold now %2.2x.\n", - dev->name, rp->tx_thresh); + netdev_info(dev, "Transmitter underrun, Tx threshold now %02x\n", + rp->tx_thresh); } if (intr_status & IntrTxDescRace) { if (debug > 2) - printk(KERN_INFO "%s: Tx descriptor write-back race.\n", - dev->name); + netdev_info(dev, "Tx descriptor write-back race\n"); } if ((intr_status & IntrTxError) && (intr_status & (IntrTxAborted | @@ -1932,9 +1924,8 @@ static void rhine_error(struct net_device *dev, int intr_status) BYTE_REG_BITS_SET((rp->tx_thresh += 0x20), 0x80, ioaddr + TxConfig); } if (debug > 1) - printk(KERN_INFO "%s: Unspecified error. Tx " - "threshold now %2.2x.\n", - dev->name, rp->tx_thresh); + netdev_info(dev, "Unspecified error. Tx threshold now %02x\n", + rp->tx_thresh); } if (intr_status & (IntrTxAborted | IntrTxUnderrun | IntrTxDescRace | IntrTxError)) @@ -1944,8 +1935,8 @@ static void rhine_error(struct net_device *dev, int intr_status) IntrTxError | IntrTxAborted | IntrNormalSummary | IntrTxDescRace)) { if (debug > 1) - printk(KERN_ERR "%s: Something Wicked happened! " - "%8.8x.\n", dev->name, intr_status); + netdev_err(dev, "Something Wicked happened! %08x\n", + intr_status); } spin_unlock(&rp->lock); @@ -2145,9 +2136,8 @@ static int rhine_close(struct net_device *dev) spin_lock_irq(&rp->lock); if (debug > 1) - printk(KERN_DEBUG "%s: Shutting down ethercard, " - "status was %4.4x.\n", - dev->name, ioread16(ioaddr + ChipCmd)); + netdev_dbg(dev, "Shutting down ethercard, status was %04x\n", + ioread16(ioaddr + ChipCmd)); /* Switch to loopback mode to avoid hardware races. */ iowrite8(rp->tx_thresh | 0x02, ioaddr + TxConfig); @@ -2265,12 +2255,12 @@ static int rhine_resume(struct pci_dev *pdev) return 0; if (request_irq(dev->irq, rhine_interrupt, IRQF_SHARED, dev->name, dev)) - printk(KERN_ERR "via-rhine %s: request_irq failed\n", dev->name); + netdev_err(dev, "request_irq failed\n"); ret = pci_set_power_state(pdev, PCI_D0); if (debug > 1) - printk(KERN_INFO "%s: Entering power state D0 %s (%d).\n", - dev->name, ret ? "failed" : "succeeded", ret); + netdev_info(dev, "Entering power state D0 %s (%d)\n", + ret ? "failed" : "succeeded", ret); pci_restore_state(pdev); @@ -2326,17 +2316,15 @@ static int __init rhine_init(void) { /* when a module, this is printed whether or not devices are found in probe */ #ifdef MODULE - printk(version); + pr_info("%s\n", version); #endif if (dmi_check_system(rhine_dmi_table)) { /* these BIOSes fail at PXE boot if chip is in D3 */ avoid_D3 = 1; - printk(KERN_WARNING "%s: Broken BIOS detected, avoid_D3 " - "enabled.\n", - DRV_NAME); + pr_warn("Broken BIOS detected, avoid_D3 enabled\n"); } else if (avoid_D3) - printk(KERN_INFO "%s: avoid_D3 set.\n", DRV_NAME); + pr_info("avoid_D3 set\n"); return pci_register_driver(&rhine_driver); } diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 4fe051753842..baf04b0a6575 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -2600,8 +2600,7 @@ static netdev_tx_t velocity_xmit(struct sk_buff *skb, /* * Handle hardware checksum */ - if ((dev->features & NETIF_F_IP_CSUM) && - (skb->ip_summed == CHECKSUM_PARTIAL)) { + if (skb->ip_summed == CHECKSUM_PARTIAL) { const struct iphdr *ip = ip_hdr(skb); if (ip->protocol == IPPROTO_TCP) td_ptr->tdesc1.TCR |= TCR0_TCPCK; @@ -2841,6 +2840,7 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi dev->ethtool_ops = &velocity_ethtool_ops; netif_napi_add(dev, &vptr->napi, velocity_poll, VELOCITY_NAPI_WEIGHT); + dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_HW_VLAN_TX; dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | NETIF_F_HW_VLAN_RX | NETIF_F_IP_CSUM; @@ -3457,13 +3457,10 @@ static const struct ethtool_ops velocity_ethtool_ops = { .get_settings = velocity_get_settings, .set_settings = velocity_set_settings, .get_drvinfo = velocity_get_drvinfo, - .set_tx_csum = ethtool_op_set_tx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, .get_wol = velocity_ethtool_get_wol, .set_wol = velocity_ethtool_set_wol, .get_msglevel = velocity_get_msglevel, .set_msglevel = velocity_set_msglevel, - .set_sg = ethtool_op_set_sg, .get_link = velocity_get_link, .get_coalesce = velocity_get_coalesce, .set_coalesce = velocity_set_coalesce, diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 82dba5aaf423..0cb0b0632672 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -710,17 +710,6 @@ static int virtnet_close(struct net_device *dev) return 0; } -static int virtnet_set_tx_csum(struct net_device *dev, u32 data) -{ - struct virtnet_info *vi = netdev_priv(dev); - struct virtio_device *vdev = vi->vdev; - - if (data && !virtio_has_feature(vdev, VIRTIO_NET_F_CSUM)) - return -ENOSYS; - - return ethtool_op_set_tx_hw_csum(dev, data); -} - static void virtnet_set_rx_mode(struct net_device *dev) { struct virtnet_info *vi = netdev_priv(dev); @@ -822,10 +811,6 @@ static void virtnet_vlan_rx_kill_vid(struct net_device *dev, u16 vid) } static const struct ethtool_ops virtnet_ethtool_ops = { - .set_tx_csum = virtnet_set_tx_csum, - .set_sg = ethtool_op_set_sg, - .set_tso = ethtool_op_set_tso, - .set_ufo = ethtool_op_set_ufo, .get_link = ethtool_op_get_link, }; @@ -912,22 +897,29 @@ static int virtnet_probe(struct virtio_device *vdev) SET_NETDEV_DEV(dev, &vdev->dev); /* Do we support "hardware" checksums? */ - if (csum && virtio_has_feature(vdev, VIRTIO_NET_F_CSUM)) { + if (virtio_has_feature(vdev, VIRTIO_NET_F_CSUM)) { /* This opens up the world of extra features. */ - dev->features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST; - if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) { - dev->features |= NETIF_F_TSO | NETIF_F_UFO + dev->hw_features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST; + if (csum) + dev->features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST; + + if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) { + dev->hw_features |= NETIF_F_TSO | NETIF_F_UFO | NETIF_F_TSO_ECN | NETIF_F_TSO6; } /* Individual feature bits: what can host handle? */ - if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_TSO4)) - dev->features |= NETIF_F_TSO; - if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_TSO6)) - dev->features |= NETIF_F_TSO6; - if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN)) - dev->features |= NETIF_F_TSO_ECN; - if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_UFO)) - dev->features |= NETIF_F_UFO; + if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_TSO4)) + dev->hw_features |= NETIF_F_TSO; + if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_TSO6)) + dev->hw_features |= NETIF_F_TSO6; + if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN)) + dev->hw_features |= NETIF_F_TSO_ECN; + if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_UFO)) + dev->hw_features |= NETIF_F_UFO; + + if (gso) + dev->features |= dev->hw_features & (NETIF_F_ALL_TSO|NETIF_F_UFO); + /* (!csum && gso) case will be fixed by register_netdev() */ } /* Configuration may specify what MAC to use. Otherwise random. */ diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index 0d47c3a05307..7a494f79c88f 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -1082,7 +1082,7 @@ vmxnet3_rx_csum(struct vmxnet3_adapter *adapter, struct sk_buff *skb, union Vmxnet3_GenericDesc *gdesc) { - if (!gdesc->rcd.cnc && adapter->rxcsum) { + if (!gdesc->rcd.cnc && adapter->netdev->features & NETIF_F_RXCSUM) { /* typical case: TCP/UDP over IP and both csums are correct */ if ((le32_to_cpu(gdesc->dword[3]) & VMXNET3_RCD_CSUM_OK) == VMXNET3_RCD_CSUM_OK) { @@ -2081,10 +2081,10 @@ vmxnet3_setup_driver_shared(struct vmxnet3_adapter *adapter) devRead->misc.ddLen = cpu_to_le32(sizeof(struct vmxnet3_adapter)); /* set up feature flags */ - if (adapter->rxcsum) + if (adapter->netdev->features & NETIF_F_RXCSUM) devRead->misc.uptFeatures |= UPT1_F_RXCSUM; - if (adapter->lro) { + if (adapter->netdev->features & NETIF_F_LRO) { devRead->misc.uptFeatures |= UPT1_F_LRO; devRead->misc.maxNumRxSG = cpu_to_le16(1 + MAX_SKB_FRAGS); } @@ -2593,9 +2593,6 @@ vmxnet3_change_mtu(struct net_device *netdev, int new_mtu) if (new_mtu < VMXNET3_MIN_MTU || new_mtu > VMXNET3_MAX_MTU) return -EINVAL; - if (new_mtu > 1500 && !adapter->jumbo_frame) - return -EINVAL; - netdev->mtu = new_mtu; /* @@ -2641,28 +2638,18 @@ vmxnet3_declare_features(struct vmxnet3_adapter *adapter, bool dma64) { struct net_device *netdev = adapter->netdev; - netdev->features = NETIF_F_SG | - NETIF_F_HW_CSUM | - NETIF_F_HW_VLAN_TX | - NETIF_F_HW_VLAN_RX | - NETIF_F_HW_VLAN_FILTER | - NETIF_F_TSO | - NETIF_F_TSO6 | - NETIF_F_LRO; - - printk(KERN_INFO "features: sg csum vlan jf tso tsoIPv6 lro"); - - adapter->rxcsum = true; - adapter->jumbo_frame = true; - adapter->lro = true; - - if (dma64) { + netdev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM | + NETIF_F_HW_CSUM | NETIF_F_HW_VLAN_TX | + NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_LRO; + if (dma64) netdev->features |= NETIF_F_HIGHDMA; - printk(" highDMA"); - } + netdev->vlan_features = netdev->hw_features & ~NETIF_F_HW_VLAN_TX; + netdev->features = netdev->hw_features | + NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; - netdev->vlan_features = netdev->features; - printk("\n"); + netdev_info(adapter->netdev, + "features: sg csum vlan jf tso tsoIPv6 lro%s\n", + dma64 ? " highDMA" : ""); } @@ -2874,6 +2861,7 @@ vmxnet3_probe_device(struct pci_dev *pdev, .ndo_start_xmit = vmxnet3_xmit_frame, .ndo_set_mac_address = vmxnet3_set_mac_addr, .ndo_change_mtu = vmxnet3_change_mtu, + .ndo_set_features = vmxnet3_set_features, .ndo_get_stats = vmxnet3_get_stats, .ndo_tx_timeout = vmxnet3_tx_timeout, .ndo_set_multicast_list = vmxnet3_set_mc, diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c index 51f2ef142a5b..70c1ab96ed27 100644 --- a/drivers/net/vmxnet3/vmxnet3_ethtool.c +++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c @@ -33,40 +33,6 @@ struct vmxnet3_stat_desc { }; -static u32 -vmxnet3_get_rx_csum(struct net_device *netdev) -{ - struct vmxnet3_adapter *adapter = netdev_priv(netdev); - return adapter->rxcsum; -} - - -static int -vmxnet3_set_rx_csum(struct net_device *netdev, u32 val) -{ - struct vmxnet3_adapter *adapter = netdev_priv(netdev); - unsigned long flags; - - if (adapter->rxcsum != val) { - adapter->rxcsum = val; - if (netif_running(netdev)) { - if (val) - adapter->shared->devRead.misc.uptFeatures |= - UPT1_F_RXCSUM; - else - adapter->shared->devRead.misc.uptFeatures &= - ~UPT1_F_RXCSUM; - - spin_lock_irqsave(&adapter->cmd_lock, flags); - VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, - VMXNET3_CMD_UPDATE_FEATURE); - spin_unlock_irqrestore(&adapter->cmd_lock, flags); - } - } - return 0; -} - - /* per tq stats maintained by the device */ static const struct vmxnet3_stat_desc vmxnet3_tq_dev_stats[] = { @@ -296,28 +262,27 @@ vmxnet3_get_strings(struct net_device *netdev, u32 stringset, u8 *buf) } } -static int -vmxnet3_set_flags(struct net_device *netdev, u32 data) +int vmxnet3_set_features(struct net_device *netdev, u32 features) { struct vmxnet3_adapter *adapter = netdev_priv(netdev); - u8 lro_requested = (data & ETH_FLAG_LRO) == 0 ? 0 : 1; - u8 lro_present = (netdev->features & NETIF_F_LRO) == 0 ? 0 : 1; unsigned long flags; + u32 changed = features ^ netdev->features; - if (ethtool_invalid_flags(netdev, data, ETH_FLAG_LRO)) - return -EINVAL; - - if (lro_requested ^ lro_present) { - /* toggle the LRO feature*/ - netdev->features ^= NETIF_F_LRO; + if (changed & (NETIF_F_RXCSUM|NETIF_F_LRO)) { + if (features & NETIF_F_RXCSUM) + adapter->shared->devRead.misc.uptFeatures |= + UPT1_F_RXCSUM; + else + adapter->shared->devRead.misc.uptFeatures &= + ~UPT1_F_RXCSUM; - /* update harware LRO capability accordingly */ - if (lro_requested) + if (features & NETIF_F_LRO) adapter->shared->devRead.misc.uptFeatures |= UPT1_F_LRO; else adapter->shared->devRead.misc.uptFeatures &= ~UPT1_F_LRO; + spin_lock_irqsave(&adapter->cmd_lock, flags); VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_UPDATE_FEATURE); @@ -654,17 +619,7 @@ static struct ethtool_ops vmxnet3_ethtool_ops = { .get_wol = vmxnet3_get_wol, .set_wol = vmxnet3_set_wol, .get_link = ethtool_op_get_link, - .get_rx_csum = vmxnet3_get_rx_csum, - .set_rx_csum = vmxnet3_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_hw_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, - .set_tso = ethtool_op_set_tso, .get_strings = vmxnet3_get_strings, - .get_flags = ethtool_op_get_flags, - .set_flags = vmxnet3_set_flags, .get_sset_count = vmxnet3_get_sset_count, .get_ethtool_stats = vmxnet3_get_ethtool_stats, .get_ringparam = vmxnet3_get_ringparam, diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h index fb5d245ac878..8ba7b5f67de2 100644 --- a/drivers/net/vmxnet3/vmxnet3_int.h +++ b/drivers/net/vmxnet3/vmxnet3_int.h @@ -329,10 +329,6 @@ struct vmxnet3_adapter { u8 __iomem *hw_addr0; /* for BAR 0 */ u8 __iomem *hw_addr1; /* for BAR 1 */ - /* feature control */ - bool rxcsum; - bool lro; - bool jumbo_frame; #ifdef VMXNET3_RSS struct UPT1_RSSConf *rss_conf; bool rss; @@ -404,6 +400,9 @@ void vmxnet3_rq_destroy_all(struct vmxnet3_adapter *adapter); int +vmxnet3_set_features(struct net_device *netdev, u32 features); + +int vmxnet3_create_queues(struct vmxnet3_adapter *adapter, u32 tx_ring_size, u32 rx_ring_size, u32 rx_ring2_size); diff --git a/drivers/net/vxge/vxge-config.c b/drivers/net/vxge/vxge-config.c index 401bebf59502..32763b2dd73f 100644 --- a/drivers/net/vxge/vxge-config.c +++ b/drivers/net/vxge/vxge-config.c @@ -159,16 +159,15 @@ vxge_hw_vpath_fw_api(struct __vxge_hw_virtualpath *vpath, u32 action, u32 fw_memo, u32 offset, u64 *data0, u64 *data1, u64 *steer_ctrl) { - struct vxge_hw_vpath_reg __iomem *vp_reg; + struct vxge_hw_vpath_reg __iomem *vp_reg = vpath->vp_reg; enum vxge_hw_status status; u64 val64; - u32 retry = 0, max_retry = 100; - - vp_reg = vpath->vp_reg; + u32 retry = 0, max_retry = 3; - if (vpath->vp_open) { - max_retry = 3; - spin_lock(&vpath->lock); + spin_lock(&vpath->lock); + if (!vpath->vp_open) { + spin_unlock(&vpath->lock); + max_retry = 100; } writeq(*data0, &vp_reg->rts_access_steer_data0); @@ -1000,7 +999,7 @@ exit: /** * vxge_hw_device_hw_info_get - Get the hw information * Returns the vpath mask that has the bits set for each vpath allocated - * for the driver, FW version information and the first mac addresse for + * for the driver, FW version information, and the first mac address for * each vpath */ enum vxge_hw_status __devinit @@ -1064,9 +1063,10 @@ vxge_hw_device_hw_info_get(void __iomem *bar0, val64 = readq(&toc->toc_vpath_pointer[i]); + spin_lock_init(&vpath.lock); vpath.vp_reg = (struct vxge_hw_vpath_reg __iomem *) (bar0 + val64); - vpath.vp_open = 0; + vpath.vp_open = VXGE_HW_VP_NOT_OPEN; status = __vxge_hw_vpath_pci_func_mode_get(&vpath, hw_info); if (status != VXGE_HW_OK) @@ -1090,7 +1090,7 @@ vxge_hw_device_hw_info_get(void __iomem *bar0, val64 = readq(&toc->toc_vpath_pointer[i]); vpath.vp_reg = (struct vxge_hw_vpath_reg __iomem *) (bar0 + val64); - vpath.vp_open = 0; + vpath.vp_open = VXGE_HW_VP_NOT_OPEN; status = __vxge_hw_vpath_addr_get(&vpath, hw_info->mac_addrs[i], @@ -4646,7 +4646,27 @@ static void __vxge_hw_vp_terminate(struct __vxge_hw_device *hldev, u32 vp_id) vpath->hldev->tim_int_mask1, vpath->vp_id); hldev->stats.hw_dev_info_stats.vpath_info[vpath->vp_id] = NULL; - memset(vpath, 0, sizeof(struct __vxge_hw_virtualpath)); + /* If the whole struct __vxge_hw_virtualpath is zeroed, nothing will + * work after the interface is brought down. + */ + spin_lock(&vpath->lock); + vpath->vp_open = VXGE_HW_VP_NOT_OPEN; + spin_unlock(&vpath->lock); + + vpath->vpmgmt_reg = NULL; + vpath->nofl_db = NULL; + vpath->max_mtu = 0; + vpath->vsport_number = 0; + vpath->max_kdfc_db = 0; + vpath->max_nofl_db = 0; + vpath->ringh = NULL; + vpath->fifoh = NULL; + memset(&vpath->vpath_handles, 0, sizeof(struct list_head)); + vpath->stats_block = 0; + vpath->hw_stats = NULL; + vpath->hw_stats_sav = NULL; + vpath->sw_stats = NULL; + exit: return; } @@ -4670,7 +4690,7 @@ __vxge_hw_vp_initialize(struct __vxge_hw_device *hldev, u32 vp_id, vpath = &hldev->virtual_paths[vp_id]; - spin_lock_init(&hldev->virtual_paths[vp_id].lock); + spin_lock_init(&vpath->lock); vpath->vp_id = vp_id; vpath->vp_open = VXGE_HW_VP_OPEN; vpath->hldev = hldev; @@ -5019,10 +5039,6 @@ enum vxge_hw_status vxge_hw_vpath_close(struct __vxge_hw_vpath_handle *vp) __vxge_hw_vp_terminate(devh, vp_id); - spin_lock(&vpath->lock); - vpath->vp_open = VXGE_HW_VP_NOT_OPEN; - spin_unlock(&vpath->lock); - vpath_close_exit: return status; } diff --git a/drivers/net/vxge/vxge-config.h b/drivers/net/vxge/vxge-config.h index 3c53aa732c9d..359b9b9f8041 100644 --- a/drivers/net/vxge/vxge-config.h +++ b/drivers/net/vxge/vxge-config.h @@ -412,44 +412,48 @@ struct vxge_hw_vp_config { * See also: struct vxge_hw_tim_intr_config{}. */ struct vxge_hw_device_config { - u32 dma_blockpool_initial; - u32 dma_blockpool_max; -#define VXGE_HW_MIN_DMA_BLOCK_POOL_SIZE 0 -#define VXGE_HW_INITIAL_DMA_BLOCK_POOL_SIZE 0 -#define VXGE_HW_INCR_DMA_BLOCK_POOL_SIZE 4 -#define VXGE_HW_MAX_DMA_BLOCK_POOL_SIZE 4096 - -#define VXGE_HW_MAX_PAYLOAD_SIZE_512 2 - - u32 intr_mode; -#define VXGE_HW_INTR_MODE_IRQLINE 0 -#define VXGE_HW_INTR_MODE_MSIX 1 -#define VXGE_HW_INTR_MODE_MSIX_ONE_SHOT 2 - -#define VXGE_HW_INTR_MODE_DEF 0 - - u32 rth_en; -#define VXGE_HW_RTH_DISABLE 0 -#define VXGE_HW_RTH_ENABLE 1 -#define VXGE_HW_RTH_DEFAULT 0 - - u32 rth_it_type; -#define VXGE_HW_RTH_IT_TYPE_SOLO_IT 0 -#define VXGE_HW_RTH_IT_TYPE_MULTI_IT 1 -#define VXGE_HW_RTH_IT_TYPE_DEFAULT 0 - - u32 rts_mac_en; + u32 device_poll_millis; +#define VXGE_HW_MIN_DEVICE_POLL_MILLIS 1 +#define VXGE_HW_MAX_DEVICE_POLL_MILLIS 100000 +#define VXGE_HW_DEF_DEVICE_POLL_MILLIS 1000 + + u32 dma_blockpool_initial; + u32 dma_blockpool_max; +#define VXGE_HW_MIN_DMA_BLOCK_POOL_SIZE 0 +#define VXGE_HW_INITIAL_DMA_BLOCK_POOL_SIZE 0 +#define VXGE_HW_INCR_DMA_BLOCK_POOL_SIZE 4 +#define VXGE_HW_MAX_DMA_BLOCK_POOL_SIZE 4096 + +#define VXGE_HW_MAX_PAYLOAD_SIZE_512 2 + + u32 intr_mode:2, +#define VXGE_HW_INTR_MODE_IRQLINE 0 +#define VXGE_HW_INTR_MODE_MSIX 1 +#define VXGE_HW_INTR_MODE_MSIX_ONE_SHOT 2 + +#define VXGE_HW_INTR_MODE_DEF 0 + + rth_en:1, +#define VXGE_HW_RTH_DISABLE 0 +#define VXGE_HW_RTH_ENABLE 1 +#define VXGE_HW_RTH_DEFAULT 0 + + rth_it_type:1, +#define VXGE_HW_RTH_IT_TYPE_SOLO_IT 0 +#define VXGE_HW_RTH_IT_TYPE_MULTI_IT 1 +#define VXGE_HW_RTH_IT_TYPE_DEFAULT 0 + + rts_mac_en:1, #define VXGE_HW_RTS_MAC_DISABLE 0 #define VXGE_HW_RTS_MAC_ENABLE 1 #define VXGE_HW_RTS_MAC_DEFAULT 0 - struct vxge_hw_vp_config vp_config[VXGE_HW_MAX_VIRTUAL_PATHS]; - - u32 device_poll_millis; -#define VXGE_HW_MIN_DEVICE_POLL_MILLIS 1 -#define VXGE_HW_MAX_DEVICE_POLL_MILLIS 100000 -#define VXGE_HW_DEF_DEVICE_POLL_MILLIS 1000 + hwts_en:1; +#define VXGE_HW_HWTS_DISABLE 0 +#define VXGE_HW_HWTS_ENABLE 1 +#define VXGE_HW_HWTS_DEFAULT 1 + struct vxge_hw_vp_config vp_config[VXGE_HW_MAX_VIRTUAL_PATHS]; }; /** diff --git a/drivers/net/vxge/vxge-ethtool.c b/drivers/net/vxge/vxge-ethtool.c index c5eb034107fd..5aef6c893aee 100644 --- a/drivers/net/vxge/vxge-ethtool.c +++ b/drivers/net/vxge/vxge-ethtool.c @@ -134,22 +134,29 @@ static void vxge_ethtool_gregs(struct net_device *dev, /** * vxge_ethtool_idnic - To physically identify the nic on the system. * @dev : device pointer. - * @id : pointer to the structure with identification parameters given by - * ethtool. + * @state : requested LED state * * Used to physically identify the NIC on the system. - * The Link LED will blink for a time specified by the user. - * Return value: * 0 on success */ -static int vxge_ethtool_idnic(struct net_device *dev, u32 data) +static int vxge_ethtool_idnic(struct net_device *dev, + enum ethtool_phys_id_state state) { struct vxgedev *vdev = netdev_priv(dev); struct __vxge_hw_device *hldev = vdev->devh; - vxge_hw_device_flick_link_led(hldev, VXGE_FLICKER_ON); - msleep_interruptible(data ? (data * HZ) : VXGE_MAX_FLICKER_TIME); - vxge_hw_device_flick_link_led(hldev, VXGE_FLICKER_OFF); + switch (state) { + case ETHTOOL_ID_ACTIVE: + vxge_hw_device_flick_link_led(hldev, VXGE_FLICKER_ON); + break; + + case ETHTOOL_ID_INACTIVE: + vxge_hw_device_flick_link_led(hldev, VXGE_FLICKER_OFF); + break; + + default: + return -EINVAL; + } return 0; } @@ -1064,35 +1071,6 @@ static int vxge_ethtool_get_regs_len(struct net_device *dev) return sizeof(struct vxge_hw_vpath_reg) * vdev->no_of_vpath; } -static u32 vxge_get_rx_csum(struct net_device *dev) -{ - struct vxgedev *vdev = netdev_priv(dev); - - return vdev->rx_csum; -} - -static int vxge_set_rx_csum(struct net_device *dev, u32 data) -{ - struct vxgedev *vdev = netdev_priv(dev); - - if (data) - vdev->rx_csum = 1; - else - vdev->rx_csum = 0; - - return 0; -} - -static int vxge_ethtool_op_set_tso(struct net_device *dev, u32 data) -{ - if (data) - dev->features |= (NETIF_F_TSO | NETIF_F_TSO6); - else - dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); - - return 0; -} - static int vxge_ethtool_get_sset_count(struct net_device *dev, int sset) { struct vxgedev *vdev = netdev_priv(dev); @@ -1112,40 +1090,6 @@ static int vxge_ethtool_get_sset_count(struct net_device *dev, int sset) } } -static int vxge_set_flags(struct net_device *dev, u32 data) -{ - struct vxgedev *vdev = netdev_priv(dev); - enum vxge_hw_status status; - - if (ethtool_invalid_flags(dev, data, ETH_FLAG_RXHASH)) - return -EINVAL; - - if (!!(data & ETH_FLAG_RXHASH) == vdev->devh->config.rth_en) - return 0; - - if (netif_running(dev) || (vdev->config.rth_steering == NO_STEERING)) - return -EINVAL; - - vdev->devh->config.rth_en = !!(data & ETH_FLAG_RXHASH); - - /* Enabling RTH requires some of the logic in vxge_device_register and a - * vpath reset. Due to these restrictions, only allow modification - * while the interface is down. - */ - status = vxge_reset_all_vpaths(vdev); - if (status != VXGE_HW_OK) { - vdev->devh->config.rth_en = !vdev->devh->config.rth_en; - return -EFAULT; - } - - if (vdev->devh->config.rth_en) - dev->features |= NETIF_F_RXHASH; - else - dev->features &= ~NETIF_F_RXHASH; - - return 0; -} - static int vxge_fw_flash(struct net_device *dev, struct ethtool_flash *parms) { struct vxgedev *vdev = netdev_priv(dev); @@ -1174,19 +1118,10 @@ static const struct ethtool_ops vxge_ethtool_ops = { .get_link = ethtool_op_get_link, .get_pauseparam = vxge_ethtool_getpause_data, .set_pauseparam = vxge_ethtool_setpause_data, - .get_rx_csum = vxge_get_rx_csum, - .set_rx_csum = vxge_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_ipv6_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, - .set_tso = vxge_ethtool_op_set_tso, .get_strings = vxge_ethtool_get_strings, - .phys_id = vxge_ethtool_idnic, + .set_phys_id = vxge_ethtool_idnic, .get_sset_count = vxge_ethtool_get_sset_count, .get_ethtool_stats = vxge_get_ethtool_stats, - .set_flags = vxge_set_flags, .flash_device = vxge_fw_flash, }; diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index aff68c1118d4..fc837cf6bd4d 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -304,22 +304,14 @@ vxge_rx_complete(struct vxge_ring *ring, struct sk_buff *skb, u16 vlan, "%s: %s:%d skb protocol = %d", ring->ndev->name, __func__, __LINE__, skb->protocol); - if (ring->gro_enable) { - if (ring->vlgrp && ext_info->vlan && - (ring->vlan_tag_strip == - VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE)) - vlan_gro_receive(ring->napi_p, ring->vlgrp, - ext_info->vlan, skb); - else - napi_gro_receive(ring->napi_p, skb); - } else { - if (ring->vlgrp && vlan && - (ring->vlan_tag_strip == - VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE)) - vlan_hwaccel_receive_skb(skb, ring->vlgrp, vlan); - else - netif_receive_skb(skb); - } + if (ring->vlgrp && ext_info->vlan && + (ring->vlan_tag_strip == + VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE)) + vlan_gro_receive(ring->napi_p, ring->vlgrp, + ext_info->vlan, skb); + else + napi_gro_receive(ring->napi_p, skb); + vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d Exiting...", ring->ndev->name, __func__, __LINE__); } @@ -490,7 +482,7 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr, if ((ext_info.proto & VXGE_HW_FRAME_PROTO_TCP_OR_UDP) && !(ext_info.proto & VXGE_HW_FRAME_PROTO_IP_FRAG) && - ring->rx_csum && /* Offload Rx side CSUM */ + (dev->features & NETIF_F_RXCSUM) && /* Offload Rx side CSUM */ ext_info.l3_cksum == VXGE_HW_L3_CKSUM_OK && ext_info.l4_cksum == VXGE_HW_L4_CKSUM_OK) skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -2094,11 +2086,9 @@ static int vxge_open_vpaths(struct vxgedev *vdev) vdev->config.fifo_indicate_max_pkts; vpath->fifo.tx_vector_no = 0; vpath->ring.rx_vector_no = 0; - vpath->ring.rx_csum = vdev->rx_csum; vpath->ring.rx_hwts = vdev->rx_hwts; vpath->is_open = 1; vdev->vp_handles[i] = vpath->handle; - vpath->ring.gro_enable = vdev->config.gro_enable; vpath->ring.vlan_tag_strip = vdev->vlan_tag_strip; vdev->stats.vpaths_open++; } else { @@ -2670,6 +2660,40 @@ static void vxge_poll_vp_lockup(unsigned long data) mod_timer(&vdev->vp_lockup_timer, jiffies + HZ / 1000); } +static u32 vxge_fix_features(struct net_device *dev, u32 features) +{ + u32 changed = dev->features ^ features; + + /* Enabling RTH requires some of the logic in vxge_device_register and a + * vpath reset. Due to these restrictions, only allow modification + * while the interface is down. + */ + if ((changed & NETIF_F_RXHASH) && netif_running(dev)) + features ^= NETIF_F_RXHASH; + + return features; +} + +static int vxge_set_features(struct net_device *dev, u32 features) +{ + struct vxgedev *vdev = netdev_priv(dev); + u32 changed = dev->features ^ features; + + if (!(changed & NETIF_F_RXHASH)) + return 0; + + /* !netif_running() ensured by vxge_fix_features() */ + + vdev->devh->config.rth_en = !!(features & NETIF_F_RXHASH); + if (vxge_reset_all_vpaths(vdev) != VXGE_HW_OK) { + dev->features = features ^ NETIF_F_RXHASH; + vdev->devh->config.rth_en = !!(dev->features & NETIF_F_RXHASH); + return -EIO; + } + + return 0; +} + /** * vxge_open * @dev: pointer to the device structure. @@ -3112,8 +3136,7 @@ vxge_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats) return net_stats; } -static enum vxge_hw_status vxge_timestamp_config(struct vxgedev *vdev, - int enable) +static enum vxge_hw_status vxge_timestamp_config(struct __vxge_hw_device *devh) { enum vxge_hw_status status; u64 val64; @@ -3123,27 +3146,24 @@ static enum vxge_hw_status vxge_timestamp_config(struct vxgedev *vdev, * required for the driver to load (due to a hardware bug), * there is no need to do anything special here. */ - if (enable) - val64 = VXGE_HW_XMAC_TIMESTAMP_EN | - VXGE_HW_XMAC_TIMESTAMP_USE_LINK_ID(0) | - VXGE_HW_XMAC_TIMESTAMP_INTERVAL(0); - else - val64 = 0; + val64 = VXGE_HW_XMAC_TIMESTAMP_EN | + VXGE_HW_XMAC_TIMESTAMP_USE_LINK_ID(0) | + VXGE_HW_XMAC_TIMESTAMP_INTERVAL(0); - status = vxge_hw_mgmt_reg_write(vdev->devh, + status = vxge_hw_mgmt_reg_write(devh, vxge_hw_mgmt_reg_type_mrpcim, 0, offsetof(struct vxge_hw_mrpcim_reg, xmac_timestamp), val64); - vxge_hw_device_flush_io(vdev->devh); + vxge_hw_device_flush_io(devh); + devh->config.hwts_en = VXGE_HW_HWTS_ENABLE; return status; } static int vxge_hwtstamp_ioctl(struct vxgedev *vdev, void __user *data) { struct hwtstamp_config config; - enum vxge_hw_status status; int i; if (copy_from_user(&config, data, sizeof(config))) @@ -3164,10 +3184,6 @@ static int vxge_hwtstamp_ioctl(struct vxgedev *vdev, void __user *data) switch (config.rx_filter) { case HWTSTAMP_FILTER_NONE: - status = vxge_timestamp_config(vdev, 0); - if (status != VXGE_HW_OK) - return -EFAULT; - vdev->rx_hwts = 0; config.rx_filter = HWTSTAMP_FILTER_NONE; break; @@ -3186,8 +3202,7 @@ static int vxge_hwtstamp_ioctl(struct vxgedev *vdev, void __user *data) case HWTSTAMP_FILTER_PTP_V2_EVENT: case HWTSTAMP_FILTER_PTP_V2_SYNC: case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: - status = vxge_timestamp_config(vdev, 1); - if (status != VXGE_HW_OK) + if (vdev->devh->config.hwts_en != VXGE_HW_HWTS_ENABLE) return -EFAULT; vdev->rx_hwts = 1; @@ -3378,6 +3393,8 @@ static const struct net_device_ops vxge_netdev_ops = { .ndo_do_ioctl = vxge_ioctl, .ndo_set_mac_address = vxge_set_mac_addr, .ndo_change_mtu = vxge_change_mtu, + .ndo_fix_features = vxge_fix_features, + .ndo_set_features = vxge_set_features, .ndo_vlan_rx_register = vxge_vlan_rx_register, .ndo_vlan_rx_kill_vid = vxge_vlan_rx_kill_vid, .ndo_vlan_rx_add_vid = vxge_vlan_rx_add_vid, @@ -3424,14 +3441,21 @@ static int __devinit vxge_device_register(struct __vxge_hw_device *hldev, vdev->devh = hldev; vdev->pdev = hldev->pdev; memcpy(&vdev->config, config, sizeof(struct vxge_config)); - vdev->rx_csum = 1; /* Enable Rx CSUM by default. */ vdev->rx_hwts = 0; vdev->titan1 = (vdev->pdev->revision == VXGE_HW_TITAN1_PCI_REVISION); SET_NETDEV_DEV(ndev, &vdev->pdev->dev); - ndev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | - NETIF_F_HW_VLAN_FILTER; + ndev->hw_features = NETIF_F_RXCSUM | NETIF_F_SG | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_TSO | NETIF_F_TSO6 | + NETIF_F_HW_VLAN_TX; + if (vdev->config.rth_steering != NO_STEERING) + ndev->hw_features |= NETIF_F_RXHASH; + + ndev->features |= ndev->hw_features | + NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; + /* Driver entry points */ ndev->irq = vdev->pdev->irq; ndev->base_addr = (unsigned long) hldev->bar0; @@ -3443,11 +3467,6 @@ static int __devinit vxge_device_register(struct __vxge_hw_device *hldev, vxge_initialize_ethtool_ops(ndev); - if (vdev->config.rth_steering != NO_STEERING) { - ndev->features |= NETIF_F_RXHASH; - hldev->config.rth_en = VXGE_HW_RTH_ENABLE; - } - /* Allocate memory for vpath */ vdev->vpaths = kzalloc((sizeof(struct vxge_vpath)) * no_of_vpath, GFP_KERNEL); @@ -3459,9 +3478,6 @@ static int __devinit vxge_device_register(struct __vxge_hw_device *hldev, goto _out1; } - ndev->features |= NETIF_F_SG; - - ndev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; vxge_debug_init(vxge_hw_device_trace_level_get(hldev), "%s : checksuming enabled", __func__); @@ -3471,11 +3487,6 @@ static int __devinit vxge_device_register(struct __vxge_hw_device *hldev, "%s : using High DMA", __func__); } - ndev->features |= NETIF_F_TSO | NETIF_F_TSO6; - - if (vdev->config.gro_enable) - ndev->features |= NETIF_F_GRO; - ret = register_netdev(ndev); if (ret) { vxge_debug_init(vxge_hw_device_trace_level_get(hldev), @@ -4005,15 +4016,6 @@ static void __devinit vxge_print_parm(struct vxgedev *vdev, u64 vpath_mask) vdev->config.tx_steering_type = 0; } - if (vdev->config.gro_enable) { - vxge_debug_init(VXGE_ERR, - "%s: Generic receive offload enabled", - vdev->ndev->name); - } else - vxge_debug_init(VXGE_TRACE, - "%s: Generic receive offload disabled", - vdev->ndev->name); - if (vdev->config.addr_learn_en) vxge_debug_init(VXGE_TRACE, "%s: MAC Address learning enabled", vdev->ndev->name); @@ -4575,12 +4577,29 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) goto _exit4; } + /* Always enable HWTS. This will always cause the FCS to be invalid, + * due to the fact that HWTS is using the FCS as the location of the + * timestamp. The HW FCS checking will still correctly determine if + * there is a valid checksum, and the FCS is being removed by the driver + * anyway. So no fucntionality is being lost. Since it is always + * enabled, we now simply use the ioctl call to set whether or not the + * driver should be paying attention to the HWTS. + */ + if (is_privileged == VXGE_HW_OK) { + status = vxge_timestamp_config(hldev); + if (status != VXGE_HW_OK) { + vxge_debug_init(VXGE_ERR, "%s: HWTS enable failed", + VXGE_DRIVER_NAME); + ret = -EFAULT; + goto _exit4; + } + } + vxge_hw_device_debug_set(hldev, VXGE_ERR, VXGE_COMPONENT_LL); /* set private device info */ pci_set_drvdata(pdev, hldev); - ll_config->gro_enable = VXGE_GRO_ALWAYS_AGGREGATE; ll_config->fifo_indicate_max_pkts = VXGE_FIFO_INDICATE_MAX_PKTS; ll_config->addr_learn_en = addr_learn_en; ll_config->rth_algorithm = RTH_ALG_JENKINS; diff --git a/drivers/net/vxge/vxge-main.h b/drivers/net/vxge/vxge-main.h index 40474f0da576..ed120aba443d 100644 --- a/drivers/net/vxge/vxge-main.h +++ b/drivers/net/vxge/vxge-main.h @@ -168,9 +168,6 @@ struct vxge_config { #define NEW_NAPI_WEIGHT 64 int napi_weight; -#define VXGE_GRO_DONOT_AGGREGATE 0 -#define VXGE_GRO_ALWAYS_AGGREGATE 1 - int gro_enable; int intr_type; #define INTA 0 #define MSI 1 @@ -290,13 +287,11 @@ struct vxge_ring { unsigned long interrupt_count; unsigned long jiffies; - /* copy of the flag indicating whether rx_csum is to be used */ - u32 rx_csum:1, - rx_hwts:1; + /* copy of the flag indicating whether rx_hwts is to be used */ + u32 rx_hwts:1; int pkts_processed; int budget; - int gro_enable; struct napi_struct napi; struct napi_struct *napi_p; @@ -369,9 +364,8 @@ struct vxgedev { */ u16 all_multi_flg; - /* A flag indicating whether rx_csum is to be used or not. */ - u32 rx_csum:1, - rx_hwts:1, + /* A flag indicating whether rx_hwts is to be used or not. */ + u32 rx_hwts:1, titan1:1; struct vxge_msix_entry *vxge_entries; diff --git a/drivers/net/vxge/vxge-traffic.h b/drivers/net/vxge/vxge-traffic.h index 6c2fc0b72af5..4a518a3b131c 100644 --- a/drivers/net/vxge/vxge-traffic.h +++ b/drivers/net/vxge/vxge-traffic.h @@ -240,7 +240,7 @@ struct vxge_hw_tim_intr_config { u32 btimer_val; #define VXGE_HW_MIN_TIM_BTIMER_VAL 0 #define VXGE_HW_MAX_TIM_BTIMER_VAL 67108864 -#define VXGE_HW_USE_FLASH_DEFAULT 0xffffffff +#define VXGE_HW_USE_FLASH_DEFAULT (~0) u32 timer_ac_en; #define VXGE_HW_TIM_TIMER_AC_ENABLE 1 diff --git a/drivers/net/vxge/vxge-version.h b/drivers/net/vxge/vxge-version.h index 581e21525e85..b9efa28bab3e 100644 --- a/drivers/net/vxge/vxge-version.h +++ b/drivers/net/vxge/vxge-version.h @@ -16,8 +16,8 @@ #define VXGE_VERSION_MAJOR "2" #define VXGE_VERSION_MINOR "5" -#define VXGE_VERSION_FIX "2" -#define VXGE_VERSION_BUILD "22259" +#define VXGE_VERSION_FIX "3" +#define VXGE_VERSION_BUILD "22640" #define VXGE_VERSION_FOR "k" #define VXGE_FW_VER(maj, min, bld) (((maj) << 16) + ((min) << 8) + (bld)) diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 7aeb113cbb90..f354bd4e121e 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -284,5 +284,6 @@ source "drivers/net/wireless/rtlwifi/Kconfig" source "drivers/net/wireless/wl1251/Kconfig" source "drivers/net/wireless/wl12xx/Kconfig" source "drivers/net/wireless/zd1211rw/Kconfig" +source "drivers/net/wireless/mwifiex/Kconfig" endif # WLAN diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index ddd3fb6ba1d3..7bba6a82b875 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -56,3 +56,5 @@ obj-$(CONFIG_WL12XX) += wl12xx/ obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx/ obj-$(CONFIG_IWM) += iwmc3200wifi/ + +obj-$(CONFIG_MWIFIEX) += mwifiex/ diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig index 92c216263ee9..d1b23067619f 100644 --- a/drivers/net/wireless/ath/Kconfig +++ b/drivers/net/wireless/ath/Kconfig @@ -24,7 +24,6 @@ config ATH_DEBUG source "drivers/net/wireless/ath/ath5k/Kconfig" source "drivers/net/wireless/ath/ath9k/Kconfig" -source "drivers/net/wireless/ath/ar9170/Kconfig" source "drivers/net/wireless/ath/carl9170/Kconfig" endif diff --git a/drivers/net/wireless/ath/Makefile b/drivers/net/wireless/ath/Makefile index 6d711ec97ec2..0e8f528c81c0 100644 --- a/drivers/net/wireless/ath/Makefile +++ b/drivers/net/wireless/ath/Makefile @@ -1,6 +1,5 @@ obj-$(CONFIG_ATH5K) += ath5k/ obj-$(CONFIG_ATH9K_HW) += ath9k/ -obj-$(CONFIG_AR9170_USB) += ar9170/ obj-$(CONFIG_CARL9170) += carl9170/ obj-$(CONFIG_ATH_COMMON) += ath.o diff --git a/drivers/net/wireless/ath/ar9170/Kconfig b/drivers/net/wireless/ath/ar9170/Kconfig deleted file mode 100644 index 7b9672b0d090..000000000000 --- a/drivers/net/wireless/ath/ar9170/Kconfig +++ /dev/null @@ -1,20 +0,0 @@ -config AR9170_USB - tristate "Atheros AR9170 802.11n USB support (OBSOLETE)" - depends on USB && MAC80211 - select FW_LOADER - help - This driver is going to get replaced by carl9170. - - This is a driver for the Atheros "otus" 802.11n USB devices. - - These devices require additional firmware (2 files). - For now, these files can be downloaded from here: - - http://wireless.kernel.org/en/users/Drivers/ar9170 - - If you choose to build a module, it'll be called ar9170usb. - -config AR9170_LEDS - bool - depends on AR9170_USB && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = AR9170_USB) - default y diff --git a/drivers/net/wireless/ath/ar9170/Makefile b/drivers/net/wireless/ath/ar9170/Makefile deleted file mode 100644 index 8d91c7ee3215..000000000000 --- a/drivers/net/wireless/ath/ar9170/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -ar9170usb-objs := usb.o main.o cmd.o mac.o phy.o led.o - -obj-$(CONFIG_AR9170_USB) += ar9170usb.o diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h deleted file mode 100644 index 371e4ce49528..000000000000 --- a/drivers/net/wireless/ath/ar9170/ar9170.h +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Atheros AR9170 driver - * - * Driver specific definitions - * - * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 Atheros Communications, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#ifndef __AR9170_H -#define __AR9170_H - -#include <linux/completion.h> -#include <linux/spinlock.h> -#include <net/cfg80211.h> -#include <net/mac80211.h> -#ifdef CONFIG_AR9170_LEDS -#include <linux/leds.h> -#endif /* CONFIG_AR9170_LEDS */ -#include "eeprom.h" -#include "hw.h" - -#include "../regd.h" - -#define PAYLOAD_MAX (AR9170_MAX_CMD_LEN/4 - 1) - -enum ar9170_bw { - AR9170_BW_20, - AR9170_BW_40_BELOW, - AR9170_BW_40_ABOVE, - - __AR9170_NUM_BW, -}; - -static inline enum ar9170_bw nl80211_to_ar9170(enum nl80211_channel_type type) -{ - switch (type) { - case NL80211_CHAN_NO_HT: - case NL80211_CHAN_HT20: - return AR9170_BW_20; - case NL80211_CHAN_HT40MINUS: - return AR9170_BW_40_BELOW; - case NL80211_CHAN_HT40PLUS: - return AR9170_BW_40_ABOVE; - default: - BUG(); - } -} - -enum ar9170_rf_init_mode { - AR9170_RFI_NONE, - AR9170_RFI_WARM, - AR9170_RFI_COLD, -}; - -#define AR9170_MAX_RX_BUFFER_SIZE 8192 - -#ifdef CONFIG_AR9170_LEDS -struct ar9170; - -struct ar9170_led { - struct ar9170 *ar; - struct led_classdev l; - char name[32]; - unsigned int toggled; - bool last_state; - bool registered; -}; - -#endif /* CONFIG_AR9170_LEDS */ - -enum ar9170_device_state { - AR9170_UNKNOWN_STATE, - AR9170_STOPPED, - AR9170_IDLE, - AR9170_STARTED, -}; - -struct ar9170_rxstream_mpdu_merge { - struct ar9170_rx_head plcp; - bool has_plcp; -}; - -struct ar9170_tx_queue_stats { - unsigned int len; - unsigned int limit; - unsigned int count; -}; - -#define AR9170_QUEUE_TIMEOUT 64 -#define AR9170_TX_TIMEOUT 8 -#define AR9170_JANITOR_DELAY 128 -#define AR9170_TX_INVALID_RATE 0xffffffff - -#define AR9170_NUM_TX_LIMIT_HARD AR9170_TXQ_DEPTH -#define AR9170_NUM_TX_LIMIT_SOFT (AR9170_TXQ_DEPTH - 10) - -struct ar9170 { - struct ieee80211_hw *hw; - struct ath_common common; - struct mutex mutex; - enum ar9170_device_state state; - bool registered; - unsigned long bad_hw_nagger; - - int (*open)(struct ar9170 *); - void (*stop)(struct ar9170 *); - int (*tx)(struct ar9170 *, struct sk_buff *); - int (*exec_cmd)(struct ar9170 *, enum ar9170_cmd, u32 , - void *, u32 , void *); - void (*callback_cmd)(struct ar9170 *, u32 , void *); - int (*flush)(struct ar9170 *); - - /* interface mode settings */ - struct ieee80211_vif *vif; - - /* beaconing */ - struct sk_buff *beacon; - struct work_struct beacon_work; - bool enable_beacon; - - /* cryptographic engine */ - u64 usedkeys; - bool rx_software_decryption; - bool disable_offload; - - /* filter settings */ - u64 cur_mc_hash; - u32 cur_filter; - unsigned int filter_state; - bool sniffer_enabled; - - /* PHY */ - struct ieee80211_channel *channel; - int noise[4]; - - /* power calibration data */ - u8 power_5G_leg[4]; - u8 power_2G_cck[4]; - u8 power_2G_ofdm[4]; - u8 power_5G_ht20[8]; - u8 power_5G_ht40[8]; - u8 power_2G_ht20[8]; - u8 power_2G_ht40[8]; - - u8 phy_heavy_clip; - -#ifdef CONFIG_AR9170_LEDS - struct delayed_work led_work; - struct ar9170_led leds[AR9170_NUM_LEDS]; -#endif /* CONFIG_AR9170_LEDS */ - - /* qos queue settings */ - spinlock_t tx_stats_lock; - struct ar9170_tx_queue_stats tx_stats[5]; - struct ieee80211_tx_queue_params edcf[5]; - - spinlock_t cmdlock; - __le32 cmdbuf[PAYLOAD_MAX + 1]; - - /* MAC statistics */ - struct ieee80211_low_level_stats stats; - - /* EEPROM */ - struct ar9170_eeprom eeprom; - - /* tx queues - as seen by hw - */ - struct sk_buff_head tx_pending[__AR9170_NUM_TXQ]; - struct sk_buff_head tx_status[__AR9170_NUM_TXQ]; - struct delayed_work tx_janitor; - - /* rxstream mpdu merge */ - struct ar9170_rxstream_mpdu_merge rx_mpdu; - struct sk_buff *rx_failover; - int rx_failover_missing; - - /* (cached) HW A-MPDU settings */ - u8 global_ampdu_density; - u8 global_ampdu_factor; -}; - -struct ar9170_tx_info { - unsigned long timeout; -}; - -#define IS_STARTED(a) (((struct ar9170 *)a)->state >= AR9170_STARTED) -#define IS_ACCEPTING_CMD(a) (((struct ar9170 *)a)->state >= AR9170_IDLE) - -/* exported interface */ -void *ar9170_alloc(size_t priv_size); -int ar9170_register(struct ar9170 *ar, struct device *pdev); -void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb); -void ar9170_unregister(struct ar9170 *ar); -void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb); -void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len); -int ar9170_nag_limiter(struct ar9170 *ar); - -/* MAC */ -void ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb); -int ar9170_init_mac(struct ar9170 *ar); -int ar9170_set_qos(struct ar9170 *ar); -int ar9170_update_multicast(struct ar9170 *ar, const u64 mc_hast); -int ar9170_update_frame_filter(struct ar9170 *ar, const u32 filter); -int ar9170_set_operating_mode(struct ar9170 *ar); -int ar9170_set_beacon_timers(struct ar9170 *ar); -int ar9170_set_dyn_sifs_ack(struct ar9170 *ar); -int ar9170_set_slot_time(struct ar9170 *ar); -int ar9170_set_basic_rates(struct ar9170 *ar); -int ar9170_set_hwretry_limit(struct ar9170 *ar, u32 max_retry); -int ar9170_update_beacon(struct ar9170 *ar); -void ar9170_new_beacon(struct work_struct *work); -int ar9170_upload_key(struct ar9170 *ar, u8 id, const u8 *mac, u8 ktype, - u8 keyidx, u8 *keydata, int keylen); -int ar9170_disable_key(struct ar9170 *ar, u8 id); - -/* LEDs */ -#ifdef CONFIG_AR9170_LEDS -int ar9170_register_leds(struct ar9170 *ar); -void ar9170_unregister_leds(struct ar9170 *ar); -#endif /* CONFIG_AR9170_LEDS */ -int ar9170_init_leds(struct ar9170 *ar); -int ar9170_set_leds_state(struct ar9170 *ar, u32 led_state); - -/* PHY / RF */ -int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band); -int ar9170_init_rf(struct ar9170 *ar); -int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, - enum ar9170_rf_init_mode rfi, enum ar9170_bw bw); - -#endif /* __AR9170_H */ diff --git a/drivers/net/wireless/ath/ar9170/cmd.c b/drivers/net/wireless/ath/ar9170/cmd.c deleted file mode 100644 index 6452c5055a63..000000000000 --- a/drivers/net/wireless/ath/ar9170/cmd.c +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Atheros AR9170 driver - * - * Basic HW register/memory/command access functions - * - * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 Atheros Communications, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "ar9170.h" -#include "cmd.h" - -int ar9170_write_mem(struct ar9170 *ar, const __le32 *data, size_t len) -{ - int err; - - if (unlikely(!IS_ACCEPTING_CMD(ar))) - return 0; - - err = ar->exec_cmd(ar, AR9170_CMD_WMEM, len, (u8 *) data, 0, NULL); - if (err) - wiphy_debug(ar->hw->wiphy, "writing memory failed\n"); - return err; -} - -int ar9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val) -{ - const __le32 buf[2] = { - cpu_to_le32(reg), - cpu_to_le32(val), - }; - int err; - - if (unlikely(!IS_ACCEPTING_CMD(ar))) - return 0; - - err = ar->exec_cmd(ar, AR9170_CMD_WREG, sizeof(buf), - (u8 *) buf, 0, NULL); - if (err) - wiphy_debug(ar->hw->wiphy, "writing reg %#x (val %#x) failed\n", - reg, val); - return err; -} - -int ar9170_read_mreg(struct ar9170 *ar, int nregs, const u32 *regs, u32 *out) -{ - int i, err; - __le32 *offs, *res; - - if (unlikely(!IS_ACCEPTING_CMD(ar))) - return 0; - - /* abuse "out" for the register offsets, must be same length */ - offs = (__le32 *)out; - for (i = 0; i < nregs; i++) - offs[i] = cpu_to_le32(regs[i]); - - /* also use the same buffer for the input */ - res = (__le32 *)out; - - err = ar->exec_cmd(ar, AR9170_CMD_RREG, - 4 * nregs, (u8 *)offs, - 4 * nregs, (u8 *)res); - if (err) - return err; - - /* convert result to cpu endian */ - for (i = 0; i < nregs; i++) - out[i] = le32_to_cpu(res[i]); - - return 0; -} - -int ar9170_read_reg(struct ar9170 *ar, u32 reg, u32 *val) -{ - return ar9170_read_mreg(ar, 1, ®, val); -} - -int ar9170_echo_test(struct ar9170 *ar, u32 v) -{ - __le32 echobuf = cpu_to_le32(v); - __le32 echores; - int err; - - if (unlikely(!IS_ACCEPTING_CMD(ar))) - return -ENODEV; - - err = ar->exec_cmd(ar, AR9170_CMD_ECHO, - 4, (u8 *)&echobuf, - 4, (u8 *)&echores); - if (err) - return err; - - if (echobuf != echores) - return -EINVAL; - - return 0; -} diff --git a/drivers/net/wireless/ath/ar9170/cmd.h b/drivers/net/wireless/ath/ar9170/cmd.h deleted file mode 100644 index ec8134b4b949..000000000000 --- a/drivers/net/wireless/ath/ar9170/cmd.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Atheros AR9170 driver - * - * Basic HW register/memory/command access functions - * - * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 Atheros Communications, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#ifndef __CMD_H -#define __CMD_H - -#include "ar9170.h" - -/* basic HW access */ -int ar9170_write_mem(struct ar9170 *ar, const __le32 *data, size_t len); -int ar9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val); -int ar9170_read_reg(struct ar9170 *ar, u32 reg, u32 *val); -int ar9170_read_mreg(struct ar9170 *ar, int nregs, const u32 *regs, u32 *out); -int ar9170_echo_test(struct ar9170 *ar, u32 v); - -/* - * Macros to facilitate writing multiple registers in a single - * write-combining USB command. Note that when the first group - * fails the whole thing will fail without any others attempted, - * but you won't know which write in the group failed. - */ -#define ar9170_regwrite_begin(ar) \ -do { \ - int __nreg = 0, __err = 0; \ - struct ar9170 *__ar = ar; - -#define ar9170_regwrite(r, v) do { \ - __ar->cmdbuf[2 * __nreg + 1] = cpu_to_le32(r); \ - __ar->cmdbuf[2 * __nreg + 2] = cpu_to_le32(v); \ - __nreg++; \ - if ((__nreg >= PAYLOAD_MAX/2)) { \ - if (IS_ACCEPTING_CMD(__ar)) \ - __err = ar->exec_cmd(__ar, AR9170_CMD_WREG, \ - 8 * __nreg, \ - (u8 *) &__ar->cmdbuf[1], \ - 0, NULL); \ - __nreg = 0; \ - if (__err) \ - goto __regwrite_out; \ - } \ -} while (0) - -#define ar9170_regwrite_finish() \ -__regwrite_out : \ - if (__nreg) { \ - if (IS_ACCEPTING_CMD(__ar)) \ - __err = ar->exec_cmd(__ar, AR9170_CMD_WREG, \ - 8 * __nreg, \ - (u8 *) &__ar->cmdbuf[1], \ - 0, NULL); \ - __nreg = 0; \ - } - -#define ar9170_regwrite_result() \ - __err; \ -} while (0); - -#endif /* __CMD_H */ diff --git a/drivers/net/wireless/ath/ar9170/eeprom.h b/drivers/net/wireless/ath/ar9170/eeprom.h deleted file mode 100644 index 6c4663883423..000000000000 --- a/drivers/net/wireless/ath/ar9170/eeprom.h +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Atheros AR9170 driver - * - * EEPROM layout - * - * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 Atheros Communications, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#ifndef __AR9170_EEPROM_H -#define __AR9170_EEPROM_H - -#define AR5416_MAX_CHAINS 2 -#define AR5416_MODAL_SPURS 5 - -struct ar9170_eeprom_modal { - __le32 antCtrlChain[AR5416_MAX_CHAINS]; - __le32 antCtrlCommon; - s8 antennaGainCh[AR5416_MAX_CHAINS]; - u8 switchSettling; - u8 txRxAttenCh[AR5416_MAX_CHAINS]; - u8 rxTxMarginCh[AR5416_MAX_CHAINS]; - s8 adcDesiredSize; - s8 pgaDesiredSize; - u8 xlnaGainCh[AR5416_MAX_CHAINS]; - u8 txEndToXpaOff; - u8 txEndToRxOn; - u8 txFrameToXpaOn; - u8 thresh62; - s8 noiseFloorThreshCh[AR5416_MAX_CHAINS]; - u8 xpdGain; - u8 xpd; - s8 iqCalICh[AR5416_MAX_CHAINS]; - s8 iqCalQCh[AR5416_MAX_CHAINS]; - u8 pdGainOverlap; - u8 ob; - u8 db; - u8 xpaBiasLvl; - u8 pwrDecreaseFor2Chain; - u8 pwrDecreaseFor3Chain; - u8 txFrameToDataStart; - u8 txFrameToPaOn; - u8 ht40PowerIncForPdadc; - u8 bswAtten[AR5416_MAX_CHAINS]; - u8 bswMargin[AR5416_MAX_CHAINS]; - u8 swSettleHt40; - u8 reserved[22]; - struct spur_channel { - __le16 spurChan; - u8 spurRangeLow; - u8 spurRangeHigh; - } __packed spur_channels[AR5416_MODAL_SPURS]; -} __packed; - -#define AR5416_NUM_PD_GAINS 4 -#define AR5416_PD_GAIN_ICEPTS 5 - -struct ar9170_calibration_data_per_freq { - u8 pwr_pdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; - u8 vpd_pdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; -} __packed; - -#define AR5416_NUM_5G_CAL_PIERS 8 -#define AR5416_NUM_2G_CAL_PIERS 4 - -#define AR5416_NUM_5G_TARGET_PWRS 8 -#define AR5416_NUM_2G_CCK_TARGET_PWRS 3 -#define AR5416_NUM_2G_OFDM_TARGET_PWRS 4 -#define AR5416_MAX_NUM_TGT_PWRS 8 - -struct ar9170_calibration_target_power_legacy { - u8 freq; - u8 power[4]; -} __packed; - -struct ar9170_calibration_target_power_ht { - u8 freq; - u8 power[8]; -} __packed; - -#define AR5416_NUM_CTLS 24 - -struct ar9170_calctl_edges { - u8 channel; -#define AR9170_CALCTL_EDGE_FLAGS 0xC0 - u8 power_flags; -} __packed; - -#define AR5416_NUM_BAND_EDGES 8 - -struct ar9170_calctl_data { - struct ar9170_calctl_edges - control_edges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES]; -} __packed; - - -struct ar9170_eeprom { - __le16 length; - __le16 checksum; - __le16 version; - u8 operating_flags; -#define AR9170_OPFLAG_5GHZ 1 -#define AR9170_OPFLAG_2GHZ 2 - u8 misc; - __le16 reg_domain[2]; - u8 mac_address[6]; - u8 rx_mask; - u8 tx_mask; - __le16 rf_silent; - __le16 bluetooth_options; - __le16 device_capabilities; - __le32 build_number; - u8 deviceType; - u8 reserved[33]; - - u8 customer_data[64]; - - struct ar9170_eeprom_modal - modal_header[2]; - - u8 cal_freq_pier_5G[AR5416_NUM_5G_CAL_PIERS]; - u8 cal_freq_pier_2G[AR5416_NUM_2G_CAL_PIERS]; - - struct ar9170_calibration_data_per_freq - cal_pier_data_5G[AR5416_MAX_CHAINS][AR5416_NUM_5G_CAL_PIERS], - cal_pier_data_2G[AR5416_MAX_CHAINS][AR5416_NUM_2G_CAL_PIERS]; - - /* power calibration data */ - struct ar9170_calibration_target_power_legacy - cal_tgt_pwr_5G[AR5416_NUM_5G_TARGET_PWRS]; - struct ar9170_calibration_target_power_ht - cal_tgt_pwr_5G_ht20[AR5416_NUM_5G_TARGET_PWRS], - cal_tgt_pwr_5G_ht40[AR5416_NUM_5G_TARGET_PWRS]; - - struct ar9170_calibration_target_power_legacy - cal_tgt_pwr_2G_cck[AR5416_NUM_2G_CCK_TARGET_PWRS], - cal_tgt_pwr_2G_ofdm[AR5416_NUM_2G_OFDM_TARGET_PWRS]; - struct ar9170_calibration_target_power_ht - cal_tgt_pwr_2G_ht20[AR5416_NUM_2G_OFDM_TARGET_PWRS], - cal_tgt_pwr_2G_ht40[AR5416_NUM_2G_OFDM_TARGET_PWRS]; - - /* conformance testing limits */ - u8 ctl_index[AR5416_NUM_CTLS]; - struct ar9170_calctl_data - ctl_data[AR5416_NUM_CTLS]; - - u8 pad; - __le16 subsystem_id; -} __packed; - -#endif /* __AR9170_EEPROM_H */ diff --git a/drivers/net/wireless/ath/ar9170/hw.h b/drivers/net/wireless/ath/ar9170/hw.h deleted file mode 100644 index 06f1f3c951a4..000000000000 --- a/drivers/net/wireless/ath/ar9170/hw.h +++ /dev/null @@ -1,430 +0,0 @@ -/* - * Atheros AR9170 driver - * - * Hardware-specific definitions - * - * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 Atheros Communications, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#ifndef __AR9170_HW_H -#define __AR9170_HW_H - -#define AR9170_MAX_CMD_LEN 64 - -enum ar9170_cmd { - AR9170_CMD_RREG = 0x00, - AR9170_CMD_WREG = 0x01, - AR9170_CMD_RMEM = 0x02, - AR9170_CMD_WMEM = 0x03, - AR9170_CMD_BITAND = 0x04, - AR9170_CMD_BITOR = 0x05, - AR9170_CMD_EKEY = 0x28, - AR9170_CMD_DKEY = 0x29, - AR9170_CMD_FREQUENCY = 0x30, - AR9170_CMD_RF_INIT = 0x31, - AR9170_CMD_SYNTH = 0x32, - AR9170_CMD_FREQ_START = 0x33, - AR9170_CMD_ECHO = 0x80, - AR9170_CMD_TALLY = 0x81, - AR9170_CMD_TALLY_APD = 0x82, - AR9170_CMD_CONFIG = 0x83, - AR9170_CMD_RESET = 0x90, - AR9170_CMD_DKRESET = 0x91, - AR9170_CMD_DKTX_STATUS = 0x92, - AR9170_CMD_FDC = 0xA0, - AR9170_CMD_WREEPROM = 0xB0, - AR9170_CMD_WFLASH = 0xB0, - AR9170_CMD_FLASH_ERASE = 0xB1, - AR9170_CMD_FLASH_PROG = 0xB2, - AR9170_CMD_FLASH_CHKSUM = 0xB3, - AR9170_CMD_FLASH_READ = 0xB4, - AR9170_CMD_FW_DL_INIT = 0xB5, - AR9170_CMD_MEM_WREEPROM = 0xBB, -}; - -/* endpoints */ -#define AR9170_EP_TX 1 -#define AR9170_EP_RX 2 -#define AR9170_EP_IRQ 3 -#define AR9170_EP_CMD 4 - -#define AR9170_EEPROM_START 0x1600 - -#define AR9170_GPIO_REG_BASE 0x1d0100 -#define AR9170_GPIO_REG_PORT_TYPE AR9170_GPIO_REG_BASE -#define AR9170_GPIO_REG_DATA (AR9170_GPIO_REG_BASE + 4) -#define AR9170_NUM_LEDS 2 - - -#define AR9170_USB_REG_BASE 0x1e1000 -#define AR9170_USB_REG_DMA_CTL (AR9170_USB_REG_BASE + 0x108) -#define AR9170_DMA_CTL_ENABLE_TO_DEVICE 0x1 -#define AR9170_DMA_CTL_ENABLE_FROM_DEVICE 0x2 -#define AR9170_DMA_CTL_HIGH_SPEED 0x4 -#define AR9170_DMA_CTL_PACKET_MODE 0x8 - -#define AR9170_USB_REG_MAX_AGG_UPLOAD (AR9170_USB_REG_BASE + 0x110) -#define AR9170_USB_REG_UPLOAD_TIME_CTL (AR9170_USB_REG_BASE + 0x114) - - - -#define AR9170_MAC_REG_BASE 0x1c3000 - -#define AR9170_MAC_REG_TSF_L (AR9170_MAC_REG_BASE + 0x514) -#define AR9170_MAC_REG_TSF_H (AR9170_MAC_REG_BASE + 0x518) - -#define AR9170_MAC_REG_ATIM_WINDOW (AR9170_MAC_REG_BASE + 0x51C) -#define AR9170_MAC_REG_BCN_PERIOD (AR9170_MAC_REG_BASE + 0x520) -#define AR9170_MAC_REG_PRETBTT (AR9170_MAC_REG_BASE + 0x524) - -#define AR9170_MAC_REG_MAC_ADDR_L (AR9170_MAC_REG_BASE + 0x610) -#define AR9170_MAC_REG_MAC_ADDR_H (AR9170_MAC_REG_BASE + 0x614) -#define AR9170_MAC_REG_BSSID_L (AR9170_MAC_REG_BASE + 0x618) -#define AR9170_MAC_REG_BSSID_H (AR9170_MAC_REG_BASE + 0x61c) - -#define AR9170_MAC_REG_GROUP_HASH_TBL_L (AR9170_MAC_REG_BASE + 0x624) -#define AR9170_MAC_REG_GROUP_HASH_TBL_H (AR9170_MAC_REG_BASE + 0x628) - -#define AR9170_MAC_REG_RX_TIMEOUT (AR9170_MAC_REG_BASE + 0x62C) - -#define AR9170_MAC_REG_BASIC_RATE (AR9170_MAC_REG_BASE + 0x630) -#define AR9170_MAC_REG_MANDATORY_RATE (AR9170_MAC_REG_BASE + 0x634) -#define AR9170_MAC_REG_RTS_CTS_RATE (AR9170_MAC_REG_BASE + 0x638) -#define AR9170_MAC_REG_BACKOFF_PROTECT (AR9170_MAC_REG_BASE + 0x63c) -#define AR9170_MAC_REG_RX_THRESHOLD (AR9170_MAC_REG_BASE + 0x640) -#define AR9170_MAC_REG_RX_PE_DELAY (AR9170_MAC_REG_BASE + 0x64C) - -#define AR9170_MAC_REG_DYNAMIC_SIFS_ACK (AR9170_MAC_REG_BASE + 0x658) -#define AR9170_MAC_REG_SNIFFER (AR9170_MAC_REG_BASE + 0x674) -#define AR9170_MAC_REG_SNIFFER_ENABLE_PROMISC BIT(0) -#define AR9170_MAC_REG_SNIFFER_DEFAULTS 0x02000000 -#define AR9170_MAC_REG_ENCRYPTION (AR9170_MAC_REG_BASE + 0x678) -#define AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE BIT(3) -#define AR9170_MAC_REG_ENCRYPTION_DEFAULTS 0x70 - -#define AR9170_MAC_REG_MISC_680 (AR9170_MAC_REG_BASE + 0x680) -#define AR9170_MAC_REG_TX_UNDERRUN (AR9170_MAC_REG_BASE + 0x688) - -#define AR9170_MAC_REG_FRAMETYPE_FILTER (AR9170_MAC_REG_BASE + 0x68c) -#define AR9170_MAC_REG_FTF_ASSOC_REQ BIT(0) -#define AR9170_MAC_REG_FTF_ASSOC_RESP BIT(1) -#define AR9170_MAC_REG_FTF_REASSOC_REQ BIT(2) -#define AR9170_MAC_REG_FTF_REASSOC_RESP BIT(3) -#define AR9170_MAC_REG_FTF_PRB_REQ BIT(4) -#define AR9170_MAC_REG_FTF_PRB_RESP BIT(5) -#define AR9170_MAC_REG_FTF_BIT6 BIT(6) -#define AR9170_MAC_REG_FTF_BIT7 BIT(7) -#define AR9170_MAC_REG_FTF_BEACON BIT(8) -#define AR9170_MAC_REG_FTF_ATIM BIT(9) -#define AR9170_MAC_REG_FTF_DEASSOC BIT(10) -#define AR9170_MAC_REG_FTF_AUTH BIT(11) -#define AR9170_MAC_REG_FTF_DEAUTH BIT(12) -#define AR9170_MAC_REG_FTF_BIT13 BIT(13) -#define AR9170_MAC_REG_FTF_BIT14 BIT(14) -#define AR9170_MAC_REG_FTF_BIT15 BIT(15) -#define AR9170_MAC_REG_FTF_BAR BIT(24) -#define AR9170_MAC_REG_FTF_BA BIT(25) -#define AR9170_MAC_REG_FTF_PSPOLL BIT(26) -#define AR9170_MAC_REG_FTF_RTS BIT(27) -#define AR9170_MAC_REG_FTF_CTS BIT(28) -#define AR9170_MAC_REG_FTF_ACK BIT(29) -#define AR9170_MAC_REG_FTF_CFE BIT(30) -#define AR9170_MAC_REG_FTF_CFE_ACK BIT(31) -#define AR9170_MAC_REG_FTF_DEFAULTS 0x0700ffff -#define AR9170_MAC_REG_FTF_MONITOR 0xfd00ffff - -#define AR9170_MAC_REG_RX_TOTAL (AR9170_MAC_REG_BASE + 0x6A0) -#define AR9170_MAC_REG_RX_CRC32 (AR9170_MAC_REG_BASE + 0x6A4) -#define AR9170_MAC_REG_RX_CRC16 (AR9170_MAC_REG_BASE + 0x6A8) -#define AR9170_MAC_REG_RX_ERR_DECRYPTION_UNI (AR9170_MAC_REG_BASE + 0x6AC) -#define AR9170_MAC_REG_RX_OVERRUN (AR9170_MAC_REG_BASE + 0x6B0) -#define AR9170_MAC_REG_RX_ERR_DECRYPTION_MUL (AR9170_MAC_REG_BASE + 0x6BC) -#define AR9170_MAC_REG_TX_RETRY (AR9170_MAC_REG_BASE + 0x6CC) -#define AR9170_MAC_REG_TX_TOTAL (AR9170_MAC_REG_BASE + 0x6F4) - - -#define AR9170_MAC_REG_ACK_EXTENSION (AR9170_MAC_REG_BASE + 0x690) -#define AR9170_MAC_REG_EIFS_AND_SIFS (AR9170_MAC_REG_BASE + 0x698) - -#define AR9170_MAC_REG_SLOT_TIME (AR9170_MAC_REG_BASE + 0x6F0) - -#define AR9170_MAC_REG_POWERMANAGEMENT (AR9170_MAC_REG_BASE + 0x700) -#define AR9170_MAC_REG_POWERMGT_IBSS 0xe0 -#define AR9170_MAC_REG_POWERMGT_AP 0xa1 -#define AR9170_MAC_REG_POWERMGT_STA 0x2 -#define AR9170_MAC_REG_POWERMGT_AP_WDS 0x3 -#define AR9170_MAC_REG_POWERMGT_DEFAULTS (0xf << 24) - -#define AR9170_MAC_REG_ROLL_CALL_TBL_L (AR9170_MAC_REG_BASE + 0x704) -#define AR9170_MAC_REG_ROLL_CALL_TBL_H (AR9170_MAC_REG_BASE + 0x708) - -#define AR9170_MAC_REG_AC0_CW (AR9170_MAC_REG_BASE + 0xB00) -#define AR9170_MAC_REG_AC1_CW (AR9170_MAC_REG_BASE + 0xB04) -#define AR9170_MAC_REG_AC2_CW (AR9170_MAC_REG_BASE + 0xB08) -#define AR9170_MAC_REG_AC3_CW (AR9170_MAC_REG_BASE + 0xB0C) -#define AR9170_MAC_REG_AC4_CW (AR9170_MAC_REG_BASE + 0xB10) -#define AR9170_MAC_REG_AC1_AC0_AIFS (AR9170_MAC_REG_BASE + 0xB14) -#define AR9170_MAC_REG_AC3_AC2_AIFS (AR9170_MAC_REG_BASE + 0xB18) - -#define AR9170_MAC_REG_RETRY_MAX (AR9170_MAC_REG_BASE + 0xB28) - -#define AR9170_MAC_REG_FCS_SELECT (AR9170_MAC_REG_BASE + 0xBB0) -#define AR9170_MAC_FCS_SWFCS 0x1 -#define AR9170_MAC_FCS_FIFO_PROT 0x4 - - -#define AR9170_MAC_REG_TXOP_NOT_ENOUGH_IND (AR9170_MAC_REG_BASE + 0xB30) - -#define AR9170_MAC_REG_AC1_AC0_TXOP (AR9170_MAC_REG_BASE + 0xB44) -#define AR9170_MAC_REG_AC3_AC2_TXOP (AR9170_MAC_REG_BASE + 0xB48) - -#define AR9170_MAC_REG_AMPDU_FACTOR (AR9170_MAC_REG_BASE + 0xB9C) -#define AR9170_MAC_REG_AMPDU_DENSITY (AR9170_MAC_REG_BASE + 0xBA0) - -#define AR9170_MAC_REG_ACK_TABLE (AR9170_MAC_REG_BASE + 0xC00) -#define AR9170_MAC_REG_AMPDU_RX_THRESH (AR9170_MAC_REG_BASE + 0xC50) - -#define AR9170_MAC_REG_TXRX_MPI (AR9170_MAC_REG_BASE + 0xD7C) -#define AR9170_MAC_TXRX_MPI_TX_MPI_MASK 0x0000000f -#define AR9170_MAC_TXRX_MPI_TX_TO_MASK 0x0000fff0 -#define AR9170_MAC_TXRX_MPI_RX_MPI_MASK 0x000f0000 -#define AR9170_MAC_TXRX_MPI_RX_TO_MASK 0xfff00000 - -#define AR9170_MAC_REG_BCN_ADDR (AR9170_MAC_REG_BASE + 0xD84) -#define AR9170_MAC_REG_BCN_LENGTH (AR9170_MAC_REG_BASE + 0xD88) -#define AR9170_MAC_REG_BCN_PLCP (AR9170_MAC_REG_BASE + 0xD90) -#define AR9170_MAC_REG_BCN_CTRL (AR9170_MAC_REG_BASE + 0xD94) -#define AR9170_MAC_REG_BCN_HT1 (AR9170_MAC_REG_BASE + 0xDA0) -#define AR9170_MAC_REG_BCN_HT2 (AR9170_MAC_REG_BASE + 0xDA4) - - -#define AR9170_PWR_REG_BASE 0x1D4000 - -#define AR9170_PWR_REG_CLOCK_SEL (AR9170_PWR_REG_BASE + 0x008) -#define AR9170_PWR_CLK_AHB_40MHZ 0 -#define AR9170_PWR_CLK_AHB_20_22MHZ 1 -#define AR9170_PWR_CLK_AHB_40_44MHZ 2 -#define AR9170_PWR_CLK_AHB_80_88MHZ 3 -#define AR9170_PWR_CLK_DAC_160_INV_DLY 0x70 - - -/* put beacon here in memory */ -#define AR9170_BEACON_BUFFER_ADDRESS 0x117900 - - -struct ar9170_tx_control { - __le16 length; - __le16 mac_control; - __le32 phy_control; - u8 frame_data[0]; -} __packed; - -/* these are either-or */ -#define AR9170_TX_MAC_PROT_RTS 0x0001 -#define AR9170_TX_MAC_PROT_CTS 0x0002 - -#define AR9170_TX_MAC_NO_ACK 0x0004 -/* if unset, MAC will only do SIFS space before frame */ -#define AR9170_TX_MAC_BACKOFF 0x0008 -#define AR9170_TX_MAC_BURST 0x0010 -#define AR9170_TX_MAC_AGGR 0x0020 - -/* encryption is a two-bit field */ -#define AR9170_TX_MAC_ENCR_NONE 0x0000 -#define AR9170_TX_MAC_ENCR_RC4 0x0040 -#define AR9170_TX_MAC_ENCR_CENC 0x0080 -#define AR9170_TX_MAC_ENCR_AES 0x00c0 - -#define AR9170_TX_MAC_MMIC 0x0100 -#define AR9170_TX_MAC_HW_DURATION 0x0200 -#define AR9170_TX_MAC_QOS_SHIFT 10 -#define AR9170_TX_MAC_QOS_MASK (3 << AR9170_TX_MAC_QOS_SHIFT) -#define AR9170_TX_MAC_AGGR_QOS_BIT1 0x0400 -#define AR9170_TX_MAC_AGGR_QOS_BIT2 0x0800 -#define AR9170_TX_MAC_DISABLE_TXOP 0x1000 -#define AR9170_TX_MAC_TXOP_RIFS 0x2000 -#define AR9170_TX_MAC_IMM_AMPDU 0x4000 -#define AR9170_TX_MAC_RATE_PROBE 0x8000 - -/* either-or */ -#define AR9170_TX_PHY_MOD_MASK 0x00000003 -#define AR9170_TX_PHY_MOD_CCK 0x00000000 -#define AR9170_TX_PHY_MOD_OFDM 0x00000001 -#define AR9170_TX_PHY_MOD_HT 0x00000002 - -/* depends on modulation */ -#define AR9170_TX_PHY_SHORT_PREAMBLE 0x00000004 -#define AR9170_TX_PHY_GREENFIELD 0x00000004 - -#define AR9170_TX_PHY_BW_SHIFT 3 -#define AR9170_TX_PHY_BW_MASK (3 << AR9170_TX_PHY_BW_SHIFT) -#define AR9170_TX_PHY_BW_20MHZ 0 -#define AR9170_TX_PHY_BW_40MHZ 2 -#define AR9170_TX_PHY_BW_40MHZ_DUP 3 - -#define AR9170_TX_PHY_TX_HEAVY_CLIP_SHIFT 6 -#define AR9170_TX_PHY_TX_HEAVY_CLIP_MASK (7 << AR9170_TX_PHY_TX_HEAVY_CLIP_SHIFT) - -#define AR9170_TX_PHY_TX_PWR_SHIFT 9 -#define AR9170_TX_PHY_TX_PWR_MASK (0x3f << AR9170_TX_PHY_TX_PWR_SHIFT) - -/* not part of the hw-spec */ -#define AR9170_TX_PHY_QOS_SHIFT 25 -#define AR9170_TX_PHY_QOS_MASK (3 << AR9170_TX_PHY_QOS_SHIFT) - -#define AR9170_TX_PHY_TXCHAIN_SHIFT 15 -#define AR9170_TX_PHY_TXCHAIN_MASK (7 << AR9170_TX_PHY_TXCHAIN_SHIFT) -#define AR9170_TX_PHY_TXCHAIN_1 1 -/* use for cck, ofdm 6/9/12/18/24 and HT if capable */ -#define AR9170_TX_PHY_TXCHAIN_2 5 - -#define AR9170_TX_PHY_MCS_SHIFT 18 -#define AR9170_TX_PHY_MCS_MASK (0x7f << AR9170_TX_PHY_MCS_SHIFT) - -#define AR9170_TX_PHY_SHORT_GI 0x80000000 - -#define AR5416_MAX_RATE_POWER 63 - -struct ar9170_rx_head { - u8 plcp[12]; -} __packed; - -struct ar9170_rx_phystatus { - union { - struct { - u8 rssi_ant0, rssi_ant1, rssi_ant2, - rssi_ant0x, rssi_ant1x, rssi_ant2x, - rssi_combined; - } __packed; - u8 rssi[7]; - } __packed; - - u8 evm_stream0[6], evm_stream1[6]; - u8 phy_err; -} __packed; - -struct ar9170_rx_macstatus { - u8 SAidx, DAidx; - u8 error; - u8 status; -} __packed; - -#define AR9170_ENC_ALG_NONE 0x0 -#define AR9170_ENC_ALG_WEP64 0x1 -#define AR9170_ENC_ALG_TKIP 0x2 -#define AR9170_ENC_ALG_AESCCMP 0x4 -#define AR9170_ENC_ALG_WEP128 0x5 -#define AR9170_ENC_ALG_WEP256 0x6 -#define AR9170_ENC_ALG_CENC 0x7 - -#define AR9170_RX_ENC_SOFTWARE 0x8 - -static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_macstatus *t) -{ - return (t->SAidx & 0xc0) >> 4 | - (t->DAidx & 0xc0) >> 6; -} - -#define AR9170_RX_STATUS_MODULATION_MASK 0x03 -#define AR9170_RX_STATUS_MODULATION_CCK 0x00 -#define AR9170_RX_STATUS_MODULATION_OFDM 0x01 -#define AR9170_RX_STATUS_MODULATION_HT 0x02 -#define AR9170_RX_STATUS_MODULATION_DUPOFDM 0x03 - -/* depends on modulation */ -#define AR9170_RX_STATUS_SHORT_PREAMBLE 0x08 -#define AR9170_RX_STATUS_GREENFIELD 0x08 - -#define AR9170_RX_STATUS_MPDU_MASK 0x30 -#define AR9170_RX_STATUS_MPDU_SINGLE 0x00 -#define AR9170_RX_STATUS_MPDU_FIRST 0x20 -#define AR9170_RX_STATUS_MPDU_MIDDLE 0x30 -#define AR9170_RX_STATUS_MPDU_LAST 0x10 - -#define AR9170_RX_ERROR_RXTO 0x01 -#define AR9170_RX_ERROR_OVERRUN 0x02 -#define AR9170_RX_ERROR_DECRYPT 0x04 -#define AR9170_RX_ERROR_FCS 0x08 -#define AR9170_RX_ERROR_WRONG_RA 0x10 -#define AR9170_RX_ERROR_PLCP 0x20 -#define AR9170_RX_ERROR_MMIC 0x40 -#define AR9170_RX_ERROR_FATAL 0x80 - -struct ar9170_cmd_tx_status { - u8 dst[ETH_ALEN]; - __le32 rate; - __le16 status; -} __packed; - -#define AR9170_TX_STATUS_COMPLETE 0x00 -#define AR9170_TX_STATUS_RETRY 0x01 -#define AR9170_TX_STATUS_FAILED 0x02 - -struct ar9170_cmd_ba_failed_count { - __le16 failed; - __le16 rate; -} __packed; - -struct ar9170_cmd_response { - u8 flag; - u8 type; - __le16 padding; - - union { - struct ar9170_cmd_tx_status tx_status; - struct ar9170_cmd_ba_failed_count ba_fail_cnt; - u8 data[0]; - }; -} __packed; - -/* QoS */ - -/* mac80211 queue to HW/FW map */ -static const u8 ar9170_qos_hwmap[4] = { 3, 2, 0, 1 }; - -/* HW/FW queue to mac80211 map */ -static const u8 ar9170_qos_mac80211map[4] = { 2, 3, 1, 0 }; - -enum ar9170_txq { - AR9170_TXQ_BE, - AR9170_TXQ_BK, - AR9170_TXQ_VI, - AR9170_TXQ_VO, - - __AR9170_NUM_TXQ, -}; - -#define AR9170_TXQ_DEPTH 32 -#define AR9170_TX_MAX_PENDING 128 -#define AR9170_RX_STREAM_MAX_SIZE 65535 - -#endif /* __AR9170_HW_H */ diff --git a/drivers/net/wireless/ath/ar9170/led.c b/drivers/net/wireless/ath/ar9170/led.c deleted file mode 100644 index 832d90087f8a..000000000000 --- a/drivers/net/wireless/ath/ar9170/led.c +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Atheros AR9170 driver - * - * LED handling - * - * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 Atheros Communications, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "ar9170.h" -#include "cmd.h" - -int ar9170_set_leds_state(struct ar9170 *ar, u32 led_state) -{ - return ar9170_write_reg(ar, AR9170_GPIO_REG_DATA, led_state); -} - -int ar9170_init_leds(struct ar9170 *ar) -{ - int err; - - /* disable LEDs */ - /* GPIO [0/1 mode: output, 2/3: input] */ - err = ar9170_write_reg(ar, AR9170_GPIO_REG_PORT_TYPE, 3); - if (err) - goto out; - - /* GPIO 0/1 value: off */ - err = ar9170_set_leds_state(ar, 0); - -out: - return err; -} - -#ifdef CONFIG_AR9170_LEDS -static void ar9170_update_leds(struct work_struct *work) -{ - struct ar9170 *ar = container_of(work, struct ar9170, led_work.work); - int i, tmp, blink_delay = 1000; - u32 led_val = 0; - bool rerun = false; - - if (unlikely(!IS_ACCEPTING_CMD(ar))) - return ; - - mutex_lock(&ar->mutex); - for (i = 0; i < AR9170_NUM_LEDS; i++) - if (ar->leds[i].registered && ar->leds[i].toggled) { - led_val |= 1 << i; - - tmp = 70 + 200 / (ar->leds[i].toggled); - if (tmp < blink_delay) - blink_delay = tmp; - - if (ar->leds[i].toggled > 1) - ar->leds[i].toggled = 0; - - rerun = true; - } - - ar9170_set_leds_state(ar, led_val); - mutex_unlock(&ar->mutex); - - if (!rerun) - return; - - ieee80211_queue_delayed_work(ar->hw, - &ar->led_work, - msecs_to_jiffies(blink_delay)); -} - -static void ar9170_led_brightness_set(struct led_classdev *led, - enum led_brightness brightness) -{ - struct ar9170_led *arl = container_of(led, struct ar9170_led, l); - struct ar9170 *ar = arl->ar; - - if (unlikely(!arl->registered)) - return ; - - if (arl->last_state != !!brightness) { - arl->toggled++; - arl->last_state = !!brightness; - } - - if (likely(IS_ACCEPTING_CMD(ar) && arl->toggled)) - ieee80211_queue_delayed_work(ar->hw, &ar->led_work, HZ/10); -} - -static int ar9170_register_led(struct ar9170 *ar, int i, char *name, - char *trigger) -{ - int err; - - snprintf(ar->leds[i].name, sizeof(ar->leds[i].name), - "ar9170-%s::%s", wiphy_name(ar->hw->wiphy), name); - - ar->leds[i].ar = ar; - ar->leds[i].l.name = ar->leds[i].name; - ar->leds[i].l.brightness_set = ar9170_led_brightness_set; - ar->leds[i].l.brightness = 0; - ar->leds[i].l.default_trigger = trigger; - - err = led_classdev_register(wiphy_dev(ar->hw->wiphy), - &ar->leds[i].l); - if (err) - wiphy_err(ar->hw->wiphy, "failed to register %s LED (%d).\n", - ar->leds[i].name, err); - else - ar->leds[i].registered = true; - - return err; -} - -void ar9170_unregister_leds(struct ar9170 *ar) -{ - int i; - - for (i = 0; i < AR9170_NUM_LEDS; i++) - if (ar->leds[i].registered) { - led_classdev_unregister(&ar->leds[i].l); - ar->leds[i].registered = false; - ar->leds[i].toggled = 0; - } - - cancel_delayed_work_sync(&ar->led_work); -} - -int ar9170_register_leds(struct ar9170 *ar) -{ - int err; - - INIT_DELAYED_WORK(&ar->led_work, ar9170_update_leds); - - err = ar9170_register_led(ar, 0, "tx", - ieee80211_get_tx_led_name(ar->hw)); - if (err) - goto fail; - - err = ar9170_register_led(ar, 1, "assoc", - ieee80211_get_assoc_led_name(ar->hw)); - if (err) - goto fail; - - return 0; - -fail: - ar9170_unregister_leds(ar); - return err; -} - -#endif /* CONFIG_AR9170_LEDS */ diff --git a/drivers/net/wireless/ath/ar9170/mac.c b/drivers/net/wireless/ath/ar9170/mac.c deleted file mode 100644 index 857e86104295..000000000000 --- a/drivers/net/wireless/ath/ar9170/mac.c +++ /dev/null @@ -1,519 +0,0 @@ -/* - * Atheros AR9170 driver - * - * MAC programming - * - * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 Atheros Communications, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <asm/unaligned.h> - -#include "ar9170.h" -#include "cmd.h" - -int ar9170_set_dyn_sifs_ack(struct ar9170 *ar) -{ - u32 val; - - if (conf_is_ht40(&ar->hw->conf)) - val = 0x010a; - else { - if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) - val = 0x105; - else - val = 0x104; - } - - return ar9170_write_reg(ar, AR9170_MAC_REG_DYNAMIC_SIFS_ACK, val); -} - -int ar9170_set_slot_time(struct ar9170 *ar) -{ - u32 slottime = 20; - - if (!ar->vif) - return 0; - - if ((ar->hw->conf.channel->band == IEEE80211_BAND_5GHZ) || - ar->vif->bss_conf.use_short_slot) - slottime = 9; - - return ar9170_write_reg(ar, AR9170_MAC_REG_SLOT_TIME, slottime << 10); -} - -int ar9170_set_basic_rates(struct ar9170 *ar) -{ - u8 cck, ofdm; - - if (!ar->vif) - return 0; - - ofdm = ar->vif->bss_conf.basic_rates >> 4; - - /* FIXME: is still necessary? */ - if (ar->hw->conf.channel->band == IEEE80211_BAND_5GHZ) - cck = 0; - else - cck = ar->vif->bss_conf.basic_rates & 0xf; - - return ar9170_write_reg(ar, AR9170_MAC_REG_BASIC_RATE, - ofdm << 8 | cck); -} - -int ar9170_set_qos(struct ar9170 *ar) -{ - ar9170_regwrite_begin(ar); - - ar9170_regwrite(AR9170_MAC_REG_AC0_CW, ar->edcf[0].cw_min | - (ar->edcf[0].cw_max << 16)); - ar9170_regwrite(AR9170_MAC_REG_AC1_CW, ar->edcf[1].cw_min | - (ar->edcf[1].cw_max << 16)); - ar9170_regwrite(AR9170_MAC_REG_AC2_CW, ar->edcf[2].cw_min | - (ar->edcf[2].cw_max << 16)); - ar9170_regwrite(AR9170_MAC_REG_AC3_CW, ar->edcf[3].cw_min | - (ar->edcf[3].cw_max << 16)); - ar9170_regwrite(AR9170_MAC_REG_AC4_CW, ar->edcf[4].cw_min | - (ar->edcf[4].cw_max << 16)); - - ar9170_regwrite(AR9170_MAC_REG_AC1_AC0_AIFS, - ((ar->edcf[0].aifs * 9 + 10)) | - ((ar->edcf[1].aifs * 9 + 10) << 12) | - ((ar->edcf[2].aifs * 9 + 10) << 24)); - ar9170_regwrite(AR9170_MAC_REG_AC3_AC2_AIFS, - ((ar->edcf[2].aifs * 9 + 10) >> 8) | - ((ar->edcf[3].aifs * 9 + 10) << 4) | - ((ar->edcf[4].aifs * 9 + 10) << 16)); - - ar9170_regwrite(AR9170_MAC_REG_AC1_AC0_TXOP, - ar->edcf[0].txop | ar->edcf[1].txop << 16); - ar9170_regwrite(AR9170_MAC_REG_AC3_AC2_TXOP, - ar->edcf[2].txop | ar->edcf[3].txop << 16); - - ar9170_regwrite_finish(); - - return ar9170_regwrite_result(); -} - -static int ar9170_set_ampdu_density(struct ar9170 *ar, u8 mpdudensity) -{ - u32 val; - - /* don't allow AMPDU density > 8us */ - if (mpdudensity > 6) - return -EINVAL; - - /* Watch out! Otus uses slightly different density values. */ - val = 0x140a00 | (mpdudensity ? (mpdudensity + 1) : 0); - - ar9170_regwrite_begin(ar); - ar9170_regwrite(AR9170_MAC_REG_AMPDU_DENSITY, val); - ar9170_regwrite_finish(); - - return ar9170_regwrite_result(); -} - -int ar9170_init_mac(struct ar9170 *ar) -{ - ar9170_regwrite_begin(ar); - - ar9170_regwrite(AR9170_MAC_REG_ACK_EXTENSION, 0x40); - - ar9170_regwrite(AR9170_MAC_REG_RETRY_MAX, 0); - - /* enable MMIC */ - ar9170_regwrite(AR9170_MAC_REG_SNIFFER, - AR9170_MAC_REG_SNIFFER_DEFAULTS); - - ar9170_regwrite(AR9170_MAC_REG_RX_THRESHOLD, 0xc1f80); - - ar9170_regwrite(AR9170_MAC_REG_RX_PE_DELAY, 0x70); - ar9170_regwrite(AR9170_MAC_REG_EIFS_AND_SIFS, 0xa144000); - ar9170_regwrite(AR9170_MAC_REG_SLOT_TIME, 9 << 10); - - /* CF-END mode */ - ar9170_regwrite(0x1c3b2c, 0x19000000); - - /* NAV protects ACK only (in TXOP) */ - ar9170_regwrite(0x1c3b38, 0x201); - - /* Set Beacon PHY CTRL's TPC to 0x7, TA1=1 */ - /* OTUS set AM to 0x1 */ - ar9170_regwrite(AR9170_MAC_REG_BCN_HT1, 0x8000170); - - ar9170_regwrite(AR9170_MAC_REG_BACKOFF_PROTECT, 0x105); - - /* AGG test code*/ - /* Aggregation MAX number and timeout */ - ar9170_regwrite(0x1c3b9c, 0x10000a); - - ar9170_regwrite(AR9170_MAC_REG_FRAMETYPE_FILTER, - AR9170_MAC_REG_FTF_DEFAULTS); - - /* Enable deaggregator, response in sniffer mode */ - ar9170_regwrite(0x1c3c40, 0x1 | 1<<30); - - /* rate sets */ - ar9170_regwrite(AR9170_MAC_REG_BASIC_RATE, 0x150f); - ar9170_regwrite(AR9170_MAC_REG_MANDATORY_RATE, 0x150f); - ar9170_regwrite(AR9170_MAC_REG_RTS_CTS_RATE, 0x10b01bb); - - /* MIMO response control */ - ar9170_regwrite(0x1c3694, 0x4003C1E);/* bit 26~28 otus-AM */ - - /* switch MAC to OTUS interface */ - ar9170_regwrite(0x1c3600, 0x3); - - ar9170_regwrite(AR9170_MAC_REG_AMPDU_RX_THRESH, 0xffff); - - /* set PHY register read timeout (??) */ - ar9170_regwrite(AR9170_MAC_REG_MISC_680, 0xf00008); - - /* Disable Rx TimeOut, workaround for BB. */ - ar9170_regwrite(AR9170_MAC_REG_RX_TIMEOUT, 0x0); - - /* Set CPU clock frequency to 88/80MHz */ - ar9170_regwrite(AR9170_PWR_REG_CLOCK_SEL, - AR9170_PWR_CLK_AHB_80_88MHZ | - AR9170_PWR_CLK_DAC_160_INV_DLY); - - /* Set WLAN DMA interrupt mode: generate int per packet */ - ar9170_regwrite(AR9170_MAC_REG_TXRX_MPI, 0x110011); - - ar9170_regwrite(AR9170_MAC_REG_FCS_SELECT, - AR9170_MAC_FCS_FIFO_PROT); - - /* Disables the CF_END frame, undocumented register */ - ar9170_regwrite(AR9170_MAC_REG_TXOP_NOT_ENOUGH_IND, - 0x141E0F48); - - ar9170_regwrite_finish(); - - return ar9170_regwrite_result(); -} - -static int ar9170_set_mac_reg(struct ar9170 *ar, const u32 reg, const u8 *mac) -{ - static const u8 zero[ETH_ALEN] = { 0 }; - - if (!mac) - mac = zero; - - ar9170_regwrite_begin(ar); - - ar9170_regwrite(reg, get_unaligned_le32(mac)); - ar9170_regwrite(reg + 4, get_unaligned_le16(mac + 4)); - - ar9170_regwrite_finish(); - - return ar9170_regwrite_result(); -} - -int ar9170_update_multicast(struct ar9170 *ar, const u64 mc_hash) -{ - int err; - - ar9170_regwrite_begin(ar); - ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_H, mc_hash >> 32); - ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_L, mc_hash); - ar9170_regwrite_finish(); - err = ar9170_regwrite_result(); - if (err) - return err; - - ar->cur_mc_hash = mc_hash; - return 0; -} - -int ar9170_update_frame_filter(struct ar9170 *ar, const u32 filter) -{ - int err; - - err = ar9170_write_reg(ar, AR9170_MAC_REG_FRAMETYPE_FILTER, filter); - if (err) - return err; - - ar->cur_filter = filter; - return 0; -} - -static int ar9170_set_promiscouous(struct ar9170 *ar) -{ - u32 encr_mode, sniffer; - int err; - - err = ar9170_read_reg(ar, AR9170_MAC_REG_SNIFFER, &sniffer); - if (err) - return err; - - err = ar9170_read_reg(ar, AR9170_MAC_REG_ENCRYPTION, &encr_mode); - if (err) - return err; - - if (ar->sniffer_enabled) { - sniffer |= AR9170_MAC_REG_SNIFFER_ENABLE_PROMISC; - - /* - * Rx decryption works in place. - * - * If we don't disable it, the hardware will render all - * encrypted frames which are encrypted with an unknown - * key useless. - */ - - encr_mode |= AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE; - ar->sniffer_enabled = true; - } else { - sniffer &= ~AR9170_MAC_REG_SNIFFER_ENABLE_PROMISC; - - if (ar->rx_software_decryption) - encr_mode |= AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE; - else - encr_mode &= ~AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE; - } - - ar9170_regwrite_begin(ar); - ar9170_regwrite(AR9170_MAC_REG_ENCRYPTION, encr_mode); - ar9170_regwrite(AR9170_MAC_REG_SNIFFER, sniffer); - ar9170_regwrite_finish(); - - return ar9170_regwrite_result(); -} - -int ar9170_set_operating_mode(struct ar9170 *ar) -{ - struct ath_common *common = &ar->common; - u32 pm_mode = AR9170_MAC_REG_POWERMGT_DEFAULTS; - u8 *mac_addr, *bssid; - int err; - - if (ar->vif) { - mac_addr = common->macaddr; - bssid = common->curbssid; - - switch (ar->vif->type) { - case NL80211_IFTYPE_MESH_POINT: - case NL80211_IFTYPE_ADHOC: - pm_mode |= AR9170_MAC_REG_POWERMGT_IBSS; - break; - case NL80211_IFTYPE_AP: - pm_mode |= AR9170_MAC_REG_POWERMGT_AP; - break; - case NL80211_IFTYPE_WDS: - pm_mode |= AR9170_MAC_REG_POWERMGT_AP_WDS; - break; - case NL80211_IFTYPE_MONITOR: - ar->sniffer_enabled = true; - ar->rx_software_decryption = true; - break; - default: - pm_mode |= AR9170_MAC_REG_POWERMGT_STA; - break; - } - } else { - mac_addr = NULL; - bssid = NULL; - } - - err = ar9170_set_mac_reg(ar, AR9170_MAC_REG_MAC_ADDR_L, mac_addr); - if (err) - return err; - - err = ar9170_set_mac_reg(ar, AR9170_MAC_REG_BSSID_L, bssid); - if (err) - return err; - - err = ar9170_set_promiscouous(ar); - if (err) - return err; - - /* set AMPDU density to 8us. */ - err = ar9170_set_ampdu_density(ar, 6); - if (err) - return err; - - ar9170_regwrite_begin(ar); - - ar9170_regwrite(AR9170_MAC_REG_POWERMANAGEMENT, pm_mode); - ar9170_regwrite_finish(); - - return ar9170_regwrite_result(); -} - -int ar9170_set_hwretry_limit(struct ar9170 *ar, unsigned int max_retry) -{ - u32 tmp = min_t(u32, 0x33333, max_retry * 0x11111); - - return ar9170_write_reg(ar, AR9170_MAC_REG_RETRY_MAX, tmp); -} - -int ar9170_set_beacon_timers(struct ar9170 *ar) -{ - u32 v = 0; - u32 pretbtt = 0; - - if (ar->vif) { - v |= ar->vif->bss_conf.beacon_int; - - if (ar->enable_beacon) { - switch (ar->vif->type) { - case NL80211_IFTYPE_MESH_POINT: - case NL80211_IFTYPE_ADHOC: - v |= BIT(25); - break; - case NL80211_IFTYPE_AP: - v |= BIT(24); - pretbtt = (ar->vif->bss_conf.beacon_int - 6) << - 16; - break; - default: - break; - } - } - - v |= ar->vif->bss_conf.dtim_period << 16; - } - - ar9170_regwrite_begin(ar); - ar9170_regwrite(AR9170_MAC_REG_PRETBTT, pretbtt); - ar9170_regwrite(AR9170_MAC_REG_BCN_PERIOD, v); - ar9170_regwrite_finish(); - return ar9170_regwrite_result(); -} - -int ar9170_update_beacon(struct ar9170 *ar) -{ - struct sk_buff *skb; - __le32 *data, *old = NULL; - u32 word; - int i; - - skb = ieee80211_beacon_get(ar->hw, ar->vif); - if (!skb) - return -ENOMEM; - - data = (__le32 *)skb->data; - if (ar->beacon) - old = (__le32 *)ar->beacon->data; - - ar9170_regwrite_begin(ar); - for (i = 0; i < DIV_ROUND_UP(skb->len, 4); i++) { - /* - * XXX: This accesses beyond skb data for up - * to the last 3 bytes!! - */ - - if (old && (data[i] == old[i])) - continue; - - word = le32_to_cpu(data[i]); - ar9170_regwrite(AR9170_BEACON_BUFFER_ADDRESS + 4 * i, word); - } - - /* XXX: use skb->cb info */ - if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) - ar9170_regwrite(AR9170_MAC_REG_BCN_PLCP, - ((skb->len + 4) << (3 + 16)) + 0x0400); - else - ar9170_regwrite(AR9170_MAC_REG_BCN_PLCP, - ((skb->len + 4) << 16) + 0x001b); - - ar9170_regwrite(AR9170_MAC_REG_BCN_LENGTH, skb->len + 4); - ar9170_regwrite(AR9170_MAC_REG_BCN_ADDR, AR9170_BEACON_BUFFER_ADDRESS); - ar9170_regwrite(AR9170_MAC_REG_BCN_CTRL, 1); - - ar9170_regwrite_finish(); - - dev_kfree_skb(ar->beacon); - ar->beacon = skb; - - return ar9170_regwrite_result(); -} - -void ar9170_new_beacon(struct work_struct *work) -{ - struct ar9170 *ar = container_of(work, struct ar9170, - beacon_work); - struct sk_buff *skb; - - if (unlikely(!IS_STARTED(ar))) - return ; - - mutex_lock(&ar->mutex); - - if (!ar->vif) - goto out; - - ar9170_update_beacon(ar); - - rcu_read_lock(); - while ((skb = ieee80211_get_buffered_bc(ar->hw, ar->vif))) - ar9170_op_tx(ar->hw, skb); - - rcu_read_unlock(); - - out: - mutex_unlock(&ar->mutex); -} - -int ar9170_upload_key(struct ar9170 *ar, u8 id, const u8 *mac, u8 ktype, - u8 keyidx, u8 *keydata, int keylen) -{ - __le32 vals[7]; - static const u8 bcast[ETH_ALEN] = - { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - u8 dummy; - - mac = mac ? : bcast; - - vals[0] = cpu_to_le32((keyidx << 16) + id); - vals[1] = cpu_to_le32(mac[1] << 24 | mac[0] << 16 | ktype); - vals[2] = cpu_to_le32(mac[5] << 24 | mac[4] << 16 | - mac[3] << 8 | mac[2]); - memset(&vals[3], 0, 16); - if (keydata) - memcpy(&vals[3], keydata, keylen); - - return ar->exec_cmd(ar, AR9170_CMD_EKEY, - sizeof(vals), (u8 *)vals, - 1, &dummy); -} - -int ar9170_disable_key(struct ar9170 *ar, u8 id) -{ - __le32 val = cpu_to_le32(id); - u8 dummy; - - return ar->exec_cmd(ar, AR9170_CMD_EKEY, - sizeof(val), (u8 *)&val, - 1, &dummy); -} diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c deleted file mode 100644 index ccc2edaaeda0..000000000000 --- a/drivers/net/wireless/ath/ar9170/main.c +++ /dev/null @@ -1,2190 +0,0 @@ -/* - * Atheros AR9170 driver - * - * mac80211 interaction code - * - * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> - * Copyright 2009, Christian Lamparter <chunkeey@web.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 Atheros Communications, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/module.h> -#include <linux/etherdevice.h> -#include <net/mac80211.h> -#include "ar9170.h" -#include "hw.h" -#include "cmd.h" - -static int modparam_nohwcrypt; -module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); -MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); - -#define RATE(_bitrate, _hw_rate, _txpidx, _flags) { \ - .bitrate = (_bitrate), \ - .flags = (_flags), \ - .hw_value = (_hw_rate) | (_txpidx) << 4, \ -} - -static struct ieee80211_rate __ar9170_ratetable[] = { - RATE(10, 0, 0, 0), - RATE(20, 1, 1, IEEE80211_RATE_SHORT_PREAMBLE), - RATE(55, 2, 2, IEEE80211_RATE_SHORT_PREAMBLE), - RATE(110, 3, 3, IEEE80211_RATE_SHORT_PREAMBLE), - RATE(60, 0xb, 0, 0), - RATE(90, 0xf, 0, 0), - RATE(120, 0xa, 0, 0), - RATE(180, 0xe, 0, 0), - RATE(240, 0x9, 0, 0), - RATE(360, 0xd, 1, 0), - RATE(480, 0x8, 2, 0), - RATE(540, 0xc, 3, 0), -}; -#undef RATE - -#define ar9170_g_ratetable (__ar9170_ratetable + 0) -#define ar9170_g_ratetable_size 12 -#define ar9170_a_ratetable (__ar9170_ratetable + 4) -#define ar9170_a_ratetable_size 8 - -/* - * NB: The hw_value is used as an index into the ar9170_phy_freq_params - * array in phy.c so that we don't have to do frequency lookups! - */ -#define CHAN(_freq, _idx) { \ - .center_freq = (_freq), \ - .hw_value = (_idx), \ - .max_power = 18, /* XXX */ \ -} - -static struct ieee80211_channel ar9170_2ghz_chantable[] = { - CHAN(2412, 0), - CHAN(2417, 1), - CHAN(2422, 2), - CHAN(2427, 3), - CHAN(2432, 4), - CHAN(2437, 5), - CHAN(2442, 6), - CHAN(2447, 7), - CHAN(2452, 8), - CHAN(2457, 9), - CHAN(2462, 10), - CHAN(2467, 11), - CHAN(2472, 12), - CHAN(2484, 13), -}; - -static struct ieee80211_channel ar9170_5ghz_chantable[] = { - CHAN(4920, 14), - CHAN(4940, 15), - CHAN(4960, 16), - CHAN(4980, 17), - CHAN(5040, 18), - CHAN(5060, 19), - CHAN(5080, 20), - CHAN(5180, 21), - CHAN(5200, 22), - CHAN(5220, 23), - CHAN(5240, 24), - CHAN(5260, 25), - CHAN(5280, 26), - CHAN(5300, 27), - CHAN(5320, 28), - CHAN(5500, 29), - CHAN(5520, 30), - CHAN(5540, 31), - CHAN(5560, 32), - CHAN(5580, 33), - CHAN(5600, 34), - CHAN(5620, 35), - CHAN(5640, 36), - CHAN(5660, 37), - CHAN(5680, 38), - CHAN(5700, 39), - CHAN(5745, 40), - CHAN(5765, 41), - CHAN(5785, 42), - CHAN(5805, 43), - CHAN(5825, 44), - CHAN(5170, 45), - CHAN(5190, 46), - CHAN(5210, 47), - CHAN(5230, 48), -}; -#undef CHAN - -#define AR9170_HT_CAP \ -{ \ - .ht_supported = true, \ - .cap = IEEE80211_HT_CAP_MAX_AMSDU | \ - IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \ - IEEE80211_HT_CAP_SGI_40 | \ - IEEE80211_HT_CAP_GRN_FLD | \ - IEEE80211_HT_CAP_DSSSCCK40 | \ - IEEE80211_HT_CAP_SM_PS, \ - .ampdu_factor = 3, \ - .ampdu_density = 6, \ - .mcs = { \ - .rx_mask = { 0xff, 0xff, 0, 0, 0x1, 0, 0, 0, 0, 0, }, \ - .rx_highest = cpu_to_le16(300), \ - .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \ - }, \ -} - -static struct ieee80211_supported_band ar9170_band_2GHz = { - .channels = ar9170_2ghz_chantable, - .n_channels = ARRAY_SIZE(ar9170_2ghz_chantable), - .bitrates = ar9170_g_ratetable, - .n_bitrates = ar9170_g_ratetable_size, - .ht_cap = AR9170_HT_CAP, -}; - -static struct ieee80211_supported_band ar9170_band_5GHz = { - .channels = ar9170_5ghz_chantable, - .n_channels = ARRAY_SIZE(ar9170_5ghz_chantable), - .bitrates = ar9170_a_ratetable, - .n_bitrates = ar9170_a_ratetable_size, - .ht_cap = AR9170_HT_CAP, -}; - -static void ar9170_tx(struct ar9170 *ar); - -static inline u16 ar9170_get_seq_h(struct ieee80211_hdr *hdr) -{ - return le16_to_cpu(hdr->seq_ctrl) >> 4; -} - -static inline u16 ar9170_get_seq(struct sk_buff *skb) -{ - struct ar9170_tx_control *txc = (void *) skb->data; - return ar9170_get_seq_h((void *) txc->frame_data); -} - -#ifdef AR9170_QUEUE_DEBUG -static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb) -{ - struct ar9170_tx_control *txc = (void *) skb->data; - struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb); - struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data; - struct ieee80211_hdr *hdr = (void *) txc->frame_data; - - wiphy_debug(ar->hw->wiphy, - "=> FRAME [skb:%p, q:%d, DA:[%pM] s:%d " - "mac_ctrl:%04x, phy_ctrl:%08x, timeout:[%d ms]]\n", - skb, skb_get_queue_mapping(skb), - ieee80211_get_DA(hdr), ar9170_get_seq_h(hdr), - le16_to_cpu(txc->mac_control), le32_to_cpu(txc->phy_control), - jiffies_to_msecs(arinfo->timeout - jiffies)); -} - -static void __ar9170_dump_txqueue(struct ar9170 *ar, - struct sk_buff_head *queue) -{ - struct sk_buff *skb; - int i = 0; - - printk(KERN_DEBUG "---[ cut here ]---\n"); - wiphy_debug(ar->hw->wiphy, "%d entries in queue.\n", - skb_queue_len(queue)); - - skb_queue_walk(queue, skb) { - printk(KERN_DEBUG "index:%d =>\n", i++); - ar9170_print_txheader(ar, skb); - } - if (i != skb_queue_len(queue)) - printk(KERN_DEBUG "WARNING: queue frame counter " - "mismatch %d != %d\n", skb_queue_len(queue), i); - printk(KERN_DEBUG "---[ end ]---\n"); -} -#endif /* AR9170_QUEUE_DEBUG */ - -#ifdef AR9170_QUEUE_DEBUG -static void ar9170_dump_txqueue(struct ar9170 *ar, - struct sk_buff_head *queue) -{ - unsigned long flags; - - spin_lock_irqsave(&queue->lock, flags); - __ar9170_dump_txqueue(ar, queue); - spin_unlock_irqrestore(&queue->lock, flags); -} -#endif /* AR9170_QUEUE_DEBUG */ - -#ifdef AR9170_QUEUE_STOP_DEBUG -static void __ar9170_dump_txstats(struct ar9170 *ar) -{ - int i; - - wiphy_debug(ar->hw->wiphy, "QoS queue stats\n"); - - for (i = 0; i < __AR9170_NUM_TXQ; i++) - wiphy_debug(ar->hw->wiphy, - "queue:%d limit:%d len:%d waitack:%d stopped:%d\n", - i, ar->tx_stats[i].limit, ar->tx_stats[i].len, - skb_queue_len(&ar->tx_status[i]), - ieee80211_queue_stopped(ar->hw, i)); -} -#endif /* AR9170_QUEUE_STOP_DEBUG */ - -/* caller must guarantee exclusive access for _bin_ queue. */ -static void ar9170_recycle_expired(struct ar9170 *ar, - struct sk_buff_head *queue, - struct sk_buff_head *bin) -{ - struct sk_buff *skb, *old = NULL; - unsigned long flags; - - spin_lock_irqsave(&queue->lock, flags); - while ((skb = skb_peek(queue))) { - struct ieee80211_tx_info *txinfo; - struct ar9170_tx_info *arinfo; - - txinfo = IEEE80211_SKB_CB(skb); - arinfo = (void *) txinfo->rate_driver_data; - - if (time_is_before_jiffies(arinfo->timeout)) { -#ifdef AR9170_QUEUE_DEBUG - wiphy_debug(ar->hw->wiphy, - "[%ld > %ld] frame expired => recycle\n", - jiffies, arinfo->timeout); - ar9170_print_txheader(ar, skb); -#endif /* AR9170_QUEUE_DEBUG */ - __skb_unlink(skb, queue); - __skb_queue_tail(bin, skb); - } else { - break; - } - - if (unlikely(old == skb)) { - /* bail out - queue is shot. */ - - WARN_ON(1); - break; - } - old = skb; - } - spin_unlock_irqrestore(&queue->lock, flags); -} - -static void ar9170_tx_status(struct ar9170 *ar, struct sk_buff *skb, - u16 tx_status) -{ - struct ieee80211_tx_info *txinfo; - unsigned int retries = 0; - - txinfo = IEEE80211_SKB_CB(skb); - ieee80211_tx_info_clear_status(txinfo); - - switch (tx_status) { - case AR9170_TX_STATUS_RETRY: - retries = 2; - case AR9170_TX_STATUS_COMPLETE: - txinfo->flags |= IEEE80211_TX_STAT_ACK; - break; - - case AR9170_TX_STATUS_FAILED: - retries = ar->hw->conf.long_frame_max_tx_count; - break; - - default: - wiphy_err(ar->hw->wiphy, - "invalid tx_status response (%x)\n", tx_status); - break; - } - - txinfo->status.rates[0].count = retries + 1; - skb_pull(skb, sizeof(struct ar9170_tx_control)); - ieee80211_tx_status_irqsafe(ar->hw, skb); -} - -void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ar9170_tx_info *arinfo = (void *) info->rate_driver_data; - unsigned int queue = skb_get_queue_mapping(skb); - unsigned long flags; - - spin_lock_irqsave(&ar->tx_stats_lock, flags); - ar->tx_stats[queue].len--; - - if (ar->tx_stats[queue].len < AR9170_NUM_TX_LIMIT_SOFT) { -#ifdef AR9170_QUEUE_STOP_DEBUG - wiphy_debug(ar->hw->wiphy, "wake queue %d\n", queue); - __ar9170_dump_txstats(ar); -#endif /* AR9170_QUEUE_STOP_DEBUG */ - ieee80211_wake_queue(ar->hw, queue); - } - spin_unlock_irqrestore(&ar->tx_stats_lock, flags); - - if (info->flags & IEEE80211_TX_CTL_NO_ACK) { - ar9170_tx_status(ar, skb, AR9170_TX_STATUS_FAILED); - } else { - arinfo->timeout = jiffies + - msecs_to_jiffies(AR9170_TX_TIMEOUT); - - skb_queue_tail(&ar->tx_status[queue], skb); - } - - if (!ar->tx_stats[queue].len && - !skb_queue_empty(&ar->tx_pending[queue])) { - ar9170_tx(ar); - } -} - -static struct sk_buff *ar9170_get_queued_skb(struct ar9170 *ar, - const u8 *mac, - struct sk_buff_head *queue, - const u32 rate) -{ - unsigned long flags; - struct sk_buff *skb; - - /* - * Unfortunately, the firmware does not tell to which (queued) frame - * this transmission status report belongs to. - * - * So we have to make risky guesses - with the scarce information - * the firmware provided (-> destination MAC, and phy_control) - - * and hope that we picked the right one... - */ - - spin_lock_irqsave(&queue->lock, flags); - skb_queue_walk(queue, skb) { - struct ar9170_tx_control *txc = (void *) skb->data; - struct ieee80211_hdr *hdr = (void *) txc->frame_data; - u32 r; - - if (mac && compare_ether_addr(ieee80211_get_DA(hdr), mac)) { -#ifdef AR9170_QUEUE_DEBUG - wiphy_debug(ar->hw->wiphy, - "skip frame => DA %pM != %pM\n", - mac, ieee80211_get_DA(hdr)); - ar9170_print_txheader(ar, skb); -#endif /* AR9170_QUEUE_DEBUG */ - continue; - } - - r = (le32_to_cpu(txc->phy_control) & AR9170_TX_PHY_MCS_MASK) >> - AR9170_TX_PHY_MCS_SHIFT; - - if ((rate != AR9170_TX_INVALID_RATE) && (r != rate)) { -#ifdef AR9170_QUEUE_DEBUG - wiphy_debug(ar->hw->wiphy, - "skip frame => rate %d != %d\n", rate, r); - ar9170_print_txheader(ar, skb); -#endif /* AR9170_QUEUE_DEBUG */ - continue; - } - - __skb_unlink(skb, queue); - spin_unlock_irqrestore(&queue->lock, flags); - return skb; - } - -#ifdef AR9170_QUEUE_DEBUG - wiphy_err(ar->hw->wiphy, - "ESS:[%pM] does not have any outstanding frames in queue.\n", - mac); - __ar9170_dump_txqueue(ar, queue); -#endif /* AR9170_QUEUE_DEBUG */ - spin_unlock_irqrestore(&queue->lock, flags); - - return NULL; -} - -/* - * This worker tries to keeps an maintain tx_status queues. - * So we can guarantee that incoming tx_status reports are - * actually for a pending frame. - */ - -static void ar9170_tx_janitor(struct work_struct *work) -{ - struct ar9170 *ar = container_of(work, struct ar9170, - tx_janitor.work); - struct sk_buff_head waste; - unsigned int i; - bool resched = false; - - if (unlikely(!IS_STARTED(ar))) - return ; - - skb_queue_head_init(&waste); - - for (i = 0; i < __AR9170_NUM_TXQ; i++) { -#ifdef AR9170_QUEUE_DEBUG - wiphy_debug(ar->hw->wiphy, "garbage collector scans queue:%d\n", - i); - ar9170_dump_txqueue(ar, &ar->tx_pending[i]); - ar9170_dump_txqueue(ar, &ar->tx_status[i]); -#endif /* AR9170_QUEUE_DEBUG */ - - ar9170_recycle_expired(ar, &ar->tx_status[i], &waste); - ar9170_recycle_expired(ar, &ar->tx_pending[i], &waste); - skb_queue_purge(&waste); - - if (!skb_queue_empty(&ar->tx_status[i]) || - !skb_queue_empty(&ar->tx_pending[i])) - resched = true; - } - - if (!resched) - return; - - ieee80211_queue_delayed_work(ar->hw, - &ar->tx_janitor, - msecs_to_jiffies(AR9170_JANITOR_DELAY)); -} - -void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len) -{ - struct ar9170_cmd_response *cmd = (void *) buf; - - if ((cmd->type & 0xc0) != 0xc0) { - ar->callback_cmd(ar, len, buf); - return; - } - - /* hardware event handlers */ - switch (cmd->type) { - case 0xc1: { - /* - * TX status notification: - * bytes: 0c c1 XX YY M1 M2 M3 M4 M5 M6 R4 R3 R2 R1 S2 S1 - * - * XX always 81 - * YY always 00 - * M1-M6 is the MAC address - * R1-R4 is the transmit rate - * S1-S2 is the transmit status - */ - - struct sk_buff *skb; - u32 phy = le32_to_cpu(cmd->tx_status.rate); - u32 q = (phy & AR9170_TX_PHY_QOS_MASK) >> - AR9170_TX_PHY_QOS_SHIFT; -#ifdef AR9170_QUEUE_DEBUG - wiphy_debug(ar->hw->wiphy, - "recv tx_status for %pm, p:%08x, q:%d\n", - cmd->tx_status.dst, phy, q); -#endif /* AR9170_QUEUE_DEBUG */ - - skb = ar9170_get_queued_skb(ar, cmd->tx_status.dst, - &ar->tx_status[q], - AR9170_TX_INVALID_RATE); - if (unlikely(!skb)) - return ; - - ar9170_tx_status(ar, skb, le16_to_cpu(cmd->tx_status.status)); - break; - } - - case 0xc0: - /* - * pre-TBTT event - */ - if (ar->vif && ar->vif->type == NL80211_IFTYPE_AP) - ieee80211_queue_work(ar->hw, &ar->beacon_work); - break; - - case 0xc2: - /* - * (IBSS) beacon send notification - * bytes: 04 c2 XX YY B4 B3 B2 B1 - * - * XX always 80 - * YY always 00 - * B1-B4 "should" be the number of send out beacons. - */ - break; - - case 0xc3: - /* End of Atim Window */ - break; - - case 0xc4: - /* BlockACK bitmap */ - break; - - case 0xc5: - /* BlockACK events */ - break; - - case 0xc6: - /* Watchdog Interrupt */ - break; - - case 0xc9: - /* retransmission issue / SIFS/EIFS collision ?! */ - break; - - /* firmware debug */ - case 0xca: - printk(KERN_DEBUG "ar9170 FW: %.*s\n", len - 4, - (char *)buf + 4); - break; - case 0xcb: - len -= 4; - - switch (len) { - case 1: - printk(KERN_DEBUG "ar9170 FW: u8: %#.2x\n", - *((char *)buf + 4)); - break; - case 2: - printk(KERN_DEBUG "ar9170 FW: u8: %#.4x\n", - le16_to_cpup((__le16 *)((char *)buf + 4))); - break; - case 4: - printk(KERN_DEBUG "ar9170 FW: u8: %#.8x\n", - le32_to_cpup((__le32 *)((char *)buf + 4))); - break; - case 8: - printk(KERN_DEBUG "ar9170 FW: u8: %#.16lx\n", - (unsigned long)le64_to_cpup( - (__le64 *)((char *)buf + 4))); - break; - } - break; - case 0xcc: - print_hex_dump_bytes("ar9170 FW:", DUMP_PREFIX_NONE, - (char *)buf + 4, len - 4); - break; - - default: - pr_info("received unhandled event %x\n", cmd->type); - print_hex_dump_bytes("dump:", DUMP_PREFIX_NONE, buf, len); - break; - } -} - -static void ar9170_rx_reset_rx_mpdu(struct ar9170 *ar) -{ - memset(&ar->rx_mpdu.plcp, 0, sizeof(struct ar9170_rx_head)); - ar->rx_mpdu.has_plcp = false; -} - -int ar9170_nag_limiter(struct ar9170 *ar) -{ - bool print_message; - - /* - * we expect all sorts of errors in promiscuous mode. - * don't bother with it, it's OK! - */ - if (ar->sniffer_enabled) - return false; - - /* - * only go for frequent errors! The hardware tends to - * do some stupid thing once in a while under load, in - * noisy environments or just for fun! - */ - if (time_before(jiffies, ar->bad_hw_nagger) && net_ratelimit()) - print_message = true; - else - print_message = false; - - /* reset threshold for "once in a while" */ - ar->bad_hw_nagger = jiffies + HZ / 4; - return print_message; -} - -static int ar9170_rx_mac_status(struct ar9170 *ar, - struct ar9170_rx_head *head, - struct ar9170_rx_macstatus *mac, - struct ieee80211_rx_status *status) -{ - u8 error, decrypt; - - BUILD_BUG_ON(sizeof(struct ar9170_rx_head) != 12); - BUILD_BUG_ON(sizeof(struct ar9170_rx_macstatus) != 4); - - error = mac->error; - if (error & AR9170_RX_ERROR_MMIC) { - status->flag |= RX_FLAG_MMIC_ERROR; - error &= ~AR9170_RX_ERROR_MMIC; - } - - if (error & AR9170_RX_ERROR_PLCP) { - status->flag |= RX_FLAG_FAILED_PLCP_CRC; - error &= ~AR9170_RX_ERROR_PLCP; - - if (!(ar->filter_state & FIF_PLCPFAIL)) - return -EINVAL; - } - - if (error & AR9170_RX_ERROR_FCS) { - status->flag |= RX_FLAG_FAILED_FCS_CRC; - error &= ~AR9170_RX_ERROR_FCS; - - if (!(ar->filter_state & FIF_FCSFAIL)) - return -EINVAL; - } - - decrypt = ar9170_get_decrypt_type(mac); - if (!(decrypt & AR9170_RX_ENC_SOFTWARE) && - decrypt != AR9170_ENC_ALG_NONE) - status->flag |= RX_FLAG_DECRYPTED; - - /* ignore wrong RA errors */ - error &= ~AR9170_RX_ERROR_WRONG_RA; - - if (error & AR9170_RX_ERROR_DECRYPT) { - error &= ~AR9170_RX_ERROR_DECRYPT; - /* - * Rx decryption is done in place, - * the original data is lost anyway. - */ - - return -EINVAL; - } - - /* drop any other error frames */ - if (unlikely(error)) { - /* TODO: update netdevice's RX dropped/errors statistics */ - - if (ar9170_nag_limiter(ar)) - wiphy_debug(ar->hw->wiphy, - "received frame with suspicious error code (%#x).\n", - error); - - return -EINVAL; - } - - status->band = ar->channel->band; - status->freq = ar->channel->center_freq; - - switch (mac->status & AR9170_RX_STATUS_MODULATION_MASK) { - case AR9170_RX_STATUS_MODULATION_CCK: - if (mac->status & AR9170_RX_STATUS_SHORT_PREAMBLE) - status->flag |= RX_FLAG_SHORTPRE; - switch (head->plcp[0]) { - case 0x0a: - status->rate_idx = 0; - break; - case 0x14: - status->rate_idx = 1; - break; - case 0x37: - status->rate_idx = 2; - break; - case 0x6e: - status->rate_idx = 3; - break; - default: - if (ar9170_nag_limiter(ar)) - wiphy_err(ar->hw->wiphy, - "invalid plcp cck rate (%x).\n", - head->plcp[0]); - return -EINVAL; - } - break; - - case AR9170_RX_STATUS_MODULATION_DUPOFDM: - case AR9170_RX_STATUS_MODULATION_OFDM: - switch (head->plcp[0] & 0xf) { - case 0xb: - status->rate_idx = 0; - break; - case 0xf: - status->rate_idx = 1; - break; - case 0xa: - status->rate_idx = 2; - break; - case 0xe: - status->rate_idx = 3; - break; - case 0x9: - status->rate_idx = 4; - break; - case 0xd: - status->rate_idx = 5; - break; - case 0x8: - status->rate_idx = 6; - break; - case 0xc: - status->rate_idx = 7; - break; - default: - if (ar9170_nag_limiter(ar)) - wiphy_err(ar->hw->wiphy, - "invalid plcp ofdm rate (%x).\n", - head->plcp[0]); - return -EINVAL; - } - if (status->band == IEEE80211_BAND_2GHZ) - status->rate_idx += 4; - break; - - case AR9170_RX_STATUS_MODULATION_HT: - if (head->plcp[3] & 0x80) - status->flag |= RX_FLAG_40MHZ; - if (head->plcp[6] & 0x80) - status->flag |= RX_FLAG_SHORT_GI; - - status->rate_idx = clamp(0, 75, head->plcp[6] & 0x7f); - status->flag |= RX_FLAG_HT; - break; - - default: - if (ar9170_nag_limiter(ar)) - wiphy_err(ar->hw->wiphy, "invalid modulation\n"); - return -EINVAL; - } - - return 0; -} - -static void ar9170_rx_phy_status(struct ar9170 *ar, - struct ar9170_rx_phystatus *phy, - struct ieee80211_rx_status *status) -{ - int i; - - BUILD_BUG_ON(sizeof(struct ar9170_rx_phystatus) != 20); - - for (i = 0; i < 3; i++) - if (phy->rssi[i] != 0x80) - status->antenna |= BIT(i); - - /* post-process RSSI */ - for (i = 0; i < 7; i++) - if (phy->rssi[i] & 0x80) - phy->rssi[i] = ((phy->rssi[i] & 0x7f) + 1) & 0x7f; - - /* TODO: we could do something with phy_errors */ - status->signal = ar->noise[0] + phy->rssi_combined; -} - -static struct sk_buff *ar9170_rx_copy_data(u8 *buf, int len) -{ - struct sk_buff *skb; - int reserved = 0; - struct ieee80211_hdr *hdr = (void *) buf; - - if (ieee80211_is_data_qos(hdr->frame_control)) { - u8 *qc = ieee80211_get_qos_ctl(hdr); - reserved += NET_IP_ALIGN; - - if (*qc & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT) - reserved += NET_IP_ALIGN; - } - - if (ieee80211_has_a4(hdr->frame_control)) - reserved += NET_IP_ALIGN; - - reserved = 32 + (reserved & NET_IP_ALIGN); - - skb = dev_alloc_skb(len + reserved); - if (likely(skb)) { - skb_reserve(skb, reserved); - memcpy(skb_put(skb, len), buf, len); - } - - return skb; -} - -/* - * If the frame alignment is right (or the kernel has - * CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), and there - * is only a single MPDU in the USB frame, then we could - * submit to mac80211 the SKB directly. However, since - * there may be multiple packets in one SKB in stream - * mode, and we need to observe the proper ordering, - * this is non-trivial. - */ - -static void ar9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) -{ - struct ar9170_rx_head *head; - struct ar9170_rx_macstatus *mac; - struct ar9170_rx_phystatus *phy = NULL; - struct ieee80211_rx_status status; - struct sk_buff *skb; - int mpdu_len; - - if (unlikely(!IS_STARTED(ar) || len < (sizeof(*mac)))) - return ; - - /* Received MPDU */ - mpdu_len = len - sizeof(*mac); - - mac = (void *)(buf + mpdu_len); - if (unlikely(mac->error & AR9170_RX_ERROR_FATAL)) { - /* this frame is too damaged and can't be used - drop it */ - - return ; - } - - switch (mac->status & AR9170_RX_STATUS_MPDU_MASK) { - case AR9170_RX_STATUS_MPDU_FIRST: - /* first mpdu packet has the plcp header */ - if (likely(mpdu_len >= sizeof(struct ar9170_rx_head))) { - head = (void *) buf; - memcpy(&ar->rx_mpdu.plcp, (void *) buf, - sizeof(struct ar9170_rx_head)); - - mpdu_len -= sizeof(struct ar9170_rx_head); - buf += sizeof(struct ar9170_rx_head); - ar->rx_mpdu.has_plcp = true; - } else { - if (ar9170_nag_limiter(ar)) - wiphy_err(ar->hw->wiphy, - "plcp info is clipped.\n"); - return ; - } - break; - - case AR9170_RX_STATUS_MPDU_LAST: - /* last mpdu has a extra tail with phy status information */ - - if (likely(mpdu_len >= sizeof(struct ar9170_rx_phystatus))) { - mpdu_len -= sizeof(struct ar9170_rx_phystatus); - phy = (void *)(buf + mpdu_len); - } else { - if (ar9170_nag_limiter(ar)) - wiphy_err(ar->hw->wiphy, - "frame tail is clipped.\n"); - return ; - } - - case AR9170_RX_STATUS_MPDU_MIDDLE: - /* middle mpdus are just data */ - if (unlikely(!ar->rx_mpdu.has_plcp)) { - if (!ar9170_nag_limiter(ar)) - return ; - - wiphy_err(ar->hw->wiphy, - "rx stream did not start with a first_mpdu frame tag.\n"); - - return ; - } - - head = &ar->rx_mpdu.plcp; - break; - - case AR9170_RX_STATUS_MPDU_SINGLE: - /* single mpdu - has plcp (head) and phy status (tail) */ - head = (void *) buf; - - mpdu_len -= sizeof(struct ar9170_rx_head); - mpdu_len -= sizeof(struct ar9170_rx_phystatus); - - buf += sizeof(struct ar9170_rx_head); - phy = (void *)(buf + mpdu_len); - break; - - default: - BUG_ON(1); - break; - } - - if (unlikely(mpdu_len < FCS_LEN)) - return ; - - memset(&status, 0, sizeof(status)); - if (unlikely(ar9170_rx_mac_status(ar, head, mac, &status))) - return ; - - if (phy) - ar9170_rx_phy_status(ar, phy, &status); - - skb = ar9170_rx_copy_data(buf, mpdu_len); - if (likely(skb)) { - memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); - ieee80211_rx_irqsafe(ar->hw, skb); - } -} - -void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb) -{ - unsigned int i, tlen, resplen, wlen = 0, clen = 0; - u8 *tbuf, *respbuf; - - tbuf = skb->data; - tlen = skb->len; - - while (tlen >= 4) { - clen = tbuf[1] << 8 | tbuf[0]; - wlen = ALIGN(clen, 4); - - /* check if this is stream has a valid tag.*/ - if (tbuf[2] != 0 || tbuf[3] != 0x4e) { - /* - * TODO: handle the highly unlikely event that the - * corrupted stream has the TAG at the right position. - */ - - /* check if the frame can be repaired. */ - if (!ar->rx_failover_missing) { - /* this is no "short read". */ - if (ar9170_nag_limiter(ar)) { - wiphy_err(ar->hw->wiphy, - "missing tag!\n"); - goto err_telluser; - } else - goto err_silent; - } - - if (ar->rx_failover_missing > tlen) { - if (ar9170_nag_limiter(ar)) { - wiphy_err(ar->hw->wiphy, - "possible multi stream corruption!\n"); - goto err_telluser; - } else - goto err_silent; - } - - memcpy(skb_put(ar->rx_failover, tlen), tbuf, tlen); - ar->rx_failover_missing -= tlen; - - if (ar->rx_failover_missing <= 0) { - /* - * nested ar9170_rx call! - * termination is guaranteed, even when the - * combined frame also have a element with - * a bad tag. - */ - - ar->rx_failover_missing = 0; - ar9170_rx(ar, ar->rx_failover); - - skb_reset_tail_pointer(ar->rx_failover); - skb_trim(ar->rx_failover, 0); - } - - return ; - } - - /* check if stream is clipped */ - if (wlen > tlen - 4) { - if (ar->rx_failover_missing) { - /* TODO: handle double stream corruption. */ - if (ar9170_nag_limiter(ar)) { - wiphy_err(ar->hw->wiphy, - "double rx stream corruption!\n"); - goto err_telluser; - } else - goto err_silent; - } - - /* - * save incomplete data set. - * the firmware will resend the missing bits when - * the rx - descriptor comes round again. - */ - - memcpy(skb_put(ar->rx_failover, tlen), tbuf, tlen); - ar->rx_failover_missing = clen - tlen; - return ; - } - resplen = clen; - respbuf = tbuf + 4; - tbuf += wlen + 4; - tlen -= wlen + 4; - - i = 0; - - /* weird thing, but this is the same in the original driver */ - while (resplen > 2 && i < 12 && - respbuf[0] == 0xff && respbuf[1] == 0xff) { - i += 2; - resplen -= 2; - respbuf += 2; - } - - if (resplen < 4) - continue; - - /* found the 6 * 0xffff marker? */ - if (i == 12) - ar9170_handle_command_response(ar, respbuf, resplen); - else - ar9170_handle_mpdu(ar, respbuf, clen); - } - - if (tlen) { - if (net_ratelimit()) - wiphy_err(ar->hw->wiphy, - "%d bytes of unprocessed data left in rx stream!\n", - tlen); - - goto err_telluser; - } - - return ; - -err_telluser: - wiphy_err(ar->hw->wiphy, - "damaged RX stream data [want:%d, data:%d, rx:%d, pending:%d ]\n", - clen, wlen, tlen, ar->rx_failover_missing); - - if (ar->rx_failover_missing) - print_hex_dump_bytes("rxbuf:", DUMP_PREFIX_OFFSET, - ar->rx_failover->data, - ar->rx_failover->len); - - print_hex_dump_bytes("stream:", DUMP_PREFIX_OFFSET, - skb->data, skb->len); - - wiphy_err(ar->hw->wiphy, - "If you see this message frequently, please check your hardware and cables.\n"); - -err_silent: - if (ar->rx_failover_missing) { - skb_reset_tail_pointer(ar->rx_failover); - skb_trim(ar->rx_failover, 0); - ar->rx_failover_missing = 0; - } -} - -#define AR9170_FILL_QUEUE(queue, ai_fs, cwmin, cwmax, _txop) \ -do { \ - queue.aifs = ai_fs; \ - queue.cw_min = cwmin; \ - queue.cw_max = cwmax; \ - queue.txop = _txop; \ -} while (0) - -static int ar9170_op_start(struct ieee80211_hw *hw) -{ - struct ar9170 *ar = hw->priv; - int err, i; - - mutex_lock(&ar->mutex); - - /* reinitialize queues statistics */ - memset(&ar->tx_stats, 0, sizeof(ar->tx_stats)); - for (i = 0; i < __AR9170_NUM_TXQ; i++) - ar->tx_stats[i].limit = AR9170_TXQ_DEPTH; - - /* reset QoS defaults */ - AR9170_FILL_QUEUE(ar->edcf[0], 3, 15, 1023, 0); /* BEST EFFORT*/ - AR9170_FILL_QUEUE(ar->edcf[1], 7, 15, 1023, 0); /* BACKGROUND */ - AR9170_FILL_QUEUE(ar->edcf[2], 2, 7, 15, 94); /* VIDEO */ - AR9170_FILL_QUEUE(ar->edcf[3], 2, 3, 7, 47); /* VOICE */ - AR9170_FILL_QUEUE(ar->edcf[4], 2, 3, 7, 0); /* SPECIAL */ - - /* set sane AMPDU defaults */ - ar->global_ampdu_density = 6; - ar->global_ampdu_factor = 3; - - ar->bad_hw_nagger = jiffies; - - err = ar->open(ar); - if (err) - goto out; - - err = ar9170_init_mac(ar); - if (err) - goto out; - - err = ar9170_set_qos(ar); - if (err) - goto out; - - err = ar9170_init_phy(ar, IEEE80211_BAND_2GHZ); - if (err) - goto out; - - err = ar9170_init_rf(ar); - if (err) - goto out; - - /* start DMA */ - err = ar9170_write_reg(ar, 0x1c3d30, 0x100); - if (err) - goto out; - - ar->state = AR9170_STARTED; - -out: - mutex_unlock(&ar->mutex); - return err; -} - -static void ar9170_op_stop(struct ieee80211_hw *hw) -{ - struct ar9170 *ar = hw->priv; - unsigned int i; - - if (IS_STARTED(ar)) - ar->state = AR9170_IDLE; - - cancel_delayed_work_sync(&ar->tx_janitor); -#ifdef CONFIG_AR9170_LEDS - cancel_delayed_work_sync(&ar->led_work); -#endif - cancel_work_sync(&ar->beacon_work); - - mutex_lock(&ar->mutex); - - if (IS_ACCEPTING_CMD(ar)) { - ar9170_set_leds_state(ar, 0); - - /* stop DMA */ - ar9170_write_reg(ar, 0x1c3d30, 0); - ar->stop(ar); - } - - for (i = 0; i < __AR9170_NUM_TXQ; i++) { - skb_queue_purge(&ar->tx_pending[i]); - skb_queue_purge(&ar->tx_status[i]); - } - - mutex_unlock(&ar->mutex); -} - -static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb) -{ - struct ieee80211_hdr *hdr; - struct ar9170_tx_control *txc; - struct ieee80211_tx_info *info; - struct ieee80211_tx_rate *txrate; - struct ar9170_tx_info *arinfo; - unsigned int queue = skb_get_queue_mapping(skb); - u16 keytype = 0; - u16 len, icv = 0; - - BUILD_BUG_ON(sizeof(*arinfo) > sizeof(info->rate_driver_data)); - - hdr = (void *)skb->data; - info = IEEE80211_SKB_CB(skb); - len = skb->len; - - txc = (void *)skb_push(skb, sizeof(*txc)); - - if (info->control.hw_key) { - icv = info->control.hw_key->icv_len; - - switch (info->control.hw_key->cipher) { - case WLAN_CIPHER_SUITE_WEP40: - case WLAN_CIPHER_SUITE_WEP104: - case WLAN_CIPHER_SUITE_TKIP: - keytype = AR9170_TX_MAC_ENCR_RC4; - break; - case WLAN_CIPHER_SUITE_CCMP: - keytype = AR9170_TX_MAC_ENCR_AES; - break; - default: - WARN_ON(1); - goto err_out; - } - } - - /* Length */ - txc->length = cpu_to_le16(len + icv + 4); - - txc->mac_control = cpu_to_le16(AR9170_TX_MAC_HW_DURATION | - AR9170_TX_MAC_BACKOFF); - txc->mac_control |= cpu_to_le16(ar9170_qos_hwmap[queue] << - AR9170_TX_MAC_QOS_SHIFT); - txc->mac_control |= cpu_to_le16(keytype); - txc->phy_control = cpu_to_le32(0); - - if (info->flags & IEEE80211_TX_CTL_NO_ACK) - txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_NO_ACK); - - txrate = &info->control.rates[0]; - if (txrate->flags & IEEE80211_TX_RC_USE_CTS_PROTECT) - txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_PROT_CTS); - else if (txrate->flags & IEEE80211_TX_RC_USE_RTS_CTS) - txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_PROT_RTS); - - arinfo = (void *)info->rate_driver_data; - arinfo->timeout = jiffies + msecs_to_jiffies(AR9170_QUEUE_TIMEOUT); - - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && - (is_valid_ether_addr(ieee80211_get_DA(hdr)))) { - /* - * WARNING: - * Putting the QoS queue bits into an unexplored territory is - * certainly not elegant. - * - * In my defense: This idea provides a reasonable way to - * smuggle valuable information to the tx_status callback. - * Also, the idea behind this bit-abuse came straight from - * the original driver code. - */ - - txc->phy_control |= - cpu_to_le32(queue << AR9170_TX_PHY_QOS_SHIFT); - - txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE); - } - - return 0; - -err_out: - skb_pull(skb, sizeof(*txc)); - return -EINVAL; -} - -static void ar9170_tx_prepare_phy(struct ar9170 *ar, struct sk_buff *skb) -{ - struct ar9170_tx_control *txc; - struct ieee80211_tx_info *info; - struct ieee80211_rate *rate = NULL; - struct ieee80211_tx_rate *txrate; - u32 power, chains; - - txc = (void *) skb->data; - info = IEEE80211_SKB_CB(skb); - txrate = &info->control.rates[0]; - - if (txrate->flags & IEEE80211_TX_RC_GREEN_FIELD) - txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_GREENFIELD); - - if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) - txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_SHORT_PREAMBLE); - - if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) - txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_BW_40MHZ); - /* this works because 40 MHz is 2 and dup is 3 */ - if (txrate->flags & IEEE80211_TX_RC_DUP_DATA) - txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_BW_40MHZ_DUP); - - if (txrate->flags & IEEE80211_TX_RC_SHORT_GI) - txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_SHORT_GI); - - if (txrate->flags & IEEE80211_TX_RC_MCS) { - u32 r = txrate->idx; - u8 *txpower; - - /* heavy clip control */ - txc->phy_control |= cpu_to_le32((r & 0x7) << 7); - - r <<= AR9170_TX_PHY_MCS_SHIFT; - BUG_ON(r & ~AR9170_TX_PHY_MCS_MASK); - - txc->phy_control |= cpu_to_le32(r & AR9170_TX_PHY_MCS_MASK); - txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_MOD_HT); - - if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) { - if (info->band == IEEE80211_BAND_5GHZ) - txpower = ar->power_5G_ht40; - else - txpower = ar->power_2G_ht40; - } else { - if (info->band == IEEE80211_BAND_5GHZ) - txpower = ar->power_5G_ht20; - else - txpower = ar->power_2G_ht20; - } - - power = txpower[(txrate->idx) & 7]; - } else { - u8 *txpower; - u32 mod; - u32 phyrate; - u8 idx = txrate->idx; - - if (info->band != IEEE80211_BAND_2GHZ) { - idx += 4; - txpower = ar->power_5G_leg; - mod = AR9170_TX_PHY_MOD_OFDM; - } else { - if (idx < 4) { - txpower = ar->power_2G_cck; - mod = AR9170_TX_PHY_MOD_CCK; - } else { - mod = AR9170_TX_PHY_MOD_OFDM; - txpower = ar->power_2G_ofdm; - } - } - - rate = &__ar9170_ratetable[idx]; - - phyrate = rate->hw_value & 0xF; - power = txpower[(rate->hw_value & 0x30) >> 4]; - phyrate <<= AR9170_TX_PHY_MCS_SHIFT; - - txc->phy_control |= cpu_to_le32(mod); - txc->phy_control |= cpu_to_le32(phyrate); - } - - power <<= AR9170_TX_PHY_TX_PWR_SHIFT; - power &= AR9170_TX_PHY_TX_PWR_MASK; - txc->phy_control |= cpu_to_le32(power); - - /* set TX chains */ - if (ar->eeprom.tx_mask == 1) { - chains = AR9170_TX_PHY_TXCHAIN_1; - } else { - chains = AR9170_TX_PHY_TXCHAIN_2; - - /* >= 36M legacy OFDM - use only one chain */ - if (rate && rate->bitrate >= 360) - chains = AR9170_TX_PHY_TXCHAIN_1; - } - txc->phy_control |= cpu_to_le32(chains << AR9170_TX_PHY_TXCHAIN_SHIFT); -} - -static void ar9170_tx(struct ar9170 *ar) -{ - struct sk_buff *skb; - unsigned long flags; - struct ieee80211_tx_info *info; - struct ar9170_tx_info *arinfo; - unsigned int i, frames, frames_failed, remaining_space; - int err; - bool schedule_garbagecollector = false; - - BUILD_BUG_ON(sizeof(*arinfo) > sizeof(info->rate_driver_data)); - - if (unlikely(!IS_STARTED(ar))) - return ; - - remaining_space = AR9170_TX_MAX_PENDING; - - for (i = 0; i < __AR9170_NUM_TXQ; i++) { - spin_lock_irqsave(&ar->tx_stats_lock, flags); - frames = min(ar->tx_stats[i].limit - ar->tx_stats[i].len, - skb_queue_len(&ar->tx_pending[i])); - - if (remaining_space < frames) { -#ifdef AR9170_QUEUE_DEBUG - wiphy_debug(ar->hw->wiphy, - "tx quota reached queue:%d, " - "remaining slots:%d, needed:%d\n", - i, remaining_space, frames); -#endif /* AR9170_QUEUE_DEBUG */ - frames = remaining_space; - } - - ar->tx_stats[i].len += frames; - ar->tx_stats[i].count += frames; - if (ar->tx_stats[i].len >= ar->tx_stats[i].limit) { -#ifdef AR9170_QUEUE_DEBUG - wiphy_debug(ar->hw->wiphy, "queue %d full\n", i); - wiphy_debug(ar->hw->wiphy, "stuck frames: ===>\n"); - ar9170_dump_txqueue(ar, &ar->tx_pending[i]); - ar9170_dump_txqueue(ar, &ar->tx_status[i]); -#endif /* AR9170_QUEUE_DEBUG */ - -#ifdef AR9170_QUEUE_STOP_DEBUG - wiphy_debug(ar->hw->wiphy, "stop queue %d\n", i); - __ar9170_dump_txstats(ar); -#endif /* AR9170_QUEUE_STOP_DEBUG */ - ieee80211_stop_queue(ar->hw, i); - } - - spin_unlock_irqrestore(&ar->tx_stats_lock, flags); - - if (!frames) - continue; - - frames_failed = 0; - while (frames) { - skb = skb_dequeue(&ar->tx_pending[i]); - if (unlikely(!skb)) { - frames_failed += frames; - frames = 0; - break; - } - - info = IEEE80211_SKB_CB(skb); - arinfo = (void *) info->rate_driver_data; - - /* TODO: cancel stuck frames */ - arinfo->timeout = jiffies + - msecs_to_jiffies(AR9170_TX_TIMEOUT); - -#ifdef AR9170_QUEUE_DEBUG - wiphy_debug(ar->hw->wiphy, "send frame q:%d =>\n", i); - ar9170_print_txheader(ar, skb); -#endif /* AR9170_QUEUE_DEBUG */ - - err = ar->tx(ar, skb); - if (unlikely(err)) { - frames_failed++; - dev_kfree_skb_any(skb); - } else { - remaining_space--; - schedule_garbagecollector = true; - } - - frames--; - } - -#ifdef AR9170_QUEUE_DEBUG - wiphy_debug(ar->hw->wiphy, - "ar9170_tx report for queue %d\n", i); - - wiphy_debug(ar->hw->wiphy, - "unprocessed pending frames left:\n"); - ar9170_dump_txqueue(ar, &ar->tx_pending[i]); -#endif /* AR9170_QUEUE_DEBUG */ - - if (unlikely(frames_failed)) { -#ifdef AR9170_QUEUE_DEBUG - wiphy_debug(ar->hw->wiphy, - "frames failed %d =>\n", frames_failed); -#endif /* AR9170_QUEUE_DEBUG */ - - spin_lock_irqsave(&ar->tx_stats_lock, flags); - ar->tx_stats[i].len -= frames_failed; - ar->tx_stats[i].count -= frames_failed; -#ifdef AR9170_QUEUE_STOP_DEBUG - wiphy_debug(ar->hw->wiphy, "wake queue %d\n", i); - __ar9170_dump_txstats(ar); -#endif /* AR9170_QUEUE_STOP_DEBUG */ - ieee80211_wake_queue(ar->hw, i); - spin_unlock_irqrestore(&ar->tx_stats_lock, flags); - } - } - - if (!schedule_garbagecollector) - return; - - ieee80211_queue_delayed_work(ar->hw, - &ar->tx_janitor, - msecs_to_jiffies(AR9170_JANITOR_DELAY)); -} - -void ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) -{ - struct ar9170 *ar = hw->priv; - struct ieee80211_tx_info *info; - unsigned int queue; - - if (unlikely(!IS_STARTED(ar))) - goto err_free; - - if (unlikely(ar9170_tx_prepare(ar, skb))) - goto err_free; - - queue = skb_get_queue_mapping(skb); - info = IEEE80211_SKB_CB(skb); - ar9170_tx_prepare_phy(ar, skb); - skb_queue_tail(&ar->tx_pending[queue], skb); - - ar9170_tx(ar); - return; - -err_free: - dev_kfree_skb_any(skb); -} - -static int ar9170_op_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct ar9170 *ar = hw->priv; - struct ath_common *common = &ar->common; - int err = 0; - - mutex_lock(&ar->mutex); - - if (ar->vif) { - err = -EBUSY; - goto unlock; - } - - ar->vif = vif; - memcpy(common->macaddr, vif->addr, ETH_ALEN); - - if (modparam_nohwcrypt || (ar->vif->type != NL80211_IFTYPE_STATION)) { - ar->rx_software_decryption = true; - ar->disable_offload = true; - } - - ar->cur_filter = 0; - err = ar9170_update_frame_filter(ar, AR9170_MAC_REG_FTF_DEFAULTS); - if (err) - goto unlock; - - err = ar9170_set_operating_mode(ar); - -unlock: - mutex_unlock(&ar->mutex); - return err; -} - -static void ar9170_op_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct ar9170 *ar = hw->priv; - - mutex_lock(&ar->mutex); - ar->vif = NULL; - ar9170_update_frame_filter(ar, 0); - ar9170_set_beacon_timers(ar); - dev_kfree_skb(ar->beacon); - ar->beacon = NULL; - ar->sniffer_enabled = false; - ar->rx_software_decryption = false; - ar9170_set_operating_mode(ar); - mutex_unlock(&ar->mutex); -} - -static int ar9170_op_config(struct ieee80211_hw *hw, u32 changed) -{ - struct ar9170 *ar = hw->priv; - int err = 0; - - mutex_lock(&ar->mutex); - - if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) { - /* TODO */ - err = 0; - } - - if (changed & IEEE80211_CONF_CHANGE_PS) { - /* TODO */ - err = 0; - } - - if (changed & IEEE80211_CONF_CHANGE_POWER) { - /* TODO */ - err = 0; - } - - if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) { - /* - * is it long_frame_max_tx_count or short_frame_max_tx_count? - */ - - err = ar9170_set_hwretry_limit(ar, - ar->hw->conf.long_frame_max_tx_count); - if (err) - goto out; - } - - if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { - - /* adjust slot time for 5 GHz */ - err = ar9170_set_slot_time(ar); - if (err) - goto out; - - err = ar9170_set_dyn_sifs_ack(ar); - if (err) - goto out; - - err = ar9170_set_channel(ar, hw->conf.channel, - AR9170_RFI_NONE, - nl80211_to_ar9170(hw->conf.channel_type)); - if (err) - goto out; - } - -out: - mutex_unlock(&ar->mutex); - return err; -} - -static u64 ar9170_op_prepare_multicast(struct ieee80211_hw *hw, - struct netdev_hw_addr_list *mc_list) -{ - u64 mchash; - struct netdev_hw_addr *ha; - - /* always get broadcast frames */ - mchash = 1ULL << (0xff >> 2); - - netdev_hw_addr_list_for_each(ha, mc_list) - mchash |= 1ULL << (ha->addr[5] >> 2); - - return mchash; -} - -static void ar9170_op_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *new_flags, - u64 multicast) -{ - struct ar9170 *ar = hw->priv; - - if (unlikely(!IS_ACCEPTING_CMD(ar))) - return ; - - mutex_lock(&ar->mutex); - - /* mask supported flags */ - *new_flags &= FIF_ALLMULTI | FIF_CONTROL | FIF_BCN_PRBRESP_PROMISC | - FIF_PROMISC_IN_BSS | FIF_FCSFAIL | FIF_PLCPFAIL; - ar->filter_state = *new_flags; - /* - * We can support more by setting the sniffer bit and - * then checking the error flags, later. - */ - - if (changed_flags & FIF_ALLMULTI && *new_flags & FIF_ALLMULTI) - multicast = ~0ULL; - - if (multicast != ar->cur_mc_hash) - ar9170_update_multicast(ar, multicast); - - if (changed_flags & FIF_CONTROL) { - u32 filter = AR9170_MAC_REG_FTF_PSPOLL | - AR9170_MAC_REG_FTF_RTS | - AR9170_MAC_REG_FTF_CTS | - AR9170_MAC_REG_FTF_ACK | - AR9170_MAC_REG_FTF_CFE | - AR9170_MAC_REG_FTF_CFE_ACK; - - if (*new_flags & FIF_CONTROL) - filter |= ar->cur_filter; - else - filter &= (~ar->cur_filter); - - ar9170_update_frame_filter(ar, filter); - } - - if (changed_flags & FIF_PROMISC_IN_BSS) { - ar->sniffer_enabled = ((*new_flags) & FIF_PROMISC_IN_BSS) != 0; - ar9170_set_operating_mode(ar); - } - - mutex_unlock(&ar->mutex); -} - - -static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, - u32 changed) -{ - struct ar9170 *ar = hw->priv; - struct ath_common *common = &ar->common; - int err = 0; - - mutex_lock(&ar->mutex); - - if (changed & BSS_CHANGED_BSSID) { - memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); - err = ar9170_set_operating_mode(ar); - if (err) - goto out; - } - - if (changed & BSS_CHANGED_BEACON_ENABLED) - ar->enable_beacon = bss_conf->enable_beacon; - - if (changed & BSS_CHANGED_BEACON) { - err = ar9170_update_beacon(ar); - if (err) - goto out; - } - - if (changed & (BSS_CHANGED_BEACON_ENABLED | BSS_CHANGED_BEACON | - BSS_CHANGED_BEACON_INT)) { - err = ar9170_set_beacon_timers(ar); - if (err) - goto out; - } - - if (changed & BSS_CHANGED_ASSOC) { -#ifndef CONFIG_AR9170_LEDS - /* enable assoc LED. */ - err = ar9170_set_leds_state(ar, bss_conf->assoc ? 2 : 0); -#endif /* CONFIG_AR9170_LEDS */ - } - - if (changed & BSS_CHANGED_HT) { - /* TODO */ - err = 0; - } - - if (changed & BSS_CHANGED_ERP_SLOT) { - err = ar9170_set_slot_time(ar); - if (err) - goto out; - } - - if (changed & BSS_CHANGED_BASIC_RATES) { - err = ar9170_set_basic_rates(ar); - if (err) - goto out; - } - -out: - mutex_unlock(&ar->mutex); -} - -static u64 ar9170_op_get_tsf(struct ieee80211_hw *hw) -{ - struct ar9170 *ar = hw->priv; - int err; - u64 tsf; -#define NR 3 - static const u32 addr[NR] = { AR9170_MAC_REG_TSF_H, - AR9170_MAC_REG_TSF_L, - AR9170_MAC_REG_TSF_H }; - u32 val[NR]; - int loops = 0; - - mutex_lock(&ar->mutex); - - while (loops++ < 10) { - err = ar9170_read_mreg(ar, NR, addr, val); - if (err || val[0] == val[2]) - break; - } - - mutex_unlock(&ar->mutex); - - if (WARN_ON(err)) - return 0; - tsf = val[0]; - tsf = (tsf << 32) | val[1]; - return tsf; -#undef NR -} - -static int ar9170_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, - struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key) -{ - struct ar9170 *ar = hw->priv; - int err = 0, i; - u8 ktype; - - if ((!ar->vif) || (ar->disable_offload)) - return -EOPNOTSUPP; - - switch (key->cipher) { - case WLAN_CIPHER_SUITE_WEP40: - ktype = AR9170_ENC_ALG_WEP64; - break; - case WLAN_CIPHER_SUITE_WEP104: - ktype = AR9170_ENC_ALG_WEP128; - break; - case WLAN_CIPHER_SUITE_TKIP: - ktype = AR9170_ENC_ALG_TKIP; - break; - case WLAN_CIPHER_SUITE_CCMP: - ktype = AR9170_ENC_ALG_AESCCMP; - break; - default: - return -EOPNOTSUPP; - } - - mutex_lock(&ar->mutex); - if (cmd == SET_KEY) { - if (unlikely(!IS_STARTED(ar))) { - err = -EOPNOTSUPP; - goto out; - } - - /* group keys need all-zeroes address */ - if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) - sta = NULL; - - if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { - for (i = 0; i < 64; i++) - if (!(ar->usedkeys & BIT(i))) - break; - if (i == 64) { - ar->rx_software_decryption = true; - ar9170_set_operating_mode(ar); - err = -ENOSPC; - goto out; - } - } else { - i = 64 + key->keyidx; - } - - key->hw_key_idx = i; - - err = ar9170_upload_key(ar, i, sta ? sta->addr : NULL, ktype, 0, - key->key, min_t(u8, 16, key->keylen)); - if (err) - goto out; - - if (key->cipher == WLAN_CIPHER_SUITE_TKIP) { - err = ar9170_upload_key(ar, i, sta ? sta->addr : NULL, - ktype, 1, key->key + 16, 16); - if (err) - goto out; - - /* - * hardware is not capable generating the MMIC - * for fragmented frames! - */ - key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; - } - - if (i < 64) - ar->usedkeys |= BIT(i); - - key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - } else { - if (unlikely(!IS_STARTED(ar))) { - /* The device is gone... together with the key ;-) */ - err = 0; - goto out; - } - - err = ar9170_disable_key(ar, key->hw_key_idx); - if (err) - goto out; - - if (key->hw_key_idx < 64) { - ar->usedkeys &= ~BIT(key->hw_key_idx); - } else { - err = ar9170_upload_key(ar, key->hw_key_idx, NULL, - AR9170_ENC_ALG_NONE, 0, - NULL, 0); - if (err) - goto out; - - if (key->cipher == WLAN_CIPHER_SUITE_TKIP) { - err = ar9170_upload_key(ar, key->hw_key_idx, - NULL, - AR9170_ENC_ALG_NONE, 1, - NULL, 0); - if (err) - goto out; - } - - } - } - - ar9170_regwrite_begin(ar); - ar9170_regwrite(AR9170_MAC_REG_ROLL_CALL_TBL_L, ar->usedkeys); - ar9170_regwrite(AR9170_MAC_REG_ROLL_CALL_TBL_H, ar->usedkeys >> 32); - ar9170_regwrite_finish(); - err = ar9170_regwrite_result(); - -out: - mutex_unlock(&ar->mutex); - - return err; -} - -static int ar9170_get_stats(struct ieee80211_hw *hw, - struct ieee80211_low_level_stats *stats) -{ - struct ar9170 *ar = hw->priv; - u32 val; - int err; - - mutex_lock(&ar->mutex); - err = ar9170_read_reg(ar, AR9170_MAC_REG_TX_RETRY, &val); - ar->stats.dot11ACKFailureCount += val; - - memcpy(stats, &ar->stats, sizeof(*stats)); - mutex_unlock(&ar->mutex); - - return 0; -} - -static int ar9170_get_survey(struct ieee80211_hw *hw, int idx, - struct survey_info *survey) -{ - struct ar9170 *ar = hw->priv; - struct ieee80211_conf *conf = &hw->conf; - - if (idx != 0) - return -ENOENT; - - /* TODO: update noise value, e.g. call ar9170_set_channel */ - - survey->channel = conf->channel; - survey->filled = SURVEY_INFO_NOISE_DBM; - survey->noise = ar->noise[0]; - - return 0; -} - -static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue, - const struct ieee80211_tx_queue_params *param) -{ - struct ar9170 *ar = hw->priv; - int ret; - - mutex_lock(&ar->mutex); - if (queue < __AR9170_NUM_TXQ) { - memcpy(&ar->edcf[ar9170_qos_hwmap[queue]], - param, sizeof(*param)); - - ret = ar9170_set_qos(ar); - } else { - ret = -EINVAL; - } - - mutex_unlock(&ar->mutex); - return ret; -} - -static int ar9170_ampdu_action(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, - u8 buf_size) -{ - switch (action) { - case IEEE80211_AMPDU_RX_START: - case IEEE80211_AMPDU_RX_STOP: - /* Handled by firmware */ - break; - - default: - return -EOPNOTSUPP; - } - - return 0; -} - -static const struct ieee80211_ops ar9170_ops = { - .start = ar9170_op_start, - .stop = ar9170_op_stop, - .tx = ar9170_op_tx, - .add_interface = ar9170_op_add_interface, - .remove_interface = ar9170_op_remove_interface, - .config = ar9170_op_config, - .prepare_multicast = ar9170_op_prepare_multicast, - .configure_filter = ar9170_op_configure_filter, - .conf_tx = ar9170_conf_tx, - .bss_info_changed = ar9170_op_bss_info_changed, - .get_tsf = ar9170_op_get_tsf, - .set_key = ar9170_set_key, - .get_stats = ar9170_get_stats, - .get_survey = ar9170_get_survey, - .ampdu_action = ar9170_ampdu_action, -}; - -void *ar9170_alloc(size_t priv_size) -{ - struct ieee80211_hw *hw; - struct ar9170 *ar; - struct sk_buff *skb; - int i; - - /* - * this buffer is used for rx stream reconstruction. - * Under heavy load this device (or the transport layer?) - * tends to split the streams into separate rx descriptors. - */ - - skb = __dev_alloc_skb(AR9170_RX_STREAM_MAX_SIZE, GFP_KERNEL); - if (!skb) - goto err_nomem; - - hw = ieee80211_alloc_hw(priv_size, &ar9170_ops); - if (!hw) - goto err_nomem; - - ar = hw->priv; - ar->hw = hw; - ar->rx_failover = skb; - - mutex_init(&ar->mutex); - spin_lock_init(&ar->cmdlock); - spin_lock_init(&ar->tx_stats_lock); - for (i = 0; i < __AR9170_NUM_TXQ; i++) { - skb_queue_head_init(&ar->tx_status[i]); - skb_queue_head_init(&ar->tx_pending[i]); - } - ar9170_rx_reset_rx_mpdu(ar); - INIT_WORK(&ar->beacon_work, ar9170_new_beacon); - INIT_DELAYED_WORK(&ar->tx_janitor, ar9170_tx_janitor); - - /* all hw supports 2.4 GHz, so set channel to 1 by default */ - ar->channel = &ar9170_2ghz_chantable[0]; - - /* first part of wiphy init */ - ar->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_WDS) | - BIT(NL80211_IFTYPE_ADHOC); - ar->hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_SIGNAL_DBM; - - ar->hw->queues = __AR9170_NUM_TXQ; - ar->hw->extra_tx_headroom = 8; - - ar->hw->max_rates = 1; - ar->hw->max_rate_tries = 3; - - for (i = 0; i < ARRAY_SIZE(ar->noise); i++) - ar->noise[i] = -95; /* ATH_DEFAULT_NOISE_FLOOR */ - - return ar; - -err_nomem: - kfree_skb(skb); - return ERR_PTR(-ENOMEM); -} - -static int ar9170_read_eeprom(struct ar9170 *ar) -{ -#define RW 8 /* number of words to read at once */ -#define RB (sizeof(u32) * RW) - struct ath_regulatory *regulatory = &ar->common.regulatory; - u8 *eeprom = (void *)&ar->eeprom; - u8 *addr = ar->eeprom.mac_address; - __le32 offsets[RW]; - unsigned int rx_streams, tx_streams, tx_params = 0; - int i, j, err, bands = 0; - - BUILD_BUG_ON(sizeof(ar->eeprom) & 3); - - BUILD_BUG_ON(RB > AR9170_MAX_CMD_LEN - 4); -#ifndef __CHECKER__ - /* don't want to handle trailing remains */ - BUILD_BUG_ON(sizeof(ar->eeprom) % RB); -#endif - - for (i = 0; i < sizeof(ar->eeprom)/RB; i++) { - for (j = 0; j < RW; j++) - offsets[j] = cpu_to_le32(AR9170_EEPROM_START + - RB * i + 4 * j); - - err = ar->exec_cmd(ar, AR9170_CMD_RREG, - RB, (u8 *) &offsets, - RB, eeprom + RB * i); - if (err) - return err; - } - -#undef RW -#undef RB - - if (ar->eeprom.length == cpu_to_le16(0xFFFF)) - return -ENODATA; - - if (ar->eeprom.operating_flags & AR9170_OPFLAG_2GHZ) { - ar->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &ar9170_band_2GHz; - bands++; - } - if (ar->eeprom.operating_flags & AR9170_OPFLAG_5GHZ) { - ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &ar9170_band_5GHz; - bands++; - } - - rx_streams = hweight8(ar->eeprom.rx_mask); - tx_streams = hweight8(ar->eeprom.tx_mask); - - if (rx_streams != tx_streams) - tx_params = IEEE80211_HT_MCS_TX_RX_DIFF; - - if (tx_streams >= 1 && tx_streams <= IEEE80211_HT_MCS_TX_MAX_STREAMS) - tx_params = (tx_streams - 1) << - IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; - - ar9170_band_2GHz.ht_cap.mcs.tx_params |= tx_params; - ar9170_band_5GHz.ht_cap.mcs.tx_params |= tx_params; - - /* - * I measured this, a bandswitch takes roughly - * 135 ms and a frequency switch about 80. - * - * FIXME: measure these values again once EEPROM settings - * are used, that will influence them! - */ - if (bands == 2) - ar->hw->channel_change_time = 135 * 1000; - else - ar->hw->channel_change_time = 80 * 1000; - - regulatory->current_rd = le16_to_cpu(ar->eeprom.reg_domain[0]); - regulatory->current_rd_ext = le16_to_cpu(ar->eeprom.reg_domain[1]); - - /* second part of wiphy init */ - SET_IEEE80211_PERM_ADDR(ar->hw, addr); - - return bands ? 0 : -EINVAL; -} - -static int ar9170_reg_notifier(struct wiphy *wiphy, - struct regulatory_request *request) -{ - struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); - struct ar9170 *ar = hw->priv; - - return ath_reg_notifier_apply(wiphy, request, &ar->common.regulatory); -} - -int ar9170_register(struct ar9170 *ar, struct device *pdev) -{ - struct ath_regulatory *regulatory = &ar->common.regulatory; - int err; - - /* try to read EEPROM, init MAC addr */ - err = ar9170_read_eeprom(ar); - if (err) - goto err_out; - - err = ath_regd_init(regulatory, ar->hw->wiphy, - ar9170_reg_notifier); - if (err) - goto err_out; - - err = ieee80211_register_hw(ar->hw); - if (err) - goto err_out; - - if (!ath_is_world_regd(regulatory)) - regulatory_hint(ar->hw->wiphy, regulatory->alpha2); - - err = ar9170_init_leds(ar); - if (err) - goto err_unreg; - -#ifdef CONFIG_AR9170_LEDS - err = ar9170_register_leds(ar); - if (err) - goto err_unreg; -#endif /* CONFIG_AR9170_LEDS */ - - dev_info(pdev, "Atheros AR9170 is registered as '%s'\n", - wiphy_name(ar->hw->wiphy)); - - ar->registered = true; - return 0; - -err_unreg: - ieee80211_unregister_hw(ar->hw); - -err_out: - return err; -} - -void ar9170_unregister(struct ar9170 *ar) -{ - if (ar->registered) { -#ifdef CONFIG_AR9170_LEDS - ar9170_unregister_leds(ar); -#endif /* CONFIG_AR9170_LEDS */ - - ieee80211_unregister_hw(ar->hw); - } - - kfree_skb(ar->rx_failover); - mutex_destroy(&ar->mutex); -} diff --git a/drivers/net/wireless/ath/ar9170/phy.c b/drivers/net/wireless/ath/ar9170/phy.c deleted file mode 100644 index aa8d06ba1ee4..000000000000 --- a/drivers/net/wireless/ath/ar9170/phy.c +++ /dev/null @@ -1,1719 +0,0 @@ -/* - * Atheros AR9170 driver - * - * PHY and RF code - * - * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 Atheros Communications, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <linux/bitrev.h> -#include "ar9170.h" -#include "cmd.h" - -static int ar9170_init_power_cal(struct ar9170 *ar) -{ - ar9170_regwrite_begin(ar); - - ar9170_regwrite(0x1bc000 + 0x993c, 0x7f); - ar9170_regwrite(0x1bc000 + 0x9934, 0x3f3f3f3f); - ar9170_regwrite(0x1bc000 + 0x9938, 0x3f3f3f3f); - ar9170_regwrite(0x1bc000 + 0xa234, 0x3f3f3f3f); - ar9170_regwrite(0x1bc000 + 0xa238, 0x3f3f3f3f); - ar9170_regwrite(0x1bc000 + 0xa38c, 0x3f3f3f3f); - ar9170_regwrite(0x1bc000 + 0xa390, 0x3f3f3f3f); - ar9170_regwrite(0x1bc000 + 0xa3cc, 0x3f3f3f3f); - ar9170_regwrite(0x1bc000 + 0xa3d0, 0x3f3f3f3f); - ar9170_regwrite(0x1bc000 + 0xa3d4, 0x3f3f3f3f); - - ar9170_regwrite_finish(); - return ar9170_regwrite_result(); -} - -struct ar9170_phy_init { - u32 reg, _5ghz_20, _5ghz_40, _2ghz_40, _2ghz_20; -}; - -static struct ar9170_phy_init ar5416_phy_init[] = { - { 0x1c5800, 0x00000007, 0x00000007, 0x00000007, 0x00000007, }, - { 0x1c5804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, }, - { 0x1c5808, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c580c, 0xad848e19, 0xad848e19, 0xad848e19, 0xad848e19, }, - { 0x1c5810, 0x7d14e000, 0x7d14e000, 0x7d14e000, 0x7d14e000, }, - { 0x1c5814, 0x9c0a9f6b, 0x9c0a9f6b, 0x9c0a9f6b, 0x9c0a9f6b, }, - { 0x1c5818, 0x00000090, 0x00000090, 0x00000090, 0x00000090, }, - { 0x1c581c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, }, - { 0x1c5824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, }, - { 0x1c5828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, }, - { 0x1c582c, 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000, }, - { 0x1c5830, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, }, - { 0x1c5838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, }, - { 0x1c583c, 0x00200400, 0x00200400, 0x00200400, 0x00200400, }, - { 0x1c5840, 0x206a002e, 0x206a002e, 0x206a002e, 0x206a002e, }, - { 0x1c5844, 0x1372161e, 0x13721c1e, 0x13721c24, 0x137216a4, }, - { 0x1c5848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, }, - { 0x1c584c, 0x1284233c, 0x1284233c, 0x1284233c, 0x1284233c, }, - { 0x1c5850, 0x6c48b4e4, 0x6c48b4e4, 0x6c48b0e4, 0x6c48b0e4, }, - { 0x1c5854, 0x00000859, 0x00000859, 0x00000859, 0x00000859, }, - { 0x1c5858, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, }, - { 0x1c585c, 0x31395c5e, 0x31395c5e, 0x31395c5e, 0x31395c5e, }, - { 0x1c5860, 0x0004dd10, 0x0004dd10, 0x0004dd20, 0x0004dd20, }, - { 0x1c5868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, }, - { 0x1c586c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, }, - { 0x1c5900, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5904, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5908, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c590c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, }, - { 0x1c5918, 0x00000118, 0x00000230, 0x00000268, 0x00000134, }, - { 0x1c591c, 0x10000fff, 0x10000fff, 0x10000fff, 0x10000fff, }, - { 0x1c5920, 0x0510081c, 0x0510081c, 0x0510001c, 0x0510001c, }, - { 0x1c5924, 0xd0058a15, 0xd0058a15, 0xd0058a15, 0xd0058a15, }, - { 0x1c5928, 0x00000001, 0x00000001, 0x00000001, 0x00000001, }, - { 0x1c592c, 0x00000004, 0x00000004, 0x00000004, 0x00000004, }, - { 0x1c5934, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, - { 0x1c5938, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, - { 0x1c593c, 0x0000007f, 0x0000007f, 0x0000007f, 0x0000007f, }, - { 0x1c5944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, }, - { 0x1c5948, 0x9280b212, 0x9280b212, 0x9280b212, 0x9280b212, }, - { 0x1c594c, 0x00020028, 0x00020028, 0x00020028, 0x00020028, }, - { 0x1c5954, 0x5d50e188, 0x5d50e188, 0x5d50e188, 0x5d50e188, }, - { 0x1c5958, 0x00081fff, 0x00081fff, 0x00081fff, 0x00081fff, }, - { 0x1c5960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, }, - { 0x1c5964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, }, - { 0x1c5970, 0x190fb515, 0x190fb515, 0x190fb515, 0x190fb515, }, - { 0x1c5974, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5978, 0x00000001, 0x00000001, 0x00000001, 0x00000001, }, - { 0x1c597c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5980, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5984, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5988, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c598c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5990, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5994, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5998, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c599c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c59a0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c59a4, 0x00000007, 0x00000007, 0x00000007, 0x00000007, }, - { 0x1c59a8, 0x001fff00, 0x001fff00, 0x001fff00, 0x001fff00, }, - { 0x1c59ac, 0x006f00c4, 0x006f00c4, 0x006f00c4, 0x006f00c4, }, - { 0x1c59b0, 0x03051000, 0x03051000, 0x03051000, 0x03051000, }, - { 0x1c59b4, 0x00000820, 0x00000820, 0x00000820, 0x00000820, }, - { 0x1c59c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, }, - { 0x1c59c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, }, - { 0x1c59c8, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0x60f6532c, }, - { 0x1c59cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, }, - { 0x1c59d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, }, - { 0x1c59d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c59d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c59dc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c59e0, 0x00000200, 0x00000200, 0x00000200, 0x00000200, }, - { 0x1c59e4, 0x64646464, 0x64646464, 0x64646464, 0x64646464, }, - { 0x1c59e8, 0x3c787878, 0x3c787878, 0x3c787878, 0x3c787878, }, - { 0x1c59ec, 0x000000aa, 0x000000aa, 0x000000aa, 0x000000aa, }, - { 0x1c59f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c59fc, 0x00001042, 0x00001042, 0x00001042, 0x00001042, }, - { 0x1c5a00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5a04, 0x00000040, 0x00000040, 0x00000040, 0x00000040, }, - { 0x1c5a08, 0x00000080, 0x00000080, 0x00000080, 0x00000080, }, - { 0x1c5a0c, 0x000001a1, 0x000001a1, 0x00000141, 0x00000141, }, - { 0x1c5a10, 0x000001e1, 0x000001e1, 0x00000181, 0x00000181, }, - { 0x1c5a14, 0x00000021, 0x00000021, 0x000001c1, 0x000001c1, }, - { 0x1c5a18, 0x00000061, 0x00000061, 0x00000001, 0x00000001, }, - { 0x1c5a1c, 0x00000168, 0x00000168, 0x00000041, 0x00000041, }, - { 0x1c5a20, 0x000001a8, 0x000001a8, 0x000001a8, 0x000001a8, }, - { 0x1c5a24, 0x000001e8, 0x000001e8, 0x000001e8, 0x000001e8, }, - { 0x1c5a28, 0x00000028, 0x00000028, 0x00000028, 0x00000028, }, - { 0x1c5a2c, 0x00000068, 0x00000068, 0x00000068, 0x00000068, }, - { 0x1c5a30, 0x00000189, 0x00000189, 0x000000a8, 0x000000a8, }, - { 0x1c5a34, 0x000001c9, 0x000001c9, 0x00000169, 0x00000169, }, - { 0x1c5a38, 0x00000009, 0x00000009, 0x000001a9, 0x000001a9, }, - { 0x1c5a3c, 0x00000049, 0x00000049, 0x000001e9, 0x000001e9, }, - { 0x1c5a40, 0x00000089, 0x00000089, 0x00000029, 0x00000029, }, - { 0x1c5a44, 0x00000170, 0x00000170, 0x00000069, 0x00000069, }, - { 0x1c5a48, 0x000001b0, 0x000001b0, 0x00000190, 0x00000190, }, - { 0x1c5a4c, 0x000001f0, 0x000001f0, 0x000001d0, 0x000001d0, }, - { 0x1c5a50, 0x00000030, 0x00000030, 0x00000010, 0x00000010, }, - { 0x1c5a54, 0x00000070, 0x00000070, 0x00000050, 0x00000050, }, - { 0x1c5a58, 0x00000191, 0x00000191, 0x00000090, 0x00000090, }, - { 0x1c5a5c, 0x000001d1, 0x000001d1, 0x00000151, 0x00000151, }, - { 0x1c5a60, 0x00000011, 0x00000011, 0x00000191, 0x00000191, }, - { 0x1c5a64, 0x00000051, 0x00000051, 0x000001d1, 0x000001d1, }, - { 0x1c5a68, 0x00000091, 0x00000091, 0x00000011, 0x00000011, }, - { 0x1c5a6c, 0x000001b8, 0x000001b8, 0x00000051, 0x00000051, }, - { 0x1c5a70, 0x000001f8, 0x000001f8, 0x00000198, 0x00000198, }, - { 0x1c5a74, 0x00000038, 0x00000038, 0x000001d8, 0x000001d8, }, - { 0x1c5a78, 0x00000078, 0x00000078, 0x00000018, 0x00000018, }, - { 0x1c5a7c, 0x00000199, 0x00000199, 0x00000058, 0x00000058, }, - { 0x1c5a80, 0x000001d9, 0x000001d9, 0x00000098, 0x00000098, }, - { 0x1c5a84, 0x00000019, 0x00000019, 0x00000159, 0x00000159, }, - { 0x1c5a88, 0x00000059, 0x00000059, 0x00000199, 0x00000199, }, - { 0x1c5a8c, 0x00000099, 0x00000099, 0x000001d9, 0x000001d9, }, - { 0x1c5a90, 0x000000d9, 0x000000d9, 0x00000019, 0x00000019, }, - { 0x1c5a94, 0x000000f9, 0x000000f9, 0x00000059, 0x00000059, }, - { 0x1c5a98, 0x000000f9, 0x000000f9, 0x00000099, 0x00000099, }, - { 0x1c5a9c, 0x000000f9, 0x000000f9, 0x000000d9, 0x000000d9, }, - { 0x1c5aa0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5aa4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5aa8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5aac, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ab0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ab4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ab8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5abc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ac0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ac4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ac8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5acc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ad0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ad4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ad8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5adc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ae0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ae4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ae8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5aec, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5af0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5af4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5af8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5afc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5b00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5b04, 0x00000001, 0x00000001, 0x00000001, 0x00000001, }, - { 0x1c5b08, 0x00000002, 0x00000002, 0x00000002, 0x00000002, }, - { 0x1c5b0c, 0x00000003, 0x00000003, 0x00000003, 0x00000003, }, - { 0x1c5b10, 0x00000004, 0x00000004, 0x00000004, 0x00000004, }, - { 0x1c5b14, 0x00000005, 0x00000005, 0x00000005, 0x00000005, }, - { 0x1c5b18, 0x00000008, 0x00000008, 0x00000008, 0x00000008, }, - { 0x1c5b1c, 0x00000009, 0x00000009, 0x00000009, 0x00000009, }, - { 0x1c5b20, 0x0000000a, 0x0000000a, 0x0000000a, 0x0000000a, }, - { 0x1c5b24, 0x0000000b, 0x0000000b, 0x0000000b, 0x0000000b, }, - { 0x1c5b28, 0x0000000c, 0x0000000c, 0x0000000c, 0x0000000c, }, - { 0x1c5b2c, 0x0000000d, 0x0000000d, 0x0000000d, 0x0000000d, }, - { 0x1c5b30, 0x00000010, 0x00000010, 0x00000010, 0x00000010, }, - { 0x1c5b34, 0x00000011, 0x00000011, 0x00000011, 0x00000011, }, - { 0x1c5b38, 0x00000012, 0x00000012, 0x00000012, 0x00000012, }, - { 0x1c5b3c, 0x00000013, 0x00000013, 0x00000013, 0x00000013, }, - { 0x1c5b40, 0x00000014, 0x00000014, 0x00000014, 0x00000014, }, - { 0x1c5b44, 0x00000015, 0x00000015, 0x00000015, 0x00000015, }, - { 0x1c5b48, 0x00000018, 0x00000018, 0x00000018, 0x00000018, }, - { 0x1c5b4c, 0x00000019, 0x00000019, 0x00000019, 0x00000019, }, - { 0x1c5b50, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, }, - { 0x1c5b54, 0x0000001b, 0x0000001b, 0x0000001b, 0x0000001b, }, - { 0x1c5b58, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c, }, - { 0x1c5b5c, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, }, - { 0x1c5b60, 0x00000020, 0x00000020, 0x00000020, 0x00000020, }, - { 0x1c5b64, 0x00000021, 0x00000021, 0x00000021, 0x00000021, }, - { 0x1c5b68, 0x00000022, 0x00000022, 0x00000022, 0x00000022, }, - { 0x1c5b6c, 0x00000023, 0x00000023, 0x00000023, 0x00000023, }, - { 0x1c5b70, 0x00000024, 0x00000024, 0x00000024, 0x00000024, }, - { 0x1c5b74, 0x00000025, 0x00000025, 0x00000025, 0x00000025, }, - { 0x1c5b78, 0x00000028, 0x00000028, 0x00000028, 0x00000028, }, - { 0x1c5b7c, 0x00000029, 0x00000029, 0x00000029, 0x00000029, }, - { 0x1c5b80, 0x0000002a, 0x0000002a, 0x0000002a, 0x0000002a, }, - { 0x1c5b84, 0x0000002b, 0x0000002b, 0x0000002b, 0x0000002b, }, - { 0x1c5b88, 0x0000002c, 0x0000002c, 0x0000002c, 0x0000002c, }, - { 0x1c5b8c, 0x0000002d, 0x0000002d, 0x0000002d, 0x0000002d, }, - { 0x1c5b90, 0x00000030, 0x00000030, 0x00000030, 0x00000030, }, - { 0x1c5b94, 0x00000031, 0x00000031, 0x00000031, 0x00000031, }, - { 0x1c5b98, 0x00000032, 0x00000032, 0x00000032, 0x00000032, }, - { 0x1c5b9c, 0x00000033, 0x00000033, 0x00000033, 0x00000033, }, - { 0x1c5ba0, 0x00000034, 0x00000034, 0x00000034, 0x00000034, }, - { 0x1c5ba4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5ba8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bac, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bb0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bb4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bb8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bbc, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bc0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bc4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bc8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bcc, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bd0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bd4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bd8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bdc, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5be0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5be4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5be8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bec, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bf0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bf4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bf8, 0x00000010, 0x00000010, 0x00000010, 0x00000010, }, - { 0x1c5bfc, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, }, - { 0x1c5c00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c0c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c10, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c14, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c18, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c1c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c20, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c24, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c28, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c2c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c30, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c34, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c38, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c3c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5cf0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5cf4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5cf8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5cfc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c6200, 0x00000008, 0x00000008, 0x0000000e, 0x0000000e, }, - { 0x1c6204, 0x00000440, 0x00000440, 0x00000440, 0x00000440, }, - { 0x1c6208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, }, - { 0x1c620c, 0x012e8160, 0x012e8160, 0x012a8160, 0x012a8160, }, - { 0x1c6210, 0x40806333, 0x40806333, 0x40806333, 0x40806333, }, - { 0x1c6214, 0x00106c10, 0x00106c10, 0x00106c10, 0x00106c10, }, - { 0x1c6218, 0x009c4060, 0x009c4060, 0x009c4060, 0x009c4060, }, - { 0x1c621c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, }, - { 0x1c6220, 0x018830c6, 0x018830c6, 0x018830c6, 0x018830c6, }, - { 0x1c6224, 0x00000400, 0x00000400, 0x00000400, 0x00000400, }, - { 0x1c6228, 0x000009b5, 0x000009b5, 0x000009b5, 0x000009b5, }, - { 0x1c622c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c6230, 0x00000108, 0x00000210, 0x00000210, 0x00000108, }, - { 0x1c6234, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, - { 0x1c6238, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, - { 0x1c623c, 0x13c889af, 0x13c889af, 0x13c889af, 0x13c889af, }, - { 0x1c6240, 0x38490a20, 0x38490a20, 0x38490a20, 0x38490a20, }, - { 0x1c6244, 0x00007bb6, 0x00007bb6, 0x00007bb6, 0x00007bb6, }, - { 0x1c6248, 0x0fff3ffc, 0x0fff3ffc, 0x0fff3ffc, 0x0fff3ffc, }, - { 0x1c624c, 0x00000001, 0x00000001, 0x00000001, 0x00000001, }, - { 0x1c6250, 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000, }, - { 0x1c6254, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c6258, 0x0cc75380, 0x0cc75380, 0x0cc75380, 0x0cc75380, }, - { 0x1c625c, 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01, }, - { 0x1c6260, 0xdfa91f01, 0xdfa91f01, 0xdfa91f01, 0xdfa91f01, }, - { 0x1c6264, 0x00418a11, 0x00418a11, 0x00418a11, 0x00418a11, }, - { 0x1c6268, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c626c, 0x09249126, 0x09249126, 0x09249126, 0x09249126, }, - { 0x1c6274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, }, - { 0x1c6278, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, }, - { 0x1c627c, 0x051701ce, 0x051701ce, 0x051701ce, 0x051701ce, }, - { 0x1c6300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, }, - { 0x1c6304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, }, - { 0x1c6308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, }, - { 0x1c630c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, }, - { 0x1c6310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, }, - { 0x1c6314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, }, - { 0x1c6318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, }, - { 0x1c631c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, }, - { 0x1c6320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, }, - { 0x1c6324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, }, - { 0x1c6328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, }, - { 0x1c632c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c6330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c6334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c6338, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c633c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c6340, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c6344, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c6348, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, }, - { 0x1c634c, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, }, - { 0x1c6350, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, }, - { 0x1c6354, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, }, - { 0x1c6358, 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f, }, - { 0x1c6388, 0x08000000, 0x08000000, 0x08000000, 0x08000000, }, - { 0x1c638c, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, - { 0x1c6390, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, - { 0x1c6394, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, }, - { 0x1c6398, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, }, - { 0x1c639c, 0x00000007, 0x00000007, 0x00000007, 0x00000007, }, - { 0x1c63a0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63a4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63a8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63ac, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63b0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63b4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63b8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63bc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63c0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63c4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63c8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63cc, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, - { 0x1c63d0, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, - { 0x1c63d4, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, - { 0x1c63d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63dc, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, }, - { 0x1c63e0, 0x000000c0, 0x000000c0, 0x000000c0, 0x000000c0, }, - { 0x1c6848, 0x00180a65, 0x00180a65, 0x00180a68, 0x00180a68, }, - { 0x1c6920, 0x0510001c, 0x0510001c, 0x0510001c, 0x0510001c, }, - { 0x1c6960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, }, - { 0x1c720c, 0x012e8160, 0x012e8160, 0x012a8160, 0x012a8160, }, - { 0x1c726c, 0x09249126, 0x09249126, 0x09249126, 0x09249126, }, - { 0x1c7848, 0x00180a65, 0x00180a65, 0x00180a68, 0x00180a68, }, - { 0x1c7920, 0x0510001c, 0x0510001c, 0x0510001c, 0x0510001c, }, - { 0x1c7960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, }, - { 0x1c820c, 0x012e8160, 0x012e8160, 0x012a8160, 0x012a8160, }, - { 0x1c826c, 0x09249126, 0x09249126, 0x09249126, 0x09249126, }, -/* { 0x1c8864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, }, */ - { 0x1c8864, 0x0001c600, 0x0001c600, 0x0001c600, 0x0001c600, }, - { 0x1c895c, 0x004b6a8e, 0x004b6a8e, 0x004b6a8e, 0x004b6a8e, }, - { 0x1c8968, 0x000003ce, 0x000003ce, 0x000003ce, 0x000003ce, }, - { 0x1c89bc, 0x00181400, 0x00181400, 0x00181400, 0x00181400, }, - { 0x1c9270, 0x00820820, 0x00820820, 0x00820820, 0x00820820, }, - { 0x1c935c, 0x066c420f, 0x066c420f, 0x066c420f, 0x066c420f, }, - { 0x1c9360, 0x0f282207, 0x0f282207, 0x0f282207, 0x0f282207, }, - { 0x1c9364, 0x17601685, 0x17601685, 0x17601685, 0x17601685, }, - { 0x1c9368, 0x1f801104, 0x1f801104, 0x1f801104, 0x1f801104, }, - { 0x1c936c, 0x37a00c03, 0x37a00c03, 0x37a00c03, 0x37a00c03, }, - { 0x1c9370, 0x3fc40883, 0x3fc40883, 0x3fc40883, 0x3fc40883, }, - { 0x1c9374, 0x57c00803, 0x57c00803, 0x57c00803, 0x57c00803, }, - { 0x1c9378, 0x5fd80682, 0x5fd80682, 0x5fd80682, 0x5fd80682, }, - { 0x1c937c, 0x7fe00482, 0x7fe00482, 0x7fe00482, 0x7fe00482, }, - { 0x1c9380, 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba, }, - { 0x1c9384, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, } -}; - -/* - * look up a certain register in ar5416_phy_init[] and return the init. value - * for the band and bandwidth given. Return 0 if register address not found. - */ -static u32 ar9170_get_default_phy_reg_val(u32 reg, bool is_2ghz, bool is_40mhz) -{ - unsigned int i; - for (i = 0; i < ARRAY_SIZE(ar5416_phy_init); i++) { - if (ar5416_phy_init[i].reg != reg) - continue; - - if (is_2ghz) { - if (is_40mhz) - return ar5416_phy_init[i]._2ghz_40; - else - return ar5416_phy_init[i]._2ghz_20; - } else { - if (is_40mhz) - return ar5416_phy_init[i]._5ghz_40; - else - return ar5416_phy_init[i]._5ghz_20; - } - } - return 0; -} - -/* - * initialize some phy regs from eeprom values in modal_header[] - * acc. to band and bandwidth - */ -static int ar9170_init_phy_from_eeprom(struct ar9170 *ar, - bool is_2ghz, bool is_40mhz) -{ - static const u8 xpd2pd[16] = { - 0x2, 0x2, 0x2, 0x1, 0x2, 0x2, 0x6, 0x2, - 0x2, 0x3, 0x7, 0x2, 0xB, 0x2, 0x2, 0x2 - }; - u32 defval, newval; - /* pointer to the modal_header acc. to band */ - struct ar9170_eeprom_modal *m = &ar->eeprom.modal_header[is_2ghz]; - - ar9170_regwrite_begin(ar); - - /* ant common control (index 0) */ - newval = le32_to_cpu(m->antCtrlCommon); - ar9170_regwrite(0x1c5964, newval); - - /* ant control chain 0 (index 1) */ - newval = le32_to_cpu(m->antCtrlChain[0]); - ar9170_regwrite(0x1c5960, newval); - - /* ant control chain 2 (index 2) */ - newval = le32_to_cpu(m->antCtrlChain[1]); - ar9170_regwrite(0x1c7960, newval); - - /* SwSettle (index 3) */ - if (!is_40mhz) { - defval = ar9170_get_default_phy_reg_val(0x1c5844, - is_2ghz, is_40mhz); - newval = (defval & ~0x3f80) | - ((m->switchSettling & 0x7f) << 7); - ar9170_regwrite(0x1c5844, newval); - } - - /* adcDesired, pdaDesired (index 4) */ - defval = ar9170_get_default_phy_reg_val(0x1c5850, is_2ghz, is_40mhz); - newval = (defval & ~0xffff) | ((u8)m->pgaDesiredSize << 8) | - ((u8)m->adcDesiredSize); - ar9170_regwrite(0x1c5850, newval); - - /* TxEndToXpaOff, TxFrameToXpaOn (index 5) */ - defval = ar9170_get_default_phy_reg_val(0x1c5834, is_2ghz, is_40mhz); - newval = (m->txEndToXpaOff << 24) | (m->txEndToXpaOff << 16) | - (m->txFrameToXpaOn << 8) | m->txFrameToXpaOn; - ar9170_regwrite(0x1c5834, newval); - - /* TxEndToRxOn (index 6) */ - defval = ar9170_get_default_phy_reg_val(0x1c5828, is_2ghz, is_40mhz); - newval = (defval & ~0xff0000) | (m->txEndToRxOn << 16); - ar9170_regwrite(0x1c5828, newval); - - /* thresh62 (index 7) */ - defval = ar9170_get_default_phy_reg_val(0x1c8864, is_2ghz, is_40mhz); - newval = (defval & ~0x7f000) | (m->thresh62 << 12); - ar9170_regwrite(0x1c8864, newval); - - /* tx/rx attenuation chain 0 (index 8) */ - defval = ar9170_get_default_phy_reg_val(0x1c5848, is_2ghz, is_40mhz); - newval = (defval & ~0x3f000) | ((m->txRxAttenCh[0] & 0x3f) << 12); - ar9170_regwrite(0x1c5848, newval); - - /* tx/rx attenuation chain 2 (index 9) */ - defval = ar9170_get_default_phy_reg_val(0x1c7848, is_2ghz, is_40mhz); - newval = (defval & ~0x3f000) | ((m->txRxAttenCh[1] & 0x3f) << 12); - ar9170_regwrite(0x1c7848, newval); - - /* tx/rx margin chain 0 (index 10) */ - defval = ar9170_get_default_phy_reg_val(0x1c620c, is_2ghz, is_40mhz); - newval = (defval & ~0xfc0000) | ((m->rxTxMarginCh[0] & 0x3f) << 18); - /* bsw margin chain 0 for 5GHz only */ - if (!is_2ghz) - newval = (newval & ~0x3c00) | ((m->bswMargin[0] & 0xf) << 10); - ar9170_regwrite(0x1c620c, newval); - - /* tx/rx margin chain 2 (index 11) */ - defval = ar9170_get_default_phy_reg_val(0x1c820c, is_2ghz, is_40mhz); - newval = (defval & ~0xfc0000) | ((m->rxTxMarginCh[1] & 0x3f) << 18); - ar9170_regwrite(0x1c820c, newval); - - /* iqCall, iqCallq chain 0 (index 12) */ - defval = ar9170_get_default_phy_reg_val(0x1c5920, is_2ghz, is_40mhz); - newval = (defval & ~0x7ff) | (((u8)m->iqCalICh[0] & 0x3f) << 5) | - ((u8)m->iqCalQCh[0] & 0x1f); - ar9170_regwrite(0x1c5920, newval); - - /* iqCall, iqCallq chain 2 (index 13) */ - defval = ar9170_get_default_phy_reg_val(0x1c7920, is_2ghz, is_40mhz); - newval = (defval & ~0x7ff) | (((u8)m->iqCalICh[1] & 0x3f) << 5) | - ((u8)m->iqCalQCh[1] & 0x1f); - ar9170_regwrite(0x1c7920, newval); - - /* xpd gain mask (index 14) */ - defval = ar9170_get_default_phy_reg_val(0x1c6258, is_2ghz, is_40mhz); - newval = (defval & ~0xf0000) | (xpd2pd[m->xpdGain & 0xf] << 16); - ar9170_regwrite(0x1c6258, newval); - ar9170_regwrite_finish(); - - return ar9170_regwrite_result(); -} - -int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band) -{ - int i, err; - u32 val; - bool is_2ghz = band == IEEE80211_BAND_2GHZ; - bool is_40mhz = conf_is_ht40(&ar->hw->conf); - - ar9170_regwrite_begin(ar); - - for (i = 0; i < ARRAY_SIZE(ar5416_phy_init); i++) { - if (is_40mhz) { - if (is_2ghz) - val = ar5416_phy_init[i]._2ghz_40; - else - val = ar5416_phy_init[i]._5ghz_40; - } else { - if (is_2ghz) - val = ar5416_phy_init[i]._2ghz_20; - else - val = ar5416_phy_init[i]._5ghz_20; - } - - ar9170_regwrite(ar5416_phy_init[i].reg, val); - } - - ar9170_regwrite_finish(); - err = ar9170_regwrite_result(); - if (err) - return err; - - err = ar9170_init_phy_from_eeprom(ar, is_2ghz, is_40mhz); - if (err) - return err; - - err = ar9170_init_power_cal(ar); - if (err) - return err; - - /* XXX: remove magic! */ - if (is_2ghz) - err = ar9170_write_reg(ar, 0x1d4014, 0x5163); - else - err = ar9170_write_reg(ar, 0x1d4014, 0x5143); - - return err; -} - -struct ar9170_rf_init { - u32 reg, _5ghz, _2ghz; -}; - -static struct ar9170_rf_init ar9170_rf_init[] = { - /* bank 0 */ - { 0x1c58b0, 0x1e5795e5, 0x1e5795e5}, - { 0x1c58e0, 0x02008020, 0x02008020}, - /* bank 1 */ - { 0x1c58b0, 0x02108421, 0x02108421}, - { 0x1c58ec, 0x00000008, 0x00000008}, - /* bank 2 */ - { 0x1c58b0, 0x0e73ff17, 0x0e73ff17}, - { 0x1c58e0, 0x00000420, 0x00000420}, - /* bank 3 */ - { 0x1c58f0, 0x01400018, 0x01c00018}, - /* bank 4 */ - { 0x1c58b0, 0x000001a1, 0x000001a1}, - { 0x1c58e8, 0x00000001, 0x00000001}, - /* bank 5 */ - { 0x1c58b0, 0x00000013, 0x00000013}, - { 0x1c58e4, 0x00000002, 0x00000002}, - /* bank 6 */ - { 0x1c58b0, 0x00000000, 0x00000000}, - { 0x1c58b0, 0x00000000, 0x00000000}, - { 0x1c58b0, 0x00000000, 0x00000000}, - { 0x1c58b0, 0x00000000, 0x00000000}, - { 0x1c58b0, 0x00000000, 0x00000000}, - { 0x1c58b0, 0x00004000, 0x00004000}, - { 0x1c58b0, 0x00006c00, 0x00006c00}, - { 0x1c58b0, 0x00002c00, 0x00002c00}, - { 0x1c58b0, 0x00004800, 0x00004800}, - { 0x1c58b0, 0x00004000, 0x00004000}, - { 0x1c58b0, 0x00006000, 0x00006000}, - { 0x1c58b0, 0x00001000, 0x00001000}, - { 0x1c58b0, 0x00004000, 0x00004000}, - { 0x1c58b0, 0x00007c00, 0x00007c00}, - { 0x1c58b0, 0x00007c00, 0x00007c00}, - { 0x1c58b0, 0x00007c00, 0x00007c00}, - { 0x1c58b0, 0x00007c00, 0x00007c00}, - { 0x1c58b0, 0x00007c00, 0x00007c00}, - { 0x1c58b0, 0x00087c00, 0x00087c00}, - { 0x1c58b0, 0x00007c00, 0x00007c00}, - { 0x1c58b0, 0x00005400, 0x00005400}, - { 0x1c58b0, 0x00000c00, 0x00000c00}, - { 0x1c58b0, 0x00001800, 0x00001800}, - { 0x1c58b0, 0x00007c00, 0x00007c00}, - { 0x1c58b0, 0x00006c00, 0x00006c00}, - { 0x1c58b0, 0x00006c00, 0x00006c00}, - { 0x1c58b0, 0x00007c00, 0x00007c00}, - { 0x1c58b0, 0x00002c00, 0x00002c00}, - { 0x1c58b0, 0x00003c00, 0x00003c00}, - { 0x1c58b0, 0x00003800, 0x00003800}, - { 0x1c58b0, 0x00001c00, 0x00001c00}, - { 0x1c58b0, 0x00000800, 0x00000800}, - { 0x1c58b0, 0x00000408, 0x00000408}, - { 0x1c58b0, 0x00004c15, 0x00004c15}, - { 0x1c58b0, 0x00004188, 0x00004188}, - { 0x1c58b0, 0x0000201e, 0x0000201e}, - { 0x1c58b0, 0x00010408, 0x00010408}, - { 0x1c58b0, 0x00000801, 0x00000801}, - { 0x1c58b0, 0x00000c08, 0x00000c08}, - { 0x1c58b0, 0x0000181e, 0x0000181e}, - { 0x1c58b0, 0x00001016, 0x00001016}, - { 0x1c58b0, 0x00002800, 0x00002800}, - { 0x1c58b0, 0x00004010, 0x00004010}, - { 0x1c58b0, 0x0000081c, 0x0000081c}, - { 0x1c58b0, 0x00000115, 0x00000115}, - { 0x1c58b0, 0x00000015, 0x00000015}, - { 0x1c58b0, 0x00000066, 0x00000066}, - { 0x1c58b0, 0x0000001c, 0x0000001c}, - { 0x1c58b0, 0x00000000, 0x00000000}, - { 0x1c58b0, 0x00000004, 0x00000004}, - { 0x1c58b0, 0x00000015, 0x00000015}, - { 0x1c58b0, 0x0000001f, 0x0000001f}, - { 0x1c58e0, 0x00000000, 0x00000400}, - /* bank 7 */ - { 0x1c58b0, 0x000000a0, 0x000000a0}, - { 0x1c58b0, 0x00000000, 0x00000000}, - { 0x1c58b0, 0x00000040, 0x00000040}, - { 0x1c58f0, 0x0000001c, 0x0000001c}, -}; - -static int ar9170_init_rf_banks_0_7(struct ar9170 *ar, bool band5ghz) -{ - int err, i; - - ar9170_regwrite_begin(ar); - - for (i = 0; i < ARRAY_SIZE(ar9170_rf_init); i++) - ar9170_regwrite(ar9170_rf_init[i].reg, - band5ghz ? ar9170_rf_init[i]._5ghz - : ar9170_rf_init[i]._2ghz); - - ar9170_regwrite_finish(); - err = ar9170_regwrite_result(); - if (err) - wiphy_err(ar->hw->wiphy, "rf init failed\n"); - return err; -} - -static int ar9170_init_rf_bank4_pwr(struct ar9170 *ar, bool band5ghz, - u32 freq, enum ar9170_bw bw) -{ - int err; - u32 d0, d1, td0, td1, fd0, fd1; - u8 chansel; - u8 refsel0 = 1, refsel1 = 0; - u8 lf_synth = 0; - - switch (bw) { - case AR9170_BW_40_ABOVE: - freq += 10; - break; - case AR9170_BW_40_BELOW: - freq -= 10; - break; - case AR9170_BW_20: - break; - case __AR9170_NUM_BW: - BUG(); - } - - if (band5ghz) { - if (freq % 10) { - chansel = (freq - 4800) / 5; - } else { - chansel = ((freq - 4800) / 10) * 2; - refsel0 = 0; - refsel1 = 1; - } - chansel = byte_rev_table[chansel]; - } else { - if (freq == 2484) { - chansel = 10 + (freq - 2274) / 5; - lf_synth = 1; - } else - chansel = 16 + (freq - 2272) / 5; - chansel *= 4; - chansel = byte_rev_table[chansel]; - } - - d1 = chansel; - d0 = 0x21 | - refsel0 << 3 | - refsel1 << 2 | - lf_synth << 1; - td0 = d0 & 0x1f; - td1 = d1 & 0x1f; - fd0 = td1 << 5 | td0; - - td0 = (d0 >> 5) & 0x7; - td1 = (d1 >> 5) & 0x7; - fd1 = td1 << 5 | td0; - - ar9170_regwrite_begin(ar); - - ar9170_regwrite(0x1c58b0, fd0); - ar9170_regwrite(0x1c58e8, fd1); - - ar9170_regwrite_finish(); - err = ar9170_regwrite_result(); - if (err) - return err; - - msleep(10); - - return 0; -} - -struct ar9170_phy_freq_params { - u8 coeff_exp; - u16 coeff_man; - u8 coeff_exp_shgi; - u16 coeff_man_shgi; -}; - -struct ar9170_phy_freq_entry { - u16 freq; - struct ar9170_phy_freq_params params[__AR9170_NUM_BW]; -}; - -/* NB: must be in sync with channel tables in main! */ -static const struct ar9170_phy_freq_entry ar9170_phy_freq_params[] = { -/* - * freq, - * 20MHz, - * 40MHz (below), - * 40Mhz (above), - */ - { 2412, { - { 3, 21737, 3, 19563, }, - { 3, 21827, 3, 19644, }, - { 3, 21647, 3, 19482, }, - } }, - { 2417, { - { 3, 21692, 3, 19523, }, - { 3, 21782, 3, 19604, }, - { 3, 21602, 3, 19442, }, - } }, - { 2422, { - { 3, 21647, 3, 19482, }, - { 3, 21737, 3, 19563, }, - { 3, 21558, 3, 19402, }, - } }, - { 2427, { - { 3, 21602, 3, 19442, }, - { 3, 21692, 3, 19523, }, - { 3, 21514, 3, 19362, }, - } }, - { 2432, { - { 3, 21558, 3, 19402, }, - { 3, 21647, 3, 19482, }, - { 3, 21470, 3, 19323, }, - } }, - { 2437, { - { 3, 21514, 3, 19362, }, - { 3, 21602, 3, 19442, }, - { 3, 21426, 3, 19283, }, - } }, - { 2442, { - { 3, 21470, 3, 19323, }, - { 3, 21558, 3, 19402, }, - { 3, 21382, 3, 19244, }, - } }, - { 2447, { - { 3, 21426, 3, 19283, }, - { 3, 21514, 3, 19362, }, - { 3, 21339, 3, 19205, }, - } }, - { 2452, { - { 3, 21382, 3, 19244, }, - { 3, 21470, 3, 19323, }, - { 3, 21295, 3, 19166, }, - } }, - { 2457, { - { 3, 21339, 3, 19205, }, - { 3, 21426, 3, 19283, }, - { 3, 21252, 3, 19127, }, - } }, - { 2462, { - { 3, 21295, 3, 19166, }, - { 3, 21382, 3, 19244, }, - { 3, 21209, 3, 19088, }, - } }, - { 2467, { - { 3, 21252, 3, 19127, }, - { 3, 21339, 3, 19205, }, - { 3, 21166, 3, 19050, }, - } }, - { 2472, { - { 3, 21209, 3, 19088, }, - { 3, 21295, 3, 19166, }, - { 3, 21124, 3, 19011, }, - } }, - { 2484, { - { 3, 21107, 3, 18996, }, - { 3, 21192, 3, 19073, }, - { 3, 21022, 3, 18920, }, - } }, - { 4920, { - { 4, 21313, 4, 19181, }, - { 4, 21356, 4, 19220, }, - { 4, 21269, 4, 19142, }, - } }, - { 4940, { - { 4, 21226, 4, 19104, }, - { 4, 21269, 4, 19142, }, - { 4, 21183, 4, 19065, }, - } }, - { 4960, { - { 4, 21141, 4, 19027, }, - { 4, 21183, 4, 19065, }, - { 4, 21098, 4, 18988, }, - } }, - { 4980, { - { 4, 21056, 4, 18950, }, - { 4, 21098, 4, 18988, }, - { 4, 21014, 4, 18912, }, - } }, - { 5040, { - { 4, 20805, 4, 18725, }, - { 4, 20846, 4, 18762, }, - { 4, 20764, 4, 18687, }, - } }, - { 5060, { - { 4, 20723, 4, 18651, }, - { 4, 20764, 4, 18687, }, - { 4, 20682, 4, 18614, }, - } }, - { 5080, { - { 4, 20641, 4, 18577, }, - { 4, 20682, 4, 18614, }, - { 4, 20601, 4, 18541, }, - } }, - { 5180, { - { 4, 20243, 4, 18219, }, - { 4, 20282, 4, 18254, }, - { 4, 20204, 4, 18183, }, - } }, - { 5200, { - { 4, 20165, 4, 18148, }, - { 4, 20204, 4, 18183, }, - { 4, 20126, 4, 18114, }, - } }, - { 5220, { - { 4, 20088, 4, 18079, }, - { 4, 20126, 4, 18114, }, - { 4, 20049, 4, 18044, }, - } }, - { 5240, { - { 4, 20011, 4, 18010, }, - { 4, 20049, 4, 18044, }, - { 4, 19973, 4, 17976, }, - } }, - { 5260, { - { 4, 19935, 4, 17941, }, - { 4, 19973, 4, 17976, }, - { 4, 19897, 4, 17907, }, - } }, - { 5280, { - { 4, 19859, 4, 17873, }, - { 4, 19897, 4, 17907, }, - { 4, 19822, 4, 17840, }, - } }, - { 5300, { - { 4, 19784, 4, 17806, }, - { 4, 19822, 4, 17840, }, - { 4, 19747, 4, 17772, }, - } }, - { 5320, { - { 4, 19710, 4, 17739, }, - { 4, 19747, 4, 17772, }, - { 4, 19673, 4, 17706, }, - } }, - { 5500, { - { 4, 19065, 4, 17159, }, - { 4, 19100, 4, 17190, }, - { 4, 19030, 4, 17127, }, - } }, - { 5520, { - { 4, 18996, 4, 17096, }, - { 4, 19030, 4, 17127, }, - { 4, 18962, 4, 17065, }, - } }, - { 5540, { - { 4, 18927, 4, 17035, }, - { 4, 18962, 4, 17065, }, - { 4, 18893, 4, 17004, }, - } }, - { 5560, { - { 4, 18859, 4, 16973, }, - { 4, 18893, 4, 17004, }, - { 4, 18825, 4, 16943, }, - } }, - { 5580, { - { 4, 18792, 4, 16913, }, - { 4, 18825, 4, 16943, }, - { 4, 18758, 4, 16882, }, - } }, - { 5600, { - { 4, 18725, 4, 16852, }, - { 4, 18758, 4, 16882, }, - { 4, 18691, 4, 16822, }, - } }, - { 5620, { - { 4, 18658, 4, 16792, }, - { 4, 18691, 4, 16822, }, - { 4, 18625, 4, 16762, }, - } }, - { 5640, { - { 4, 18592, 4, 16733, }, - { 4, 18625, 4, 16762, }, - { 4, 18559, 4, 16703, }, - } }, - { 5660, { - { 4, 18526, 4, 16673, }, - { 4, 18559, 4, 16703, }, - { 4, 18493, 4, 16644, }, - } }, - { 5680, { - { 4, 18461, 4, 16615, }, - { 4, 18493, 4, 16644, }, - { 4, 18428, 4, 16586, }, - } }, - { 5700, { - { 4, 18396, 4, 16556, }, - { 4, 18428, 4, 16586, }, - { 4, 18364, 4, 16527, }, - } }, - { 5745, { - { 4, 18252, 4, 16427, }, - { 4, 18284, 4, 16455, }, - { 4, 18220, 4, 16398, }, - } }, - { 5765, { - { 4, 18189, 5, 32740, }, - { 4, 18220, 4, 16398, }, - { 4, 18157, 5, 32683, }, - } }, - { 5785, { - { 4, 18126, 5, 32626, }, - { 4, 18157, 5, 32683, }, - { 4, 18094, 5, 32570, }, - } }, - { 5805, { - { 4, 18063, 5, 32514, }, - { 4, 18094, 5, 32570, }, - { 4, 18032, 5, 32458, }, - } }, - { 5825, { - { 4, 18001, 5, 32402, }, - { 4, 18032, 5, 32458, }, - { 4, 17970, 5, 32347, }, - } }, - { 5170, { - { 4, 20282, 4, 18254, }, - { 4, 20321, 4, 18289, }, - { 4, 20243, 4, 18219, }, - } }, - { 5190, { - { 4, 20204, 4, 18183, }, - { 4, 20243, 4, 18219, }, - { 4, 20165, 4, 18148, }, - } }, - { 5210, { - { 4, 20126, 4, 18114, }, - { 4, 20165, 4, 18148, }, - { 4, 20088, 4, 18079, }, - } }, - { 5230, { - { 4, 20049, 4, 18044, }, - { 4, 20088, 4, 18079, }, - { 4, 20011, 4, 18010, }, - } }, -}; - -static const struct ar9170_phy_freq_params * -ar9170_get_hw_dyn_params(struct ieee80211_channel *channel, - enum ar9170_bw bw) -{ - unsigned int chanidx = 0; - u16 freq = 2412; - - if (channel) { - chanidx = channel->hw_value; - freq = channel->center_freq; - } - - BUG_ON(chanidx >= ARRAY_SIZE(ar9170_phy_freq_params)); - - BUILD_BUG_ON(__AR9170_NUM_BW != 3); - - WARN_ON(ar9170_phy_freq_params[chanidx].freq != freq); - - return &ar9170_phy_freq_params[chanidx].params[bw]; -} - - -int ar9170_init_rf(struct ar9170 *ar) -{ - const struct ar9170_phy_freq_params *freqpar; - __le32 cmd[7]; - int err; - - err = ar9170_init_rf_banks_0_7(ar, false); - if (err) - return err; - - err = ar9170_init_rf_bank4_pwr(ar, false, 2412, AR9170_BW_20); - if (err) - return err; - - freqpar = ar9170_get_hw_dyn_params(NULL, AR9170_BW_20); - - cmd[0] = cpu_to_le32(2412 * 1000); - cmd[1] = cpu_to_le32(0); - cmd[2] = cpu_to_le32(1); - cmd[3] = cpu_to_le32(freqpar->coeff_exp); - cmd[4] = cpu_to_le32(freqpar->coeff_man); - cmd[5] = cpu_to_le32(freqpar->coeff_exp_shgi); - cmd[6] = cpu_to_le32(freqpar->coeff_man_shgi); - - /* RF_INIT echoes the command back to us */ - err = ar->exec_cmd(ar, AR9170_CMD_RF_INIT, - sizeof(cmd), (u8 *)cmd, - sizeof(cmd), (u8 *)cmd); - if (err) - return err; - - msleep(1000); - - return ar9170_echo_test(ar, 0xaabbccdd); -} - -static int ar9170_find_freq_idx(int nfreqs, u8 *freqs, u8 f) -{ - int idx = nfreqs - 2; - - while (idx >= 0) { - if (f >= freqs[idx]) - return idx; - idx--; - } - - return 0; -} - -static s32 ar9170_interpolate_s32(s32 x, s32 x1, s32 y1, s32 x2, s32 y2) -{ - /* nothing to interpolate, it's horizontal */ - if (y2 == y1) - return y1; - - /* check if we hit one of the edges */ - if (x == x1) - return y1; - if (x == x2) - return y2; - - /* x1 == x2 is bad, hopefully == x */ - if (x2 == x1) - return y1; - - return y1 + (((y2 - y1) * (x - x1)) / (x2 - x1)); -} - -static u8 ar9170_interpolate_u8(u8 x, u8 x1, u8 y1, u8 x2, u8 y2) -{ -#define SHIFT 8 - s32 y; - - y = ar9170_interpolate_s32(x << SHIFT, - x1 << SHIFT, y1 << SHIFT, - x2 << SHIFT, y2 << SHIFT); - - /* - * XXX: unwrap this expression - * Isn't it just DIV_ROUND_UP(y, 1<<SHIFT)? - * Can we rely on the compiler to optimise away the div? - */ - return (y >> SHIFT) + ((y & (1<<(SHIFT-1))) >> (SHIFT - 1)); -#undef SHIFT -} - -static u8 ar9170_interpolate_val(u8 x, u8 *x_array, u8 *y_array) -{ - int i; - - for (i = 0; i < 3; i++) - if (x <= x_array[i + 1]) - break; - - return ar9170_interpolate_u8(x, - x_array[i], - y_array[i], - x_array[i + 1], - y_array[i + 1]); -} - -static int ar9170_set_freq_cal_data(struct ar9170 *ar, - struct ieee80211_channel *channel) -{ - u8 *cal_freq_pier; - u8 vpds[2][AR5416_PD_GAIN_ICEPTS]; - u8 pwrs[2][AR5416_PD_GAIN_ICEPTS]; - int chain, idx, i; - u32 phy_data = 0; - u8 f, tmp; - - switch (channel->band) { - case IEEE80211_BAND_2GHZ: - f = channel->center_freq - 2300; - cal_freq_pier = ar->eeprom.cal_freq_pier_2G; - i = AR5416_NUM_2G_CAL_PIERS - 1; - break; - - case IEEE80211_BAND_5GHZ: - f = (channel->center_freq - 4800) / 5; - cal_freq_pier = ar->eeprom.cal_freq_pier_5G; - i = AR5416_NUM_5G_CAL_PIERS - 1; - break; - - default: - return -EINVAL; - break; - } - - for (; i >= 0; i--) { - if (cal_freq_pier[i] != 0xff) - break; - } - if (i < 0) - return -EINVAL; - - idx = ar9170_find_freq_idx(i, cal_freq_pier, f); - - ar9170_regwrite_begin(ar); - - for (chain = 0; chain < AR5416_MAX_CHAINS; chain++) { - for (i = 0; i < AR5416_PD_GAIN_ICEPTS; i++) { - struct ar9170_calibration_data_per_freq *cal_pier_data; - int j; - - switch (channel->band) { - case IEEE80211_BAND_2GHZ: - cal_pier_data = &ar->eeprom. - cal_pier_data_2G[chain][idx]; - break; - - case IEEE80211_BAND_5GHZ: - cal_pier_data = &ar->eeprom. - cal_pier_data_5G[chain][idx]; - break; - - default: - return -EINVAL; - } - - for (j = 0; j < 2; j++) { - vpds[j][i] = ar9170_interpolate_u8(f, - cal_freq_pier[idx], - cal_pier_data->vpd_pdg[j][i], - cal_freq_pier[idx + 1], - cal_pier_data[1].vpd_pdg[j][i]); - - pwrs[j][i] = ar9170_interpolate_u8(f, - cal_freq_pier[idx], - cal_pier_data->pwr_pdg[j][i], - cal_freq_pier[idx + 1], - cal_pier_data[1].pwr_pdg[j][i]) / 2; - } - } - - for (i = 0; i < 76; i++) { - if (i < 25) { - tmp = ar9170_interpolate_val(i, &pwrs[0][0], - &vpds[0][0]); - } else { - tmp = ar9170_interpolate_val(i - 12, - &pwrs[1][0], - &vpds[1][0]); - } - - phy_data |= tmp << ((i & 3) << 3); - if ((i & 3) == 3) { - ar9170_regwrite(0x1c6280 + chain * 0x1000 + - (i & ~3), phy_data); - phy_data = 0; - } - } - - for (i = 19; i < 32; i++) - ar9170_regwrite(0x1c6280 + chain * 0x1000 + (i << 2), - 0x0); - } - - ar9170_regwrite_finish(); - return ar9170_regwrite_result(); -} - -static u8 ar9170_get_max_edge_power(struct ar9170 *ar, - struct ar9170_calctl_edges edges[], - u32 freq) -{ - int i; - u8 rc = AR5416_MAX_RATE_POWER; - u8 f; - if (freq < 3000) - f = freq - 2300; - else - f = (freq - 4800) / 5; - - for (i = 0; i < AR5416_NUM_BAND_EDGES; i++) { - if (edges[i].channel == 0xff) - break; - if (f == edges[i].channel) { - /* exact freq match */ - rc = edges[i].power_flags & ~AR9170_CALCTL_EDGE_FLAGS; - break; - } - if (i > 0 && f < edges[i].channel) { - if (f > edges[i - 1].channel && - edges[i - 1].power_flags & - AR9170_CALCTL_EDGE_FLAGS) { - /* lower channel has the inband flag set */ - rc = edges[i - 1].power_flags & - ~AR9170_CALCTL_EDGE_FLAGS; - } - break; - } - } - - if (i == AR5416_NUM_BAND_EDGES) { - if (f > edges[i - 1].channel && - edges[i - 1].power_flags & AR9170_CALCTL_EDGE_FLAGS) { - /* lower channel has the inband flag set */ - rc = edges[i - 1].power_flags & - ~AR9170_CALCTL_EDGE_FLAGS; - } - } - return rc; -} - -static u8 ar9170_get_heavy_clip(struct ar9170 *ar, - struct ar9170_calctl_edges edges[], - u32 freq, enum ar9170_bw bw) -{ - u8 f; - int i; - u8 rc = 0; - - if (freq < 3000) - f = freq - 2300; - else - f = (freq - 4800) / 5; - - if (bw == AR9170_BW_40_BELOW || bw == AR9170_BW_40_ABOVE) - rc |= 0xf0; - - for (i = 0; i < AR5416_NUM_BAND_EDGES; i++) { - if (edges[i].channel == 0xff) - break; - if (f == edges[i].channel) { - if (!(edges[i].power_flags & AR9170_CALCTL_EDGE_FLAGS)) - rc |= 0x0f; - break; - } - } - - return rc; -} - -/* - * calculate the conformance test limits and the heavy clip parameter - * and apply them to ar->power* (derived from otus hal/hpmain.c, line 3706) - */ -static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) -{ - u8 ctl_grp; /* CTL group */ - u8 ctl_idx; /* CTL index */ - int i, j; - struct ctl_modes { - u8 ctl_mode; - u8 max_power; - u8 *pwr_cal_data; - int pwr_cal_len; - } *modes; - - /* - * order is relevant in the mode_list_*: we fall back to the - * lower indices if any mode is missed in the EEPROM. - */ - struct ctl_modes mode_list_2ghz[] = { - { CTL_11B, 0, ar->power_2G_cck, 4 }, - { CTL_11G, 0, ar->power_2G_ofdm, 4 }, - { CTL_2GHT20, 0, ar->power_2G_ht20, 8 }, - { CTL_2GHT40, 0, ar->power_2G_ht40, 8 }, - }; - struct ctl_modes mode_list_5ghz[] = { - { CTL_11A, 0, ar->power_5G_leg, 4 }, - { CTL_5GHT20, 0, ar->power_5G_ht20, 8 }, - { CTL_5GHT40, 0, ar->power_5G_ht40, 8 }, - }; - int nr_modes; - -#define EDGES(c, n) (ar->eeprom.ctl_data[c].control_edges[n]) - - ar->phy_heavy_clip = 0; - - /* - * TODO: investigate the differences between OTUS' - * hpreg.c::zfHpGetRegulatoryDomain() and - * ath/regd.c::ath_regd_get_band_ctl() - - * e.g. for FCC3_WORLD the OTUS procedure - * always returns CTL_FCC, while the one in ath/ delivers - * CTL_ETSI for 2GHz and CTL_FCC for 5GHz. - */ - ctl_grp = ath_regd_get_band_ctl(&ar->common.regulatory, - ar->hw->conf.channel->band); - - /* ctl group not found - either invalid band (NO_CTL) or ww roaming */ - if (ctl_grp == NO_CTL || ctl_grp == SD_NO_CTL) - ctl_grp = CTL_FCC; - - if (ctl_grp != CTL_FCC) - /* skip CTL and heavy clip for CTL_MKK and CTL_ETSI */ - return; - - if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) { - modes = mode_list_2ghz; - nr_modes = ARRAY_SIZE(mode_list_2ghz); - } else { - modes = mode_list_5ghz; - nr_modes = ARRAY_SIZE(mode_list_5ghz); - } - - for (i = 0; i < nr_modes; i++) { - u8 c = ctl_grp | modes[i].ctl_mode; - for (ctl_idx = 0; ctl_idx < AR5416_NUM_CTLS; ctl_idx++) - if (c == ar->eeprom.ctl_index[ctl_idx]) - break; - if (ctl_idx < AR5416_NUM_CTLS) { - int f_off = 0; - - /* determine heav clip parameter from - the 11G edges array */ - if (modes[i].ctl_mode == CTL_11G) { - ar->phy_heavy_clip = - ar9170_get_heavy_clip(ar, - EDGES(ctl_idx, 1), - freq, bw); - } - - /* adjust freq for 40MHz */ - if (modes[i].ctl_mode == CTL_2GHT40 || - modes[i].ctl_mode == CTL_5GHT40) { - if (bw == AR9170_BW_40_BELOW) - f_off = -10; - else - f_off = 10; - } - - modes[i].max_power = - ar9170_get_max_edge_power(ar, EDGES(ctl_idx, 1), - freq+f_off); - - /* - * TODO: check if the regulatory max. power is - * controlled by cfg80211 for DFS - * (hpmain applies it to max_power itself for DFS freq) - */ - - } else { - /* - * Workaround in otus driver, hpmain.c, line 3906: - * if no data for 5GHT20 are found, take the - * legacy 5G value. - * We extend this here to fallback from any other *HT or - * 11G, too. - */ - int k = i; - - modes[i].max_power = AR5416_MAX_RATE_POWER; - while (k-- > 0) { - if (modes[k].max_power != - AR5416_MAX_RATE_POWER) { - modes[i].max_power = modes[k].max_power; - break; - } - } - } - - /* apply max power to pwr_cal_data (ar->power_*) */ - for (j = 0; j < modes[i].pwr_cal_len; j++) { - modes[i].pwr_cal_data[j] = min(modes[i].pwr_cal_data[j], - modes[i].max_power); - } - } - - if (ar->phy_heavy_clip & 0xf0) { - ar->power_2G_ht40[0]--; - ar->power_2G_ht40[1]--; - ar->power_2G_ht40[2]--; - } - if (ar->phy_heavy_clip & 0xf) { - ar->power_2G_ht20[0]++; - ar->power_2G_ht20[1]++; - ar->power_2G_ht20[2]++; - } - - -#undef EDGES -} - -static int ar9170_set_power_cal(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) -{ - struct ar9170_calibration_target_power_legacy *ctpl; - struct ar9170_calibration_target_power_ht *ctph; - u8 *ctpres; - int ntargets; - int idx, i, n; - u8 ackpower, ackchains, f; - u8 pwr_freqs[AR5416_MAX_NUM_TGT_PWRS]; - - if (freq < 3000) - f = freq - 2300; - else - f = (freq - 4800)/5; - - /* - * cycle through the various modes - * - * legacy modes first: 5G, 2G CCK, 2G OFDM - */ - for (i = 0; i < 3; i++) { - switch (i) { - case 0: /* 5 GHz legacy */ - ctpl = &ar->eeprom.cal_tgt_pwr_5G[0]; - ntargets = AR5416_NUM_5G_TARGET_PWRS; - ctpres = ar->power_5G_leg; - break; - case 1: /* 2.4 GHz CCK */ - ctpl = &ar->eeprom.cal_tgt_pwr_2G_cck[0]; - ntargets = AR5416_NUM_2G_CCK_TARGET_PWRS; - ctpres = ar->power_2G_cck; - break; - case 2: /* 2.4 GHz OFDM */ - ctpl = &ar->eeprom.cal_tgt_pwr_2G_ofdm[0]; - ntargets = AR5416_NUM_2G_OFDM_TARGET_PWRS; - ctpres = ar->power_2G_ofdm; - break; - default: - BUG(); - } - - for (n = 0; n < ntargets; n++) { - if (ctpl[n].freq == 0xff) - break; - pwr_freqs[n] = ctpl[n].freq; - } - ntargets = n; - idx = ar9170_find_freq_idx(ntargets, pwr_freqs, f); - for (n = 0; n < 4; n++) - ctpres[n] = ar9170_interpolate_u8( - f, - ctpl[idx + 0].freq, - ctpl[idx + 0].power[n], - ctpl[idx + 1].freq, - ctpl[idx + 1].power[n]); - } - - /* - * HT modes now: 5G HT20, 5G HT40, 2G CCK, 2G OFDM, 2G HT20, 2G HT40 - */ - for (i = 0; i < 4; i++) { - switch (i) { - case 0: /* 5 GHz HT 20 */ - ctph = &ar->eeprom.cal_tgt_pwr_5G_ht20[0]; - ntargets = AR5416_NUM_5G_TARGET_PWRS; - ctpres = ar->power_5G_ht20; - break; - case 1: /* 5 GHz HT 40 */ - ctph = &ar->eeprom.cal_tgt_pwr_5G_ht40[0]; - ntargets = AR5416_NUM_5G_TARGET_PWRS; - ctpres = ar->power_5G_ht40; - break; - case 2: /* 2.4 GHz HT 20 */ - ctph = &ar->eeprom.cal_tgt_pwr_2G_ht20[0]; - ntargets = AR5416_NUM_2G_OFDM_TARGET_PWRS; - ctpres = ar->power_2G_ht20; - break; - case 3: /* 2.4 GHz HT 40 */ - ctph = &ar->eeprom.cal_tgt_pwr_2G_ht40[0]; - ntargets = AR5416_NUM_2G_OFDM_TARGET_PWRS; - ctpres = ar->power_2G_ht40; - break; - default: - BUG(); - } - - for (n = 0; n < ntargets; n++) { - if (ctph[n].freq == 0xff) - break; - pwr_freqs[n] = ctph[n].freq; - } - ntargets = n; - idx = ar9170_find_freq_idx(ntargets, pwr_freqs, f); - for (n = 0; n < 8; n++) - ctpres[n] = ar9170_interpolate_u8( - f, - ctph[idx + 0].freq, - ctph[idx + 0].power[n], - ctph[idx + 1].freq, - ctph[idx + 1].power[n]); - } - - - /* calc. conformance test limits and apply to ar->power*[] */ - ar9170_calc_ctl(ar, freq, bw); - - /* set ACK/CTS TX power */ - ar9170_regwrite_begin(ar); - - if (ar->eeprom.tx_mask != 1) - ackchains = AR9170_TX_PHY_TXCHAIN_2; - else - ackchains = AR9170_TX_PHY_TXCHAIN_1; - - if (freq < 3000) - ackpower = ar->power_2G_ofdm[0] & 0x3f; - else - ackpower = ar->power_5G_leg[0] & 0x3f; - - ar9170_regwrite(0x1c3694, ackpower << 20 | ackchains << 26); - ar9170_regwrite(0x1c3bb4, ackpower << 5 | ackchains << 11 | - ackpower << 21 | ackchains << 27); - - ar9170_regwrite_finish(); - return ar9170_regwrite_result(); -} - -static int ar9170_calc_noise_dbm(u32 raw_noise) -{ - if (raw_noise & 0x100) - return ~((raw_noise & 0x0ff) >> 1); - else - return (raw_noise & 0xff) >> 1; -} - -int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, - enum ar9170_rf_init_mode rfi, enum ar9170_bw bw) -{ - const struct ar9170_phy_freq_params *freqpar; - u32 cmd, tmp, offs; - __le32 vals[8]; - int i, err; - bool bandswitch; - - /* clear BB heavy clip enable */ - err = ar9170_write_reg(ar, 0x1c59e0, 0x200); - if (err) - return err; - - /* may be NULL at first setup */ - if (ar->channel) - bandswitch = ar->channel->band != channel->band; - else - bandswitch = true; - - /* HW workaround */ - if (!ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] && - channel->center_freq <= 2417) - bandswitch = true; - - err = ar->exec_cmd(ar, AR9170_CMD_FREQ_START, 0, NULL, 0, NULL); - if (err) - return err; - - if (rfi != AR9170_RFI_NONE || bandswitch) { - u32 val = 0x400; - - if (rfi == AR9170_RFI_COLD) - val = 0x800; - - /* warm/cold reset BB/ADDA */ - err = ar9170_write_reg(ar, 0x1d4004, val); - if (err) - return err; - - err = ar9170_write_reg(ar, 0x1d4004, 0x0); - if (err) - return err; - - err = ar9170_init_phy(ar, channel->band); - if (err) - return err; - - err = ar9170_init_rf_banks_0_7(ar, - channel->band == IEEE80211_BAND_5GHZ); - if (err) - return err; - - cmd = AR9170_CMD_RF_INIT; - } else { - cmd = AR9170_CMD_FREQUENCY; - } - - err = ar9170_init_rf_bank4_pwr(ar, - channel->band == IEEE80211_BAND_5GHZ, - channel->center_freq, bw); - if (err) - return err; - - switch (bw) { - case AR9170_BW_20: - tmp = 0x240; - offs = 0; - break; - case AR9170_BW_40_BELOW: - tmp = 0x2c4; - offs = 3; - break; - case AR9170_BW_40_ABOVE: - tmp = 0x2d4; - offs = 1; - break; - default: - BUG(); - return -ENOSYS; - } - - if (ar->eeprom.tx_mask != 1) - tmp |= 0x100; - - err = ar9170_write_reg(ar, 0x1c5804, tmp); - if (err) - return err; - - err = ar9170_set_freq_cal_data(ar, channel); - if (err) - return err; - - err = ar9170_set_power_cal(ar, channel->center_freq, bw); - if (err) - return err; - - freqpar = ar9170_get_hw_dyn_params(channel, bw); - - vals[0] = cpu_to_le32(channel->center_freq * 1000); - vals[1] = cpu_to_le32(conf_is_ht40(&ar->hw->conf)); - vals[2] = cpu_to_le32(offs << 2 | 1); - vals[3] = cpu_to_le32(freqpar->coeff_exp); - vals[4] = cpu_to_le32(freqpar->coeff_man); - vals[5] = cpu_to_le32(freqpar->coeff_exp_shgi); - vals[6] = cpu_to_le32(freqpar->coeff_man_shgi); - vals[7] = cpu_to_le32(1000); - - err = ar->exec_cmd(ar, cmd, sizeof(vals), (u8 *)vals, - sizeof(vals), (u8 *)vals); - if (err) - return err; - - if (ar->phy_heavy_clip) { - err = ar9170_write_reg(ar, 0x1c59e0, - 0x200 | ar->phy_heavy_clip); - if (err) { - if (ar9170_nag_limiter(ar)) - wiphy_err(ar->hw->wiphy, - "failed to set heavy clip\n"); - } - } - - for (i = 0; i < 2; i++) { - ar->noise[i] = ar9170_calc_noise_dbm( - (le32_to_cpu(vals[2 + i]) >> 19) & 0x1ff); - - ar->noise[i + 2] = ar9170_calc_noise_dbm( - (le32_to_cpu(vals[5 + i]) >> 23) & 0x1ff); - } - - ar->channel = channel; - return 0; -} diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c deleted file mode 100644 index d3be6f9816b5..000000000000 --- a/drivers/net/wireless/ath/ar9170/usb.c +++ /dev/null @@ -1,1008 +0,0 @@ -/* - * Atheros AR9170 driver - * - * USB - frontend - * - * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> - * Copyright 2009, Christian Lamparter <chunkeey@web.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 Atheros Communications, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/usb.h> -#include <linux/firmware.h> -#include <linux/etherdevice.h> -#include <linux/device.h> -#include <net/mac80211.h> -#include "ar9170.h" -#include "cmd.h" -#include "hw.h" -#include "usb.h" - -MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); -MODULE_AUTHOR("Christian Lamparter <chunkeey@web.de>"); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Atheros AR9170 802.11n USB wireless"); -MODULE_FIRMWARE("ar9170.fw"); - -enum ar9170_requirements { - AR9170_REQ_FW1_ONLY = 1, -}; - -static struct usb_device_id ar9170_usb_ids[] = { - /* Atheros 9170 */ - { USB_DEVICE(0x0cf3, 0x9170) }, - /* Atheros TG121N */ - { USB_DEVICE(0x0cf3, 0x1001) }, - /* TP-Link TL-WN821N v2 */ - { USB_DEVICE(0x0cf3, 0x1002) }, - /* 3Com Dual Band 802.11n USB Adapter */ - { USB_DEVICE(0x0cf3, 0x1010) }, - /* H3C Dual Band 802.11n USB Adapter */ - { USB_DEVICE(0x0cf3, 0x1011) }, - /* Cace Airpcap NX */ - { USB_DEVICE(0xcace, 0x0300) }, - /* D-Link DWA 160 A1 */ - { USB_DEVICE(0x07d1, 0x3c10) }, - /* D-Link DWA 160 A2 */ - { USB_DEVICE(0x07d1, 0x3a09) }, - /* Netgear WNA1000 */ - { USB_DEVICE(0x0846, 0x9040) }, - /* Netgear WNDA3100 */ - { USB_DEVICE(0x0846, 0x9010) }, - /* Netgear WN111 v2 */ - { USB_DEVICE(0x0846, 0x9001) }, - /* Zydas ZD1221 */ - { USB_DEVICE(0x0ace, 0x1221) }, - /* Proxim ORiNOCO 802.11n USB */ - { USB_DEVICE(0x1435, 0x0804) }, - /* WNC Generic 11n USB Dongle */ - { USB_DEVICE(0x1435, 0x0326) }, - /* ZyXEL NWD271N */ - { USB_DEVICE(0x0586, 0x3417) }, - /* Z-Com UB81 BG */ - { USB_DEVICE(0x0cde, 0x0023) }, - /* Z-Com UB82 ABG */ - { USB_DEVICE(0x0cde, 0x0026) }, - /* Sphairon Homelink 1202 */ - { USB_DEVICE(0x0cde, 0x0027) }, - /* Arcadyan WN7512 */ - { USB_DEVICE(0x083a, 0xf522) }, - /* Planex GWUS300 */ - { USB_DEVICE(0x2019, 0x5304) }, - /* IO-Data WNGDNUS2 */ - { USB_DEVICE(0x04bb, 0x093f) }, - /* AVM FRITZ!WLAN USB Stick N */ - { USB_DEVICE(0x057C, 0x8401) }, - /* NEC WL300NU-G */ - { USB_DEVICE(0x0409, 0x0249) }, - /* AVM FRITZ!WLAN USB Stick N 2.4 */ - { USB_DEVICE(0x057C, 0x8402), .driver_info = AR9170_REQ_FW1_ONLY }, - /* Qwest/Actiontec 802AIN Wireless N USB Network Adapter */ - { USB_DEVICE(0x1668, 0x1200) }, - - /* terminate */ - {} -}; -MODULE_DEVICE_TABLE(usb, ar9170_usb_ids); - -static void ar9170_usb_submit_urb(struct ar9170_usb *aru) -{ - struct urb *urb; - unsigned long flags; - int err; - - if (unlikely(!IS_STARTED(&aru->common))) - return ; - - spin_lock_irqsave(&aru->tx_urb_lock, flags); - if (atomic_read(&aru->tx_submitted_urbs) >= AR9170_NUM_TX_URBS) { - spin_unlock_irqrestore(&aru->tx_urb_lock, flags); - return ; - } - atomic_inc(&aru->tx_submitted_urbs); - - urb = usb_get_from_anchor(&aru->tx_pending); - if (!urb) { - atomic_dec(&aru->tx_submitted_urbs); - spin_unlock_irqrestore(&aru->tx_urb_lock, flags); - - return ; - } - spin_unlock_irqrestore(&aru->tx_urb_lock, flags); - - aru->tx_pending_urbs--; - usb_anchor_urb(urb, &aru->tx_submitted); - - err = usb_submit_urb(urb, GFP_ATOMIC); - if (unlikely(err)) { - if (ar9170_nag_limiter(&aru->common)) - dev_err(&aru->udev->dev, "submit_urb failed (%d).\n", - err); - - usb_unanchor_urb(urb); - atomic_dec(&aru->tx_submitted_urbs); - ar9170_tx_callback(&aru->common, urb->context); - } - - usb_free_urb(urb); -} - -static void ar9170_usb_tx_urb_complete_frame(struct urb *urb) -{ - struct sk_buff *skb = urb->context; - struct ar9170_usb *aru = usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); - - if (unlikely(!aru)) { - dev_kfree_skb_irq(skb); - return ; - } - - atomic_dec(&aru->tx_submitted_urbs); - - ar9170_tx_callback(&aru->common, skb); - - ar9170_usb_submit_urb(aru); -} - -static void ar9170_usb_tx_urb_complete(struct urb *urb) -{ -} - -static void ar9170_usb_irq_completed(struct urb *urb) -{ - struct ar9170_usb *aru = urb->context; - - switch (urb->status) { - /* everything is fine */ - case 0: - break; - - /* disconnect */ - case -ENOENT: - case -ECONNRESET: - case -ENODEV: - case -ESHUTDOWN: - goto free; - - default: - goto resubmit; - } - - ar9170_handle_command_response(&aru->common, urb->transfer_buffer, - urb->actual_length); - -resubmit: - usb_anchor_urb(urb, &aru->rx_submitted); - if (usb_submit_urb(urb, GFP_ATOMIC)) { - usb_unanchor_urb(urb); - goto free; - } - - return; - -free: - usb_free_coherent(aru->udev, 64, urb->transfer_buffer, urb->transfer_dma); -} - -static void ar9170_usb_rx_completed(struct urb *urb) -{ - struct sk_buff *skb = urb->context; - struct ar9170_usb *aru = usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); - int err; - - if (!aru) - goto free; - - switch (urb->status) { - /* everything is fine */ - case 0: - break; - - /* disconnect */ - case -ENOENT: - case -ECONNRESET: - case -ENODEV: - case -ESHUTDOWN: - goto free; - - default: - goto resubmit; - } - - skb_put(skb, urb->actual_length); - ar9170_rx(&aru->common, skb); - -resubmit: - skb_reset_tail_pointer(skb); - skb_trim(skb, 0); - - usb_anchor_urb(urb, &aru->rx_submitted); - err = usb_submit_urb(urb, GFP_ATOMIC); - if (unlikely(err)) { - usb_unanchor_urb(urb); - goto free; - } - - return ; - -free: - dev_kfree_skb_irq(skb); -} - -static int ar9170_usb_prep_rx_urb(struct ar9170_usb *aru, - struct urb *urb, gfp_t gfp) -{ - struct sk_buff *skb; - - skb = __dev_alloc_skb(AR9170_MAX_RX_BUFFER_SIZE + 32, gfp); - if (!skb) - return -ENOMEM; - - /* reserve some space for mac80211's radiotap */ - skb_reserve(skb, 32); - - usb_fill_bulk_urb(urb, aru->udev, - usb_rcvbulkpipe(aru->udev, AR9170_EP_RX), - skb->data, min(skb_tailroom(skb), - AR9170_MAX_RX_BUFFER_SIZE), - ar9170_usb_rx_completed, skb); - - return 0; -} - -static int ar9170_usb_alloc_rx_irq_urb(struct ar9170_usb *aru) -{ - struct urb *urb = NULL; - void *ibuf; - int err = -ENOMEM; - - /* initialize interrupt endpoint */ - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) - goto out; - - ibuf = usb_alloc_coherent(aru->udev, 64, GFP_KERNEL, &urb->transfer_dma); - if (!ibuf) - goto out; - - usb_fill_int_urb(urb, aru->udev, - usb_rcvintpipe(aru->udev, AR9170_EP_IRQ), ibuf, - 64, ar9170_usb_irq_completed, aru, 1); - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - - usb_anchor_urb(urb, &aru->rx_submitted); - err = usb_submit_urb(urb, GFP_KERNEL); - if (err) { - usb_unanchor_urb(urb); - usb_free_coherent(aru->udev, 64, urb->transfer_buffer, - urb->transfer_dma); - } - -out: - usb_free_urb(urb); - return err; -} - -static int ar9170_usb_alloc_rx_bulk_urbs(struct ar9170_usb *aru) -{ - struct urb *urb; - int i; - int err = -EINVAL; - - for (i = 0; i < AR9170_NUM_RX_URBS; i++) { - err = -ENOMEM; - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) - goto err_out; - - err = ar9170_usb_prep_rx_urb(aru, urb, GFP_KERNEL); - if (err) { - usb_free_urb(urb); - goto err_out; - } - - usb_anchor_urb(urb, &aru->rx_submitted); - err = usb_submit_urb(urb, GFP_KERNEL); - if (err) { - usb_unanchor_urb(urb); - dev_kfree_skb_any((void *) urb->transfer_buffer); - usb_free_urb(urb); - goto err_out; - } - usb_free_urb(urb); - } - - /* the device now waiting for a firmware. */ - aru->common.state = AR9170_IDLE; - return 0; - -err_out: - - usb_kill_anchored_urbs(&aru->rx_submitted); - return err; -} - -static int ar9170_usb_flush(struct ar9170 *ar) -{ - struct ar9170_usb *aru = (void *) ar; - struct urb *urb; - int ret, err = 0; - - if (IS_STARTED(ar)) - aru->common.state = AR9170_IDLE; - - usb_wait_anchor_empty_timeout(&aru->tx_pending, - msecs_to_jiffies(800)); - while ((urb = usb_get_from_anchor(&aru->tx_pending))) { - ar9170_tx_callback(&aru->common, (void *) urb->context); - usb_free_urb(urb); - } - - /* lets wait a while until the tx - queues are dried out */ - ret = usb_wait_anchor_empty_timeout(&aru->tx_submitted, - msecs_to_jiffies(100)); - if (ret == 0) - err = -ETIMEDOUT; - - usb_kill_anchored_urbs(&aru->tx_submitted); - - if (IS_ACCEPTING_CMD(ar)) - aru->common.state = AR9170_STARTED; - - return err; -} - -static void ar9170_usb_cancel_urbs(struct ar9170_usb *aru) -{ - int err; - - aru->common.state = AR9170_UNKNOWN_STATE; - - err = ar9170_usb_flush(&aru->common); - if (err) - dev_err(&aru->udev->dev, "stuck tx urbs!\n"); - - usb_poison_anchored_urbs(&aru->tx_submitted); - usb_poison_anchored_urbs(&aru->rx_submitted); -} - -static int ar9170_usb_exec_cmd(struct ar9170 *ar, enum ar9170_cmd cmd, - unsigned int plen, void *payload, - unsigned int outlen, void *out) -{ - struct ar9170_usb *aru = (void *) ar; - struct urb *urb = NULL; - unsigned long flags; - int err = -ENOMEM; - - if (unlikely(!IS_ACCEPTING_CMD(ar))) - return -EPERM; - - if (WARN_ON(plen > AR9170_MAX_CMD_LEN - 4)) - return -EINVAL; - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (unlikely(!urb)) - goto err_free; - - ar->cmdbuf[0] = cpu_to_le32(plen); - ar->cmdbuf[0] |= cpu_to_le32(cmd << 8); - /* writing multiple regs fills this buffer already */ - if (plen && payload != (u8 *)(&ar->cmdbuf[1])) - memcpy(&ar->cmdbuf[1], payload, plen); - - spin_lock_irqsave(&aru->common.cmdlock, flags); - aru->readbuf = (u8 *)out; - aru->readlen = outlen; - spin_unlock_irqrestore(&aru->common.cmdlock, flags); - - usb_fill_int_urb(urb, aru->udev, - usb_sndintpipe(aru->udev, AR9170_EP_CMD), - aru->common.cmdbuf, plen + 4, - ar9170_usb_tx_urb_complete, NULL, 1); - - usb_anchor_urb(urb, &aru->tx_submitted); - err = usb_submit_urb(urb, GFP_ATOMIC); - if (unlikely(err)) { - usb_unanchor_urb(urb); - usb_free_urb(urb); - goto err_unbuf; - } - usb_free_urb(urb); - - err = wait_for_completion_timeout(&aru->cmd_wait, HZ); - if (err == 0) { - err = -ETIMEDOUT; - goto err_unbuf; - } - - if (aru->readlen != outlen) { - err = -EMSGSIZE; - goto err_unbuf; - } - - return 0; - -err_unbuf: - /* Maybe the device was removed in the second we were waiting? */ - if (IS_STARTED(ar)) { - dev_err(&aru->udev->dev, "no command feedback " - "received (%d).\n", err); - - /* provide some maybe useful debug information */ - print_hex_dump_bytes("ar9170 cmd: ", DUMP_PREFIX_NONE, - aru->common.cmdbuf, plen + 4); - dump_stack(); - } - - /* invalidate to avoid completing the next prematurely */ - spin_lock_irqsave(&aru->common.cmdlock, flags); - aru->readbuf = NULL; - aru->readlen = 0; - spin_unlock_irqrestore(&aru->common.cmdlock, flags); - -err_free: - - return err; -} - -static int ar9170_usb_tx(struct ar9170 *ar, struct sk_buff *skb) -{ - struct ar9170_usb *aru = (struct ar9170_usb *) ar; - struct urb *urb; - - if (unlikely(!IS_STARTED(ar))) { - /* Seriously, what were you drink... err... thinking!? */ - return -EPERM; - } - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (unlikely(!urb)) - return -ENOMEM; - - usb_fill_bulk_urb(urb, aru->udev, - usb_sndbulkpipe(aru->udev, AR9170_EP_TX), - skb->data, skb->len, - ar9170_usb_tx_urb_complete_frame, skb); - urb->transfer_flags |= URB_ZERO_PACKET; - - usb_anchor_urb(urb, &aru->tx_pending); - aru->tx_pending_urbs++; - - usb_free_urb(urb); - - ar9170_usb_submit_urb(aru); - return 0; -} - -static void ar9170_usb_callback_cmd(struct ar9170 *ar, u32 len , void *buffer) -{ - struct ar9170_usb *aru = (void *) ar; - unsigned long flags; - u32 in, out; - - if (unlikely(!buffer)) - return ; - - in = le32_to_cpup((__le32 *)buffer); - out = le32_to_cpu(ar->cmdbuf[0]); - - /* mask off length byte */ - out &= ~0xFF; - - if (aru->readlen >= 0) { - /* add expected length */ - out |= aru->readlen; - } else { - /* add obtained length */ - out |= in & 0xFF; - } - - /* - * Some commands (e.g: AR9170_CMD_FREQUENCY) have a variable response - * length and we cannot predict the correct length in advance. - * So we only check if we provided enough space for the data. - */ - if (unlikely(out < in)) { - dev_warn(&aru->udev->dev, "received invalid command response " - "got %d bytes, instead of %d bytes " - "and the resp length is %d bytes\n", - in, out, len); - print_hex_dump_bytes("ar9170 invalid resp: ", - DUMP_PREFIX_OFFSET, buffer, len); - /* - * Do not complete, then the command times out, - * and we get a stack trace from there. - */ - return ; - } - - spin_lock_irqsave(&aru->common.cmdlock, flags); - if (aru->readbuf && len > 0) { - memcpy(aru->readbuf, buffer + 4, len - 4); - aru->readbuf = NULL; - } - complete(&aru->cmd_wait); - spin_unlock_irqrestore(&aru->common.cmdlock, flags); -} - -static int ar9170_usb_upload(struct ar9170_usb *aru, const void *data, - size_t len, u32 addr, bool complete) -{ - int transfer, err; - u8 *buf = kmalloc(4096, GFP_KERNEL); - - if (!buf) - return -ENOMEM; - - while (len) { - transfer = min_t(int, len, 4096); - memcpy(buf, data, transfer); - - err = usb_control_msg(aru->udev, usb_sndctrlpipe(aru->udev, 0), - 0x30 /* FW DL */, 0x40 | USB_DIR_OUT, - addr >> 8, 0, buf, transfer, 1000); - - if (err < 0) { - kfree(buf); - return err; - } - - len -= transfer; - data += transfer; - addr += transfer; - } - kfree(buf); - - if (complete) { - err = usb_control_msg(aru->udev, usb_sndctrlpipe(aru->udev, 0), - 0x31 /* FW DL COMPLETE */, - 0x40 | USB_DIR_OUT, 0, 0, NULL, 0, 5000); - } - - return 0; -} - -static int ar9170_usb_reset(struct ar9170_usb *aru) -{ - int ret, lock = (aru->intf->condition != USB_INTERFACE_BINDING); - - if (lock) { - ret = usb_lock_device_for_reset(aru->udev, aru->intf); - if (ret < 0) { - dev_err(&aru->udev->dev, "unable to lock device " - "for reset (%d).\n", ret); - return ret; - } - } - - ret = usb_reset_device(aru->udev); - if (lock) - usb_unlock_device(aru->udev); - - /* let it rest - for a second - */ - msleep(1000); - - return ret; -} - -static int ar9170_usb_upload_firmware(struct ar9170_usb *aru) -{ - int err; - - if (!aru->init_values) - goto upload_fw_start; - - /* First, upload initial values to device RAM */ - err = ar9170_usb_upload(aru, aru->init_values->data, - aru->init_values->size, 0x102800, false); - if (err) { - dev_err(&aru->udev->dev, "firmware part 1 " - "upload failed (%d).\n", err); - return err; - } - -upload_fw_start: - - /* Then, upload the firmware itself and start it */ - return ar9170_usb_upload(aru, aru->firmware->data, aru->firmware->size, - 0x200000, true); -} - -static int ar9170_usb_init_transport(struct ar9170_usb *aru) -{ - struct ar9170 *ar = (void *) &aru->common; - int err; - - ar9170_regwrite_begin(ar); - - /* Set USB Rx stream mode MAX packet number to 2 */ - ar9170_regwrite(AR9170_USB_REG_MAX_AGG_UPLOAD, 0x4); - - /* Set USB Rx stream mode timeout to 10us */ - ar9170_regwrite(AR9170_USB_REG_UPLOAD_TIME_CTL, 0x80); - - ar9170_regwrite_finish(); - - err = ar9170_regwrite_result(); - if (err) - dev_err(&aru->udev->dev, "USB setup failed (%d).\n", err); - - return err; -} - -static void ar9170_usb_stop(struct ar9170 *ar) -{ - struct ar9170_usb *aru = (void *) ar; - int ret; - - if (IS_ACCEPTING_CMD(ar)) - aru->common.state = AR9170_STOPPED; - - ret = ar9170_usb_flush(ar); - if (ret) - dev_err(&aru->udev->dev, "kill pending tx urbs.\n"); - - usb_poison_anchored_urbs(&aru->tx_submitted); - - /* - * Note: - * So far we freed all tx urbs, but we won't dare to touch any rx urbs. - * Else we would end up with a unresponsive device... - */ -} - -static int ar9170_usb_open(struct ar9170 *ar) -{ - struct ar9170_usb *aru = (void *) ar; - int err; - - usb_unpoison_anchored_urbs(&aru->tx_submitted); - err = ar9170_usb_init_transport(aru); - if (err) { - usb_poison_anchored_urbs(&aru->tx_submitted); - return err; - } - - aru->common.state = AR9170_IDLE; - return 0; -} - -static int ar9170_usb_init_device(struct ar9170_usb *aru) -{ - int err; - - err = ar9170_usb_alloc_rx_irq_urb(aru); - if (err) - goto err_out; - - err = ar9170_usb_alloc_rx_bulk_urbs(aru); - if (err) - goto err_unrx; - - err = ar9170_usb_upload_firmware(aru); - if (err) { - err = ar9170_echo_test(&aru->common, 0x60d43110); - if (err) { - /* force user invention, by disabling the device */ - err = usb_driver_set_configuration(aru->udev, -1); - dev_err(&aru->udev->dev, "device is in a bad state. " - "please reconnect it!\n"); - goto err_unrx; - } - } - - return 0; - -err_unrx: - ar9170_usb_cancel_urbs(aru); - -err_out: - return err; -} - -static void ar9170_usb_firmware_failed(struct ar9170_usb *aru) -{ - struct device *parent = aru->udev->dev.parent; - struct usb_device *udev; - - /* - * Store a copy of the usb_device pointer locally. - * This is because device_release_driver initiates - * ar9170_usb_disconnect, which in turn frees our - * driver context (aru). - */ - udev = aru->udev; - - complete(&aru->firmware_loading_complete); - - /* unbind anything failed */ - if (parent) - device_lock(parent); - - device_release_driver(&udev->dev); - if (parent) - device_unlock(parent); - - usb_put_dev(udev); -} - -static void ar9170_usb_firmware_finish(const struct firmware *fw, void *context) -{ - struct ar9170_usb *aru = context; - int err; - - aru->firmware = fw; - - if (!fw) { - dev_err(&aru->udev->dev, "firmware file not found.\n"); - goto err_freefw; - } - - err = ar9170_usb_init_device(aru); - if (err) - goto err_freefw; - - err = ar9170_usb_open(&aru->common); - if (err) - goto err_unrx; - - err = ar9170_register(&aru->common, &aru->udev->dev); - - ar9170_usb_stop(&aru->common); - if (err) - goto err_unrx; - - complete(&aru->firmware_loading_complete); - usb_put_dev(aru->udev); - return; - - err_unrx: - ar9170_usb_cancel_urbs(aru); - - err_freefw: - ar9170_usb_firmware_failed(aru); -} - -static void ar9170_usb_firmware_inits(const struct firmware *fw, - void *context) -{ - struct ar9170_usb *aru = context; - int err; - - if (!fw) { - dev_err(&aru->udev->dev, "file with init values not found.\n"); - ar9170_usb_firmware_failed(aru); - return; - } - - aru->init_values = fw; - - /* ok so we have the init values -- get code for two-stage */ - - err = request_firmware_nowait(THIS_MODULE, 1, "ar9170-2.fw", - &aru->udev->dev, GFP_KERNEL, aru, - ar9170_usb_firmware_finish); - if (err) - ar9170_usb_firmware_failed(aru); -} - -static void ar9170_usb_firmware_step2(const struct firmware *fw, void *context) -{ - struct ar9170_usb *aru = context; - int err; - - if (fw) { - ar9170_usb_firmware_finish(fw, context); - return; - } - - if (aru->req_one_stage_fw) { - dev_err(&aru->udev->dev, "ar9170.fw firmware file " - "not found and is required for this device\n"); - ar9170_usb_firmware_failed(aru); - return; - } - - dev_err(&aru->udev->dev, "ar9170.fw firmware file " - "not found, trying old firmware...\n"); - - err = request_firmware_nowait(THIS_MODULE, 1, "ar9170-1.fw", - &aru->udev->dev, GFP_KERNEL, aru, - ar9170_usb_firmware_inits); - if (err) - ar9170_usb_firmware_failed(aru); -} - -static bool ar9170_requires_one_stage(const struct usb_device_id *id) -{ - if (!id->driver_info) - return false; - if (id->driver_info == AR9170_REQ_FW1_ONLY) - return true; - return false; -} - -static int ar9170_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct ar9170_usb *aru; - struct ar9170 *ar; - struct usb_device *udev; - int err; - - aru = ar9170_alloc(sizeof(*aru)); - if (IS_ERR(aru)) { - err = PTR_ERR(aru); - goto out; - } - - udev = interface_to_usbdev(intf); - usb_get_dev(udev); - aru->udev = udev; - aru->intf = intf; - ar = &aru->common; - - aru->req_one_stage_fw = ar9170_requires_one_stage(id); - - usb_set_intfdata(intf, aru); - SET_IEEE80211_DEV(ar->hw, &intf->dev); - - init_usb_anchor(&aru->rx_submitted); - init_usb_anchor(&aru->tx_pending); - init_usb_anchor(&aru->tx_submitted); - init_completion(&aru->cmd_wait); - init_completion(&aru->firmware_loading_complete); - spin_lock_init(&aru->tx_urb_lock); - - aru->tx_pending_urbs = 0; - atomic_set(&aru->tx_submitted_urbs, 0); - - aru->common.stop = ar9170_usb_stop; - aru->common.flush = ar9170_usb_flush; - aru->common.open = ar9170_usb_open; - aru->common.tx = ar9170_usb_tx; - aru->common.exec_cmd = ar9170_usb_exec_cmd; - aru->common.callback_cmd = ar9170_usb_callback_cmd; - -#ifdef CONFIG_PM - udev->reset_resume = 1; -#endif /* CONFIG_PM */ - err = ar9170_usb_reset(aru); - if (err) - goto err_freehw; - - usb_get_dev(aru->udev); - return request_firmware_nowait(THIS_MODULE, 1, "ar9170.fw", - &aru->udev->dev, GFP_KERNEL, aru, - ar9170_usb_firmware_step2); -err_freehw: - usb_set_intfdata(intf, NULL); - usb_put_dev(udev); - ieee80211_free_hw(ar->hw); -out: - return err; -} - -static void ar9170_usb_disconnect(struct usb_interface *intf) -{ - struct ar9170_usb *aru = usb_get_intfdata(intf); - - if (!aru) - return; - - aru->common.state = AR9170_IDLE; - - wait_for_completion(&aru->firmware_loading_complete); - - ar9170_unregister(&aru->common); - ar9170_usb_cancel_urbs(aru); - - usb_put_dev(aru->udev); - usb_set_intfdata(intf, NULL); - ieee80211_free_hw(aru->common.hw); - - release_firmware(aru->init_values); - release_firmware(aru->firmware); -} - -#ifdef CONFIG_PM -static int ar9170_suspend(struct usb_interface *intf, - pm_message_t message) -{ - struct ar9170_usb *aru = usb_get_intfdata(intf); - - if (!aru) - return -ENODEV; - - aru->common.state = AR9170_IDLE; - ar9170_usb_cancel_urbs(aru); - - return 0; -} - -static int ar9170_resume(struct usb_interface *intf) -{ - struct ar9170_usb *aru = usb_get_intfdata(intf); - int err; - - if (!aru) - return -ENODEV; - - usb_unpoison_anchored_urbs(&aru->rx_submitted); - usb_unpoison_anchored_urbs(&aru->tx_submitted); - - err = ar9170_usb_init_device(aru); - if (err) - goto err_unrx; - - err = ar9170_usb_open(&aru->common); - if (err) - goto err_unrx; - - return 0; - -err_unrx: - aru->common.state = AR9170_IDLE; - ar9170_usb_cancel_urbs(aru); - - return err; -} -#endif /* CONFIG_PM */ - -static struct usb_driver ar9170_driver = { - .name = "ar9170usb", - .probe = ar9170_usb_probe, - .disconnect = ar9170_usb_disconnect, - .id_table = ar9170_usb_ids, - .soft_unbind = 1, -#ifdef CONFIG_PM - .suspend = ar9170_suspend, - .resume = ar9170_resume, - .reset_resume = ar9170_resume, -#endif /* CONFIG_PM */ -}; - -static int __init ar9170_init(void) -{ - return usb_register(&ar9170_driver); -} - -static void __exit ar9170_exit(void) -{ - usb_deregister(&ar9170_driver); -} - -module_init(ar9170_init); -module_exit(ar9170_exit); diff --git a/drivers/net/wireless/ath/ar9170/usb.h b/drivers/net/wireless/ath/ar9170/usb.h deleted file mode 100644 index 919b06046eb3..000000000000 --- a/drivers/net/wireless/ath/ar9170/usb.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Atheros AR9170 USB driver - * - * Driver specific definitions - * - * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> - * Copyright 2009, Christian Lamparter <chunkeey@web.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 Atheros Communications, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#ifndef __USB_H -#define __USB_H - -#include <linux/usb.h> -#include <linux/completion.h> -#include <linux/spinlock.h> -#include <linux/leds.h> -#include <net/cfg80211.h> -#include <net/mac80211.h> -#include <linux/firmware.h> -#include "eeprom.h" -#include "hw.h" -#include "ar9170.h" - -#define AR9170_NUM_RX_URBS 16 -#define AR9170_NUM_TX_URBS 8 - -struct firmware; - -struct ar9170_usb { - struct ar9170 common; - struct usb_device *udev; - struct usb_interface *intf; - - struct usb_anchor rx_submitted; - struct usb_anchor tx_pending; - struct usb_anchor tx_submitted; - - bool req_one_stage_fw; - - spinlock_t tx_urb_lock; - atomic_t tx_submitted_urbs; - unsigned int tx_pending_urbs; - - struct completion cmd_wait; - struct completion firmware_loading_complete; - int readlen; - u8 *readbuf; - - const struct firmware *init_values; - const struct firmware *firmware; -}; - -#endif /* __USB_H */ diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index a6c6a466000f..6d7105b7e8f1 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -119,6 +119,7 @@ struct ath_ops { void (*write)(void *, u32 val, u32 reg_offset); void (*enable_write_buffer)(void *); void (*write_flush) (void *); + u32 (*rmw)(void *, u32 reg_offset, u32 set, u32 clr); }; struct ath_common; diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index 106c0b06cf55..4bf9dab4f2b3 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -44,6 +44,34 @@ static const int m1ThreshExt_off = 127; static const int m2ThreshExt_off = 127; +static void ar5008_rf_bank_setup(u32 *bank, struct ar5416IniArray *array, + int col) +{ + int i; + + for (i = 0; i < array->ia_rows; i++) + bank[i] = INI_RA(array, i, col); +} + + +#define REG_WRITE_RF_ARRAY(iniarray, regData, regWr) \ + ar5008_write_rf_array(ah, iniarray, regData, &(regWr)) + +static void ar5008_write_rf_array(struct ath_hw *ah, struct ar5416IniArray *array, + u32 *data, unsigned int *writecnt) +{ + int r; + + ENABLE_REGWRITE_BUFFER(ah); + + for (r = 0; r < array->ia_rows; r++) { + REG_WRITE(ah, INI_RA(array, r, 0), data[r]); + DO_DELAY(*writecnt); + } + + REGWRITE_BUFFER_FLUSH(ah); +} + /** * ar5008_hw_phy_modify_rx_buffer() - perform analog swizzling of parameters * @rfbuf: @@ -530,16 +558,16 @@ static bool ar5008_hw_set_rf_regs(struct ath_hw *ah, eepMinorRev = ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV); /* Setup Bank 0 Write */ - RF_BANK_SETUP(ah->analogBank0Data, &ah->iniBank0, 1); + ar5008_rf_bank_setup(ah->analogBank0Data, &ah->iniBank0, 1); /* Setup Bank 1 Write */ - RF_BANK_SETUP(ah->analogBank1Data, &ah->iniBank1, 1); + ar5008_rf_bank_setup(ah->analogBank1Data, &ah->iniBank1, 1); /* Setup Bank 2 Write */ - RF_BANK_SETUP(ah->analogBank2Data, &ah->iniBank2, 1); + ar5008_rf_bank_setup(ah->analogBank2Data, &ah->iniBank2, 1); /* Setup Bank 6 Write */ - RF_BANK_SETUP(ah->analogBank3Data, &ah->iniBank3, + ar5008_rf_bank_setup(ah->analogBank3Data, &ah->iniBank3, modesIndex); { int i; @@ -569,7 +597,7 @@ static bool ar5008_hw_set_rf_regs(struct ath_hw *ah, } /* Setup Bank 7 Setup */ - RF_BANK_SETUP(ah->analogBank7Data, &ah->iniBank7, 1); + ar5008_rf_bank_setup(ah->analogBank7Data, &ah->iniBank7, 1); /* Write Analog registers */ REG_WRITE_RF_ARRAY(&ah->iniBank0, ah->analogBank0Data, @@ -729,6 +757,7 @@ static int ar5008_hw_process_ini(struct ath_hw *ah, struct ath9k_channel *chan) { struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); + struct ath_common *common = ath9k_hw_common(ah); int i, regWrites = 0; struct ieee80211_channel *channel = chan->chan; u32 modesIndex, freqIndex; @@ -805,7 +834,8 @@ static int ar5008_hw_process_ini(struct ath_hw *ah, REG_WRITE(ah, reg, val); if (reg >= 0x7800 && reg < 0x78a0 - && ah->config.analog_shiftreg) { + && ah->config.analog_shiftreg + && (common->bus_ops->ath_bus_type != ATH_USB)) { udelay(100); } @@ -835,7 +865,8 @@ static int ar5008_hw_process_ini(struct ath_hw *ah, REG_WRITE(ah, reg, val); if (reg >= 0x7800 && reg < 0x78a0 - && ah->config.analog_shiftreg) { + && ah->config.analog_shiftreg + && (common->bus_ops->ath_bus_type != ATH_USB)) { udelay(100); } diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c index 76388c6d6692..cb611b287b35 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c @@ -26,6 +26,27 @@ enum ar9002_cal_types { IQ_MISMATCH_CAL = BIT(2), }; +static bool ar9002_hw_is_cal_supported(struct ath_hw *ah, + struct ath9k_channel *chan, + enum ar9002_cal_types cal_type) +{ + bool supported = false; + switch (ah->supp_cals & cal_type) { + case IQ_MISMATCH_CAL: + /* Run IQ Mismatch for non-CCK only */ + if (!IS_CHAN_B(chan)) + supported = true; + break; + case ADC_GAIN_CAL: + case ADC_DC_CAL: + /* Run ADC Gain Cal for non-CCK & non 2GHz-HT20 only */ + if (!IS_CHAN_B(chan) && + !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan))) + supported = true; + break; + } + return supported; +} static void ar9002_hw_setup_calibration(struct ath_hw *ah, struct ath9k_cal_list *currCal) @@ -858,26 +879,32 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) { ah->supp_cals = IQ_MISMATCH_CAL; - if (AR_SREV_9160_10_OR_LATER(ah) && - !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan))) { + if (AR_SREV_9160_10_OR_LATER(ah)) ah->supp_cals |= ADC_GAIN_CAL | ADC_DC_CAL; + if (AR_SREV_9287(ah)) + ah->supp_cals &= ~ADC_GAIN_CAL; + if (ar9002_hw_is_cal_supported(ah, chan, ADC_GAIN_CAL)) { INIT_CAL(&ah->adcgain_caldata); INSERT_CAL(ah, &ah->adcgain_caldata); ath_dbg(common, ATH_DBG_CALIBRATE, - "enabling ADC Gain Calibration.\n"); + "enabling ADC Gain Calibration.\n"); + } + if (ar9002_hw_is_cal_supported(ah, chan, ADC_DC_CAL)) { INIT_CAL(&ah->adcdc_caldata); INSERT_CAL(ah, &ah->adcdc_caldata); ath_dbg(common, ATH_DBG_CALIBRATE, - "enabling ADC DC Calibration.\n"); + "enabling ADC DC Calibration.\n"); } - INIT_CAL(&ah->iq_caldata); - INSERT_CAL(ah, &ah->iq_caldata); - ath_dbg(common, ATH_DBG_CALIBRATE, - "enabling IQ Calibration.\n"); + if (ar9002_hw_is_cal_supported(ah, chan, IQ_MISMATCH_CAL)) { + INIT_CAL(&ah->iq_caldata); + INSERT_CAL(ah, &ah->iq_caldata); + ath_dbg(common, ATH_DBG_CALIBRATE, + "enabling IQ Calibration.\n"); + } ah->cal_list_curr = ah->cal_list; diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c index 399ab3bb299b..8dd8f6308502 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c @@ -415,17 +415,6 @@ static void ar9002_hw_set11n_burstduration(struct ath_hw *ah, void *ds, ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur); } -static void ar9002_hw_set11n_virtualmorefrag(struct ath_hw *ah, void *ds, - u32 vmf) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - - if (vmf) - ads->ds_ctl0 |= AR_VirtMoreFrag; - else - ads->ds_ctl0 &= ~AR_VirtMoreFrag; -} - void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, u32 size, u32 flags) { @@ -459,5 +448,4 @@ void ar9002_hw_attach_mac_ops(struct ath_hw *ah) ops->set11n_aggr_last = ar9002_hw_set11n_aggr_last; ops->clr11n_aggr = ar9002_hw_clr11n_aggr; ops->set11n_burstduration = ar9002_hw_set11n_burstduration; - ops->set11n_virtualmorefrag = ar9002_hw_set11n_virtualmorefrag; } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index 7f5de6e4448b..aebaad97b190 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -66,8 +66,8 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) /* rx/tx gain */ INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9485_common_rx_gain_1_1, - ARRAY_SIZE(ar9485_common_rx_gain_1_1), 2); + ar9485Common_wo_xlna_rx_gain_1_1, + ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1), 2); INIT_INI_ARRAY(&ah->iniModesTxGain, ar9485_modes_lowest_ob_db_tx_gain_1_1, ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1), @@ -88,66 +88,6 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) ar9485_1_1_pcie_phy_clkreq_disable_L1, ARRAY_SIZE(ar9485_1_1_pcie_phy_clkreq_disable_L1), 2); - } else if (AR_SREV_9485(ah)) { - /* mac */ - INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); - INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], - ar9485_1_0_mac_core, - ARRAY_SIZE(ar9485_1_0_mac_core), 2); - INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], - ar9485_1_0_mac_postamble, - ARRAY_SIZE(ar9485_1_0_mac_postamble), 5); - - /* bb */ - INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], ar9485_1_0, - ARRAY_SIZE(ar9485_1_0), 2); - INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], - ar9485_1_0_baseband_core, - ARRAY_SIZE(ar9485_1_0_baseband_core), 2); - INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], - ar9485_1_0_baseband_postamble, - ARRAY_SIZE(ar9485_1_0_baseband_postamble), 5); - - /* radio */ - INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0); - INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], - ar9485_1_0_radio_core, - ARRAY_SIZE(ar9485_1_0_radio_core), 2); - INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], - ar9485_1_0_radio_postamble, - ARRAY_SIZE(ar9485_1_0_radio_postamble), 2); - - /* soc */ - INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE], - ar9485_1_0_soc_preamble, - ARRAY_SIZE(ar9485_1_0_soc_preamble), 2); - INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0); - INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], NULL, 0, 0); - - /* rx/tx gain */ - INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9485Common_rx_gain_1_0, - ARRAY_SIZE(ar9485Common_rx_gain_1_0), 2); - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9485Modes_lowest_ob_db_tx_gain_1_0, - ARRAY_SIZE(ar9485Modes_lowest_ob_db_tx_gain_1_0), - 5); - - /* Load PCIE SERDES settings from INI */ - - /* Awake Setting */ - - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1, - ARRAY_SIZE(ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1), - 2); - - /* Sleep Setting */ - - INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, - ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1, - ARRAY_SIZE(ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1), - 2); } else { /* mac */ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); @@ -228,11 +168,6 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah) ar9485_modes_lowest_ob_db_tx_gain_1_1, ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1), 5); - else if (AR_SREV_9485(ah)) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9485Modes_lowest_ob_db_tx_gain_1_0, - ARRAY_SIZE(ar9485Modes_lowest_ob_db_tx_gain_1_0), - 5); else INIT_INI_ARRAY(&ah->iniModesTxGain, ar9300Modes_lowest_ob_db_tx_gain_table_2p2, @@ -245,11 +180,6 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah) ar9485Modes_high_ob_db_tx_gain_1_1, ARRAY_SIZE(ar9485Modes_high_ob_db_tx_gain_1_1), 5); - else if (AR_SREV_9485(ah)) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9485Modes_high_ob_db_tx_gain_1_0, - ARRAY_SIZE(ar9485Modes_high_ob_db_tx_gain_1_0), - 5); else INIT_INI_ARRAY(&ah->iniModesTxGain, ar9300Modes_high_ob_db_tx_gain_table_2p2, @@ -262,11 +192,6 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah) ar9485Modes_low_ob_db_tx_gain_1_1, ARRAY_SIZE(ar9485Modes_low_ob_db_tx_gain_1_1), 5); - else if (AR_SREV_9485(ah)) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9485Modes_low_ob_db_tx_gain_1_0, - ARRAY_SIZE(ar9485Modes_low_ob_db_tx_gain_1_0), - 5); else INIT_INI_ARRAY(&ah->iniModesTxGain, ar9300Modes_low_ob_db_tx_gain_table_2p2, @@ -279,11 +204,6 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah) ar9485Modes_high_power_tx_gain_1_1, ARRAY_SIZE(ar9485Modes_high_power_tx_gain_1_1), 5); - else if (AR_SREV_9485(ah)) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9485Modes_high_power_tx_gain_1_0, - ARRAY_SIZE(ar9485Modes_high_power_tx_gain_1_0), - 5); else INIT_INI_ARRAY(&ah->iniModesTxGain, ar9300Modes_high_power_tx_gain_table_2p2, @@ -300,13 +220,8 @@ static void ar9003_rx_gain_table_apply(struct ath_hw *ah) default: if (AR_SREV_9485_11(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9485_common_rx_gain_1_1, - ARRAY_SIZE(ar9485_common_rx_gain_1_1), - 2); - else if (AR_SREV_9485(ah)) - INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9485Common_rx_gain_1_0, - ARRAY_SIZE(ar9485Common_rx_gain_1_0), + ar9485Common_wo_xlna_rx_gain_1_1, + ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1), 2); else INIT_INI_ARRAY(&ah->iniModesRxGain, @@ -320,11 +235,6 @@ static void ar9003_rx_gain_table_apply(struct ath_hw *ah) ar9485Common_wo_xlna_rx_gain_1_1, ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1), 2); - else if (AR_SREV_9485(ah)) - INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9485Common_wo_xlna_rx_gain_1_0, - ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_0), - 2); else INIT_INI_ARRAY(&ah->iniModesRxGain, ar9300Common_wo_xlna_rx_gain_table_2p2, diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index 038a0cbfc6e7..724ac2464ad5 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c @@ -485,17 +485,6 @@ static void ar9003_hw_set11n_burstduration(struct ath_hw *ah, void *ds, } -static void ar9003_hw_set11n_virtualmorefrag(struct ath_hw *ah, void *ds, - u32 vmf) -{ - struct ar9003_txc *ads = (struct ar9003_txc *) ds; - - if (vmf) - ads->ctl11 |= AR_VirtMoreFrag; - else - ads->ctl11 &= ~AR_VirtMoreFrag; -} - void ar9003_hw_set_paprd_txdesc(struct ath_hw *ah, void *ds, u8 chains) { struct ar9003_txc *ads = ds; @@ -521,7 +510,6 @@ void ar9003_hw_attach_mac_ops(struct ath_hw *hw) ops->set11n_aggr_last = ar9003_hw_set11n_aggr_last; ops->clr11n_aggr = ar9003_hw_clr11n_aggr; ops->set11n_burstduration = ar9003_hw_set11n_burstduration; - ops->set11n_virtualmorefrag = ar9003_hw_set11n_virtualmorefrag; } void ath9k_hw_set_rx_bufsize(struct ath_hw *ah, u16 buf_size) diff --git a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h index 71cc0a3a29fb..f91f73e50d00 100644 --- a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h @@ -17,931 +17,6 @@ #ifndef INITVALS_9485_H #define INITVALS_9485_H -static const u32 ar9485Common_1_0[][2] = { - /* Addr allmodes */ - {0x00007010, 0x00000022}, - {0x00007020, 0x00000000}, - {0x00007034, 0x00000002}, - {0x00007038, 0x000004c2}, -}; - -static const u32 ar9485_1_0_mac_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, - {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c}, - {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38}, - {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, - {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b}, - {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, - {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a}, - {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440}, -}; - -static const u32 ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1[][2] = { - /* Addr allmodes */ - {0x00018c00, 0x10212e5e}, - {0x00018c04, 0x000801d8}, - {0x00018c08, 0x0000580c}, -}; - -static const u32 ar9485Common_wo_xlna_rx_gain_1_0[][2] = { - /* Addr allmodes */ - {0x0000a000, 0x00010000}, - {0x0000a004, 0x00030002}, - {0x0000a008, 0x00050004}, - {0x0000a00c, 0x00810080}, - {0x0000a010, 0x01800082}, - {0x0000a014, 0x01820181}, - {0x0000a018, 0x01840183}, - {0x0000a01c, 0x01880185}, - {0x0000a020, 0x018a0189}, - {0x0000a024, 0x02850284}, - {0x0000a028, 0x02890288}, - {0x0000a02c, 0x03850384}, - {0x0000a030, 0x03890388}, - {0x0000a034, 0x038b038a}, - {0x0000a038, 0x038d038c}, - {0x0000a03c, 0x03910390}, - {0x0000a040, 0x03930392}, - {0x0000a044, 0x03950394}, - {0x0000a048, 0x00000396}, - {0x0000a04c, 0x00000000}, - {0x0000a050, 0x00000000}, - {0x0000a054, 0x00000000}, - {0x0000a058, 0x00000000}, - {0x0000a05c, 0x00000000}, - {0x0000a060, 0x00000000}, - {0x0000a064, 0x00000000}, - {0x0000a068, 0x00000000}, - {0x0000a06c, 0x00000000}, - {0x0000a070, 0x00000000}, - {0x0000a074, 0x00000000}, - {0x0000a078, 0x00000000}, - {0x0000a07c, 0x00000000}, - {0x0000a080, 0x28282828}, - {0x0000a084, 0x28282828}, - {0x0000a088, 0x28282828}, - {0x0000a08c, 0x28282828}, - {0x0000a090, 0x28282828}, - {0x0000a094, 0x21212128}, - {0x0000a098, 0x171c1c1c}, - {0x0000a09c, 0x02020212}, - {0x0000a0a0, 0x00000202}, - {0x0000a0a4, 0x00000000}, - {0x0000a0a8, 0x00000000}, - {0x0000a0ac, 0x00000000}, - {0x0000a0b0, 0x00000000}, - {0x0000a0b4, 0x00000000}, - {0x0000a0b8, 0x00000000}, - {0x0000a0bc, 0x00000000}, - {0x0000a0c0, 0x001f0000}, - {0x0000a0c4, 0x111f1100}, - {0x0000a0c8, 0x111d111e}, - {0x0000a0cc, 0x111b111c}, - {0x0000a0d0, 0x22032204}, - {0x0000a0d4, 0x22012202}, - {0x0000a0d8, 0x221f2200}, - {0x0000a0dc, 0x221d221e}, - {0x0000a0e0, 0x33013302}, - {0x0000a0e4, 0x331f3300}, - {0x0000a0e8, 0x4402331e}, - {0x0000a0ec, 0x44004401}, - {0x0000a0f0, 0x441e441f}, - {0x0000a0f4, 0x55015502}, - {0x0000a0f8, 0x551f5500}, - {0x0000a0fc, 0x6602551e}, - {0x0000a100, 0x66006601}, - {0x0000a104, 0x661e661f}, - {0x0000a108, 0x7703661d}, - {0x0000a10c, 0x77017702}, - {0x0000a110, 0x00007700}, - {0x0000a114, 0x00000000}, - {0x0000a118, 0x00000000}, - {0x0000a11c, 0x00000000}, - {0x0000a120, 0x00000000}, - {0x0000a124, 0x00000000}, - {0x0000a128, 0x00000000}, - {0x0000a12c, 0x00000000}, - {0x0000a130, 0x00000000}, - {0x0000a134, 0x00000000}, - {0x0000a138, 0x00000000}, - {0x0000a13c, 0x00000000}, - {0x0000a140, 0x001f0000}, - {0x0000a144, 0x111f1100}, - {0x0000a148, 0x111d111e}, - {0x0000a14c, 0x111b111c}, - {0x0000a150, 0x22032204}, - {0x0000a154, 0x22012202}, - {0x0000a158, 0x221f2200}, - {0x0000a15c, 0x221d221e}, - {0x0000a160, 0x33013302}, - {0x0000a164, 0x331f3300}, - {0x0000a168, 0x4402331e}, - {0x0000a16c, 0x44004401}, - {0x0000a170, 0x441e441f}, - {0x0000a174, 0x55015502}, - {0x0000a178, 0x551f5500}, - {0x0000a17c, 0x6602551e}, - {0x0000a180, 0x66006601}, - {0x0000a184, 0x661e661f}, - {0x0000a188, 0x7703661d}, - {0x0000a18c, 0x77017702}, - {0x0000a190, 0x00007700}, - {0x0000a194, 0x00000000}, - {0x0000a198, 0x00000000}, - {0x0000a19c, 0x00000000}, - {0x0000a1a0, 0x00000000}, - {0x0000a1a4, 0x00000000}, - {0x0000a1a8, 0x00000000}, - {0x0000a1ac, 0x00000000}, - {0x0000a1b0, 0x00000000}, - {0x0000a1b4, 0x00000000}, - {0x0000a1b8, 0x00000000}, - {0x0000a1bc, 0x00000000}, - {0x0000a1c0, 0x00000000}, - {0x0000a1c4, 0x00000000}, - {0x0000a1c8, 0x00000000}, - {0x0000a1cc, 0x00000000}, - {0x0000a1d0, 0x00000000}, - {0x0000a1d4, 0x00000000}, - {0x0000a1d8, 0x00000000}, - {0x0000a1dc, 0x00000000}, - {0x0000a1e0, 0x00000000}, - {0x0000a1e4, 0x00000000}, - {0x0000a1e8, 0x00000000}, - {0x0000a1ec, 0x00000000}, - {0x0000a1f0, 0x00000396}, - {0x0000a1f4, 0x00000396}, - {0x0000a1f8, 0x00000396}, - {0x0000a1fc, 0x00000296}, -}; - -static const u32 ar9485Modes_high_power_tx_gain_1_0[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, - {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, - {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, - {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, - {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200}, - {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202}, - {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400}, - {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402}, - {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404}, - {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603}, - {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605}, - {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03}, - {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04}, - {0x0000a530, 0x48023ec6, 0x48023ec6, 0x2e000a20, 0x2e000a20}, - {0x0000a534, 0x4d023f01, 0x4d023f01, 0x34000e20, 0x34000e20}, - {0x0000a538, 0x53023f4b, 0x53023f4b, 0x38000e22, 0x38000e22}, - {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x3c000e24, 0x3c000e24}, - {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x40000e26, 0x40000e26}, - {0x0000a544, 0x6502feca, 0x6502feca, 0x43001640, 0x43001640}, - {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x46001660, 0x46001660}, - {0x0000a54c, 0x7203feca, 0x7203feca, 0x49001861, 0x49001861}, - {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x4c001a81, 0x4c001a81}, - {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x4f001a83, 0x4f001a83}, - {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x54001c85, 0x54001c85}, - {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x58001ce5, 0x58001ce5}, - {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5b001ce9, 0x5b001ce9}, - {0x0000a564, 0x960fffcb, 0x960fffcb, 0x60001eeb, 0x60001eeb}, - {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x00016044, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db}, -}; - -static const u32 ar9485_1_0[][2] = { - /* Addr allmodes */ - {0x0000a580, 0x00000000}, - {0x0000a584, 0x00000000}, - {0x0000a588, 0x00000000}, - {0x0000a58c, 0x00000000}, - {0x0000a590, 0x00000000}, - {0x0000a594, 0x00000000}, - {0x0000a598, 0x00000000}, - {0x0000a59c, 0x00000000}, - {0x0000a5a0, 0x00000000}, - {0x0000a5a4, 0x00000000}, - {0x0000a5a8, 0x00000000}, - {0x0000a5ac, 0x00000000}, - {0x0000a5b0, 0x00000000}, - {0x0000a5b4, 0x00000000}, - {0x0000a5b8, 0x00000000}, - {0x0000a5bc, 0x00000000}, -}; - -static const u32 ar9485_1_0_radio_core[][2] = { - /* Addr allmodes */ - {0x00016000, 0x36db6db6}, - {0x00016004, 0x6db6db40}, - {0x00016008, 0x73800000}, - {0x0001600c, 0x00000000}, - {0x00016040, 0x7f80fff8}, - {0x00016048, 0x6c92426e}, - {0x0001604c, 0x000f0278}, - {0x00016050, 0x6db6db6c}, - {0x00016054, 0x6db60000}, - {0x00016080, 0x00080000}, - {0x00016084, 0x0e48048c}, - {0x00016088, 0x14214514}, - {0x0001608c, 0x119f081e}, - {0x00016090, 0x24926490}, - {0x00016098, 0xd28b3330}, - {0x000160a0, 0xc2108ffe}, - {0x000160a4, 0x812fc370}, - {0x000160a8, 0x423c8000}, - {0x000160b4, 0x92480040}, - {0x000160c0, 0x006db6db}, - {0x000160c4, 0x0186db60}, - {0x000160c8, 0x6db6db6c}, - {0x000160cc, 0x6de6fbe0}, - {0x000160d0, 0xf7dfcf3c}, - {0x00016100, 0x04cb0001}, - {0x00016104, 0xfff80015}, - {0x00016108, 0x00080010}, - {0x00016144, 0x01884080}, - {0x00016148, 0x00008040}, - {0x00016180, 0x08453333}, - {0x00016184, 0x18e82f01}, - {0x00016188, 0x00000000}, - {0x0001618c, 0x00000000}, - {0x00016240, 0x08400000}, - {0x00016244, 0x1bf90f00}, - {0x00016248, 0x00000000}, - {0x0001624c, 0x00000000}, - {0x00016280, 0x01000015}, - {0x00016284, 0x00d30000}, - {0x00016288, 0x00318000}, - {0x0001628c, 0x50000000}, - {0x00016290, 0x4b96210f}, - {0x00016380, 0x00000000}, - {0x00016384, 0x00000000}, - {0x00016388, 0x00800700}, - {0x0001638c, 0x00800700}, - {0x00016390, 0x00800700}, - {0x00016394, 0x00000000}, - {0x00016398, 0x00000000}, - {0x0001639c, 0x00000000}, - {0x000163a0, 0x00000001}, - {0x000163a4, 0x00000001}, - {0x000163a8, 0x00000000}, - {0x000163ac, 0x00000000}, - {0x000163b0, 0x00000000}, - {0x000163b4, 0x00000000}, - {0x000163b8, 0x00000000}, - {0x000163bc, 0x00000000}, - {0x000163c0, 0x000000a0}, - {0x000163c4, 0x000c0000}, - {0x000163c8, 0x14021402}, - {0x000163cc, 0x00001402}, - {0x000163d0, 0x00000000}, - {0x000163d4, 0x00000000}, - {0x00016c40, 0x1319c178}, - {0x00016c44, 0x10000000}, -}; - -static const u32 ar9485Modes_lowest_ob_db_tx_gain_1_0[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, - {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, - {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, - {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, - {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200}, - {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202}, - {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400}, - {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402}, - {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404}, - {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603}, - {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605}, - {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03}, - {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04}, - {0x0000a530, 0x48023ec6, 0x48023ec6, 0x2e000a20, 0x2e000a20}, - {0x0000a534, 0x4d023f01, 0x4d023f01, 0x34000e20, 0x34000e20}, - {0x0000a538, 0x53023f4b, 0x53023f4b, 0x38000e22, 0x38000e22}, - {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x3c000e24, 0x3c000e24}, - {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x40000e26, 0x40000e26}, - {0x0000a544, 0x6502feca, 0x6502feca, 0x43001640, 0x43001640}, - {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x46001660, 0x46001660}, - {0x0000a54c, 0x7203feca, 0x7203feca, 0x49001861, 0x49001861}, - {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x4c001a81, 0x4c001a81}, - {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x4f001a83, 0x4f001a83}, - {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x54001c85, 0x54001c85}, - {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x58001ce5, 0x58001ce5}, - {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5b001ce9, 0x5b001ce9}, - {0x0000a564, 0x960fffcb, 0x960fffcb, 0x60001eeb, 0x60001eeb}, - {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x00016044, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db}, -}; - -static const u32 ar9485_1_0_baseband_core[][2] = { - /* Addr allmodes */ - {0x00009800, 0xafe68e30}, - {0x00009804, 0xfd14e000}, - {0x00009808, 0x9c0a8f6b}, - {0x0000980c, 0x04800000}, - {0x00009814, 0x9280c00a}, - {0x00009818, 0x00000000}, - {0x0000981c, 0x00020028}, - {0x00009834, 0x5f3ca3de}, - {0x00009838, 0x0108ecff}, - {0x0000983c, 0x14750600}, - {0x00009880, 0x201fff00}, - {0x00009884, 0x00001042}, - {0x000098a4, 0x00200400}, - {0x000098b0, 0x52440bbe}, - {0x000098bc, 0x00000002}, - {0x000098d0, 0x004b6a8e}, - {0x000098d4, 0x00000820}, - {0x000098dc, 0x00000000}, - {0x000098f0, 0x00000000}, - {0x000098f4, 0x00000000}, - {0x00009c04, 0x00000000}, - {0x00009c08, 0x03200000}, - {0x00009c0c, 0x00000000}, - {0x00009c10, 0x00000000}, - {0x00009c14, 0x00046384}, - {0x00009c18, 0x05b6b440}, - {0x00009c1c, 0x00b6b440}, - {0x00009d00, 0xc080a333}, - {0x00009d04, 0x40206c10}, - {0x00009d08, 0x009c4060}, - {0x00009d0c, 0x1883800a}, - {0x00009d10, 0x01834061}, - {0x00009d14, 0x00c00400}, - {0x00009d18, 0x00000000}, - {0x00009d1c, 0x00000000}, - {0x00009e08, 0x0038233c}, - {0x00009e24, 0x990bb515}, - {0x00009e28, 0x0a6f0000}, - {0x00009e30, 0x06336f77}, - {0x00009e34, 0x6af6532f}, - {0x00009e38, 0x0cc80c00}, - {0x00009e40, 0x0d261820}, - {0x00009e4c, 0x00001004}, - {0x00009e50, 0x00ff03f1}, - {0x00009fc0, 0x80be4788}, - {0x00009fc4, 0x0001efb5}, - {0x00009fcc, 0x40000014}, - {0x0000a20c, 0x00000000}, - {0x0000a210, 0x00000000}, - {0x0000a220, 0x00000000}, - {0x0000a224, 0x00000000}, - {0x0000a228, 0x10002310}, - {0x0000a23c, 0x00000000}, - {0x0000a244, 0x0c000000}, - {0x0000a2a0, 0x00000001}, - {0x0000a2c0, 0x00000001}, - {0x0000a2c8, 0x00000000}, - {0x0000a2cc, 0x18c43433}, - {0x0000a2d4, 0x00000000}, - {0x0000a2dc, 0x00000000}, - {0x0000a2e0, 0x00000000}, - {0x0000a2e4, 0x00000000}, - {0x0000a2e8, 0x00000000}, - {0x0000a2ec, 0x00000000}, - {0x0000a2f0, 0x00000000}, - {0x0000a2f4, 0x00000000}, - {0x0000a2f8, 0x00000000}, - {0x0000a344, 0x00000000}, - {0x0000a34c, 0x00000000}, - {0x0000a350, 0x0000a000}, - {0x0000a364, 0x00000000}, - {0x0000a370, 0x00000000}, - {0x0000a390, 0x00000001}, - {0x0000a394, 0x00000444}, - {0x0000a398, 0x001f0e0f}, - {0x0000a39c, 0x0075393f}, - {0x0000a3a0, 0xb79f6427}, - {0x0000a3a4, 0x00000000}, - {0x0000a3a8, 0xaaaaaaaa}, - {0x0000a3ac, 0x3c466478}, - {0x0000a3c0, 0x20202020}, - {0x0000a3c4, 0x22222220}, - {0x0000a3c8, 0x20200020}, - {0x0000a3cc, 0x20202020}, - {0x0000a3d0, 0x20202020}, - {0x0000a3d4, 0x20202020}, - {0x0000a3d8, 0x20202020}, - {0x0000a3dc, 0x20202020}, - {0x0000a3e0, 0x20202020}, - {0x0000a3e4, 0x20202020}, - {0x0000a3e8, 0x20202020}, - {0x0000a3ec, 0x20202020}, - {0x0000a3f0, 0x00000000}, - {0x0000a3f4, 0x00000006}, - {0x0000a3f8, 0x0cdbd380}, - {0x0000a3fc, 0x000f0f01}, - {0x0000a400, 0x8fa91f01}, - {0x0000a404, 0x00000000}, - {0x0000a408, 0x0e79e5c6}, - {0x0000a40c, 0x00820820}, - {0x0000a414, 0x1ce739ce}, - {0x0000a418, 0x2d0011ce}, - {0x0000a41c, 0x1ce739ce}, - {0x0000a420, 0x000001ce}, - {0x0000a424, 0x1ce739ce}, - {0x0000a428, 0x000001ce}, - {0x0000a42c, 0x1ce739ce}, - {0x0000a430, 0x1ce739ce}, - {0x0000a434, 0x00000000}, - {0x0000a438, 0x00001801}, - {0x0000a43c, 0x00000000}, - {0x0000a440, 0x00000000}, - {0x0000a444, 0x00000000}, - {0x0000a448, 0x04000000}, - {0x0000a44c, 0x00000001}, - {0x0000a450, 0x00010000}, - {0x0000a458, 0x00000000}, - {0x0000a5c4, 0x3fad9d74}, - {0x0000a5c8, 0x0048060a}, - {0x0000a5cc, 0x00000637}, - {0x0000a760, 0x03020100}, - {0x0000a764, 0x09080504}, - {0x0000a768, 0x0d0c0b0a}, - {0x0000a76c, 0x13121110}, - {0x0000a770, 0x31301514}, - {0x0000a774, 0x35343332}, - {0x0000a778, 0x00000036}, - {0x0000a780, 0x00000838}, - {0x0000a7c0, 0x00000000}, - {0x0000a7c4, 0xfffffffc}, - {0x0000a7c8, 0x00000000}, - {0x0000a7cc, 0x00000000}, - {0x0000a7d0, 0x00000000}, - {0x0000a7d4, 0x00000004}, - {0x0000a7dc, 0x00000001}, -}; - -static const u32 ar9485Modes_high_ob_db_tx_gain_1_0[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, - {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, - {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, - {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, - {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200}, - {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202}, - {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400}, - {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402}, - {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404}, - {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603}, - {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605}, - {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03}, - {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04}, - {0x0000a530, 0x48023ec6, 0x48023ec6, 0x2e000a20, 0x2e000a20}, - {0x0000a534, 0x4d023f01, 0x4d023f01, 0x34000e20, 0x34000e20}, - {0x0000a538, 0x53023f4b, 0x53023f4b, 0x38000e22, 0x38000e22}, - {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x3c000e24, 0x3c000e24}, - {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x40000e26, 0x40000e26}, - {0x0000a544, 0x6502feca, 0x6502feca, 0x43001640, 0x43001640}, - {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x46001660, 0x46001660}, - {0x0000a54c, 0x7203feca, 0x7203feca, 0x49001861, 0x49001861}, - {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x4c001a81, 0x4c001a81}, - {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x4f001a83, 0x4f001a83}, - {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x54001c85, 0x54001c85}, - {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x58001ce5, 0x58001ce5}, - {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5b001ce9, 0x5b001ce9}, - {0x0000a564, 0x960fffcb, 0x960fffcb, 0x60001eeb, 0x60001eeb}, - {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x00016044, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db}, -}; - -static const u32 ar9485Common_rx_gain_1_0[][2] = { - /* Addr allmodes */ - {0x0000a000, 0x00010000}, - {0x0000a004, 0x00030002}, - {0x0000a008, 0x00050004}, - {0x0000a00c, 0x00810080}, - {0x0000a010, 0x01800082}, - {0x0000a014, 0x01820181}, - {0x0000a018, 0x01840183}, - {0x0000a01c, 0x01880185}, - {0x0000a020, 0x018a0189}, - {0x0000a024, 0x02850284}, - {0x0000a028, 0x02890288}, - {0x0000a02c, 0x03850384}, - {0x0000a030, 0x03890388}, - {0x0000a034, 0x038b038a}, - {0x0000a038, 0x038d038c}, - {0x0000a03c, 0x03910390}, - {0x0000a040, 0x03930392}, - {0x0000a044, 0x03950394}, - {0x0000a048, 0x00000396}, - {0x0000a04c, 0x00000000}, - {0x0000a050, 0x00000000}, - {0x0000a054, 0x00000000}, - {0x0000a058, 0x00000000}, - {0x0000a05c, 0x00000000}, - {0x0000a060, 0x00000000}, - {0x0000a064, 0x00000000}, - {0x0000a068, 0x00000000}, - {0x0000a06c, 0x00000000}, - {0x0000a070, 0x00000000}, - {0x0000a074, 0x00000000}, - {0x0000a078, 0x00000000}, - {0x0000a07c, 0x00000000}, - {0x0000a080, 0x28282828}, - {0x0000a084, 0x28282828}, - {0x0000a088, 0x28282828}, - {0x0000a08c, 0x28282828}, - {0x0000a090, 0x28282828}, - {0x0000a094, 0x21212128}, - {0x0000a098, 0x171c1c1c}, - {0x0000a09c, 0x02020212}, - {0x0000a0a0, 0x00000202}, - {0x0000a0a4, 0x00000000}, - {0x0000a0a8, 0x00000000}, - {0x0000a0ac, 0x00000000}, - {0x0000a0b0, 0x00000000}, - {0x0000a0b4, 0x00000000}, - {0x0000a0b8, 0x00000000}, - {0x0000a0bc, 0x00000000}, - {0x0000a0c0, 0x001f0000}, - {0x0000a0c4, 0x111f1100}, - {0x0000a0c8, 0x111d111e}, - {0x0000a0cc, 0x111b111c}, - {0x0000a0d0, 0x22032204}, - {0x0000a0d4, 0x22012202}, - {0x0000a0d8, 0x221f2200}, - {0x0000a0dc, 0x221d221e}, - {0x0000a0e0, 0x33013302}, - {0x0000a0e4, 0x331f3300}, - {0x0000a0e8, 0x4402331e}, - {0x0000a0ec, 0x44004401}, - {0x0000a0f0, 0x441e441f}, - {0x0000a0f4, 0x55015502}, - {0x0000a0f8, 0x551f5500}, - {0x0000a0fc, 0x6602551e}, - {0x0000a100, 0x66006601}, - {0x0000a104, 0x661e661f}, - {0x0000a108, 0x7703661d}, - {0x0000a10c, 0x77017702}, - {0x0000a110, 0x00007700}, - {0x0000a114, 0x00000000}, - {0x0000a118, 0x00000000}, - {0x0000a11c, 0x00000000}, - {0x0000a120, 0x00000000}, - {0x0000a124, 0x00000000}, - {0x0000a128, 0x00000000}, - {0x0000a12c, 0x00000000}, - {0x0000a130, 0x00000000}, - {0x0000a134, 0x00000000}, - {0x0000a138, 0x00000000}, - {0x0000a13c, 0x00000000}, - {0x0000a140, 0x001f0000}, - {0x0000a144, 0x111f1100}, - {0x0000a148, 0x111d111e}, - {0x0000a14c, 0x111b111c}, - {0x0000a150, 0x22032204}, - {0x0000a154, 0x22012202}, - {0x0000a158, 0x221f2200}, - {0x0000a15c, 0x221d221e}, - {0x0000a160, 0x33013302}, - {0x0000a164, 0x331f3300}, - {0x0000a168, 0x4402331e}, - {0x0000a16c, 0x44004401}, - {0x0000a170, 0x441e441f}, - {0x0000a174, 0x55015502}, - {0x0000a178, 0x551f5500}, - {0x0000a17c, 0x6602551e}, - {0x0000a180, 0x66006601}, - {0x0000a184, 0x661e661f}, - {0x0000a188, 0x7703661d}, - {0x0000a18c, 0x77017702}, - {0x0000a190, 0x00007700}, - {0x0000a194, 0x00000000}, - {0x0000a198, 0x00000000}, - {0x0000a19c, 0x00000000}, - {0x0000a1a0, 0x00000000}, - {0x0000a1a4, 0x00000000}, - {0x0000a1a8, 0x00000000}, - {0x0000a1ac, 0x00000000}, - {0x0000a1b0, 0x00000000}, - {0x0000a1b4, 0x00000000}, - {0x0000a1b8, 0x00000000}, - {0x0000a1bc, 0x00000000}, - {0x0000a1c0, 0x00000000}, - {0x0000a1c4, 0x00000000}, - {0x0000a1c8, 0x00000000}, - {0x0000a1cc, 0x00000000}, - {0x0000a1d0, 0x00000000}, - {0x0000a1d4, 0x00000000}, - {0x0000a1d8, 0x00000000}, - {0x0000a1dc, 0x00000000}, - {0x0000a1e0, 0x00000000}, - {0x0000a1e4, 0x00000000}, - {0x0000a1e8, 0x00000000}, - {0x0000a1ec, 0x00000000}, - {0x0000a1f0, 0x00000396}, - {0x0000a1f4, 0x00000396}, - {0x0000a1f8, 0x00000396}, - {0x0000a1fc, 0x00000296}, -}; - -static const u32 ar9485_1_0_pcie_phy_pll_on_clkreq_enable_L1[][2] = { - /* Addr allmodes */ - {0x00018c00, 0x10252e5e}, - {0x00018c04, 0x000801d8}, - {0x00018c08, 0x0000580c}, -}; - -static const u32 ar9485_1_0_pcie_phy_clkreq_enable_L1[][2] = { - /* Addr allmodes */ - {0x00018c00, 0x10253e5e}, - {0x00018c04, 0x000801d8}, - {0x00018c08, 0x0000580c}, -}; - -static const u32 ar9485_1_0_soc_preamble[][2] = { - /* Addr allmodes */ - {0x00004090, 0x00aa10aa}, - {0x000040a4, 0x00a0c9c9}, - {0x00007048, 0x00000004}, -}; - -static const u32 ar9485_fast_clock_1_0_baseband_postamble[][3] = { - /* Addr 5G_HT20 5G_HT40 */ - {0x00009e00, 0x03721821, 0x03721821}, - {0x0000a230, 0x0000400b, 0x00004016}, - {0x0000a254, 0x00000898, 0x00001130}, -}; - -static const u32 ar9485_1_0_baseband_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a8005}, - {0x00009820, 0x206a002e, 0x206a002e, 0x206a002e, 0x206a002e}, - {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, - {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, - {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, - {0x00009830, 0x0000059c, 0x0000059c, 0x0000059c, 0x0000059c}, - {0x00009c00, 0x00000044, 0x00000044, 0x00000044, 0x00000044}, - {0x00009e00, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0}, - {0x00009e04, 0x00182020, 0x00182020, 0x00182020, 0x00182020}, - {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2}, - {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec80d2e, 0x7ec80d2e}, - {0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e}, - {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, - {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, - {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, - {0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946222, 0xcf946222}, - {0x00009e44, 0x02321e27, 0x02321e27, 0x02282324, 0x02282324}, - {0x00009e48, 0x5030201a, 0x5030201a, 0x50302010, 0x50302010}, - {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, - {0x0000a204, 0x01303fc0, 0x01303fc4, 0x01303fc4, 0x01303fc0}, - {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, - {0x0000a230, 0x0000400a, 0x00004014, 0x00004016, 0x0000400b}, - {0x0000a234, 0x10000fff, 0x10000fff, 0x10000fff, 0x10000fff}, - {0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018}, - {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, - {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, - {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002}, - {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e}, - {0x0000a260, 0x3a021501, 0x3a021501, 0x3a021501, 0x3a021501}, - {0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, - {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b}, - {0x0000a284, 0x00000000, 0x00000000, 0x000002a0, 0x000002a0}, - {0x0000a288, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a28c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, - {0x0000a2d0, 0x00071981, 0x00071981, 0x00071981, 0x00071982}, - {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a}, - {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000be04, 0x00802020, 0x00802020, 0x00802020, 0x00802020}, - {0x0000be18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -}; - -static const u32 ar9485Modes_low_ob_db_tx_gain_1_0[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, - {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, - {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, - {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, - {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200}, - {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202}, - {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400}, - {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402}, - {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404}, - {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603}, - {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605}, - {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03}, - {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04}, - {0x0000a530, 0x48023ec6, 0x48023ec6, 0x2e000a20, 0x2e000a20}, - {0x0000a534, 0x4d023f01, 0x4d023f01, 0x34000e20, 0x34000e20}, - {0x0000a538, 0x53023f4b, 0x53023f4b, 0x38000e22, 0x38000e22}, - {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x3c000e24, 0x3c000e24}, - {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x40000e26, 0x40000e26}, - {0x0000a544, 0x6502feca, 0x6502feca, 0x43001640, 0x43001640}, - {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x46001660, 0x46001660}, - {0x0000a54c, 0x7203feca, 0x7203feca, 0x49001861, 0x49001861}, - {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x4c001a81, 0x4c001a81}, - {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x4f001a83, 0x4f001a83}, - {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x54001c85, 0x54001c85}, - {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x58001ce5, 0x58001ce5}, - {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5b001ce9, 0x5b001ce9}, - {0x0000a564, 0x960fffcb, 0x960fffcb, 0x60001eeb, 0x60001eeb}, - {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x00016044, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db}, -}; - -static const u32 ar9485_1_0_pcie_phy_clkreq_disable_L1[][2] = { - /* Addr allmodes */ - {0x00018c00, 0x10213e5e}, - {0x00018c04, 0x000801d8}, - {0x00018c08, 0x0000580c}, -}; - -static const u32 ar9485_1_0_radio_postamble[][2] = { - /* Addr allmodes */ - {0x0001609c, 0x0b283f31}, - {0x000160ac, 0x24611800}, - {0x000160b0, 0x03284f3e}, - {0x0001610c, 0x00170000}, - {0x00016140, 0x10804008}, -}; - -static const u32 ar9485_1_0_mac_core[][2] = { - /* Addr allmodes */ - {0x00000008, 0x00000000}, - {0x00000030, 0x00020085}, - {0x00000034, 0x00000005}, - {0x00000040, 0x00000000}, - {0x00000044, 0x00000000}, - {0x00000048, 0x00000008}, - {0x0000004c, 0x00000010}, - {0x00000050, 0x00000000}, - {0x00001040, 0x002ffc0f}, - {0x00001044, 0x002ffc0f}, - {0x00001048, 0x002ffc0f}, - {0x0000104c, 0x002ffc0f}, - {0x00001050, 0x002ffc0f}, - {0x00001054, 0x002ffc0f}, - {0x00001058, 0x002ffc0f}, - {0x0000105c, 0x002ffc0f}, - {0x00001060, 0x002ffc0f}, - {0x00001064, 0x002ffc0f}, - {0x000010f0, 0x00000100}, - {0x00001270, 0x00000000}, - {0x000012b0, 0x00000000}, - {0x000012f0, 0x00000000}, - {0x0000143c, 0x00000000}, - {0x0000147c, 0x00000000}, - {0x00008000, 0x00000000}, - {0x00008004, 0x00000000}, - {0x00008008, 0x00000000}, - {0x0000800c, 0x00000000}, - {0x00008018, 0x00000000}, - {0x00008020, 0x00000000}, - {0x00008038, 0x00000000}, - {0x0000803c, 0x00000000}, - {0x00008040, 0x00000000}, - {0x00008044, 0x00000000}, - {0x00008048, 0x00000000}, - {0x0000804c, 0xffffffff}, - {0x00008054, 0x00000000}, - {0x00008058, 0x00000000}, - {0x0000805c, 0x000fc78f}, - {0x00008060, 0x0000000f}, - {0x00008064, 0x00000000}, - {0x00008070, 0x00000310}, - {0x00008074, 0x00000020}, - {0x00008078, 0x00000000}, - {0x0000809c, 0x0000000f}, - {0x000080a0, 0x00000000}, - {0x000080a4, 0x02ff0000}, - {0x000080a8, 0x0e070605}, - {0x000080ac, 0x0000000d}, - {0x000080b0, 0x00000000}, - {0x000080b4, 0x00000000}, - {0x000080b8, 0x00000000}, - {0x000080bc, 0x00000000}, - {0x000080c0, 0x2a800000}, - {0x000080c4, 0x06900168}, - {0x000080c8, 0x13881c20}, - {0x000080cc, 0x01f40000}, - {0x000080d0, 0x00252500}, - {0x000080d4, 0x00a00000}, - {0x000080d8, 0x00400000}, - {0x000080dc, 0x00000000}, - {0x000080e0, 0xffffffff}, - {0x000080e4, 0x0000ffff}, - {0x000080e8, 0x3f3f3f3f}, - {0x000080ec, 0x00000000}, - {0x000080f0, 0x00000000}, - {0x000080f4, 0x00000000}, - {0x000080fc, 0x00020000}, - {0x00008100, 0x00000000}, - {0x00008108, 0x00000052}, - {0x0000810c, 0x00000000}, - {0x00008110, 0x00000000}, - {0x00008114, 0x000007ff}, - {0x00008118, 0x000000aa}, - {0x0000811c, 0x00003210}, - {0x00008124, 0x00000000}, - {0x00008128, 0x00000000}, - {0x0000812c, 0x00000000}, - {0x00008130, 0x00000000}, - {0x00008134, 0x00000000}, - {0x00008138, 0x00000000}, - {0x0000813c, 0x0000ffff}, - {0x00008144, 0xffffffff}, - {0x00008168, 0x00000000}, - {0x0000816c, 0x00000000}, - {0x00008170, 0x18486200}, - {0x00008174, 0x33332210}, - {0x00008178, 0x00000000}, - {0x0000817c, 0x00020000}, - {0x000081c0, 0x00000000}, - {0x000081c4, 0x33332210}, - {0x000081c8, 0x00000000}, - {0x000081cc, 0x00000000}, - {0x000081d4, 0x00000000}, - {0x000081ec, 0x00000000}, - {0x000081f0, 0x00000000}, - {0x000081f4, 0x00000000}, - {0x000081f8, 0x00000000}, - {0x000081fc, 0x00000000}, - {0x00008240, 0x00100000}, - {0x00008244, 0x0010f400}, - {0x00008248, 0x00000800}, - {0x0000824c, 0x0001e800}, - {0x00008250, 0x00000000}, - {0x00008254, 0x00000000}, - {0x00008258, 0x00000000}, - {0x0000825c, 0x40000000}, - {0x00008260, 0x00080922}, - {0x00008264, 0x9ca00010}, - {0x00008268, 0xffffffff}, - {0x0000826c, 0x0000ffff}, - {0x00008270, 0x00000000}, - {0x00008274, 0x40000000}, - {0x00008278, 0x003e4180}, - {0x0000827c, 0x00000004}, - {0x00008284, 0x0000002c}, - {0x00008288, 0x0000002c}, - {0x0000828c, 0x000000ff}, - {0x00008294, 0x00000000}, - {0x00008298, 0x00000000}, - {0x0000829c, 0x00000000}, - {0x00008300, 0x00000140}, - {0x00008314, 0x00000000}, - {0x0000831c, 0x0000010d}, - {0x00008328, 0x00000000}, - {0x0000832c, 0x00000007}, - {0x00008330, 0x00000302}, - {0x00008334, 0x00000700}, - {0x00008338, 0x00ff0000}, - {0x0000833c, 0x02400000}, - {0x00008340, 0x000107ff}, - {0x00008344, 0xa248105b}, - {0x00008348, 0x008f0000}, - {0x0000835c, 0x00000000}, - {0x00008360, 0xffffffff}, - {0x00008364, 0xffffffff}, - {0x00008368, 0x00000000}, - {0x00008370, 0x00000000}, - {0x00008374, 0x000000ff}, - {0x00008378, 0x00000000}, - {0x0000837c, 0x00000000}, - {0x00008380, 0xffffffff}, - {0x00008384, 0xffffffff}, - {0x00008390, 0xffffffff}, - {0x00008394, 0xffffffff}, - {0x00008398, 0x00000000}, - {0x0000839c, 0x00000000}, - {0x000083a0, 0x00000000}, - {0x000083a4, 0x0000fa14}, - {0x000083a8, 0x000f0c00}, - {0x000083ac, 0x33332210}, - {0x000083b0, 0x33332210}, - {0x000083b4, 0x33332210}, - {0x000083b8, 0x33332210}, - {0x000083bc, 0x00000000}, - {0x000083c0, 0x00000000}, - {0x000083c4, 0x00000000}, - {0x000083c8, 0x00000000}, - {0x000083cc, 0x00000200}, - {0x000083d0, 0x000301ff}, -}; - static const u32 ar9485_1_1_mac_core[][2] = { /* Addr allmodes */ {0x00000008, 0x00000000}, diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 099bd4183ad0..38835bc324b2 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -120,13 +120,11 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, /* RX / TX */ /***********/ -#define ATH_MAX_ANTENNA 3 #define ATH_RXBUF 512 #define ATH_TXBUF 512 #define ATH_TXBUF_RESERVE 5 #define ATH_MAX_QDEPTH (ATH_TXBUF / 4 - ATH_TXBUF_RESERVE) #define ATH_TXMAXTRY 13 -#define ATH_MGT_TXMAXTRY 4 #define TID_TO_WME_AC(_tid) \ ((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \ @@ -346,11 +344,9 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid struct ath_vif { int av_bslot; - bool is_bslot_active; + bool is_bslot_active, primary_sta_vif; __le64 tsf_adjust; /* TSF adjustment for staggered beacons */ - enum nl80211_iftype av_opmode; struct ath_buf *av_bcbuf; - u8 bssid[ETH_ALEN]; /* current BSSID from config_interface */ }; /*******************/ @@ -362,7 +358,7 @@ struct ath_vif { * number of BSSIDs) if a given beacon does not go out even after waiting this * number of beacon intervals, the game's up. */ -#define BSTUCK_THRESH (9 * ATH_BCBUF) +#define BSTUCK_THRESH 9 #define ATH_BCBUF 4 #define ATH_DEFAULT_BINTVAL 100 /* TU */ #define ATH_DEFAULT_BMISS_LIMIT 10 @@ -386,7 +382,7 @@ struct ath_beacon { u32 beaconq; u32 bmisscnt; u32 ast_be_xmit; - u64 bc_tstamp; + u32 bc_tstamp; struct ieee80211_vif *bslot[ATH_BCBUF]; int slottime; int slotupdate; @@ -401,6 +397,7 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif); int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif); void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp); int ath_beaconq_config(struct ath_softc *sc); +void ath_set_beacon(struct ath_softc *sc); void ath9k_set_beaconing_status(struct ath_softc *sc, bool status); /*******/ @@ -550,6 +547,7 @@ struct ath_ant_comb { #define SC_OP_BT_SCAN BIT(13) #define SC_OP_ANI_RUN BIT(14) #define SC_OP_ENABLE_APM BIT(15) +#define SC_OP_PRIM_STA_VIF BIT(16) /* Powersave flags */ #define PS_WAIT_FOR_BEACON BIT(0) @@ -688,8 +686,6 @@ void ath9k_ps_restore(struct ath_softc *sc); u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate); -void ath9k_set_bssid_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif); - void ath_start_rfkill_poll(struct ath_softc *sc); extern void ath9k_rfkill_poll_state(struct ieee80211_hw *hw); void ath9k_calculate_iter_data(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 6d2a545fc35e..eccb0ec87adb 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -57,8 +57,8 @@ int ath_beaconq_config(struct ath_softc *sc) /* * Associates the beacon frame buffer with a transmit descriptor. Will set - * up all required antenna switch parameters, rate codes, and channel flags. - * Beacons are always sent out at the lowest rate, and are not retried. + * up rate codes, and channel flags. Beacons are always sent out at the + * lowest rate, and are not retried. */ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, struct ath_buf *bf, int rateidx) @@ -68,7 +68,7 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, struct ath_common *common = ath9k_hw_common(ah); struct ath_desc *ds; struct ath9k_11n_rate_series series[4]; - int flags, antenna, ctsrate = 0, ctsduration = 0; + int flags, ctsrate = 0, ctsduration = 0; struct ieee80211_supported_band *sband; u8 rate = 0; @@ -76,12 +76,6 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, flags = ATH9K_TXDESC_NOACK; ds->ds_link = 0; - /* - * Switch antenna every beacon. - * Should only switch every beacon period, not for every SWBA - * XXX assumes two antennae - */ - antenna = ((sc->beacon.ast_be_xmit / sc->nbcnvifs) & 1 ? 2 : 1); sband = &sc->sbands[common->hw->conf.channel->band]; rate = sband->bitrates[rateidx].hw_value; @@ -278,7 +272,7 @@ int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif) return -ENOMEM; tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; - sc->beacon.bc_tstamp = le64_to_cpu(tstamp); + sc->beacon.bc_tstamp = (u32) le64_to_cpu(tstamp); /* Calculate a TSF adjustment factor required for staggered beacons. */ if (avp->av_bslot > 0) { u64 tsfadjust; @@ -294,8 +288,8 @@ int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif) * adjustment. Other slots are adjusted to get the timestamp * close to the TBTT for the BSS. */ - tsfadjust = intval * avp->av_bslot / ATH_BCBUF; - avp->tsf_adjust = cpu_to_le64(TU_TO_USEC(tsfadjust)); + tsfadjust = TU_TO_USEC(intval * avp->av_bslot) / ATH_BCBUF; + avp->tsf_adjust = cpu_to_le64(tsfadjust); ath_dbg(common, ATH_DBG_BEACON, "stagger beacons, bslot %d intval %u tsfadjust %llu\n", @@ -329,6 +323,7 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp) if (avp->av_bslot != -1) { sc->beacon.bslot[avp->av_bslot] = NULL; sc->nbcnvifs--; + avp->av_bslot = -1; } bf = avp->av_bcbuf; @@ -369,12 +364,13 @@ void ath_beacon_tasklet(unsigned long data) if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0) { sc->beacon.bmisscnt++; - if (sc->beacon.bmisscnt < BSTUCK_THRESH) { + if (sc->beacon.bmisscnt < BSTUCK_THRESH * sc->nbcnvifs) { ath_dbg(common, ATH_DBG_BSTUCK, "missed %u consecutive beacons\n", sc->beacon.bmisscnt); ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq); - ath9k_hw_bstuck_nfcal(ah); + if (sc->beacon.bmisscnt > 3) + ath9k_hw_bstuck_nfcal(ah); } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) { ath_dbg(common, ATH_DBG_BSTUCK, "beacon is officially stuck\n"); @@ -385,13 +381,6 @@ void ath_beacon_tasklet(unsigned long data) return; } - if (sc->beacon.bmisscnt != 0) { - ath_dbg(common, ATH_DBG_BSTUCK, - "resume beacon xmit after %u misses\n", - sc->beacon.bmisscnt); - sc->beacon.bmisscnt = 0; - } - /* * Generate beacon frames. we are sending frames * staggered so calculate the slot for this frame based @@ -401,21 +390,14 @@ void ath_beacon_tasklet(unsigned long data) intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL; tsf = ath9k_hw_gettsf64(ah); - tsftu = TSF_TO_TU(tsf>>32, tsf); - slot = ((tsftu % intval) * ATH_BCBUF) / intval; - /* - * Reverse the slot order to get slot 0 on the TBTT offset that does - * not require TSF adjustment and other slots adding - * slot/ATH_BCBUF * beacon_int to timestamp. For example, with - * ATH_BCBUF = 4, we process beacon slots as follows: 3 2 1 0 3 2 1 .. - * and slot 0 is at correct offset to TBTT. - */ - slot = ATH_BCBUF - slot - 1; + tsf += TU_TO_USEC(ah->config.sw_beacon_response_time); + tsftu = TSF_TO_TU((tsf * ATH_BCBUF) >>32, tsf * ATH_BCBUF); + slot = (tsftu % (intval * ATH_BCBUF)) / intval; vif = sc->beacon.bslot[slot]; ath_dbg(common, ATH_DBG_BEACON, "slot %d [tsf %llu tsftu %u intval %u] vif %p\n", - slot, tsf, tsftu, intval, vif); + slot, tsf, tsftu / ATH_BCBUF, intval, vif); bfaddr = 0; if (vif) { @@ -424,6 +406,13 @@ void ath_beacon_tasklet(unsigned long data) bfaddr = bf->bf_daddr; bc = 1; } + + if (sc->beacon.bmisscnt != 0) { + ath_dbg(common, ATH_DBG_BSTUCK, + "resume beacon xmit after %u misses\n", + sc->beacon.bmisscnt); + sc->beacon.bmisscnt = 0; + } } /* @@ -463,13 +452,17 @@ static void ath9k_beacon_init(struct ath_softc *sc, u32 next_beacon, u32 beacon_period) { - if (beacon_period & ATH9K_BEACON_RESET_TSF) + if (sc->sc_flags & SC_OP_TSF_RESET) { ath9k_ps_wakeup(sc); + ath9k_hw_reset_tsf(sc->sc_ah); + } ath9k_hw_beaconinit(sc->sc_ah, next_beacon, beacon_period); - if (beacon_period & ATH9K_BEACON_RESET_TSF) + if (sc->sc_flags & SC_OP_TSF_RESET) { ath9k_ps_restore(sc); + sc->sc_flags &= ~SC_OP_TSF_RESET; + } } /* @@ -484,18 +477,14 @@ static void ath_beacon_config_ap(struct ath_softc *sc, u32 nexttbtt, intval; /* NB: the beacon interval is kept internally in TU's */ - intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; + intval = TU_TO_USEC(conf->beacon_interval & ATH9K_BEACON_PERIOD); intval /= ATH_BCBUF; /* for staggered beacons */ nexttbtt = intval; - if (sc->sc_flags & SC_OP_TSF_RESET) - intval |= ATH9K_BEACON_RESET_TSF; - /* * In AP mode we enable the beacon timers and SWBA interrupts to * prepare beacon frames. */ - intval |= ATH9K_BEACON_ENA; ah->imask |= ATH9K_INT_SWBA; ath_beaconq_config(sc); @@ -505,11 +494,6 @@ static void ath_beacon_config_ap(struct ath_softc *sc, ath9k_beacon_init(sc, nexttbtt, intval); sc->beacon.bmisscnt = 0; ath9k_hw_set_interrupts(ah, ah->imask); - - /* Clear the reset TSF flag, so that subsequent beacon updation - will not reset the HW TSF. */ - - sc->sc_flags &= ~SC_OP_TSF_RESET; } /* @@ -643,25 +627,20 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); - u64 tsf; - u32 tsftu, intval, nexttbtt; - - intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; - - - /* Pull nexttbtt forward to reflect the current TSF */ - - nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp); - if (nexttbtt == 0) - nexttbtt = intval; - else if (intval) - nexttbtt = roundup(nexttbtt, intval); - - tsf = ath9k_hw_gettsf64(ah); - tsftu = TSF_TO_TU((u32)(tsf>>32), (u32)tsf) + FUDGE; - do { - nexttbtt += intval; - } while (nexttbtt < tsftu); + u32 tsf, delta, intval, nexttbtt; + + tsf = ath9k_hw_gettsf32(ah) + TU_TO_USEC(FUDGE); + intval = TU_TO_USEC(conf->beacon_interval & ATH9K_BEACON_PERIOD); + + if (!sc->beacon.bc_tstamp) + nexttbtt = tsf + intval; + else { + if (tsf > sc->beacon.bc_tstamp) + delta = (tsf - sc->beacon.bc_tstamp); + else + delta = (tsf + 1 + (~0U - sc->beacon.bc_tstamp)); + nexttbtt = tsf + roundup(delta, intval); + } ath_dbg(common, ATH_DBG_BEACON, "IBSS nexttbtt %u intval %u (%u)\n", @@ -672,7 +651,6 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, * if we need to manually prepare beacon frames. Otherwise we use a * self-linked tx descriptor and let the hardware deal with things. */ - intval |= ATH9K_BEACON_ENA; ah->imask |= ATH9K_INT_SWBA; ath_beaconq_config(sc); @@ -685,22 +663,63 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, ath9k_hw_set_interrupts(ah, ah->imask); } -void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) +static bool ath9k_allow_beacon_config(struct ath_softc *sc, + struct ieee80211_vif *vif) { struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; struct ath_common *common = ath9k_hw_common(sc->sc_ah); - enum nl80211_iftype iftype; + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + struct ath_vif *avp = (void *)vif->drv_priv; - /* Setup the beacon configuration parameters */ - if (vif) { - struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; - iftype = vif->type; - cur_conf->beacon_interval = bss_conf->beacon_int; - cur_conf->dtim_period = bss_conf->dtim_period; - } else { - iftype = sc->sc_ah->opmode; + /* + * Can not have different beacon interval on multiple + * AP interface case + */ + if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) && + (sc->nbcnvifs > 1) && + (vif->type == NL80211_IFTYPE_AP) && + (cur_conf->beacon_interval != bss_conf->beacon_int)) { + ath_dbg(common, ATH_DBG_CONFIG, + "Changing beacon interval of multiple \ + AP interfaces !\n"); + return false; } + /* + * Can not configure station vif's beacon config + * while on AP opmode + */ + if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) && + (vif->type != NL80211_IFTYPE_AP)) { + ath_dbg(common, ATH_DBG_CONFIG, + "STA vif's beacon not allowed on AP mode\n"); + return false; + } + /* + * Do not allow beacon config if HW was already configured + * with another STA vif + */ + if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) && + (vif->type == NL80211_IFTYPE_STATION) && + (sc->sc_flags & SC_OP_BEACONS) && + !avp->primary_sta_vif) { + ath_dbg(common, ATH_DBG_CONFIG, + "Beacon already configured for a station interface\n"); + return false; + } + return true; +} + +void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) +{ + struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + + if (!ath9k_allow_beacon_config(sc, vif)) + return; + /* Setup the beacon configuration parameters */ + cur_conf->beacon_interval = bss_conf->beacon_int; + cur_conf->dtim_period = bss_conf->dtim_period; cur_conf->listen_interval = 1; cur_conf->dtim_count = 1; cur_conf->bmiss_timeout = @@ -723,7 +742,16 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) if (cur_conf->dtim_period == 0) cur_conf->dtim_period = 1; - switch (iftype) { + ath_set_beacon(sc); + sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; +} + +void ath_set_beacon(struct ath_softc *sc) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; + + switch (sc->sc_ah->opmode) { case NL80211_IFTYPE_AP: ath_beacon_config_ap(sc, cur_conf); break; @@ -750,22 +778,23 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status) int slot; bool found = false; - ath9k_ps_wakeup(sc); - if (status) { - for (slot = 0; slot < ATH_BCBUF; slot++) { - if (sc->beacon.bslot[slot]) { - avp = (void *)sc->beacon.bslot[slot]->drv_priv; - if (avp->is_bslot_active) { - found = true; - break; - } + for (slot = 0; slot < ATH_BCBUF; slot++) { + if (sc->beacon.bslot[slot]) { + avp = (void *)sc->beacon.bslot[slot]->drv_priv; + if (avp->is_bslot_active) { + found = true; + break; } } - if (found) { - /* Re-enable beaconing */ - ah->imask |= ATH9K_INT_SWBA; - ath9k_hw_set_interrupts(ah, ah->imask); - } + } + if (!found) + return; + + ath9k_ps_wakeup(sc); + if (status) { + /* Re-enable beaconing */ + ah->imask |= ATH9K_INT_SWBA; + ath9k_hw_set_interrupts(ah, ah->imask); } else { /* Disable SWBA interrupt */ ah->imask &= ~ATH9K_INT_SWBA; diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c index 615e68276e72..16ba8c67fbd5 100644 --- a/drivers/net/wireless/ath/ath9k/common.c +++ b/drivers/net/wireless/ath/ath9k/common.c @@ -116,7 +116,7 @@ void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan, if (chan->band == IEEE80211_BAND_2GHZ) { ichan->chanmode = CHANNEL_G; - ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM | CHANNEL_G; + ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM; } else { ichan->chanmode = CHANNEL_A; ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM; diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 8df5a92a20f1..a762cadb3ab7 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -1088,67 +1088,43 @@ int ath9k_init_debug(struct ath_hw *ah) return -ENOMEM; #ifdef CONFIG_ATH_DEBUG - if (!debugfs_create_file("debug", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, &fops_debug)) - goto err; + debugfs_create_file("debug", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, + sc, &fops_debug); #endif - - if (!debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, - sc, &fops_dma)) - goto err; - - if (!debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy, - sc, &fops_interrupt)) - goto err; - - if (!debugfs_create_file("wiphy", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, &fops_wiphy)) - goto err; - - if (!debugfs_create_file("xmit", S_IRUSR, sc->debug.debugfs_phy, - sc, &fops_xmit)) - goto err; - - if (!debugfs_create_file("stations", S_IRUSR, sc->debug.debugfs_phy, - sc, &fops_stations)) - goto err; - - if (!debugfs_create_file("misc", S_IRUSR, sc->debug.debugfs_phy, - sc, &fops_misc)) - goto err; - - if (!debugfs_create_file("recv", S_IRUSR, sc->debug.debugfs_phy, - sc, &fops_recv)) - goto err; - - if (!debugfs_create_file("rx_chainmask", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, &fops_rx_chainmask)) - goto err; - - if (!debugfs_create_file("tx_chainmask", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, &fops_tx_chainmask)) - goto err; - - if (!debugfs_create_file("regidx", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, &fops_regidx)) - goto err; - - if (!debugfs_create_file("regval", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, &fops_regval)) - goto err; - - if (!debugfs_create_bool("ignore_extcca", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, &ah->config.cwm_ignore_extcca)) - goto err; - - if (!debugfs_create_file("regdump", S_IRUSR, sc->debug.debugfs_phy, - sc, &fops_regdump)) - goto err; + debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, sc, + &fops_dma); + debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy, sc, + &fops_interrupt); + debugfs_create_file("wiphy", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, + sc, &fops_wiphy); + debugfs_create_file("xmit", S_IRUSR, sc->debug.debugfs_phy, sc, + &fops_xmit); + debugfs_create_file("stations", S_IRUSR, sc->debug.debugfs_phy, sc, + &fops_stations); + debugfs_create_file("misc", S_IRUSR, sc->debug.debugfs_phy, sc, + &fops_misc); + debugfs_create_file("recv", S_IRUSR, sc->debug.debugfs_phy, sc, + &fops_recv); + debugfs_create_file("rx_chainmask", S_IRUSR | S_IWUSR, + sc->debug.debugfs_phy, sc, &fops_rx_chainmask); + debugfs_create_file("tx_chainmask", S_IRUSR | S_IWUSR, + sc->debug.debugfs_phy, sc, &fops_tx_chainmask); + debugfs_create_file("regidx", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, + sc, &fops_regidx); + debugfs_create_file("regval", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, + sc, &fops_regval); + debugfs_create_bool("ignore_extcca", S_IRUSR | S_IWUSR, + sc->debug.debugfs_phy, + &ah->config.cwm_ignore_extcca); + debugfs_create_file("regdump", S_IRUSR, sc->debug.debugfs_phy, sc, + &fops_regdump); + + debugfs_create_u32("gpio_mask", S_IRUSR | S_IWUSR, + sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask); + + debugfs_create_u32("gpio_val", S_IRUSR | S_IWUSR, + sc->debug.debugfs_phy, &sc->sc_ah->gpio_val); sc->debug.regidx = 0; return 0; -err: - debugfs_remove_recursive(sc->debug.debugfs_phy); - sc->debug.debugfs_phy = NULL; - return -ENOMEM; } diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index 8cd8333cc086..2f0712ea49a6 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -392,6 +392,8 @@ static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah, numXpdGain); } + ENABLE_REGWRITE_BUFFER(ah); + if (i == 0) { if (!ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { @@ -442,6 +444,7 @@ static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah, regOffset += 4; } } + REGWRITE_BUFFER_FLUSH(ah); } } @@ -757,6 +760,8 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah, ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2; } + ENABLE_REGWRITE_BUFFER(ah); + /* OFDM power per rate */ REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, ATH9K_POW_SM(ratesArray[rate18mb], 24) @@ -840,6 +845,7 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah, | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); } + REGWRITE_BUFFER_FLUSH(ah); } static void ath9k_hw_ar9287_set_addac(struct ath_hw *ah, diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c index fccd87df7300..995949ddd63e 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_def.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c @@ -799,6 +799,8 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, pwr_table_offset, &diff); + ENABLE_REGWRITE_BUFFER(ah); + if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) { if (OLC_FOR_AR9280_20_LATER) { REG_WRITE(ah, @@ -847,6 +849,7 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, regOffset += 4; } + REGWRITE_BUFFER_FLUSH(ah); } } @@ -1205,6 +1208,8 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah, } } + ENABLE_REGWRITE_BUFFER(ah); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, ATH9K_POW_SM(ratesArray[rate18mb], 24) | ATH9K_POW_SM(ratesArray[rate12mb], 16) @@ -1291,6 +1296,8 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah, REG_WRITE(ah, AR_PHY_POWER_TX_SUB, ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6) | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0)); + + REGWRITE_BUFFER_FLUSH(ah); } static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index 0fb8f8ac275a..44a0a886124d 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -41,12 +41,14 @@ void ath_init_leds(struct ath_softc *sc) { int ret; - if (AR_SREV_9287(sc->sc_ah)) - sc->sc_ah->led_pin = ATH_LED_PIN_9287; - else if (AR_SREV_9485(sc->sc_ah)) - sc->sc_ah->led_pin = ATH_LED_PIN_9485; - else - sc->sc_ah->led_pin = ATH_LED_PIN_DEF; + if (sc->sc_ah->led_pin < 0) { + if (AR_SREV_9287(sc->sc_ah)) + sc->sc_ah->led_pin = ATH_LED_PIN_9287; + else if (AR_SREV_9485(sc->sc_ah)) + sc->sc_ah->led_pin = ATH_LED_PIN_9485; + else + sc->sc_ah->led_pin = ATH_LED_PIN_DEF; + } /* Configure gpio 1 for output */ ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin, diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 753a245c5ad1..ec47be94b74f 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -328,7 +328,7 @@ struct ath9k_debug { #endif /* CONFIG_ATH9K_HTC_DEBUGFS */ #define ATH_LED_PIN_DEF 1 -#define ATH_LED_PIN_9287 8 +#define ATH_LED_PIN_9287 10 #define ATH_LED_PIN_9271 15 #define ATH_LED_PIN_7010 12 #define ATH_LED_ON_DURATION_IDLE 350 /* in msecs */ diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index 8d1d8792436d..8f56158e5887 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -155,7 +155,7 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, nexttbtt = intval; if (priv->op_flags & OP_TSF_RESET) { - intval |= ATH9K_BEACON_RESET_TSF; + ath9k_hw_reset_tsf(priv->ah); priv->op_flags &= ~OP_TSF_RESET; } else { /* @@ -168,8 +168,6 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, } while (nexttbtt < tsftu); } - intval |= ATH9K_BEACON_ENA; - if (priv->op_flags & OP_ENABLE_BEACON) imask |= ATH9K_INT_SWBA; @@ -178,7 +176,7 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, bss_conf->beacon_interval, nexttbtt, imask); WMI_CMD(WMI_DISABLE_INTR_CMDID); - ath9k_hw_beaconinit(priv->ah, nexttbtt, intval); + ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval)); priv->bmiss_cnt = 0; htc_imask = cpu_to_be32(imask); WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); @@ -207,7 +205,6 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, nexttbtt += intval; } while (nexttbtt < tsftu); - intval |= ATH9K_BEACON_ENA; if (priv->op_flags & OP_ENABLE_BEACON) imask |= ATH9K_INT_SWBA; @@ -216,7 +213,7 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, bss_conf->beacon_interval, nexttbtt, imask); WMI_CMD(WMI_DISABLE_INTR_CMDID); - ath9k_hw_beaconinit(priv->ah, nexttbtt, intval); + ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval)); priv->bmiss_cnt = 0; htc_imask = cpu_to_be32(imask); WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index fc67c937e172..8303b34bdc90 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -430,13 +430,16 @@ static void ath9k_regwrite_flush(void *hw_priv) mutex_unlock(&priv->wmi->multi_write_mutex); } -static const struct ath_ops ath9k_common_ops = { - .read = ath9k_regread, - .multi_read = ath9k_multi_regread, - .write = ath9k_regwrite, - .enable_write_buffer = ath9k_enable_regwrite_buffer, - .write_flush = ath9k_regwrite_flush, -}; +static u32 ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr) +{ + u32 val; + + val = ath9k_regread(hw_priv, reg_offset); + val &= ~clr; + val |= set; + ath9k_regwrite(hw_priv, val, reg_offset); + return val; +} static void ath_usb_read_cachesize(struct ath_common *common, int *csz) { @@ -561,13 +564,7 @@ static void ath9k_init_crypto(struct ath9k_htc_priv *priv) int i = 0; /* Get the hardware key cache size. */ - common->keymax = priv->ah->caps.keycache_size; - if (common->keymax > ATH_KEYMAX) { - ath_dbg(common, ATH_DBG_ANY, - "Warning, using only %u entries in %u key cache\n", - ATH_KEYMAX, common->keymax); - common->keymax = ATH_KEYMAX; - } + common->keymax = AR_KEYTABLE_SIZE; if (priv->ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) common->crypt_caps |= ATH_CRYPT_CAP_MIC_COMBINED; @@ -658,10 +655,16 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, ah->hw_version.subsysid = 0; /* FIXME */ ah->hw_version.usbdev = drv_info; ah->ah_flags |= AH_USE_EEPROM; + ah->reg_ops.read = ath9k_regread; + ah->reg_ops.multi_read = ath9k_multi_regread; + ah->reg_ops.write = ath9k_regwrite; + ah->reg_ops.enable_write_buffer = ath9k_enable_regwrite_buffer; + ah->reg_ops.write_flush = ath9k_regwrite_flush; + ah->reg_ops.rmw = ath9k_reg_rmw; priv->ah = ah; common = ath9k_hw_common(ah); - common->ops = &ath9k_common_ops; + common->ops = &ah->reg_ops; common->bus_ops = &ath9k_usb_bus_ops; common->ah = ah; common->hw = priv->hw; diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h index c8f254fe0f0b..22ee888b0baf 100644 --- a/drivers/net/wireless/ath/ath9k/hw-ops.h +++ b/drivers/net/wireless/ath/ath9k/hw-ops.h @@ -122,12 +122,6 @@ static inline void ath9k_hw_set11n_burstduration(struct ath_hw *ah, void *ds, ath9k_hw_ops(ah)->set11n_burstduration(ah, ds, burstDuration); } -static inline void ath9k_hw_set11n_virtualmorefrag(struct ath_hw *ah, void *ds, - u32 vmf) -{ - ath9k_hw_ops(ah)->set11n_virtualmorefrag(ah, ds, vmf); -} - /* Private hardware call ops */ /* PHY ops */ diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index c95bc5cc1a1f..c8a2d0dae796 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -130,6 +130,20 @@ bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout) } EXPORT_SYMBOL(ath9k_hw_wait); +void ath9k_hw_write_array(struct ath_hw *ah, struct ar5416IniArray *array, + int column, unsigned int *writecnt) +{ + int r; + + ENABLE_REGWRITE_BUFFER(ah); + for (r = 0; r < array->ia_rows; r++) { + REG_WRITE(ah, INI_RA(array, r, 0), + INI_RA(array, r, column)); + DO_DELAY(*writecnt); + } + REGWRITE_BUFFER_FLUSH(ah); +} + u32 ath9k_hw_reverse_bits(u32 val, u32 n) { u32 retval; @@ -142,25 +156,6 @@ u32 ath9k_hw_reverse_bits(u32 val, u32 n) return retval; } -bool ath9k_get_channel_edges(struct ath_hw *ah, - u16 flags, u16 *low, - u16 *high) -{ - struct ath9k_hw_capabilities *pCap = &ah->caps; - - if (flags & CHANNEL_5GHZ) { - *low = pCap->low_5ghz_chan; - *high = pCap->high_5ghz_chan; - return true; - } - if ((flags & CHANNEL_2GHZ)) { - *low = pCap->low_2ghz_chan; - *high = pCap->high_2ghz_chan; - return true; - } - return false; -} - u16 ath9k_hw_computetxtime(struct ath_hw *ah, u8 phy, int kbps, u32 frameLen, u16 rateix, @@ -364,11 +359,6 @@ static void ath9k_hw_init_config(struct ath_hw *ah) ah->config.spurchans[i][1] = AR_NO_SPUR; } - if (ah->hw_version.devid != AR2427_DEVID_PCIE) - ah->config.ht_enable = 1; - else - ah->config.ht_enable = 0; - /* PAPRD needs some more work to be enabled */ ah->config.paprd_disable = 1; @@ -410,6 +400,8 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah) ah->sta_id1_defaults = AR_STA_ID1_CRPT_MIC_ENABLE | AR_STA_ID1_MCAST_KSRCH; + if (AR_SREV_9100(ah)) + ah->sta_id1_defaults |= AR_STA_ID1_AR9100_BA_FIX; ah->enable_32kHz_clock = DONT_USE_32KHZ; ah->slottime = 20; ah->globaltxtimeout = (u32) -1; @@ -673,14 +665,14 @@ static void ath9k_hw_init_qos(struct ath_hw *ah) unsigned long ar9003_get_pll_sqsum_dvc(struct ath_hw *ah) { - REG_WRITE(ah, PLL3, (REG_READ(ah, PLL3) & ~(PLL3_DO_MEAS_MASK))); - udelay(100); - REG_WRITE(ah, PLL3, (REG_READ(ah, PLL3) | PLL3_DO_MEAS_MASK)); + REG_CLR_BIT(ah, PLL3, PLL3_DO_MEAS_MASK); + udelay(100); + REG_SET_BIT(ah, PLL3, PLL3_DO_MEAS_MASK); - while ((REG_READ(ah, PLL4) & PLL4_MEAS_DONE) == 0) - udelay(100); + while ((REG_READ(ah, PLL4) & PLL4_MEAS_DONE) == 0) + udelay(100); - return (REG_READ(ah, PLL3) & SQSUM_DVC_MASK) >> 3; + return (REG_READ(ah, PLL3) & SQSUM_DVC_MASK) >> 3; } EXPORT_SYMBOL(ar9003_get_pll_sqsum_dvc); @@ -830,8 +822,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) ah->misc_mode); if (ah->misc_mode != 0) - REG_WRITE(ah, AR_PCU_MISC, - REG_READ(ah, AR_PCU_MISC) | ah->misc_mode); + REG_SET_BIT(ah, AR_PCU_MISC, ah->misc_mode); if (conf->channel && conf->channel->band == IEEE80211_BAND_5GHZ) sifstime = 16; @@ -899,23 +890,19 @@ u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, struct ath9k_channel *chan) static inline void ath9k_hw_set_dma(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); - u32 regval; ENABLE_REGWRITE_BUFFER(ah); /* * set AHB_MODE not to do cacheline prefetches */ - if (!AR_SREV_9300_20_OR_LATER(ah)) { - regval = REG_READ(ah, AR_AHB_MODE); - REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN); - } + if (!AR_SREV_9300_20_OR_LATER(ah)) + REG_SET_BIT(ah, AR_AHB_MODE, AR_AHB_PREFETCH_RD_EN); /* * let mac dma reads be in 128 byte chunks */ - regval = REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK; - REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B); + REG_RMW(ah, AR_TXCFG, AR_TXCFG_DMASZ_128B, AR_TXCFG_DMASZ_MASK); REGWRITE_BUFFER_FLUSH(ah); @@ -932,8 +919,7 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah) /* * let mac dma writes be in 128 byte chunks */ - regval = REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK; - REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B); + REG_RMW(ah, AR_RXCFG, AR_RXCFG_DMASZ_128B, AR_RXCFG_DMASZ_MASK); /* * Setup receive FIFO threshold to hold off TX activities @@ -972,30 +958,27 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah) static void ath9k_hw_set_operating_mode(struct ath_hw *ah, int opmode) { - u32 val; + u32 mask = AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC; + u32 set = AR_STA_ID1_KSRCH_MODE; - val = REG_READ(ah, AR_STA_ID1); - val &= ~(AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC); switch (opmode) { - case NL80211_IFTYPE_AP: - REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_STA_AP - | AR_STA_ID1_KSRCH_MODE); - REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); - break; case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_MESH_POINT: - REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_ADHOC - | AR_STA_ID1_KSRCH_MODE); + set |= AR_STA_ID1_ADHOC; REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); break; + case NL80211_IFTYPE_AP: + set |= AR_STA_ID1_STA_AP; + /* fall through */ case NL80211_IFTYPE_STATION: - REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE); + REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); break; default: - if (ah->is_monitoring) - REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE); + if (!ah->is_monitoring) + set = 0; break; } + REG_RMW(ah, AR_STA_ID1, set, mask); } void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, u32 coef_scaled, @@ -1021,10 +1004,8 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type) u32 tmpReg; if (AR_SREV_9100(ah)) { - u32 val = REG_READ(ah, AR_RTC_DERIVED_CLK); - val &= ~AR_RTC_DERIVED_CLK_PERIOD; - val |= SM(1, AR_RTC_DERIVED_CLK_PERIOD); - REG_WRITE(ah, AR_RTC_DERIVED_CLK, val); + REG_RMW_FIELD(ah, AR_RTC_DERIVED_CLK, + AR_RTC_DERIVED_CLK_PERIOD, 1); (void)REG_READ(ah, AR_RTC_DERIVED_CLK); } @@ -1212,6 +1193,20 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, return true; } +static void ath9k_hw_apply_gpio_override(struct ath_hw *ah) +{ + u32 gpio_mask = ah->gpio_mask; + int i; + + for (i = 0; gpio_mask; i++, gpio_mask >>= 1) { + if (!(gpio_mask & 1)) + continue; + + ath9k_hw_cfg_output(ah, i, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + ath9k_hw_set_gpio(ah, i, !!(ah->gpio_val & BIT(i))); + } +} + bool ath9k_hw_check_alive(struct ath_hw *ah) { int count = 50; @@ -1409,7 +1404,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, REGWRITE_BUFFER_FLUSH(ah); ah->intr_txqs = 0; - for (i = 0; i < ah->caps.total_queues; i++) + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) ath9k_hw_resettxqueue(ah, i); ath9k_hw_init_interrupt_masks(ah, ah->opmode); @@ -1426,8 +1421,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ar9002_hw_enable_wep_aggregation(ah); } - REG_WRITE(ah, AR_STA_ID1, - REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PRESERVE_SEQNUM); + REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM); ath9k_hw_set_dma(ah); @@ -1491,6 +1485,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, if (AR_SREV_9300_20_OR_LATER(ah)) ar9003_hw_bb_watchdog_config(ah); + ath9k_hw_apply_gpio_override(ah); + return 0; } EXPORT_SYMBOL(ath9k_hw_reset); @@ -1670,21 +1666,15 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period) case NL80211_IFTYPE_MESH_POINT: REG_SET_BIT(ah, AR_TXCFG, AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY); - REG_WRITE(ah, AR_NEXT_NDP_TIMER, - TU_TO_USEC(next_beacon + - (ah->atim_window ? ah-> - atim_window : 1))); + REG_WRITE(ah, AR_NEXT_NDP_TIMER, next_beacon + + TU_TO_USEC(ah->atim_window ? ah->atim_window : 1)); flags |= AR_NDP_TIMER_EN; case NL80211_IFTYPE_AP: - REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(next_beacon)); - REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, - TU_TO_USEC(next_beacon - - ah->config. - dma_beacon_response_time)); - REG_WRITE(ah, AR_NEXT_SWBA, - TU_TO_USEC(next_beacon - - ah->config. - sw_beacon_response_time)); + REG_WRITE(ah, AR_NEXT_TBTT_TIMER, next_beacon); + REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, next_beacon - + TU_TO_USEC(ah->config.dma_beacon_response_time)); + REG_WRITE(ah, AR_NEXT_SWBA, next_beacon - + TU_TO_USEC(ah->config.sw_beacon_response_time)); flags |= AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN; break; @@ -1696,18 +1686,13 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period) break; } - REG_WRITE(ah, AR_BEACON_PERIOD, TU_TO_USEC(beacon_period)); - REG_WRITE(ah, AR_DMA_BEACON_PERIOD, TU_TO_USEC(beacon_period)); - REG_WRITE(ah, AR_SWBA_PERIOD, TU_TO_USEC(beacon_period)); - REG_WRITE(ah, AR_NDP_PERIOD, TU_TO_USEC(beacon_period)); + REG_WRITE(ah, AR_BEACON_PERIOD, beacon_period); + REG_WRITE(ah, AR_DMA_BEACON_PERIOD, beacon_period); + REG_WRITE(ah, AR_SWBA_PERIOD, beacon_period); + REG_WRITE(ah, AR_NDP_PERIOD, beacon_period); REGWRITE_BUFFER_FLUSH(ah); - beacon_period &= ~ATH9K_BEACON_ENA; - if (beacon_period & ATH9K_BEACON_RESET_TSF) { - ath9k_hw_reset_tsf(ah); - } - REG_SET_BIT(ah, AR_TIMER_MODE, flags); } EXPORT_SYMBOL(ath9k_hw_beaconinit); @@ -1842,6 +1827,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) !(AR_SREV_9271(ah))) /* CB71: GPIO 0 is pulled down to indicate 3 rx chains */ pCap->rx_chainmask = ath9k_hw_gpio_get(ah, 0) ? 0x5 : 0x7; + else if (AR_SREV_9100(ah)) + pCap->rx_chainmask = 0x7; else /* Use rx_chainmask from EEPROM. */ pCap->rx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_RX_MASK); @@ -1852,36 +1839,13 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) if (AR_SREV_9300_20_OR_LATER(ah)) ah->misc_mode |= AR_PCU_ALWAYS_PERFORM_KEYSEARCH; - pCap->low_2ghz_chan = 2312; - pCap->high_2ghz_chan = 2732; - - pCap->low_5ghz_chan = 4920; - pCap->high_5ghz_chan = 6100; - common->crypt_caps |= ATH_CRYPT_CAP_CIPHER_AESCCM; - if (ah->config.ht_enable) + if (ah->hw_version.devid != AR2427_DEVID_PCIE) pCap->hw_caps |= ATH9K_HW_CAP_HT; else pCap->hw_caps &= ~ATH9K_HW_CAP_HT; - if (capField & AR_EEPROM_EEPCAP_MAXQCU) - pCap->total_queues = - MS(capField, AR_EEPROM_EEPCAP_MAXQCU); - else - pCap->total_queues = ATH9K_NUM_TX_QUEUES; - - if (capField & AR_EEPROM_EEPCAP_KC_ENTRIES) - pCap->keycache_size = - 1 << MS(capField, AR_EEPROM_EEPCAP_KC_ENTRIES); - else - pCap->keycache_size = AR_KEYTABLE_SIZE; - - if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) - pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD >> 1; - else - pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD; - if (AR_SREV_9271(ah)) pCap->num_gpio_pins = AR9271_NUM_GPIO; else if (AR_DEVID_7010(ah)) @@ -1900,8 +1864,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) pCap->rts_aggr_limit = (8 * 1024); } - pCap->hw_caps |= ATH9K_HW_CAP_ENHANCEDPM; - #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) ah->rfsilent = ah->eep_ops->get_eeprom(ah, EEP_RF_SILENT); if (ah->rfsilent & EEP_RFSILENT_ENABLED) { @@ -1923,23 +1885,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) else pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS; - if (regulatory->current_rd_ext & (1 << REG_EXT_JAPAN_MIDBAND)) { - pCap->reg_cap = - AR_EEPROM_EEREGCAP_EN_KK_NEW_11A | - AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN | - AR_EEPROM_EEREGCAP_EN_KK_U2 | - AR_EEPROM_EEREGCAP_EN_KK_MIDBAND; - } else { - pCap->reg_cap = - AR_EEPROM_EEREGCAP_EN_KK_NEW_11A | - AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN; - } - - /* Advertise midband for AR5416 with FCC midband set in eeprom */ - if (regulatory->current_rd_ext & (1 << REG_EXT_FCC_MIDBAND) && - AR_SREV_5416(ah)) - pCap->reg_cap |= AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND; - if (AR_SREV_9280_20_OR_LATER(ah) && common->btcoex_enabled) { btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO; btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO; @@ -2186,11 +2131,9 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits) REG_WRITE(ah, AR_PHY_ERR, phybits); if (phybits) - REG_WRITE(ah, AR_RXCFG, - REG_READ(ah, AR_RXCFG) | AR_RXCFG_ZLFDMA); + REG_SET_BIT(ah, AR_RXCFG, AR_RXCFG_ZLFDMA); else - REG_WRITE(ah, AR_RXCFG, - REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA); + REG_CLR_BIT(ah, AR_RXCFG, AR_RXCFG_ZLFDMA); REGWRITE_BUFFER_FLUSH(ah); } @@ -2366,10 +2309,11 @@ static u32 rightmost_index(struct ath_gen_timer_table *timer_table, u32 *mask) return timer_table->gen_timer_index[b]; } -static u32 ath9k_hw_gettsf32(struct ath_hw *ah) +u32 ath9k_hw_gettsf32(struct ath_hw *ah) { return REG_READ(ah, AR_TSF_L32); } +EXPORT_SYMBOL(ath9k_hw_gettsf32); struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah, void (*trigger)(void *), diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 6650fd48415c..a778b66f4438 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -65,53 +65,49 @@ /* Register read/write primitives */ #define REG_WRITE(_ah, _reg, _val) \ - ath9k_hw_common(_ah)->ops->write((_ah), (_val), (_reg)) + (_ah)->reg_ops.write((_ah), (_val), (_reg)) #define REG_READ(_ah, _reg) \ - ath9k_hw_common(_ah)->ops->read((_ah), (_reg)) + (_ah)->reg_ops.read((_ah), (_reg)) #define REG_READ_MULTI(_ah, _addr, _val, _cnt) \ - ath9k_hw_common(_ah)->ops->multi_read((_ah), (_addr), (_val), (_cnt)) + (_ah)->reg_ops.multi_read((_ah), (_addr), (_val), (_cnt)) + +#define REG_RMW(_ah, _reg, _set, _clr) \ + (_ah)->reg_ops.rmw((_ah), (_reg), (_set), (_clr)) #define ENABLE_REGWRITE_BUFFER(_ah) \ do { \ - if (ath9k_hw_common(_ah)->ops->enable_write_buffer) \ - ath9k_hw_common(_ah)->ops->enable_write_buffer((_ah)); \ + if ((_ah)->reg_ops.enable_write_buffer) \ + (_ah)->reg_ops.enable_write_buffer((_ah)); \ } while (0) #define REGWRITE_BUFFER_FLUSH(_ah) \ do { \ - if (ath9k_hw_common(_ah)->ops->write_flush) \ - ath9k_hw_common(_ah)->ops->write_flush((_ah)); \ + if ((_ah)->reg_ops.write_flush) \ + (_ah)->reg_ops.write_flush((_ah)); \ } while (0) #define SM(_v, _f) (((_v) << _f##_S) & _f) #define MS(_v, _f) (((_v) & _f) >> _f##_S) -#define REG_RMW(_a, _r, _set, _clr) \ - REG_WRITE(_a, _r, (REG_READ(_a, _r) & ~(_clr)) | (_set)) #define REG_RMW_FIELD(_a, _r, _f, _v) \ - REG_WRITE(_a, _r, \ - (REG_READ(_a, _r) & ~_f) | (((_v) << _f##_S) & _f)) + REG_RMW(_a, _r, (((_v) << _f##_S) & _f), (_f)) #define REG_READ_FIELD(_a, _r, _f) \ (((REG_READ(_a, _r) & _f) >> _f##_S)) #define REG_SET_BIT(_a, _r, _f) \ - REG_WRITE(_a, _r, REG_READ(_a, _r) | (_f)) + REG_RMW(_a, _r, (_f), 0) #define REG_CLR_BIT(_a, _r, _f) \ - REG_WRITE(_a, _r, REG_READ(_a, _r) & ~(_f)) + REG_RMW(_a, _r, 0, (_f)) -#define DO_DELAY(x) do { \ - if ((++(x) % 64) == 0) \ - udelay(1); \ +#define DO_DELAY(x) do { \ + if (((++(x) % 64) == 0) && \ + (ath9k_hw_common(ah)->bus_ops->ath_bus_type \ + != ATH_USB)) \ + udelay(1); \ } while (0) -#define REG_WRITE_ARRAY(iniarray, column, regWr) do { \ - int r; \ - for (r = 0; r < ((iniarray)->ia_rows); r++) { \ - REG_WRITE(ah, INI_RA((iniarray), (r), 0), \ - INI_RA((iniarray), r, (column))); \ - DO_DELAY(regWr); \ - } \ - } while (0) +#define REG_WRITE_ARRAY(iniarray, column, regWr) \ + ath9k_hw_write_array(ah, iniarray, column, &(regWr)) #define AR_GPIO_OUTPUT_MUX_AS_OUTPUT 0 #define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1 @@ -178,7 +174,6 @@ enum ath9k_hw_caps { ATH9K_HW_CAP_HT = BIT(0), ATH9K_HW_CAP_RFSILENT = BIT(1), ATH9K_HW_CAP_CST = BIT(2), - ATH9K_HW_CAP_ENHANCEDPM = BIT(3), ATH9K_HW_CAP_AUTOSLEEP = BIT(4), ATH9K_HW_CAP_4KB_SPLITTRANS = BIT(5), ATH9K_HW_CAP_EDMA = BIT(6), @@ -195,17 +190,11 @@ enum ath9k_hw_caps { struct ath9k_hw_capabilities { u32 hw_caps; /* ATH9K_HW_CAP_* from ath9k_hw_caps */ - u16 total_queues; - u16 keycache_size; - u16 low_5ghz_chan, high_5ghz_chan; - u16 low_2ghz_chan, high_2ghz_chan; u16 rts_aggr_limit; u8 tx_chainmask; u8 rx_chainmask; u8 max_txchains; u8 max_rxchains; - u16 tx_triglevel_max; - u16 reg_cap; u8 num_gpio_pins; u8 rx_hp_qdepth; u8 rx_lp_qdepth; @@ -227,7 +216,6 @@ struct ath9k_ops_config { u8 pcie_clock_req; u32 pcie_waen; u8 analog_shiftreg; - u8 ht_enable; u8 paprd_disable; u32 ofdm_trig_low; u32 ofdm_trig_high; @@ -412,8 +400,6 @@ struct ath9k_beacon_state { u32 bs_nextdtim; u32 bs_intval; #define ATH9K_BEACON_PERIOD 0x0000ffff -#define ATH9K_BEACON_ENA 0x00800000 -#define ATH9K_BEACON_RESET_TSF 0x01000000 #define ATH9K_TSFOOR_THRESHOLD 0x00004240 /* 16k us */ u32 bs_dtimperiod; u16 bs_cfpperiod; @@ -640,8 +626,6 @@ struct ath_hw_ops { void (*clr11n_aggr)(struct ath_hw *ah, void *ds); void (*set11n_burstduration)(struct ath_hw *ah, void *ds, u32 burstDuration); - void (*set11n_virtualmorefrag)(struct ath_hw *ah, void *ds, - u32 vmf); }; struct ath_nf_limits { @@ -655,6 +639,8 @@ struct ath_nf_limits { #define AH_UNPLUGGED 0x2 /* The card has been physically removed. */ struct ath_hw { + struct ath_ops reg_ops; + struct ieee80211_hw *hw; struct ath_common common; struct ath9k_hw_version hw_version; @@ -794,7 +780,9 @@ struct ath_hw { u32 originalGain[22]; int initPDADC; int PDADCdelta; - u8 led_pin; + int led_pin; + u32 gpio_mask; + u32 gpio_val; struct ar5416IniArray iniModes; struct ar5416IniArray iniCommon; @@ -907,8 +895,9 @@ void ath9k_hw_antdiv_comb_conf_set(struct ath_hw *ah, /* General Operation */ bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout); +void ath9k_hw_write_array(struct ath_hw *ah, struct ar5416IniArray *array, + int column, unsigned int *writecnt); u32 ath9k_hw_reverse_bits(u32 val, u32 n); -bool ath9k_get_channel_edges(struct ath_hw *ah, u16 flags, u16 *low, u16 *high); u16 ath9k_hw_computetxtime(struct ath_hw *ah, u8 phy, int kbps, u32 frameLen, u16 rateix, bool shortPreamble); @@ -924,6 +913,7 @@ void ath9k_hw_setopmode(struct ath_hw *ah); void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1); void ath9k_hw_setbssidmask(struct ath_hw *ah); void ath9k_hw_write_associd(struct ath_hw *ah); +u32 ath9k_hw_gettsf32(struct ath_hw *ah); u64 ath9k_hw_gettsf64(struct ath_hw *ah); void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64); void ath9k_hw_reset_tsf(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 79aec983279f..1ac8318d82a3 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -15,6 +15,7 @@ */ #include <linux/slab.h> +#include <linux/ath9k_platform.h> #include "ath9k.h" @@ -195,10 +196,27 @@ static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset) return val; } -static const struct ath_ops ath9k_common_ops = { - .read = ath9k_ioread32, - .write = ath9k_iowrite32, -}; +static unsigned int ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr) +{ + struct ath_hw *ah = (struct ath_hw *) hw_priv; + struct ath_common *common = ath9k_hw_common(ah); + struct ath_softc *sc = (struct ath_softc *) common->priv; + unsigned long uninitialized_var(flags); + u32 val; + + if (ah->config.serialize_regmode == SER_REG_MODE_ON) + spin_lock_irqsave(&sc->sc_serial_rw, flags); + + val = ioread32(sc->mem + reg_offset); + val &= ~clr; + val |= set; + iowrite32(val, sc->mem + reg_offset); + + if (ah->config.serialize_regmode == SER_REG_MODE_ON) + spin_unlock_irqrestore(&sc->sc_serial_rw, flags); + + return val; +} /**************************/ /* Initialization */ @@ -389,13 +407,7 @@ void ath9k_init_crypto(struct ath_softc *sc) int i = 0; /* Get the hardware key cache size. */ - common->keymax = sc->sc_ah->caps.keycache_size; - if (common->keymax > ATH_KEYMAX) { - ath_dbg(common, ATH_DBG_ANY, - "Warning, using only %u entries in %u key cache\n", - ATH_KEYMAX, common->keymax); - common->keymax = ATH_KEYMAX; - } + common->keymax = AR_KEYTABLE_SIZE; /* * Reset the key cache since some parts do not @@ -537,6 +549,7 @@ static void ath9k_init_misc(struct ath_softc *sc) static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, const struct ath_bus_ops *bus_ops) { + struct ath9k_platform_data *pdata = sc->dev->platform_data; struct ath_hw *ah = NULL; struct ath_common *common; int ret = 0, i; @@ -549,13 +562,22 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, ah->hw = sc->hw; ah->hw_version.devid = devid; ah->hw_version.subsysid = subsysid; + ah->reg_ops.read = ath9k_ioread32; + ah->reg_ops.write = ath9k_iowrite32; + ah->reg_ops.rmw = ath9k_reg_rmw; sc->sc_ah = ah; - if (!sc->dev->platform_data) + if (!pdata) { ah->ah_flags |= AH_USE_EEPROM; + sc->sc_ah->led_pin = -1; + } else { + sc->sc_ah->gpio_mask = pdata->gpio_mask; + sc->sc_ah->gpio_val = pdata->gpio_val; + sc->sc_ah->led_pin = pdata->led_pin; + } common = ath9k_hw_common(ah); - common->ops = &ath9k_common_ops; + common->ops = &ah->reg_ops; common->bus_ops = bus_ops; common->ah = ah; common->hw = sc->hw; @@ -587,6 +609,9 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, if (ret) goto err_hw; + if (pdata && pdata->macaddr) + memcpy(common->macaddr, pdata->macaddr, ETH_ALEN); + ret = ath9k_init_queues(sc); if (ret) goto err_queues; @@ -679,6 +704,8 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) if (AR_SREV_5416(sc->sc_ah)) hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; + hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + hw->queues = 4; hw->max_rates = 4; hw->channel_change_time = 5000; diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index edc1cbbfecaf..1968c67e3fab 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -209,15 +209,8 @@ bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q, { u32 cw; struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath9k_tx_queue_info *qi; - if (q >= pCap->total_queues) { - ath_dbg(common, ATH_DBG_QUEUE, - "Set TXQ properties, invalid queue: %u\n", q); - return false; - } - qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { ath_dbg(common, ATH_DBG_QUEUE, @@ -280,15 +273,8 @@ bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q, struct ath9k_tx_queue_info *qinfo) { struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath9k_tx_queue_info *qi; - if (q >= pCap->total_queues) { - ath_dbg(common, ATH_DBG_QUEUE, - "Get TXQ properties, invalid queue: %u\n", q); - return false; - } - qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { ath_dbg(common, ATH_DBG_QUEUE, @@ -320,28 +306,27 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type, { struct ath_common *common = ath9k_hw_common(ah); struct ath9k_tx_queue_info *qi; - struct ath9k_hw_capabilities *pCap = &ah->caps; int q; switch (type) { case ATH9K_TX_QUEUE_BEACON: - q = pCap->total_queues - 1; + q = ATH9K_NUM_TX_QUEUES - 1; break; case ATH9K_TX_QUEUE_CAB: - q = pCap->total_queues - 2; + q = ATH9K_NUM_TX_QUEUES - 2; break; case ATH9K_TX_QUEUE_PSPOLL: q = 1; break; case ATH9K_TX_QUEUE_UAPSD: - q = pCap->total_queues - 3; + q = ATH9K_NUM_TX_QUEUES - 3; break; case ATH9K_TX_QUEUE_DATA: - for (q = 0; q < pCap->total_queues; q++) + for (q = 0; q < ATH9K_NUM_TX_QUEUES; q++) if (ah->txq[q].tqi_type == ATH9K_TX_QUEUE_INACTIVE) break; - if (q == pCap->total_queues) { + if (q == ATH9K_NUM_TX_QUEUES) { ath_err(common, "No available TX queue\n"); return -1; } @@ -382,15 +367,9 @@ EXPORT_SYMBOL(ath9k_hw_setuptxqueue); bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q) { - struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath_common *common = ath9k_hw_common(ah); struct ath9k_tx_queue_info *qi; - if (q >= pCap->total_queues) { - ath_dbg(common, ATH_DBG_QUEUE, - "Release TXQ, invalid queue: %u\n", q); - return false; - } qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { ath_dbg(common, ATH_DBG_QUEUE, @@ -414,18 +393,11 @@ EXPORT_SYMBOL(ath9k_hw_releasetxqueue); bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) { - struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath_common *common = ath9k_hw_common(ah); struct ath9k_channel *chan = ah->curchan; struct ath9k_tx_queue_info *qi; u32 cwMin, chanCwMin, value; - if (q >= pCap->total_queues) { - ath_dbg(common, ATH_DBG_QUEUE, - "Reset TXQ, invalid queue: %u\n", q); - return false; - } - qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { ath_dbg(common, ATH_DBG_QUEUE, @@ -465,10 +437,9 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) REG_WRITE(ah, AR_QCBRCFG(q), SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) | SM(qi->tqi_cbrOverflowLimit, AR_Q_CBRCFG_OVF_THRESH)); - REG_WRITE(ah, AR_QMISC(q), - REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_FSP_CBR | - (qi->tqi_cbrOverflowLimit ? - AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN : 0)); + REG_SET_BIT(ah, AR_QMISC(q), AR_Q_MISC_FSP_CBR | + (qi->tqi_cbrOverflowLimit ? + AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN : 0)); } if (qi->tqi_readyTime && (qi->tqi_type != ATH9K_TX_QUEUE_CAB)) { REG_WRITE(ah, AR_QRDYTIMECFG(q), @@ -481,40 +452,31 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0)); if (qi->tqi_burstTime - && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)) { - REG_WRITE(ah, AR_QMISC(q), - REG_READ(ah, AR_QMISC(q)) | - AR_Q_MISC_RDYTIME_EXP_POLICY); - - } + && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)) + REG_SET_BIT(ah, AR_QMISC(q), AR_Q_MISC_RDYTIME_EXP_POLICY); - if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE) { - REG_WRITE(ah, AR_DMISC(q), - REG_READ(ah, AR_DMISC(q)) | - AR_D_MISC_POST_FR_BKOFF_DIS); - } + if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE) + REG_SET_BIT(ah, AR_DMISC(q), AR_D_MISC_POST_FR_BKOFF_DIS); REGWRITE_BUFFER_FLUSH(ah); - if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) { - REG_WRITE(ah, AR_DMISC(q), - REG_READ(ah, AR_DMISC(q)) | - AR_D_MISC_FRAG_BKOFF_EN); - } + if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) + REG_SET_BIT(ah, AR_DMISC(q), AR_D_MISC_FRAG_BKOFF_EN); + switch (qi->tqi_type) { case ATH9K_TX_QUEUE_BEACON: ENABLE_REGWRITE_BUFFER(ah); - REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q)) - | AR_Q_MISC_FSP_DBA_GATED - | AR_Q_MISC_BEACON_USE - | AR_Q_MISC_CBR_INCR_DIS1); + REG_SET_BIT(ah, AR_QMISC(q), + AR_Q_MISC_FSP_DBA_GATED + | AR_Q_MISC_BEACON_USE + | AR_Q_MISC_CBR_INCR_DIS1); - REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) - | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << + REG_SET_BIT(ah, AR_DMISC(q), + (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << AR_D_MISC_ARB_LOCKOUT_CNTRL_S) - | AR_D_MISC_BEACON_USE - | AR_D_MISC_POST_FR_BKOFF_DIS); + | AR_D_MISC_BEACON_USE + | AR_D_MISC_POST_FR_BKOFF_DIS); REGWRITE_BUFFER_FLUSH(ah); @@ -533,41 +495,38 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) case ATH9K_TX_QUEUE_CAB: ENABLE_REGWRITE_BUFFER(ah); - REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q)) - | AR_Q_MISC_FSP_DBA_GATED - | AR_Q_MISC_CBR_INCR_DIS1 - | AR_Q_MISC_CBR_INCR_DIS0); + REG_SET_BIT(ah, AR_QMISC(q), + AR_Q_MISC_FSP_DBA_GATED + | AR_Q_MISC_CBR_INCR_DIS1 + | AR_Q_MISC_CBR_INCR_DIS0); value = (qi->tqi_readyTime - (ah->config.sw_beacon_response_time - ah->config.dma_beacon_response_time) - ah->config.additional_swba_backoff) * 1024; REG_WRITE(ah, AR_QRDYTIMECFG(q), value | AR_Q_RDYTIMECFG_EN); - REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) - | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << + REG_SET_BIT(ah, AR_DMISC(q), + (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << AR_D_MISC_ARB_LOCKOUT_CNTRL_S)); REGWRITE_BUFFER_FLUSH(ah); break; case ATH9K_TX_QUEUE_PSPOLL: - REG_WRITE(ah, AR_QMISC(q), - REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_CBR_INCR_DIS1); + REG_SET_BIT(ah, AR_QMISC(q), AR_Q_MISC_CBR_INCR_DIS1); break; case ATH9K_TX_QUEUE_UAPSD: - REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) | - AR_D_MISC_POST_FR_BKOFF_DIS); + REG_SET_BIT(ah, AR_DMISC(q), AR_D_MISC_POST_FR_BKOFF_DIS); break; default: break; } if (qi->tqi_intFlags & ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS) { - REG_WRITE(ah, AR_DMISC(q), - REG_READ(ah, AR_DMISC(q)) | - SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL, - AR_D_MISC_ARB_LOCKOUT_CNTRL) | - AR_D_MISC_POST_FR_BKOFF_DIS); + REG_SET_BIT(ah, AR_DMISC(q), + SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL, + AR_D_MISC_ARB_LOCKOUT_CNTRL) | + AR_D_MISC_POST_FR_BKOFF_DIS); } if (AR_SREV_9300_20_OR_LATER(ah)) @@ -754,7 +713,6 @@ EXPORT_SYMBOL(ath9k_hw_abortpcurecv); bool ath9k_hw_stopdmarecv(struct ath_hw *ah, bool *reset) { #define AH_RX_STOP_DMA_TIMEOUT 10000 /* usec */ -#define AH_RX_TIME_QUANTUM 100 /* usec */ struct ath_common *common = ath9k_hw_common(ah); u32 mac_status, last_mac_status = 0; int i; @@ -797,7 +755,6 @@ bool ath9k_hw_stopdmarecv(struct ath_hw *ah, bool *reset) return true; } -#undef AH_RX_TIME_QUANTUM #undef AH_RX_STOP_DMA_TIMEOUT } EXPORT_SYMBOL(ath9k_hw_stopdmarecv); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 17d04ff8d678..4c5c9997dac6 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -299,7 +299,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, if (!(sc->sc_flags & (SC_OP_OFFCHANNEL))) { if (sc->sc_flags & SC_OP_BEACONS) - ath_beacon_config(sc, NULL); + ath_set_beacon(sc); ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/2); ath_start_ani(common); @@ -828,48 +828,6 @@ chip_reset: #undef SCHED_INTR } -static void ath9k_bss_assoc_info(struct ath_softc *sc, - struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf) -{ - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - - if (bss_conf->assoc) { - ath_dbg(common, ATH_DBG_CONFIG, - "Bss Info ASSOC %d, bssid: %pM\n", - bss_conf->aid, common->curbssid); - - /* New association, store aid */ - common->curaid = bss_conf->aid; - ath9k_hw_write_associd(ah); - - /* - * Request a re-configuration of Beacon related timers - * on the receipt of the first Beacon frame (i.e., - * after time sync with the AP). - */ - sc->ps_flags |= PS_BEACON_SYNC; - - /* Configure the beacon */ - ath_beacon_config(sc, vif); - - /* Reset rssi stats */ - sc->last_rssi = ATH_RSSI_DUMMY_MARKER; - sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; - - sc->sc_flags |= SC_OP_ANI_RUN; - ath_start_ani(common); - } else { - ath_dbg(common, ATH_DBG_CONFIG, "Bss Info DISASSOC\n"); - common->curaid = 0; - /* Stop ANI */ - sc->sc_flags &= ~SC_OP_ANI_RUN; - del_timer_sync(&common->ani.timer); - } -} - void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) { struct ath_hw *ah = sc->sc_ah; @@ -899,7 +857,7 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) goto out; } if (sc->sc_flags & SC_OP_BEACONS) - ath_beacon_config(sc, NULL); /* restart beacons */ + ath_set_beacon(sc); /* restart beacons */ /* Re-Enable interrupts */ ath9k_hw_set_interrupts(ah, ah->imask); @@ -1006,7 +964,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) sc->config.txpowlimit, &sc->curtxpow); if ((sc->sc_flags & SC_OP_BEACONS) || !(sc->sc_flags & (SC_OP_OFFCHANNEL))) - ath_beacon_config(sc, NULL); /* restart beacons */ + ath_set_beacon(sc); /* restart beacons */ ath9k_hw_set_interrupts(ah, ah->imask); @@ -1415,9 +1373,6 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, if ((iter_data.naps + iter_data.nadhocs) > 0) { sc->sc_flags |= SC_OP_ANI_RUN; ath_start_ani(common); - } else { - sc->sc_flags &= ~SC_OP_ANI_RUN; - del_timer_sync(&common->ani.timer); } } @@ -1452,7 +1407,6 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); - struct ath_vif *avp = (void *)vif->drv_priv; int ret = 0; ath9k_ps_wakeup(sc); @@ -1482,8 +1436,9 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, } } - if ((vif->type == NL80211_IFTYPE_ADHOC) && - sc->nvifs > 0) { + if ((ah->opmode == NL80211_IFTYPE_ADHOC) || + ((vif->type == NL80211_IFTYPE_ADHOC) && + sc->nvifs > 0)) { ath_err(common, "Cannot create ADHOC interface when other" " interfaces already exist.\n"); ret = -EINVAL; @@ -1493,10 +1448,6 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, ath_dbg(common, ATH_DBG_CONFIG, "Attach a VIF of type: %d\n", vif->type); - /* Set the VIF opmode */ - avp->av_opmode = vif->type; - avp->av_bslot = -1; - sc->nvifs++; ath9k_do_vif_add_setup(hw, vif); @@ -1855,6 +1806,20 @@ static int ath9k_set_key(struct ieee80211_hw *hw, if (ath9k_modparam_nohwcrypt) return -ENOSPC; + if (vif->type == NL80211_IFTYPE_ADHOC && + (key->cipher == WLAN_CIPHER_SUITE_TKIP || + key->cipher == WLAN_CIPHER_SUITE_CCMP) && + !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { + /* + * For now, disable hw crypto for the RSN IBSS group keys. This + * could be optimized in the future to use a modified key cache + * design to support per-STA RX GTK, but until that gets + * implemented, use of software crypto for group addressed + * frames is a acceptable to allow RSN IBSS to be used. + */ + return -EOPNOTSUPP; + } + mutex_lock(&sc->mutex); ath9k_ps_wakeup(sc); ath_dbg(common, ATH_DBG_CONFIG, "Set HW Key\n"); @@ -1886,6 +1851,86 @@ static int ath9k_set_key(struct ieee80211_hw *hw, return ret; } +static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif) +{ + struct ath_softc *sc = data; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + struct ath_vif *avp = (void *)vif->drv_priv; + + switch (sc->sc_ah->opmode) { + case NL80211_IFTYPE_ADHOC: + /* There can be only one vif available */ + memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); + common->curaid = bss_conf->aid; + ath9k_hw_write_associd(sc->sc_ah); + /* configure beacon */ + if (bss_conf->enable_beacon) + ath_beacon_config(sc, vif); + break; + case NL80211_IFTYPE_STATION: + /* + * Skip iteration if primary station vif's bss info + * was not changed + */ + if (sc->sc_flags & SC_OP_PRIM_STA_VIF) + break; + + if (bss_conf->assoc) { + sc->sc_flags |= SC_OP_PRIM_STA_VIF; + avp->primary_sta_vif = true; + memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); + common->curaid = bss_conf->aid; + ath9k_hw_write_associd(sc->sc_ah); + ath_dbg(common, ATH_DBG_CONFIG, + "Bss Info ASSOC %d, bssid: %pM\n", + bss_conf->aid, common->curbssid); + ath_beacon_config(sc, vif); + /* Reset rssi stats */ + sc->last_rssi = ATH_RSSI_DUMMY_MARKER; + sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; + + sc->sc_flags |= SC_OP_ANI_RUN; + ath_start_ani(common); + } + break; + default: + break; + } +} + +static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + struct ath_vif *avp = (void *)vif->drv_priv; + + /* Reconfigure bss info */ + if (avp->primary_sta_vif && !bss_conf->assoc) { + ath_dbg(common, ATH_DBG_CONFIG, + "Bss Info DISASSOC %d, bssid %pM\n", + common->curaid, common->curbssid); + sc->sc_flags &= ~(SC_OP_PRIM_STA_VIF | SC_OP_BEACONS); + avp->primary_sta_vif = false; + memset(common->curbssid, 0, ETH_ALEN); + common->curaid = 0; + } + + ieee80211_iterate_active_interfaces_atomic( + sc->hw, ath9k_bss_iter, sc); + + /* + * None of station vifs are associated. + * Clear bssid & aid + */ + if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) && + !(sc->sc_flags & SC_OP_PRIM_STA_VIF)) { + ath9k_hw_write_associd(sc->sc_ah); + /* Stop ANI */ + sc->sc_flags &= ~SC_OP_ANI_RUN; + del_timer_sync(&common->ani.timer); + } +} static void ath9k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -1893,7 +1938,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, u32 changed) { struct ath_softc *sc = hw->priv; - struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ath_vif *avp = (void *)vif->drv_priv; @@ -1904,20 +1948,13 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, mutex_lock(&sc->mutex); if (changed & BSS_CHANGED_BSSID) { - /* Set BSSID */ - memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); - memcpy(avp->bssid, bss_conf->bssid, ETH_ALEN); - common->curaid = 0; - ath9k_hw_write_associd(ah); + ath9k_config_bss(sc, vif); /* Set aggregation protection mode parameters */ sc->config.ath_aggr_prot = 0; ath_dbg(common, ATH_DBG_CONFIG, "BSSID: %pM aid: 0x%x\n", common->curbssid, common->curaid); - - /* need to reconfigure the beacon */ - sc->sc_flags &= ~SC_OP_BEACONS ; } /* Enable transmission of beacons (AP, IBSS, MESH) */ @@ -1958,7 +1995,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_BEACON_INT) { - cur_conf->beacon_interval = bss_conf->beacon_int; /* * In case of AP mode, the HW TSF has to be reset * when the beacon interval changes. @@ -1970,9 +2006,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, if (!error) ath_beacon_config(sc, vif); ath9k_set_beaconing_status(sc, true); - } else { + } else ath_beacon_config(sc, vif); - } } if (changed & BSS_CHANGED_ERP_PREAMBLE) { @@ -1994,12 +2029,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, sc->sc_flags &= ~SC_OP_PROTECT_ENABLE; } - if (changed & BSS_CHANGED_ASSOC) { - ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n", - bss_conf->assoc); - ath9k_bss_assoc_info(sc, hw, vif, bss_conf); - } - mutex_unlock(&sc->mutex); ath9k_ps_restore(sc); } diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h index 5e3d7496986e..f50e2c29f71e 100644 --- a/drivers/net/wireless/ath/ath9k/phy.h +++ b/drivers/net/wireless/ath/ath9k/phy.h @@ -38,25 +38,11 @@ #define AR_PHY_CLC_Q0 0x0000ffd0 #define AR_PHY_CLC_Q0_S 5 -#define REG_WRITE_RF_ARRAY(iniarray, regData, regWr) do { \ - int r; \ - for (r = 0; r < ((iniarray)->ia_rows); r++) { \ - REG_WRITE(ah, INI_RA((iniarray), r, 0), (regData)[r]); \ - DO_DELAY(regWr); \ - } \ - } while (0) - #define ANTSWAP_AB 0x0001 #define REDUCE_CHAIN_0 0x00000050 #define REDUCE_CHAIN_1 0x00000051 #define AR_PHY_CHIP_ID 0x9818 -#define RF_BANK_SETUP(_bank, _iniarray, _col) do { \ - int i; \ - for (i = 0; i < (_iniarray)->ia_rows; i++) \ - (_bank)[i] = INI_RA((_iniarray), i, _col);; \ - } while (0) - #define AR_PHY_TIMING11_SPUR_FREQ_SD 0x3FF00000 #define AR_PHY_TIMING11_SPUR_FREQ_SD_S 20 diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index dcd19bc337d1..cfaf0a48b939 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -574,7 +574,7 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) sc->ps_flags &= ~PS_BEACON_SYNC; ath_dbg(common, ATH_DBG_PS, "Reconfigure Beacon timers based on timestamp from the AP\n"); - ath_beacon_config(sc, NULL); + ath_set_beacon(sc); } if (ath_beacon_dtim_pending_cab(skb)) { diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 8fa8acfde62e..693d543937b5 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -1396,6 +1396,7 @@ enum { #define AR_STA_ID1_PCF 0x00100000 #define AR_STA_ID1_USE_DEFANT 0x00200000 #define AR_STA_ID1_DEFANT_UPDATE 0x00400000 +#define AR_STA_ID1_AR9100_BA_FIX 0x00400000 #define AR_STA_ID1_RTS_USE_DEF 0x00800000 #define AR_STA_ID1_ACKCTS_6MB 0x01000000 #define AR_STA_ID1_BASE_RATE_11B 0x02000000 diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 88fa7fdffd05..3cea3f76e373 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1980,7 +1980,7 @@ static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf, if (ieee80211_is_data(hdr->frame_control) && (ts->ts_flags & (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN)) && - ah->tx_trig_level >= sc->sc_ah->caps.tx_triglevel_max) + ah->tx_trig_level >= sc->sc_ah->config.max_txtrig_level) tx_info->status.rates[tx_rateindex].count = hw->max_rate_tries; } @@ -2144,33 +2144,6 @@ static void ath_tx_complete_poll_work(struct work_struct *work) } else { txq->axq_tx_inprogress = true; } - } else { - /* If the queue has pending buffers, then it - * should be doing tx work (and have axq_depth). - * Shouldn't get to this state I think..but - * we do. - */ - if (!(sc->sc_flags & (SC_OP_OFFCHANNEL)) && - (txq->pending_frames > 0 || - !list_empty(&txq->axq_acq) || - txq->stopped)) { - ath_err(ath9k_hw_common(sc->sc_ah), - "txq: %p axq_qnum: %u," - " mac80211_qnum: %i" - " axq_link: %p" - " pending frames: %i" - " axq_acq empty: %i" - " stopped: %i" - " axq_depth: 0 Attempting to" - " restart tx logic.\n", - txq, txq->axq_qnum, - txq->mac80211_qnum, - txq->axq_link, - txq->pending_frames, - list_empty(&txq->axq_acq), - txq->stopped); - ath_txq_schedule(sc, txq); - } } spin_unlock_bh(&txq->axq_lock); } diff --git a/drivers/net/wireless/ath/key.c b/drivers/net/wireless/ath/key.c index 37b8e115375a..0d4f39cbdcab 100644 --- a/drivers/net/wireless/ath/key.c +++ b/drivers/net/wireless/ath/key.c @@ -23,6 +23,14 @@ #define REG_READ (common->ops->read) #define REG_WRITE(_ah, _reg, _val) (common->ops->write)(_ah, _val, _reg) +#define ENABLE_REGWRITE_BUFFER(_ah) \ + if (common->ops->enable_write_buffer) \ + common->ops->enable_write_buffer((_ah)); + +#define REGWRITE_BUFFER_FLUSH(_ah) \ + if (common->ops->write_flush) \ + common->ops->write_flush((_ah)); + #define IEEE80211_WEP_NKID 4 /* number of key ids */ @@ -42,6 +50,8 @@ bool ath_hw_keyreset(struct ath_common *common, u16 entry) keyType = REG_READ(ah, AR_KEYTABLE_TYPE(entry)); + ENABLE_REGWRITE_BUFFER(ah); + REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0); REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0); REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0); @@ -66,6 +76,8 @@ bool ath_hw_keyreset(struct ath_common *common, u16 entry) } + REGWRITE_BUFFER_FLUSH(ah); + return true; } EXPORT_SYMBOL(ath_hw_keyreset); @@ -104,9 +116,13 @@ static bool ath_hw_keysetmac(struct ath_common *common, } else { macLo = macHi = 0; } + ENABLE_REGWRITE_BUFFER(ah); + REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo); REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | unicast_flag); + REGWRITE_BUFFER_FLUSH(ah); + return true; } @@ -223,6 +239,8 @@ static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry, mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff; mic4 = get_unaligned_le32(k->kv_txmic + 4); + ENABLE_REGWRITE_BUFFER(ah); + /* Write RX[31:0] and TX[31:16] */ REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1); @@ -236,6 +254,8 @@ static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry, REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), AR_KEYTABLE_TYPE_CLR); + REGWRITE_BUFFER_FLUSH(ah); + } else { /* * TKIP uses four key cache entries (two for group @@ -258,6 +278,8 @@ static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry, mic0 = get_unaligned_le32(k->kv_mic + 0); mic2 = get_unaligned_le32(k->kv_mic + 4); + ENABLE_REGWRITE_BUFFER(ah); + /* Write MIC key[31:0] */ REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0); @@ -270,8 +292,12 @@ static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry, REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0); REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), AR_KEYTABLE_TYPE_CLR); + + REGWRITE_BUFFER_FLUSH(ah); } + ENABLE_REGWRITE_BUFFER(ah); + /* MAC address registers are reserved for the MIC entry */ REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0); REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0); @@ -283,7 +309,11 @@ static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry, */ REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); + + REGWRITE_BUFFER_FLUSH(ah); } else { + ENABLE_REGWRITE_BUFFER(ah); + /* Write key[47:0] */ REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); @@ -296,6 +326,8 @@ static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry, REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); + REGWRITE_BUFFER_FLUSH(ah); + /* Write MAC address for the entry */ (void) ath_hw_keysetmac(common, entry, mac); } diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 9d6ee836426c..3652931753e0 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -2,7 +2,7 @@ obj-$(CONFIG_IWLAGN) += iwlagn.o iwlagn-objs := iwl-agn.o iwl-agn-rs.o iwl-agn-led.o iwlagn-objs += iwl-agn-ucode.o iwl-agn-tx.o -iwlagn-objs += iwl-agn-lib.o iwl-agn-calib.o +iwlagn-objs += iwl-agn-lib.o iwl-agn-calib.o iwl-io.o iwlagn-objs += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-eeprom.o iwlagn-objs += iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 27c5007e577c..1b2799291834 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -141,7 +141,6 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE; priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE; - priv->hw_params.max_bsm_size = 0; priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; @@ -179,21 +178,16 @@ static struct iwl_lib_ops iwl1000_lib = { .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, .txq_set_sched = iwlagn_txq_set_sched, - .txq_agg_enable = iwlagn_txq_agg_enable, - .txq_agg_disable = iwlagn_txq_agg_disable, .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, .txq_free_tfd = iwl_hw_txq_free_tfd, .txq_init = iwl_hw_tx_queue_init, .rx_handler_setup = iwlagn_rx_handler_setup, .setup_deferred_work = iwlagn_setup_deferred_work, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, - .load_ucode = iwlagn_load_ucode, .dump_nic_event_log = iwl_dump_nic_event_log, .dump_nic_error_log = iwl_dump_nic_error_log, .dump_csr = iwl_dump_csr, .dump_fh = iwl_dump_fh, - .init_alive_start = iwlagn_init_alive_start, - .alive_notify = iwlagn_alive_notify, .send_tx_power = iwlagn_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .apm_ops = { @@ -215,13 +209,6 @@ static struct iwl_lib_ops iwl1000_lib = { .calib_version = iwlagn_eeprom_calib_version, .query_addr = iwlagn_eeprom_query_addr, }, - .isr_ops = { - .isr = iwl_isr_ict, - .free = iwl_free_isr_ict, - .alloc = iwl_alloc_isr_ict, - .reset = iwl_reset_ict, - .disable = iwl_disable_ict, - }, .temp_ops = { .temperature = iwlagn_temperature, }, @@ -255,7 +242,6 @@ static struct iwl_base_params iwl1000_base_params = { .eeprom_size = OTP_LOW_IMAGE_SIZE, .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, .set_l0s = true, - .use_bsm = false, .max_ll_items = OTP_MAX_LL_ITEMS_1000, .shadow_ram_support = false, .led_compensation = 51, diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index d7b6126408c9..f602af4b9408 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -147,7 +147,6 @@ static int iwl2000_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE; priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE; - priv->hw_params.max_bsm_size = 0; priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; @@ -259,8 +258,6 @@ static struct iwl_lib_ops iwl2000_lib = { .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, .txq_set_sched = iwlagn_txq_set_sched, - .txq_agg_enable = iwlagn_txq_agg_enable, - .txq_agg_disable = iwlagn_txq_agg_disable, .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, .txq_free_tfd = iwl_hw_txq_free_tfd, .txq_init = iwl_hw_tx_queue_init, @@ -268,13 +265,10 @@ static struct iwl_lib_ops iwl2000_lib = { .setup_deferred_work = iwlagn_bt_setup_deferred_work, .cancel_deferred_work = iwlagn_bt_cancel_deferred_work, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, - .load_ucode = iwlagn_load_ucode, .dump_nic_event_log = iwl_dump_nic_event_log, .dump_nic_error_log = iwl_dump_nic_error_log, .dump_csr = iwl_dump_csr, .dump_fh = iwl_dump_fh, - .init_alive_start = iwlagn_init_alive_start, - .alive_notify = iwlagn_alive_notify, .send_tx_power = iwlagn_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .set_channel_switch = iwl2030_hw_channel_switch, @@ -298,13 +292,6 @@ static struct iwl_lib_ops iwl2000_lib = { .query_addr = iwlagn_eeprom_query_addr, .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, }, - .isr_ops = { - .isr = iwl_isr_ict, - .free = iwl_free_isr_ict, - .alloc = iwl_alloc_isr_ict, - .reset = iwl_reset_ict, - .disable = iwl_disable_ict, - }, .temp_ops = { .temperature = iwlagn_temperature, }, @@ -362,7 +349,6 @@ static struct iwl_base_params iwl2000_base_params = { .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .pll_cfg_val = 0, .set_l0s = true, - .use_bsm = false, .max_ll_items = OTP_MAX_LL_ITEMS_2x00, .shadow_ram_support = true, .led_compensation = 51, @@ -386,7 +372,6 @@ static struct iwl_base_params iwl2030_base_params = { .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .pll_cfg_val = 0, .set_l0s = true, - .use_bsm = false, .max_ll_items = OTP_MAX_LL_ITEMS_2x00, .shadow_ram_support = true, .led_compensation = 57, @@ -471,37 +456,6 @@ struct iwl_cfg iwl2030_2bg_cfg = { IWL_DEVICE_2030, }; -#define IWL_DEVICE_6035 \ - .fw_name_pre = IWL2030_FW_PRE, \ - .ucode_api_max = IWL2030_UCODE_API_MAX, \ - .ucode_api_min = IWL2030_UCODE_API_MIN, \ - .eeprom_ver = EEPROM_6035_EEPROM_VERSION, \ - .eeprom_calib_ver = EEPROM_6035_TX_POWER_VERSION, \ - .ops = &iwl2030_ops, \ - .mod_params = &iwlagn_mod_params, \ - .base_params = &iwl2030_base_params, \ - .bt_params = &iwl2030_bt_params, \ - .need_dc_calib = true, \ - .need_temp_offset_calib = true, \ - .led_mode = IWL_LED_RF_STATE, \ - .adv_pm = true \ - -struct iwl_cfg iwl6035_2agn_cfg = { - .name = "2000 Series 2x2 AGN/BT", - IWL_DEVICE_6035, - .ht_params = &iwl2000_ht_params, -}; - -struct iwl_cfg iwl6035_2abg_cfg = { - .name = "2000 Series 2x2 ABG/BT", - IWL_DEVICE_6035, -}; - -struct iwl_cfg iwl6035_2bg_cfg = { - .name = "2000 Series 2x2 BG/BT", - IWL_DEVICE_6035, -}; - #define IWL_DEVICE_200 \ .fw_name_pre = IWL200_FW_PRE, \ .ucode_api_max = IWL200_UCODE_API_MAX, \ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h index 3975e45e7500..05ad47628b63 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 22e045b5bcee..66f5fe8fe1ac 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -185,7 +185,6 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE; priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE; - priv->hw_params.max_bsm_size = 0; priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; @@ -231,7 +230,6 @@ static int iwl5150_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE; priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE; - priv->hw_params.max_bsm_size = 0; priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; @@ -348,8 +346,6 @@ static struct iwl_lib_ops iwl5000_lib = { .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, .txq_set_sched = iwlagn_txq_set_sched, - .txq_agg_enable = iwlagn_txq_agg_enable, - .txq_agg_disable = iwlagn_txq_agg_disable, .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, .txq_free_tfd = iwl_hw_txq_free_tfd, .txq_init = iwl_hw_tx_queue_init, @@ -360,9 +356,6 @@ static struct iwl_lib_ops iwl5000_lib = { .dump_nic_error_log = iwl_dump_nic_error_log, .dump_csr = iwl_dump_csr, .dump_fh = iwl_dump_fh, - .load_ucode = iwlagn_load_ucode, - .init_alive_start = iwlagn_init_alive_start, - .alive_notify = iwlagn_alive_notify, .send_tx_power = iwlagn_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .set_channel_switch = iwl5000_hw_channel_switch, @@ -385,13 +378,6 @@ static struct iwl_lib_ops iwl5000_lib = { .calib_version = iwlagn_eeprom_calib_version, .query_addr = iwlagn_eeprom_query_addr, }, - .isr_ops = { - .isr = iwl_isr_ict, - .free = iwl_free_isr_ict, - .alloc = iwl_alloc_isr_ict, - .reset = iwl_reset_ict, - .disable = iwl_disable_ict, - }, .temp_ops = { .temperature = iwlagn_temperature, }, @@ -416,8 +402,6 @@ static struct iwl_lib_ops iwl5150_lib = { .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, .txq_set_sched = iwlagn_txq_set_sched, - .txq_agg_enable = iwlagn_txq_agg_enable, - .txq_agg_disable = iwlagn_txq_agg_disable, .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, .txq_free_tfd = iwl_hw_txq_free_tfd, .txq_init = iwl_hw_tx_queue_init, @@ -427,9 +411,6 @@ static struct iwl_lib_ops iwl5150_lib = { .dump_nic_event_log = iwl_dump_nic_event_log, .dump_nic_error_log = iwl_dump_nic_error_log, .dump_csr = iwl_dump_csr, - .load_ucode = iwlagn_load_ucode, - .init_alive_start = iwlagn_init_alive_start, - .alive_notify = iwlagn_alive_notify, .send_tx_power = iwlagn_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .set_channel_switch = iwl5000_hw_channel_switch, @@ -452,13 +433,6 @@ static struct iwl_lib_ops iwl5150_lib = { .calib_version = iwlagn_eeprom_calib_version, .query_addr = iwlagn_eeprom_query_addr, }, - .isr_ops = { - .isr = iwl_isr_ict, - .free = iwl_free_isr_ict, - .alloc = iwl_alloc_isr_ict, - .reset = iwl_reset_ict, - .disable = iwl_disable_ict, - }, .temp_ops = { .temperature = iwl5150_temperature, }, @@ -500,7 +474,6 @@ static struct iwl_base_params iwl5000_base_params = { .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, .set_l0s = true, - .use_bsm = false, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000-hw.h b/drivers/net/wireless/iwlwifi/iwl-6000-hw.h index 47891e16a758..b27986e57c92 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-6000-hw.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index a745b01c0ec1..24d105b29aec 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -176,7 +176,6 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE; priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE; - priv->hw_params.max_bsm_size = 0; priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; @@ -288,21 +287,16 @@ static struct iwl_lib_ops iwl6000_lib = { .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, .txq_set_sched = iwlagn_txq_set_sched, - .txq_agg_enable = iwlagn_txq_agg_enable, - .txq_agg_disable = iwlagn_txq_agg_disable, .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, .txq_free_tfd = iwl_hw_txq_free_tfd, .txq_init = iwl_hw_tx_queue_init, .rx_handler_setup = iwlagn_rx_handler_setup, .setup_deferred_work = iwlagn_setup_deferred_work, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, - .load_ucode = iwlagn_load_ucode, .dump_nic_event_log = iwl_dump_nic_event_log, .dump_nic_error_log = iwl_dump_nic_error_log, .dump_csr = iwl_dump_csr, .dump_fh = iwl_dump_fh, - .init_alive_start = iwlagn_init_alive_start, - .alive_notify = iwlagn_alive_notify, .send_tx_power = iwlagn_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .set_channel_switch = iwl6000_hw_channel_switch, @@ -326,13 +320,6 @@ static struct iwl_lib_ops iwl6000_lib = { .query_addr = iwlagn_eeprom_query_addr, .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, }, - .isr_ops = { - .isr = iwl_isr_ict, - .free = iwl_free_isr_ict, - .alloc = iwl_alloc_isr_ict, - .reset = iwl_reset_ict, - .disable = iwl_disable_ict, - }, .temp_ops = { .temperature = iwlagn_temperature, }, @@ -357,8 +344,6 @@ static struct iwl_lib_ops iwl6030_lib = { .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, .txq_set_sched = iwlagn_txq_set_sched, - .txq_agg_enable = iwlagn_txq_agg_enable, - .txq_agg_disable = iwlagn_txq_agg_disable, .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, .txq_free_tfd = iwl_hw_txq_free_tfd, .txq_init = iwl_hw_tx_queue_init, @@ -366,13 +351,10 @@ static struct iwl_lib_ops iwl6030_lib = { .setup_deferred_work = iwlagn_bt_setup_deferred_work, .cancel_deferred_work = iwlagn_bt_cancel_deferred_work, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, - .load_ucode = iwlagn_load_ucode, .dump_nic_event_log = iwl_dump_nic_event_log, .dump_nic_error_log = iwl_dump_nic_error_log, .dump_csr = iwl_dump_csr, .dump_fh = iwl_dump_fh, - .init_alive_start = iwlagn_init_alive_start, - .alive_notify = iwlagn_alive_notify, .send_tx_power = iwlagn_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .set_channel_switch = iwl6000_hw_channel_switch, @@ -396,13 +378,6 @@ static struct iwl_lib_ops iwl6030_lib = { .query_addr = iwlagn_eeprom_query_addr, .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, }, - .isr_ops = { - .isr = iwl_isr_ict, - .free = iwl_free_isr_ict, - .alloc = iwl_alloc_isr_ict, - .reset = iwl_reset_ict, - .disable = iwl_disable_ict, - }, .temp_ops = { .temperature = iwlagn_temperature, }, @@ -470,7 +445,6 @@ static struct iwl_base_params iwl6000_base_params = { .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .pll_cfg_val = 0, .set_l0s = true, - .use_bsm = false, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, .led_compensation = 51, @@ -493,7 +467,6 @@ static struct iwl_base_params iwl6050_base_params = { .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .pll_cfg_val = 0, .set_l0s = true, - .use_bsm = false, .max_ll_items = OTP_MAX_LL_ITEMS_6x50, .shadow_ram_support = true, .led_compensation = 51, @@ -515,7 +488,6 @@ static struct iwl_base_params iwl6000_g2_base_params = { .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .pll_cfg_val = 0, .set_l0s = true, - .use_bsm = false, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, .led_compensation = 57, @@ -613,6 +585,22 @@ struct iwl_cfg iwl6030_2bg_cfg = { IWL_DEVICE_6030, }; +struct iwl_cfg iwl6035_2agn_cfg = { + .name = "6035 Series 2x2 AGN/BT", + IWL_DEVICE_6030, + .ht_params = &iwl6000_ht_params, +}; + +struct iwl_cfg iwl6035_2abg_cfg = { + .name = "6035 Series 2x2 ABG/BT", + IWL_DEVICE_6030, +}; + +struct iwl_cfg iwl6035_2bg_cfg = { + .name = "6035 Series 2x2 BG/BT", + IWL_DEVICE_6030, +}; + struct iwl_cfg iwl1030_bgn_cfg = { .name = "Intel(R) Centrino(R) Wireless-N 1030 BGN", IWL_DEVICE_6030, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c index 9006293e740c..7b761de77b0a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.h b/drivers/net/wireless/iwlwifi/iwl-agn-calib.h index e37ae7261630..ef4d5079a7ed 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c index b500aaae53ec..d1834aa7edf0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c @@ -1,30 +1,30 @@ /****************************************************************************** -* -* GPL LICENSE SUMMARY -* -* Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of version 2 of the GNU General Public License as -* published by the Free Software Foundation. -* -* This program is distributed in the hope that it will be useful, but -* WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, -* USA -* -* The full GNU General Public License is included in this distribution -* in the file called LICENSE.GPL. -* -* Contact Information: -* Intel Linux Wireless <ilw@linux.intel.com> -* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*****************************************************************************/ + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Intel Linux Wireless <ilw@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + *****************************************************************************/ #include "iwl-agn.h" #include "iwl-agn-debugfs.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h index f2573b5486cd..9a3f329e508f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c index 27b5a3eec9dc..3bcaa10f9929 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -103,7 +103,7 @@ int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv) CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, EEPROM_SEM_TIMEOUT); if (ret >= 0) { - IWL_DEBUG_IO(priv, + IWL_DEBUG_EEPROM(priv, "Acquired semaphore after %d tries.\n", count+1); return ret; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c index 41543ad4cb84..861cc93957a9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h index a52b82c8e7a6..7bd19f4e66de 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ict.c b/drivers/net/wireless/iwlwifi/iwl-agn-ict.c index ed0148d714de..0d5fda44c3a3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ict.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ict.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -59,8 +59,6 @@ void iwl_free_isr_ict(struct iwl_priv *priv) int iwl_alloc_isr_ict(struct iwl_priv *priv) { - if (priv->cfg->base_params->use_isr_legacy) - return 0; /* allocate shrared data table */ priv->_agn.ict_tbl_vir = dma_alloc_coherent(&priv->pci_dev->dev, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-led.c b/drivers/net/wireless/iwlwifi/iwl-agn-led.c index c1190d965614..4bb877e600c7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-led.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-led.h b/drivers/net/wireless/iwlwifi/iwl-agn-led.h index 96f323dc5dd6..c0b7611b72c3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-led.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-led.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 08ccb9496f76..9e47be6a7393 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -652,8 +652,7 @@ int iwlagn_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */ u32 rb_timeout = 0; /* FIXME: RX_RB_TIMEOUT for all devices? */ - if (!priv->cfg->base_params->use_isr_legacy) - rb_timeout = RX_RB_TIMEOUT; + rb_timeout = RX_RB_TIMEOUT; if (priv->cfg->mod_params->amsdu_size_8K) rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K; @@ -913,7 +912,6 @@ void iwlagn_rx_allocate(struct iwl_priv *priv, gfp_t priority) list_add_tail(&rxb->list, &rxq->rx_free); rxq->free_count++; - priv->alloc_rxb_page++; spin_unlock_irqrestore(&rxq->lock, flags); } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index d03b4734c892..dbe6295bbf23 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -115,13 +115,18 @@ const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = { /* FIXME:RS: ^^ should be INV (legacy) */ }; +static inline u8 rs_extract_rate(u32 rate_n_flags) +{ + return (u8)(rate_n_flags & RATE_MCS_RATE_MSK); +} + static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) { int idx = 0; /* HT rate format */ if (rate_n_flags & RATE_MCS_HT_MSK) { - idx = (rate_n_flags & 0xff); + idx = rs_extract_rate(rate_n_flags); if (idx >= IWL_RATE_MIMO3_6M_PLCP) idx = idx - IWL_RATE_MIMO3_6M_PLCP; @@ -138,7 +143,8 @@ static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) /* legacy rate format, search for match in table */ } else { for (idx = 0; idx < ARRAY_SIZE(iwl_rates); idx++) - if (iwl_rates[idx].plcp == (rate_n_flags & 0xFF)) + if (iwl_rates[idx].plcp == + rs_extract_rate(rate_n_flags)) return idx; } @@ -239,11 +245,6 @@ static const struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = { #define MCS_INDEX_PER_STREAM (8) -static inline u8 rs_extract_rate(u32 rate_n_flags) -{ - return (u8)(rate_n_flags & 0xFF); -} - static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window) { window->data = 0; @@ -2770,16 +2771,13 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta, gfp_t gfp) { - struct iwl_lq_sta *lq_sta; struct iwl_station_priv *sta_priv = (struct iwl_station_priv *) sta->drv_priv; struct iwl_priv *priv; priv = (struct iwl_priv *)priv_rate; IWL_DEBUG_RATE(priv, "create station rate scale window\n"); - lq_sta = &sta_priv->lq_sta; - - return lq_sta; + return &sta_priv->lq_sta; } /* @@ -2912,7 +2910,8 @@ static void rs_fill_link_cmd(struct iwl_priv *priv, ant_toggle_cnt = 1; repeat_rate = IWL_NUMBER_TRY; } else { - repeat_rate = IWL_HT_NUMBER_TRY; + repeat_rate = min(IWL_HT_NUMBER_TRY, + LINK_QUAL_AGG_DISABLE_START_DEF - 1); } lq_cmd->general_params.mimo_delimiter = @@ -3257,7 +3256,6 @@ static ssize_t rs_sta_dbgfs_rate_scale_data_read(struct file *file, { char buff[120]; int desc = 0; - ssize_t ret; struct iwl_lq_sta *lq_sta = file->private_data; struct iwl_priv *priv; @@ -3274,8 +3272,7 @@ static ssize_t rs_sta_dbgfs_rate_scale_data_read(struct file *file, "Bit Rate= %d Mb/s\n", iwl_rates[lq_sta->last_txrate_idx].ieee >> 1); - ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc); - return ret; + return simple_read_from_buffer(user_buf, count, ppos, buff, desc); } static const struct file_operations rs_sta_dbgfs_rate_scale_data_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h index 184828c72b31..69a29932babc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -41,20 +41,6 @@ struct iwl_rate_info { u8 next_rs_tgg; /* next rate used in TGG rs algo */ }; -struct iwl3945_rate_info { - u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */ - u8 ieee; /* MAC header: IWL_RATE_6M_IEEE, etc. */ - u8 prev_ieee; /* previous rate in IEEE speeds */ - u8 next_ieee; /* next rate in IEEE speeds */ - u8 prev_rs; /* previous rate used in rs algo */ - u8 next_rs; /* next rate used in rs algo */ - u8 prev_rs_tgg; /* previous rate used in TGG rs algo */ - u8 next_rs_tgg; /* next rate used in TGG rs algo */ - u8 table_rs_index; /* index in rate scale table cmd */ - u8 prev_table_rs; /* prev in rate table cmd */ -}; - - /* * These serve as indexes into * struct iwl_rate_info iwl_rates[IWL_RATE_COUNT]; @@ -75,7 +61,6 @@ enum { IWL_RATE_60M_INDEX, IWL_RATE_COUNT, /*FIXME:RS:change to IWL_RATE_INDEX_COUNT,*/ IWL_RATE_COUNT_LEGACY = IWL_RATE_COUNT - 1, /* Excluding 60M */ - IWL_RATE_COUNT_3945 = IWL_RATE_COUNT - 1, IWL_RATE_INVM_INDEX = IWL_RATE_COUNT, IWL_RATE_INVALID = IWL_RATE_COUNT, }; @@ -213,7 +198,6 @@ enum { IWL_CCK_BASIC_RATES_MASK) #define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1) -#define IWL_RATES_MASK_3945 ((1 << IWL_RATE_COUNT_3945) - 1) #define IWL_INVALID_VALUE -1 @@ -453,19 +437,9 @@ static inline u8 first_antenna(u8 mask) } -/** - * iwl3945_rate_scale_init - Initialize the rate scale table based on assoc info - * - * The specific throughput table used is based on the type of network - * the associated with, including A, B, G, and G w/ TGG protection - */ -extern void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id); - /* Initialize station's rate scaling information after adding station */ extern void iwl_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 sta_id); -extern void iwl3945_rs_rate_init(struct iwl_priv *priv, - struct ieee80211_sta *sta, u8 sta_id); /** * iwl_rate_control_register - Register the rate control algorithm callbacks @@ -478,7 +452,6 @@ extern void iwl3945_rs_rate_init(struct iwl_priv *priv, * */ extern int iwlagn_rate_control_register(void); -extern int iwl3945_rate_control_register(void); /** * iwl_rate_control_unregister - Unregister the rate control callbacks @@ -487,6 +460,5 @@ extern int iwl3945_rate_control_register(void); * the driver is unloaded. */ extern void iwlagn_rate_control_unregister(void); -extern void iwl3945_rate_control_unregister(void); #endif /* __iwl_agn__rs__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index dfdbea6e8f99..c335ee6883ee 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c index 35f085ac336b..079275f2c64d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -474,7 +474,7 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv, memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key)); memset(&priv->stations[sta_id].sta.key, 0, - sizeof(struct iwl4965_keyinfo)); + sizeof(struct iwl_keyinfo)); priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC | STA_KEY_FLG_INVALID; priv->stations[sta_id].sta.key.key_offset = WEP_INVALID_OFFSET; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tt.c b/drivers/net/wireless/iwlwifi/iwl-agn-tt.c index e3a8216a033c..348f74f1c8e8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tt.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tt.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tt.h b/drivers/net/wireless/iwlwifi/iwl-agn-tt.h index d55060427cac..d118ed29bf3f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tt.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tt.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index a709d05c5868..2816b432c62f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -222,13 +222,8 @@ void iwlagn_tx_queue_set_status(struct iwl_priv *priv, scd_retry ? "BA" : "AC/CMD", txq_id, tx_fifo_id); } -int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, - int tx_fifo, int sta_id, int tid, u16 ssn_idx) +static int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, int sta_id, int tid) { - unsigned long flags; - u16 ra_tid; - int ret; - if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) || (IWLAGN_FIRST_AMPDU_QUEUE + priv->cfg->base_params->num_of_ampdu_queues <= txq_id)) { @@ -240,12 +235,33 @@ int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, return -EINVAL; } - ra_tid = BUILD_RAxTID(sta_id, tid); - /* Modify device's station table to Tx this TID */ - ret = iwl_sta_tx_modify_enable_tid(priv, sta_id, tid); - if (ret) - return ret; + return iwl_sta_tx_modify_enable_tid(priv, sta_id, tid); +} + +void iwlagn_txq_agg_queue_setup(struct iwl_priv *priv, + struct ieee80211_sta *sta, + int tid, int frame_limit) +{ + int sta_id, tx_fifo, txq_id, ssn_idx; + u16 ra_tid; + unsigned long flags; + struct iwl_tid_data *tid_data; + + sta_id = iwl_sta_id(sta); + if (WARN_ON(sta_id == IWL_INVALID_STATION)) + return; + if (WARN_ON(tid >= MAX_TID_COUNT)) + return; + + spin_lock_irqsave(&priv->sta_lock, flags); + tid_data = &priv->stations[sta_id].tid[tid]; + ssn_idx = SEQ_TO_SN(tid_data->seq_number); + txq_id = tid_data->agg.txq_id; + tx_fifo = tid_data->agg.tx_fifo; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + ra_tid = BUILD_RAxTID(sta_id, tid); spin_lock_irqsave(&priv->lock, flags); @@ -271,10 +287,10 @@ int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, iwl_write_targ_mem(priv, priv->scd_base_addr + IWLAGN_SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32), - ((SCD_WIN_SIZE << + ((frame_limit << IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) & IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) | - ((SCD_FRAME_LIMIT << + ((frame_limit << IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK)); @@ -284,12 +300,10 @@ int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, iwlagn_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1); spin_unlock_irqrestore(&priv->lock, flags); - - return 0; } -int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, - u16 ssn_idx, u8 tx_fifo) +static int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, + u16 ssn_idx, u8 tx_fifo) { if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) || (IWLAGN_FIRST_AMPDU_QUEUE + @@ -1034,11 +1048,11 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, tid_data = &priv->stations[sta_id].tid[tid]; *ssn = SEQ_TO_SN(tid_data->seq_number); tid_data->agg.txq_id = txq_id; + tid_data->agg.tx_fifo = tx_fifo; iwl_set_swq_id(&priv->txq[txq_id], get_ac_from_tid(tid), txq_id); spin_unlock_irqrestore(&priv->sta_lock, flags); - ret = priv->cfg->ops->lib->txq_agg_enable(priv, txq_id, tx_fifo, - sta_id, tid, *ssn); + ret = iwlagn_txq_agg_enable(priv, txq_id, sta_id, tid); if (ret) return ret; @@ -1125,8 +1139,7 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, * to deactivate the uCode queue, just return "success" to allow * mac80211 to clean up it own data. */ - priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, ssn, - tx_fifo_id); + iwlagn_txq_agg_disable(priv, txq_id, ssn, tx_fifo_id); spin_unlock_irqrestore(&priv->lock, flags); ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); @@ -1155,8 +1168,7 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv, u16 ssn = SEQ_TO_SN(tid_data->seq_number); int tx_fifo = get_fifo_from_tid(ctx, tid); IWL_DEBUG_HT(priv, "HW queue empty: continue DELBA flow\n"); - priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, - ssn, tx_fifo); + iwlagn_txq_agg_disable(priv, txq_id, ssn, tx_fifo); tid_data->agg.state = IWL_AGG_OFF; ieee80211_stop_tx_ba_cb_irqsafe(ctx->vif, addr, tid); } @@ -1251,11 +1263,11 @@ static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv, struct iwl_compressed_ba_resp *ba_resp) { - int i, sh, ack; + int sh; u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl); u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); - int successes = 0; struct ieee80211_tx_info *info; + u64 bitmap, sent_bitmap; if (unlikely(!agg->wait_for_ba)) { if (unlikely(ba_resp->bitmap)) @@ -1269,70 +1281,42 @@ static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv, /* Calculate shift to align block-ack bits with our Tx window bits */ sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl >> 4); - if (sh < 0) /* tbw something is wrong with indices */ + if (sh < 0) sh += 0x100; - if (agg->frame_count > (64 - sh)) { - IWL_DEBUG_TX_REPLY(priv, "more frames than bitmap size"); - return -1; - } - if (!priv->cfg->base_params->no_agg_framecnt_info && ba_resp->txed) { + /* + * Check for success or failure according to the + * transmitted bitmap and block-ack bitmap + */ + bitmap = le64_to_cpu(ba_resp->bitmap) >> sh; + sent_bitmap = bitmap & agg->bitmap; + + /* Sanity check values reported by uCode */ + if (ba_resp->txed_2_done > ba_resp->txed) { + IWL_DEBUG_TX_REPLY(priv, + "bogus sent(%d) and ack(%d) count\n", + ba_resp->txed, ba_resp->txed_2_done); /* - * sent and ack information provided by uCode - * use it instead of figure out ourself + * set txed_2_done = txed, + * so it won't impact rate scale */ - if (ba_resp->txed_2_done > ba_resp->txed) { - IWL_DEBUG_TX_REPLY(priv, - "bogus sent(%d) and ack(%d) count\n", - ba_resp->txed, ba_resp->txed_2_done); - /* - * set txed_2_done = txed, - * so it won't impact rate scale - */ - ba_resp->txed = ba_resp->txed_2_done; - } - IWL_DEBUG_HT(priv, "agg frames sent:%d, acked:%d\n", - ba_resp->txed, ba_resp->txed_2_done); - } else { - u64 bitmap, sent_bitmap; - - /* don't use 64-bit values for now */ - bitmap = le64_to_cpu(ba_resp->bitmap) >> sh; - - /* check for success or failure according to the - * transmitted bitmap and block-ack bitmap */ - sent_bitmap = bitmap & agg->bitmap; - - /* For each frame attempted in aggregation, - * update driver's record of tx frame's status. */ - i = 0; - while (sent_bitmap) { - ack = sent_bitmap & 1ULL; - successes += ack; - IWL_DEBUG_TX_REPLY(priv, "%s ON i=%d idx=%d raw=%d\n", - ack ? "ACK" : "NACK", i, - (agg->start_idx + i) & 0xff, - agg->start_idx + i); - sent_bitmap >>= 1; - ++i; - } + ba_resp->txed = ba_resp->txed_2_done; + } + IWL_DEBUG_HT(priv, "agg frames sent:%d, acked:%d\n", + ba_resp->txed, ba_resp->txed_2_done); - IWL_DEBUG_TX_REPLY(priv, "Bitmap %llx\n", - (unsigned long long)bitmap); + /* Find the first ACKed frame to store the TX status */ + while (sent_bitmap && !(sent_bitmap & 1)) { + agg->start_idx = (agg->start_idx + 1) & 0xff; + sent_bitmap >>= 1; } info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb); memset(&info->status, 0, sizeof(info->status)); info->flags |= IEEE80211_TX_STAT_ACK; info->flags |= IEEE80211_TX_STAT_AMPDU; - if (!priv->cfg->base_params->no_agg_framecnt_info && ba_resp->txed) { - info->status.ampdu_ack_len = ba_resp->txed_2_done; - info->status.ampdu_len = ba_resp->txed; - - } else { - info->status.ampdu_ack_len = successes; - info->status.ampdu_len = agg->frame_count; - } + info->status.ampdu_ack_len = ba_resp->txed_2_done; + info->status.ampdu_len = ba_resp->txed; iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags, info); return 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c index d807e5e2b718..01a6d2fc795c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -311,14 +311,14 @@ void iwlagn_init_alive_start(struct iwl_priv *priv) /* initialize uCode was loaded... verify inst image. * This is a paranoid check, because we would not have gotten the * "initialize" alive if code weren't properly loaded. */ - if (iwl_verify_ucode(priv)) { + if (iwl_verify_ucode(priv, &priv->ucode_init)) { /* Runtime instruction load was bad; * take it all the way back down so we can try again */ IWL_DEBUG_INFO(priv, "Bad \"initialize\" uCode load.\n"); goto restart; } - ret = priv->cfg->ops->lib->alive_notify(priv); + ret = iwlagn_alive_notify(priv); if (ret) { IWL_WARN(priv, "Could not complete ALIVE transition: %d\n", ret); @@ -432,6 +432,7 @@ int iwlagn_alive_notify(struct iwl_priv *priv) unsigned long flags; int i, chan; u32 reg_val; + int ret; spin_lock_irqsave(&priv->lock, flags); @@ -527,12 +528,15 @@ int iwlagn_alive_notify(struct iwl_priv *priv) iwl_clear_bits_prph(priv, APMG_PCIDEV_STT_REG, APMG_PCIDEV_STT_VAL_L1_ACT_DIS); - iwlagn_send_wimax_coex(priv); + ret = iwlagn_send_wimax_coex(priv); + if (ret) + return ret; - iwlagn_set_Xtal_calib(priv); - iwl_send_calib_results(priv); + ret = iwlagn_set_Xtal_calib(priv); + if (ret) + return ret; - return 0; + return iwl_send_calib_results(priv); } @@ -541,11 +545,12 @@ int iwlagn_alive_notify(struct iwl_priv *priv) * using sample data 100 bytes apart. If these sample points are good, * it's a pretty good bet that everything between them is good, too. */ -static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len) +static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, + struct fw_desc *fw_desc) { + __le32 *image = (__le32 *)fw_desc->v_addr; + u32 len = fw_desc->len; u32 val; - int ret = 0; - u32 errcnt = 0; u32 i; IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len); @@ -556,104 +561,55 @@ static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 * if IWL_DL_IO is set */ iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, i + IWLAGN_RTC_INST_LOWER_BOUND); - val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); - if (val != le32_to_cpu(*image)) { - ret = -EIO; - errcnt++; - if (errcnt >= 3) - break; - } + val = iwl_read32(priv, HBUS_TARG_MEM_RDAT); + if (val != le32_to_cpu(*image)) + return -EIO; } - return ret; + return 0; } -/** - * iwlcore_verify_inst_full - verify runtime uCode image in card vs. host, - * looking at all data. - */ -static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 *image, - u32 len) +static void iwl_print_mismatch_inst(struct iwl_priv *priv, + struct fw_desc *fw_desc) { + __le32 *image = (__le32 *)fw_desc->v_addr; + u32 len = fw_desc->len; u32 val; - u32 save_len = len; - int ret = 0; - u32 errcnt; + u32 offs; + int errors = 0; IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len); iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, IWLAGN_RTC_INST_LOWER_BOUND); - errcnt = 0; - for (; len > 0; len -= sizeof(u32), image++) { + for (offs = 0; + offs < len && errors < 20; + offs += sizeof(u32), image++) { /* read data comes through single port, auto-incr addr */ - /* NOTE: Use the debugless read so we don't flood kernel log - * if IWL_DL_IO is set */ - val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); + val = iwl_read32(priv, HBUS_TARG_MEM_RDAT); if (val != le32_to_cpu(*image)) { - IWL_ERR(priv, "uCode INST section is invalid at " - "offset 0x%x, is 0x%x, s/b 0x%x\n", - save_len - len, val, le32_to_cpu(*image)); - ret = -EIO; - errcnt++; - if (errcnt >= 20) - break; + IWL_ERR(priv, "uCode INST section at " + "offset 0x%x, is 0x%x, s/b 0x%x\n", + offs, val, le32_to_cpu(*image)); + errors++; } } - - if (!errcnt) - IWL_DEBUG_INFO(priv, - "ucode image in INSTRUCTION memory is good\n"); - - return ret; } /** * iwl_verify_ucode - determine which instruction image is in SRAM, * and verify its contents */ -int iwl_verify_ucode(struct iwl_priv *priv) +int iwl_verify_ucode(struct iwl_priv *priv, struct fw_desc *fw_desc) { - __le32 *image; - u32 len; - int ret; - - /* Try bootstrap */ - image = (__le32 *)priv->ucode_boot.v_addr; - len = priv->ucode_boot.len; - ret = iwlcore_verify_inst_sparse(priv, image, len); - if (!ret) { - IWL_DEBUG_INFO(priv, "Bootstrap uCode is good in inst SRAM\n"); - return 0; - } - - /* Try initialize */ - image = (__le32 *)priv->ucode_init.v_addr; - len = priv->ucode_init.len; - ret = iwlcore_verify_inst_sparse(priv, image, len); - if (!ret) { - IWL_DEBUG_INFO(priv, "Initialize uCode is good in inst SRAM\n"); - return 0; - } - - /* Try runtime/protocol */ - image = (__le32 *)priv->ucode_code.v_addr; - len = priv->ucode_code.len; - ret = iwlcore_verify_inst_sparse(priv, image, len); - if (!ret) { - IWL_DEBUG_INFO(priv, "Runtime uCode is good in inst SRAM\n"); + if (!iwlcore_verify_inst_sparse(priv, fw_desc)) { + IWL_DEBUG_INFO(priv, "uCode is good in inst SRAM\n"); return 0; } - IWL_ERR(priv, "NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n"); + IWL_ERR(priv, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n"); - /* Since nothing seems to match, show first several data entries in - * instruction SRAM, so maybe visual inspection will give a clue. - * Selection of bootstrap image (vs. other images) is arbitrary. */ - image = (__le32 *)priv->ucode_boot.v_addr; - len = priv->ucode_boot.len; - ret = iwl_verify_inst_full(priv, image, len); - - return ret; + iwl_print_mismatch_inst(priv, fw_desc); + return -EIO; } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 321b18b59135..60bfde75ce87 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -409,7 +409,7 @@ int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, * Tell nic where to find circular buffer of Tx Frame Descriptors for * given Tx queue, and enable the DMA channel used for that queue. * - * 4965 supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA + * supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA * channels supported in hardware. */ int iwl_hw_tx_queue_init(struct iwl_priv *priv, @@ -483,12 +483,14 @@ static void iwl_bg_bt_full_concurrency(struct work_struct *work) container_of(work, struct iwl_priv, bt_full_concurrency); struct iwl_rxon_context *ctx; + mutex_lock(&priv->mutex); + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; + goto out; /* dont send host command if rf-kill is on */ if (!iwl_is_ready_rf(priv)) - return; + goto out; IWL_DEBUG_INFO(priv, "BT coex in %s mode\n", priv->bt_full_concurrent ? @@ -498,15 +500,15 @@ static void iwl_bg_bt_full_concurrency(struct work_struct *work) * LQ & RXON updated cmds must be sent before BT Config cmd * to avoid 3-wire collisions */ - mutex_lock(&priv->mutex); for_each_context(priv, ctx) { if (priv->cfg->ops->hcmd->set_rxon_chain) priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); iwlcore_commit_rxon(priv, ctx); } - mutex_unlock(&priv->mutex); priv->cfg->ops->hcmd->send_bt_config(priv); +out: + mutex_unlock(&priv->mutex); } /** @@ -556,7 +558,7 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base, } /* Set starting address; reads will auto-increment */ - _iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, ptr); + iwl_write32(priv, HBUS_TARG_MEM_RADDR, ptr); rmb(); /* @@ -564,13 +566,13 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base, * place event id # at far right for easier visual parsing. */ for (i = 0; i < num_events; i++) { - ev = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); - time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); + ev = iwl_read32(priv, HBUS_TARG_MEM_RDAT); + time = iwl_read32(priv, HBUS_TARG_MEM_RDAT); if (mode == 0) { trace_iwlwifi_dev_ucode_cont_event(priv, 0, time, ev); } else { - data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); + data = iwl_read32(priv, HBUS_TARG_MEM_RDAT); trace_iwlwifi_dev_ucode_cont_event(priv, time, data, ev); } @@ -588,10 +590,7 @@ static void iwl_continuous_event_trace(struct iwl_priv *priv) u32 num_wraps; /* # times uCode wrapped to top of log */ u32 next_entry; /* index of next entry to be written by uCode */ - if (priv->ucode_type == UCODE_INIT) - base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr); - else - base = le32_to_cpu(priv->card_alive.log_event_table_ptr); + base = priv->device_pointers.error_event_table; if (priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { capacity = iwl_read_targ_mem(priv, base); num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32))); @@ -845,191 +844,6 @@ static inline void iwl_synchronize_irq(struct iwl_priv *priv) tasklet_kill(&priv->irq_tasklet); } -static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) -{ - u32 inta, handled = 0; - u32 inta_fh; - unsigned long flags; - u32 i; -#ifdef CONFIG_IWLWIFI_DEBUG - u32 inta_mask; -#endif - - spin_lock_irqsave(&priv->lock, flags); - - /* Ack/clear/reset pending uCode interrupts. - * Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS, - * and will clear only when CSR_FH_INT_STATUS gets cleared. */ - inta = iwl_read32(priv, CSR_INT); - iwl_write32(priv, CSR_INT, inta); - - /* Ack/clear/reset pending flow-handler (DMA) interrupts. - * Any new interrupts that happen after this, either while we're - * in this tasklet, or later, will show up in next ISR/tasklet. */ - inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); - iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh); - -#ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_get_debug_level(priv) & IWL_DL_ISR) { - /* just for debug */ - inta_mask = iwl_read32(priv, CSR_INT_MASK); - IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", - inta, inta_mask, inta_fh); - } -#endif - - spin_unlock_irqrestore(&priv->lock, flags); - - /* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not - * atomic, make sure that inta covers all the interrupts that - * we've discovered, even if FH interrupt came in just after - * reading CSR_INT. */ - if (inta_fh & CSR49_FH_INT_RX_MASK) - inta |= CSR_INT_BIT_FH_RX; - if (inta_fh & CSR49_FH_INT_TX_MASK) - inta |= CSR_INT_BIT_FH_TX; - - /* Now service all interrupt bits discovered above. */ - if (inta & CSR_INT_BIT_HW_ERR) { - IWL_ERR(priv, "Hardware error detected. Restarting.\n"); - - /* Tell the device to stop sending interrupts */ - iwl_disable_interrupts(priv); - - priv->isr_stats.hw++; - iwl_irq_handle_error(priv); - - handled |= CSR_INT_BIT_HW_ERR; - - return; - } - -#ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { - /* NIC fires this, but we don't use it, redundant with WAKEUP */ - if (inta & CSR_INT_BIT_SCD) { - IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " - "the frame/frames.\n"); - priv->isr_stats.sch++; - } - - /* Alive notification via Rx interrupt will do the real work */ - if (inta & CSR_INT_BIT_ALIVE) { - IWL_DEBUG_ISR(priv, "Alive interrupt\n"); - priv->isr_stats.alive++; - } - } -#endif - /* Safely ignore these bits for debug checks below */ - inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE); - - /* HW RF KILL switch toggled */ - if (inta & CSR_INT_BIT_RF_KILL) { - int hw_rf_kill = 0; - if (!(iwl_read32(priv, CSR_GP_CNTRL) & - CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) - hw_rf_kill = 1; - - IWL_WARN(priv, "RF_KILL bit toggled to %s.\n", - hw_rf_kill ? "disable radio" : "enable radio"); - - priv->isr_stats.rfkill++; - - /* driver only loads ucode once setting the interface up. - * the driver allows loading the ucode even if the radio - * is killed. Hence update the killswitch state here. The - * rfkill handler will care about restarting if needed. - */ - if (!test_bit(STATUS_ALIVE, &priv->status)) { - if (hw_rf_kill) - set_bit(STATUS_RF_KILL_HW, &priv->status); - else - clear_bit(STATUS_RF_KILL_HW, &priv->status); - wiphy_rfkill_set_hw_state(priv->hw->wiphy, hw_rf_kill); - } - - handled |= CSR_INT_BIT_RF_KILL; - } - - /* Chip got too hot and stopped itself */ - if (inta & CSR_INT_BIT_CT_KILL) { - IWL_ERR(priv, "Microcode CT kill error detected.\n"); - priv->isr_stats.ctkill++; - handled |= CSR_INT_BIT_CT_KILL; - } - - /* Error detected by uCode */ - if (inta & CSR_INT_BIT_SW_ERR) { - IWL_ERR(priv, "Microcode SW error detected. " - " Restarting 0x%X.\n", inta); - priv->isr_stats.sw++; - iwl_irq_handle_error(priv); - handled |= CSR_INT_BIT_SW_ERR; - } - - /* - * uCode wakes up after power-down sleep. - * Tell device about any new tx or host commands enqueued, - * and about any Rx buffers made available while asleep. - */ - if (inta & CSR_INT_BIT_WAKEUP) { - IWL_DEBUG_ISR(priv, "Wakeup interrupt\n"); - iwl_rx_queue_update_write_ptr(priv, &priv->rxq); - for (i = 0; i < priv->hw_params.max_txq_num; i++) - iwl_txq_update_write_ptr(priv, &priv->txq[i]); - priv->isr_stats.wakeup++; - handled |= CSR_INT_BIT_WAKEUP; - } - - /* All uCode command responses, including Tx command responses, - * Rx "responses" (frame-received notification), and other - * notifications from uCode come through here*/ - if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { - iwl_rx_handle(priv); - priv->isr_stats.rx++; - handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); - } - - /* This "Tx" DMA channel is used only for loading uCode */ - if (inta & CSR_INT_BIT_FH_TX) { - IWL_DEBUG_ISR(priv, "uCode load interrupt\n"); - priv->isr_stats.tx++; - handled |= CSR_INT_BIT_FH_TX; - /* Wake up uCode load routine, now that load is complete */ - priv->ucode_write_complete = 1; - wake_up_interruptible(&priv->wait_command_queue); - } - - if (inta & ~handled) { - IWL_ERR(priv, "Unhandled INTA bits 0x%08x\n", inta & ~handled); - priv->isr_stats.unhandled++; - } - - if (inta & ~(priv->inta_mask)) { - IWL_WARN(priv, "Disabled INTA bits 0x%08x were pending\n", - inta & ~priv->inta_mask); - IWL_WARN(priv, " with FH_INT = 0x%08x\n", inta_fh); - } - - /* Re-enable all interrupts */ - /* only Re-enable if disabled by irq */ - if (test_bit(STATUS_INT_ENABLED, &priv->status)) - iwl_enable_interrupts(priv); - /* Re-enable RF_KILL if it occurred */ - else if (handled & CSR_INT_BIT_RF_KILL) - iwl_enable_rfkill_int(priv); - -#ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { - inta = iwl_read32(priv, CSR_INT); - inta_mask = iwl_read32(priv, CSR_INT_MASK); - inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); - IWL_DEBUG_ISR(priv, "End inta 0x%08x, enabled 0x%08x, fh 0x%08x, " - "flags 0x%08lx\n", inta, inta_mask, inta_fh, flags); - } -#endif -} - /* tasklet for iwlagn interrupt */ static void iwl_irq_tasklet(struct iwl_priv *priv) { @@ -1171,7 +985,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); iwl_write32(priv, CSR_FH_INT_STATUS, - CSR49_FH_INT_RX_MASK); + CSR_FH_INT_RX_MASK); } if (inta & CSR_INT_BIT_RX_PERIODIC) { handled |= CSR_INT_BIT_RX_PERIODIC; @@ -1209,7 +1023,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) /* This "Tx" DMA channel is used only for loading uCode */ if (inta & CSR_INT_BIT_FH_TX) { - iwl_write32(priv, CSR_FH_INT_STATUS, CSR49_FH_INT_TX_MASK); + iwl_write32(priv, CSR_FH_INT_STATUS, CSR_FH_INT_TX_MASK); IWL_DEBUG_ISR(priv, "uCode load interrupt\n"); priv->isr_stats.tx++; handled |= CSR_INT_BIT_FH_TX; @@ -1361,10 +1175,8 @@ static void iwl_dealloc_ucode_pci(struct iwl_priv *priv) { iwl_free_fw_desc(priv->pci_dev, &priv->ucode_code); iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data); - iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data_backup); iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init); iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init_data); - iwl_free_fw_desc(priv->pci_dev, &priv->ucode_boot); } static void iwl_nic_start(struct iwl_priv *priv) @@ -1376,7 +1188,7 @@ static void iwl_nic_start(struct iwl_priv *priv) struct iwlagn_ucode_capabilities { u32 max_probe_length; u32 standard_phy_calibration_size; - bool pan; + u32 flags; }; static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context); @@ -1422,8 +1234,8 @@ static int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first) } struct iwlagn_firmware_pieces { - const void *inst, *data, *init, *init_data, *boot; - size_t inst_size, data_size, init_size, init_data_size, boot_size; + const void *inst, *data, *init, *init_data; + size_t inst_size, data_size, init_size, init_data_size; u32 build; @@ -1444,28 +1256,18 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv, switch (api_ver) { default: - /* - * 4965 doesn't revision the firmware file format - * along with the API version, it always uses v1 - * file format. - */ - if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != - CSR_HW_REV_TYPE_4965) { - hdr_size = 28; - if (ucode_raw->size < hdr_size) { - IWL_ERR(priv, "File size too small!\n"); - return -EINVAL; - } - pieces->build = le32_to_cpu(ucode->u.v2.build); - pieces->inst_size = le32_to_cpu(ucode->u.v2.inst_size); - pieces->data_size = le32_to_cpu(ucode->u.v2.data_size); - pieces->init_size = le32_to_cpu(ucode->u.v2.init_size); - pieces->init_data_size = le32_to_cpu(ucode->u.v2.init_data_size); - pieces->boot_size = le32_to_cpu(ucode->u.v2.boot_size); - src = ucode->u.v2.data; - break; + hdr_size = 28; + if (ucode_raw->size < hdr_size) { + IWL_ERR(priv, "File size too small!\n"); + return -EINVAL; } - /* fall through for 4965 */ + pieces->build = le32_to_cpu(ucode->u.v2.build); + pieces->inst_size = le32_to_cpu(ucode->u.v2.inst_size); + pieces->data_size = le32_to_cpu(ucode->u.v2.data_size); + pieces->init_size = le32_to_cpu(ucode->u.v2.init_size); + pieces->init_data_size = le32_to_cpu(ucode->u.v2.init_data_size); + src = ucode->u.v2.data; + break; case 0: case 1: case 2: @@ -1479,7 +1281,6 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv, pieces->data_size = le32_to_cpu(ucode->u.v1.data_size); pieces->init_size = le32_to_cpu(ucode->u.v1.init_size); pieces->init_data_size = le32_to_cpu(ucode->u.v1.init_data_size); - pieces->boot_size = le32_to_cpu(ucode->u.v1.boot_size); src = ucode->u.v1.data; break; } @@ -1487,7 +1288,7 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv, /* Verify size of file vs. image size info in file's header */ if (ucode_raw->size != hdr_size + pieces->inst_size + pieces->data_size + pieces->init_size + - pieces->init_data_size + pieces->boot_size) { + pieces->init_data_size) { IWL_ERR(priv, "uCode file size %d does not match expected size\n", @@ -1503,8 +1304,6 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv, src += pieces->init_size; pieces->init_data = src; src += pieces->init_data_size; - pieces->boot = src; - src += pieces->boot_size; return 0; } @@ -1605,8 +1404,7 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, pieces->init_data_size = tlv_len; break; case IWL_UCODE_TLV_BOOT: - pieces->boot = tlv_data; - pieces->boot_size = tlv_len; + IWL_ERR(priv, "Found unexpected BOOT ucode\n"); break; case IWL_UCODE_TLV_PROBE_MAX_LEN: if (tlv_len != sizeof(u32)) @@ -1617,7 +1415,23 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, case IWL_UCODE_TLV_PAN: if (tlv_len) goto invalid_tlv_len; - capa->pan = true; + capa->flags |= IWL_UCODE_TLV_FLAGS_PAN; + break; + case IWL_UCODE_TLV_FLAGS: + /* must be at least one u32 */ + if (tlv_len < sizeof(u32)) + goto invalid_tlv_len; + /* and a proper number of u32s */ + if (tlv_len % sizeof(u32)) + goto invalid_tlv_len; + /* + * This driver only reads the first u32 as + * right now no more features are defined, + * if that changes then either the driver + * will not work with the new firmware, or + * it'll not take advantage of new features. + */ + capa->flags = le32_to_cpup((__le32 *)tlv_data); break; case IWL_UCODE_TLV_INIT_EVTLOG_PTR: if (tlv_len != sizeof(u32)) @@ -1806,8 +1620,6 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) pieces.init_size); IWL_DEBUG_INFO(priv, "f/w package hdr init data size = %Zd\n", pieces.init_data_size); - IWL_DEBUG_INFO(priv, "f/w package hdr boot inst size = %Zd\n", - pieces.boot_size); /* Verify that uCode images will fit in card's SRAM */ if (pieces.inst_size > priv->hw_params.max_inst_size) { @@ -1834,12 +1646,6 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) goto try_again; } - if (pieces.boot_size > priv->hw_params.max_bsm_size) { - IWL_ERR(priv, "uCode boot instr len %Zd too large to fit in\n", - pieces.boot_size); - goto try_again; - } - /* Allocate ucode buffers for card's bus-master loading ... */ /* Runtime instructions and 2 copies of data: @@ -1851,11 +1657,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) priv->ucode_data.len = pieces.data_size; iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data); - priv->ucode_data_backup.len = pieces.data_size; - iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data_backup); - - if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr || - !priv->ucode_data_backup.v_addr) + if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr) goto err_pci_alloc; /* Initialization instructions and data */ @@ -1870,15 +1672,6 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) goto err_pci_alloc; } - /* Bootstrap (instructions only, no data) */ - if (pieces.boot_size) { - priv->ucode_boot.len = pieces.boot_size; - iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_boot); - - if (!priv->ucode_boot.v_addr) - goto err_pci_alloc; - } - /* Now that we can no longer fail, copy information */ /* @@ -1901,12 +1694,21 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) priv->cfg->base_params->max_event_log_size; priv->_agn.inst_errlog_ptr = pieces.inst_errlog_ptr; - if (ucode_capa.pan) { + if (ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN) { priv->valid_contexts |= BIT(IWL_RXON_CTX_PAN); priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN; } else priv->sta_key_max_num = STA_KEY_MAX_NUM; + if (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS)) + priv->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM; + else + priv->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; + + if (ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BTSTATS || + (priv->cfg->bt_params && priv->cfg->bt_params->bt_statistics)) + priv->bt_statistics = true; + /* Copy images into buffers for card's bus-master reads ... */ /* Runtime instructions (first block of data in file) */ @@ -1924,7 +1726,6 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %Zd\n", pieces.data_size); memcpy(priv->ucode_data.v_addr, pieces.data, pieces.data_size); - memcpy(priv->ucode_data_backup.v_addr, pieces.data, pieces.data_size); /* Initialization instructions */ if (pieces.init_size) { @@ -1941,11 +1742,6 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) pieces.init_data_size); } - /* Bootstrap instructions */ - IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %Zd\n", - pieces.boot_size); - memcpy(priv->ucode_boot.v_addr, pieces.boot, pieces.boot_size); - /* * figure out the offset of chain noise reset and gain commands * base on the size of standard phy calibration commands table size @@ -2077,12 +1873,11 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) u32 blink1, blink2, ilink1, ilink2; u32 pc, hcmd; + base = priv->device_pointers.error_event_table; if (priv->ucode_type == UCODE_INIT) { - base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr); if (!base) base = priv->_agn.init_errlog_ptr; } else { - base = le32_to_cpu(priv->card_alive.error_event_table_ptr); if (!base) base = priv->_agn.inst_errlog_ptr; } @@ -2147,12 +1942,11 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, if (num_events == 0) return pos; + base = priv->device_pointers.log_event_table; if (priv->ucode_type == UCODE_INIT) { - base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); if (!base) base = priv->_agn.init_evtlog_ptr; } else { - base = le32_to_cpu(priv->card_alive.log_event_table_ptr); if (!base) base = priv->_agn.inst_evtlog_ptr; } @@ -2169,14 +1963,14 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, iwl_grab_nic_access(priv); /* Set starting address; reads will auto-increment */ - _iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, ptr); + iwl_write32(priv, HBUS_TARG_MEM_RADDR, ptr); rmb(); /* "time" is actually "data" for mode 0 (no timestamp). * place event id # at far right for easier visual parsing. */ for (i = 0; i < num_events; i++) { - ev = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); - time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); + ev = iwl_read32(priv, HBUS_TARG_MEM_RDAT); + time = iwl_read32(priv, HBUS_TARG_MEM_RDAT); if (mode == 0) { /* data, ev */ if (bufsz) { @@ -2190,7 +1984,7 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, time, ev); } } else { - data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); + data = iwl_read32(priv, HBUS_TARG_MEM_RDAT); if (bufsz) { pos += scnprintf(*buf + pos, bufsz - pos, "EVT_LOGT:%010u:0x%08x:%04u\n", @@ -2261,13 +2055,12 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, int pos = 0; size_t bufsz = 0; + base = priv->device_pointers.log_event_table; if (priv->ucode_type == UCODE_INIT) { - base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); logsize = priv->_agn.init_evtlog_size; if (!base) base = priv->_agn.init_evtlog_ptr; } else { - base = le32_to_cpu(priv->card_alive.log_event_table_ptr); logsize = priv->_agn.inst_evtlog_size; if (!base) base = priv->_agn.inst_evtlog_ptr; @@ -2433,14 +2226,14 @@ static void iwl_alive_start(struct iwl_priv *priv) /* Initialize uCode has loaded Runtime uCode ... verify inst image. * This is a paranoid check, because we would not have gotten the * "runtime" alive if code weren't properly loaded. */ - if (iwl_verify_ucode(priv)) { + if (iwl_verify_ucode(priv, &priv->ucode_code)) { /* Runtime instruction load was bad; * take it all the way back down so we can try again */ IWL_DEBUG_INFO(priv, "Bad runtime uCode load.\n"); goto restart; } - ret = priv->cfg->ops->lib->alive_notify(priv); + ret = iwlagn_alive_notify(priv); if (ret) { IWL_WARN(priv, "Could not complete ALIVE transition [ntf]: %d\n", ret); @@ -2537,7 +2330,7 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv); static void __iwl_down(struct iwl_priv *priv) { unsigned long flags; - int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status); + int exit_pending; IWL_DEBUG_INFO(priv, DRV_NAME " is going down\n"); @@ -2563,9 +2356,6 @@ static void __iwl_down(struct iwl_priv *priv) priv->bt_full_concurrent = false; priv->bt_ci_compliance = 0; - /* Unblock any waiting calls */ - wake_up_interruptible_all(&priv->wait_command_queue); - /* Wipe out the EXIT_PENDING status bit if we are not actually * exiting the module */ if (!exit_pending) @@ -2607,8 +2397,7 @@ static void __iwl_down(struct iwl_priv *priv) STATUS_EXIT_PENDING; /* device going down, Stop using ICT table */ - if (priv->cfg->ops->lib->isr_ops.disable) - priv->cfg->ops->lib->isr_ops.disable(priv); + iwl_disable_ict(priv); iwlagn_txq_ctx_stop(priv); iwlagn_rxq_stop(priv); @@ -2624,8 +2413,6 @@ static void __iwl_down(struct iwl_priv *priv) iwl_apm_stop(priv); exit: - memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp)); - dev_kfree_skb(priv->beacon_skb); priv->beacon_skb = NULL; @@ -2704,11 +2491,6 @@ static int __iwl_up(struct iwl_priv *priv) return -EIO; } - if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) { - IWL_ERR(priv, "ucode not available for device bringup\n"); - return -EIO; - } - for_each_context(priv, ctx) { ret = iwlagn_alloc_bcast_station(priv, ctx); if (ret) { @@ -2740,12 +2522,6 @@ static int __iwl_up(struct iwl_priv *priv) iwl_write32(priv, CSR_INT, 0xFFFFFFFF); - /* must be initialised before iwl_hw_nic_init */ - if (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS)) - priv->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM; - else - priv->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; - ret = iwlagn_hw_nic_init(priv); if (ret) { IWL_ERR(priv, "Unable to init nic\n"); @@ -2765,18 +2541,12 @@ static int __iwl_up(struct iwl_priv *priv) iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - /* Copy original ucode data image from disk into backup cache. - * This will be used to initialize the on-board processor's - * data SRAM for a clean start when the runtime program first loads. */ - memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr, - priv->ucode_data.len); - for (i = 0; i < MAX_HW_RESTARTS; i++) { /* load bootstrap state machine, * load bootstrap program into processor's memory, * prepare to load the "initialize" uCode */ - ret = priv->cfg->ops->lib->load_ucode(priv); + ret = iwlagn_load_ucode(priv); if (ret) { IWL_ERR(priv, "Unable to set up bootstrap uCode: %d\n", @@ -2814,11 +2584,14 @@ static void iwl_bg_init_alive_start(struct work_struct *data) struct iwl_priv *priv = container_of(data, struct iwl_priv, init_alive_start.work); - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + mutex_lock(&priv->mutex); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { + mutex_unlock(&priv->mutex); return; + } - mutex_lock(&priv->mutex); - priv->cfg->ops->lib->init_alive_start(priv); + iwlagn_init_alive_start(priv); mutex_unlock(&priv->mutex); } @@ -2827,15 +2600,15 @@ static void iwl_bg_alive_start(struct work_struct *data) struct iwl_priv *priv = container_of(data, struct iwl_priv, alive_start.work); + mutex_lock(&priv->mutex); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; + goto unlock; /* enable dram interrupt */ - if (priv->cfg->ops->lib->isr_ops.reset) - priv->cfg->ops->lib->isr_ops.reset(priv); + iwl_reset_ict(priv); - mutex_lock(&priv->mutex); iwl_alive_start(priv); +unlock: mutex_unlock(&priv->mutex); } @@ -3063,6 +2836,9 @@ static int iwl_mac_setup_register(struct iwl_priv *priv, hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | IEEE80211_HW_SUPPORTS_STATIC_SMPS; + if (capa->flags & IWL_UCODE_TLV_FLAGS_MFP) + hw->flags |= IEEE80211_HW_MFP_CAPABLE; + hw->sta_data_size = sizeof(struct iwl_station_priv); hw->vif_data_size = sizeof(struct iwl_vif_priv); @@ -3112,7 +2888,7 @@ static int iwl_mac_setup_register(struct iwl_priv *priv, } -int iwlagn_mac_start(struct ieee80211_hw *hw) +static int iwlagn_mac_start(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; int ret; @@ -3153,7 +2929,7 @@ out: return 0; } -void iwlagn_mac_stop(struct ieee80211_hw *hw) +static void iwlagn_mac_stop(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; @@ -3176,7 +2952,7 @@ void iwlagn_mac_stop(struct ieee80211_hw *hw) IWL_DEBUG_MAC80211(priv, "leave\n"); } -void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +static void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct iwl_priv *priv = hw->priv; @@ -3191,11 +2967,11 @@ void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) IWL_DEBUG_MACDUMP(priv, "leave\n"); } -void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_key_conf *keyconf, - struct ieee80211_sta *sta, - u32 iv32, u16 *phase1key) +static void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_key_conf *keyconf, + struct ieee80211_sta *sta, + u32 iv32, u16 *phase1key) { struct iwl_priv *priv = hw->priv; struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; @@ -3208,9 +2984,10 @@ void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211(priv, "leave\n"); } -int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, - struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key) +static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) { struct iwl_priv *priv = hw->priv; struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; @@ -3285,11 +3062,11 @@ int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return ret; } -int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, - u8 buf_size) +static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum ieee80211_ampdu_mlme_action action, + struct ieee80211_sta *sta, u16 tid, u16 *ssn, + u8 buf_size) { struct iwl_priv *priv = hw->priv; int ret = -EINVAL; @@ -3348,6 +3125,10 @@ int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, } break; case IEEE80211_AMPDU_TX_OPERATIONAL: + buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF); + + iwlagn_txq_agg_queue_setup(priv, sta, tid, buf_size); + /* * If the limit is 0, then it wasn't initialised yet, * use the default. We can do that since we take the @@ -3392,9 +3173,9 @@ int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, return ret; } -int iwlagn_mac_sta_add(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +static int iwlagn_mac_sta_add(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) { struct iwl_priv *priv = hw->priv; struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; @@ -3435,8 +3216,8 @@ int iwlagn_mac_sta_add(struct ieee80211_hw *hw, return 0; } -void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, - struct ieee80211_channel_switch *ch_switch) +static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, + struct ieee80211_channel_switch *ch_switch) { struct iwl_priv *priv = hw->priv; const struct iwl_channel_info *ch_info; @@ -3457,21 +3238,22 @@ void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211(priv, "enter\n"); + mutex_lock(&priv->mutex); + if (iwl_is_rfkill(priv)) - goto out_exit; + goto out; if (test_bit(STATUS_EXIT_PENDING, &priv->status) || test_bit(STATUS_SCANNING, &priv->status)) - goto out_exit; + goto out; if (!iwl_is_associated_ctx(ctx)) - goto out_exit; + goto out; /* channel switch in progress */ if (priv->switch_rxon.switch_in_progress == true) - goto out_exit; + goto out; - mutex_lock(&priv->mutex); if (priv->cfg->ops->lib->set_channel_switch) { ch = channel->hw_value; @@ -3527,16 +3309,15 @@ void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, } out: mutex_unlock(&priv->mutex); -out_exit: if (!priv->switch_rxon.switch_in_progress) ieee80211_chswitch_done(ctx->vif, false); IWL_DEBUG_MAC80211(priv, "leave\n"); } -void iwlagn_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, - u64 multicast) +static void iwlagn_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + u64 multicast) { struct iwl_priv *priv = hw->priv; __le32 filter_or = 0, filter_nand = 0; @@ -3583,7 +3364,7 @@ void iwlagn_configure_filter(struct ieee80211_hw *hw, FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; } -void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop) +static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop) { struct iwl_priv *priv = hw->priv; @@ -3750,12 +3531,8 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) priv->watchdog.data = (unsigned long)priv; priv->watchdog.function = iwl_bg_watchdog; - if (!priv->cfg->base_params->use_isr_legacy) - tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) - iwl_irq_tasklet, (unsigned long)priv); - else - tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) - iwl_irq_tasklet_legacy, (unsigned long)priv); + tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) + iwl_irq_tasklet, (unsigned long)priv); } static void iwl_cancel_deferred_work(struct iwl_priv *priv) @@ -3808,7 +3585,6 @@ static int iwl_init_drv(struct iwl_priv *priv) INIT_LIST_HEAD(&priv->free_frames); mutex_init(&priv->mutex); - mutex_init(&priv->sync_cmd_mutex); priv->ieee_channels = NULL; priv->ieee_rates = NULL; @@ -3907,12 +3683,13 @@ struct ieee80211_ops iwlagn_hw_ops = { .offchannel_tx_cancel_wait = iwl_mac_offchannel_tx_cancel_wait, }; -static void iwl_hw_detect(struct iwl_priv *priv) +static u32 iwl_hw_detect(struct iwl_priv *priv) { - priv->hw_rev = _iwl_read32(priv, CSR_HW_REV); - priv->hw_wa_rev = _iwl_read32(priv, CSR_HW_REV_WA_REG); - priv->rev_id = priv->pci_dev->revision; - IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", priv->rev_id); + u8 rev_id; + + pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &rev_id); + IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", rev_id); + return iwl_read32(priv, CSR_HW_REV); } static int iwl_set_hw_params(struct iwl_priv *priv) @@ -3963,19 +3740,12 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data); unsigned long flags; u16 pci_cmd, num_mac; + u32 hw_rev; /************************ * 1. Allocating HW data ************************/ - /* Disabling hardware scan means that mac80211 will perform scans - * "the hard way", rather than using device's scan. */ - if (cfg->mod_params->disable_hw_scan) { - dev_printk(KERN_DEBUG, &(pdev->dev), - "sw scan support is deprecated\n"); - iwlagn_hw_ops.hw_scan = NULL; - } - hw = iwl_alloc_all(cfg); if (!hw) { err = -ENOMEM; @@ -4116,9 +3886,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) */ iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); - iwl_hw_detect(priv); + hw_rev = iwl_hw_detect(priv); IWL_INFO(priv, "Detected %s, REV=0x%X\n", - priv->cfg->name, priv->hw_rev); + priv->cfg->name, hw_rev); /* We disable the RETRY_TIMEOUT register (0x41) to keep * PCI Tx retries from interfering with C3 CPU state */ @@ -4134,7 +3904,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) * 4. Read EEPROM *****************/ /* Read the EEPROM */ - err = iwl_eeprom_init(priv); + err = iwl_eeprom_init(priv, hw_rev); if (err) { IWL_ERR(priv, "Unable to init EEPROM\n"); goto out_iounmap; @@ -4186,10 +3956,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_enable_msi(priv->pci_dev); - if (priv->cfg->ops->lib->isr_ops.alloc) - priv->cfg->ops->lib->isr_ops.alloc(priv); + iwl_alloc_isr_ict(priv); - err = request_irq(priv->pci_dev->irq, priv->cfg->ops->lib->isr_ops.isr, + err = request_irq(priv->pci_dev->irq, iwl_isr_ict, IRQF_SHARED, DRV_NAME, priv); if (err) { IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq); @@ -4236,8 +4005,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) destroy_workqueue(priv->workqueue); priv->workqueue = NULL; free_irq(priv->pci_dev->irq, priv); - if (priv->cfg->ops->lib->isr_ops.free) - priv->cfg->ops->lib->isr_ops.free(priv); + iwl_free_isr_ict(priv); out_disable_msi: pci_disable_msi(priv->pci_dev); iwl_uninit_drv(priv); @@ -4335,8 +4103,7 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) iwl_uninit_drv(priv); - if (priv->cfg->ops->lib->isr_ops.free) - priv->cfg->ops->lib->isr_ops.free(priv); + iwl_free_isr_ict(priv); dev_kfree_skb(priv->beacon_skb); @@ -4585,43 +4352,21 @@ module_exit(iwl_exit); module_init(iwl_init); #ifdef CONFIG_IWLWIFI_DEBUG -module_param_named(debug50, iwl_debug_level, uint, S_IRUGO); -MODULE_PARM_DESC(debug50, "50XX debug output mask (deprecated)"); module_param_named(debug, iwl_debug_level, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "debug output mask"); #endif -module_param_named(swcrypto50, iwlagn_mod_params.sw_crypto, bool, S_IRUGO); -MODULE_PARM_DESC(swcrypto50, - "using crypto in software (default 0 [hardware]) (deprecated)"); module_param_named(swcrypto, iwlagn_mod_params.sw_crypto, int, S_IRUGO); MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])"); -module_param_named(queues_num50, - iwlagn_mod_params.num_of_queues, int, S_IRUGO); -MODULE_PARM_DESC(queues_num50, - "number of hw queues in 50xx series (deprecated)"); module_param_named(queues_num, iwlagn_mod_params.num_of_queues, int, S_IRUGO); MODULE_PARM_DESC(queues_num, "number of hw queues."); -module_param_named(11n_disable50, iwlagn_mod_params.disable_11n, int, S_IRUGO); -MODULE_PARM_DESC(11n_disable50, "disable 50XX 11n functionality (deprecated)"); module_param_named(11n_disable, iwlagn_mod_params.disable_11n, int, S_IRUGO); MODULE_PARM_DESC(11n_disable, "disable 11n functionality"); -module_param_named(amsdu_size_8K50, iwlagn_mod_params.amsdu_size_8K, - int, S_IRUGO); -MODULE_PARM_DESC(amsdu_size_8K50, - "enable 8K amsdu size in 50XX series (deprecated)"); module_param_named(amsdu_size_8K, iwlagn_mod_params.amsdu_size_8K, int, S_IRUGO); MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size"); -module_param_named(fw_restart50, iwlagn_mod_params.restart_fw, int, S_IRUGO); -MODULE_PARM_DESC(fw_restart50, - "restart firmware in case of error (deprecated)"); module_param_named(fw_restart, iwlagn_mod_params.restart_fw, int, S_IRUGO); MODULE_PARM_DESC(fw_restart, "restart firmware in case of error"); -module_param_named( - disable_hw_scan, iwlagn_mod_params.disable_hw_scan, int, S_IRUGO); -MODULE_PARM_DESC(disable_hw_scan, - "disable hardware scanning (default 0) (deprecated)"); module_param_named(ucode_alternative, iwlagn_wanted_ucode_alternative, int, S_IRUGO); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index 20f8e4188994..016b79e4421e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -66,7 +66,6 @@ #include "iwl-dev.h" /* configuration for the _agn devices */ -extern struct iwl_cfg iwl4965_agn_cfg; extern struct iwl_cfg iwl5300_agn_cfg; extern struct iwl_cfg iwl5100_agn_cfg; extern struct iwl_cfg iwl5350_agn_cfg; @@ -114,7 +113,6 @@ extern struct iwl_hcmd_ops iwlagn_bt_hcmd; extern struct iwl_hcmd_utils_ops iwlagn_hcmd_utils; extern struct ieee80211_ops iwlagn_hw_ops; -extern struct ieee80211_ops iwl4965_hw_ops; int iwl_reset_ict(struct iwl_priv *priv); void iwl_disable_ict(struct iwl_priv *priv); @@ -133,10 +131,6 @@ void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv, u16 byte_cnt); void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_priv *priv, struct iwl_tx_queue *txq); -int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, - int tx_fifo, int sta_id, int tid, u16 ssn_idx); -int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, - u16 ssn_idx, u8 tx_fifo); void iwlagn_txq_set_sched(struct iwl_priv *priv, u32 mask); void iwl_free_tfds_in_queue(struct iwl_priv *priv, int sta_id, int tid, int freed); @@ -158,7 +152,7 @@ void iwlagn_rx_calib_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); void iwlagn_init_alive_start(struct iwl_priv *priv); int iwlagn_alive_notify(struct iwl_priv *priv); -int iwl_verify_ucode(struct iwl_priv *priv); +int iwl_verify_ucode(struct iwl_priv *priv, struct fw_desc *fw_desc); void iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type); void iwlagn_send_prio_tbl(struct iwl_priv *priv); @@ -206,6 +200,9 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u16 tid, u16 *ssn); int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u16 tid); +void iwlagn_txq_agg_queue_setup(struct iwl_priv *priv, + struct ieee80211_sta *sta, + int tid, int frame_limit); int iwlagn_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id); void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, @@ -311,7 +308,7 @@ static inline u32 iwl_ant_idx_to_flags(u8 ant_idx) static inline u8 iwl_hw_get_rate(__le32 rate_n_flags) { - return le32_to_cpu(rate_n_flags) & 0xFF; + return le32_to_cpu(rate_n_flags) & RATE_MCS_RATE_MSK; } static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags) @@ -340,32 +337,4 @@ void __releases(wait_entry) iwlagn_remove_notification(struct iwl_priv *priv, struct iwl_notification_wait *wait_entry); -/* mac80211 handlers (for 4965) */ -void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb); -int iwlagn_mac_start(struct ieee80211_hw *hw); -void iwlagn_mac_stop(struct ieee80211_hw *hw); -void iwlagn_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, - u64 multicast); -int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, - struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key); -void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_key_conf *keyconf, - struct ieee80211_sta *sta, - u32 iv32, u16 *phase1key); -int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, - u8 buf_size); -int iwlagn_mac_sta_add(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta); -void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, - struct ieee80211_channel_switch *ch_switch); -void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop); - #endif /* __iwl_agn_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index ca42ffa63ed7..a1a5c1b23096 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -103,9 +103,7 @@ enum { REPLY_WEPKEY = 0x20, /* RX, TX, LEDs */ - REPLY_3945_RX = 0x1b, /* 3945 only */ REPLY_TX = 0x1c, - REPLY_RATE_SCALE = 0x47, /* 3945 only */ REPLY_LEDS_CMD = 0x48, REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* for 4965 and up */ @@ -229,7 +227,7 @@ struct iwl_cmd_header { * There is one exception: uCode sets bit 15 when it originates * the response/notification, i.e. when the response/notification * is not a direct response to a command sent by the driver. For - * example, uCode issues REPLY_3945_RX when it sends a received frame + * example, uCode issues REPLY_RX when it sends a received frame * to the driver; it is not a direct response to any driver command. * * The Linux driver uses the following format: @@ -249,36 +247,6 @@ struct iwl_cmd_header { /** - * struct iwl3945_tx_power - * - * Used in REPLY_TX_PWR_TABLE_CMD, REPLY_SCAN_CMD, REPLY_CHANNEL_SWITCH - * - * Each entry contains two values: - * 1) DSP gain (or sometimes called DSP attenuation). This is a fine-grained - * linear value that multiplies the output of the digital signal processor, - * before being sent to the analog radio. - * 2) Radio gain. This sets the analog gain of the radio Tx path. - * It is a coarser setting, and behaves in a logarithmic (dB) fashion. - * - * Driver obtains values from struct iwl3945_tx_power power_gain_table[][]. - */ -struct iwl3945_tx_power { - u8 tx_gain; /* gain for analog radio */ - u8 dsp_atten; /* gain for DSP */ -} __packed; - -/** - * struct iwl3945_power_per_rate - * - * Used in REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH - */ -struct iwl3945_power_per_rate { - u8 rate; /* plcp */ - struct iwl3945_tx_power tpc; - u8 reserved; -} __packed; - -/** * iwlagn rate_n_flags bit fields * * rate_n_flags format is used in following iwlagn commands: @@ -324,6 +292,8 @@ struct iwl3945_power_per_rate { #define RATE_MCS_SPATIAL_MSK 0x18 #define RATE_MCS_HT_DUP_POS 5 #define RATE_MCS_HT_DUP_MSK 0x20 +/* Both legacy and HT use bits 7:0 as the CCK/OFDM rate or HT MCS */ +#define RATE_MCS_RATE_MSK 0xff /* Bit 8: (1) HT format, (0) legacy format in bits 7:0 */ #define RATE_MCS_FLAGS_POS 8 @@ -375,30 +345,6 @@ struct iwl3945_power_per_rate { #define IWL_PWR_CCK_ENTRIES 2 /** - * union iwl4965_tx_power_dual_stream - * - * Host format used for REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH - * Use __le32 version (struct tx_power_dual_stream) when building command. - * - * Driver provides radio gain and DSP attenuation settings to device in pairs, - * one value for each transmitter chain. The first value is for transmitter A, - * second for transmitter B. - * - * For SISO bit rates, both values in a pair should be identical. - * For MIMO rates, one value may be different from the other, - * in order to balance the Tx output between the two transmitters. - * - * See more details in doc for TXPOWER in iwl-4965-hw.h. - */ -union iwl4965_tx_power_dual_stream { - struct { - u8 radio_tx_gain[2]; - u8 dsp_predis_atten[2]; - } s; - u32 dw; -}; - -/** * struct tx_power_dual_stream * * Table entries in REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH @@ -410,15 +356,6 @@ struct tx_power_dual_stream { } __packed; /** - * struct iwl4965_tx_power_db - * - * Entire table within REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH - */ -struct iwl4965_tx_power_db { - struct tx_power_dual_stream power_tbl[POWER_TABLE_NUM_ENTRIES]; -} __packed; - -/** * Command REPLY_TX_POWER_DBM_CMD = 0x98 * struct iwlagn_tx_power_dbm_cmd */ @@ -451,54 +388,6 @@ struct iwl_tx_ant_config_cmd { #define UCODE_VALID_OK cpu_to_le32(0x1) #define INITIALIZE_SUBTYPE (9) -/* - * ("Initialize") REPLY_ALIVE = 0x1 (response only, not a command) - * - * uCode issues this "initialize alive" notification once the initialization - * uCode image has completed its work, and is ready to load the runtime image. - * This is the *first* "alive" notification that the driver will receive after - * rebooting uCode; the "initialize" alive is indicated by subtype field == 9. - * - * See comments documenting "BSM" (bootstrap state machine). - * - * For 4965, this notification contains important calibration data for - * calculating txpower settings: - * - * 1) Power supply voltage indication. The voltage sensor outputs higher - * values for lower voltage, and vice verse. - * - * 2) Temperature measurement parameters, for each of two channel widths - * (20 MHz and 40 MHz) supported by the radios. Temperature sensing - * is done via one of the receiver chains, and channel width influences - * the results. - * - * 3) Tx gain compensation to balance 4965's 2 Tx chains for MIMO operation, - * for each of 5 frequency ranges. - */ -struct iwl_init_alive_resp { - u8 ucode_minor; - u8 ucode_major; - __le16 reserved1; - u8 sw_rev[8]; - u8 ver_type; - u8 ver_subtype; /* "9" for initialize alive */ - __le16 reserved2; - __le32 log_event_table_ptr; - __le32 error_event_table_ptr; - __le32 timestamp; - __le32 is_valid; - - /* calibration values from "initialize" uCode */ - __le32 voltage; /* signed, higher value is lower voltage */ - __le32 therm_r1[2]; /* signed, 1st for normal, 2nd for HT40 */ - __le32 therm_r2[2]; /* signed */ - __le32 therm_r3[2]; /* signed */ - __le32 therm_r4[2]; /* signed */ - __le32 tx_atten[5][2]; /* signed MIMO gain comp, 5 freq groups, - * 2 Tx chains */ -} __packed; - - /** * REPLY_ALIVE = 0x1 (response only, not a command) * @@ -722,46 +611,6 @@ enum { * regardless of whether RXON_FILTER_ASSOC_MSK is set. */ -struct iwl3945_rxon_cmd { - u8 node_addr[6]; - __le16 reserved1; - u8 bssid_addr[6]; - __le16 reserved2; - u8 wlap_bssid_addr[6]; - __le16 reserved3; - u8 dev_type; - u8 air_propagation; - __le16 reserved4; - u8 ofdm_basic_rates; - u8 cck_basic_rates; - __le16 assoc_id; - __le32 flags; - __le32 filter_flags; - __le16 channel; - __le16 reserved5; -} __packed; - -struct iwl4965_rxon_cmd { - u8 node_addr[6]; - __le16 reserved1; - u8 bssid_addr[6]; - __le16 reserved2; - u8 wlap_bssid_addr[6]; - __le16 reserved3; - u8 dev_type; - u8 air_propagation; - __le16 rx_chain; - u8 ofdm_basic_rates; - u8 cck_basic_rates; - __le16 assoc_id; - __le32 flags; - __le32 filter_flags; - __le16 channel; - u8 ofdm_ht_single_stream_basic_rates; - u8 ofdm_ht_dual_stream_basic_rates; -} __packed; - -/* 5000 HW just extend this command */ struct iwl_rxon_cmd { u8 node_addr[6]; __le16 reserved1; @@ -789,25 +638,6 @@ struct iwl_rxon_cmd { /* * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response) */ -struct iwl3945_rxon_assoc_cmd { - __le32 flags; - __le32 filter_flags; - u8 ofdm_basic_rates; - u8 cck_basic_rates; - __le16 reserved; -} __packed; - -struct iwl4965_rxon_assoc_cmd { - __le32 flags; - __le32 filter_flags; - u8 ofdm_basic_rates; - u8 cck_basic_rates; - u8 ofdm_ht_single_stream_basic_rates; - u8 ofdm_ht_dual_stream_basic_rates; - __le16 rx_chain_select_flags; - __le16 reserved; -} __packed; - struct iwl5000_rxon_assoc_cmd { __le32 flags; __le32 filter_flags; @@ -843,26 +673,6 @@ struct iwl_rxon_time_cmd { /* * REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response) */ -struct iwl3945_channel_switch_cmd { - u8 band; - u8 expect_beacon; - __le16 channel; - __le32 rxon_flags; - __le32 rxon_filter_flags; - __le32 switch_time; - struct iwl3945_power_per_rate power[IWL_MAX_RATES]; -} __packed; - -struct iwl4965_channel_switch_cmd { - u8 band; - u8 expect_beacon; - __le16 channel; - __le32 rxon_flags; - __le32 rxon_filter_flags; - __le32 switch_time; - struct iwl4965_tx_power_db tx_power; -} __packed; - /** * struct iwl5000_channel_switch_cmd * @band: 0- 5.2GHz, 1- 2.4GHz @@ -976,15 +786,10 @@ struct iwl_qosparam_cmd { #define IWL_AP_ID 0 #define IWL_AP_ID_PAN 1 #define IWL_STA_ID 2 -#define IWL3945_BROADCAST_ID 24 -#define IWL3945_STATION_COUNT 25 -#define IWL4965_BROADCAST_ID 31 -#define IWL4965_STATION_COUNT 32 #define IWLAGN_PAN_BCAST_ID 14 #define IWLAGN_BROADCAST_ID 15 #define IWLAGN_STATION_COUNT 16 -#define IWL_STATION_COUNT 32 /* MAX(3945,4965)*/ #define IWL_INVALID_STATION 255 #define STA_FLG_TX_RATE_MSK cpu_to_le32(1 << 2) @@ -1032,16 +837,6 @@ struct iwl_qosparam_cmd { * combined with Traffic ID (QOS priority), in format used by Tx Scheduler */ #define BUILD_RAxTID(sta_id, tid) (((sta_id) << 4) + (tid)) -struct iwl4965_keyinfo { - __le16 key_flags; - u8 tkip_rx_tsc_byte2; /* TSC[2] for key mix ph1 detection */ - u8 reserved1; - __le16 tkip_rx_ttak[5]; /* 10-byte unicast TKIP TTAK */ - u8 key_offset; - u8 reserved2; - u8 key[16]; /* 16-byte unicast decryption key */ -} __packed; - /* agn */ struct iwl_keyinfo { __le16 key_flags; @@ -1083,7 +878,6 @@ struct sta_id_modify { * with info on security keys, aggregation parameters, and Tx rates for * initial Tx attempt and any retries (agn devices uses * REPLY_TX_LINK_QUALITY_CMD, - * 3945 uses REPLY_RATE_SCALE to set up rate tables). * * REPLY_ADD_STA sets up the table entry for one station, either creating * a new entry, or modifying a pre-existing one. @@ -1103,72 +897,6 @@ struct sta_id_modify { * entries for all STAs in network, starting with index IWL_STA_ID. */ -struct iwl3945_addsta_cmd { - u8 mode; /* 1: modify existing, 0: add new station */ - u8 reserved[3]; - struct sta_id_modify sta; - struct iwl4965_keyinfo key; - __le32 station_flags; /* STA_FLG_* */ - __le32 station_flags_msk; /* STA_FLG_* */ - - /* bit field to disable (1) or enable (0) Tx for Traffic ID (TID) - * corresponding to bit (e.g. bit 5 controls TID 5). - * Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */ - __le16 tid_disable_tx; - - __le16 rate_n_flags; - - /* TID for which to add block-ack support. - * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ - u8 add_immediate_ba_tid; - - /* TID for which to remove block-ack support. - * Set modify_mask bit STA_MODIFY_DELBA_TID_MSK to use this field. */ - u8 remove_immediate_ba_tid; - - /* Starting Sequence Number for added block-ack support. - * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ - __le16 add_immediate_ba_ssn; -} __packed; - -struct iwl4965_addsta_cmd { - u8 mode; /* 1: modify existing, 0: add new station */ - u8 reserved[3]; - struct sta_id_modify sta; - struct iwl4965_keyinfo key; - __le32 station_flags; /* STA_FLG_* */ - __le32 station_flags_msk; /* STA_FLG_* */ - - /* bit field to disable (1) or enable (0) Tx for Traffic ID (TID) - * corresponding to bit (e.g. bit 5 controls TID 5). - * Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */ - __le16 tid_disable_tx; - - __le16 reserved1; - - /* TID for which to add block-ack support. - * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ - u8 add_immediate_ba_tid; - - /* TID for which to remove block-ack support. - * Set modify_mask bit STA_MODIFY_DELBA_TID_MSK to use this field. */ - u8 remove_immediate_ba_tid; - - /* Starting Sequence Number for added block-ack support. - * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ - __le16 add_immediate_ba_ssn; - - /* - * Number of packets OK to transmit to station even though - * it is asleep -- used to synchronise PS-poll and u-APSD - * responses while ucode keeps track of STA sleep state. - */ - __le16 sleep_tx_count; - - __le16 reserved2; -} __packed; - -/* agn */ struct iwl_addsta_cmd { u8 mode; /* 1: modify existing, 0: add new station */ u8 reserved[3]; @@ -1337,62 +1065,6 @@ struct iwl_wep_cmd { #define RX_MPDU_RES_STATUS_DEC_DONE_MSK (0x800) -struct iwl3945_rx_frame_stats { - u8 phy_count; - u8 id; - u8 rssi; - u8 agc; - __le16 sig_avg; - __le16 noise_diff; - u8 payload[0]; -} __packed; - -struct iwl3945_rx_frame_hdr { - __le16 channel; - __le16 phy_flags; - u8 reserved1; - u8 rate; - __le16 len; - u8 payload[0]; -} __packed; - -struct iwl3945_rx_frame_end { - __le32 status; - __le64 timestamp; - __le32 beacon_timestamp; -} __packed; - -/* - * REPLY_3945_RX = 0x1b (response only, not a command) - * - * NOTE: DO NOT dereference from casts to this structure - * It is provided only for calculating minimum data set size. - * The actual offsets of the hdr and end are dynamic based on - * stats.phy_count - */ -struct iwl3945_rx_frame { - struct iwl3945_rx_frame_stats stats; - struct iwl3945_rx_frame_hdr hdr; - struct iwl3945_rx_frame_end end; -} __packed; - -#define IWL39_RX_FRAME_SIZE (4 + sizeof(struct iwl3945_rx_frame)) - -/* Fixed (non-configurable) rx data from phy */ - -#define IWL49_RX_RES_PHY_CNT 14 -#define IWL49_RX_PHY_FLAGS_ANTENNAE_OFFSET (4) -#define IWL49_RX_PHY_FLAGS_ANTENNAE_MASK (0x70) -#define IWL49_AGC_DB_MASK (0x3f80) /* MASK(7,13) */ -#define IWL49_AGC_DB_POS (7) -struct iwl4965_rx_non_cfg_phy { - __le16 ant_selection; /* ant A bit 4, ant B bit 5, ant C bit 6 */ - __le16 agc_info; /* agc code 0:6, agc dB 7:13, reserved 14:15 */ - u8 rssi_info[6]; /* we use even entries, 0/2/4 for A/B/C rssi */ - u8 pad[0]; -} __packed; - - #define IWLAGN_RX_RES_PHY_CNT 8 #define IWLAGN_RX_RES_AGC_IDX 1 #define IWLAGN_RX_RES_RSSI_AB_IDX 2 @@ -1576,80 +1248,6 @@ struct iwl_rx_mpdu_res_start { * REPLY_TX = 0x1c (command) */ -struct iwl3945_tx_cmd { - /* - * MPDU byte count: - * MAC header (24/26/30/32 bytes) + 2 bytes pad if 26/30 header size, - * + 8 byte IV for CCM or TKIP (not used for WEP) - * + Data payload - * + 8-byte MIC (not used for CCM/WEP) - * NOTE: Does not include Tx command bytes, post-MAC pad bytes, - * MIC (CCM) 8 bytes, ICV (WEP/TKIP/CKIP) 4 bytes, CRC 4 bytes.i - * Range: 14-2342 bytes. - */ - __le16 len; - - /* - * MPDU or MSDU byte count for next frame. - * Used for fragmentation and bursting, but not 11n aggregation. - * Same as "len", but for next frame. Set to 0 if not applicable. - */ - __le16 next_frame_len; - - __le32 tx_flags; /* TX_CMD_FLG_* */ - - u8 rate; - - /* Index of recipient station in uCode's station table */ - u8 sta_id; - u8 tid_tspec; - u8 sec_ctl; - u8 key[16]; - union { - u8 byte[8]; - __le16 word[4]; - __le32 dw[2]; - } tkip_mic; - __le32 next_frame_info; - union { - __le32 life_time; - __le32 attempt; - } stop_time; - u8 supp_rates[2]; - u8 rts_retry_limit; /*byte 50 */ - u8 data_retry_limit; /*byte 51 */ - union { - __le16 pm_frame_timeout; - __le16 attempt_duration; - } timeout; - - /* - * Duration of EDCA burst Tx Opportunity, in 32-usec units. - * Set this if txop time is not specified by HCCA protocol (e.g. by AP). - */ - __le16 driver_txop; - - /* - * MAC header goes here, followed by 2 bytes padding if MAC header - * length is 26 or 30 bytes, followed by payload data - */ - u8 payload[0]; - struct ieee80211_hdr hdr[0]; -} __packed; - -/* - * REPLY_TX = 0x1c (response) - */ -struct iwl3945_tx_resp { - u8 failure_rts; - u8 failure_frame; - u8 bt_kill_count; - u8 rate; - __le32 wireless_media_time; - __le32 status; /* TX status */ -} __packed; - - /* * 4965 uCode updates these Tx attempt count values in host DRAM. * Used for managing Tx retries when expecting block-acks. @@ -1740,54 +1338,6 @@ struct iwl_tx_cmd { struct ieee80211_hdr hdr[0]; } __packed; -/* TX command response is sent after *3945* transmission attempts. - * - * NOTES: - * - * TX_STATUS_FAIL_NEXT_FRAG - * - * If the fragment flag in the MAC header for the frame being transmitted - * is set and there is insufficient time to transmit the next frame, the - * TX status will be returned with 'TX_STATUS_FAIL_NEXT_FRAG'. - * - * TX_STATUS_FIFO_UNDERRUN - * - * Indicates the host did not provide bytes to the FIFO fast enough while - * a TX was in progress. - * - * TX_STATUS_FAIL_MGMNT_ABORT - * - * This status is only possible if the ABORT ON MGMT RX parameter was - * set to true with the TX command. - * - * If the MSB of the status parameter is set then an abort sequence is - * required. This sequence consists of the host activating the TX Abort - * control line, and then waiting for the TX Abort command response. This - * indicates that a the device is no longer in a transmit state, and that the - * command FIFO has been cleared. The host must then deactivate the TX Abort - * control line. Receiving is still allowed in this case. - */ -enum { - TX_3945_STATUS_SUCCESS = 0x01, - TX_3945_STATUS_DIRECT_DONE = 0x02, - TX_3945_STATUS_FAIL_SHORT_LIMIT = 0x82, - TX_3945_STATUS_FAIL_LONG_LIMIT = 0x83, - TX_3945_STATUS_FAIL_FIFO_UNDERRUN = 0x84, - TX_3945_STATUS_FAIL_MGMNT_ABORT = 0x85, - TX_3945_STATUS_FAIL_NEXT_FRAG = 0x86, - TX_3945_STATUS_FAIL_LIFE_EXPIRE = 0x87, - TX_3945_STATUS_FAIL_DEST_PS = 0x88, - TX_3945_STATUS_FAIL_ABORTED = 0x89, - TX_3945_STATUS_FAIL_BT_RETRY = 0x8a, - TX_3945_STATUS_FAIL_STA_INVALID = 0x8b, - TX_3945_STATUS_FAIL_FRAG_DROPPED = 0x8c, - TX_3945_STATUS_FAIL_TID_DISABLE = 0x8d, - TX_3945_STATUS_FAIL_FRAME_FLUSHED = 0x8e, - TX_3945_STATUS_FAIL_INSUFFICIENT_CF_POLL = 0x8f, - TX_3945_STATUS_FAIL_TX_LOCKED = 0x90, - TX_3945_STATUS_FAIL_NO_BEACON_ON_RADAR = 0x91, -}; - /* * TX command response is sent after *agn* transmission attempts. * @@ -1905,43 +1455,6 @@ struct agg_tx_status { __le16 sequence; } __packed; -struct iwl4965_tx_resp { - u8 frame_count; /* 1 no aggregation, >1 aggregation */ - u8 bt_kill_count; /* # blocked by bluetooth (unused for agg) */ - u8 failure_rts; /* # failures due to unsuccessful RTS */ - u8 failure_frame; /* # failures due to no ACK (unused for agg) */ - - /* For non-agg: Rate at which frame was successful. - * For agg: Rate at which all frames were transmitted. */ - __le32 rate_n_flags; /* RATE_MCS_* */ - - /* For non-agg: RTS + CTS + frame tx attempts time + ACK. - * For agg: RTS + CTS + aggregation tx time + block-ack time. */ - __le16 wireless_media_time; /* uSecs */ - - __le16 reserved; - __le32 pa_power1; /* RF power amplifier measurement (not used) */ - __le32 pa_power2; - - /* - * For non-agg: frame status TX_STATUS_* - * For agg: status of 1st frame, AGG_TX_STATE_*; other frame status - * fields follow this one, up to frame_count. - * Bit fields: - * 11- 0: AGG_TX_STATE_* status code - * 15-12: Retry count for 1st frame in aggregation (retries - * occur if tx failed for this frame when it was a - * member of a previous aggregation block). If rate - * scaling is used, retry count indicates the rate - * table entry used for all frames in the new agg. - * 31-16: Sequence # for this frame's Tx cmd (not SSN!) - */ - union { - __le32 status; - struct agg_tx_status agg_status[0]; /* for each agg frame */ - } u; -} __packed; - /* * definitions for initial rate index field * bits [3:0] initial rate index @@ -2030,51 +1543,7 @@ struct iwl_compressed_ba_resp { /* * REPLY_TX_PWR_TABLE_CMD = 0x97 (command, has simple generic response) * - * See details under "TXPOWER" in iwl-4965-hw.h. - */ - -struct iwl3945_txpowertable_cmd { - u8 band; /* 0: 5 GHz, 1: 2.4 GHz */ - u8 reserved; - __le16 channel; - struct iwl3945_power_per_rate power[IWL_MAX_RATES]; -} __packed; - -struct iwl4965_txpowertable_cmd { - u8 band; /* 0: 5 GHz, 1: 2.4 GHz */ - u8 reserved; - __le16 channel; - struct iwl4965_tx_power_db tx_power; -} __packed; - - -/** - * struct iwl3945_rate_scaling_cmd - Rate Scaling Command & Response - * - * REPLY_RATE_SCALE = 0x47 (command, has simple generic response) - * - * NOTE: The table of rates passed to the uCode via the - * RATE_SCALE command sets up the corresponding order of - * rates used for all related commands, including rate - * masks, etc. - * - * For example, if you set 9MB (PLCP 0x0f) as the first - * rate in the rate table, the bit mask for that rate - * when passed through ofdm_basic_rates on the REPLY_RXON - * command would be bit 0 (1 << 0) */ -struct iwl3945_rate_scaling_info { - __le16 rate_n_flags; - u8 try_cnt; - u8 next_rate_index; -} __packed; - -struct iwl3945_rate_scaling_cmd { - u8 table_id; - u8 reserved[3]; - struct iwl3945_rate_scaling_info table[IWL_MAX_RATES]; -} __packed; - /*RS_NEW_API: only TLC_RTS remains and moved to bit 0 */ #define LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK (1 << 0) @@ -2130,7 +1599,7 @@ struct iwl_link_qual_general_params { #define LINK_QUAL_AGG_DISABLE_START_MAX (255) #define LINK_QUAL_AGG_DISABLE_START_MIN (0) -#define LINK_QUAL_AGG_FRAME_LIMIT_DEF (31) +#define LINK_QUAL_AGG_FRAME_LIMIT_DEF (63) #define LINK_QUAL_AGG_FRAME_LIMIT_MAX (63) #define LINK_QUAL_AGG_FRAME_LIMIT_MIN (0) @@ -2696,14 +2165,6 @@ struct iwl_spectrum_notification { #define IWL_POWER_BT_SCO_ENA cpu_to_le16(BIT(8)) #define IWL_POWER_ADVANCE_PM_ENA_MSK cpu_to_le16(BIT(9)) -struct iwl3945_powertable_cmd { - __le16 flags; - u8 reserved[2]; - __le32 rx_data_timeout; - __le32 tx_data_timeout; - __le32 sleep_interval[IWL_POWER_VEC_SIZE]; -} __packed; - struct iwl_powertable_cmd { __le16 flags; u8 keep_alive_seconds; /* 3945 reserved */ @@ -2806,25 +2267,6 @@ struct iwl_ct_kill_throttling_config { * active_dwell < max_out_time */ -/* FIXME: rename to AP1, remove tpc */ -struct iwl3945_scan_channel { - /* - * type is defined as: - * 0:0 1 = active, 0 = passive - * 1:4 SSID direct bit map; if a bit is set, then corresponding - * SSID IE is transmitted in probe request. - * 5:7 reserved - */ - u8 type; - u8 channel; /* band is selected by iwl3945_scan_cmd "flags" field */ - struct iwl3945_tx_power tpc; - __le16 active_dwell; /* in 1024-uSec TU (time units), typ 5-50 */ - __le16 passive_dwell; /* in 1024-uSec TU (time units), typ 20-500 */ -} __packed; - -/* set number of direct probes u8 type */ -#define IWL39_SCAN_PROBE_MASK(n) ((BIT(n) | (BIT(n) - BIT(1)))) - struct iwl_scan_channel { /* * type is defined as: @@ -2920,50 +2362,6 @@ struct iwl_ssid_ie { * struct iwl_scan_channel. */ -struct iwl3945_scan_cmd { - __le16 len; - u8 reserved0; - u8 channel_count; /* # channels in channel list */ - __le16 quiet_time; /* dwell only this # millisecs on quiet channel - * (only for active scan) */ - __le16 quiet_plcp_th; /* quiet chnl is < this # pkts (typ. 1) */ - __le16 good_CRC_th; /* passive -> active promotion threshold */ - __le16 reserved1; - __le32 max_out_time; /* max usec to be away from associated (service) - * channel */ - __le32 suspend_time; /* pause scan this long (in "extended beacon - * format") when returning to service channel: - * 3945; 31:24 # beacons, 19:0 additional usec, - * 4965; 31:22 # beacons, 21:0 additional usec. - */ - __le32 flags; /* RXON_FLG_* */ - __le32 filter_flags; /* RXON_FILTER_* */ - - /* For active scans (set to all-0s for passive scans). - * Does not include payload. Must specify Tx rate; no rate scaling. */ - struct iwl3945_tx_cmd tx_cmd; - - /* For directed active scans (set to all-0s otherwise) */ - struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX_3945]; - - /* - * Probe request frame, followed by channel list. - * - * Size of probe request frame is specified by byte count in tx_cmd. - * Channel list follows immediately after probe request frame. - * Number of channels in list is specified by channel_count. - * Each channel in list is of type: - * - * struct iwl3945_scan_channel channels[0]; - * - * NOTE: Only one band of channels can be scanned per pass. You - * must not mix 2.4GHz channels and 5.2GHz channels, and you must wait - * for one scan to complete (i.e. receive SCAN_COMPLETE_NOTIFICATION) - * before requesting another scan. - */ - u8 data[0]; -} __packed; - enum iwl_scan_flags { /* BIT(0) currently unused */ IWL_SCAN_FLAGS_ACTION_FRAME_TX = BIT(1), @@ -3090,20 +2488,6 @@ enum iwl_ibss_manager { * BEACON_NOTIFICATION = 0x90 (notification only, not a command) */ -struct iwl3945_beacon_notif { - struct iwl3945_tx_resp beacon_notify_hdr; - __le32 low_tsf; - __le32 high_tsf; - __le32 ibss_mgr_status; -} __packed; - -struct iwl4965_beacon_notif { - struct iwl4965_tx_resp beacon_notify_hdr; - __le32 low_tsf; - __le32 high_tsf; - __le32 ibss_mgr_status; -} __packed; - struct iwlagn_beacon_notif { struct iwlagn_tx_resp beacon_notify_hdr; __le32 low_tsf; @@ -3115,14 +2499,6 @@ struct iwlagn_beacon_notif { * REPLY_TX_BEACON = 0x91 (command, has simple generic response) */ -struct iwl3945_tx_beacon_cmd { - struct iwl3945_tx_cmd tx; - __le16 tim_idx; - u8 tim_size; - u8 reserved1; - struct ieee80211_hdr frame[0]; /* beacon frame */ -} __packed; - struct iwl_tx_beacon_cmd { struct iwl_tx_cmd tx; __le16 tim_idx; @@ -3471,13 +2847,6 @@ struct iwl_statistics_cmd { #define STATISTICS_REPLY_FLG_BAND_24G_MSK cpu_to_le32(0x2) #define STATISTICS_REPLY_FLG_HT40_MODE_MSK cpu_to_le32(0x8) -struct iwl3945_notif_statistics { - __le32 flag; - struct iwl39_statistics_rx rx; - struct iwl39_statistics_tx tx; - struct iwl39_statistics_general general; -} __packed; - struct iwl_notif_statistics { __le32 flag; struct statistics_rx rx; @@ -4451,10 +3820,6 @@ struct iwl_rx_packet { __le32 len_n_flags; struct iwl_cmd_header hdr; union { - struct iwl3945_rx_frame rx_frame; - struct iwl3945_tx_resp tx_resp; - struct iwl3945_beacon_notif beacon_status; - struct iwl_alive_resp alive_frame; struct iwl_spectrum_notification spectrum_notif; struct iwl_csa_notification csa_notif; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index bafbe57c9602..45ec5cfe3fcf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -890,10 +890,8 @@ void iwl_print_rx_config_cmd(struct iwl_priv *priv, IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id)); } #endif -/** - * iwl_irq_handle_error - called for HW or SW error interrupt from card - */ -void iwl_irq_handle_error(struct iwl_priv *priv) + +void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) { unsigned int reload_msec; unsigned long reload_jiffies; @@ -904,18 +902,62 @@ void iwl_irq_handle_error(struct iwl_priv *priv) /* Cancel currently queued command. */ clear_bit(STATUS_HCMD_ACTIVE, &priv->status); + /* Keep the restart process from trying to send host + * commands by clearing the ready bit */ + clear_bit(STATUS_READY, &priv->status); + + wake_up_interruptible(&priv->wait_command_queue); + + if (!ondemand) { + /* + * If firmware keep reloading, then it indicate something + * serious wrong and firmware having problem to recover + * from it. Instead of keep trying which will fill the syslog + * and hang the system, let's just stop it + */ + reload_jiffies = jiffies; + reload_msec = jiffies_to_msecs((long) reload_jiffies - + (long) priv->reload_jiffies); + priv->reload_jiffies = reload_jiffies; + if (reload_msec <= IWL_MIN_RELOAD_DURATION) { + priv->reload_count++; + if (priv->reload_count >= IWL_MAX_CONTINUE_RELOAD_CNT) { + IWL_ERR(priv, "BUG_ON, Stop restarting\n"); + return; + } + } else + priv->reload_count = 0; + } + + if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) { + if (priv->cfg->mod_params->restart_fw) { + IWL_DEBUG(priv, IWL_DL_FW_ERRORS, + "Restarting adapter due to uCode error.\n"); + queue_work(priv->workqueue, &priv->restart); + } else + IWL_DEBUG(priv, IWL_DL_FW_ERRORS, + "Detected FW error, but not restarting\n"); + } +} + +/** + * iwl_irq_handle_error - called for HW or SW error interrupt from card + */ +void iwl_irq_handle_error(struct iwl_priv *priv) +{ /* W/A for WiFi/WiMAX coex and WiMAX own the RF */ if (priv->cfg->internal_wimax_coex && (!(iwl_read_prph(priv, APMG_CLK_CTRL_REG) & APMS_CLK_VAL_MRB_FUNC_MODE) || (iwl_read_prph(priv, APMG_PS_CTRL_REG) & APMG_PS_CTRL_VAL_RESET_REQ))) { - wake_up_interruptible(&priv->wait_command_queue); /* - *Keep the restart process from trying to send host - * commands by clearing the INIT status bit + * Keep the restart process from trying to send host + * commands by clearing the ready bit. */ clear_bit(STATUS_READY, &priv->status); + clear_bit(STATUS_HCMD_ACTIVE, &priv->status); + wake_up_interruptible(&priv->wait_command_queue); IWL_ERR(priv, "RF is used by WiMAX\n"); return; } @@ -935,38 +977,7 @@ void iwl_irq_handle_error(struct iwl_priv *priv) &priv->contexts[IWL_RXON_CTX_BSS]); #endif - wake_up_interruptible(&priv->wait_command_queue); - - /* Keep the restart process from trying to send host - * commands by clearing the INIT status bit */ - clear_bit(STATUS_READY, &priv->status); - - /* - * If firmware keep reloading, then it indicate something - * serious wrong and firmware having problem to recover - * from it. Instead of keep trying which will fill the syslog - * and hang the system, let's just stop it - */ - reload_jiffies = jiffies; - reload_msec = jiffies_to_msecs((long) reload_jiffies - - (long) priv->reload_jiffies); - priv->reload_jiffies = reload_jiffies; - if (reload_msec <= IWL_MIN_RELOAD_DURATION) { - priv->reload_count++; - if (priv->reload_count >= IWL_MAX_CONTINUE_RELOAD_CNT) { - IWL_ERR(priv, "BUG_ON, Stop restarting\n"); - return; - } - } else - priv->reload_count = 0; - - if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) { - IWL_DEBUG(priv, IWL_DL_FW_ERRORS, - "Restarting adapter due to uCode error.\n"); - - if (priv->cfg->mod_params->restart_fw) - queue_work(priv->workqueue, &priv->restart); - } + iwlagn_fw_error(priv, false); } static int iwl_apm_stop_master(struct iwl_priv *priv) @@ -1094,21 +1105,13 @@ int iwl_apm_init(struct iwl_priv *priv) } /* - * Enable DMA and BSM (if used) clocks, wait for them to stabilize. - * BSM (Boostrap State Machine) is only in 3945 and 4965; - * later devices (i.e. 5000 and later) have non-volatile SRAM, - * and don't need BSM to restore data after power-saving sleep. + * Enable DMA clock and wait for it to stabilize. * * Write to "CLK_EN_REG"; "1" bits enable clocks, while "0" bits * do not disable clocks. This preserves any hardware bits already * set by default in "CLK_CTRL_REG" after reset. */ - if (priv->cfg->base_params->use_bsm) - iwl_write_prph(priv, APMG_CLK_EN_REG, - APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT); - else - iwl_write_prph(priv, APMG_CLK_EN_REG, - APMG_CLK_VAL_DMA_CLK_RQT); + iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT); udelay(20); /* Disable L1-Active */ @@ -1430,7 +1433,6 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw, iwl_teardown_interface(priv, vif, false); - memset(priv->bssid, 0, ETH_ALEN); mutex_unlock(&priv->mutex); IWL_DEBUG_MAC80211(priv, "leave\n"); @@ -1756,15 +1758,7 @@ int iwl_force_reset(struct iwl_priv *priv, int mode, bool external) break; } IWL_ERR(priv, "On demand firmware reload\n"); - /* Set the FW error flag -- cleared on iwl_down */ - set_bit(STATUS_FW_ERROR, &priv->status); - wake_up_interruptible(&priv->wait_command_queue); - /* - * Keep the restart process from trying to send host - * commands by clearing the INIT status bit - */ - clear_bit(STATUS_READY, &priv->status); - queue_work(priv->workqueue, &priv->restart); + iwlagn_fw_error(priv, true); break; } return 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index b316d833d9a2..82939f851eb9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -73,7 +73,7 @@ struct iwl_cmd; #define IWLWIFI_VERSION "in-tree:" -#define DRV_COPYRIGHT "Copyright(c) 2003-2010 Intel Corporation" +#define DRV_COPYRIGHT "Copyright(c) 2003-2011 Intel Corporation" #define DRV_AUTHOR "<ilw@linux.intel.com>" #define IWL_PCI_DEVICE(dev, subdev, cfg) \ @@ -122,14 +122,6 @@ struct iwl_apm_ops { void (*config)(struct iwl_priv *priv); }; -struct iwl_isr_ops { - irqreturn_t (*isr) (int irq, void *data); - void (*free)(struct iwl_priv *priv); - int (*alloc)(struct iwl_priv *priv); - int (*reset)(struct iwl_priv *priv); - void (*disable)(struct iwl_priv *priv); -}; - struct iwl_debugfs_ops { ssize_t (*rx_stats_read)(struct file *file, char __user *user_buf, size_t count, loff_t *ppos); @@ -171,25 +163,15 @@ struct iwl_lib_ops { struct iwl_tx_queue *txq); int (*txq_init)(struct iwl_priv *priv, struct iwl_tx_queue *txq); - /* aggregations */ - int (*txq_agg_enable)(struct iwl_priv *priv, int txq_id, int tx_fifo, - int sta_id, int tid, u16 ssn_idx); - int (*txq_agg_disable)(struct iwl_priv *priv, u16 txq_id, u16 ssn_idx, - u8 tx_fifo); /* setup Rx handler */ void (*rx_handler_setup)(struct iwl_priv *priv); /* setup deferred work */ void (*setup_deferred_work)(struct iwl_priv *priv); /* cancel deferred work */ void (*cancel_deferred_work)(struct iwl_priv *priv); - /* alive notification after init uCode load */ - void (*init_alive_start)(struct iwl_priv *priv); - /* alive notification */ - int (*alive_notify)(struct iwl_priv *priv); /* check validity of rtc data address */ int (*is_valid_rtc_data_addr)(u32 addr); - /* 1st ucode load */ - int (*load_ucode)(struct iwl_priv *priv); + int (*dump_nic_event_log)(struct iwl_priv *priv, bool full_log, char **buf, bool display); void (*dump_nic_error_log)(struct iwl_priv *priv); @@ -204,9 +186,6 @@ struct iwl_lib_ops { int (*send_tx_power) (struct iwl_priv *priv); void (*update_chain_flags)(struct iwl_priv *priv); - /* isr */ - struct iwl_isr_ops isr_ops; - /* eeprom operations (as defined in iwl-eeprom.h) */ struct iwl_eeprom_ops eeprom_ops; @@ -252,7 +231,6 @@ struct iwl_ops { struct iwl_mod_params { int sw_crypto; /* def: 0 = using hardware encryption */ - int disable_hw_scan; /* def: 0 = use h/w scan */ int num_of_queues; /* def: HW dependent */ int disable_11n; /* def: 0 = 11n capabilities enabled */ int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */ @@ -286,8 +264,6 @@ struct iwl_mod_params { * @chain_noise_calib_by_driver: driver has the capability to perform * chain noise calibration operation * @shadow_reg_enable: HW shadhow register bit - * @no_agg_framecnt_info: uCode do not provide aggregation frame count - * information */ struct iwl_base_params { int eeprom_size; @@ -296,9 +272,7 @@ struct iwl_base_params { /* for iwl_apm_init() */ u32 pll_cfg_val; bool set_l0s; - bool use_bsm; - bool use_isr_legacy; const u16 max_ll_items; const bool shadow_ram_support; u16 led_compensation; @@ -317,7 +291,6 @@ struct iwl_base_params { const bool sensitivity_calib_by_driver; const bool chain_noise_calib_by_driver; const bool shadow_reg_enable; - const bool no_agg_framecnt_info; }; /* * @advanced_bt_coexist: support advanced bt coexist @@ -738,10 +711,13 @@ static inline bool iwl_advanced_bt_coexist(struct iwl_priv *priv) static inline bool iwl_bt_statistics(struct iwl_priv *priv) { - return priv->cfg->bt_params && priv->cfg->bt_params->bt_statistics; + return priv->bt_statistics; } extern bool bt_coex_active; extern bool bt_siso_mode; + +void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand); + #endif /* __iwl_core_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index f52bc040bcbf..5ab90ba7a024 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -155,18 +155,10 @@ #define CSR_DBG_LINK_PWR_MGMT_REG (CSR_BASE+0x250) /* Bits for CSR_HW_IF_CONFIG_REG */ -#define CSR49_HW_IF_CONFIG_REG_BIT_4965_R (0x00000010) #define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER (0x00000C00) #define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI (0x00000100) #define CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI (0x00000200) -#define CSR39_HW_IF_CONFIG_REG_BIT_3945_MB (0x00000100) -#define CSR39_HW_IF_CONFIG_REG_BIT_3945_MM (0x00000200) -#define CSR39_HW_IF_CONFIG_REG_BIT_SKU_MRC (0x00000400) -#define CSR39_HW_IF_CONFIG_REG_BIT_BOARD_TYPE (0x00000800) -#define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A (0x00000000) -#define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B (0x00001000) - #define CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A (0x00080000) #define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000) #define CSR_HW_IF_CONFIG_REG_BIT_NIC_READY (0x00400000) /* PCI_OWN_SEM */ @@ -186,7 +178,7 @@ #define CSR_INT_BIT_SW_ERR (1 << 25) /* uCode error */ #define CSR_INT_BIT_RF_KILL (1 << 7) /* HW RFKILL switch GP_CNTRL[27] toggled */ #define CSR_INT_BIT_CT_KILL (1 << 6) /* Critical temp (chip too hot) rfkill */ -#define CSR_INT_BIT_SW_RX (1 << 3) /* Rx, command responses, 3945 */ +#define CSR_INT_BIT_SW_RX (1 << 3) /* Rx, command responses */ #define CSR_INT_BIT_WAKEUP (1 << 1) /* NIC controller waking up (pwr mgmt) */ #define CSR_INT_BIT_ALIVE (1 << 0) /* uCode interrupts once it initializes */ @@ -202,29 +194,17 @@ /* interrupt flags in FH (flow handler) (PCI busmaster DMA) */ #define CSR_FH_INT_BIT_ERR (1 << 31) /* Error */ #define CSR_FH_INT_BIT_HI_PRIOR (1 << 30) /* High priority Rx, bypass coalescing */ -#define CSR39_FH_INT_BIT_RX_CHNL2 (1 << 18) /* Rx channel 2 (3945 only) */ #define CSR_FH_INT_BIT_RX_CHNL1 (1 << 17) /* Rx channel 1 */ #define CSR_FH_INT_BIT_RX_CHNL0 (1 << 16) /* Rx channel 0 */ -#define CSR39_FH_INT_BIT_TX_CHNL6 (1 << 6) /* Tx channel 6 (3945 only) */ #define CSR_FH_INT_BIT_TX_CHNL1 (1 << 1) /* Tx channel 1 */ #define CSR_FH_INT_BIT_TX_CHNL0 (1 << 0) /* Tx channel 0 */ -#define CSR39_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \ - CSR39_FH_INT_BIT_RX_CHNL2 | \ - CSR_FH_INT_BIT_RX_CHNL1 | \ - CSR_FH_INT_BIT_RX_CHNL0) - - -#define CSR39_FH_INT_TX_MASK (CSR39_FH_INT_BIT_TX_CHNL6 | \ - CSR_FH_INT_BIT_TX_CHNL1 | \ - CSR_FH_INT_BIT_TX_CHNL0) - -#define CSR49_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \ - CSR_FH_INT_BIT_RX_CHNL1 | \ - CSR_FH_INT_BIT_RX_CHNL0) +#define CSR_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \ + CSR_FH_INT_BIT_RX_CHNL1 | \ + CSR_FH_INT_BIT_RX_CHNL0) -#define CSR49_FH_INT_TX_MASK (CSR_FH_INT_BIT_TX_CHNL1 | \ - CSR_FH_INT_BIT_TX_CHNL0) +#define CSR_FH_INT_TX_MASK (CSR_FH_INT_BIT_TX_CHNL1 | \ + CSR_FH_INT_BIT_TX_CHNL0) /* GPIO */ #define CSR_GPIO_IN_BIT_AUX_POWER (0x00000200) @@ -268,7 +248,7 @@ * Indicates MAC (ucode processor, etc.) is powered up and can run. * Internal resources are accessible. * NOTE: This does not indicate that the processor is actually running. - * NOTE: This does not indicate that 4965 or 3945 has completed + * NOTE: This does not indicate that device has completed * init or post-power-down restore of internal SRAM memory. * Use CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP as indication that * SRAM is restored and uCode is in normal operation mode. @@ -291,8 +271,6 @@ /* HW REV */ #define CSR_HW_REV_TYPE_MSK (0x00001F0) -#define CSR_HW_REV_TYPE_3945 (0x00000D0) -#define CSR_HW_REV_TYPE_4965 (0x0000000) #define CSR_HW_REV_TYPE_5300 (0x0000020) #define CSR_HW_REV_TYPE_5350 (0x0000030) #define CSR_HW_REV_TYPE_5100 (0x0000050) @@ -363,7 +341,7 @@ * 0: MAC_SLEEP * uCode sets this when preparing a power-saving power-down. * uCode resets this when power-up is complete and SRAM is sane. - * NOTE: 3945/4965 saves internal SRAM data to host when powering down, + * NOTE: device saves internal SRAM data to host when powering down, * and must restore this data after powering back up. * MAC_SLEEP is the best indication that restore is complete. * Later devices (5xxx/6xxx/1xxx) use non-volatile SRAM, and @@ -394,7 +372,6 @@ #define CSR_LED_REG_TRUN_OFF (0x38) /* ANA_PLL */ -#define CSR39_ANA_PLL_CFG_VAL (0x01000000) #define CSR50_ANA_PLL_CFG_VAL (0x00880300) /* HPET MEM debug */ diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index ebdea3be3ef9..2824ccbcc1fc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project. * @@ -146,7 +146,6 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv) #define IWL_DL_RX (1 << 24) #define IWL_DL_ISR (1 << 25) #define IWL_DL_HT (1 << 26) -#define IWL_DL_IO (1 << 27) /* 0xF0000000 - 0x10000000 */ #define IWL_DL_11H (1 << 28) #define IWL_DL_STATS (1 << 29) @@ -174,7 +173,6 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv) IWL_DEBUG_LIMIT(p, IWL_DL_DROP, f, ## a) #define IWL_DEBUG_AP(p, f, a...) IWL_DEBUG(p, IWL_DL_AP, f, ## a) #define IWL_DEBUG_TXPOWER(p, f, a...) IWL_DEBUG(p, IWL_DL_TXPOWER, f, ## a) -#define IWL_DEBUG_IO(p, f, a...) IWL_DEBUG(p, IWL_DL_IO, f, ## a) #define IWL_DEBUG_RATE(p, f, a...) IWL_DEBUG(p, IWL_DL_RATE, f, ## a) #define IWL_DEBUG_RATE_LIMIT(p, f, a...) \ IWL_DEBUG_LIMIT(p, IWL_DL_RATE, f, ## a) diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 8842411f1cf3..92f6efd2c73f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -1572,12 +1572,10 @@ static ssize_t iwl_dbgfs_bt_traffic_read(struct file *file, int pos = 0; char buf[200]; const size_t bufsz = sizeof(buf); - ssize_t ret; if (!priv->bt_enable_flag) { pos += scnprintf(buf + pos, bufsz - pos, "BT coex disabled\n"); - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - return ret; + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } pos += scnprintf(buf + pos, bufsz - pos, "BT enable flag: 0x%x\n", priv->bt_enable_flag); @@ -1608,8 +1606,7 @@ static ssize_t iwl_dbgfs_bt_traffic_read(struct file *file, break; } - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - return ret; + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } static ssize_t iwl_dbgfs_protection_mode_read(struct file *file, diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 68b953f2bdc7..72133368c1f5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -26,7 +26,6 @@ /* * Please use this file (iwl-dev.h) for driver implementation definitions. * Please use iwl-commands.h for uCode API definitions. - * Please use iwl-4965-hw.h for hardware-related definitions. */ #ifndef __iwl_dev_h__ @@ -179,53 +178,12 @@ struct iwl_tx_queue { #define IWL_NUM_SCAN_RATES (2) -struct iwl4965_channel_tgd_info { - u8 type; - s8 max_power; -}; - -struct iwl4965_channel_tgh_info { - s64 last_radar_time; -}; - -#define IWL4965_MAX_RATE (33) - -struct iwl3945_clip_group { - /* maximum power level to prevent clipping for each rate, derived by - * us from this band's saturation power in EEPROM */ - const s8 clip_powers[IWL_MAX_RATES]; -}; - -/* current Tx power values to use, one for each rate for each channel. - * requested power is limited by: - * -- regulatory EEPROM limits for this channel - * -- hardware capabilities (clip-powers) - * -- spectrum management - * -- user preference (e.g. iwconfig) - * when requested power is set, base power index must also be set. */ -struct iwl3945_channel_power_info { - struct iwl3945_tx_power tpc; /* actual radio and DSP gain settings */ - s8 power_table_index; /* actual (compenst'd) index into gain table */ - s8 base_power_index; /* gain index for power at factory temp. */ - s8 requested_power; /* power (dBm) requested for this chnl/rate */ -}; - -/* current scan Tx power values to use, one for each scan rate for each - * channel. */ -struct iwl3945_scan_power_info { - struct iwl3945_tx_power tpc; /* actual radio and DSP gain settings */ - s8 power_table_index; /* actual (compenst'd) index into gain table */ - s8 requested_power; /* scan pwr (dBm) requested for chnl/rate */ -}; - /* * One for each channel, holds all channel setup data * Some of the fields (e.g. eeprom and flags/max_power_avg) are redundant * with one another! */ struct iwl_channel_info { - struct iwl4965_channel_tgd_info tgd; - struct iwl4965_channel_tgh_info tgh; struct iwl_eeprom_channel eeprom; /* EEPROM regulatory limit */ struct iwl_eeprom_channel ht40_eeprom; /* EEPROM regulatory limit for * HT40 channel */ @@ -245,14 +203,6 @@ struct iwl_channel_info { s8 ht40_max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */ u8 ht40_flags; /* flags copied from EEPROM */ u8 ht40_extension_channel; /* HT_IE_EXT_CHANNEL_* */ - - /* Radio/DSP gain settings for each "normal" data Tx rate. - * These include, in addition to RF and DSP gain, a few fields for - * remembering/modifying gain settings (indexes). */ - struct iwl3945_channel_power_info power_info[IWL4965_MAX_RATE]; - - /* Radio/DSP gain settings for each scan rate, for directed scans. */ - struct iwl3945_scan_power_info scan_pwr_info[IWL_NUM_SCAN_RATES]; }; #define IWL_TX_FIFO_BK 0 /* shared */ @@ -309,6 +259,7 @@ enum { CMD_SIZE_HUGE = (1 << 0), CMD_ASYNC = (1 << 1), CMD_WANT_SKB = (1 << 2), + CMD_MAPPED = (1 << 3), }; #define DEF_CMD_PAYLOAD_SIZE 320 @@ -416,6 +367,7 @@ struct iwl_ht_agg { #define IWL_EMPTYING_HW_QUEUE_ADDBA 2 #define IWL_EMPTYING_HW_QUEUE_DELBA 3 u8 state; + u8 tx_fifo; }; @@ -499,9 +451,6 @@ struct iwl_station_priv_common { * When mac80211 creates a station it reserves some space (hw->sta_data_size) * in the structure for use by driver. This structure is places in that * space. - * - * The common struct MUST be first because it is shared between - * 3945 and agn! */ struct iwl_station_priv { struct iwl_station_priv_common common; @@ -586,6 +535,22 @@ enum iwl_ucode_tlv_type { IWL_UCODE_TLV_INIT_ERRLOG_PTR = 13, IWL_UCODE_TLV_ENHANCE_SENS_TBL = 14, IWL_UCODE_TLV_PHY_CALIBRATION_SIZE = 15, + /* 16 and 17 reserved for future use */ + IWL_UCODE_TLV_FLAGS = 18, +}; + +/** + * enum iwl_ucode_tlv_flag - ucode API flags + * @IWL_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously + * was a separate TLV but moved here to save space. + * @IWL_UCODE_TLV_FLAGS_BTSTATS: This uCode image uses BT statistics, which + * may be true even if the device doesn't have BT. + * @IWL_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w). + */ +enum iwl_ucode_tlv_flag { + IWL_UCODE_TLV_FLAGS_PAN = BIT(0), + IWL_UCODE_TLV_FLAGS_BTSTATS = BIT(1), + IWL_UCODE_TLV_FLAGS_MFP = BIT(2), }; struct iwl_ucode_tlv { @@ -619,14 +584,6 @@ struct iwl_tlv_ucode_header { u8 data[0]; }; -struct iwl4965_ibss_seq { - u8 mac[ETH_ALEN]; - u16 seq_num; - u16 frag_num; - unsigned long packet_time; - struct list_head list; -}; - struct iwl_sensitivity_ranges { u16 min_nrg_cck; u16 max_nrg_cck; @@ -700,7 +657,6 @@ struct iwl_hw_params { u8 max_beacon_itrvl; /* in 1024 ms */ u32 max_inst_size; u32 max_data_size; - u32 max_bsm_size; u32 ct_kill_threshold; /* value in hw-dependent units */ u32 ct_kill_exit_threshold; /* value in hw-dependent units */ /* for 1000, 6000 series and up */ @@ -722,8 +678,6 @@ struct iwl_hw_params { * Naming convention -- * iwl_ <-- Is part of iwlwifi * iwlXXXX_ <-- Hardware specific (implemented in iwl-XXXX.c for XXXX) - * iwl4965_bg_ <-- Called from work queue context - * iwl4965_mac_ <-- mac80211 callback * ****************************************************************************/ extern void iwl_update_chain_flags(struct iwl_priv *priv); @@ -772,7 +726,6 @@ struct iwl_dma_ptr { /* Sensitivity and chain noise calibration */ #define INITIALIZATION_VALUE 0xFFFF -#define IWL4965_CAL_NUM_BEACONS 20 #define IWL_CAL_NUM_BEACONS 16 #define MAXIMUM_ALLOWED_PATHLOSS 15 @@ -806,24 +759,19 @@ struct iwl_dma_ptr { #define NRG_NUM_PREV_STAT_L 20 #define NUM_RX_CHAINS 3 -enum iwl4965_false_alarm_state { +enum iwlagn_false_alarm_state { IWL_FA_TOO_MANY = 0, IWL_FA_TOO_FEW = 1, IWL_FA_GOOD_RANGE = 2, }; -enum iwl4965_chain_noise_state { +enum iwlagn_chain_noise_state { IWL_CHAIN_NOISE_ALIVE = 0, /* must be 0 */ IWL_CHAIN_NOISE_ACCUMULATE, IWL_CHAIN_NOISE_CALIBRATED, IWL_CHAIN_NOISE_DONE, }; -enum iwl4965_calib_enabled_state { - IWL_CALIB_DISABLED = 0, /* must be 0 */ - IWL_CALIB_ENABLED = 1, -}; - /* * enum iwl_calib @@ -1131,12 +1079,6 @@ struct iwl_force_reset { /* extend beacon time format bit shifting */ /* - * for _3945 devices - * bits 31:24 - extended - * bits 23:0 - interval - */ -#define IWL3945_EXT_BEACON_TIME_POS 24 -/* * for _agn devices * bits 31:22 - extended * bits 21:0 - interval @@ -1249,7 +1191,6 @@ struct iwl_priv { int frames_count; enum ieee80211_band band; - int alloc_rxb_page; void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); @@ -1305,16 +1246,12 @@ struct iwl_priv { spinlock_t hcmd_lock; /* protect hcmd */ spinlock_t reg_lock; /* protect hw register access */ struct mutex mutex; - struct mutex sync_cmd_mutex; /* enable serialization of sync commands */ /* basic pci-network driver stuff */ struct pci_dev *pci_dev; /* pci hardware address support */ void __iomem *hw_base; - u32 hw_rev; - u32 hw_wa_rev; - u8 rev_id; /* microcode/device supports multiple contexts */ u8 valid_contexts; @@ -1334,10 +1271,8 @@ struct iwl_priv { iwl_ucode.ver */ struct fw_desc ucode_code; /* runtime inst */ struct fw_desc ucode_data; /* runtime data original */ - struct fw_desc ucode_data_backup; /* runtime data save/restore */ struct fw_desc ucode_init; /* initialization inst */ struct fw_desc ucode_init_data; /* initialization data */ - struct fw_desc ucode_boot; /* bootstrap inst */ enum ucode_type ucode_type; u8 ucode_write_complete; /* the image write is complete */ char firmware_name[25]; @@ -1346,10 +1281,10 @@ struct iwl_priv { struct iwl_switch_rxon switch_rxon; - /* 1st responses from initialize and runtime uCode images. - * _agn's initialize alive response contains some calibration data. */ - struct iwl_init_alive_resp card_alive_init; - struct iwl_alive_resp card_alive; + struct { + u32 error_event_table; + u32 log_event_table; + } device_pointers; u16 active_rate; @@ -1390,15 +1325,12 @@ struct iwl_priv { struct iwl_power_mgr power_data; struct iwl_tt_mgmt thermal_throttle; - /* context information */ - u8 bssid[ETH_ALEN]; /* used only on 3945 but filled by core */ - /* station table variables */ /* Note: if lock and sta_lock are needed, lock must be acquired first */ spinlock_t sta_lock; int num_stations; - struct iwl_station_entry stations[IWL_STATION_COUNT]; + struct iwl_station_entry stations[IWLAGN_STATION_COUNT]; unsigned long ucode_key_table; /* queue refcounts */ @@ -1422,101 +1354,66 @@ struct iwl_priv { /* Last Rx'd beacon timestamp */ u64 timestamp; - union { -#if defined(CONFIG_IWL3945) || defined(CONFIG_IWL3945_MODULE) - struct { - void *shared_virt; - dma_addr_t shared_phys; - - struct delayed_work thermal_periodic; - struct delayed_work rfkill_poll; - - struct iwl3945_notif_statistics statistics; -#ifdef CONFIG_IWLWIFI_DEBUGFS - struct iwl3945_notif_statistics accum_statistics; - struct iwl3945_notif_statistics delta_statistics; - struct iwl3945_notif_statistics max_delta; -#endif - - u32 sta_supp_rates; - int last_rx_rssi; /* From Rx packet statistics */ - - /* Rx'd packet timing information */ - u32 last_beacon_time; - u64 last_tsf; - - /* - * each calibration channel group in the - * EEPROM has a derived clip setting for - * each rate. - */ - const struct iwl3945_clip_group clip_groups[5]; - - } _3945; -#endif -#if defined(CONFIG_IWLAGN) || defined(CONFIG_IWLAGN_MODULE) - struct { - /* INT ICT Table */ - __le32 *ict_tbl; - void *ict_tbl_vir; - dma_addr_t ict_tbl_dma; - dma_addr_t aligned_ict_tbl_dma; - int ict_index; - u32 inta; - bool use_ict; - /* - * reporting the number of tids has AGG on. 0 means - * no AGGREGATION - */ - u8 agg_tids_count; - - struct iwl_rx_phy_res last_phy_res; - bool last_phy_res_valid; - - struct completion firmware_loading_complete; - - u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; - u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; - - /* - * chain noise reset and gain commands are the - * two extra calibration commands follows the standard - * phy calibration commands - */ - u8 phy_calib_chain_noise_reset_cmd; - u8 phy_calib_chain_noise_gain_cmd; - - struct iwl_notif_statistics statistics; - struct iwl_bt_notif_statistics statistics_bt; - /* counts reply_tx error */ - struct reply_tx_error_statistics reply_tx_stats; - struct reply_agg_tx_error_statistics reply_agg_tx_stats; + struct { + /* INT ICT Table */ + __le32 *ict_tbl; + void *ict_tbl_vir; + dma_addr_t ict_tbl_dma; + dma_addr_t aligned_ict_tbl_dma; + int ict_index; + u32 inta; + bool use_ict; + /* + * reporting the number of tids has AGG on. 0 means + * no AGGREGATION + */ + u8 agg_tids_count; + + struct iwl_rx_phy_res last_phy_res; + bool last_phy_res_valid; + + struct completion firmware_loading_complete; + + u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; + u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; + + /* + * chain noise reset and gain commands are the + * two extra calibration commands follows the standard + * phy calibration commands + */ + u8 phy_calib_chain_noise_reset_cmd; + u8 phy_calib_chain_noise_gain_cmd; + + struct iwl_notif_statistics statistics; + struct iwl_bt_notif_statistics statistics_bt; + /* counts reply_tx error */ + struct reply_tx_error_statistics reply_tx_stats; + struct reply_agg_tx_error_statistics reply_agg_tx_stats; #ifdef CONFIG_IWLWIFI_DEBUGFS - struct iwl_notif_statistics accum_statistics; - struct iwl_notif_statistics delta_statistics; - struct iwl_notif_statistics max_delta; - struct iwl_bt_notif_statistics accum_statistics_bt; - struct iwl_bt_notif_statistics delta_statistics_bt; - struct iwl_bt_notif_statistics max_delta_bt; + struct iwl_notif_statistics accum_statistics; + struct iwl_notif_statistics delta_statistics; + struct iwl_notif_statistics max_delta; + struct iwl_bt_notif_statistics accum_statistics_bt; + struct iwl_bt_notif_statistics delta_statistics_bt; + struct iwl_bt_notif_statistics max_delta_bt; #endif - - /* notification wait support */ - struct list_head notif_waits; - spinlock_t notif_wait_lock; - wait_queue_head_t notif_waitq; - - /* remain-on-channel offload support */ - struct ieee80211_channel *hw_roc_channel; - struct delayed_work hw_roc_work; - enum nl80211_channel_type hw_roc_chantype; - int hw_roc_duration; - - struct sk_buff *offchan_tx_skb; - int offchan_tx_timeout; - struct ieee80211_channel *offchan_tx_chan; - } _agn; -#endif - }; + /* notification wait support */ + struct list_head notif_waits; + spinlock_t notif_wait_lock; + wait_queue_head_t notif_waitq; + + /* remain-on-channel offload support */ + struct ieee80211_channel *hw_roc_channel; + struct delayed_work hw_roc_work; + enum nl80211_channel_type hw_roc_chantype; + int hw_roc_duration; + bool hw_roc_setup; + + struct sk_buff *offchan_tx_skb; + int offchan_tx_timeout; + struct ieee80211_channel *offchan_tx_chan; + } _agn; /* bt coex */ u8 bt_enable_flag; @@ -1525,6 +1422,7 @@ struct iwl_priv { bool bt_ch_announce; bool bt_full_concurrent; bool bt_ant_couple_ok; + bool bt_statistics; __le32 kill_ack_mask; __le32 kill_cts_mask; __le16 bt_valid; @@ -1710,12 +1608,10 @@ static inline int is_channel_ibss(const struct iwl_channel_info *ch) static inline void __iwl_free_pages(struct iwl_priv *priv, struct page *page) { __free_pages(page, priv->hw_params.rx_page_order); - priv->alloc_rxb_page--; } static inline void iwl_free_pages(struct iwl_priv *priv, unsigned long page) { free_pages(page, priv->hw_params.rx_page_order); - priv->alloc_rxb_page--; } #endif /* __iwl_dev_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.c b/drivers/net/wireless/iwlwifi/iwl-devtrace.c index 4a487639d932..a635a7e75447 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.c +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2009 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2009 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h index 4cf864c664ee..f00172cb8a6d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2009 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2009 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 833194a2c639..859b94a12297 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -188,18 +188,16 @@ static void iwl_set_otp_access(struct iwl_priv *priv, enum iwl_access_mode mode) CSR_OTP_GP_REG_OTP_ACCESS_MODE); } -static int iwlcore_get_nvm_type(struct iwl_priv *priv) +static int iwlcore_get_nvm_type(struct iwl_priv *priv, u32 hw_rev) { u32 otpgp; int nvm_type; /* OTP only valid for CP/PP and after */ - switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { + switch (hw_rev & CSR_HW_REV_TYPE_MSK) { case CSR_HW_REV_TYPE_NONE: IWL_ERR(priv, "Unknown hardware type\n"); return -ENOENT; - case CSR_HW_REV_TYPE_3945: - case CSR_HW_REV_TYPE_4965: case CSR_HW_REV_TYPE_5300: case CSR_HW_REV_TYPE_5350: case CSR_HW_REV_TYPE_5100: @@ -228,15 +226,15 @@ static int iwl_init_otp_access(struct iwl_priv *priv) int ret; /* Enable 40MHz radio clock */ - _iwl_write32(priv, CSR_GP_CNTRL, - _iwl_read32(priv, CSR_GP_CNTRL) | - CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + iwl_write32(priv, CSR_GP_CNTRL, + iwl_read32(priv, CSR_GP_CNTRL) | + CSR_GP_CNTRL_REG_FLAG_INIT_DONE); /* wait for clock to be ready */ ret = iwl_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - 25000); + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + 25000); if (ret < 0) IWL_ERR(priv, "Time out access OTP\n"); else { @@ -263,17 +261,17 @@ static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, __le16 *eeprom_dat u32 r; u32 otpgp; - _iwl_write32(priv, CSR_EEPROM_REG, - CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); + iwl_write32(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); ret = iwl_poll_bit(priv, CSR_EEPROM_REG, - CSR_EEPROM_REG_READ_VALID_MSK, - CSR_EEPROM_REG_READ_VALID_MSK, - IWL_EEPROM_ACCESS_TIMEOUT); + CSR_EEPROM_REG_READ_VALID_MSK, + CSR_EEPROM_REG_READ_VALID_MSK, + IWL_EEPROM_ACCESS_TIMEOUT); if (ret < 0) { IWL_ERR(priv, "Time out reading OTP[%d]\n", addr); return ret; } - r = _iwl_read_direct32(priv, CSR_EEPROM_REG); + r = iwl_read32(priv, CSR_EEPROM_REG); /* check for ECC errors: */ otpgp = iwl_read32(priv, CSR_OTP_GP_REG); if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) { @@ -396,7 +394,7 @@ u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset) * * NOTE: This routine uses the non-debug IO access functions. */ -int iwl_eeprom_init(struct iwl_priv *priv) +int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev) { __le16 *e; u32 gp = iwl_read32(priv, CSR_EEPROM_GP); @@ -406,7 +404,7 @@ int iwl_eeprom_init(struct iwl_priv *priv) u16 validblockaddr = 0; u16 cache_addr = 0; - priv->nvm_device_type = iwlcore_get_nvm_type(priv); + priv->nvm_device_type = iwlcore_get_nvm_type(priv, hw_rev); if (priv->nvm_device_type == -ENOENT) return -ENOENT; /* allocate eeprom */ @@ -444,9 +442,9 @@ int iwl_eeprom_init(struct iwl_priv *priv) ret = -ENOENT; goto done; } - _iwl_write32(priv, CSR_EEPROM_GP, - iwl_read32(priv, CSR_EEPROM_GP) & - ~CSR_EEPROM_GP_IF_OWNER_MSK); + iwl_write32(priv, CSR_EEPROM_GP, + iwl_read32(priv, CSR_EEPROM_GP) & + ~CSR_EEPROM_GP_IF_OWNER_MSK); iwl_set_bit(priv, CSR_OTP_GP_REG, CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK | @@ -473,8 +471,8 @@ int iwl_eeprom_init(struct iwl_priv *priv) for (addr = 0; addr < sz; addr += sizeof(u16)) { u32 r; - _iwl_write32(priv, CSR_EEPROM_REG, - CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); + iwl_write32(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); ret = iwl_poll_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_READ_VALID_MSK, @@ -484,7 +482,7 @@ int iwl_eeprom_init(struct iwl_priv *priv) IWL_ERR(priv, "Time out reading EEPROM[%d]\n", addr); goto done; } - r = _iwl_read_direct32(priv, CSR_EEPROM_REG); + r = iwl_read32(priv, CSR_EEPROM_REG); e[addr / 2] = cpu_to_le16(r >> 16); } } diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 20b66469d68f..0e9d9703636a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -110,10 +110,6 @@ enum { }; /* SKU Capabilities */ -/* 3945 only */ -#define EEPROM_SKU_CAP_SW_RF_KILL_ENABLE (1 << 0) -#define EEPROM_SKU_CAP_HW_RF_KILL_ENABLE (1 << 1) - /* 5000 and up */ #define EEPROM_SKU_CAP_BAND_POS (4) #define EEPROM_SKU_CAP_BAND_SELECTION \ @@ -168,28 +164,6 @@ struct iwl_eeprom_enhanced_txpwr { s8 mimo3_max; } __packed; -/* 3945 Specific */ -#define EEPROM_3945_EEPROM_VERSION (0x2f) - -/* 4965 has two radio transmitters (and 3 radio receivers) */ -#define EEPROM_TX_POWER_TX_CHAINS (2) - -/* 4965 has room for up to 8 sets of txpower calibration data */ -#define EEPROM_TX_POWER_BANDS (8) - -/* 4965 factory calibration measures txpower gain settings for - * each of 3 target output levels */ -#define EEPROM_TX_POWER_MEASUREMENTS (3) - -/* 4965 Specific */ -/* 4965 driver does not work with txpower calibration version < 5 */ -#define EEPROM_4965_TX_POWER_VERSION (5) -#define EEPROM_4965_EEPROM_VERSION (0x2f) -#define EEPROM_4965_CALIB_VERSION_OFFSET (2*0xB6) /* 2 bytes */ -#define EEPROM_4965_CALIB_TXPOWER_OFFSET (2*0xE8) /* 48 bytes */ -#define EEPROM_4965_BOARD_REVISION (2*0x4F) /* 2 bytes */ -#define EEPROM_4965_BOARD_PBA (2*0x56+1) /* 9 bytes */ - /* 5000 Specific */ #define EEPROM_5000_TX_POWER_VERSION (4) #define EEPROM_5000_EEPROM_VERSION (0x11A) @@ -282,90 +256,6 @@ struct iwl_eeprom_enhanced_txpwr { /* 2.4 GHz */ extern const u8 iwl_eeprom_band_1[14]; -/* - * factory calibration data for one txpower level, on one channel, - * measured on one of the 2 tx chains (radio transmitter and associated - * antenna). EEPROM contains: - * - * 1) Temperature (degrees Celsius) of device when measurement was made. - * - * 2) Gain table index used to achieve the target measurement power. - * This refers to the "well-known" gain tables (see iwl-4965-hw.h). - * - * 3) Actual measured output power, in half-dBm ("34" = 17 dBm). - * - * 4) RF power amplifier detector level measurement (not used). - */ -struct iwl_eeprom_calib_measure { - u8 temperature; /* Device temperature (Celsius) */ - u8 gain_idx; /* Index into gain table */ - u8 actual_pow; /* Measured RF output power, half-dBm */ - s8 pa_det; /* Power amp detector level (not used) */ -} __packed; - - -/* - * measurement set for one channel. EEPROM contains: - * - * 1) Channel number measured - * - * 2) Measurements for each of 3 power levels for each of 2 radio transmitters - * (a.k.a. "tx chains") (6 measurements altogether) - */ -struct iwl_eeprom_calib_ch_info { - u8 ch_num; - struct iwl_eeprom_calib_measure - measurements[EEPROM_TX_POWER_TX_CHAINS] - [EEPROM_TX_POWER_MEASUREMENTS]; -} __packed; - -/* - * txpower subband info. - * - * For each frequency subband, EEPROM contains the following: - * - * 1) First and last channels within range of the subband. "0" values - * indicate that this sample set is not being used. - * - * 2) Sample measurement sets for 2 channels close to the range endpoints. - */ -struct iwl_eeprom_calib_subband_info { - u8 ch_from; /* channel number of lowest channel in subband */ - u8 ch_to; /* channel number of highest channel in subband */ - struct iwl_eeprom_calib_ch_info ch1; - struct iwl_eeprom_calib_ch_info ch2; -} __packed; - - -/* - * txpower calibration info. EEPROM contains: - * - * 1) Factory-measured saturation power levels (maximum levels at which - * tx power amplifier can output a signal without too much distortion). - * There is one level for 2.4 GHz band and one for 5 GHz band. These - * values apply to all channels within each of the bands. - * - * 2) Factory-measured power supply voltage level. This is assumed to be - * constant (i.e. same value applies to all channels/bands) while the - * factory measurements are being made. - * - * 3) Up to 8 sets of factory-measured txpower calibration values. - * These are for different frequency ranges, since txpower gain - * characteristics of the analog radio circuitry vary with frequency. - * - * Not all sets need to be filled with data; - * struct iwl_eeprom_calib_subband_info contains range of channels - * (0 if unused) for each set of data. - */ -struct iwl_eeprom_calib_info { - u8 saturation_power24; /* half-dBm (e.g. "34" = 17 dBm) */ - u8 saturation_power52; /* half-dBm */ - __le16 voltage; /* signed */ - struct iwl_eeprom_calib_subband_info - band_info[EEPROM_TX_POWER_BANDS]; -} __packed; - - #define ADDRESS_MSK 0x0000FFFF #define INDIRECT_TYPE_MSK 0x000F0000 #define INDIRECT_HOST 0x00010000 @@ -398,83 +288,8 @@ struct iwl_eeprom_calib_info { #define EEPROM_RF_CFG_TX_ANT_MSK(x) ((x >> 8) & 0xF) /* bits 8-11 */ #define EEPROM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */ -#define EEPROM_3945_RF_CFG_TYPE_MAX 0x0 -#define EEPROM_4965_RF_CFG_TYPE_MAX 0x1 - -/* Radio Config for 5000 and up */ -#define EEPROM_RF_CONFIG_TYPE_R3x3 0x0 -#define EEPROM_RF_CONFIG_TYPE_R2x2 0x1 -#define EEPROM_RF_CONFIG_TYPE_R1x2 0x2 #define EEPROM_RF_CONFIG_TYPE_MAX 0x3 -/* - * Per-channel regulatory data. - * - * Each channel that *might* be supported by iwl has a fixed location - * in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory - * txpower (MSB). - * - * Entries immediately below are for 20 MHz channel width. HT40 (40 MHz) - * channels (only for 4965, not supported by 3945) appear later in the EEPROM. - * - * 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 - */ -#define EEPROM_REGULATORY_SKU_ID (2*0x60) /* 4 bytes */ -#define EEPROM_REGULATORY_BAND_1 (2*0x62) /* 2 bytes */ -#define EEPROM_REGULATORY_BAND_1_CHANNELS (2*0x63) /* 28 bytes */ - -/* - * 4.9 GHz channels 183, 184, 185, 187, 188, 189, 192, 196, - * 5.0 GHz channels 7, 8, 11, 12, 16 - * (4915-5080MHz) (none of these is ever supported) - */ -#define EEPROM_REGULATORY_BAND_2 (2*0x71) /* 2 bytes */ -#define EEPROM_REGULATORY_BAND_2_CHANNELS (2*0x72) /* 26 bytes */ - -/* - * 5.2 GHz channels 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64 - * (5170-5320MHz) - */ -#define EEPROM_REGULATORY_BAND_3 (2*0x7F) /* 2 bytes */ -#define EEPROM_REGULATORY_BAND_3_CHANNELS (2*0x80) /* 24 bytes */ - -/* - * 5.5 GHz channels 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 - * (5500-5700MHz) - */ -#define EEPROM_REGULATORY_BAND_4 (2*0x8C) /* 2 bytes */ -#define EEPROM_REGULATORY_BAND_4_CHANNELS (2*0x8D) /* 22 bytes */ - -/* - * 5.7 GHz channels 145, 149, 153, 157, 161, 165 - * (5725-5825MHz) - */ -#define EEPROM_REGULATORY_BAND_5 (2*0x98) /* 2 bytes */ -#define EEPROM_REGULATORY_BAND_5_CHANNELS (2*0x99) /* 12 bytes */ - -/* - * 2.4 GHz HT40 channels 1 (5), 2 (6), 3 (7), 4 (8), 5 (9), 6 (10), 7 (11) - * - * The channel listed is the center of the lower 20 MHz half of the channel. - * The overall center frequency is actually 2 channels (10 MHz) above that, - * and the upper half of each HT40 channel is centered 4 channels (20 MHz) away - * from the lower half; e.g. the upper half of HT40 channel 1 is channel 5, - * and the overall HT40 channel width centers on channel 3. - * - * NOTE: The RXON command uses 20 MHz channel numbers to specify the - * control channel to which to tune. RXON also specifies whether the - * control channel is the upper or lower half of a HT40 channel. - * - * NOTE: 4965 does not support HT40 channels on 2.4 GHz. - */ -#define EEPROM_4965_REGULATORY_BAND_24_HT40_CHANNELS (2*0xA0) /* 14 bytes */ - -/* - * 5.2 GHz HT40 channels 36 (40), 44 (48), 52 (56), 60 (64), - * 100 (104), 108 (112), 116 (120), 124 (128), 132 (136), 149 (153), 157 (161) - */ -#define EEPROM_4965_REGULATORY_BAND_52_HT40_CHANNELS (2*0xA8) /* 22 bytes */ - #define EEPROM_REGULATORY_BAND_NO_HT40 (0) struct iwl_eeprom_ops { @@ -487,7 +302,7 @@ struct iwl_eeprom_ops { }; -int iwl_eeprom_init(struct iwl_priv *priv); +int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev); void iwl_eeprom_free(struct iwl_priv *priv); int iwl_eeprom_check_version(struct iwl_priv *priv); int iwl_eeprom_check_sku(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index 474009a244d4..e7a1bc6b76fd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index 02499f684683..9177b553fe57 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -51,9 +51,7 @@ const char *get_cmd_string(u8 cmd) IWL_CMD(REPLY_REMOVE_ALL_STA); IWL_CMD(REPLY_TXFIFO_FLUSH); IWL_CMD(REPLY_WEPKEY); - IWL_CMD(REPLY_3945_RX); IWL_CMD(REPLY_TX); - IWL_CMD(REPLY_RATE_SCALE); IWL_CMD(REPLY_LEDS_CMD); IWL_CMD(REPLY_TX_LINK_QUALITY_CMD); IWL_CMD(COEX_PRIORITY_TABLE_CMD); @@ -171,14 +169,13 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) int cmd_idx; int ret; - BUG_ON(cmd->flags & CMD_ASYNC); + lockdep_assert_held(&priv->mutex); /* A synchronous command can not have a callback set. */ - BUG_ON(cmd->callback); + BUG_ON((cmd->flags & CMD_ASYNC) || cmd->callback); IWL_DEBUG_INFO(priv, "Attempting to send sync command %s\n", get_cmd_string(cmd->id)); - mutex_lock(&priv->sync_cmd_mutex); set_bit(STATUS_HCMD_ACTIVE, &priv->status); IWL_DEBUG_INFO(priv, "Setting HCMD_ACTIVE for command %s\n", @@ -189,7 +186,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) ret = cmd_idx; IWL_ERR(priv, "Error sending %s: enqueue_hcmd failed: %d\n", get_cmd_string(cmd->id), ret); - goto out; + return ret; } ret = wait_event_interruptible_timeout(priv->wait_command_queue, @@ -229,8 +226,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) goto cancel; } - ret = 0; - goto out; + return 0; cancel: if (cmd->flags & CMD_WANT_SKB) { @@ -248,8 +244,7 @@ fail: iwl_free_pages(priv, cmd->reply_page); cmd->reply_page = 0; } -out: - mutex_unlock(&priv->sync_cmd_mutex); + return ret; } diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h index 8821f088ba7f..5da5761c74b1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-helpers.h +++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c new file mode 100644 index 000000000000..51337416e4ca --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-io.c @@ -0,0 +1,274 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * Intel Linux Wireless <ilw@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#include "iwl-io.h" + +#define IWL_POLL_INTERVAL 10 /* microseconds */ + +static inline void __iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask) +{ + iwl_write32(priv, reg, iwl_read32(priv, reg) | mask); +} + +static inline void __iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask) +{ + iwl_write32(priv, reg, iwl_read32(priv, reg) & ~mask); +} + +void iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->reg_lock, flags); + __iwl_set_bit(priv, reg, mask); + spin_unlock_irqrestore(&priv->reg_lock, flags); +} + +void iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->reg_lock, flags); + __iwl_clear_bit(priv, reg, mask); + spin_unlock_irqrestore(&priv->reg_lock, flags); +} + +int iwl_poll_bit(struct iwl_priv *priv, u32 addr, + u32 bits, u32 mask, int timeout) +{ + int t = 0; + + do { + if ((iwl_read32(priv, addr) & mask) == (bits & mask)) + return t; + udelay(IWL_POLL_INTERVAL); + t += IWL_POLL_INTERVAL; + } while (t < timeout); + + return -ETIMEDOUT; +} + +int iwl_grab_nic_access(struct iwl_priv *priv) +{ + int ret; + u32 val; + + lockdep_assert_held(&priv->reg_lock); + + /* this bit wakes up the NIC */ + __iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + + /* + * These bits say the device is running, and should keep running for + * at least a short while (at least as long as MAC_ACCESS_REQ stays 1), + * but they do not indicate that embedded SRAM is restored yet; + * 3945 and 4965 have volatile SRAM, and must save/restore contents + * to/from host DRAM when sleeping/waking for power-saving. + * Each direction takes approximately 1/4 millisecond; with this + * overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a + * series of register accesses are expected (e.g. reading Event Log), + * to keep device from sleeping. + * + * CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that + * SRAM is okay/restored. We don't check that here because this call + * is just for hardware register access; but GP1 MAC_SLEEP check is a + * good idea before accessing 3945/4965 SRAM (e.g. reading Event Log). + * + * 5000 series and later (including 1000 series) have non-volatile SRAM, + * and do not save/restore SRAM when power cycling. + */ + ret = iwl_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, + (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | + CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000); + if (ret < 0) { + val = iwl_read32(priv, CSR_GP_CNTRL); + IWL_ERR(priv, + "MAC is in deep sleep!. CSR_GP_CNTRL = 0x%08X\n", val); + iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI); + return -EIO; + } + + return 0; +} + +void iwl_release_nic_access(struct iwl_priv *priv) +{ + lockdep_assert_held(&priv->reg_lock); + __iwl_clear_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); +} + +u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg) +{ + u32 value; + unsigned long flags; + + spin_lock_irqsave(&priv->reg_lock, flags); + iwl_grab_nic_access(priv); + value = iwl_read32(priv, reg); + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, flags); + + return value; +} + +void iwl_write_direct32(struct iwl_priv *priv, u32 reg, u32 value) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->reg_lock, flags); + if (!iwl_grab_nic_access(priv)) { + iwl_write32(priv, reg, value); + iwl_release_nic_access(priv); + } + spin_unlock_irqrestore(&priv->reg_lock, flags); +} + +int iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, u32 mask, + int timeout) +{ + int t = 0; + + do { + if ((iwl_read_direct32(priv, addr) & mask) == mask) + return t; + udelay(IWL_POLL_INTERVAL); + t += IWL_POLL_INTERVAL; + } while (t < timeout); + + return -ETIMEDOUT; +} + +static inline u32 __iwl_read_prph(struct iwl_priv *priv, u32 reg) +{ + iwl_write32(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24)); + rmb(); + return iwl_read32(priv, HBUS_TARG_PRPH_RDAT); +} + +static inline void __iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val) +{ + iwl_write32(priv, HBUS_TARG_PRPH_WADDR, + ((addr & 0x0000FFFF) | (3 << 24))); + wmb(); + iwl_write32(priv, HBUS_TARG_PRPH_WDAT, val); +} + +u32 iwl_read_prph(struct iwl_priv *priv, u32 reg) +{ + unsigned long flags; + u32 val; + + spin_lock_irqsave(&priv->reg_lock, flags); + iwl_grab_nic_access(priv); + val = __iwl_read_prph(priv, reg); + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, flags); + return val; +} + +void iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->reg_lock, flags); + if (!iwl_grab_nic_access(priv)) { + __iwl_write_prph(priv, addr, val); + iwl_release_nic_access(priv); + } + spin_unlock_irqrestore(&priv->reg_lock, flags); +} + +void iwl_set_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->reg_lock, flags); + iwl_grab_nic_access(priv); + __iwl_write_prph(priv, reg, __iwl_read_prph(priv, reg) | mask); + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, flags); +} + +void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg, + u32 bits, u32 mask) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->reg_lock, flags); + iwl_grab_nic_access(priv); + __iwl_write_prph(priv, reg, + (__iwl_read_prph(priv, reg) & mask) | bits); + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, flags); +} + +void iwl_clear_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask) +{ + unsigned long flags; + u32 val; + + spin_lock_irqsave(&priv->reg_lock, flags); + iwl_grab_nic_access(priv); + val = __iwl_read_prph(priv, reg); + __iwl_write_prph(priv, reg, (val & ~mask)); + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, flags); +} + +u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr) +{ + unsigned long flags; + u32 value; + + spin_lock_irqsave(&priv->reg_lock, flags); + iwl_grab_nic_access(priv); + + iwl_write32(priv, HBUS_TARG_MEM_RADDR, addr); + rmb(); + value = iwl_read32(priv, HBUS_TARG_MEM_RDAT); + + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, flags); + return value; +} + +void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->reg_lock, flags); + if (!iwl_grab_nic_access(priv)) { + iwl_write32(priv, HBUS_TARG_MEM_WADDR, addr); + wmb(); + iwl_write32(priv, HBUS_TARG_MEM_WDAT, val); + iwl_release_nic_access(priv); + } + spin_unlock_irqrestore(&priv->reg_lock, flags); +} diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index 0203a3bbf872..ab632baf49d5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project. * @@ -35,494 +35,47 @@ #include "iwl-debug.h" #include "iwl-devtrace.h" -/* - * IO, register, and NIC memory access functions - * - * NOTE on naming convention and macro usage for these - * - * A single _ prefix before a an access function means that no state - * check or debug information is printed when that function is called. - * - * A double __ prefix before an access function means that state is checked - * and the current line number and caller function name are printed in addition - * to any other debug output. - * - * The non-prefixed name is the #define that maps the caller into a - * #define that provides the caller's name and __LINE__ to the double - * prefix version. - * - * If you wish to call the function without any debug or state checking, - * you should use the single _ prefix version (as is used by dependent IO - * routines, for example _iwl_read_direct32 calls the non-check version of - * _iwl_read32.) - * - * These declarations are *extremely* useful in quickly isolating code deltas - * which result in misconfiguration of the hardware I/O. In combination with - * git-bisect and the IO debug level you can quickly determine the specific - * commit which breaks the IO sequence to the hardware. - * - */ - -static inline void _iwl_write8(struct iwl_priv *priv, u32 ofs, u8 val) +static inline void iwl_write8(struct iwl_priv *priv, u32 ofs, u8 val) { trace_iwlwifi_dev_iowrite8(priv, ofs, val); iowrite8(val, priv->hw_base + ofs); } -#ifdef CONFIG_IWLWIFI_DEBUG -static inline void __iwl_write8(const char *f, u32 l, struct iwl_priv *priv, - u32 ofs, u8 val) -{ - IWL_DEBUG_IO(priv, "write8(0x%08X, 0x%02X) - %s %d\n", ofs, val, f, l); - _iwl_write8(priv, ofs, val); -} -#define iwl_write8(priv, ofs, val) \ - __iwl_write8(__FILE__, __LINE__, priv, ofs, val) -#else -#define iwl_write8(priv, ofs, val) _iwl_write8(priv, ofs, val) -#endif - - -static inline void _iwl_write32(struct iwl_priv *priv, u32 ofs, u32 val) +static inline void iwl_write32(struct iwl_priv *priv, u32 ofs, u32 val) { trace_iwlwifi_dev_iowrite32(priv, ofs, val); iowrite32(val, priv->hw_base + ofs); } -#ifdef CONFIG_IWLWIFI_DEBUG -static inline void __iwl_write32(const char *f, u32 l, struct iwl_priv *priv, - u32 ofs, u32 val) -{ - IWL_DEBUG_IO(priv, "write32(0x%08X, 0x%08X) - %s %d\n", ofs, val, f, l); - _iwl_write32(priv, ofs, val); -} -#define iwl_write32(priv, ofs, val) \ - __iwl_write32(__FILE__, __LINE__, priv, ofs, val) -#else -#define iwl_write32(priv, ofs, val) _iwl_write32(priv, ofs, val) -#endif - -static inline u32 _iwl_read32(struct iwl_priv *priv, u32 ofs) +static inline u32 iwl_read32(struct iwl_priv *priv, u32 ofs) { u32 val = ioread32(priv->hw_base + ofs); trace_iwlwifi_dev_ioread32(priv, ofs, val); return val; } -#ifdef CONFIG_IWLWIFI_DEBUG -static inline u32 __iwl_read32(char *f, u32 l, struct iwl_priv *priv, u32 ofs) -{ - IWL_DEBUG_IO(priv, "read_direct32(0x%08X) - %s %d\n", ofs, f, l); - return _iwl_read32(priv, ofs); -} -#define iwl_read32(priv, ofs) __iwl_read32(__FILE__, __LINE__, priv, ofs) -#else -#define iwl_read32(p, o) _iwl_read32(p, o) -#endif - -#define IWL_POLL_INTERVAL 10 /* microseconds */ -static inline int _iwl_poll_bit(struct iwl_priv *priv, u32 addr, - u32 bits, u32 mask, int timeout) -{ - int t = 0; - - do { - if ((_iwl_read32(priv, addr) & mask) == (bits & mask)) - return t; - udelay(IWL_POLL_INTERVAL); - t += IWL_POLL_INTERVAL; - } while (t < timeout); - - return -ETIMEDOUT; -} -#ifdef CONFIG_IWLWIFI_DEBUG -static inline int __iwl_poll_bit(const char *f, u32 l, - struct iwl_priv *priv, u32 addr, - u32 bits, u32 mask, int timeout) -{ - int ret = _iwl_poll_bit(priv, addr, bits, mask, timeout); - IWL_DEBUG_IO(priv, "poll_bit(0x%08X, 0x%08X, 0x%08X) - %s- %s %d\n", - addr, bits, mask, - unlikely(ret == -ETIMEDOUT) ? "timeout" : "", f, l); - return ret; -} -#define iwl_poll_bit(priv, addr, bits, mask, timeout) \ - __iwl_poll_bit(__FILE__, __LINE__, priv, addr, bits, mask, timeout) -#else -#define iwl_poll_bit(p, a, b, m, t) _iwl_poll_bit(p, a, b, m, t) -#endif - -static inline void _iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask) -{ - _iwl_write32(priv, reg, _iwl_read32(priv, reg) | mask); -} -#ifdef CONFIG_IWLWIFI_DEBUG -static inline void __iwl_set_bit(const char *f, u32 l, - struct iwl_priv *priv, u32 reg, u32 mask) -{ - u32 val = _iwl_read32(priv, reg) | mask; - IWL_DEBUG_IO(priv, "set_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val); - _iwl_write32(priv, reg, val); -} -static inline void iwl_set_bit(struct iwl_priv *p, u32 r, u32 m) -{ - unsigned long reg_flags; - - spin_lock_irqsave(&p->reg_lock, reg_flags); - __iwl_set_bit(__FILE__, __LINE__, p, r, m); - spin_unlock_irqrestore(&p->reg_lock, reg_flags); -} -#else -static inline void iwl_set_bit(struct iwl_priv *p, u32 r, u32 m) -{ - unsigned long reg_flags; - - spin_lock_irqsave(&p->reg_lock, reg_flags); - _iwl_set_bit(p, r, m); - spin_unlock_irqrestore(&p->reg_lock, reg_flags); -} -#endif - -static inline void _iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask) -{ - _iwl_write32(priv, reg, _iwl_read32(priv, reg) & ~mask); -} -#ifdef CONFIG_IWLWIFI_DEBUG -static inline void __iwl_clear_bit(const char *f, u32 l, - struct iwl_priv *priv, u32 reg, u32 mask) -{ - u32 val = _iwl_read32(priv, reg) & ~mask; - IWL_DEBUG_IO(priv, "clear_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val); - _iwl_write32(priv, reg, val); -} -static inline void iwl_clear_bit(struct iwl_priv *p, u32 r, u32 m) -{ - unsigned long reg_flags; - - spin_lock_irqsave(&p->reg_lock, reg_flags); - __iwl_clear_bit(__FILE__, __LINE__, p, r, m); - spin_unlock_irqrestore(&p->reg_lock, reg_flags); -} -#else -static inline void iwl_clear_bit(struct iwl_priv *p, u32 r, u32 m) -{ - unsigned long reg_flags; - - spin_lock_irqsave(&p->reg_lock, reg_flags); - _iwl_clear_bit(p, r, m); - spin_unlock_irqrestore(&p->reg_lock, reg_flags); -} -#endif - -static inline int _iwl_grab_nic_access(struct iwl_priv *priv) -{ - int ret; - u32 val; - - /* this bit wakes up the NIC */ - _iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - - /* - * These bits say the device is running, and should keep running for - * at least a short while (at least as long as MAC_ACCESS_REQ stays 1), - * but they do not indicate that embedded SRAM is restored yet; - * 3945 and 4965 have volatile SRAM, and must save/restore contents - * to/from host DRAM when sleeping/waking for power-saving. - * Each direction takes approximately 1/4 millisecond; with this - * overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a - * series of register accesses are expected (e.g. reading Event Log), - * to keep device from sleeping. - * - * CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that - * SRAM is okay/restored. We don't check that here because this call - * is just for hardware register access; but GP1 MAC_SLEEP check is a - * good idea before accessing 3945/4965 SRAM (e.g. reading Event Log). - * - * 5000 series and later (including 1000 series) have non-volatile SRAM, - * and do not save/restore SRAM when power cycling. - */ - ret = _iwl_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, - (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | - CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000); - if (ret < 0) { - val = _iwl_read32(priv, CSR_GP_CNTRL); - IWL_ERR(priv, "MAC is in deep sleep!. CSR_GP_CNTRL = 0x%08X\n", val); - _iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI); - return -EIO; - } - - return 0; -} - -#ifdef CONFIG_IWLWIFI_DEBUG -static inline int __iwl_grab_nic_access(const char *f, u32 l, - struct iwl_priv *priv) -{ - IWL_DEBUG_IO(priv, "grabbing nic access - %s %d\n", f, l); - return _iwl_grab_nic_access(priv); -} -#define iwl_grab_nic_access(priv) \ - __iwl_grab_nic_access(__FILE__, __LINE__, priv) -#else -#define iwl_grab_nic_access(priv) \ - _iwl_grab_nic_access(priv) -#endif - -static inline void _iwl_release_nic_access(struct iwl_priv *priv) -{ - _iwl_clear_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); -} -#ifdef CONFIG_IWLWIFI_DEBUG -static inline void __iwl_release_nic_access(const char *f, u32 l, - struct iwl_priv *priv) -{ - - IWL_DEBUG_IO(priv, "releasing nic access - %s %d\n", f, l); - _iwl_release_nic_access(priv); -} -#define iwl_release_nic_access(priv) \ - __iwl_release_nic_access(__FILE__, __LINE__, priv) -#else -#define iwl_release_nic_access(priv) \ - _iwl_release_nic_access(priv) -#endif - -static inline u32 _iwl_read_direct32(struct iwl_priv *priv, u32 reg) -{ - return _iwl_read32(priv, reg); -} -#ifdef CONFIG_IWLWIFI_DEBUG -static inline u32 __iwl_read_direct32(const char *f, u32 l, - struct iwl_priv *priv, u32 reg) -{ - u32 value = _iwl_read_direct32(priv, reg); - IWL_DEBUG_IO(priv, "read_direct32(0x%4X) = 0x%08x - %s %d\n", reg, value, - f, l); - return value; -} -static inline u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg) -{ - u32 value; - unsigned long reg_flags; - - spin_lock_irqsave(&priv->reg_lock, reg_flags); - iwl_grab_nic_access(priv); - value = __iwl_read_direct32(__FILE__, __LINE__, priv, reg); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); - return value; -} - -#else -static inline u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg) -{ - u32 value; - unsigned long reg_flags; - - spin_lock_irqsave(&priv->reg_lock, reg_flags); - iwl_grab_nic_access(priv); - value = _iwl_read_direct32(priv, reg); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); - return value; - -} -#endif - -static inline void _iwl_write_direct32(struct iwl_priv *priv, - u32 reg, u32 value) -{ - _iwl_write32(priv, reg, value); -} -static inline void iwl_write_direct32(struct iwl_priv *priv, u32 reg, u32 value) -{ - unsigned long reg_flags; - - spin_lock_irqsave(&priv->reg_lock, reg_flags); - if (!iwl_grab_nic_access(priv)) { - _iwl_write_direct32(priv, reg, value); - iwl_release_nic_access(priv); - } - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); -} - -static inline void iwl_write_reg_buf(struct iwl_priv *priv, - u32 reg, u32 len, u32 *values) -{ - u32 count = sizeof(u32); - - if ((priv != NULL) && (values != NULL)) { - for (; 0 < len; len -= count, reg += count, values++) - iwl_write_direct32(priv, reg, *values); - } -} - -static inline int _iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, - u32 mask, int timeout) -{ - int t = 0; - - do { - if ((iwl_read_direct32(priv, addr) & mask) == mask) - return t; - udelay(IWL_POLL_INTERVAL); - t += IWL_POLL_INTERVAL; - } while (t < timeout); - - return -ETIMEDOUT; -} - -#ifdef CONFIG_IWLWIFI_DEBUG -static inline int __iwl_poll_direct_bit(const char *f, u32 l, - struct iwl_priv *priv, - u32 addr, u32 mask, int timeout) -{ - int ret = _iwl_poll_direct_bit(priv, addr, mask, timeout); - - if (unlikely(ret == -ETIMEDOUT)) - IWL_DEBUG_IO(priv, "poll_direct_bit(0x%08X, 0x%08X) - " - "timedout - %s %d\n", addr, mask, f, l); - else - IWL_DEBUG_IO(priv, "poll_direct_bit(0x%08X, 0x%08X) = 0x%08X " - "- %s %d\n", addr, mask, ret, f, l); - return ret; -} -#define iwl_poll_direct_bit(priv, addr, mask, timeout) \ - __iwl_poll_direct_bit(__FILE__, __LINE__, priv, addr, mask, timeout) -#else -#define iwl_poll_direct_bit _iwl_poll_direct_bit -#endif - -static inline u32 _iwl_read_prph(struct iwl_priv *priv, u32 reg) -{ - _iwl_write_direct32(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24)); - rmb(); - return _iwl_read_direct32(priv, HBUS_TARG_PRPH_RDAT); -} -static inline u32 iwl_read_prph(struct iwl_priv *priv, u32 reg) -{ - unsigned long reg_flags; - u32 val; - - spin_lock_irqsave(&priv->reg_lock, reg_flags); - iwl_grab_nic_access(priv); - val = _iwl_read_prph(priv, reg); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); - return val; -} - -static inline void _iwl_write_prph(struct iwl_priv *priv, - u32 addr, u32 val) -{ - _iwl_write_direct32(priv, HBUS_TARG_PRPH_WADDR, - ((addr & 0x0000FFFF) | (3 << 24))); - wmb(); - _iwl_write_direct32(priv, HBUS_TARG_PRPH_WDAT, val); -} - -static inline void iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val) -{ - unsigned long reg_flags; +void iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask); +void iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask); - spin_lock_irqsave(&priv->reg_lock, reg_flags); - if (!iwl_grab_nic_access(priv)) { - _iwl_write_prph(priv, addr, val); - iwl_release_nic_access(priv); - } - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); -} +int iwl_poll_bit(struct iwl_priv *priv, u32 addr, + u32 bits, u32 mask, int timeout); +int iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, u32 mask, + int timeout); -#define _iwl_set_bits_prph(priv, reg, mask) \ - _iwl_write_prph(priv, reg, (_iwl_read_prph(priv, reg) | mask)) +int iwl_grab_nic_access(struct iwl_priv *priv); +void iwl_release_nic_access(struct iwl_priv *priv); -static inline void iwl_set_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask) -{ - unsigned long reg_flags; +u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg); +void iwl_write_direct32(struct iwl_priv *priv, u32 reg, u32 value); - spin_lock_irqsave(&priv->reg_lock, reg_flags); - iwl_grab_nic_access(priv); - _iwl_set_bits_prph(priv, reg, mask); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); -} -#define _iwl_set_bits_mask_prph(priv, reg, bits, mask) \ - _iwl_write_prph(priv, reg, ((_iwl_read_prph(priv, reg) & mask) | bits)) +u32 iwl_read_prph(struct iwl_priv *priv, u32 reg); +void iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val); +void iwl_set_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask); +void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg, + u32 bits, u32 mask); +void iwl_clear_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask); -static inline void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg, - u32 bits, u32 mask) -{ - unsigned long reg_flags; - - spin_lock_irqsave(&priv->reg_lock, reg_flags); - iwl_grab_nic_access(priv); - _iwl_set_bits_mask_prph(priv, reg, bits, mask); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); -} - -static inline void iwl_clear_bits_prph(struct iwl_priv - *priv, u32 reg, u32 mask) -{ - unsigned long reg_flags; - u32 val; - - spin_lock_irqsave(&priv->reg_lock, reg_flags); - iwl_grab_nic_access(priv); - val = _iwl_read_prph(priv, reg); - _iwl_write_prph(priv, reg, (val & ~mask)); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); -} - -static inline u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr) -{ - unsigned long reg_flags; - u32 value; - - spin_lock_irqsave(&priv->reg_lock, reg_flags); - iwl_grab_nic_access(priv); - - _iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, addr); - rmb(); - value = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); - - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); - return value; -} - -static inline void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val) -{ - unsigned long reg_flags; - - spin_lock_irqsave(&priv->reg_lock, reg_flags); - if (!iwl_grab_nic_access(priv)) { - _iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); - wmb(); - _iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, val); - iwl_release_nic_access(priv); - } - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); -} - -static inline void iwl_write_targ_mem_buf(struct iwl_priv *priv, u32 addr, - u32 len, u32 *values) -{ - unsigned long reg_flags; - - spin_lock_irqsave(&priv->reg_lock, reg_flags); - if (!iwl_grab_nic_access(priv)) { - _iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); - wmb(); - for (; 0 < len; len -= sizeof(u32), values++) - _iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, *values); - - iwl_release_nic_access(priv); - } - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); -} +u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr); +void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val); #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index d7f2a0bb32c9..c2862d4e00e3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h index 101eef12b3bb..05b8e8f7dd4a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.h +++ b/drivers/net/wireless/iwlwifi/iwl-led.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 576795e2c75b..c43c8e66de73 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index fe012032c28c..59635d784e27 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 86f5123bccda..c960195df989 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -91,7 +91,6 @@ #define APMG_PS_CTRL_VAL_RESET_REQ (0x04000000) #define APMG_PS_CTRL_MSK_PWR_SRC (0x03000000) #define APMG_PS_CTRL_VAL_PWR_SRC_VMAIN (0x00000000) -#define APMG_PS_CTRL_VAL_PWR_SRC_MAX (0x01000000) /* 3945 only */ #define APMG_PS_CTRL_VAL_PWR_SRC_VAUX (0x02000000) #define APMG_SVR_VOLTAGE_CONFIG_BIT_MSK (0x000001E0) /* bit 8:5 */ #define APMG_SVR_DIGITAL_VOLTAGE_1_32 (0x00000060) @@ -99,152 +98,6 @@ #define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800) /** - * BSM (Bootstrap State Machine) - * - * The Bootstrap State Machine (BSM) stores a short bootstrap uCode program - * in special SRAM that does not power down when the embedded control - * processor is sleeping (e.g. for periodic power-saving shutdowns of radio). - * - * When powering back up after sleeps (or during initial uCode load), the BSM - * internally loads the short bootstrap program from the special SRAM into the - * embedded processor's instruction SRAM, and starts the processor so it runs - * the bootstrap program. - * - * This bootstrap program loads (via PCI busmaster DMA) instructions and data - * images for a uCode program from host DRAM locations. The host driver - * indicates DRAM locations and sizes for instruction and data images via the - * four BSM_DRAM_* registers. Once the bootstrap program loads the new program, - * the new program starts automatically. - * - * The uCode used for open-source drivers includes two programs: - * - * 1) Initialization -- performs hardware calibration and sets up some - * internal data, then notifies host via "initialize alive" notification - * (struct iwl_init_alive_resp) that it has completed all of its work. - * After signal from host, it then loads and starts the runtime program. - * The initialization program must be used when initially setting up the - * NIC after loading the driver. - * - * 2) Runtime/Protocol -- performs all normal runtime operations. This - * notifies host via "alive" notification (struct iwl_alive_resp) that it - * is ready to be used. - * - * When initializing the NIC, the host driver does the following procedure: - * - * 1) Load bootstrap program (instructions only, no data image for bootstrap) - * into bootstrap memory. Use dword writes starting at BSM_SRAM_LOWER_BOUND - * - * 2) Point (via BSM_DRAM_*) to the "initialize" uCode data and instruction - * images in host DRAM. - * - * 3) Set up BSM to copy from BSM SRAM into uCode instruction SRAM when asked: - * BSM_WR_MEM_SRC_REG = 0 - * BSM_WR_MEM_DST_REG = RTC_INST_LOWER_BOUND - * BSM_WR_MEM_DWCOUNT_REG = # dwords in bootstrap instruction image - * - * 4) Load bootstrap into instruction SRAM: - * BSM_WR_CTRL_REG = BSM_WR_CTRL_REG_BIT_START - * - * 5) Wait for load completion: - * Poll BSM_WR_CTRL_REG for BSM_WR_CTRL_REG_BIT_START = 0 - * - * 6) Enable future boot loads whenever NIC's power management triggers it: - * BSM_WR_CTRL_REG = BSM_WR_CTRL_REG_BIT_START_EN - * - * 7) Start the NIC by removing all reset bits: - * CSR_RESET = 0 - * - * The bootstrap uCode (already in instruction SRAM) loads initialization - * uCode. Initialization uCode performs data initialization, sends - * "initialize alive" notification to host, and waits for a signal from - * host to load runtime code. - * - * 4) Point (via BSM_DRAM_*) to the "runtime" uCode data and instruction - * images in host DRAM. The last register loaded must be the instruction - * byte count register ("1" in MSbit tells initialization uCode to load - * the runtime uCode): - * BSM_DRAM_INST_BYTECOUNT_REG = byte count | BSM_DRAM_INST_LOAD - * - * 5) Wait for "alive" notification, then issue normal runtime commands. - * - * Data caching during power-downs: - * - * Just before the embedded controller powers down (e.g for automatic - * power-saving modes, or for RFKILL), uCode stores (via PCI busmaster DMA) - * a current snapshot of the embedded processor's data SRAM into host DRAM. - * This caches the data while the embedded processor's memory is powered down. - * Location and size are controlled by BSM_DRAM_DATA_* registers. - * - * NOTE: Instruction SRAM does not need to be saved, since that doesn't - * change during operation; the original image (from uCode distribution - * file) can be used for reload. - * - * When powering back up, the BSM loads the bootstrap program. Bootstrap looks - * at the BSM_DRAM_* registers, which now point to the runtime instruction - * image and the cached (modified) runtime data (*not* the initialization - * uCode). Bootstrap reloads these runtime images into SRAM, and restarts the - * uCode from where it left off before the power-down. - * - * NOTE: Initialization uCode does *not* run as part of the save/restore - * procedure. - * - * This save/restore method is mostly for autonomous power management during - * normal operation (result of POWER_TABLE_CMD). Platform suspend/resume and - * RFKILL should use complete restarts (with total re-initialization) of uCode, - * allowing total shutdown (including BSM memory). - * - * Note that, during normal operation, the host DRAM that held the initial - * startup data for the runtime code is now being used as a backup data cache - * for modified data! If you need to completely re-initialize the NIC, make - * sure that you use the runtime data image from the uCode distribution file, - * not the modified/saved runtime data. You may want to store a separate - * "clean" runtime data image in DRAM to avoid disk reads of distribution file. - */ - -/* BSM bit fields */ -#define BSM_WR_CTRL_REG_BIT_START (0x80000000) /* start boot load now */ -#define BSM_WR_CTRL_REG_BIT_START_EN (0x40000000) /* enable boot after pwrup*/ -#define BSM_DRAM_INST_LOAD (0x80000000) /* start program load now */ - -/* BSM addresses */ -#define BSM_BASE (PRPH_BASE + 0x3400) -#define BSM_END (PRPH_BASE + 0x3800) - -#define BSM_WR_CTRL_REG (BSM_BASE + 0x000) /* ctl and status */ -#define BSM_WR_MEM_SRC_REG (BSM_BASE + 0x004) /* source in BSM mem */ -#define BSM_WR_MEM_DST_REG (BSM_BASE + 0x008) /* dest in SRAM mem */ -#define BSM_WR_DWCOUNT_REG (BSM_BASE + 0x00C) /* bytes */ -#define BSM_WR_STATUS_REG (BSM_BASE + 0x010) /* bit 0: 1 == done */ - -/* - * Pointers and size regs for bootstrap load and data SRAM save/restore. - * NOTE: 3945 pointers use bits 31:0 of DRAM address. - * 4965 pointers use bits 35:4 of DRAM address. - */ -#define BSM_DRAM_INST_PTR_REG (BSM_BASE + 0x090) -#define BSM_DRAM_INST_BYTECOUNT_REG (BSM_BASE + 0x094) -#define BSM_DRAM_DATA_PTR_REG (BSM_BASE + 0x098) -#define BSM_DRAM_DATA_BYTECOUNT_REG (BSM_BASE + 0x09C) - -/* - * BSM special memory, stays powered on during power-save sleeps. - * Read/write, address range from LOWER_BOUND to (LOWER_BOUND + SIZE -1) - */ -#define BSM_SRAM_LOWER_BOUND (PRPH_BASE + 0x3800) -#define BSM_SRAM_SIZE (1024) /* bytes */ - - -/* 3945 Tx scheduler registers */ -#define ALM_SCD_BASE (PRPH_BASE + 0x2E00) -#define ALM_SCD_MODE_REG (ALM_SCD_BASE + 0x000) -#define ALM_SCD_ARASTAT_REG (ALM_SCD_BASE + 0x004) -#define ALM_SCD_TXFACT_REG (ALM_SCD_BASE + 0x010) -#define ALM_SCD_TXF4MF_REG (ALM_SCD_BASE + 0x014) -#define ALM_SCD_TXF5MF_REG (ALM_SCD_BASE + 0x020) -#define ALM_SCD_SBYP_MODE_1_REG (ALM_SCD_BASE + 0x02C) -#define ALM_SCD_SBYP_MODE_2_REG (ALM_SCD_BASE + 0x030) - -/** * Tx Scheduler * * The Tx Scheduler selects the next frame to be transmitted, choosing TFDs @@ -330,201 +183,10 @@ * Max Tx window size is the max number of contiguous TFDs that the scheduler * can keep track of at one time when creating block-ack chains of frames. * Note that "64" matches the number of ack bits in a block-ack packet. - * Driver should use SCD_WIN_SIZE and SCD_FRAME_LIMIT values to initialize - * IWL49_SCD_CONTEXT_QUEUE_OFFSET(x) values. */ #define SCD_WIN_SIZE 64 #define SCD_FRAME_LIMIT 64 -/* SCD registers are internal, must be accessed via HBUS_TARG_PRPH regs */ -#define IWL49_SCD_START_OFFSET 0xa02c00 - -/* - * 4965 tells driver SRAM address for internal scheduler structs via this reg. - * Value is valid only after "Alive" response from uCode. - */ -#define IWL49_SCD_SRAM_BASE_ADDR (IWL49_SCD_START_OFFSET + 0x0) - -/* - * Driver may need to update queue-empty bits after changing queue's - * write and read pointers (indexes) during (re-)initialization (i.e. when - * scheduler is not tracking what's happening). - * Bit fields: - * 31-16: Write mask -- 1: update empty bit, 0: don't change empty bit - * 15-00: Empty state, one for each queue -- 1: empty, 0: non-empty - * NOTE: This register is not used by Linux driver. - */ -#define IWL49_SCD_EMPTY_BITS (IWL49_SCD_START_OFFSET + 0x4) - -/* - * Physical base address of array of byte count (BC) circular buffers (CBs). - * Each Tx queue has a BC CB in host DRAM to support Scheduler-ACK mode. - * This register points to BC CB for queue 0, must be on 1024-byte boundary. - * Others are spaced by 1024 bytes. - * Each BC CB is 2 bytes * (256 + 64) = 740 bytes, followed by 384 bytes pad. - * (Index into a queue's BC CB) = (index into queue's TFD CB) = (SSN & 0xff). - * Bit fields: - * 25-00: Byte Count CB physical address [35:10], must be 1024-byte aligned. - */ -#define IWL49_SCD_DRAM_BASE_ADDR (IWL49_SCD_START_OFFSET + 0x10) - -/* - * Enables any/all Tx DMA/FIFO channels. - * Scheduler generates requests for only the active channels. - * Set this to 0xff to enable all 8 channels (normal usage). - * Bit fields: - * 7- 0: Enable (1), disable (0), one bit for each channel 0-7 - */ -#define IWL49_SCD_TXFACT (IWL49_SCD_START_OFFSET + 0x1c) -/* - * Queue (x) Write Pointers (indexes, really!), one for each Tx queue. - * Initialized and updated by driver as new TFDs are added to queue. - * NOTE: If using Block Ack, index must correspond to frame's - * Start Sequence Number; index = (SSN & 0xff) - * NOTE: Alternative to HBUS_TARG_WRPTR, which is what Linux driver uses? - */ -#define IWL49_SCD_QUEUE_WRPTR(x) (IWL49_SCD_START_OFFSET + 0x24 + (x) * 4) - -/* - * Queue (x) Read Pointers (indexes, really!), one for each Tx queue. - * For FIFO mode, index indicates next frame to transmit. - * For Scheduler-ACK mode, index indicates first frame in Tx window. - * Initialized by driver, updated by scheduler. - */ -#define IWL49_SCD_QUEUE_RDPTR(x) (IWL49_SCD_START_OFFSET + 0x64 + (x) * 4) - -/* - * Select which queues work in chain mode (1) vs. not (0). - * Use chain mode to build chains of aggregated frames. - * Bit fields: - * 31-16: Reserved - * 15-00: Mode, one bit for each queue -- 1: Chain mode, 0: one-at-a-time - * NOTE: If driver sets up queue for chain mode, it should be also set up - * Scheduler-ACK mode as well, via SCD_QUEUE_STATUS_BITS(x). - */ -#define IWL49_SCD_QUEUECHAIN_SEL (IWL49_SCD_START_OFFSET + 0xd0) - -/* - * Select which queues interrupt driver when scheduler increments - * a queue's read pointer (index). - * Bit fields: - * 31-16: Reserved - * 15-00: Interrupt enable, one bit for each queue -- 1: enabled, 0: disabled - * NOTE: This functionality is apparently a no-op; driver relies on interrupts - * from Rx queue to read Tx command responses and update Tx queues. - */ -#define IWL49_SCD_INTERRUPT_MASK (IWL49_SCD_START_OFFSET + 0xe4) - -/* - * Queue search status registers. One for each queue. - * Sets up queue mode and assigns queue to Tx DMA channel. - * Bit fields: - * 19-10: Write mask/enable bits for bits 0-9 - * 9: Driver should init to "0" - * 8: Scheduler-ACK mode (1), non-Scheduler-ACK (i.e. FIFO) mode (0). - * Driver should init to "1" for aggregation mode, or "0" otherwise. - * 7-6: Driver should init to "0" - * 5: Window Size Left; indicates whether scheduler can request - * another TFD, based on window size, etc. Driver should init - * this bit to "1" for aggregation mode, or "0" for non-agg. - * 4-1: Tx FIFO to use (range 0-7). - * 0: Queue is active (1), not active (0). - * Other bits should be written as "0" - * - * NOTE: If enabling Scheduler-ACK mode, chain mode should also be enabled - * via SCD_QUEUECHAIN_SEL. - */ -#define IWL49_SCD_QUEUE_STATUS_BITS(x)\ - (IWL49_SCD_START_OFFSET + 0x104 + (x) * 4) - -/* Bit field positions */ -#define IWL49_SCD_QUEUE_STTS_REG_POS_ACTIVE (0) -#define IWL49_SCD_QUEUE_STTS_REG_POS_TXF (1) -#define IWL49_SCD_QUEUE_STTS_REG_POS_WSL (5) -#define IWL49_SCD_QUEUE_STTS_REG_POS_SCD_ACK (8) - -/* Write masks */ -#define IWL49_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN (10) -#define IWL49_SCD_QUEUE_STTS_REG_MSK (0x0007FC00) - -/** - * 4965 internal SRAM structures for scheduler, shared with driver ... - * - * Driver should clear and initialize the following areas after receiving - * "Alive" response from 4965 uCode, i.e. after initial - * uCode load, or after a uCode load done for error recovery: - * - * SCD_CONTEXT_DATA_OFFSET (size 128 bytes) - * SCD_TX_STTS_BITMAP_OFFSET (size 256 bytes) - * SCD_TRANSLATE_TBL_OFFSET (size 32 bytes) - * - * Driver accesses SRAM via HBUS_TARG_MEM_* registers. - * Driver reads base address of this scheduler area from SCD_SRAM_BASE_ADDR. - * All OFFSET values must be added to this base address. - */ - -/* - * Queue context. One 8-byte entry for each of 16 queues. - * - * Driver should clear this entire area (size 0x80) to 0 after receiving - * "Alive" notification from uCode. Additionally, driver should init - * each queue's entry as follows: - * - * LS Dword bit fields: - * 0-06: Max Tx window size for Scheduler-ACK. Driver should init to 64. - * - * MS Dword bit fields: - * 16-22: Frame limit. Driver should init to 10 (0xa). - * - * Driver should init all other bits to 0. - * - * Init must be done after driver receives "Alive" response from 4965 uCode, - * and when setting up queue for aggregation. - */ -#define IWL49_SCD_CONTEXT_DATA_OFFSET 0x380 -#define IWL49_SCD_CONTEXT_QUEUE_OFFSET(x) \ - (IWL49_SCD_CONTEXT_DATA_OFFSET + ((x) * 8)) - -#define IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_POS (0) -#define IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK (0x0000007F) -#define IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16) -#define IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000) - -/* - * Tx Status Bitmap - * - * Driver should clear this entire area (size 0x100) to 0 after receiving - * "Alive" notification from uCode. Area is used only by device itself; - * no other support (besides clearing) is required from driver. - */ -#define IWL49_SCD_TX_STTS_BITMAP_OFFSET 0x400 - -/* - * RAxTID to queue translation mapping. - * - * When queue is in Scheduler-ACK mode, frames placed in a that queue must be - * for only one combination of receiver address (RA) and traffic ID (TID), i.e. - * one QOS priority level destined for one station (for this wireless link, - * not final destination). The SCD_TRANSLATE_TABLE area provides 16 16-bit - * mappings, one for each of the 16 queues. If queue is not in Scheduler-ACK - * mode, the device ignores the mapping value. - * - * Bit fields, for each 16-bit map: - * 15-9: Reserved, set to 0 - * 8-4: Index into device's station table for recipient station - * 3-0: Traffic ID (tid), range 0-15 - * - * Driver should clear this entire area (size 32 bytes) to 0 after receiving - * "Alive" notification from uCode. To update a 16-bit map value, driver - * must read a dword-aligned value from device SRAM, replace the 16-bit map - * value of interest, and write the dword value back into device SRAM. - */ -#define IWL49_SCD_TRANSLATE_TBL_OFFSET 0x500 - -/* Find translation table dword to read/write for given queue */ -#define IWL49_SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \ - ((IWL49_SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffffffc) - #define IWL_SCD_TXFIFO_POS_TID (0) #define IWL_SCD_TXFIFO_POS_RA (4) #define IWL_SCD_QUEUE_RA_TID_MAP_RATID_MSK (0x01FF) diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 6f9a2fa04763..c421f566982f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -239,16 +239,16 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv, palive->is_valid, palive->ver_type, palive->ver_subtype); + priv->device_pointers.log_event_table = + le32_to_cpu(palive->log_event_table_ptr); + priv->device_pointers.error_event_table = + le32_to_cpu(palive->error_event_table_ptr); + if (palive->ver_subtype == INITIALIZE_SUBTYPE) { IWL_DEBUG_INFO(priv, "Initialization Alive received.\n"); - memcpy(&priv->card_alive_init, - &pkt->u.alive_frame, - sizeof(struct iwl_init_alive_resp)); pwork = &priv->init_alive_start; } else { IWL_DEBUG_INFO(priv, "Runtime Alive received.\n"); - memcpy(&priv->card_alive, &pkt->u.alive_frame, - sizeof(struct iwl_alive_resp)); pwork = &priv->alive_start; } @@ -898,7 +898,6 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); ieee80211_rx(priv->hw, skb); - priv->alloc_rxb_page--; rxb->page = NULL; } diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 914c77e44588..d60d630cb93a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.h b/drivers/net/wireless/iwlwifi/iwl-spectrum.h index c4ca0b5d77da..cb80bb4ce45e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-spectrum.h +++ b/drivers/net/wireless/iwlwifi/iwl-spectrum.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ieee80211 subsystem header files. * diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index bc90a12408a3..c21515640077 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -233,7 +233,6 @@ u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx, struct iwl_station_entry *station; int i; u8 sta_id = IWL_INVALID_STATION; - u16 rate; if (is_ap) sta_id = ctx->ap_sta_id; @@ -306,12 +305,6 @@ u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx, */ iwl_set_ht_add_station(priv, sta_id, sta, ctx); - /* 3945 only */ - rate = (priv->band == IEEE80211_BAND_5GHZ) ? - IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP; - /* Turn on both antennas for the station... */ - station->sta.rate_n_flags = cpu_to_le16(rate | RATE_MCS_ANT_AB_MSK); - return sta_id; } diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h index 206f1e1a0caf..ff64027ff4cb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.h +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 277c9175dcf6..565980fbb591 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -149,32 +149,31 @@ void iwl_cmd_queue_unmap(struct iwl_priv *priv) struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue]; struct iwl_queue *q = &txq->q; int i; - bool huge = false; if (q->n_bd == 0) return; while (q->read_ptr != q->write_ptr) { - /* we have no way to tell if it is a huge cmd ATM */ i = get_cmd_index(q, q->read_ptr, 0); - if (txq->meta[i].flags & CMD_SIZE_HUGE) - huge = true; - else + if (txq->meta[i].flags & CMD_MAPPED) { pci_unmap_single(priv->pci_dev, dma_unmap_addr(&txq->meta[i], mapping), dma_unmap_len(&txq->meta[i], len), PCI_DMA_BIDIRECTIONAL); + txq->meta[i].flags = 0; + } - q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd); + q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd); } - if (huge) { - i = q->n_window; + i = q->n_window; + if (txq->meta[i].flags & CMD_MAPPED) { pci_unmap_single(priv->pci_dev, dma_unmap_addr(&txq->meta[i], mapping), dma_unmap_len(&txq->meta[i], len), PCI_DMA_BIDIRECTIONAL); + txq->meta[i].flags = 0; } } @@ -463,7 +462,11 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) return -EIO; } + spin_lock_irqsave(&priv->hcmd_lock, flags); + if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) { + spin_unlock_irqrestore(&priv->hcmd_lock, flags); + IWL_ERR(priv, "No space in command queue\n"); if (priv->cfg->ops->lib->tt_ops.ct_kill_check) { is_ct_kill = @@ -471,27 +474,22 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) } if (!is_ct_kill) { IWL_ERR(priv, "Restarting adapter due to queue full\n"); - queue_work(priv->workqueue, &priv->restart); + iwlagn_fw_error(priv, false); } return -ENOSPC; } - spin_lock_irqsave(&priv->hcmd_lock, flags); - - /* If this is a huge cmd, mark the huge flag also on the meta.flags - * of the _original_ cmd. This is used for DMA mapping clean up. - */ - if (cmd->flags & CMD_SIZE_HUGE) { - idx = get_cmd_index(q, q->write_ptr, 0); - txq->meta[idx].flags = CMD_SIZE_HUGE; - } - idx = get_cmd_index(q, q->write_ptr, cmd->flags & CMD_SIZE_HUGE); out_cmd = txq->cmd[idx]; out_meta = &txq->meta[idx]; + if (WARN_ON(out_meta->flags & CMD_MAPPED)) { + spin_unlock_irqrestore(&priv->hcmd_lock, flags); + return -ENOSPC; + } + memset(out_meta, 0, sizeof(*out_meta)); /* re-initialize to NULL */ - out_meta->flags = cmd->flags; + out_meta->flags = cmd->flags | CMD_MAPPED; if (cmd->flags & CMD_WANT_SKB) out_meta->source = cmd; if (cmd->flags & CMD_ASYNC) @@ -584,7 +582,7 @@ static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, if (nfreed++ > 0) { IWL_ERR(priv, "HCMD skipped: index (%d) %d %d\n", idx, q->write_ptr, q->read_ptr); - queue_work(priv->workqueue, &priv->restart); + iwlagn_fw_error(priv, false); } } @@ -609,6 +607,10 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) struct iwl_device_cmd *cmd; struct iwl_cmd_meta *meta; struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue]; + unsigned long flags; + void (*callback) (struct iwl_priv *priv, struct iwl_device_cmd *cmd, + struct iwl_rx_packet *pkt); + /* If a Tx command is being handled and it isn't in the actual * command queue then there a command routing bug has been introduced @@ -622,14 +624,8 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) return; } - /* If this is a huge cmd, clear the huge flag on the meta.flags - * of the _original_ cmd. So that iwl_cmd_queue_free won't unmap - * the DMA buffer for the scan (huge) command. - */ - if (huge) { - cmd_index = get_cmd_index(&txq->q, index, 0); - txq->meta[cmd_index].flags = 0; - } + spin_lock_irqsave(&priv->hcmd_lock, flags); + cmd_index = get_cmd_index(&txq->q, index, huge); cmd = txq->cmd[cmd_index]; meta = &txq->meta[cmd_index]; @@ -639,12 +635,13 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) dma_unmap_len(meta, len), PCI_DMA_BIDIRECTIONAL); + callback = NULL; /* Input error checking is done when commands are added to queue. */ if (meta->flags & CMD_WANT_SKB) { meta->source->reply_page = (unsigned long)rxb_addr(rxb); rxb->page = NULL; - } else if (meta->callback) - meta->callback(priv, cmd, pkt); + } else + callback = meta->callback; iwl_hcmd_queue_reclaim(priv, txq_id, index, cmd_index); @@ -654,5 +651,12 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) get_cmd_string(cmd->hdr.cmd)); wake_up_interruptible(&priv->wait_command_queue); } + + /* Mark as unmapped */ meta->flags = 0; + + spin_unlock_irqrestore(&priv->hcmd_lock, flags); + + if (callback) + callback(priv, cmd, pkt); } diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index f6c2cd665f49..078ef43d957d 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c @@ -57,6 +57,7 @@ struct if_spi_card { /* Handles all SPI communication (except for FW load) */ struct workqueue_struct *workqueue; struct work_struct packet_work; + struct work_struct resume_work; u8 cmd_buffer[IF_SPI_CMD_BUF_SIZE]; @@ -68,6 +69,9 @@ struct if_spi_card { /* Protects cmd_packet_list and data_packet_list */ spinlock_t buffer_lock; + + /* True is card suspended */ + u8 suspended; }; static void free_if_spi_card(struct if_spi_card *card) @@ -1057,6 +1061,28 @@ out: return err; } +static void if_spi_resume_worker(struct work_struct *work) +{ + struct if_spi_card *card; + + card = container_of(work, struct if_spi_card, resume_work); + + if (card->suspended) { + if (card->pdata->setup) + card->pdata->setup(card->spi); + + /* Init card ... */ + if_spi_init_card(card); + + enable_irq(card->spi->irq); + + /* And resume it ... */ + lbs_resume(card->priv); + + card->suspended = 0; + } +} + static int __devinit if_spi_probe(struct spi_device *spi) { struct if_spi_card *card; @@ -1107,6 +1133,7 @@ static int __devinit if_spi_probe(struct spi_device *spi) goto free_card; } card->priv = priv; + priv->setup_fw_on_resume = 1; priv->card = card; priv->hw_host_to_card = if_spi_host_to_card; priv->enter_deep_sleep = NULL; @@ -1117,6 +1144,7 @@ static int __devinit if_spi_probe(struct spi_device *spi) /* Initialize interrupt handling stuff. */ card->workqueue = create_workqueue("libertas_spi"); INIT_WORK(&card->packet_work, if_spi_host_to_card_worker); + INIT_WORK(&card->resume_work, if_spi_resume_worker); err = request_irq(spi->irq, if_spi_host_interrupt, IRQF_TRIGGER_FALLING, "libertas_spi", card); @@ -1161,6 +1189,8 @@ static int __devexit libertas_spi_remove(struct spi_device *spi) lbs_deb_spi("libertas_spi_remove\n"); lbs_deb_enter(LBS_DEB_SPI); + cancel_work_sync(&card->resume_work); + lbs_stop_card(priv); lbs_remove_card(priv); /* will call free_netdev */ @@ -1174,6 +1204,40 @@ static int __devexit libertas_spi_remove(struct spi_device *spi) return 0; } +static int if_spi_suspend(struct device *dev) +{ + struct spi_device *spi = to_spi_device(dev); + struct if_spi_card *card = spi_get_drvdata(spi); + + if (!card->suspended) { + lbs_suspend(card->priv); + flush_workqueue(card->workqueue); + disable_irq(spi->irq); + + if (card->pdata->teardown) + card->pdata->teardown(spi); + card->suspended = 1; + } + + return 0; +} + +static int if_spi_resume(struct device *dev) +{ + struct spi_device *spi = to_spi_device(dev); + struct if_spi_card *card = spi_get_drvdata(spi); + + /* Schedule delayed work */ + schedule_work(&card->resume_work); + + return 0; +} + +static const struct dev_pm_ops if_spi_pm_ops = { + .suspend = if_spi_suspend, + .resume = if_spi_resume, +}; + static struct spi_driver libertas_spi_driver = { .probe = if_spi_probe, .remove = __devexit_p(libertas_spi_remove), @@ -1181,6 +1245,7 @@ static struct spi_driver libertas_spi_driver = { .name = "libertas_spi", .bus = &spi_bus_type, .owner = THIS_MODULE, + .pm = &if_spi_pm_ops, }, }; diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c new file mode 100644 index 000000000000..73a6e62f5680 --- /dev/null +++ b/drivers/net/wireless/mwifiex/11n.c @@ -0,0 +1,809 @@ +/* + * Marvell Wireless LAN device driver: 802.11n + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" + +/* + * Fills HT capability information field, AMPDU Parameters field, HT extended + * capability field, and supported MCS set fields. + * + * Only the following HT capability information fields are used, all other + * fields are always turned off. + * + * Bit 1 : Supported channel width (0: 20MHz, 1: Both 20 and 40 MHz) + * Bit 4 : Greenfield support (0: Not supported, 1: Supported) + * Bit 5 : Short GI for 20 MHz support (0: Not supported, 1: Supported) + * Bit 6 : Short GI for 40 MHz support (0: Not supported, 1: Supported) + * Bit 7 : Tx STBC (0: Not supported, 1: Supported) + * Bit 8-9 : Rx STBC (0: Not supported, X: Support for up to X spatial streams) + * Bit 10 : Delayed BA support (0: Not supported, 1: Supported) + * Bit 11 : Maximum AMSDU length (0: 3839 octets, 1: 7935 octets) + * Bit 14 : 40-Mhz intolerant support (0: Not supported, 1: Supported) + * + * In addition, the following AMPDU Parameters are set - + * - Maximum AMPDU length exponent (set to 3) + * - Minimum AMPDU start spacing (set to 0 - No restrictions) + * + * MCS is set for 1x1, with MSC32 for infra mode or ad-hoc mode with 40 MHz + * support. + * + * RD responder bit to set to clear in the extended capability header. + */ +void +mwifiex_fill_cap_info(struct mwifiex_private *priv, + struct mwifiex_ie_types_htcap *ht_cap) +{ + struct mwifiex_adapter *adapter = priv->adapter; + u8 *mcs; + int rx_mcs_supp; + uint16_t ht_cap_info = le16_to_cpu(ht_cap->ht_cap.cap_info); + uint16_t ht_ext_cap = le16_to_cpu(ht_cap->ht_cap.extended_ht_cap_info); + + /* Convert dev_cap to IEEE80211_HT_CAP */ + if (ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap)) + ht_cap_info |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; + else + ht_cap_info &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; + + if (ISSUPP_SHORTGI20(adapter->hw_dot_11n_dev_cap)) + ht_cap_info |= IEEE80211_HT_CAP_SGI_20; + else + ht_cap_info &= ~IEEE80211_HT_CAP_SGI_20; + + if (ISSUPP_SHORTGI40(adapter->hw_dot_11n_dev_cap)) + ht_cap_info |= IEEE80211_HT_CAP_SGI_40; + else + ht_cap_info &= ~IEEE80211_HT_CAP_SGI_40; + + if (ISSUPP_TXSTBC(adapter->hw_dot_11n_dev_cap)) + ht_cap_info |= IEEE80211_HT_CAP_TX_STBC; + else + ht_cap_info &= ~IEEE80211_HT_CAP_TX_STBC; + + if (ISSUPP_RXSTBC(adapter->hw_dot_11n_dev_cap)) + ht_cap_info |= 1 << IEEE80211_HT_CAP_RX_STBC_SHIFT; + else + ht_cap_info &= ~(3 << IEEE80211_HT_CAP_RX_STBC_SHIFT); + + if (ISSUPP_GREENFIELD(adapter->hw_dot_11n_dev_cap)) + ht_cap_info |= IEEE80211_HT_CAP_GRN_FLD; + else + ht_cap_info &= ~IEEE80211_HT_CAP_GRN_FLD; + + ht_cap_info &= ~IEEE80211_HT_CAP_MAX_AMSDU; + ht_cap_info |= IEEE80211_HT_CAP_SM_PS; + + ht_cap->ht_cap.ampdu_params_info |= IEEE80211_HT_AMPDU_PARM_FACTOR; + ht_cap->ht_cap.ampdu_params_info &= ~IEEE80211_HT_AMPDU_PARM_DENSITY; + + rx_mcs_supp = GET_RXMCSSUPP(adapter->hw_dev_mcs_support); + + mcs = (u8 *)&ht_cap->ht_cap.mcs; + + /* Set MCS for 1x1 */ + memset(mcs, 0xff, rx_mcs_supp); + + /* Clear all the other values */ + memset(&mcs[rx_mcs_supp], 0, + sizeof(struct ieee80211_mcs_info) - rx_mcs_supp); + + if (priv->bss_mode == NL80211_IFTYPE_STATION || + (ht_cap_info & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) + /* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */ + SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask); + + /* Clear RD responder bit */ + RESETHT_EXTCAP_RDG(ht_ext_cap); + + ht_cap->ht_cap.cap_info = cpu_to_le16(ht_cap_info); + ht_cap->ht_cap.extended_ht_cap_info = cpu_to_le16(ht_ext_cap); +} + +/* + * This function returns the pointer to an entry in BA Stream + * table which matches the requested BA status. + */ +static struct mwifiex_tx_ba_stream_tbl * +mwifiex_11n_get_tx_ba_stream_status(struct mwifiex_private *priv, + enum mwifiex_ba_status ba_status) +{ + struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl; + unsigned long flags; + + spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); + list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { + if (tx_ba_tsr_tbl->ba_status == ba_status) { + spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, + flags); + return tx_ba_tsr_tbl; + } + } + spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); + return NULL; +} + +/* + * This function handles the command response of delete a block + * ack request. + * + * The function checks the response success status and takes action + * accordingly (send an add BA request in case of success, or recreate + * the deleted stream in case of failure, if the add BA was also + * initiated by us). + */ +int mwifiex_ret_11n_delba(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + int tid; + struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl; + struct host_cmd_ds_11n_delba *del_ba = + (struct host_cmd_ds_11n_delba *) &resp->params.del_ba; + uint16_t del_ba_param_set = le16_to_cpu(del_ba->del_ba_param_set); + + tid = del_ba_param_set >> DELBA_TID_POS; + if (del_ba->del_result == BA_RESULT_SUCCESS) { + mwifiex_11n_delete_ba_stream_tbl(priv, tid, + del_ba->peer_mac_addr, TYPE_DELBA_SENT, + INITIATOR_BIT(del_ba_param_set)); + + tx_ba_tbl = mwifiex_11n_get_tx_ba_stream_status(priv, + BA_STREAM_SETUP_INPROGRESS); + if (tx_ba_tbl) + mwifiex_send_addba(priv, tx_ba_tbl->tid, + tx_ba_tbl->ra); + } else { /* + * In case of failure, recreate the deleted stream in case + * we initiated the ADDBA + */ + if (INITIATOR_BIT(del_ba_param_set)) { + mwifiex_11n_create_tx_ba_stream_tbl(priv, + del_ba->peer_mac_addr, tid, + BA_STREAM_SETUP_INPROGRESS); + + tx_ba_tbl = mwifiex_11n_get_tx_ba_stream_status(priv, + BA_STREAM_SETUP_INPROGRESS); + if (tx_ba_tbl) + mwifiex_11n_delete_ba_stream_tbl(priv, + tx_ba_tbl->tid, tx_ba_tbl->ra, + TYPE_DELBA_SENT, true); + } + } + + return 0; +} + +/* + * This function handles the command response of add a block + * ack request. + * + * Handling includes changing the header fields to CPU formats, checking + * the response success status and taking actions accordingly (delete the + * BA stream table in case of failure). + */ +int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + int tid; + struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = + (struct host_cmd_ds_11n_addba_rsp *) &resp->params.add_ba_rsp; + struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl; + + add_ba_rsp->ssn = cpu_to_le16((le16_to_cpu(add_ba_rsp->ssn)) + & SSN_MASK); + + tid = (le16_to_cpu(add_ba_rsp->block_ack_param_set) + & IEEE80211_ADDBA_PARAM_TID_MASK) + >> BLOCKACKPARAM_TID_POS; + if (le16_to_cpu(add_ba_rsp->status_code) == BA_RESULT_SUCCESS) { + tx_ba_tbl = mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, + add_ba_rsp->peer_mac_addr); + if (tx_ba_tbl) { + dev_dbg(priv->adapter->dev, "info: BA stream complete\n"); + tx_ba_tbl->ba_status = BA_STREAM_SETUP_COMPLETE; + } else { + dev_err(priv->adapter->dev, "BA stream not created\n"); + } + } else { + mwifiex_11n_delete_ba_stream_tbl(priv, tid, + add_ba_rsp->peer_mac_addr, + TYPE_DELBA_SENT, true); + if (add_ba_rsp->add_rsp_result != BA_RESULT_TIMEOUT) + priv->aggr_prio_tbl[tid].ampdu_ap = + BA_STREAM_NOT_ALLOWED; + } + + return 0; +} + +/* + * This function handles the command response of 11n configuration request. + * + * Handling includes changing the header fields into CPU format. + */ +int mwifiex_ret_11n_cfg(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *data_buf) +{ + struct mwifiex_ds_11n_tx_cfg *tx_cfg = NULL; + struct host_cmd_ds_11n_cfg *htcfg = &resp->params.htcfg; + + if (data_buf) { + tx_cfg = (struct mwifiex_ds_11n_tx_cfg *) data_buf; + tx_cfg->tx_htcap = le16_to_cpu(htcfg->ht_tx_cap); + tx_cfg->tx_htinfo = le16_to_cpu(htcfg->ht_tx_info); + } + return 0; +} + +/* + * This function prepares command of reconfigure Tx buffer. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting Tx buffer size (for SET only) + * - Ensuring correct endian-ness + */ +int mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, int cmd_action, + void *data_buf) +{ + struct host_cmd_ds_txbuf_cfg *tx_buf = &cmd->params.tx_buf; + u16 action = (u16) cmd_action; + u16 buf_size = *((u16 *) data_buf); + + cmd->command = cpu_to_le16(HostCmd_CMD_RECONFIGURE_TX_BUFF); + cmd->size = + cpu_to_le16(sizeof(struct host_cmd_ds_txbuf_cfg) + S_DS_GEN); + tx_buf->action = cpu_to_le16(action); + switch (action) { + case HostCmd_ACT_GEN_SET: + dev_dbg(priv->adapter->dev, "cmd: set tx_buf=%d\n", buf_size); + tx_buf->buff_size = cpu_to_le16(buf_size); + break; + case HostCmd_ACT_GEN_GET: + default: + tx_buf->buff_size = 0; + break; + } + return 0; +} + +/* + * This function prepares command of AMSDU aggregation control. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting AMSDU control parameters (for SET only) + * - Ensuring correct endian-ness + */ +int mwifiex_cmd_amsdu_aggr_ctrl(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + int cmd_action, void *data_buf) +{ + struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl = + &cmd->params.amsdu_aggr_ctrl; + u16 action = (u16) cmd_action; + struct mwifiex_ds_11n_amsdu_aggr_ctrl *aa_ctrl = + (struct mwifiex_ds_11n_amsdu_aggr_ctrl *) data_buf; + + cmd->command = cpu_to_le16(HostCmd_CMD_AMSDU_AGGR_CTRL); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_amsdu_aggr_ctrl) + + S_DS_GEN); + amsdu_ctrl->action = cpu_to_le16(action); + switch (action) { + case HostCmd_ACT_GEN_SET: + amsdu_ctrl->enable = cpu_to_le16(aa_ctrl->enable); + amsdu_ctrl->curr_buf_size = 0; + break; + case HostCmd_ACT_GEN_GET: + default: + amsdu_ctrl->curr_buf_size = 0; + break; + } + return 0; +} + +/* + * This function handles the command response of AMSDU aggregation + * control request. + * + * Handling includes changing the header fields into CPU format. + */ +int mwifiex_ret_amsdu_aggr_ctrl(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *data_buf) +{ + struct mwifiex_ds_11n_amsdu_aggr_ctrl *amsdu_aggr_ctrl = NULL; + struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl = + &resp->params.amsdu_aggr_ctrl; + + if (data_buf) { + amsdu_aggr_ctrl = + (struct mwifiex_ds_11n_amsdu_aggr_ctrl *) data_buf; + amsdu_aggr_ctrl->enable = le16_to_cpu(amsdu_ctrl->enable); + amsdu_aggr_ctrl->curr_buf_size = + le16_to_cpu(amsdu_ctrl->curr_buf_size); + } + return 0; +} + +/* + * This function prepares 11n configuration command. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting HT Tx capability and HT Tx information fields + * - Ensuring correct endian-ness + */ +int mwifiex_cmd_11n_cfg(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf) +{ + struct host_cmd_ds_11n_cfg *htcfg = &cmd->params.htcfg; + struct mwifiex_ds_11n_tx_cfg *txcfg = + (struct mwifiex_ds_11n_tx_cfg *) data_buf; + + cmd->command = cpu_to_le16(HostCmd_CMD_11N_CFG); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_11n_cfg) + S_DS_GEN); + htcfg->action = cpu_to_le16(cmd_action); + htcfg->ht_tx_cap = cpu_to_le16(txcfg->tx_htcap); + htcfg->ht_tx_info = cpu_to_le16(txcfg->tx_htinfo); + return 0; +} + +/* + * This function appends an 11n TLV to a buffer. + * + * Buffer allocation is responsibility of the calling + * function. No size validation is made here. + * + * The function fills up the following sections, if applicable - + * - HT capability IE + * - HT information IE (with channel list) + * - 20/40 BSS Coexistence IE + * - HT Extended Capabilities IE + */ +int +mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc, + u8 **buffer) +{ + struct mwifiex_ie_types_htcap *ht_cap; + struct mwifiex_ie_types_htinfo *ht_info; + struct mwifiex_ie_types_chan_list_param_set *chan_list; + struct mwifiex_ie_types_2040bssco *bss_co_2040; + struct mwifiex_ie_types_extcap *ext_cap; + int ret_len = 0; + + if (!buffer || !*buffer) + return ret_len; + + if (bss_desc->bcn_ht_cap) { + ht_cap = (struct mwifiex_ie_types_htcap *) *buffer; + memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap)); + ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY); + ht_cap->header.len = + cpu_to_le16(sizeof(struct ieee80211_ht_cap)); + memcpy((u8 *) ht_cap + sizeof(struct mwifiex_ie_types_header), + (u8 *) bss_desc->bcn_ht_cap + + sizeof(struct ieee_types_header), + le16_to_cpu(ht_cap->header.len)); + + mwifiex_fill_cap_info(priv, ht_cap); + + *buffer += sizeof(struct mwifiex_ie_types_htcap); + ret_len += sizeof(struct mwifiex_ie_types_htcap); + } + + if (bss_desc->bcn_ht_info) { + if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { + ht_info = (struct mwifiex_ie_types_htinfo *) *buffer; + memset(ht_info, 0, + sizeof(struct mwifiex_ie_types_htinfo)); + ht_info->header.type = + cpu_to_le16(WLAN_EID_HT_INFORMATION); + ht_info->header.len = + cpu_to_le16(sizeof(struct ieee80211_ht_info)); + + memcpy((u8 *) ht_info + + sizeof(struct mwifiex_ie_types_header), + (u8 *) bss_desc->bcn_ht_info + + sizeof(struct ieee_types_header), + le16_to_cpu(ht_info->header.len)); + + if (!ISSUPP_CHANWIDTH40 + (priv->adapter->hw_dot_11n_dev_cap)) + ht_info->ht_info.ht_param &= + ~(IEEE80211_HT_PARAM_CHAN_WIDTH_ANY | + IEEE80211_HT_PARAM_CHA_SEC_OFFSET); + + *buffer += sizeof(struct mwifiex_ie_types_htinfo); + ret_len += sizeof(struct mwifiex_ie_types_htinfo); + } + + chan_list = + (struct mwifiex_ie_types_chan_list_param_set *) *buffer; + memset(chan_list, 0, + sizeof(struct mwifiex_ie_types_chan_list_param_set)); + chan_list->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); + chan_list->header.len = cpu_to_le16( + sizeof(struct mwifiex_ie_types_chan_list_param_set) - + sizeof(struct mwifiex_ie_types_header)); + chan_list->chan_scan_param[0].chan_number = + bss_desc->bcn_ht_info->control_chan; + chan_list->chan_scan_param[0].radio_type = + mwifiex_band_to_radio_type((u8) bss_desc->bss_band); + + if (ISSUPP_CHANWIDTH40(priv->adapter->hw_dot_11n_dev_cap) + && (bss_desc->bcn_ht_info->ht_param & + IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) + SET_SECONDARYCHAN(chan_list->chan_scan_param[0]. + radio_type, + (bss_desc->bcn_ht_info->ht_param & + IEEE80211_HT_PARAM_CHA_SEC_OFFSET)); + + *buffer += sizeof(struct mwifiex_ie_types_chan_list_param_set); + ret_len += sizeof(struct mwifiex_ie_types_chan_list_param_set); + } + + if (bss_desc->bcn_bss_co_2040) { + bss_co_2040 = (struct mwifiex_ie_types_2040bssco *) *buffer; + memset(bss_co_2040, 0, + sizeof(struct mwifiex_ie_types_2040bssco)); + bss_co_2040->header.type = cpu_to_le16(WLAN_EID_BSS_COEX_2040); + bss_co_2040->header.len = + cpu_to_le16(sizeof(bss_co_2040->bss_co_2040)); + + memcpy((u8 *) bss_co_2040 + + sizeof(struct mwifiex_ie_types_header), + (u8 *) bss_desc->bcn_bss_co_2040 + + sizeof(struct ieee_types_header), + le16_to_cpu(bss_co_2040->header.len)); + + *buffer += sizeof(struct mwifiex_ie_types_2040bssco); + ret_len += sizeof(struct mwifiex_ie_types_2040bssco); + } + + if (bss_desc->bcn_ext_cap) { + ext_cap = (struct mwifiex_ie_types_extcap *) *buffer; + memset(ext_cap, 0, sizeof(struct mwifiex_ie_types_extcap)); + ext_cap->header.type = cpu_to_le16(WLAN_EID_EXT_CAPABILITY); + ext_cap->header.len = cpu_to_le16(sizeof(ext_cap->ext_cap)); + + memcpy((u8 *) ext_cap + + sizeof(struct mwifiex_ie_types_header), + (u8 *) bss_desc->bcn_ext_cap + + sizeof(struct ieee_types_header), + le16_to_cpu(ext_cap->header.len)); + + *buffer += sizeof(struct mwifiex_ie_types_extcap); + ret_len += sizeof(struct mwifiex_ie_types_extcap); + } + + return ret_len; +} + +/* + * This function reconfigures the Tx buffer size in firmware. + * + * This function prepares a firmware command and issues it, if + * the current Tx buffer size is different from the one requested. + * Maximum configurable Tx buffer size is limited by the HT capability + * field value. + */ +void +mwifiex_cfg_tx_buf(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc) +{ + u16 max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_2K; + u16 tx_buf = 0; + u16 curr_tx_buf_size = 0; + + if (bss_desc->bcn_ht_cap) { + if (le16_to_cpu(bss_desc->bcn_ht_cap->cap_info) & + IEEE80211_HT_CAP_MAX_AMSDU) + max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_8K; + else + max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_4K; + } + + tx_buf = min(priv->adapter->max_tx_buf_size, max_amsdu); + + dev_dbg(priv->adapter->dev, "info: max_amsdu=%d, max_tx_buf=%d\n", + max_amsdu, priv->adapter->max_tx_buf_size); + + if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_2K) + curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; + else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_4K) + curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K; + else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_8K) + curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_8K; + if (curr_tx_buf_size != tx_buf) + mwifiex_prepare_cmd(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF, + HostCmd_ACT_GEN_SET, 0, + NULL, &tx_buf); + + return; +} + +/* + * This function checks if the given pointer is valid entry of + * Tx BA Stream table. + */ +static int mwifiex_is_tx_ba_stream_ptr_valid(struct mwifiex_private *priv, + struct mwifiex_tx_ba_stream_tbl *tx_tbl_ptr) +{ + struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl; + + list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { + if (tx_ba_tsr_tbl == tx_tbl_ptr) + return true; + } + + return false; +} + +/* + * This function deletes the given entry in Tx BA Stream table. + * + * The function also performs a validity check on the supplied + * pointer before trying to delete. + */ +void mwifiex_11n_delete_tx_ba_stream_tbl_entry(struct mwifiex_private *priv, + struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl) +{ + if (!tx_ba_tsr_tbl && + mwifiex_is_tx_ba_stream_ptr_valid(priv, tx_ba_tsr_tbl)) + return; + + dev_dbg(priv->adapter->dev, "info: tx_ba_tsr_tbl %p\n", tx_ba_tsr_tbl); + + list_del(&tx_ba_tsr_tbl->list); + + kfree(tx_ba_tsr_tbl); + + return; +} + +/* + * This function deletes all the entries in Tx BA Stream table. + */ +void mwifiex_11n_delete_all_tx_ba_stream_tbl(struct mwifiex_private *priv) +{ + int i; + struct mwifiex_tx_ba_stream_tbl *del_tbl_ptr, *tmp_node; + unsigned long flags; + + spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); + list_for_each_entry_safe(del_tbl_ptr, tmp_node, + &priv->tx_ba_stream_tbl_ptr, list) + mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, del_tbl_ptr); + spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); + + INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr); + + for (i = 0; i < MAX_NUM_TID; ++i) + priv->aggr_prio_tbl[i].ampdu_ap = + priv->aggr_prio_tbl[i].ampdu_user; +} + +/* + * This function returns the pointer to an entry in BA Stream + * table which matches the given RA/TID pair. + */ +struct mwifiex_tx_ba_stream_tbl * +mwifiex_11n_get_tx_ba_stream_tbl(struct mwifiex_private *priv, + int tid, u8 *ra) +{ + struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl; + unsigned long flags; + + spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); + list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { + if ((!memcmp(tx_ba_tsr_tbl->ra, ra, ETH_ALEN)) + && (tx_ba_tsr_tbl->tid == tid)) { + spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, + flags); + return tx_ba_tsr_tbl; + } + } + spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); + return NULL; +} + +/* + * This function creates an entry in Tx BA stream table for the + * given RA/TID pair. + */ +void mwifiex_11n_create_tx_ba_stream_tbl(struct mwifiex_private *priv, + u8 *ra, int tid, + enum mwifiex_ba_status ba_status) +{ + struct mwifiex_tx_ba_stream_tbl *new_node; + unsigned long flags; + + if (!mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, ra)) { + new_node = kzalloc(sizeof(struct mwifiex_tx_ba_stream_tbl), + GFP_ATOMIC); + if (!new_node) { + dev_err(priv->adapter->dev, + "%s: failed to alloc new_node\n", __func__); + return; + } + + INIT_LIST_HEAD(&new_node->list); + + new_node->tid = tid; + new_node->ba_status = ba_status; + memcpy(new_node->ra, ra, ETH_ALEN); + + spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); + list_add_tail(&new_node->list, &priv->tx_ba_stream_tbl_ptr); + spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); + } + + return; +} + +/* + * This function sends an add BA request to the given TID/RA pair. + */ +int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac) +{ + struct host_cmd_ds_11n_addba_req add_ba_req; + static u8 dialog_tok; + int ret; + + dev_dbg(priv->adapter->dev, "cmd: %s: tid %d\n", __func__, tid); + + add_ba_req.block_ack_param_set = cpu_to_le16( + (u16) ((tid << BLOCKACKPARAM_TID_POS) | + (priv->add_ba_param. + tx_win_size << BLOCKACKPARAM_WINSIZE_POS) | + IMMEDIATE_BLOCK_ACK)); + add_ba_req.block_ack_tmo = cpu_to_le16((u16)priv->add_ba_param.timeout); + + ++dialog_tok; + + if (dialog_tok == 0) + dialog_tok = 1; + + add_ba_req.dialog_token = dialog_tok; + memcpy(&add_ba_req.peer_mac_addr, peer_mac, ETH_ALEN); + + /* We don't wait for the response of this command */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_11N_ADDBA_REQ, + 0, 0, NULL, &add_ba_req); + + return ret; +} + +/* + * This function sends a delete BA request to the given TID/RA pair. + */ +int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac, + int initiator) +{ + struct host_cmd_ds_11n_delba delba; + int ret; + uint16_t del_ba_param_set; + + memset(&delba, 0, sizeof(delba)); + delba.del_ba_param_set = cpu_to_le16(tid << DELBA_TID_POS); + + del_ba_param_set = le16_to_cpu(delba.del_ba_param_set); + if (initiator) + del_ba_param_set |= IEEE80211_DELBA_PARAM_INITIATOR_MASK; + else + del_ba_param_set &= ~IEEE80211_DELBA_PARAM_INITIATOR_MASK; + + memcpy(&delba.peer_mac_addr, peer_mac, ETH_ALEN); + + /* We don't wait for the response of this command */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_11N_DELBA, + HostCmd_ACT_GEN_SET, 0, NULL, &delba); + + return ret; +} + +/* + * This function handles the command response of a delete BA request. + */ +void mwifiex_11n_delete_ba_stream(struct mwifiex_private *priv, u8 *del_ba) +{ + struct host_cmd_ds_11n_delba *cmd_del_ba = + (struct host_cmd_ds_11n_delba *) del_ba; + uint16_t del_ba_param_set = le16_to_cpu(cmd_del_ba->del_ba_param_set); + int tid; + + tid = del_ba_param_set >> DELBA_TID_POS; + + mwifiex_11n_delete_ba_stream_tbl(priv, tid, cmd_del_ba->peer_mac_addr, + TYPE_DELBA_RECEIVE, + INITIATOR_BIT(del_ba_param_set)); +} + +/* + * This function retrieves the Rx reordering table. + */ +int mwifiex_get_rx_reorder_tbl(struct mwifiex_private *priv, + struct mwifiex_ds_rx_reorder_tbl *buf) +{ + int i; + struct mwifiex_ds_rx_reorder_tbl *rx_reo_tbl = buf; + struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr; + int count = 0; + unsigned long flags; + + spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); + list_for_each_entry(rx_reorder_tbl_ptr, &priv->rx_reorder_tbl_ptr, + list) { + rx_reo_tbl->tid = (u16) rx_reorder_tbl_ptr->tid; + memcpy(rx_reo_tbl->ta, rx_reorder_tbl_ptr->ta, ETH_ALEN); + rx_reo_tbl->start_win = rx_reorder_tbl_ptr->start_win; + rx_reo_tbl->win_size = rx_reorder_tbl_ptr->win_size; + for (i = 0; i < rx_reorder_tbl_ptr->win_size; ++i) { + if (rx_reorder_tbl_ptr->rx_reorder_ptr[i]) + rx_reo_tbl->buffer[i] = true; + else + rx_reo_tbl->buffer[i] = false; + } + rx_reo_tbl++; + count++; + + if (count >= MWIFIEX_MAX_RX_BASTREAM_SUPPORTED) + break; + } + spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); + + return count; +} + +/* + * This function retrieves the Tx BA stream table. + */ +int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv, + struct mwifiex_ds_tx_ba_stream_tbl *buf) +{ + struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl; + struct mwifiex_ds_tx_ba_stream_tbl *rx_reo_tbl = buf; + int count = 0; + unsigned long flags; + + spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); + list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { + rx_reo_tbl->tid = (u16) tx_ba_tsr_tbl->tid; + dev_dbg(priv->adapter->dev, "data: %s tid=%d\n", + __func__, rx_reo_tbl->tid); + memcpy(rx_reo_tbl->ra, tx_ba_tsr_tbl->ra, ETH_ALEN); + rx_reo_tbl++; + count++; + if (count >= MWIFIEX_MAX_TX_BASTREAM_SUPPORTED) + break; + } + spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); + + return count; +} diff --git a/drivers/net/wireless/mwifiex/11n.h b/drivers/net/wireless/mwifiex/11n.h new file mode 100644 index 000000000000..71a853e61b61 --- /dev/null +++ b/drivers/net/wireless/mwifiex/11n.h @@ -0,0 +1,176 @@ +/* + * Marvell Wireless LAN device driver: 802.11n + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#ifndef _MWIFIEX_11N_H_ +#define _MWIFIEX_11N_H_ + +#include "11n_aggr.h" +#include "11n_rxreorder.h" +#include "wmm.h" + +int mwifiex_ret_11n_delba(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp); +int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp); +int mwifiex_ret_11n_cfg(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *data_buf); +int mwifiex_cmd_11n_cfg(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf); + +int mwifiex_cmd_11n_cfg(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf); + +int mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc, + u8 **buffer); +void mwifiex_cfg_tx_buf(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc); +void mwifiex_fill_cap_info(struct mwifiex_private *, + struct mwifiex_ie_types_htcap *); +int mwifiex_set_get_11n_htcap_cfg(struct mwifiex_private *priv, + u16 action, int *htcap_cfg); +void mwifiex_11n_delete_tx_ba_stream_tbl_entry(struct mwifiex_private *priv, + struct mwifiex_tx_ba_stream_tbl + *tx_tbl); +void mwifiex_11n_delete_all_tx_ba_stream_tbl(struct mwifiex_private *priv); +struct mwifiex_tx_ba_stream_tbl *mwifiex_11n_get_tx_ba_stream_tbl(struct + mwifiex_private + *priv, int tid, + u8 *ra); +void mwifiex_11n_create_tx_ba_stream_tbl(struct mwifiex_private *priv, u8 *ra, + int tid, + enum mwifiex_ba_status ba_status); +int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac); +int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac, + int initiator); +void mwifiex_11n_delete_ba_stream(struct mwifiex_private *priv, u8 *del_ba); +int mwifiex_get_rx_reorder_tbl(struct mwifiex_private *priv, + struct mwifiex_ds_rx_reorder_tbl *buf); +int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv, + struct mwifiex_ds_tx_ba_stream_tbl *buf); +int mwifiex_ret_amsdu_aggr_ctrl(struct mwifiex_private *priv, + struct host_cmd_ds_command + *resp, + void *data_buf); +int mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + int cmd_action, void *data_buf); +int mwifiex_cmd_amsdu_aggr_ctrl(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + int cmd_action, + void *data_buf); + +/* + * This function checks whether AMPDU is allowed or not for a particular TID. + */ +static inline u8 +mwifiex_is_ampdu_allowed(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *ptr, int tid) +{ + return ((priv->aggr_prio_tbl[tid].ampdu_ap != BA_STREAM_NOT_ALLOWED) + ? true : false); +} + +/* + * This function checks whether AMSDU is allowed or not for a particular TID. + */ +static inline u8 +mwifiex_is_amsdu_allowed(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *ptr, int tid) +{ + return (((priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED) + && ((priv->is_data_rate_auto) + || !((priv->bitmap_rates[2]) & 0x03))) + ? true : false); +} + +/* + * This function checks whether a BA stream is available or not. + */ +static inline u8 +mwifiex_is_ba_stream_avail(struct mwifiex_private *priv) +{ + struct mwifiex_private *pmpriv = NULL; + u8 i = 0; + u32 ba_stream_num = 0; + + for (i = 0; i < priv->adapter->priv_num; i++) { + pmpriv = priv->adapter->priv[i]; + if (pmpriv) + ba_stream_num += + mwifiex_wmm_list_len(priv->adapter, + (struct list_head + *) &pmpriv-> + tx_ba_stream_tbl_ptr); + } + + return ((ba_stream_num < + MWIFIEX_MAX_TX_BASTREAM_SUPPORTED) ? true : false); +} + +/* + * This function finds the correct Tx BA stream to delete. + * + * Upon successfully locating, both the TID and the RA are returned. + */ +static inline u8 +mwifiex_find_stream_to_delete(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *ptr, int ptr_tid, + int *ptid, u8 *ra) +{ + int tid; + u8 ret = false; + struct mwifiex_tx_ba_stream_tbl *tx_tbl; + unsigned long flags; + + tid = priv->aggr_prio_tbl[ptr_tid].ampdu_user; + + spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); + list_for_each_entry(tx_tbl, &priv->tx_ba_stream_tbl_ptr, list) { + if (tid > priv->aggr_prio_tbl[tx_tbl->tid].ampdu_user) { + tid = priv->aggr_prio_tbl[tx_tbl->tid].ampdu_user; + *ptid = tx_tbl->tid; + memcpy(ra, tx_tbl->ra, ETH_ALEN); + ret = true; + } + } + spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); + + return ret; +} + +/* + * This function checks whether BA stream is set up or not. + */ +static inline int +mwifiex_is_ba_stream_setup(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *ptr, int tid) +{ + struct mwifiex_tx_ba_stream_tbl *tx_tbl; + + tx_tbl = mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, ptr->ra); + if (tx_tbl && IS_BASTREAM_SETUP(tx_tbl)) + return true; + + return false; +} +#endif /* !_MWIFIEX_11N_H_ */ diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c new file mode 100644 index 000000000000..c2abced66957 --- /dev/null +++ b/drivers/net/wireless/mwifiex/11n_aggr.c @@ -0,0 +1,423 @@ +/* + * Marvell Wireless LAN device driver: 802.11n Aggregation + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" +#include "11n_aggr.h" + +/* + * Creates an AMSDU subframe for aggregation into one AMSDU packet. + * + * The resultant AMSDU subframe format is - + * + * +---- ~ -----+---- ~ ------+---- ~ -----+----- ~ -----+---- ~ -----+ + * | DA | SA | Length | SNAP header | MSDU | + * | data[0..5] | data[6..11] | | | data[14..] | + * +---- ~ -----+---- ~ ------+---- ~ -----+----- ~ -----+---- ~ -----+ + * <--6-bytes--> <--6-bytes--> <--2-bytes--><--8-bytes--> <--n-bytes--> + * + * This function also computes the amount of padding required to make the + * buffer length multiple of 4 bytes. + * + * Data => |DA|SA|SNAP-TYPE|........ .| + * MSDU => |DA|SA|Length|SNAP|...... ..| + */ +static int +mwifiex_11n_form_amsdu_pkt(struct mwifiex_adapter *adapter, + struct sk_buff *skb_aggr, + struct sk_buff *skb_src, int *pad) + +{ + int dt_offset; + struct rfc_1042_hdr snap = { + 0xaa, /* LLC DSAP */ + 0xaa, /* LLC SSAP */ + 0x03, /* LLC CTRL */ + {0x00, 0x00, 0x00}, /* SNAP OUI */ + 0x0000 /* SNAP type */ + /* + * This field will be overwritten + * later with ethertype + */ + }; + struct tx_packet_hdr *tx_header = NULL; + + skb_put(skb_aggr, sizeof(*tx_header)); + + tx_header = (struct tx_packet_hdr *) skb_aggr->data; + + /* Copy DA and SA */ + dt_offset = 2 * ETH_ALEN; + memcpy(&tx_header->eth803_hdr, skb_src->data, dt_offset); + + /* Copy SNAP header */ + snap.snap_type = *(u16 *) ((u8 *)skb_src->data + dt_offset); + dt_offset += sizeof(u16); + + memcpy(&tx_header->rfc1042_hdr, &snap, sizeof(struct rfc_1042_hdr)); + + skb_pull(skb_src, dt_offset); + + /* Update Length field */ + tx_header->eth803_hdr.h_proto = htons(skb_src->len + LLC_SNAP_LEN); + + /* Add payload */ + skb_put(skb_aggr, skb_src->len); + memcpy(skb_aggr->data + sizeof(*tx_header), skb_src->data, + skb_src->len); + *pad = (((skb_src->len + LLC_SNAP_LEN) & 3)) ? (4 - (((skb_src->len + + LLC_SNAP_LEN)) & 3)) : 0; + skb_put(skb_aggr, *pad); + + return skb_aggr->len + *pad; +} + +/* + * Adds TxPD to AMSDU header. + * + * Each AMSDU packet will contain one TxPD at the beginning, + * followed by multiple AMSDU subframes. + */ +static void +mwifiex_11n_form_amsdu_txpd(struct mwifiex_private *priv, + struct sk_buff *skb) +{ + struct txpd *local_tx_pd; + + skb_push(skb, sizeof(*local_tx_pd)); + + local_tx_pd = (struct txpd *) skb->data; + memset(local_tx_pd, 0, sizeof(struct txpd)); + + /* Original priority has been overwritten */ + local_tx_pd->priority = (u8) skb->priority; + local_tx_pd->pkt_delay_2ms = + mwifiex_wmm_compute_drv_pkt_delay(priv, skb); + local_tx_pd->bss_num = priv->bss_num; + local_tx_pd->bss_type = priv->bss_type; + /* Always zero as the data is followed by struct txpd */ + local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd)); + local_tx_pd->tx_pkt_type = cpu_to_le16(PKT_TYPE_AMSDU); + local_tx_pd->tx_pkt_length = cpu_to_le16(skb->len - + sizeof(*local_tx_pd)); + + if (local_tx_pd->tx_control == 0) + /* TxCtrl set by user or default */ + local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl); + + if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && + (priv->adapter->pps_uapsd_mode)) { + if (true == mwifiex_check_last_packet_indication(priv)) { + priv->adapter->tx_lock_flag = true; + local_tx_pd->flags = + MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET; + } + } +} + +/* + * Counts the number of subframes in an aggregate packet. + * + * This function parses an aggregate packet buffer, looking for + * subframes and counting the number of such subframe found. The + * function automatically skips the DA/SA fields at the beginning + * of each subframe and padding at the end. + */ +static int +mwifiex_11n_get_num_aggr_pkts(u8 *data, int total_pkt_len) +{ + int pkt_count = 0, pkt_len, pad; + + while (total_pkt_len > 0) { + /* Length will be in network format, change it to host */ + pkt_len = ntohs((*(__be16 *)(data + 2 * ETH_ALEN))); + pad = (((pkt_len + sizeof(struct ethhdr)) & 3)) ? + (4 - ((pkt_len + sizeof(struct ethhdr)) & 3)) : 0; + data += pkt_len + pad + sizeof(struct ethhdr); + total_pkt_len -= pkt_len + pad + sizeof(struct ethhdr); + ++pkt_count; + } + + return pkt_count; +} + +/* + * De-aggregate received packets. + * + * This function parses the received aggregate buffer, extracts each subframe, + * strips off the SNAP header from them and sends the data portion for further + * processing. + * + * Each subframe body is copied onto a separate buffer, which are freed by + * upper layer after processing. The function also performs sanity tests on + * the received buffer. + */ +int mwifiex_11n_deaggregate_pkt(struct mwifiex_private *priv, + struct sk_buff *skb) +{ + u16 pkt_len; + int total_pkt_len; + u8 *data; + int pad; + struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); + struct rxpd *local_rx_pd = (struct rxpd *) skb->data; + struct sk_buff *skb_daggr; + struct mwifiex_rxinfo *rx_info_daggr = NULL; + int ret = -1; + struct rx_packet_hdr *rx_pkt_hdr; + struct mwifiex_adapter *adapter = priv->adapter; + u8 rfc1042_eth_hdr[ETH_ALEN] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; + + data = (u8 *) (local_rx_pd + local_rx_pd->rx_pkt_offset); + total_pkt_len = local_rx_pd->rx_pkt_length; + + /* Sanity test */ + if (total_pkt_len > MWIFIEX_RX_DATA_BUF_SIZE) { + dev_err(adapter->dev, "total pkt len greater than buffer" + " size %d\n", total_pkt_len); + return -1; + } + + rx_info->use_count = mwifiex_11n_get_num_aggr_pkts(data, total_pkt_len); + + while (total_pkt_len > 0) { + rx_pkt_hdr = (struct rx_packet_hdr *) data; + /* Length will be in network format, change it to host */ + pkt_len = ntohs((*(__be16 *) (data + 2 * ETH_ALEN))); + if (pkt_len > total_pkt_len) { + dev_err(adapter->dev, "pkt_len %d > total_pkt_len %d\n", + total_pkt_len, pkt_len); + break; + } + + pad = (((pkt_len + sizeof(struct ethhdr)) & 3)) ? + (4 - ((pkt_len + sizeof(struct ethhdr)) & 3)) : 0; + + total_pkt_len -= pkt_len + pad + sizeof(struct ethhdr); + + if (memcmp(&rx_pkt_hdr->rfc1042_hdr, + rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) { + memmove(data + LLC_SNAP_LEN, data, 2 * ETH_ALEN); + data += LLC_SNAP_LEN; + pkt_len += sizeof(struct ethhdr) - LLC_SNAP_LEN; + } else { + *(u16 *) (data + 2 * ETH_ALEN) = (u16) 0; + pkt_len += sizeof(struct ethhdr); + } + + skb_daggr = dev_alloc_skb(pkt_len); + if (!skb_daggr) { + dev_err(adapter->dev, "%s: failed to alloc skb_daggr\n", + __func__); + return -1; + } + rx_info_daggr = MWIFIEX_SKB_RXCB(skb_daggr); + + rx_info_daggr->bss_index = rx_info->bss_index; + skb_daggr->tstamp = skb->tstamp; + rx_info_daggr->parent = skb; + skb_daggr->priority = skb->priority; + skb_put(skb_daggr, pkt_len); + memcpy(skb_daggr->data, data, pkt_len); + + ret = mwifiex_recv_packet(adapter, skb_daggr); + + switch (ret) { + case -EINPROGRESS: + break; + case -1: + dev_err(adapter->dev, "deaggr: host_to_card failed\n"); + case 0: + mwifiex_recv_packet_complete(adapter, skb_daggr, ret); + break; + default: + break; + } + + data += pkt_len + pad; + } + + return ret; +} + +/* + * Create aggregated packet. + * + * This function creates an aggregated MSDU packet, by combining buffers + * from the RA list. Each individual buffer is encapsulated as an AMSDU + * subframe and all such subframes are concatenated together to form the + * AMSDU packet. + * + * A TxPD is also added to the front of the resultant AMSDU packets for + * transmission. The resultant packets format is - + * + * +---- ~ ----+------ ~ ------+------ ~ ------+-..-+------ ~ ------+ + * | TxPD |AMSDU sub-frame|AMSDU sub-frame| .. |AMSDU sub-frame| + * | | 1 | 2 | .. | n | + * +---- ~ ----+------ ~ ------+------ ~ ------+ .. +------ ~ ------+ + */ +int +mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *pra_list, int headroom, + int ptrindex, unsigned long ra_list_flags) + __releases(&priv->wmm.ra_list_spinlock) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct sk_buff *skb_aggr, *skb_src; + struct mwifiex_txinfo *tx_info_aggr, *tx_info_src; + int pad = 0; + int ret = 0; + struct mwifiex_tx_param tx_param; + struct txpd *ptx_pd = NULL; + + if (skb_queue_empty(&pra_list->skb_head)) { + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + return 0; + } + skb_src = skb_peek(&pra_list->skb_head); + tx_info_src = MWIFIEX_SKB_TXCB(skb_src); + skb_aggr = dev_alloc_skb(adapter->tx_buf_size); + if (!skb_aggr) { + dev_err(adapter->dev, "%s: alloc skb_aggr\n", __func__); + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + return -1; + } + skb_reserve(skb_aggr, headroom + sizeof(struct txpd)); + tx_info_aggr = MWIFIEX_SKB_TXCB(skb_aggr); + + tx_info_aggr->bss_index = tx_info_src->bss_index; + skb_aggr->priority = skb_src->priority; + + while (skb_src && ((skb_headroom(skb_aggr) + skb_src->len + + LLC_SNAP_LEN) + <= adapter->tx_buf_size)) { + + if (!skb_queue_empty(&pra_list->skb_head)) + skb_src = skb_dequeue(&pra_list->skb_head); + else + skb_src = NULL; + + pra_list->total_pkts_size -= skb_src->len; + + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + mwifiex_11n_form_amsdu_pkt(adapter, skb_aggr, skb_src, &pad); + + mwifiex_write_data_complete(adapter, skb_src, 0); + + spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); + + if (!mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) { + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + return -1; + } + + if (!skb_queue_empty(&pra_list->skb_head)) + skb_src = skb_peek(&pra_list->skb_head); + else + skb_src = NULL; + } + + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags); + + /* Last AMSDU packet does not need padding */ + skb_trim(skb_aggr, skb_aggr->len - pad); + + /* Form AMSDU */ + mwifiex_11n_form_amsdu_txpd(priv, skb_aggr); + if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) + ptx_pd = (struct txpd *)skb_aggr->data; + + skb_push(skb_aggr, headroom); + + tx_param.next_pkt_len = ((pra_list->total_pkts_size) ? + (((pra_list->total_pkts_size) > + adapter->tx_buf_size) ? adapter-> + tx_buf_size : pra_list->total_pkts_size + + LLC_SNAP_LEN + sizeof(struct txpd)) : 0); + ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, + skb_aggr->data, + skb_aggr->len, &tx_param); + switch (ret) { + case -EBUSY: + spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); + if (!mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) { + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + mwifiex_write_data_complete(adapter, skb_aggr, -1); + return -1; + } + if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && + (adapter->pps_uapsd_mode) && + (adapter->tx_lock_flag)) { + priv->adapter->tx_lock_flag = false; + ptx_pd->flags = 0; + } + + skb_queue_tail(&pra_list->skb_head, skb_aggr); + + pra_list->total_pkts_size += skb_aggr->len; + + tx_info_aggr->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT; + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + dev_dbg(adapter->dev, "data: -EBUSY is returned\n"); + break; + case -1: + adapter->data_sent = false; + dev_err(adapter->dev, "%s: host_to_card failed: %#x\n", + __func__, ret); + adapter->dbg.num_tx_host_to_card_failure++; + mwifiex_write_data_complete(adapter, skb_aggr, ret); + return 0; + case -EINPROGRESS: + adapter->data_sent = false; + break; + case 0: + mwifiex_write_data_complete(adapter, skb_aggr, ret); + break; + default: + break; + } + if (ret != -EBUSY) { + spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); + if (mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) { + priv->wmm.packets_out[ptrindex]++; + priv->wmm.tid_tbl_ptr[ptrindex].ra_list_curr = pra_list; + } + /* Now bss_prio_cur pointer points to next node */ + adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur = + list_first_entry( + &adapter->bss_prio_tbl[priv->bss_priority] + .bss_prio_cur->list, + struct mwifiex_bss_prio_node, list); + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + } + + return 0; +} diff --git a/drivers/net/wireless/mwifiex/11n_aggr.h b/drivers/net/wireless/mwifiex/11n_aggr.h new file mode 100644 index 000000000000..9c6dca7ab02c --- /dev/null +++ b/drivers/net/wireless/mwifiex/11n_aggr.h @@ -0,0 +1,32 @@ +/* + * Marvell Wireless LAN device driver: 802.11n Aggregation + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#ifndef _MWIFIEX_11N_AGGR_H_ +#define _MWIFIEX_11N_AGGR_H_ + +#define PKT_TYPE_AMSDU 0xE6 + +int mwifiex_11n_deaggregate_pkt(struct mwifiex_private *priv, + struct sk_buff *skb); +int mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *ptr, int headroom, + int ptr_index, unsigned long flags) + __releases(&priv->wmm.ra_list_spinlock); + +#endif /* !_MWIFIEX_11N_AGGR_H_ */ diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c new file mode 100644 index 000000000000..8e94e620e6f4 --- /dev/null +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c @@ -0,0 +1,637 @@ +/* + * Marvell Wireless LAN device driver: 802.11n RX Re-ordering + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" +#include "11n_rxreorder.h" + +/* + * This function processes a received packet and forwards + * it to the kernel/upper layer. + */ +static int mwifiex_11n_dispatch_pkt(struct mwifiex_private *priv, void *payload) +{ + int ret = 0; + struct mwifiex_adapter *adapter = priv->adapter; + + ret = mwifiex_process_rx_packet(adapter, (struct sk_buff *) payload); + return ret; +} + +/* + * This function dispatches all packets in the Rx reorder table. + * + * There could be holes in the buffer, which are skipped by the function. + * Since the buffer is linear, the function uses rotation to simulate + * circular buffer. + */ +static int +mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv, + struct mwifiex_rx_reorder_tbl + *rx_reor_tbl_ptr, int start_win) +{ + int no_pkt_to_send, i, xchg; + void *rx_tmp_ptr = NULL; + unsigned long flags; + + no_pkt_to_send = (start_win > rx_reor_tbl_ptr->start_win) ? + min((start_win - rx_reor_tbl_ptr->start_win), + rx_reor_tbl_ptr->win_size) : rx_reor_tbl_ptr->win_size; + + for (i = 0; i < no_pkt_to_send; ++i) { + spin_lock_irqsave(&priv->rx_pkt_lock, flags); + rx_tmp_ptr = NULL; + if (rx_reor_tbl_ptr->rx_reorder_ptr[i]) { + rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i]; + rx_reor_tbl_ptr->rx_reorder_ptr[i] = NULL; + } + spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); + if (rx_tmp_ptr) + mwifiex_11n_dispatch_pkt(priv, rx_tmp_ptr); + } + + spin_lock_irqsave(&priv->rx_pkt_lock, flags); + /* + * We don't have a circular buffer, hence use rotation to simulate + * circular buffer + */ + xchg = rx_reor_tbl_ptr->win_size - no_pkt_to_send; + for (i = 0; i < xchg; ++i) { + rx_reor_tbl_ptr->rx_reorder_ptr[i] = + rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i]; + rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i] = NULL; + } + + rx_reor_tbl_ptr->start_win = start_win; + spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); + + return 0; +} + +/* + * This function dispatches all packets in the Rx reorder table until + * a hole is found. + * + * The start window is adjusted automatically when a hole is located. + * Since the buffer is linear, the function uses rotation to simulate + * circular buffer. + */ +static int +mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv, + struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr) +{ + int i, j, xchg; + void *rx_tmp_ptr = NULL; + unsigned long flags; + + for (i = 0; i < rx_reor_tbl_ptr->win_size; ++i) { + spin_lock_irqsave(&priv->rx_pkt_lock, flags); + if (!rx_reor_tbl_ptr->rx_reorder_ptr[i]) { + spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); + break; + } + rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i]; + rx_reor_tbl_ptr->rx_reorder_ptr[i] = NULL; + spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); + mwifiex_11n_dispatch_pkt(priv, rx_tmp_ptr); + } + + spin_lock_irqsave(&priv->rx_pkt_lock, flags); + /* + * We don't have a circular buffer, hence use rotation to simulate + * circular buffer + */ + if (i > 0) { + xchg = rx_reor_tbl_ptr->win_size - i; + for (j = 0; j < xchg; ++j) { + rx_reor_tbl_ptr->rx_reorder_ptr[j] = + rx_reor_tbl_ptr->rx_reorder_ptr[i + j]; + rx_reor_tbl_ptr->rx_reorder_ptr[i + j] = NULL; + } + } + rx_reor_tbl_ptr->start_win = (rx_reor_tbl_ptr->start_win + i) + &(MAX_TID_VALUE - 1); + spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); + return 0; +} + +/* + * This function deletes the Rx reorder table and frees the memory. + * + * The function stops the associated timer and dispatches all the + * pending packets in the Rx reorder table before deletion. + */ +static void +mwifiex_11n_delete_rx_reorder_tbl_entry(struct mwifiex_private *priv, + struct mwifiex_rx_reorder_tbl + *rx_reor_tbl_ptr) +{ + unsigned long flags; + + if (!rx_reor_tbl_ptr) + return; + + mwifiex_11n_dispatch_pkt_until_start_win(priv, rx_reor_tbl_ptr, + (rx_reor_tbl_ptr->start_win + + rx_reor_tbl_ptr->win_size) + &(MAX_TID_VALUE - 1)); + + del_timer(&rx_reor_tbl_ptr->timer_context.timer); + + spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); + list_del(&rx_reor_tbl_ptr->list); + spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); + + kfree(rx_reor_tbl_ptr->rx_reorder_ptr); + kfree(rx_reor_tbl_ptr); +} + +/* + * This function returns the pointer to an entry in Rx reordering + * table which matches the given TA/TID pair. + */ +static struct mwifiex_rx_reorder_tbl * +mwifiex_11n_get_rx_reorder_tbl(struct mwifiex_private *priv, int tid, u8 *ta) +{ + struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr; + unsigned long flags; + + spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); + list_for_each_entry(rx_reor_tbl_ptr, &priv->rx_reorder_tbl_ptr, list) { + if ((!memcmp(rx_reor_tbl_ptr->ta, ta, ETH_ALEN)) + && (rx_reor_tbl_ptr->tid == tid)) { + spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, + flags); + return rx_reor_tbl_ptr; + } + } + spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); + + return NULL; +} + +/* + * This function finds the last sequence number used in the packets + * buffered in Rx reordering table. + */ +static int +mwifiex_11n_find_last_seq_num(struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr) +{ + int i; + + for (i = (rx_reorder_tbl_ptr->win_size - 1); i >= 0; --i) + if (rx_reorder_tbl_ptr->rx_reorder_ptr[i]) + return i; + + return -1; +} + +/* + * This function flushes all the packets in Rx reordering table. + * + * The function checks if any packets are currently buffered in the + * table or not. In case there are packets available, it dispatches + * them and then dumps the Rx reordering table. + */ +static void +mwifiex_flush_data(unsigned long context) +{ + struct reorder_tmr_cnxt *reorder_cnxt = + (struct reorder_tmr_cnxt *) context; + int start_win; + + start_win = mwifiex_11n_find_last_seq_num(reorder_cnxt->ptr); + if (start_win >= 0) { + dev_dbg(reorder_cnxt->priv->adapter->dev, + "info: flush data %d\n", start_win); + mwifiex_11n_dispatch_pkt_until_start_win(reorder_cnxt->priv, + reorder_cnxt->ptr, + ((reorder_cnxt->ptr->start_win + + start_win + 1) & (MAX_TID_VALUE - 1))); + } +} + +/* + * This function creates an entry in Rx reordering table for the + * given TA/TID. + * + * The function also initializes the entry with sequence number, window + * size as well as initializes the timer. + * + * If the received TA/TID pair is already present, all the packets are + * dispatched and the window size is moved until the SSN. + */ +static void +mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta, + int tid, int win_size, int seq_num) +{ + int i; + struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr, *new_node; + u16 last_seq = 0; + unsigned long flags; + + /* + * If we get a TID, ta pair which is already present dispatch all the + * the packets and move the window size until the ssn + */ + rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta); + if (rx_reor_tbl_ptr) { + mwifiex_11n_dispatch_pkt_until_start_win(priv, rx_reor_tbl_ptr, + seq_num); + return; + } + /* if !rx_reor_tbl_ptr then create one */ + new_node = kzalloc(sizeof(struct mwifiex_rx_reorder_tbl), GFP_KERNEL); + if (!new_node) { + dev_err(priv->adapter->dev, "%s: failed to alloc new_node\n", + __func__); + return; + } + + INIT_LIST_HEAD(&new_node->list); + new_node->tid = tid; + memcpy(new_node->ta, ta, ETH_ALEN); + new_node->start_win = seq_num; + if (mwifiex_queuing_ra_based(priv)) + /* TODO for adhoc */ + dev_dbg(priv->adapter->dev, + "info: ADHOC:last_seq=%d start_win=%d\n", + last_seq, new_node->start_win); + else + last_seq = priv->rx_seq[tid]; + + if (last_seq >= new_node->start_win) + new_node->start_win = last_seq + 1; + + new_node->win_size = win_size; + + new_node->rx_reorder_ptr = kzalloc(sizeof(void *) * win_size, + GFP_KERNEL); + if (!new_node->rx_reorder_ptr) { + kfree((u8 *) new_node); + dev_err(priv->adapter->dev, + "%s: failed to alloc reorder_ptr\n", __func__); + return; + } + + new_node->timer_context.ptr = new_node; + new_node->timer_context.priv = priv; + + init_timer(&new_node->timer_context.timer); + new_node->timer_context.timer.function = mwifiex_flush_data; + new_node->timer_context.timer.data = + (unsigned long) &new_node->timer_context; + + for (i = 0; i < win_size; ++i) + new_node->rx_reorder_ptr[i] = NULL; + + spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); + list_add_tail(&new_node->list, &priv->rx_reorder_tbl_ptr); + spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); + + return; +} + +/* + * This function prepares command for adding a BA request. + * + * Preparation includes - + * - Setting command ID and proper size + * - Setting add BA request buffer + * - Ensuring correct endian-ness + */ +int mwifiex_cmd_11n_addba_req(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, void *data_buf) +{ + struct host_cmd_ds_11n_addba_req *add_ba_req = + (struct host_cmd_ds_11n_addba_req *) + &cmd->params.add_ba_req; + + cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_REQ); + cmd->size = cpu_to_le16(sizeof(*add_ba_req) + S_DS_GEN); + memcpy(add_ba_req, data_buf, sizeof(*add_ba_req)); + + return 0; +} + +/* + * This function prepares command for adding a BA response. + * + * Preparation includes - + * - Setting command ID and proper size + * - Setting add BA response buffer + * - Ensuring correct endian-ness + */ +int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf) +{ + struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = + (struct host_cmd_ds_11n_addba_rsp *) + &cmd->params.add_ba_rsp; + struct host_cmd_ds_11n_addba_req *cmd_addba_req = + (struct host_cmd_ds_11n_addba_req *) data_buf; + u8 tid = 0; + int win_size = 0; + uint16_t block_ack_param_set; + + cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_RSP); + cmd->size = cpu_to_le16(sizeof(*add_ba_rsp) + S_DS_GEN); + + memcpy(add_ba_rsp->peer_mac_addr, cmd_addba_req->peer_mac_addr, + ETH_ALEN); + add_ba_rsp->dialog_token = cmd_addba_req->dialog_token; + add_ba_rsp->block_ack_tmo = cmd_addba_req->block_ack_tmo; + add_ba_rsp->ssn = cmd_addba_req->ssn; + + block_ack_param_set = le16_to_cpu(cmd_addba_req->block_ack_param_set); + tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK) + >> BLOCKACKPARAM_TID_POS; + add_ba_rsp->status_code = cpu_to_le16(ADDBA_RSP_STATUS_ACCEPT); + block_ack_param_set &= ~IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK; + /* We donot support AMSDU inside AMPDU, hence reset the bit */ + block_ack_param_set &= ~BLOCKACKPARAM_AMSDU_SUPP_MASK; + block_ack_param_set |= (priv->add_ba_param.rx_win_size << + BLOCKACKPARAM_WINSIZE_POS); + add_ba_rsp->block_ack_param_set = cpu_to_le16(block_ack_param_set); + win_size = (le16_to_cpu(add_ba_rsp->block_ack_param_set) + & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) + >> BLOCKACKPARAM_WINSIZE_POS; + cmd_addba_req->block_ack_param_set = cpu_to_le16(block_ack_param_set); + + mwifiex_11n_create_rx_reorder_tbl(priv, cmd_addba_req->peer_mac_addr, + tid, win_size, le16_to_cpu(cmd_addba_req->ssn)); + return 0; +} + +/* + * This function prepares command for deleting a BA request. + * + * Preparation includes - + * - Setting command ID and proper size + * - Setting del BA request buffer + * - Ensuring correct endian-ness + */ +int mwifiex_cmd_11n_delba(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, void *data_buf) +{ + struct host_cmd_ds_11n_delba *del_ba = (struct host_cmd_ds_11n_delba *) + &cmd->params.del_ba; + + cmd->command = cpu_to_le16(HostCmd_CMD_11N_DELBA); + cmd->size = cpu_to_le16(sizeof(*del_ba) + S_DS_GEN); + memcpy(del_ba, data_buf, sizeof(*del_ba)); + + return 0; +} + +/* + * This function identifies if Rx reordering is needed for a received packet. + * + * In case reordering is required, the function will do the reordering + * before sending it to kernel. + * + * The Rx reorder table is checked first with the received TID/TA pair. If + * not found, the received packet is dispatched immediately. But if found, + * the packet is reordered and all the packets in the updated Rx reordering + * table is dispatched until a hole is found. + * + * For sequence number less than the starting window, the packet is dropped. + */ +int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv, + u16 seq_num, u16 tid, + u8 *ta, u8 pkt_type, void *payload) +{ + struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr; + int start_win, end_win, win_size; + int ret = 0; + u16 pkt_index = 0; + + rx_reor_tbl_ptr = + mwifiex_11n_get_rx_reorder_tbl((struct mwifiex_private *) priv, + tid, ta); + if (!rx_reor_tbl_ptr) { + if (pkt_type != PKT_TYPE_BAR) + mwifiex_11n_dispatch_pkt(priv, payload); + return 0; + } + start_win = rx_reor_tbl_ptr->start_win; + win_size = rx_reor_tbl_ptr->win_size; + end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1); + del_timer(&rx_reor_tbl_ptr->timer_context.timer); + mod_timer(&rx_reor_tbl_ptr->timer_context.timer, jiffies + + (MIN_FLUSH_TIMER_MS * win_size * HZ) / 1000); + + /* + * If seq_num is less then starting win then ignore and drop the + * packet + */ + if ((start_win + TWOPOW11) > (MAX_TID_VALUE - 1)) {/* Wrap */ + if (seq_num >= ((start_win + (TWOPOW11)) & (MAX_TID_VALUE - 1)) + && (seq_num < start_win)) + return -1; + } else if ((seq_num < start_win) + || (seq_num > (start_win + (TWOPOW11)))) { + return -1; + } + + /* + * If this packet is a BAR we adjust seq_num as + * WinStart = seq_num + */ + if (pkt_type == PKT_TYPE_BAR) + seq_num = ((seq_num + win_size) - 1) & (MAX_TID_VALUE - 1); + + if (((end_win < start_win) + && (seq_num < (TWOPOW11 - (MAX_TID_VALUE - start_win))) + && (seq_num > end_win)) || ((end_win > start_win) + && ((seq_num > end_win) || (seq_num < start_win)))) { + end_win = seq_num; + if (((seq_num - win_size) + 1) >= 0) + start_win = (end_win - win_size) + 1; + else + start_win = (MAX_TID_VALUE - (win_size - seq_num)) + 1; + ret = mwifiex_11n_dispatch_pkt_until_start_win(priv, + rx_reor_tbl_ptr, start_win); + + if (ret) + return ret; + } + + if (pkt_type != PKT_TYPE_BAR) { + if (seq_num >= start_win) + pkt_index = seq_num - start_win; + else + pkt_index = (seq_num+MAX_TID_VALUE) - start_win; + + if (rx_reor_tbl_ptr->rx_reorder_ptr[pkt_index]) + return -1; + + rx_reor_tbl_ptr->rx_reorder_ptr[pkt_index] = payload; + } + + /* + * Dispatch all packets sequentially from start_win until a + * hole is found and adjust the start_win appropriately + */ + ret = mwifiex_11n_scan_and_dispatch(priv, rx_reor_tbl_ptr); + + return ret; +} + +/* + * This function deletes an entry for a given TID/TA pair. + * + * The TID/TA are taken from del BA event body. + */ +void +mwifiex_11n_delete_ba_stream_tbl(struct mwifiex_private *priv, int tid, + u8 *peer_mac, u8 type, int initiator) +{ + struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr; + struct mwifiex_tx_ba_stream_tbl *ptx_tbl; + u8 cleanup_rx_reorder_tbl; + unsigned long flags; + + if (type == TYPE_DELBA_RECEIVE) + cleanup_rx_reorder_tbl = (initiator) ? true : false; + else + cleanup_rx_reorder_tbl = (initiator) ? false : true; + + dev_dbg(priv->adapter->dev, "event: DELBA: %pM tid=%d, " + "initiator=%d\n", peer_mac, tid, initiator); + + if (cleanup_rx_reorder_tbl) { + rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv, tid, + peer_mac); + if (!rx_reor_tbl_ptr) { + dev_dbg(priv->adapter->dev, + "event: TID, TA not found in table\n"); + return; + } + mwifiex_11n_delete_rx_reorder_tbl_entry(priv, rx_reor_tbl_ptr); + } else { + ptx_tbl = mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, peer_mac); + if (!ptx_tbl) { + dev_dbg(priv->adapter->dev, + "event: TID, RA not found in table\n"); + return; + } + + spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); + mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, ptx_tbl); + spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); + } +} + +/* + * This function handles the command response of an add BA response. + * + * Handling includes changing the header fields into CPU format and + * creating the stream, provided the add BA is accepted. + */ +int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = + (struct host_cmd_ds_11n_addba_rsp *) + &resp->params.add_ba_rsp; + int tid, win_size; + struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr = NULL; + uint16_t block_ack_param_set; + + block_ack_param_set = le16_to_cpu(add_ba_rsp->block_ack_param_set); + + tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK) + >> BLOCKACKPARAM_TID_POS; + /* + * Check if we had rejected the ADDBA, if yes then do not create + * the stream + */ + if (le16_to_cpu(add_ba_rsp->status_code) == BA_RESULT_SUCCESS) { + win_size = (block_ack_param_set & + IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) + >> BLOCKACKPARAM_WINSIZE_POS; + + dev_dbg(priv->adapter->dev, "cmd: ADDBA RSP: %pM" + " tid=%d ssn=%d win_size=%d\n", + add_ba_rsp->peer_mac_addr, + tid, add_ba_rsp->ssn, win_size); + } else { + dev_err(priv->adapter->dev, "ADDBA RSP: failed %pM tid=%d)\n", + add_ba_rsp->peer_mac_addr, tid); + + rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv, + tid, add_ba_rsp->peer_mac_addr); + if (rx_reor_tbl_ptr) + mwifiex_11n_delete_rx_reorder_tbl_entry(priv, + rx_reor_tbl_ptr); + } + + return 0; +} + +/* + * This function handles BA stream timeout event by preparing and sending + * a command to the firmware. + */ +void mwifiex_11n_ba_stream_timeout(struct mwifiex_private *priv, + struct host_cmd_ds_11n_batimeout *event) +{ + struct host_cmd_ds_11n_delba delba; + + memset(&delba, 0, sizeof(struct host_cmd_ds_11n_delba)); + memcpy(delba.peer_mac_addr, event->peer_mac_addr, ETH_ALEN); + + delba.del_ba_param_set |= + cpu_to_le16((u16) event->tid << DELBA_TID_POS); + delba.del_ba_param_set |= cpu_to_le16( + (u16) event->origninator << DELBA_INITIATOR_POS); + delba.reason_code = cpu_to_le16(WLAN_REASON_QSTA_TIMEOUT); + mwifiex_prepare_cmd(priv, HostCmd_CMD_11N_DELBA, 0, 0, NULL, &delba); + + return; +} + +/* + * This function cleans up the Rx reorder table by deleting all the entries + * and re-initializing. + */ +void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv) +{ + struct mwifiex_rx_reorder_tbl *del_tbl_ptr, *tmp_node; + unsigned long flags; + + spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); + list_for_each_entry_safe(del_tbl_ptr, tmp_node, + &priv->rx_reorder_tbl_ptr, list) { + spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); + mwifiex_11n_delete_rx_reorder_tbl_entry(priv, del_tbl_ptr); + spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); + } + spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); + + INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr); + memset(priv->rx_seq, 0, sizeof(priv->rx_seq)); +} diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.h b/drivers/net/wireless/mwifiex/11n_rxreorder.h new file mode 100644 index 000000000000..42f569035745 --- /dev/null +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.h @@ -0,0 +1,67 @@ +/* + * Marvell Wireless LAN device driver: 802.11n RX Re-ordering + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#ifndef _MWIFIEX_11N_RXREORDER_H_ +#define _MWIFIEX_11N_RXREORDER_H_ + +#define MIN_FLUSH_TIMER_MS 50 + +#define PKT_TYPE_BAR 0xE7 +#define MAX_TID_VALUE (2 << 11) +#define TWOPOW11 (2 << 10) + +#define BLOCKACKPARAM_TID_POS 2 +#define BLOCKACKPARAM_AMSDU_SUPP_MASK 0x1 +#define BLOCKACKPARAM_WINSIZE_POS 6 +#define DELBA_TID_POS 12 +#define DELBA_INITIATOR_POS 11 +#define TYPE_DELBA_SENT 1 +#define TYPE_DELBA_RECEIVE 2 +#define IMMEDIATE_BLOCK_ACK 0x2 + +#define ADDBA_RSP_STATUS_ACCEPT 0 + +int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *, + u16 seqNum, + u16 tid, u8 *ta, + u8 pkttype, void *payload); +void mwifiex_11n_delete_ba_stream_tbl(struct mwifiex_private *priv, int Tid, + u8 *PeerMACAddr, u8 type, + int initiator); +void mwifiex_11n_ba_stream_timeout(struct mwifiex_private *priv, + struct host_cmd_ds_11n_batimeout *event); +int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv, + struct host_cmd_ds_command + *resp); +int mwifiex_cmd_11n_delba(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf); +int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv, + struct host_cmd_ds_command + *cmd, void *data_buf); +int mwifiex_cmd_11n_addba_req(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf); +void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv); +struct mwifiex_rx_reorder_tbl *mwifiex_11n_get_rxreorder_tbl(struct + mwifiex_private + *priv, int tid, + u8 *ta); + +#endif /* _MWIFIEX_11N_RXREORDER_H_ */ diff --git a/drivers/net/wireless/mwifiex/Kconfig b/drivers/net/wireless/mwifiex/Kconfig new file mode 100644 index 000000000000..86962920cef3 --- /dev/null +++ b/drivers/net/wireless/mwifiex/Kconfig @@ -0,0 +1,21 @@ +config MWIFIEX + tristate "Marvell WiFi-Ex Driver" + depends on CFG80211 + select LIB80211 + ---help--- + This adds support for wireless adapters based on Marvell + 802.11n chipsets. + + If you choose to build it as a module, it will be called + mwifiex. + +config MWIFIEX_SDIO + tristate "Marvell WiFi-Ex Driver for SD8787" + depends on MWIFIEX && MMC + select FW_LOADER + ---help--- + This adds support for wireless adapters based on Marvell + 8787 chipset with SDIO interface. + + If you choose to build it as a module, it will be called + mwifiex_sdio. diff --git a/drivers/net/wireless/mwifiex/Makefile b/drivers/net/wireless/mwifiex/Makefile new file mode 100644 index 000000000000..42cb733ea33a --- /dev/null +++ b/drivers/net/wireless/mwifiex/Makefile @@ -0,0 +1,41 @@ +# +# Copyright (C) 2011, Marvell International Ltd. +# +# This software file (the "File") is distributed by Marvell International +# Ltd. under the terms of the GNU General Public License Version 2, June 1991 +# (the "License"). You may use, redistribute and/or modify this File in +# accordance with the terms and conditions of the License, a copy of which +# is available by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the +# worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. +# +# THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE +# IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE +# ARE EXPRESSLY DISCLAIMED. The License provides additional details about +# this warranty disclaimer. + + +mwifiex-y += main.o +mwifiex-y += init.o +mwifiex-y += cfp.o +mwifiex-y += cmdevt.o +mwifiex-y += util.o +mwifiex-y += txrx.o +mwifiex-y += wmm.o +mwifiex-y += 11n.o +mwifiex-y += 11n_aggr.o +mwifiex-y += 11n_rxreorder.o +mwifiex-y += scan.o +mwifiex-y += join.o +mwifiex-y += sta_ioctl.o +mwifiex-y += sta_cmd.o +mwifiex-y += sta_cmdresp.o +mwifiex-y += sta_event.o +mwifiex-y += sta_tx.o +mwifiex-y += sta_rx.o +mwifiex-y += cfg80211.o +mwifiex-$(CONFIG_DEBUG_FS) += debugfs.o +obj-$(CONFIG_MWIFIEX) += mwifiex.o + +mwifiex_sdio-y += sdio.o +obj-$(CONFIG_MWIFIEX_SDIO) += mwifiex_sdio.o diff --git a/drivers/net/wireless/mwifiex/README b/drivers/net/wireless/mwifiex/README new file mode 100644 index 000000000000..338377f7093b --- /dev/null +++ b/drivers/net/wireless/mwifiex/README @@ -0,0 +1,204 @@ +# Copyright (C) 2011, Marvell International Ltd. +# +# This software file (the "File") is distributed by Marvell International +# Ltd. under the terms of the GNU General Public License Version 2, June 1991 +# (the "License"). You may use, redistribute and/or modify this File in +# accordance with the terms and conditions of the License, a copy of which +# is available by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the +# worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. +# +# THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE +# IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE +# ARE EXPRESSLY DISCLAIMED. The License provides additional details about +# this warranty disclaimer. + + +=============================================================================== + U S E R M A N U A L + +1) FOR DRIVER INSTALL + + a) Copy sd8787.bin to /lib/firmware/mrvl/ directory, + create the directory if it doesn't exist. + b) Install WLAN driver, + insmod mwifiex.ko + c) Uninstall WLAN driver, + ifconfig mlanX down + rmmod mwifiex + + +2) FOR DRIVER CONFIGURATION AND INFO + The configurations can be done either using the 'iw' user space + utility or debugfs. + + a) 'iw' utility commands + + Following are some useful iw commands:- + +iw dev mlan0 scan + + This command will trigger a scan. + The command will then display the scan table entries + +iw dev mlan0 connect -w <SSID> [<freq in MHz>] [<bssid>] [key 0:abcde d:1123456789a] + The above command can be used to connect to an AP with a particular SSID. + Ap's operating frequency can be specified or even the bssid. If the AP is using + WEP encryption, wep keys can be specified in the command. + Note: Every time before connecting to an AP scan command (iw dev mlan0 scan) should be used by user. + +iw dev mlan0 disconnect + This command will be used to disconnect from an AP. + + +iw dev mlan0 ibss join <SSID> <freq in MHz> [fixed-freq] [fixed-bssid] [key 0:abcde] + The command will be used to join or create an ibss. Optionally, operating frequency, + bssid and the security related parameters can be specified while joining/creating + and ibss. + +iw dev mlan0 ibss leave + The command will be used to leave an ibss network. + +iw dev mlan0 link + The command will be used to get the connection status. The command will return parameters + such as SSID, operating frequency, rx/tx packets, signal strength, tx bitrate. + + Apart from the iw utility all standard configurations using the 'iwconfig' utility are also supported. + + b) Debugfs interface + + The debugfs interface can be used for configurations and for getting + some useful information from the driver. + The section below explains the configurations that can be + done. + + Mount debugfs to /debugfs mount point: + + mkdir /debugfs + mount -t debugfs debugfs /debugfs + + The information is provided in /debugfs/mwifiex/mlanX/: + +iw reg set <country code> + The command will be used to change the regulatory domain. + +iw reg get + The command will be used to get current regulatory domain. + +info + This command is used to get driver info. + + Usage: + cat info + + driver_name = "mwifiex" + driver_version = <driver_name, driver_version, (firmware_version)> + interface_name = "mlanX" + bss_mode = "Ad-hoc" | "Managed" | "Auto" | "Unknown" + media_state = "Disconnected" | "Connected" + mac_address = <6-byte adapter MAC address> + multicase_count = <multicast address count> + essid = <current SSID> + bssid = <current BSSID> + channel = <current channel> + region_code = <current region code> + multicasr_address[n] = <multicast address> + num_tx_bytes = <number of bytes sent to device> + num_rx_bytes = <number of bytes received from device and sent to kernel> + num_tx_pkts = <number of packets sent to device> + num_rx_pkts = <number of packets received from device and sent to kernel> + num_tx_pkts_dropped = <number of Tx packets dropped by driver> + num_rx_pkts_dropped = <number of Rx packets dropped by driver> + num_tx_pkts_err = <number of Tx packets failed to send to device> + num_rx_pkts_err = <number of Rx packets failed to receive from device> + carrier "on" | "off" + tx queue "stopped" | "started" + + The following debug info are provided in /debugfs/mwifiex/mlanX/debug: + + int_counter = <interrupt count, cleared when interrupt handled> + wmm_ac_vo = <number of packets sent to device from WMM AcVo queue> + wmm_ac_vi = <number of packets sent to device from WMM AcVi queue> + wmm_ac_be = <number of packets sent to device from WMM AcBE queue> + wmm_ac_bk = <number of packets sent to device from WMM AcBK queue> + max_tx_buf_size = <maximum Tx buffer size> + tx_buf_size = <current Tx buffer size> + curr_tx_buf_size = <current Tx buffer size> + ps_mode = <0/1, CAM mode/PS mode> + ps_state = <0/1/2/3, full power state/awake state/pre-sleep state/sleep state> + is_deep_sleep = <0/1, not deep sleep state/deep sleep state> + wakeup_dev_req = <0/1, wakeup device not required/required> + wakeup_tries = <wakeup device count, cleared when device awake> + hs_configured = <0/1, host sleep not configured/configured> + hs_activated = <0/1, extended host sleep not activated/activated> + num_tx_timeout = <number of Tx timeout> + num_cmd_timeout = <number of timeout commands> + timeout_cmd_id = <command id of the last timeout command> + timeout_cmd_act = <command action of the last timeout command> + last_cmd_id = <command id of the last several commands sent to device> + last_cmd_act = <command action of the last several commands sent to device> + last_cmd_index = <0 based last command index> + last_cmd_resp_id = <command id of the last several command responses received from device> + last_cmd_resp_index = <0 based last command response index> + last_event = <event id of the last several events received from device> + last_event_index = <0 based last event index> + num_cmd_h2c_fail = <number of commands failed to send to device> + num_cmd_sleep_cfm_fail = <number of sleep confirm failed to send to device> + num_tx_h2c_fail = <number of data packets failed to send to device> + num_evt_deauth = <number of deauthenticated events received from device> + num_evt_disassoc = <number of disassociated events received from device> + num_evt_link_lost = <number of link lost events received from device> + num_cmd_deauth = <number of deauthenticate commands sent to device> + num_cmd_assoc_ok = <number of associate commands with success return> + num_cmd_assoc_fail = <number of associate commands with failure return> + cmd_sent = <0/1, send command resources available/sending command to device> + data_sent = <0/1, send data resources available/sending data to device> + mp_rd_bitmap = <SDIO multi-port read bitmap> + mp_wr_bitmap = <SDIO multi-port write bitmap> + cmd_resp_received = <0/1, no cmd response to process/response received and yet to process> + event_received = <0/1, no event to process/event received and yet to process> + ioctl_pending = <number of ioctl pending> + tx_pending = <number of Tx packet pending> + rx_pending = <number of Rx packet pending> + + +3) FOR DRIVER CONFIGURATION + +regrdwr + This command is used to read/write the adapter register. + + Usage: + echo " <type> <offset> [value]" > regrdwr + cat regrdwr + + where the parameters are, + <type>: 1:MAC/SOC, 2:BBP, 3:RF, 4:PMIC, 5:CAU + <offset>: offset of register + [value]: value to be written + + Examples: + echo "1 0xa060" > regrdwr : Read the MAC register + echo "1 0xa060 0x12" > regrdwr : Write the MAC register + echo "1 0xa794 0x80000000" > regrdwr + : Write 0x80000000 to MAC register +rdeeprom + This command is used to read the EEPROM contents of the card. + + Usage: + echo "<offset> <length>" > rdeeprom + cat rdeeprom + + where the parameters are, + <offset>: multiples of 4 + <length>: 4-20, multiples of 4 + + Example: + echo "0 20" > rdeeprom : Read 20 bytes of EEPROM data from offset 0 + +getlog + This command is used to get the statistics available in the station. + Usage: + + cat getlog + +=============================================================================== diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c new file mode 100644 index 000000000000..ec0895f4e8d3 --- /dev/null +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -0,0 +1,1456 @@ +/* + * Marvell Wireless LAN device driver: CFG80211 + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "cfg80211.h" +#include "main.h" + +/* + * This function maps the nl802.11 channel type into driver channel type. + * + * The mapping is as follows - + * NL80211_CHAN_NO_HT -> NO_SEC_CHANNEL + * NL80211_CHAN_HT20 -> NO_SEC_CHANNEL + * NL80211_CHAN_HT40PLUS -> SEC_CHANNEL_ABOVE + * NL80211_CHAN_HT40MINUS -> SEC_CHANNEL_BELOW + * Others -> NO_SEC_CHANNEL + */ +static int +mwifiex_cfg80211_channel_type_to_mwifiex_channels(enum nl80211_channel_type + channel_type) +{ + int channel; + switch (channel_type) { + case NL80211_CHAN_NO_HT: + case NL80211_CHAN_HT20: + channel = NO_SEC_CHANNEL; + break; + case NL80211_CHAN_HT40PLUS: + channel = SEC_CHANNEL_ABOVE; + break; + case NL80211_CHAN_HT40MINUS: + channel = SEC_CHANNEL_BELOW; + break; + default: + channel = NO_SEC_CHANNEL; + } + return channel; +} + +/* + * This function maps the driver channel type into nl802.11 channel type. + * + * The mapping is as follows - + * NO_SEC_CHANNEL -> NL80211_CHAN_HT20 + * SEC_CHANNEL_ABOVE -> NL80211_CHAN_HT40PLUS + * SEC_CHANNEL_BELOW -> NL80211_CHAN_HT40MINUS + * Others -> NL80211_CHAN_HT20 + */ +static enum nl80211_channel_type +mwifiex_channels_to_cfg80211_channel_type(int channel_type) +{ + int channel; + switch (channel_type) { + case NO_SEC_CHANNEL: + channel = NL80211_CHAN_HT20; + break; + case SEC_CHANNEL_ABOVE: + channel = NL80211_CHAN_HT40PLUS; + break; + case SEC_CHANNEL_BELOW: + channel = NL80211_CHAN_HT40MINUS; + break; + default: + channel = NL80211_CHAN_HT20; + } + return channel; +} + +/* + * This function checks whether WEP is set. + */ +static int +mwifiex_is_alg_wep(u32 cipher) +{ + int alg = 0; + + switch (cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + alg = 1; + break; + default: + alg = 0; + break; + } + return alg; +} + +/* + * This function retrieves the private structure from kernel wiphy structure. + */ +static void *mwifiex_cfg80211_get_priv(struct wiphy *wiphy) +{ + return (void *) (*(unsigned long *) wiphy_priv(wiphy)); +} + +/* + * CFG802.11 operation handler to delete a network key. + */ +static int +mwifiex_cfg80211_del_key(struct wiphy *wiphy, struct net_device *netdev, + u8 key_index, bool pairwise, const u8 *mac_addr) +{ + struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + int ret = 0; + + ret = mwifiex_set_encode(priv, NULL, 0, key_index, 1); + if (ret) { + wiphy_err(wiphy, "deleting the crypto keys\n"); + return -EFAULT; + } + + wiphy_dbg(wiphy, "info: crypto keys deleted\n"); + return 0; +} + +/* + * CFG802.11 operation handler to set Tx power. + */ +static int +mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy, + enum nl80211_tx_power_setting type, + int dbm) +{ + int ret = 0; + struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + + ret = mwifiex_set_tx_power(priv, type, dbm); + + return ret; +} + +/* + * CFG802.11 operation handler to set Power Save option. + * + * The timeout value, if provided, is currently ignored. + */ +static int +mwifiex_cfg80211_set_power_mgmt(struct wiphy *wiphy, + struct net_device *dev, + bool enabled, int timeout) +{ + int ret = 0; + struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + + if (timeout) + wiphy_dbg(wiphy, + "info: ignoring the timeout value" + " for IEEE power save\n"); + + ret = mwifiex_drv_set_power(priv, enabled); + + return ret; +} + +/* + * CFG802.11 operation handler to set the default network key. + */ +static int +mwifiex_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *netdev, + u8 key_index, bool unicast, + bool multicast) +{ + struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + int ret; + + /* Return if WEP key not configured */ + if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED) + return 0; + + ret = mwifiex_set_encode(priv, NULL, 0, key_index, 0); + + wiphy_dbg(wiphy, "info: set default Tx key index\n"); + + if (ret) + return -EFAULT; + + return 0; +} + +/* + * CFG802.11 operation handler to add a network key. + */ +static int +mwifiex_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev, + u8 key_index, bool pairwise, const u8 *mac_addr, + struct key_params *params) +{ + struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + int ret = 0; + + ret = mwifiex_set_encode(priv, params->key, params->key_len, + key_index, 0); + + wiphy_dbg(wiphy, "info: crypto keys added\n"); + + if (ret) + return -EFAULT; + + return 0; +} + +/* + * This function sends domain information to the firmware. + * + * The following information are passed to the firmware - + * - Country codes + * - Sub bands (first channel, number of channels, maximum Tx power) + */ +static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy) +{ + u8 no_of_triplet = 0; + struct ieee80211_country_ie_triplet *t; + u8 no_of_parsed_chan = 0; + u8 first_chan = 0, next_chan = 0, max_pwr = 0; + u8 i, flag = 0; + enum ieee80211_band band; + struct ieee80211_supported_band *sband; + struct ieee80211_channel *ch; + struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_802_11d_domain_reg *domain_info = &adapter->domain_reg; + int ret = 0; + + /* Set country code */ + domain_info->country_code[0] = priv->country_code[0]; + domain_info->country_code[1] = priv->country_code[1]; + domain_info->country_code[2] = ' '; + + band = mwifiex_band_to_radio_type(adapter->config_bands); + if (!wiphy->bands[band]) { + wiphy_err(wiphy, "11D: setting domain info in FW\n"); + return -1; + } + + sband = wiphy->bands[band]; + + for (i = 0; i < sband->n_channels ; i++) { + ch = &sband->channels[i]; + if (ch->flags & IEEE80211_CHAN_DISABLED) + continue; + + if (!flag) { + flag = 1; + first_chan = (u32) ch->hw_value; + next_chan = first_chan; + max_pwr = ch->max_power; + no_of_parsed_chan = 1; + continue; + } + + if (ch->hw_value == next_chan + 1 && + ch->max_power == max_pwr) { + next_chan++; + no_of_parsed_chan++; + } else { + t = &domain_info->triplet[no_of_triplet]; + t->chans.first_channel = first_chan; + t->chans.num_channels = no_of_parsed_chan; + t->chans.max_power = max_pwr; + no_of_triplet++; + first_chan = (u32) ch->hw_value; + next_chan = first_chan; + max_pwr = ch->max_power; + no_of_parsed_chan = 1; + } + } + + if (flag) { + t = &domain_info->triplet[no_of_triplet]; + t->chans.first_channel = first_chan; + t->chans.num_channels = no_of_parsed_chan; + t->chans.max_power = max_pwr; + no_of_triplet++; + } + + domain_info->no_of_triplet = no_of_triplet; + /* Send cmd to FW to set domain info */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11D_DOMAIN_INFO, + HostCmd_ACT_GEN_SET, 0, NULL, NULL); + if (ret) + wiphy_err(wiphy, "11D: setting domain info in FW\n"); + + return ret; +} + +/* + * CFG802.11 regulatory domain callback function. + * + * This function is called when the regulatory domain is changed due to the + * following reasons - + * - Set by driver + * - Set by system core + * - Set by user + * - Set bt Country IE + */ +static int mwifiex_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *request) +{ + struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + + wiphy_dbg(wiphy, "info: cfg80211 regulatory domain callback for domain" + " %c%c\n", request->alpha2[0], request->alpha2[1]); + + memcpy(priv->country_code, request->alpha2, sizeof(request->alpha2)); + + switch (request->initiator) { + case NL80211_REGDOM_SET_BY_DRIVER: + case NL80211_REGDOM_SET_BY_CORE: + case NL80211_REGDOM_SET_BY_USER: + break; + /* Todo: apply driver specific changes in channel flags based + on the request initiator if necessary. */ + case NL80211_REGDOM_SET_BY_COUNTRY_IE: + break; + } + mwifiex_send_domain_info_cmd_fw(wiphy); + + return 0; +} + +/* + * This function sets the RF channel. + * + * This function creates multiple IOCTL requests, populates them accordingly + * and issues them to set the band/channel and frequency. + */ +static int +mwifiex_set_rf_channel(struct mwifiex_private *priv, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type) +{ + struct mwifiex_chan_freq_power cfp; + int ret = 0; + int status = 0; + struct mwifiex_ds_band_cfg band_cfg; + u32 config_bands = 0; + struct wiphy *wiphy = priv->wdev->wiphy; + + if (chan) { + memset(&band_cfg, 0, sizeof(band_cfg)); + /* Set appropriate bands */ + if (chan->band == IEEE80211_BAND_2GHZ) + config_bands = BAND_B | BAND_G | BAND_GN; + else + config_bands = BAND_AN | BAND_A; + if (priv->bss_mode == NL80211_IFTYPE_STATION + || priv->bss_mode == NL80211_IFTYPE_UNSPECIFIED) { + band_cfg.config_bands = config_bands; + } else if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { + band_cfg.config_bands = config_bands; + band_cfg.adhoc_start_band = config_bands; + } + /* Set channel offset */ + band_cfg.sec_chan_offset = + mwifiex_cfg80211_channel_type_to_mwifiex_channels + (channel_type); + status = mwifiex_radio_ioctl_band_cfg(priv, HostCmd_ACT_GEN_SET, + &band_cfg); + + if (status) + return -EFAULT; + mwifiex_send_domain_info_cmd_fw(wiphy); + } + + wiphy_dbg(wiphy, "info: setting band %d, channel offset %d and " + "mode %d\n", config_bands, band_cfg.sec_chan_offset, + priv->bss_mode); + if (!chan) + return ret; + + memset(&cfp, 0, sizeof(cfp)); + cfp.freq = chan->center_freq; + /* Convert frequency to channel */ + cfp.channel = ieee80211_frequency_to_channel(chan->center_freq); + + status = mwifiex_bss_ioctl_channel(priv, HostCmd_ACT_GEN_SET, &cfp); + if (status) + return -EFAULT; + + ret = mwifiex_drv_change_adhoc_chan(priv, cfp.channel); + + return ret; +} + +/* + * CFG802.11 operation handler to set channel. + * + * This function can only be used when station is not connected. + */ +static int +mwifiex_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type) +{ + struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + + if (priv->media_connected) { + wiphy_err(wiphy, "This setting is valid only when station " + "is not connected\n"); + return -EINVAL; + } + + return mwifiex_set_rf_channel(priv, chan, channel_type); +} + +/* + * This function sets the fragmentation threshold. + * + * This function creates an IOCTL request, populates it accordingly + * and issues an IOCTL. + * + * The fragmentation threshold value must lies between MWIFIEX_FRAG_MIN_VALUE + * and MWIFIEX_FRAG_MAX_VALUE. + */ +static int +mwifiex_set_frag(struct mwifiex_private *priv, u32 frag_thr) +{ + int ret = 0; + int status = 0; + struct mwifiex_wait_queue *wait = NULL; + u8 wait_option = MWIFIEX_IOCTL_WAIT; + + if (frag_thr < MWIFIEX_FRAG_MIN_VALUE + || frag_thr > MWIFIEX_FRAG_MAX_VALUE) + return -EINVAL; + + wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); + if (!wait) + return -ENOMEM; + + status = mwifiex_snmp_mib_ioctl(priv, wait, FRAG_THRESH_I, + HostCmd_ACT_GEN_SET, &frag_thr); + + if (mwifiex_request_ioctl(priv, wait, status, wait_option)) + ret = -EFAULT; + + kfree(wait); + return ret; +} + +/* + * This function sets the RTS threshold. + * + * This function creates an IOCTL request, populates it accordingly + * and issues an IOCTL. + */ +static int +mwifiex_set_rts(struct mwifiex_private *priv, u32 rts_thr) +{ + int ret = 0; + struct mwifiex_wait_queue *wait = NULL; + int status = 0; + u8 wait_option = MWIFIEX_IOCTL_WAIT; + + if (rts_thr < MWIFIEX_RTS_MIN_VALUE || rts_thr > MWIFIEX_RTS_MAX_VALUE) + rts_thr = MWIFIEX_RTS_MAX_VALUE; + + wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); + if (!wait) + return -ENOMEM; + + status = mwifiex_snmp_mib_ioctl(priv, wait, RTS_THRESH_I, + HostCmd_ACT_GEN_SET, &rts_thr); + + if (mwifiex_request_ioctl(priv, wait, status, wait_option)) + ret = -EFAULT; + + kfree(wait); + return ret; +} + +/* + * CFG802.11 operation handler to set wiphy parameters. + * + * This function can be used to set the RTS threshold and the + * Fragmentation threshold of the driver. + */ +static int +mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) +{ + struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + + int ret = 0; + + if (changed & WIPHY_PARAM_RTS_THRESHOLD) + ret = mwifiex_set_rts(priv, wiphy->rts_threshold); + + if (changed & WIPHY_PARAM_FRAG_THRESHOLD) + ret = mwifiex_set_frag(priv, wiphy->frag_threshold); + + return ret; +} + +/* + * CFG802.11 operation handler to change interface type. + */ +static int +mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, + struct net_device *dev, + enum nl80211_iftype type, u32 *flags, + struct vif_params *params) +{ + int ret = 0; + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + struct mwifiex_wait_queue *wait = NULL; + + if (priv->bss_mode == type) { + wiphy_warn(wiphy, "already set to required type\n"); + return 0; + } + + priv->bss_mode = type; + + switch (type) { + case NL80211_IFTYPE_ADHOC: + dev->ieee80211_ptr->iftype = NL80211_IFTYPE_ADHOC; + wiphy_dbg(wiphy, "info: setting interface type to adhoc\n"); + break; + case NL80211_IFTYPE_STATION: + dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION; + wiphy_dbg(wiphy, "info: setting interface type to managed\n"); + break; + case NL80211_IFTYPE_UNSPECIFIED: + dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION; + wiphy_dbg(wiphy, "info: setting interface type to auto\n"); + return 0; + default: + wiphy_err(wiphy, "unknown interface type: %d\n", type); + return -EINVAL; + } + + wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT); + if (!wait) + return -ENOMEM; + + mwifiex_deauthenticate(priv, wait, NULL); + + priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM; + + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_SET_BSS_MODE, + HostCmd_ACT_GEN_SET, 0, wait, NULL); + if (!ret) + ret = -EINPROGRESS; + + ret = mwifiex_request_ioctl(priv, wait, ret, MWIFIEX_IOCTL_WAIT); + if (ret) + ret = -EFAULT; + + kfree(wait); + return ret; +} + +/* + * This function dumps the station information on a buffer. + * + * The following information are shown - + * - Total bytes transmitted + * - Total bytes received + * - Total packets transmitted + * - Total packets received + * - Signal quality level + * - Transmission rate + */ +static int +mwifiex_dump_station_info(struct mwifiex_private *priv, + struct station_info *sinfo) +{ + struct mwifiex_ds_get_signal signal; + struct mwifiex_rate_cfg rate; + int ret = 0; + + sinfo->filled = STATION_INFO_RX_BYTES | STATION_INFO_TX_BYTES | + STATION_INFO_RX_PACKETS | + STATION_INFO_TX_PACKETS + | STATION_INFO_SIGNAL | STATION_INFO_TX_BITRATE; + + /* Get signal information from the firmware */ + memset(&signal, 0, sizeof(struct mwifiex_ds_get_signal)); + if (mwifiex_get_signal_info(priv, MWIFIEX_IOCTL_WAIT, &signal)) { + dev_err(priv->adapter->dev, "getting signal information\n"); + ret = -EFAULT; + } + + if (mwifiex_drv_get_data_rate(priv, &rate)) { + dev_err(priv->adapter->dev, "getting data rate\n"); + ret = -EFAULT; + } + + sinfo->rx_bytes = priv->stats.rx_bytes; + sinfo->tx_bytes = priv->stats.tx_bytes; + sinfo->rx_packets = priv->stats.rx_packets; + sinfo->tx_packets = priv->stats.tx_packets; + sinfo->signal = priv->w_stats.qual.level; + sinfo->txrate.legacy = rate.rate; + + return ret; +} + +/* + * CFG802.11 operation handler to get station information. + * + * This function only works in connected mode, and dumps the + * requested station information, if available. + */ +static int +mwifiex_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, + u8 *mac, struct station_info *sinfo) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + int ret = 0; + + mwifiex_dump_station_info(priv, sinfo); + + if (!priv->media_connected) + return -ENOENT; + if (memcmp(mac, priv->cfg_bssid, ETH_ALEN)) + return -ENOENT; + + + ret = mwifiex_dump_station_info(priv, sinfo); + + return ret; +} + +/* Supported rates to be advertised to the cfg80211 */ + +static struct ieee80211_rate mwifiex_rates[] = { + {.bitrate = 10, .hw_value = 2, }, + {.bitrate = 20, .hw_value = 4, }, + {.bitrate = 55, .hw_value = 11, }, + {.bitrate = 110, .hw_value = 22, }, + {.bitrate = 220, .hw_value = 44, }, + {.bitrate = 60, .hw_value = 12, }, + {.bitrate = 90, .hw_value = 18, }, + {.bitrate = 120, .hw_value = 24, }, + {.bitrate = 180, .hw_value = 36, }, + {.bitrate = 240, .hw_value = 48, }, + {.bitrate = 360, .hw_value = 72, }, + {.bitrate = 480, .hw_value = 96, }, + {.bitrate = 540, .hw_value = 108, }, + {.bitrate = 720, .hw_value = 144, }, +}; + +/* Channel definitions to be advertised to cfg80211 */ + +static struct ieee80211_channel mwifiex_channels_2ghz[] = { + {.center_freq = 2412, .hw_value = 1, }, + {.center_freq = 2417, .hw_value = 2, }, + {.center_freq = 2422, .hw_value = 3, }, + {.center_freq = 2427, .hw_value = 4, }, + {.center_freq = 2432, .hw_value = 5, }, + {.center_freq = 2437, .hw_value = 6, }, + {.center_freq = 2442, .hw_value = 7, }, + {.center_freq = 2447, .hw_value = 8, }, + {.center_freq = 2452, .hw_value = 9, }, + {.center_freq = 2457, .hw_value = 10, }, + {.center_freq = 2462, .hw_value = 11, }, + {.center_freq = 2467, .hw_value = 12, }, + {.center_freq = 2472, .hw_value = 13, }, + {.center_freq = 2484, .hw_value = 14, }, +}; + +static struct ieee80211_supported_band mwifiex_band_2ghz = { + .channels = mwifiex_channels_2ghz, + .n_channels = ARRAY_SIZE(mwifiex_channels_2ghz), + .bitrates = mwifiex_rates, + .n_bitrates = 14, +}; + +static struct ieee80211_channel mwifiex_channels_5ghz[] = { + {.center_freq = 5040, .hw_value = 8, }, + {.center_freq = 5060, .hw_value = 12, }, + {.center_freq = 5080, .hw_value = 16, }, + {.center_freq = 5170, .hw_value = 34, }, + {.center_freq = 5190, .hw_value = 38, }, + {.center_freq = 5210, .hw_value = 42, }, + {.center_freq = 5230, .hw_value = 46, }, + {.center_freq = 5180, .hw_value = 36, }, + {.center_freq = 5200, .hw_value = 40, }, + {.center_freq = 5220, .hw_value = 44, }, + {.center_freq = 5240, .hw_value = 48, }, + {.center_freq = 5260, .hw_value = 52, }, + {.center_freq = 5280, .hw_value = 56, }, + {.center_freq = 5300, .hw_value = 60, }, + {.center_freq = 5320, .hw_value = 64, }, + {.center_freq = 5500, .hw_value = 100, }, + {.center_freq = 5520, .hw_value = 104, }, + {.center_freq = 5540, .hw_value = 108, }, + {.center_freq = 5560, .hw_value = 112, }, + {.center_freq = 5580, .hw_value = 116, }, + {.center_freq = 5600, .hw_value = 120, }, + {.center_freq = 5620, .hw_value = 124, }, + {.center_freq = 5640, .hw_value = 128, }, + {.center_freq = 5660, .hw_value = 132, }, + {.center_freq = 5680, .hw_value = 136, }, + {.center_freq = 5700, .hw_value = 140, }, + {.center_freq = 5745, .hw_value = 149, }, + {.center_freq = 5765, .hw_value = 153, }, + {.center_freq = 5785, .hw_value = 157, }, + {.center_freq = 5805, .hw_value = 161, }, + {.center_freq = 5825, .hw_value = 165, }, +}; + +static struct ieee80211_supported_band mwifiex_band_5ghz = { + .channels = mwifiex_channels_5ghz, + .n_channels = ARRAY_SIZE(mwifiex_channels_5ghz), + .bitrates = mwifiex_rates - 4, + .n_bitrates = ARRAY_SIZE(mwifiex_rates) + 4, +}; + + +/* Supported crypto cipher suits to be advertised to cfg80211 */ + +static const u32 mwifiex_cipher_suites[] = { + WLAN_CIPHER_SUITE_WEP40, + WLAN_CIPHER_SUITE_WEP104, + WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_CCMP, +}; + +/* + * CFG802.11 operation handler for disconnection request. + * + * This function does not work when there is already a disconnection + * procedure going on. + */ +static int +mwifiex_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, + u16 reason_code) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + + if (priv->disconnect) + return -EBUSY; + + priv->disconnect = 1; + if (mwifiex_disconnect(priv, MWIFIEX_IOCTL_WAIT, NULL)) + return -EFAULT; + + wiphy_dbg(wiphy, "info: successfully disconnected from %pM:" + " reason code %d\n", priv->cfg_bssid, reason_code); + + queue_work(priv->workqueue, &priv->cfg_workqueue); + + return 0; +} + +/* + * This function informs the CFG802.11 subsystem of a new IBSS. + * + * The following information are sent to the CFG802.11 subsystem + * to register the new IBSS. If we do not register the new IBSS, + * a kernel panic will result. + * - SSID + * - SSID length + * - BSSID + * - Channel + */ +static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv) +{ + int ret = 0; + struct ieee80211_channel *chan; + struct mwifiex_bss_info bss_info; + int ie_len = 0; + u8 ie_buf[IEEE80211_MAX_SSID_LEN + sizeof(struct ieee_types_header)]; + + ret = mwifiex_get_bss_info(priv, &bss_info); + if (ret) + return ret; + + ie_buf[0] = WLAN_EID_SSID; + ie_buf[1] = bss_info.ssid.ssid_len; + + memcpy(&ie_buf[sizeof(struct ieee_types_header)], + &bss_info.ssid.ssid, + bss_info.ssid.ssid_len); + ie_len = ie_buf[1] + sizeof(struct ieee_types_header); + + chan = __ieee80211_get_channel(priv->wdev->wiphy, + ieee80211_channel_to_frequency(bss_info.bss_chan, + priv->curr_bss_params.band)); + + cfg80211_inform_bss(priv->wdev->wiphy, chan, + bss_info.bssid, 0, WLAN_CAPABILITY_IBSS, + 0, ie_buf, ie_len, 0, GFP_KERNEL); + memcpy(priv->cfg_bssid, bss_info.bssid, ETH_ALEN); + + return ret; +} + +/* + * This function informs the CFG802.11 subsystem of a new BSS connection. + * + * The following information are sent to the CFG802.11 subsystem + * to register the new BSS connection. If we do not register the new BSS, + * a kernel panic will result. + * - MAC address + * - Capabilities + * - Beacon period + * - RSSI value + * - Channel + * - Supported rates IE + * - Extended capabilities IE + * - DS parameter set IE + * - HT Capability IE + * - Vendor Specific IE (221) + * - WPA IE + * - RSN IE + */ +static int mwifiex_inform_bss_from_scan_result(struct mwifiex_private *priv, + struct mwifiex_802_11_ssid *ssid) +{ + struct mwifiex_scan_resp scan_resp; + struct mwifiex_bssdescriptor *scan_table; + int i, j; + struct ieee80211_channel *chan; + u8 *ie, *tmp, *ie_buf; + u32 ie_len; + u64 ts = 0; + u8 *beacon; + int beacon_size; + u8 element_id, element_len; + + memset(&scan_resp, 0, sizeof(scan_resp)); + if (mwifiex_get_scan_table(priv, MWIFIEX_IOCTL_WAIT, &scan_resp)) + return -EFAULT; + +#define MAX_IE_BUF 2048 + ie_buf = kzalloc(MAX_IE_BUF, GFP_KERNEL); + if (!ie_buf) { + dev_err(priv->adapter->dev, "%s: failed to alloc ie_buf\n", + __func__); + return -ENOMEM; + } + + scan_table = (struct mwifiex_bssdescriptor *) scan_resp.scan_table; + for (i = 0; i < scan_resp.num_in_scan_table; i++) { + if (ssid) { + /* Inform specific BSS only */ + if (memcmp(ssid->ssid, scan_table[i].ssid.ssid, + ssid->ssid_len)) + continue; + } + memset(ie_buf, 0, MAX_IE_BUF); + ie_buf[0] = WLAN_EID_SSID; + ie_buf[1] = scan_table[i].ssid.ssid_len; + memcpy(&ie_buf[sizeof(struct ieee_types_header)], + scan_table[i].ssid.ssid, ie_buf[1]); + + ie = ie_buf + ie_buf[1] + sizeof(struct ieee_types_header); + ie_len = ie_buf[1] + sizeof(struct ieee_types_header); + + ie[0] = WLAN_EID_SUPP_RATES; + + for (j = 0; j < sizeof(scan_table[i].supported_rates); j++) { + if (!scan_table[i].supported_rates[j]) + break; + else + ie[j + sizeof(struct ieee_types_header)] = + scan_table[i].supported_rates[j]; + } + + ie[1] = j; + ie_len += ie[1] + sizeof(struct ieee_types_header); + + beacon = scan_table[i].beacon_buf; + beacon_size = scan_table[i].beacon_buf_size; + + /* Skip time stamp, beacon interval and capability */ + + if (beacon) { + beacon += sizeof(scan_table[i].beacon_period) + + sizeof(scan_table[i].time_stamp) + + +sizeof(scan_table[i].cap_info_bitmap); + + beacon_size -= sizeof(scan_table[i].beacon_period) + + sizeof(scan_table[i].time_stamp) + + sizeof(scan_table[i].cap_info_bitmap); + } + + while (beacon_size >= sizeof(struct ieee_types_header)) { + ie = ie_buf + ie_len; + element_id = *beacon; + element_len = *(beacon + 1); + if (beacon_size < (int) element_len + + sizeof(struct ieee_types_header)) { + dev_err(priv->adapter->dev, "%s: in processing" + " IE, bytes left < IE length\n", + __func__); + break; + } + switch (element_id) { + case WLAN_EID_EXT_CAPABILITY: + case WLAN_EID_DS_PARAMS: + case WLAN_EID_HT_CAPABILITY: + case WLAN_EID_VENDOR_SPECIFIC: + case WLAN_EID_RSN: + case WLAN_EID_BSS_AC_ACCESS_DELAY: + ie[0] = element_id; + ie[1] = element_len; + tmp = (u8 *) beacon; + memcpy(&ie[sizeof(struct ieee_types_header)], + tmp + sizeof(struct ieee_types_header), + element_len); + ie_len += ie[1] + + sizeof(struct ieee_types_header); + break; + default: + break; + } + beacon += element_len + + sizeof(struct ieee_types_header); + beacon_size -= element_len + + sizeof(struct ieee_types_header); + } + chan = ieee80211_get_channel(priv->wdev->wiphy, + scan_table[i].freq); + cfg80211_inform_bss(priv->wdev->wiphy, chan, + scan_table[i].mac_address, + ts, scan_table[i].cap_info_bitmap, + scan_table[i].beacon_period, + ie_buf, ie_len, + scan_table[i].rssi, GFP_KERNEL); + } + + kfree(ie_buf); + return 0; +} + +/* + * This function connects with a BSS. + * + * This function handles both Infra and Ad-Hoc modes. It also performs + * validity checking on the provided parameters, disconnects from the + * current BSS (if any), sets up the association/scan parameters, + * including security settings, and performs specific SSID scan before + * trying to connect. + * + * For Infra mode, the function returns failure if the specified SSID + * is not found in scan table. However, for Ad-Hoc mode, it can create + * the IBSS if it does not exist. On successful completion in either case, + * the function notifies the CFG802.11 subsystem of the new BSS connection, + * otherwise the kernel will panic. + */ +static int +mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, + u8 *bssid, int mode, struct ieee80211_channel *channel, + struct cfg80211_connect_params *sme, bool privacy) +{ + struct mwifiex_802_11_ssid req_ssid; + struct mwifiex_ssid_bssid ssid_bssid; + int ret = 0; + int auth_type = 0, pairwise_encrypt_mode = 0; + int group_encrypt_mode = 0; + int alg_is_wep = 0; + + memset(&req_ssid, 0, sizeof(struct mwifiex_802_11_ssid)); + memset(&ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid)); + + req_ssid.ssid_len = ssid_len; + if (ssid_len > IEEE80211_MAX_SSID_LEN) { + dev_err(priv->adapter->dev, "invalid SSID - aborting\n"); + return -EINVAL; + } + + memcpy(req_ssid.ssid, ssid, ssid_len); + if (!req_ssid.ssid_len || req_ssid.ssid[0] < 0x20) { + dev_err(priv->adapter->dev, "invalid SSID - aborting\n"); + return -EINVAL; + } + + /* disconnect before try to associate */ + mwifiex_disconnect(priv, MWIFIEX_IOCTL_WAIT, NULL); + + if (channel) + ret = mwifiex_set_rf_channel(priv, channel, + mwifiex_channels_to_cfg80211_channel_type + (priv->adapter->chan_offset)); + + ret = mwifiex_set_encode(priv, NULL, 0, 0, 1); /* Disable keys */ + + if (mode == NL80211_IFTYPE_ADHOC) { + /* "privacy" is set only for ad-hoc mode */ + if (privacy) { + /* + * Keep WLAN_CIPHER_SUITE_WEP104 for now so that + * the firmware can find a matching network from the + * scan. The cfg80211 does not give us the encryption + * mode at this stage so just setting it to WEP here. + */ + priv->sec_info.encryption_mode = + WLAN_CIPHER_SUITE_WEP104; + priv->sec_info.authentication_mode = + NL80211_AUTHTYPE_OPEN_SYSTEM; + } + + goto done; + } + + /* Now handle infra mode. "sme" is valid for infra mode only */ + if (sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC + || sme->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) + auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM; + else if (sme->auth_type == NL80211_AUTHTYPE_SHARED_KEY) + auth_type = NL80211_AUTHTYPE_SHARED_KEY; + + if (sme->crypto.n_ciphers_pairwise) { + priv->sec_info.encryption_mode = + sme->crypto.ciphers_pairwise[0]; + priv->sec_info.authentication_mode = auth_type; + } + + if (sme->crypto.cipher_group) { + priv->sec_info.encryption_mode = sme->crypto.cipher_group; + priv->sec_info.authentication_mode = auth_type; + } + if (sme->ie) + ret = mwifiex_set_gen_ie(priv, sme->ie, sme->ie_len); + + if (sme->key) { + alg_is_wep = mwifiex_is_alg_wep(pairwise_encrypt_mode) + | mwifiex_is_alg_wep(group_encrypt_mode); + if (alg_is_wep) { + dev_dbg(priv->adapter->dev, + "info: setting wep encryption" + " with key len %d\n", sme->key_len); + ret = mwifiex_set_encode(priv, sme->key, sme->key_len, + sme->key_idx, 0); + } + } +done: + /* Do specific SSID scanning */ + if (mwifiex_request_scan(priv, MWIFIEX_IOCTL_WAIT, &req_ssid)) { + dev_err(priv->adapter->dev, "scan error\n"); + return -EFAULT; + } + + + memcpy(&ssid_bssid.ssid, &req_ssid, sizeof(struct mwifiex_802_11_ssid)); + + if (mode != NL80211_IFTYPE_ADHOC) { + if (mwifiex_find_best_bss(priv, MWIFIEX_IOCTL_WAIT, + &ssid_bssid)) + return -EFAULT; + /* Inform the BSS information to kernel, otherwise + * kernel will give a panic after successful assoc */ + if (mwifiex_inform_bss_from_scan_result(priv, &req_ssid)) + return -EFAULT; + } + + dev_dbg(priv->adapter->dev, "info: trying to associate to %s and bssid %pM\n", + (char *) req_ssid.ssid, ssid_bssid.bssid); + + memcpy(&priv->cfg_bssid, ssid_bssid.bssid, 6); + + /* Connect to BSS by ESSID */ + memset(&ssid_bssid.bssid, 0, ETH_ALEN); + + if (mwifiex_bss_start(priv, MWIFIEX_IOCTL_WAIT, &ssid_bssid)) + return -EFAULT; + + if (mode == NL80211_IFTYPE_ADHOC) { + /* Inform the BSS information to kernel, otherwise + * kernel will give a panic after successful assoc */ + if (mwifiex_cfg80211_inform_ibss_bss(priv)) + return -EFAULT; + } + + return ret; +} + +/* + * CFG802.11 operation handler for association request. + * + * This function does not work when the current mode is set to Ad-Hoc, or + * when there is already an association procedure going on. The given BSS + * information is used to associate. + */ +static int +mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_connect_params *sme) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + int ret = 0; + + if (priv->assoc_request) + return -EBUSY; + + if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { + wiphy_err(wiphy, "received infra assoc request " + "when station is in ibss mode\n"); + goto done; + } + + priv->assoc_request = 1; + + wiphy_dbg(wiphy, "info: Trying to associate to %s and bssid %pM\n", + (char *) sme->ssid, sme->bssid); + + ret = mwifiex_cfg80211_assoc(priv, sme->ssid_len, sme->ssid, sme->bssid, + priv->bss_mode, sme->channel, sme, 0); + +done: + priv->assoc_result = ret; + queue_work(priv->workqueue, &priv->cfg_workqueue); + return ret; +} + +/* + * CFG802.11 operation handler to join an IBSS. + * + * This function does not work in any mode other than Ad-Hoc, or if + * a join operation is already in progress. + */ +static int +mwifiex_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ibss_params *params) +{ + struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + int ret = 0; + + if (priv->ibss_join_request) + return -EBUSY; + + if (priv->bss_mode != NL80211_IFTYPE_ADHOC) { + wiphy_err(wiphy, "request to join ibss received " + "when station is not in ibss mode\n"); + goto done; + } + + priv->ibss_join_request = 1; + + wiphy_dbg(wiphy, "info: trying to join to %s and bssid %pM\n", + (char *) params->ssid, params->bssid); + + ret = mwifiex_cfg80211_assoc(priv, params->ssid_len, params->ssid, + params->bssid, priv->bss_mode, + params->channel, NULL, params->privacy); +done: + priv->ibss_join_result = ret; + queue_work(priv->workqueue, &priv->cfg_workqueue); + return ret; +} + +/* + * CFG802.11 operation handler to leave an IBSS. + * + * This function does not work if a leave operation is + * already in progress. + */ +static int +mwifiex_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) +{ + struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + + if (priv->disconnect) + return -EBUSY; + + priv->disconnect = 1; + + wiphy_dbg(wiphy, "info: disconnecting from essid %pM\n", + priv->cfg_bssid); + if (mwifiex_disconnect(priv, MWIFIEX_IOCTL_WAIT, NULL)) + return -EFAULT; + + queue_work(priv->workqueue, &priv->cfg_workqueue); + + return 0; +} + +/* + * CFG802.11 operation handler for scan request. + * + * This function issues a scan request to the firmware based upon + * the user specified scan configuration. On successfull completion, + * it also informs the results. + */ +static int +mwifiex_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_scan_request *request) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + + wiphy_dbg(wiphy, "info: received scan request on %s\n", dev->name); + + if (priv->scan_request && priv->scan_request != request) + return -EBUSY; + + priv->scan_request = request; + + queue_work(priv->workqueue, &priv->cfg_workqueue); + return 0; +} + +/* + * This function sets up the CFG802.11 specific HT capability fields + * with default values. + * + * The following default values are set - + * - HT Supported = True + * - Maximum AMPDU length factor = 0x3 + * - Minimum AMPDU spacing = 0x6 + * - HT Capabilities map = IEEE80211_HT_CAP_SUP_WIDTH_20_40 (0x0002) + * - MCS information, Rx mask = 0xff + * - MCD information, Tx parameters = IEEE80211_HT_MCS_TX_DEFINED (0x01) + */ +static void +mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info, + struct mwifiex_private *priv) +{ + int rx_mcs_supp; + struct ieee80211_mcs_info mcs_set; + u8 *mcs = (u8 *)&mcs_set; + struct mwifiex_adapter *adapter = priv->adapter; + + ht_info->ht_supported = true; + ht_info->ampdu_factor = 0x3; + ht_info->ampdu_density = 0x6; + + memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); + ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40; + + rx_mcs_supp = GET_RXMCSSUPP(priv->adapter->hw_dev_mcs_support); + /* Set MCS for 1x1 */ + memset(mcs, 0xff, rx_mcs_supp); + /* Clear all the other values */ + memset(&mcs[rx_mcs_supp], 0, + sizeof(struct ieee80211_mcs_info) - rx_mcs_supp); + if (priv->bss_mode == NL80211_IFTYPE_STATION || + ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap)) + /* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */ + SETHT_MCS32(mcs_set.rx_mask); + + memcpy((u8 *) &ht_info->mcs, mcs, sizeof(struct ieee80211_mcs_info)); + + ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; +} + +/* station cfg80211 operations */ +static struct cfg80211_ops mwifiex_cfg80211_ops = { + .change_virtual_intf = mwifiex_cfg80211_change_virtual_intf, + .scan = mwifiex_cfg80211_scan, + .connect = mwifiex_cfg80211_connect, + .disconnect = mwifiex_cfg80211_disconnect, + .get_station = mwifiex_cfg80211_get_station, + .set_wiphy_params = mwifiex_cfg80211_set_wiphy_params, + .set_channel = mwifiex_cfg80211_set_channel, + .join_ibss = mwifiex_cfg80211_join_ibss, + .leave_ibss = mwifiex_cfg80211_leave_ibss, + .add_key = mwifiex_cfg80211_add_key, + .del_key = mwifiex_cfg80211_del_key, + .set_default_key = mwifiex_cfg80211_set_default_key, + .set_power_mgmt = mwifiex_cfg80211_set_power_mgmt, + .set_tx_power = mwifiex_cfg80211_set_tx_power, +}; + +/* + * This function registers the device with CFG802.11 subsystem. + * + * The function creates the wireless device/wiphy, populates it with + * default parameters and handler function pointers, and finally + * registers the device. + */ +int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac, + struct mwifiex_private *priv) +{ + int ret = 0; + void *wdev_priv = NULL; + struct wireless_dev *wdev; + + wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); + if (!wdev) { + dev_err(priv->adapter->dev, "%s: allocating wireless device\n", + __func__); + return -ENOMEM; + } + wdev->wiphy = + wiphy_new(&mwifiex_cfg80211_ops, + sizeof(struct mwifiex_private *)); + if (!wdev->wiphy) + return -ENOMEM; + wdev->iftype = NL80211_IFTYPE_STATION; + wdev->wiphy->max_scan_ssids = 10; + wdev->wiphy->interface_modes = + BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); + wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &mwifiex_band_2ghz; + wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &mwifiex_band_5ghz; + + /* Initialize cipher suits */ + wdev->wiphy->cipher_suites = mwifiex_cipher_suites; + wdev->wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites); + + /* Initialize parameters for 2GHz band */ + + mwifiex_setup_ht_caps(&wdev->wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap, + priv); + mwifiex_setup_ht_caps(&wdev->wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap, + priv); + + memcpy(wdev->wiphy->perm_addr, mac, 6); + wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + + /* We are using custom domains */ + wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; + + wdev->wiphy->reg_notifier = mwifiex_reg_notifier; + + /* Set struct mwifiex_private pointer in wiphy_priv */ + wdev_priv = wiphy_priv(wdev->wiphy); + + *(unsigned long *) wdev_priv = (unsigned long) priv; + + ret = wiphy_register(wdev->wiphy); + if (ret < 0) { + dev_err(priv->adapter->dev, "%s: registering cfg80211 device\n", + __func__); + wiphy_free(wdev->wiphy); + return ret; + } else { + dev_dbg(priv->adapter->dev, + "info: successfully registered wiphy device\n"); + } + + dev_net_set(dev, wiphy_net(wdev->wiphy)); + dev->ieee80211_ptr = wdev; + memcpy(dev->dev_addr, wdev->wiphy->perm_addr, 6); + memcpy(dev->perm_addr, wdev->wiphy->perm_addr, 6); + SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy)); + priv->wdev = wdev; + + dev->flags |= IFF_BROADCAST | IFF_MULTICAST; + dev->watchdog_timeo = MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT; + dev->hard_header_len += MWIFIEX_MIN_DATA_HEADER_LEN; + + return ret; +} + +/* + * This function handles the result of different pending network operations. + * + * The following operations are handled and CFG802.11 subsystem is + * notified accordingly - + * - Scan request completion + * - Association request completion + * - IBSS join request completion + * - Disconnect request completion + */ +void +mwifiex_cfg80211_results(struct work_struct *work) +{ + struct mwifiex_private *priv = + container_of(work, struct mwifiex_private, cfg_workqueue); + struct mwifiex_user_scan_cfg *scan_req; + int ret = 0, i; + struct ieee80211_channel *chan; + + if (priv->scan_request) { + scan_req = kzalloc(sizeof(struct mwifiex_user_scan_cfg), + GFP_KERNEL); + if (!scan_req) { + dev_err(priv->adapter->dev, "failed to alloc " + "scan_req\n"); + return; + } + for (i = 0; i < priv->scan_request->n_ssids; i++) { + memcpy(scan_req->ssid_list[i].ssid, + priv->scan_request->ssids[i].ssid, + priv->scan_request->ssids[i].ssid_len); + scan_req->ssid_list[i].max_len = + priv->scan_request->ssids[i].ssid_len; + } + for (i = 0; i < priv->scan_request->n_channels; i++) { + chan = priv->scan_request->channels[i]; + scan_req->chan_list[i].chan_number = chan->hw_value; + scan_req->chan_list[i].radio_type = chan->band; + if (chan->flags & IEEE80211_CHAN_DISABLED) + scan_req->chan_list[i].scan_type = + MWIFIEX_SCAN_TYPE_PASSIVE; + else + scan_req->chan_list[i].scan_type = + MWIFIEX_SCAN_TYPE_ACTIVE; + scan_req->chan_list[i].scan_time = 0; + } + if (mwifiex_set_user_scan_ioctl(priv, scan_req)) { + ret = -EFAULT; + goto done; + } + if (mwifiex_inform_bss_from_scan_result(priv, NULL)) + ret = -EFAULT; +done: + priv->scan_result_status = ret; + dev_dbg(priv->adapter->dev, "info: %s: sending scan results\n", + __func__); + cfg80211_scan_done(priv->scan_request, + (priv->scan_result_status < 0)); + priv->scan_request = NULL; + kfree(scan_req); + } + + if (priv->assoc_request) { + if (!priv->assoc_result) { + cfg80211_connect_result(priv->netdev, priv->cfg_bssid, + NULL, 0, NULL, 0, + WLAN_STATUS_SUCCESS, + GFP_KERNEL); + dev_dbg(priv->adapter->dev, + "info: associated to bssid %pM successfully\n", + priv->cfg_bssid); + } else { + dev_dbg(priv->adapter->dev, + "info: association to bssid %pM failed\n", + priv->cfg_bssid); + memset(priv->cfg_bssid, 0, ETH_ALEN); + } + priv->assoc_request = 0; + priv->assoc_result = 0; + } + + if (priv->ibss_join_request) { + if (!priv->ibss_join_result) { + cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid, + GFP_KERNEL); + dev_dbg(priv->adapter->dev, + "info: joined/created adhoc network with bssid" + " %pM successfully\n", priv->cfg_bssid); + } else { + dev_dbg(priv->adapter->dev, + "info: failed creating/joining adhoc network\n"); + } + priv->ibss_join_request = 0; + priv->ibss_join_result = 0; + } + + if (priv->disconnect) { + memset(priv->cfg_bssid, 0, ETH_ALEN); + priv->disconnect = 0; + } + + return; +} diff --git a/drivers/net/wireless/mwifiex/cfg80211.h b/drivers/net/wireless/mwifiex/cfg80211.h new file mode 100644 index 000000000000..c4db8f36aa16 --- /dev/null +++ b/drivers/net/wireless/mwifiex/cfg80211.h @@ -0,0 +1,31 @@ +/* + * Marvell Wireless LAN device driver: CFG80211 + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#ifndef __MWIFIEX_CFG80211__ +#define __MWIFIEX_CFG80211__ + +#include <net/cfg80211.h> + +#include "main.h" + +int mwifiex_register_cfg80211(struct net_device *, u8 *, + struct mwifiex_private *); + +void mwifiex_cfg80211_results(struct work_struct *work); +#endif diff --git a/drivers/net/wireless/mwifiex/cfp.c b/drivers/net/wireless/mwifiex/cfp.c new file mode 100644 index 000000000000..07187a405fee --- /dev/null +++ b/drivers/net/wireless/mwifiex/cfp.c @@ -0,0 +1,367 @@ +/* + * Marvell Wireless LAN device driver: Channel, Frequence and Power + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "cfg80211.h" + +/* 100mW */ +#define MWIFIEX_TX_PWR_DEFAULT 20 +/* 100mW */ +#define MWIFIEX_TX_PWR_US_DEFAULT 20 +/* 50mW */ +#define MWIFIEX_TX_PWR_JP_DEFAULT 16 +/* 100mW */ +#define MWIFIEX_TX_PWR_FR_100MW 20 +/* 10mW */ +#define MWIFIEX_TX_PWR_FR_10MW 10 +/* 100mW */ +#define MWIFIEX_TX_PWR_EMEA_DEFAULT 20 + +static u8 adhoc_rates_b[B_SUPPORTED_RATES] = { 0x82, 0x84, 0x8b, 0x96, 0 }; + +static u8 adhoc_rates_g[G_SUPPORTED_RATES] = { 0x8c, 0x12, 0x98, 0x24, + 0xb0, 0x48, 0x60, 0x6c, 0 }; + +static u8 adhoc_rates_bg[BG_SUPPORTED_RATES] = { 0x82, 0x84, 0x8b, 0x96, + 0x0c, 0x12, 0x18, 0x24, + 0x30, 0x48, 0x60, 0x6c, 0 }; + +static u8 adhoc_rates_a[A_SUPPORTED_RATES] = { 0x8c, 0x12, 0x98, 0x24, + 0xb0, 0x48, 0x60, 0x6c, 0 }; +u8 supported_rates_a[A_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24, + 0xb0, 0x48, 0x60, 0x6c, 0 }; +static u16 mwifiex_data_rates[MWIFIEX_SUPPORTED_RATES_EXT] = { 0x02, 0x04, + 0x0B, 0x16, 0x00, 0x0C, 0x12, 0x18, + 0x24, 0x30, 0x48, 0x60, 0x6C, 0x90, + 0x0D, 0x1A, 0x27, 0x34, 0x4E, 0x68, + 0x75, 0x82, 0x0C, 0x1B, 0x36, 0x51, + 0x6C, 0xA2, 0xD8, 0xF3, 0x10E, 0x00 }; + +u8 supported_rates_b[B_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x16, 0 }; + +u8 supported_rates_g[G_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24, + 0x30, 0x48, 0x60, 0x6c, 0 }; + +u8 supported_rates_bg[BG_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x0c, + 0x12, 0x16, 0x18, 0x24, 0x30, 0x48, + 0x60, 0x6c, 0 }; + +u16 region_code_index[MWIFIEX_MAX_REGION_CODE] = { 0x10, 0x20, 0x30, + 0x32, 0x40, 0x41, 0xff }; + +u8 supported_rates_n[N_SUPPORTED_RATES] = { 0x02, 0x04, 0 }; + +/* + * This function maps an index in supported rates table into + * the corresponding data rate. + */ +u32 mwifiex_index_to_data_rate(struct mwifiex_adapter *adapter, u8 index, + u8 ht_info) +{ + u16 mcs_rate[4][8] = { + {0x1b, 0x36, 0x51, 0x6c, 0xa2, 0xd8, 0xf3, 0x10e} + , /* LG 40M */ + {0x1e, 0x3c, 0x5a, 0x78, 0xb4, 0xf0, 0x10e, 0x12c} + , /* SG 40M */ + {0x0d, 0x1a, 0x27, 0x34, 0x4e, 0x68, 0x75, 0x82} + , /* LG 20M */ + {0x0e, 0x1c, 0x2b, 0x39, 0x56, 0x73, 0x82, 0x90} + }; /* SG 20M */ + + u32 rate; + + if (ht_info & BIT(0)) { + if (index == MWIFIEX_RATE_BITMAP_MCS0) { + if (ht_info & BIT(2)) + rate = 0x0D; /* MCS 32 SGI rate */ + else + rate = 0x0C; /* MCS 32 LGI rate */ + } else if (index < 8) { + if (ht_info & BIT(1)) { + if (ht_info & BIT(2)) + /* SGI, 40M */ + rate = mcs_rate[1][index]; + else + /* LGI, 40M */ + rate = mcs_rate[0][index]; + } else { + if (ht_info & BIT(2)) + /* SGI, 20M */ + rate = mcs_rate[3][index]; + else + /* LGI, 20M */ + rate = mcs_rate[2][index]; + } + } else + rate = mwifiex_data_rates[0]; + } else { + if (index >= MWIFIEX_SUPPORTED_RATES_EXT) + index = 0; + rate = mwifiex_data_rates[index]; + } + return rate; +} + +/* + * This function maps a data rate value into corresponding index in supported + * rates table. + */ +u8 mwifiex_data_rate_to_index(struct mwifiex_adapter *adapter, u32 rate) +{ + u16 *ptr; + + if (rate) { + ptr = memchr(mwifiex_data_rates, rate, + sizeof(mwifiex_data_rates)); + if (ptr) + return (u8) (ptr - mwifiex_data_rates); + } + return 0; +} + +/* + * This function returns the current active data rates. + * + * The result may vary depending upon connection status. + */ +u32 mwifiex_get_active_data_rates(struct mwifiex_private *priv, u8 *rates) +{ + u32 k; + + if (!priv->media_connected) + k = mwifiex_get_supported_rates(priv, rates); + else + k = mwifiex_copy_rates(rates, 0, + priv->curr_bss_params.data_rates, + priv->curr_bss_params.num_of_rates); + + return k; +} + +/* + * This function locates the Channel-Frequency-Power triplet based upon + * band and channel parameters. + */ +struct mwifiex_chan_freq_power * +mwifiex_get_cfp_by_band_and_channel_from_cfg80211(struct mwifiex_private + *priv, u8 band, u16 channel) +{ + struct mwifiex_chan_freq_power *cfp = NULL; + struct ieee80211_supported_band *sband; + struct ieee80211_channel *ch; + int i; + + if (mwifiex_band_to_radio_type(band) == HostCmd_SCAN_RADIO_TYPE_BG) + sband = priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ]; + else + sband = priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ]; + + if (!sband) { + dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d" + " & channel %d\n", __func__, band, channel); + return cfp; + } + + for (i = 0; i < sband->n_channels; i++) { + ch = &sband->channels[i]; + if (((ch->hw_value == channel) || + (channel == FIRST_VALID_CHANNEL)) + && !(ch->flags & IEEE80211_CHAN_DISABLED)) { + priv->cfp.channel = channel; + priv->cfp.freq = ch->center_freq; + priv->cfp.max_tx_power = ch->max_power; + cfp = &priv->cfp; + break; + } + } + if (i == sband->n_channels) + dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d" + " & channel %d\n", __func__, band, channel); + + return cfp; +} + +/* + * This function locates the Channel-Frequency-Power triplet based upon + * band and frequency parameters. + */ +struct mwifiex_chan_freq_power * +mwifiex_get_cfp_by_band_and_freq_from_cfg80211(struct mwifiex_private *priv, + u8 band, u32 freq) +{ + struct mwifiex_chan_freq_power *cfp = NULL; + struct ieee80211_supported_band *sband; + struct ieee80211_channel *ch; + int i; + + if (mwifiex_band_to_radio_type(band) == HostCmd_SCAN_RADIO_TYPE_BG) + sband = priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ]; + else + sband = priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ]; + + if (!sband) { + dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d" + " & freq %d\n", __func__, band, freq); + return cfp; + } + + for (i = 0; i < sband->n_channels; i++) { + ch = &sband->channels[i]; + if ((ch->center_freq == freq) && + !(ch->flags & IEEE80211_CHAN_DISABLED)) { + priv->cfp.channel = ch->hw_value; + priv->cfp.freq = freq; + priv->cfp.max_tx_power = ch->max_power; + cfp = &priv->cfp; + break; + } + } + if (i == sband->n_channels) + dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d" + " & freq %d\n", __func__, band, freq); + + return cfp; +} + +/* + * This function checks if the data rate is set to auto. + */ +u8 +mwifiex_is_rate_auto(struct mwifiex_private *priv) +{ + u32 i; + int rate_num = 0; + + for (i = 0; i < ARRAY_SIZE(priv->bitmap_rates); i++) + if (priv->bitmap_rates[i]) + rate_num++; + + if (rate_num > 1) + return true; + else + return false; +} + +/* + * This function converts rate bitmap into rate index. + */ +int +mwifiex_get_rate_index(struct mwifiex_adapter *adapter, u16 *rate_bitmap, + int size) +{ + int i; + + for (i = 0; i < size * 8; i++) + if (rate_bitmap[i / 16] & (1 << (i % 16))) + return i; + + return 0; +} + +/* + * This function gets the supported data rates. + * + * The function works in both Ad-Hoc and infra mode by printing the + * band and returning the data rates. + */ +u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates) +{ + u32 k = 0; + struct mwifiex_adapter *adapter = priv->adapter; + if (priv->bss_mode == NL80211_IFTYPE_STATION) { + switch (adapter->config_bands) { + case BAND_B: + dev_dbg(adapter->dev, "info: infra band=%d " + "supported_rates_b\n", adapter->config_bands); + k = mwifiex_copy_rates(rates, k, supported_rates_b, + sizeof(supported_rates_b)); + break; + case BAND_G: + case BAND_G | BAND_GN: + dev_dbg(adapter->dev, "info: infra band=%d " + "supported_rates_g\n", adapter->config_bands); + k = mwifiex_copy_rates(rates, k, supported_rates_g, + sizeof(supported_rates_g)); + break; + case BAND_B | BAND_G: + case BAND_A | BAND_B | BAND_G: + case BAND_A | BAND_B: + case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN: + case BAND_B | BAND_G | BAND_GN: + dev_dbg(adapter->dev, "info: infra band=%d " + "supported_rates_bg\n", adapter->config_bands); + k = mwifiex_copy_rates(rates, k, supported_rates_bg, + sizeof(supported_rates_bg)); + break; + case BAND_A: + case BAND_A | BAND_G: + dev_dbg(adapter->dev, "info: infra band=%d " + "supported_rates_a\n", adapter->config_bands); + k = mwifiex_copy_rates(rates, k, supported_rates_a, + sizeof(supported_rates_a)); + break; + case BAND_A | BAND_AN: + case BAND_A | BAND_G | BAND_AN | BAND_GN: + dev_dbg(adapter->dev, "info: infra band=%d " + "supported_rates_a\n", adapter->config_bands); + k = mwifiex_copy_rates(rates, k, supported_rates_a, + sizeof(supported_rates_a)); + break; + case BAND_GN: + dev_dbg(adapter->dev, "info: infra band=%d " + "supported_rates_n\n", adapter->config_bands); + k = mwifiex_copy_rates(rates, k, supported_rates_n, + sizeof(supported_rates_n)); + break; + } + } else { + /* Ad-hoc mode */ + switch (adapter->adhoc_start_band) { + case BAND_B: + dev_dbg(adapter->dev, "info: adhoc B\n"); + k = mwifiex_copy_rates(rates, k, adhoc_rates_b, + sizeof(adhoc_rates_b)); + break; + case BAND_G: + case BAND_G | BAND_GN: + dev_dbg(adapter->dev, "info: adhoc G only\n"); + k = mwifiex_copy_rates(rates, k, adhoc_rates_g, + sizeof(adhoc_rates_g)); + break; + case BAND_B | BAND_G: + case BAND_B | BAND_G | BAND_GN: + dev_dbg(adapter->dev, "info: adhoc BG\n"); + k = mwifiex_copy_rates(rates, k, adhoc_rates_bg, + sizeof(adhoc_rates_bg)); + break; + case BAND_A: + case BAND_A | BAND_AN: + dev_dbg(adapter->dev, "info: adhoc A\n"); + k = mwifiex_copy_rates(rates, k, adhoc_rates_a, + sizeof(adhoc_rates_a)); + break; + } + } + + return k; +} diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c new file mode 100644 index 000000000000..a9aeb31af455 --- /dev/null +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -0,0 +1,1459 @@ +/* + * Marvell Wireless LAN device driver: commands and events + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" + +/* + * This function initializes a command node. + * + * The actual allocation of the node is not done by this function. It only + * initiates a node by filling it with default parameters. Similarly, + * allocation of the different buffers used (IOCTL buffer, data buffer) are + * not done by this function either. + */ +static void +mwifiex_init_cmd_node(struct mwifiex_private *priv, + struct cmd_ctrl_node *cmd_node, + u32 cmd_oid, void *wait_queue, void *data_buf) +{ + cmd_node->priv = priv; + cmd_node->cmd_oid = cmd_oid; + cmd_node->wq_buf = wait_queue; + cmd_node->data_buf = data_buf; + cmd_node->cmd_skb = cmd_node->skb; +} + +/* + * This function returns a command node from the free queue depending upon + * availability. + */ +static struct cmd_ctrl_node * +mwifiex_get_cmd_node(struct mwifiex_adapter *adapter) +{ + struct cmd_ctrl_node *cmd_node; + unsigned long flags; + + spin_lock_irqsave(&adapter->cmd_free_q_lock, flags); + if (list_empty(&adapter->cmd_free_q)) { + dev_err(adapter->dev, "GET_CMD_NODE: cmd node not available\n"); + spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags); + return NULL; + } + cmd_node = list_first_entry(&adapter->cmd_free_q, + struct cmd_ctrl_node, list); + list_del(&cmd_node->list); + spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags); + + return cmd_node; +} + +/* + * This function cleans up a command node. + * + * The function resets the fields including the buffer pointers. + * This function does not try to free the buffers. They must be + * freed before calling this function. + * + * This function will however call the receive completion callback + * in case a response buffer is still available before resetting + * the pointer. + */ +static void +mwifiex_clean_cmd_node(struct mwifiex_adapter *adapter, + struct cmd_ctrl_node *cmd_node) +{ + cmd_node->cmd_oid = 0; + cmd_node->cmd_flag = 0; + cmd_node->wq_buf = NULL; + cmd_node->data_buf = NULL; + + if (cmd_node->resp_skb) { + mwifiex_recv_complete(adapter, cmd_node->resp_skb, 0); + cmd_node->resp_skb = NULL; + } + + return; +} + +/* + * This function returns a command node from the pending queue which + * matches the given IOCTL request. + */ +static struct cmd_ctrl_node * +mwifiex_get_pending_ioctl_cmd(struct mwifiex_adapter *adapter, + struct mwifiex_wait_queue *wait_queue) +{ + unsigned long flags; + struct cmd_ctrl_node *cmd_node; + + spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); + list_for_each_entry(cmd_node, &adapter->cmd_pending_q, list) { + if (cmd_node->wq_buf == wait_queue) { + spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, + flags); + return cmd_node; + } + } + spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); + + return NULL; +} + +/* + * This function sends a host command to the firmware. + * + * The function copies the host command into the driver command + * buffer, which will be transferred to the firmware later by the + * main thread. + */ +static int mwifiex_cmd_host_cmd(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, void *data_buf) +{ + struct mwifiex_ds_misc_cmd *pcmd_ptr = + (struct mwifiex_ds_misc_cmd *) data_buf; + + /* Copy the HOST command to command buffer */ + memcpy((void *) cmd, pcmd_ptr->cmd, pcmd_ptr->len); + dev_dbg(priv->adapter->dev, "cmd: host cmd size = %d\n", pcmd_ptr->len); + return 0; +} + +/* + * This function downloads a command to the firmware. + * + * The function performs sanity tests, sets the command sequence + * number and size, converts the header fields to CPU format before + * sending. Afterwards, it logs the command ID and action for debugging + * and sets up the command timeout timer. + */ +static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv, + struct cmd_ctrl_node *cmd_node) +{ + + struct mwifiex_adapter *adapter = priv->adapter; + int ret = 0; + struct host_cmd_ds_command *host_cmd; + struct mwifiex_wait_queue *wait_queue = NULL; + uint16_t cmd_code; + uint16_t cmd_size; + struct timeval tstamp; + unsigned long flags; + + if (!adapter || !cmd_node) + return -1; + + host_cmd = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data); + if (cmd_node->wq_buf) + wait_queue = (struct mwifiex_wait_queue *) cmd_node->wq_buf; + + /* Sanity test */ + if (host_cmd == NULL || host_cmd->size == 0) { + dev_err(adapter->dev, "DNLD_CMD: host_cmd is null" + " or cmd size is 0, not sending\n"); + if (wait_queue) + wait_queue->status = MWIFIEX_ERROR_CMD_DNLD_FAIL; + mwifiex_insert_cmd_to_free_q(adapter, cmd_node); + return -1; + } + + /* Set command sequence number */ + adapter->seq_num++; + host_cmd->seq_num = cpu_to_le16(HostCmd_SET_SEQ_NO_BSS_INFO + (adapter->seq_num, cmd_node->priv->bss_num, + cmd_node->priv->bss_type)); + + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->curr_cmd = cmd_node; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + + cmd_code = le16_to_cpu(host_cmd->command); + cmd_size = le16_to_cpu(host_cmd->size); + + skb_trim(cmd_node->cmd_skb, cmd_size); + + do_gettimeofday(&tstamp); + dev_dbg(adapter->dev, "cmd: DNLD_CMD: (%lu.%lu): %#x, act %#x, len %d," + " seqno %#x\n", + tstamp.tv_sec, tstamp.tv_usec, cmd_code, + le16_to_cpu(*(__le16 *) ((u8 *) host_cmd + S_DS_GEN)), cmd_size, + le16_to_cpu(host_cmd->seq_num)); + + skb_push(cmd_node->cmd_skb, INTF_HEADER_LEN); + + ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD, + cmd_node->cmd_skb->data, + cmd_node->cmd_skb->len, NULL); + + if (ret == -1) { + dev_err(adapter->dev, "DNLD_CMD: host to card failed\n"); + if (wait_queue) + wait_queue->status = MWIFIEX_ERROR_CMD_DNLD_FAIL; + mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); + + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->curr_cmd = NULL; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + + adapter->dbg.num_cmd_host_to_card_failure++; + return -1; + } + + /* Save the last command id and action to debug log */ + adapter->dbg.last_cmd_index = + (adapter->dbg.last_cmd_index + 1) % DBG_CMD_NUM; + adapter->dbg.last_cmd_id[adapter->dbg.last_cmd_index] = cmd_code; + adapter->dbg.last_cmd_act[adapter->dbg.last_cmd_index] = + le16_to_cpu(*(__le16 *) ((u8 *) host_cmd + S_DS_GEN)); + + /* Clear BSS_NO_BITS from HostCmd */ + cmd_code &= HostCmd_CMD_ID_MASK; + + /* Setup the timer after transmit command */ + mod_timer(&adapter->cmd_timer, + jiffies + (MWIFIEX_TIMER_10S * HZ) / 1000); + + return 0; +} + +/* + * This function downloads a sleep confirm command to the firmware. + * + * The function performs sanity tests, sets the command sequence + * number and size, converts the header fields to CPU format before + * sending. + * + * No responses are needed for sleep confirm command. + */ +static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter) +{ + int ret = 0; + u16 cmd_len = 0; + struct mwifiex_private *priv; + struct mwifiex_opt_sleep_confirm_buffer *sleep_cfm_buf = + (struct mwifiex_opt_sleep_confirm_buffer *) + adapter->sleep_cfm->data; + cmd_len = sizeof(struct mwifiex_opt_sleep_confirm); + priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + + sleep_cfm_buf->ps_cfm_sleep.seq_num = + cpu_to_le16((HostCmd_SET_SEQ_NO_BSS_INFO + (adapter->seq_num, priv->bss_num, + priv->bss_type))); + adapter->seq_num++; + + ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD, + adapter->sleep_cfm->data, + adapter->sleep_cfm->len + + INTF_HEADER_LEN, NULL); + + if (ret == -1) { + dev_err(adapter->dev, "SLEEP_CFM: failed\n"); + adapter->dbg.num_cmd_sleep_cfm_host_to_card_failure++; + return -1; + } + if (GET_BSS_ROLE(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY)) + == MWIFIEX_BSS_ROLE_STA) { + if (!sleep_cfm_buf->ps_cfm_sleep.resp_ctrl) + /* Response is not needed for sleep + confirm command */ + adapter->ps_state = PS_STATE_SLEEP; + else + adapter->ps_state = PS_STATE_SLEEP_CFM; + + if (!sleep_cfm_buf->ps_cfm_sleep.resp_ctrl + && (adapter->is_hs_configured + && !adapter->sleep_period.period)) { + adapter->pm_wakeup_card_req = true; + mwifiex_hs_activated_event(mwifiex_get_priv(adapter, + MWIFIEX_BSS_ROLE_STA), true); + } + } + + return ret; +} + +/* + * This function allocates the command buffers and links them to + * the command free queue. + * + * The driver uses a pre allocated number of command buffers, which + * are created at driver initializations and freed at driver cleanup. + * Every command needs to obtain a command buffer from this pool before + * it can be issued. The command free queue lists the command buffers + * currently free to use, while the command pending queue lists the + * command buffers already in use and awaiting handling. Command buffers + * are returned to the free queue after use. + */ +int mwifiex_alloc_cmd_buffer(struct mwifiex_adapter *adapter) +{ + struct cmd_ctrl_node *cmd_array; + u32 buf_size; + u32 i; + + /* Allocate and initialize struct cmd_ctrl_node */ + buf_size = sizeof(struct cmd_ctrl_node) * MWIFIEX_NUM_OF_CMD_BUFFER; + cmd_array = kzalloc(buf_size, GFP_KERNEL); + if (!cmd_array) { + dev_err(adapter->dev, "%s: failed to alloc cmd_array\n", + __func__); + return -1; + } + + adapter->cmd_pool = cmd_array; + memset(adapter->cmd_pool, 0, buf_size); + + /* Allocate and initialize command buffers */ + for (i = 0; i < MWIFIEX_NUM_OF_CMD_BUFFER; i++) { + cmd_array[i].skb = dev_alloc_skb(MWIFIEX_SIZE_OF_CMD_BUFFER); + if (!cmd_array[i].skb) { + dev_err(adapter->dev, "ALLOC_CMD_BUF: out of memory\n"); + return -1; + } + } + + for (i = 0; i < MWIFIEX_NUM_OF_CMD_BUFFER; i++) + mwifiex_insert_cmd_to_free_q(adapter, &cmd_array[i]); + + return 0; +} + +/* + * This function frees the command buffers. + * + * The function calls the completion callback for all the command + * buffers that still have response buffers associated with them. + */ +int mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter) +{ + struct cmd_ctrl_node *cmd_array; + u32 i; + + /* Need to check if cmd pool is allocated or not */ + if (!adapter->cmd_pool) { + dev_dbg(adapter->dev, "info: FREE_CMD_BUF: cmd_pool is null\n"); + return 0; + } + + cmd_array = adapter->cmd_pool; + + /* Release shared memory buffers */ + for (i = 0; i < MWIFIEX_NUM_OF_CMD_BUFFER; i++) { + if (cmd_array[i].skb) { + dev_dbg(adapter->dev, "cmd: free cmd buffer %d\n", i); + dev_kfree_skb_any(cmd_array[i].skb); + } + if (!cmd_array[i].resp_skb) + continue; + mwifiex_recv_complete(adapter, cmd_array[i].resp_skb, 0); + } + /* Release struct cmd_ctrl_node */ + if (adapter->cmd_pool) { + dev_dbg(adapter->dev, "cmd: free cmd pool\n"); + kfree(adapter->cmd_pool); + adapter->cmd_pool = NULL; + } + + return 0; +} + +/* + * This function handles events generated by firmware. + * + * Event body of events received from firmware are not used (though they are + * saved), only the event ID is used. Some events are re-invoked by + * the driver, with a new event body. + * + * After processing, the function calls the completion callback + * for cleanup. + */ +int mwifiex_process_event(struct mwifiex_adapter *adapter) +{ + int ret = 0; + struct mwifiex_private *priv = + mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + struct sk_buff *skb = adapter->event_skb; + u32 eventcause = adapter->event_cause; + struct timeval tstamp; + struct mwifiex_rxinfo *rx_info = NULL; + + /* Save the last event to debug log */ + adapter->dbg.last_event_index = + (adapter->dbg.last_event_index + 1) % DBG_CMD_NUM; + adapter->dbg.last_event[adapter->dbg.last_event_index] = + (u16) eventcause; + + /* Get BSS number and corresponding priv */ + priv = mwifiex_get_priv_by_id(adapter, EVENT_GET_BSS_NUM(eventcause), + EVENT_GET_BSS_TYPE(eventcause)); + if (!priv) + priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + /* Clear BSS_NO_BITS from event */ + eventcause &= EVENT_ID_MASK; + adapter->event_cause = eventcause; + + if (skb) { + rx_info = MWIFIEX_SKB_RXCB(skb); + rx_info->bss_index = priv->bss_index; + } + + if (eventcause != EVENT_PS_SLEEP && eventcause != EVENT_PS_AWAKE) { + do_gettimeofday(&tstamp); + dev_dbg(adapter->dev, "event: %lu.%lu: cause: %#x\n", + tstamp.tv_sec, tstamp.tv_usec, eventcause); + } + + ret = mwifiex_process_sta_event(priv); + + adapter->event_cause = 0; + adapter->event_skb = NULL; + + mwifiex_recv_complete(adapter, skb, 0); + + return ret; +} + +/* + * This function prepares a command before sending it to the firmware. + * + * Preparation includes - + * - Sanity tests to make sure the card is still present or the FW + * is not reset + * - Getting a new command node from the command free queue + * - Initializing the command node for default parameters + * - Fill up the non-default parameters and buffer pointers + * - Add the command to pending queue + */ +int mwifiex_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, + u16 cmd_action, u32 cmd_oid, + void *wait_queue, void *data_buf) +{ + int ret = 0; + struct mwifiex_adapter *adapter = priv->adapter; + struct cmd_ctrl_node *cmd_node = NULL; + struct host_cmd_ds_command *cmd_ptr = NULL; + + if (!adapter) { + pr_err("PREP_CMD: adapter is NULL\n"); + return -1; + } + + if (adapter->is_suspended) { + dev_err(adapter->dev, "PREP_CMD: device in suspended state\n"); + return -1; + } + + if (adapter->surprise_removed) { + dev_err(adapter->dev, "PREP_CMD: card is removed\n"); + return -1; + } + + if (adapter->hw_status == MWIFIEX_HW_STATUS_RESET) { + if (cmd_no != HostCmd_CMD_FUNC_INIT) { + dev_err(adapter->dev, "PREP_CMD: FW in reset state\n"); + return -1; + } + } + + /* Get a new command node */ + cmd_node = mwifiex_get_cmd_node(adapter); + + if (!cmd_node) { + dev_err(adapter->dev, "PREP_CMD: no free cmd node\n"); + return -1; + } + + /* Initialize the command node */ + mwifiex_init_cmd_node(priv, cmd_node, cmd_oid, wait_queue, data_buf); + + if (!cmd_node->cmd_skb) { + dev_err(adapter->dev, "PREP_CMD: no free cmd buf\n"); + return -1; + } + + memset(skb_put(cmd_node->cmd_skb, sizeof(struct host_cmd_ds_command)), + 0, sizeof(struct host_cmd_ds_command)); + + cmd_ptr = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data); + cmd_ptr->command = cpu_to_le16(cmd_no); + cmd_ptr->result = 0; + + /* Prepare command */ + if (cmd_no) { + ret = mwifiex_sta_prepare_cmd(priv, cmd_no, cmd_action, + cmd_oid, data_buf, cmd_ptr); + } else { + ret = mwifiex_cmd_host_cmd(priv, cmd_ptr, data_buf); + cmd_node->cmd_flag |= CMD_F_HOSTCMD; + } + + /* Return error, since the command preparation failed */ + if (ret) { + dev_err(adapter->dev, "PREP_CMD: cmd %#x preparation failed\n", + cmd_no); + mwifiex_insert_cmd_to_free_q(adapter, cmd_node); + return -1; + } + + /* Send command */ + if (cmd_no == HostCmd_CMD_802_11_SCAN) + mwifiex_queue_scan_cmd(priv, cmd_node); + else + mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true); + + return ret; +} + +/* + * This function returns a command to the command free queue. + * + * The function also calls the completion callback if required, before + * cleaning the command node and re-inserting it into the free queue. + */ +void +mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter, + struct cmd_ctrl_node *cmd_node) +{ + struct mwifiex_wait_queue *wait_queue = NULL; + unsigned long flags; + + if (cmd_node == NULL) + return; + if (cmd_node->wq_buf) { + wait_queue = (struct mwifiex_wait_queue *) cmd_node->wq_buf; + if (wait_queue->status != MWIFIEX_ERROR_NO_ERROR) + mwifiex_ioctl_complete(adapter, wait_queue, -1); + else + mwifiex_ioctl_complete(adapter, wait_queue, 0); + } + /* Clean the node */ + mwifiex_clean_cmd_node(adapter, cmd_node); + + /* Insert node into cmd_free_q */ + spin_lock_irqsave(&adapter->cmd_free_q_lock, flags); + list_add_tail(&cmd_node->list, &adapter->cmd_free_q); + spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags); + + return; +} + +/* + * This function queues a command to the command pending queue. + * + * This in effect adds the command to the command list to be executed. + * Exit PS command is handled specially, by placing it always to the + * front of the command queue. + */ +void +mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter, + struct cmd_ctrl_node *cmd_node, u32 add_tail) +{ + struct host_cmd_ds_command *host_cmd = NULL; + u16 command; + unsigned long flags; + + host_cmd = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data); + if (!host_cmd) { + dev_err(adapter->dev, "QUEUE_CMD: host_cmd is NULL\n"); + return; + } + + command = le16_to_cpu(host_cmd->command); + + /* Exit_PS command needs to be queued in the header always. */ + if (command == HostCmd_CMD_802_11_PS_MODE_ENH) { + struct host_cmd_ds_802_11_ps_mode_enh *pm = + &host_cmd->params.psmode_enh; + if ((le16_to_cpu(pm->action) == DIS_PS) + || (le16_to_cpu(pm->action) == DIS_AUTO_PS)) { + if (adapter->ps_state != PS_STATE_AWAKE) + add_tail = false; + } + } + + spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); + if (add_tail) + list_add_tail(&cmd_node->list, &adapter->cmd_pending_q); + else + list_add(&cmd_node->list, &adapter->cmd_pending_q); + spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); + + dev_dbg(adapter->dev, "cmd: QUEUE_CMD: cmd=%#x is queued\n", command); + + return; +} + +/* + * This function executes the next command in command pending queue. + * + * This function will fail if a command is already in processing stage, + * otherwise it will dequeue the first command from the command pending + * queue and send to the firmware. + * + * If the device is currently in host sleep mode, any commands, except the + * host sleep configuration command will de-activate the host sleep. For PS + * mode, the function will put the firmware back to sleep if applicable. + */ +int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter) +{ + struct mwifiex_private *priv = NULL; + struct cmd_ctrl_node *cmd_node = NULL; + int ret = 0; + struct host_cmd_ds_command *host_cmd; + unsigned long cmd_flags; + unsigned long cmd_pending_q_flags; + + /* Check if already in processing */ + if (adapter->curr_cmd) { + dev_err(adapter->dev, "EXEC_NEXT_CMD: cmd in processing\n"); + return -1; + } + + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags); + /* Check if any command is pending */ + spin_lock_irqsave(&adapter->cmd_pending_q_lock, cmd_pending_q_flags); + if (list_empty(&adapter->cmd_pending_q)) { + spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, + cmd_pending_q_flags); + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); + return 0; + } + cmd_node = list_first_entry(&adapter->cmd_pending_q, + struct cmd_ctrl_node, list); + spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, + cmd_pending_q_flags); + + host_cmd = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data); + priv = cmd_node->priv; + + if (adapter->ps_state != PS_STATE_AWAKE) { + dev_err(adapter->dev, "%s: cannot send cmd in sleep state," + " this should not happen\n", __func__); + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); + return ret; + } + + spin_lock_irqsave(&adapter->cmd_pending_q_lock, cmd_pending_q_flags); + list_del(&cmd_node->list); + spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, + cmd_pending_q_flags); + + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); + ret = mwifiex_dnld_cmd_to_fw(priv, cmd_node); + priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + /* Any command sent to the firmware when host is in sleep + * mode should de-configure host sleep. We should skip the + * host sleep configuration command itself though + */ + if (priv && (host_cmd->command != + cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH))) { + if (adapter->hs_activated) { + adapter->is_hs_configured = false; + mwifiex_hs_activated_event(priv, false); + } + } + + return ret; +} + +/* + * This function handles the command response. + * + * After processing, the function cleans the command node and puts + * it back to the command free queue. + */ +int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter) +{ + struct host_cmd_ds_command *resp = NULL; + struct mwifiex_private *priv = + mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + int ret = 0; + uint16_t orig_cmdresp_no; + uint16_t cmdresp_no; + uint16_t cmdresp_result; + struct mwifiex_wait_queue *wait_queue = NULL; + struct timeval tstamp; + unsigned long flags; + + /* Now we got response from FW, cancel the command timer */ + del_timer(&adapter->cmd_timer); + + if (!adapter->curr_cmd || !adapter->curr_cmd->resp_skb) { + resp = (struct host_cmd_ds_command *) adapter->upld_buf; + dev_err(adapter->dev, "CMD_RESP: NULL curr_cmd, %#x\n", + le16_to_cpu(resp->command)); + return -1; + } + + if (adapter->curr_cmd->wq_buf) + wait_queue = (struct mwifiex_wait_queue *) + adapter->curr_cmd->wq_buf; + + adapter->num_cmd_timeout = 0; + + resp = (struct host_cmd_ds_command *) adapter->curr_cmd->resp_skb->data; + if (adapter->curr_cmd->cmd_flag & CMD_F_CANCELED) { + dev_err(adapter->dev, "CMD_RESP: %#x been canceled\n", + le16_to_cpu(resp->command)); + mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->curr_cmd = NULL; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + return -1; + } + + if (adapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) { + /* Copy original response back to response buffer */ + struct mwifiex_ds_misc_cmd *hostcmd = NULL; + uint16_t size = le16_to_cpu(resp->size); + dev_dbg(adapter->dev, "info: host cmd resp size = %d\n", size); + size = min_t(u16, size, MWIFIEX_SIZE_OF_CMD_BUFFER); + if (adapter->curr_cmd->data_buf) { + hostcmd = (struct mwifiex_ds_misc_cmd *) + adapter->curr_cmd->data_buf; + hostcmd->len = size; + memcpy(hostcmd->cmd, (void *) resp, size); + } + } + orig_cmdresp_no = le16_to_cpu(resp->command); + + /* Get BSS number and corresponding priv */ + priv = mwifiex_get_priv_by_id(adapter, + HostCmd_GET_BSS_NO(le16_to_cpu(resp->seq_num)), + HostCmd_GET_BSS_TYPE(le16_to_cpu(resp->seq_num))); + if (!priv) + priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + /* Clear RET_BIT from HostCmd */ + resp->command = cpu_to_le16(orig_cmdresp_no & HostCmd_CMD_ID_MASK); + + cmdresp_no = le16_to_cpu(resp->command); + cmdresp_result = le16_to_cpu(resp->result); + + /* Save the last command response to debug log */ + adapter->dbg.last_cmd_resp_index = + (adapter->dbg.last_cmd_resp_index + 1) % DBG_CMD_NUM; + adapter->dbg.last_cmd_resp_id[adapter->dbg.last_cmd_resp_index] = + orig_cmdresp_no; + + do_gettimeofday(&tstamp); + dev_dbg(adapter->dev, "cmd: CMD_RESP: (%lu.%lu): 0x%x, result %d," + " len %d, seqno 0x%x\n", + tstamp.tv_sec, tstamp.tv_usec, orig_cmdresp_no, cmdresp_result, + le16_to_cpu(resp->size), le16_to_cpu(resp->seq_num)); + + if (!(orig_cmdresp_no & HostCmd_RET_BIT)) { + dev_err(adapter->dev, "CMD_RESP: invalid cmd resp\n"); + if (wait_queue) + wait_queue->status = MWIFIEX_ERROR_FW_CMDRESP; + + mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->curr_cmd = NULL; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + return -1; + } + + if (adapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) { + adapter->curr_cmd->cmd_flag &= ~CMD_F_HOSTCMD; + if ((cmdresp_result == HostCmd_RESULT_OK) + && (cmdresp_no == HostCmd_CMD_802_11_HS_CFG_ENH)) + ret = mwifiex_ret_802_11_hs_cfg(priv, resp); + } else { + /* handle response */ + ret = mwifiex_process_sta_cmdresp(priv, cmdresp_no, resp, + wait_queue); + } + + /* Check init command response */ + if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) { + if (ret == -1) { + dev_err(adapter->dev, "%s: cmd %#x failed during " + "initialization\n", __func__, cmdresp_no); + mwifiex_init_fw_complete(adapter); + return -1; + } else if (adapter->last_init_cmd == cmdresp_no) + adapter->hw_status = MWIFIEX_HW_STATUS_INIT_DONE; + } + + if (adapter->curr_cmd) { + if (wait_queue && (!ret)) + wait_queue->status = MWIFIEX_ERROR_NO_ERROR; + else if (wait_queue && (ret == -1)) + wait_queue->status = MWIFIEX_ERROR_CMD_RESP_FAIL; + + /* Clean up and put current command back to cmd_free_q */ + mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); + + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->curr_cmd = NULL; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + } + + return ret; +} + +/* + * This function handles the timeout of command sending. + * + * It will re-send the same command again. + */ +void +mwifiex_cmd_timeout_func(unsigned long function_context) +{ + struct mwifiex_adapter *adapter = + (struct mwifiex_adapter *) function_context; + struct cmd_ctrl_node *cmd_node = NULL; + struct mwifiex_wait_queue *wait_queue = NULL; + struct timeval tstamp; + + adapter->num_cmd_timeout++; + adapter->dbg.num_cmd_timeout++; + if (!adapter->curr_cmd) { + dev_dbg(adapter->dev, "cmd: empty curr_cmd\n"); + return; + } + cmd_node = adapter->curr_cmd; + if (cmd_node->wq_buf) { + wait_queue = (struct mwifiex_wait_queue *) cmd_node->wq_buf; + wait_queue->status = MWIFIEX_ERROR_CMD_TIMEOUT; + } + + if (cmd_node) { + adapter->dbg.timeout_cmd_id = + adapter->dbg.last_cmd_id[adapter->dbg.last_cmd_index]; + adapter->dbg.timeout_cmd_act = + adapter->dbg.last_cmd_act[adapter->dbg.last_cmd_index]; + do_gettimeofday(&tstamp); + dev_err(adapter->dev, "%s: Timeout cmd id (%lu.%lu) = %#x," + " act = %#x\n", __func__, + tstamp.tv_sec, tstamp.tv_usec, + adapter->dbg.timeout_cmd_id, + adapter->dbg.timeout_cmd_act); + + dev_err(adapter->dev, "num_data_h2c_failure = %d\n", + adapter->dbg.num_tx_host_to_card_failure); + dev_err(adapter->dev, "num_cmd_h2c_failure = %d\n", + adapter->dbg.num_cmd_host_to_card_failure); + + dev_err(adapter->dev, "num_cmd_timeout = %d\n", + adapter->dbg.num_cmd_timeout); + dev_err(adapter->dev, "num_tx_timeout = %d\n", + adapter->dbg.num_tx_timeout); + + dev_err(adapter->dev, "last_cmd_index = %d\n", + adapter->dbg.last_cmd_index); + print_hex_dump_bytes("last_cmd_id: ", DUMP_PREFIX_OFFSET, + adapter->dbg.last_cmd_id, DBG_CMD_NUM); + print_hex_dump_bytes("last_cmd_act: ", DUMP_PREFIX_OFFSET, + adapter->dbg.last_cmd_act, DBG_CMD_NUM); + + dev_err(adapter->dev, "last_cmd_resp_index = %d\n", + adapter->dbg.last_cmd_resp_index); + print_hex_dump_bytes("last_cmd_resp_id: ", DUMP_PREFIX_OFFSET, + adapter->dbg.last_cmd_resp_id, DBG_CMD_NUM); + + dev_err(adapter->dev, "last_event_index = %d\n", + adapter->dbg.last_event_index); + print_hex_dump_bytes("last_event: ", DUMP_PREFIX_OFFSET, + adapter->dbg.last_event, DBG_CMD_NUM); + + dev_err(adapter->dev, "data_sent=%d cmd_sent=%d\n", + adapter->data_sent, adapter->cmd_sent); + + dev_err(adapter->dev, "ps_mode=%d ps_state=%d\n", + adapter->ps_mode, adapter->ps_state); + } + if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) + mwifiex_init_fw_complete(adapter); + + return; +} + +/* + * This function cancels all the pending commands. + * + * The current command, all commands in command pending queue and all scan + * commands in scan pending queue are cancelled. All the completion callbacks + * are called with failure status to ensure cleanup. + */ +void +mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter) +{ + struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL; + struct mwifiex_wait_queue *wait_queue = NULL; + unsigned long flags; + + /* Cancel current cmd */ + if ((adapter->curr_cmd) && (adapter->curr_cmd->wq_buf)) { + wait_queue = + (struct mwifiex_wait_queue *) adapter->curr_cmd->wq_buf; + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->curr_cmd->wq_buf = NULL; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + wait_queue->status = MWIFIEX_ERROR_CMD_CANCEL; + mwifiex_ioctl_complete(adapter, wait_queue, -1); + } + /* Cancel all pending command */ + spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); + list_for_each_entry_safe(cmd_node, tmp_node, + &adapter->cmd_pending_q, list) { + list_del(&cmd_node->list); + spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); + + if (cmd_node->wq_buf) { + wait_queue = + (struct mwifiex_wait_queue *) cmd_node->wq_buf; + wait_queue->status = MWIFIEX_ERROR_CMD_CANCEL; + mwifiex_ioctl_complete(adapter, wait_queue, -1); + cmd_node->wq_buf = NULL; + } + mwifiex_insert_cmd_to_free_q(adapter, cmd_node); + spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); + } + spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); + + /* Cancel all pending scan command */ + spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); + list_for_each_entry_safe(cmd_node, tmp_node, + &adapter->scan_pending_q, list) { + list_del(&cmd_node->list); + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); + + cmd_node->wq_buf = NULL; + mwifiex_insert_cmd_to_free_q(adapter, cmd_node); + spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); + } + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); + + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->scan_processing = false; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); +} + +/* + * This function cancels all pending commands that matches with + * the given IOCTL request. + * + * Both the current command buffer and the pending command queue are + * searched for matching IOCTL request. The completion callback of + * the matched command is called with failure status to ensure cleanup. + * In case of scan commands, all pending commands in scan pending queue + * are cancelled. + */ +void +mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter, + struct mwifiex_wait_queue *wait_queue) +{ + struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL; + unsigned long cmd_flags; + unsigned long cmd_pending_q_flags; + unsigned long scan_pending_q_flags; + uint16_t cancel_scan_cmd = false; + + if ((adapter->curr_cmd) && + (adapter->curr_cmd->wq_buf == wait_queue)) { + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags); + cmd_node = adapter->curr_cmd; + cmd_node->wq_buf = NULL; + cmd_node->cmd_flag |= CMD_F_CANCELED; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); + } + + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags); + while (1) { + cmd_node = mwifiex_get_pending_ioctl_cmd(adapter, wait_queue); + if (!cmd_node) + break; + + spin_lock_irqsave(&adapter->cmd_pending_q_lock, + cmd_pending_q_flags); + list_del(&cmd_node->list); + spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, + cmd_pending_q_flags); + + cmd_node->wq_buf = NULL; + mwifiex_insert_cmd_to_free_q(adapter, cmd_node); + } + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); + /* Cancel all pending scan command */ + spin_lock_irqsave(&adapter->scan_pending_q_lock, + scan_pending_q_flags); + list_for_each_entry_safe(cmd_node, tmp_node, + &adapter->scan_pending_q, list) { + if (cmd_node->wq_buf == wait_queue) { + list_del(&cmd_node->list); + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, + scan_pending_q_flags); + cmd_node->wq_buf = NULL; + mwifiex_insert_cmd_to_free_q(adapter, cmd_node); + spin_lock_irqsave(&adapter->scan_pending_q_lock, + scan_pending_q_flags); + cancel_scan_cmd = true; + } + } + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, + scan_pending_q_flags); + + if (cancel_scan_cmd) { + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags); + adapter->scan_processing = false; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); + } + wait_queue->status = MWIFIEX_ERROR_CMD_CANCEL; + mwifiex_ioctl_complete(adapter, wait_queue, -1); + + return; +} + +/* + * This function sends the sleep confirm command to firmware, if + * possible. + * + * The sleep confirm command cannot be issued if command response, + * data response or event response is awaiting handling, or if we + * are in the middle of sending a command, or expecting a command + * response. + */ +void +mwifiex_check_ps_cond(struct mwifiex_adapter *adapter) +{ + if (!adapter->cmd_sent && + !adapter->curr_cmd && !IS_CARD_RX_RCVD(adapter)) + mwifiex_dnld_sleep_confirm_cmd(adapter); + else + dev_dbg(adapter->dev, + "cmd: Delay Sleep Confirm (%s%s%s)\n", + (adapter->cmd_sent) ? "D" : "", + (adapter->curr_cmd) ? "C" : "", + (IS_CARD_RX_RCVD(adapter)) ? "R" : ""); +} + +/* + * This function sends a Host Sleep activated event to applications. + * + * This event is generated by the driver, with a blank event body. + */ +void +mwifiex_hs_activated_event(struct mwifiex_private *priv, u8 activated) +{ + if (activated) { + if (priv->adapter->is_hs_configured) { + priv->adapter->hs_activated = true; + dev_dbg(priv->adapter->dev, "event: hs_activated\n"); + priv->adapter->hs_activate_wait_q_woken = true; + wake_up_interruptible( + &priv->adapter->hs_activate_wait_q); + } else { + dev_dbg(priv->adapter->dev, "event: HS not configured\n"); + } + } else { + dev_dbg(priv->adapter->dev, "event: hs_deactivated\n"); + priv->adapter->hs_activated = false; + } +} + +/* + * This function handles the command response of a Host Sleep configuration + * command. + * + * Handling includes changing the header fields into CPU format + * and setting the current host sleep activation status in driver. + * + * In case host sleep status change, the function generates an event to + * notify the applications. + */ +int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct host_cmd_ds_802_11_hs_cfg_enh *phs_cfg = + &resp->params.opt_hs_cfg; + uint32_t conditions = le32_to_cpu(phs_cfg->params.hs_config.conditions); + + if (phs_cfg->action == cpu_to_le16(HS_ACTIVATE)) { + mwifiex_hs_activated_event(priv, true); + return 0; + } else { + dev_dbg(adapter->dev, "cmd: CMD_RESP: HS_CFG cmd reply" + " result=%#x, conditions=0x%x gpio=0x%x gap=0x%x\n", + resp->result, conditions, + phs_cfg->params.hs_config.gpio, + phs_cfg->params.hs_config.gap); + } + if (conditions != HOST_SLEEP_CFG_CANCEL) { + adapter->is_hs_configured = true; + } else { + adapter->is_hs_configured = false; + if (adapter->hs_activated) + mwifiex_hs_activated_event(priv, false); + } + + return 0; +} + +/* + * This function wakes up the adapter and generates a Host Sleep + * cancel event on receiving the power up interrupt. + */ +void +mwifiex_process_hs_config(struct mwifiex_adapter *adapter) +{ + dev_dbg(adapter->dev, "info: %s: auto cancelling host sleep" + " since there is interrupt from the firmware\n", __func__); + + adapter->if_ops.wakeup(adapter); + adapter->hs_activated = false; + adapter->is_hs_configured = false; + mwifiex_hs_activated_event(mwifiex_get_priv(adapter, + MWIFIEX_BSS_ROLE_ANY), false); + return; +} + +/* + * This function handles the command response of a sleep confirm command. + * + * The function sets the card state to SLEEP if the response indicates success. + */ +void +mwifiex_process_sleep_confirm_resp(struct mwifiex_adapter *adapter, + u8 *pbuf, u32 upld_len) +{ + struct host_cmd_ds_command *cmd = (struct host_cmd_ds_command *) pbuf; + struct mwifiex_private *priv = + mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + uint16_t result = le16_to_cpu(cmd->result); + uint16_t command = le16_to_cpu(cmd->command); + uint16_t seq_num = le16_to_cpu(cmd->seq_num); + + if (!upld_len) { + dev_err(adapter->dev, "%s: cmd size is 0\n", __func__); + return; + } + + /* Get BSS number and corresponding priv */ + priv = mwifiex_get_priv_by_id(adapter, HostCmd_GET_BSS_NO(seq_num), + HostCmd_GET_BSS_TYPE(seq_num)); + if (!priv) + priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + + /* Update sequence number */ + seq_num = HostCmd_GET_SEQ_NO(seq_num); + /* Clear RET_BIT from HostCmd */ + command &= HostCmd_CMD_ID_MASK; + + if (command != HostCmd_CMD_802_11_PS_MODE_ENH) { + dev_err(adapter->dev, "%s: received unexpected response for" + " cmd %x, result = %x\n", __func__, command, result); + return; + } + + if (result) { + dev_err(adapter->dev, "%s: sleep confirm cmd failed\n", + __func__); + adapter->pm_wakeup_card_req = false; + adapter->ps_state = PS_STATE_AWAKE; + return; + } + adapter->pm_wakeup_card_req = true; + if (adapter->is_hs_configured) + mwifiex_hs_activated_event(mwifiex_get_priv(adapter, + MWIFIEX_BSS_ROLE_ANY), true); + adapter->ps_state = PS_STATE_SLEEP; + cmd->command = cpu_to_le16(command); + cmd->seq_num = cpu_to_le16(seq_num); +} +EXPORT_SYMBOL_GPL(mwifiex_process_sleep_confirm_resp); + +/* + * This function prepares an enhanced power mode command. + * + * This function can be used to disable power save or to configure + * power save with auto PS or STA PS or auto deep sleep. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting Power Save bitmap, PS parameters TLV, PS mode TLV, + * auto deep sleep TLV (as required) + * - Ensuring correct endian-ness + */ +int mwifiex_cmd_enh_power_mode(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, uint16_t ps_bitmap, + void *data_buf) +{ + struct host_cmd_ds_802_11_ps_mode_enh *psmode_enh = + &cmd->params.psmode_enh; + u8 *tlv = NULL; + u16 cmd_size = 0; + + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH); + if (cmd_action == DIS_AUTO_PS) { + psmode_enh->action = cpu_to_le16(DIS_AUTO_PS); + psmode_enh->params.ps_bitmap = cpu_to_le16(ps_bitmap); + cmd->size = cpu_to_le16(S_DS_GEN + sizeof(psmode_enh->action) + + sizeof(psmode_enh->params.ps_bitmap)); + } else if (cmd_action == GET_PS) { + psmode_enh->action = cpu_to_le16(GET_PS); + psmode_enh->params.ps_bitmap = cpu_to_le16(ps_bitmap); + cmd->size = cpu_to_le16(S_DS_GEN + sizeof(psmode_enh->action) + + sizeof(psmode_enh->params.ps_bitmap)); + } else if (cmd_action == EN_AUTO_PS) { + psmode_enh->action = cpu_to_le16(EN_AUTO_PS); + psmode_enh->params.ps_bitmap = cpu_to_le16(ps_bitmap); + cmd_size = S_DS_GEN + sizeof(psmode_enh->action) + + sizeof(psmode_enh->params.ps_bitmap); + tlv = (u8 *) cmd + cmd_size; + if (ps_bitmap & BITMAP_STA_PS) { + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_ie_types_ps_param *ps_tlv = + (struct mwifiex_ie_types_ps_param *) tlv; + struct mwifiex_ps_param *ps_mode = &ps_tlv->param; + ps_tlv->header.type = cpu_to_le16(TLV_TYPE_PS_PARAM); + ps_tlv->header.len = cpu_to_le16(sizeof(*ps_tlv) - + sizeof(struct mwifiex_ie_types_header)); + cmd_size += sizeof(*ps_tlv); + tlv += sizeof(*ps_tlv); + dev_dbg(adapter->dev, "cmd: PS Command: Enter PS\n"); + ps_mode->null_pkt_interval = + cpu_to_le16(adapter->null_pkt_interval); + ps_mode->multiple_dtims = + cpu_to_le16(adapter->multiple_dtim); + ps_mode->bcn_miss_timeout = + cpu_to_le16(adapter->bcn_miss_time_out); + ps_mode->local_listen_interval = + cpu_to_le16(adapter->local_listen_interval); + ps_mode->adhoc_wake_period = + cpu_to_le16(adapter->adhoc_awake_period); + ps_mode->delay_to_ps = + cpu_to_le16(adapter->delay_to_ps); + ps_mode->mode = + cpu_to_le16(adapter->enhanced_ps_mode); + + } + if (ps_bitmap & BITMAP_AUTO_DS) { + struct mwifiex_ie_types_auto_ds_param *auto_ds_tlv = + (struct mwifiex_ie_types_auto_ds_param *) tlv; + u16 idletime = 0; + + auto_ds_tlv->header.type = + cpu_to_le16(TLV_TYPE_AUTO_DS_PARAM); + auto_ds_tlv->header.len = + cpu_to_le16(sizeof(*auto_ds_tlv) - + sizeof(struct mwifiex_ie_types_header)); + cmd_size += sizeof(*auto_ds_tlv); + tlv += sizeof(*auto_ds_tlv); + if (data_buf) + idletime = ((struct mwifiex_ds_auto_ds *) + data_buf)->idle_time; + dev_dbg(priv->adapter->dev, + "cmd: PS Command: Enter Auto Deep Sleep\n"); + auto_ds_tlv->deep_sleep_timeout = cpu_to_le16(idletime); + } + cmd->size = cpu_to_le16(cmd_size); + } + return 0; +} + +/* + * This function handles the command response of an enhanced power mode + * command. + * + * Handling includes changing the header fields into CPU format + * and setting the current enhanced power mode in driver. + */ +int mwifiex_ret_enh_power_mode(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *data_buf) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct host_cmd_ds_802_11_ps_mode_enh *ps_mode = + &resp->params.psmode_enh; + uint16_t action = le16_to_cpu(ps_mode->action); + uint16_t ps_bitmap = le16_to_cpu(ps_mode->params.ps_bitmap); + uint16_t auto_ps_bitmap = + le16_to_cpu(ps_mode->params.ps_bitmap); + + dev_dbg(adapter->dev, "info: %s: PS_MODE cmd reply result=%#x action=%#X\n", + __func__, resp->result, action); + if (action == EN_AUTO_PS) { + if (auto_ps_bitmap & BITMAP_AUTO_DS) { + dev_dbg(adapter->dev, "cmd: Enabled auto deep sleep\n"); + priv->adapter->is_deep_sleep = true; + } + if (auto_ps_bitmap & BITMAP_STA_PS) { + dev_dbg(adapter->dev, "cmd: Enabled STA power save\n"); + if (adapter->sleep_period.period) + dev_dbg(adapter->dev, "cmd: set to uapsd/pps mode\n"); + } + } else if (action == DIS_AUTO_PS) { + if (ps_bitmap & BITMAP_AUTO_DS) { + priv->adapter->is_deep_sleep = false; + dev_dbg(adapter->dev, "cmd: Disabled auto deep sleep\n"); + } + if (ps_bitmap & BITMAP_STA_PS) { + dev_dbg(adapter->dev, "cmd: Disabled STA power save\n"); + if (adapter->sleep_period.period) { + adapter->delay_null_pkt = false; + adapter->tx_lock_flag = false; + adapter->pps_uapsd_mode = false; + } + } + } else if (action == GET_PS) { + if (ps_bitmap & BITMAP_STA_PS) + adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP; + else + adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM; + + dev_dbg(adapter->dev, "cmd: ps_bitmap=%#x\n", ps_bitmap); + + if (data_buf) { + /* This section is for get power save mode */ + struct mwifiex_ds_pm_cfg *pm_cfg = + (struct mwifiex_ds_pm_cfg *)data_buf; + if (ps_bitmap & BITMAP_STA_PS) + pm_cfg->param.ps_mode = 1; + else + pm_cfg->param.ps_mode = 0; + } + } + return 0; +} + +/* + * This function prepares command to get hardware specifications. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting permanent address parameter + * - Ensuring correct endian-ness + */ +int mwifiex_cmd_get_hw_spec(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd) +{ + struct host_cmd_ds_get_hw_spec *hw_spec = &cmd->params.hw_spec; + + cmd->command = cpu_to_le16(HostCmd_CMD_GET_HW_SPEC); + cmd->size = + cpu_to_le16(sizeof(struct host_cmd_ds_get_hw_spec) + S_DS_GEN); + memcpy(hw_spec->permanent_addr, priv->curr_addr, ETH_ALEN); + + return 0; +} + +/* + * This function handles the command response of get hardware + * specifications. + * + * Handling includes changing the header fields into CPU format + * and saving/updating the following parameters in driver - + * - Firmware capability information + * - Firmware band settings + * - Ad-hoc start band and channel + * - Ad-hoc 11n activation status + * - Firmware release number + * - Number of antennas + * - Hardware address + * - Hardware interface version + * - Firmware version + * - Region code + * - 11n capabilities + * - MCS support fields + * - MP end port + */ +int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + struct host_cmd_ds_get_hw_spec *hw_spec = &resp->params.hw_spec; + struct mwifiex_adapter *adapter = priv->adapter; + int i; + + adapter->fw_cap_info = le32_to_cpu(hw_spec->fw_cap_info); + + if (IS_SUPPORT_MULTI_BANDS(adapter)) + adapter->fw_bands = (u8) GET_FW_DEFAULT_BANDS(adapter); + else + adapter->fw_bands = BAND_B; + + adapter->config_bands = adapter->fw_bands; + + if (adapter->fw_bands & BAND_A) { + if (adapter->fw_bands & BAND_GN) { + adapter->config_bands |= BAND_AN; + adapter->fw_bands |= BAND_AN; + } + if (adapter->fw_bands & BAND_AN) { + adapter->adhoc_start_band = BAND_A | BAND_AN; + adapter->adhoc_11n_enabled = true; + } else { + adapter->adhoc_start_band = BAND_A; + } + priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL_A; + } else if (adapter->fw_bands & BAND_GN) { + adapter->adhoc_start_band = BAND_G | BAND_B | BAND_GN; + priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL; + adapter->adhoc_11n_enabled = true; + } else if (adapter->fw_bands & BAND_G) { + adapter->adhoc_start_band = BAND_G | BAND_B; + priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL; + } else if (adapter->fw_bands & BAND_B) { + adapter->adhoc_start_band = BAND_B; + priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL; + } + + adapter->fw_release_number = le32_to_cpu(hw_spec->fw_release_number); + adapter->number_of_antenna = le16_to_cpu(hw_spec->number_of_antenna); + + dev_dbg(adapter->dev, "info: GET_HW_SPEC: fw_release_number- %#x\n", + adapter->fw_release_number); + dev_dbg(adapter->dev, "info: GET_HW_SPEC: permanent addr: %pM\n", + hw_spec->permanent_addr); + dev_dbg(adapter->dev, "info: GET_HW_SPEC: hw_if_version=%#x version=%#x\n", + le16_to_cpu(hw_spec->hw_if_version), + le16_to_cpu(hw_spec->version)); + + if (priv->curr_addr[0] == 0xff) + memmove(priv->curr_addr, hw_spec->permanent_addr, ETH_ALEN); + + adapter->region_code = le16_to_cpu(hw_spec->region_code); + + for (i = 0; i < MWIFIEX_MAX_REGION_CODE; i++) + /* Use the region code to search for the index */ + if (adapter->region_code == region_code_index[i]) + break; + + /* If it's unidentified region code, use the default (USA) */ + if (i >= MWIFIEX_MAX_REGION_CODE) { + adapter->region_code = 0x10; + dev_dbg(adapter->dev, "cmd: unknown region code, use default (USA)\n"); + } + + adapter->hw_dot_11n_dev_cap = le32_to_cpu(hw_spec->dot_11n_dev_cap); + adapter->hw_dev_mcs_support = hw_spec->dev_mcs_support; + + if (adapter->if_ops.update_mp_end_port) + adapter->if_ops.update_mp_end_port(adapter, + le16_to_cpu(hw_spec->mp_end_port)); + + return 0; +} diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c new file mode 100644 index 000000000000..63b09692f27d --- /dev/null +++ b/drivers/net/wireless/mwifiex/debugfs.c @@ -0,0 +1,773 @@ +/* + * Marvell Wireless LAN device driver: debugfs + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include <linux/debugfs.h> + +#include "main.h" +#include "11n.h" + + +static struct dentry *mwifiex_dfs_dir; + +static char *bss_modes[] = { + "Unknown", + "Managed", + "Ad-hoc", + "Auto" +}; + +/* size/addr for mwifiex_debug_info */ +#define item_size(n) (FIELD_SIZEOF(struct mwifiex_debug_info, n)) +#define item_addr(n) (offsetof(struct mwifiex_debug_info, n)) + +/* size/addr for struct mwifiex_adapter */ +#define adapter_item_size(n) (FIELD_SIZEOF(struct mwifiex_adapter, n)) +#define adapter_item_addr(n) (offsetof(struct mwifiex_adapter, n)) + +struct mwifiex_debug_data { + char name[32]; /* variable/array name */ + u32 size; /* size of the variable/array */ + size_t addr; /* address of the variable/array */ + int num; /* number of variables in an array */ +}; + +static struct mwifiex_debug_data items[] = { + {"int_counter", item_size(int_counter), + item_addr(int_counter), 1}, + {"wmm_ac_vo", item_size(packets_out[WMM_AC_VO]), + item_addr(packets_out[WMM_AC_VO]), 1}, + {"wmm_ac_vi", item_size(packets_out[WMM_AC_VI]), + item_addr(packets_out[WMM_AC_VI]), 1}, + {"wmm_ac_be", item_size(packets_out[WMM_AC_BE]), + item_addr(packets_out[WMM_AC_BE]), 1}, + {"wmm_ac_bk", item_size(packets_out[WMM_AC_BK]), + item_addr(packets_out[WMM_AC_BK]), 1}, + {"max_tx_buf_size", item_size(max_tx_buf_size), + item_addr(max_tx_buf_size), 1}, + {"tx_buf_size", item_size(tx_buf_size), + item_addr(tx_buf_size), 1}, + {"curr_tx_buf_size", item_size(curr_tx_buf_size), + item_addr(curr_tx_buf_size), 1}, + {"ps_mode", item_size(ps_mode), + item_addr(ps_mode), 1}, + {"ps_state", item_size(ps_state), + item_addr(ps_state), 1}, + {"is_deep_sleep", item_size(is_deep_sleep), + item_addr(is_deep_sleep), 1}, + {"wakeup_dev_req", item_size(pm_wakeup_card_req), + item_addr(pm_wakeup_card_req), 1}, + {"wakeup_tries", item_size(pm_wakeup_fw_try), + item_addr(pm_wakeup_fw_try), 1}, + {"hs_configured", item_size(is_hs_configured), + item_addr(is_hs_configured), 1}, + {"hs_activated", item_size(hs_activated), + item_addr(hs_activated), 1}, + {"num_tx_timeout", item_size(num_tx_timeout), + item_addr(num_tx_timeout), 1}, + {"num_cmd_timeout", item_size(num_cmd_timeout), + item_addr(num_cmd_timeout), 1}, + {"timeout_cmd_id", item_size(timeout_cmd_id), + item_addr(timeout_cmd_id), 1}, + {"timeout_cmd_act", item_size(timeout_cmd_act), + item_addr(timeout_cmd_act), 1}, + {"last_cmd_id", item_size(last_cmd_id), + item_addr(last_cmd_id), DBG_CMD_NUM}, + {"last_cmd_act", item_size(last_cmd_act), + item_addr(last_cmd_act), DBG_CMD_NUM}, + {"last_cmd_index", item_size(last_cmd_index), + item_addr(last_cmd_index), 1}, + {"last_cmd_resp_id", item_size(last_cmd_resp_id), + item_addr(last_cmd_resp_id), DBG_CMD_NUM}, + {"last_cmd_resp_index", item_size(last_cmd_resp_index), + item_addr(last_cmd_resp_index), 1}, + {"last_event", item_size(last_event), + item_addr(last_event), DBG_CMD_NUM}, + {"last_event_index", item_size(last_event_index), + item_addr(last_event_index), 1}, + {"num_cmd_h2c_fail", item_size(num_cmd_host_to_card_failure), + item_addr(num_cmd_host_to_card_failure), 1}, + {"num_cmd_sleep_cfm_fail", + item_size(num_cmd_sleep_cfm_host_to_card_failure), + item_addr(num_cmd_sleep_cfm_host_to_card_failure), 1}, + {"num_tx_h2c_fail", item_size(num_tx_host_to_card_failure), + item_addr(num_tx_host_to_card_failure), 1}, + {"num_evt_deauth", item_size(num_event_deauth), + item_addr(num_event_deauth), 1}, + {"num_evt_disassoc", item_size(num_event_disassoc), + item_addr(num_event_disassoc), 1}, + {"num_evt_link_lost", item_size(num_event_link_lost), + item_addr(num_event_link_lost), 1}, + {"num_cmd_deauth", item_size(num_cmd_deauth), + item_addr(num_cmd_deauth), 1}, + {"num_cmd_assoc_ok", item_size(num_cmd_assoc_success), + item_addr(num_cmd_assoc_success), 1}, + {"num_cmd_assoc_fail", item_size(num_cmd_assoc_failure), + item_addr(num_cmd_assoc_failure), 1}, + {"cmd_sent", item_size(cmd_sent), + item_addr(cmd_sent), 1}, + {"data_sent", item_size(data_sent), + item_addr(data_sent), 1}, + {"cmd_resp_received", item_size(cmd_resp_received), + item_addr(cmd_resp_received), 1}, + {"event_received", item_size(event_received), + item_addr(event_received), 1}, + + /* variables defined in struct mwifiex_adapter */ + {"ioctl_pending", adapter_item_size(ioctl_pending), + adapter_item_addr(ioctl_pending), 1}, + {"tx_pending", adapter_item_size(tx_pending), + adapter_item_addr(tx_pending), 1}, + {"rx_pending", adapter_item_size(rx_pending), + adapter_item_addr(rx_pending), 1}, +}; + +static int num_of_items = ARRAY_SIZE(items); + +/* + * Generic proc file open handler. + * + * This function is called every time a file is accessed for read or write. + */ +static int +mwifiex_open_generic(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +/* + * Proc info file read handler. + * + * This function is called when the 'info' file is opened for reading. + * It prints the following driver related information - + * - Driver name + * - Driver version + * - Driver extended version + * - Interface name + * - BSS mode + * - Media state (connected or disconnected) + * - MAC address + * - Total number of Tx bytes + * - Total number of Rx bytes + * - Total number of Tx packets + * - Total number of Rx packets + * - Total number of dropped Tx packets + * - Total number of dropped Rx packets + * - Total number of corrupted Tx packets + * - Total number of corrupted Rx packets + * - Carrier status (on or off) + * - Tx queue status (started or stopped) + * + * For STA mode drivers, it also prints the following extra - + * - ESSID + * - BSSID + * - Channel + * - Region code + * - Multicast count + * - Multicast addresses + */ +static ssize_t +mwifiex_info_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct mwifiex_private *priv = + (struct mwifiex_private *) file->private_data; + struct net_device *netdev = priv->netdev; + struct netdev_hw_addr *ha; + unsigned long page = get_zeroed_page(GFP_KERNEL); + char *p = (char *) page, fmt[64]; + struct mwifiex_bss_info info; + ssize_t ret = 0; + int i = 0; + + if (!p) + return -ENOMEM; + + memset(&info, 0, sizeof(info)); + ret = mwifiex_get_bss_info(priv, &info); + if (ret) + goto free_and_exit; + + mwifiex_drv_get_driver_version(priv->adapter, fmt, sizeof(fmt) - 1); + + if (!priv->version_str[0]) + mwifiex_get_ver_ext(priv); + + p += sprintf(p, "driver_name = " "\"mwifiex\"\n"); + p += sprintf(p, "driver_version = %s", fmt); + p += sprintf(p, "\nverext = %s", priv->version_str); + p += sprintf(p, "\ninterface_name=\"%s\"\n", netdev->name); + p += sprintf(p, "bss_mode=\"%s\"\n", bss_modes[info.bss_mode]); + p += sprintf(p, "media_state=\"%s\"\n", + (!priv->media_connected ? "Disconnected" : "Connected")); + p += sprintf(p, "mac_address=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n", + netdev->dev_addr[0], netdev->dev_addr[1], + netdev->dev_addr[2], netdev->dev_addr[3], + netdev->dev_addr[4], netdev->dev_addr[5]); + + if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) { + p += sprintf(p, "multicast_count=\"%d\"\n", + netdev_mc_count(netdev)); + p += sprintf(p, "essid=\"%s\"\n", info.ssid.ssid); + p += sprintf(p, "bssid=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n", + info.bssid[0], info.bssid[1], + info.bssid[2], info.bssid[3], + info.bssid[4], info.bssid[5]); + p += sprintf(p, "channel=\"%d\"\n", (int) info.bss_chan); + p += sprintf(p, "region_code = \"%02x\"\n", info.region_code); + + netdev_for_each_mc_addr(ha, netdev) + p += sprintf(p, "multicast_address[%d]=" + "\"%02x:%02x:%02x:%02x:%02x:%02x\"\n", i++, + ha->addr[0], ha->addr[1], + ha->addr[2], ha->addr[3], + ha->addr[4], ha->addr[5]); + } + + p += sprintf(p, "num_tx_bytes = %lu\n", priv->stats.tx_bytes); + p += sprintf(p, "num_rx_bytes = %lu\n", priv->stats.rx_bytes); + p += sprintf(p, "num_tx_pkts = %lu\n", priv->stats.tx_packets); + p += sprintf(p, "num_rx_pkts = %lu\n", priv->stats.rx_packets); + p += sprintf(p, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped); + p += sprintf(p, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped); + p += sprintf(p, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors); + p += sprintf(p, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors); + p += sprintf(p, "carrier %s\n", ((netif_carrier_ok(priv->netdev)) + ? "on" : "off")); + p += sprintf(p, "tx queue %s\n", ((netif_queue_stopped(priv->netdev)) + ? "stopped" : "started")); + + ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page, + (unsigned long) p - page); + +free_and_exit: + free_page(page); + return ret; +} + +/* + * Proc getlog file read handler. + * + * This function is called when the 'getlog' file is opened for reading + * It prints the following log information - + * - Number of multicast Tx frames + * - Number of failed packets + * - Number of Tx retries + * - Number of multicast Tx retries + * - Number of duplicate frames + * - Number of RTS successes + * - Number of RTS failures + * - Number of ACK failures + * - Number of fragmented Rx frames + * - Number of multicast Rx frames + * - Number of FCS errors + * - Number of Tx frames + * - WEP ICV error counts + */ +static ssize_t +mwifiex_getlog_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct mwifiex_private *priv = + (struct mwifiex_private *) file->private_data; + unsigned long page = get_zeroed_page(GFP_KERNEL); + char *p = (char *) page; + ssize_t ret = 0; + struct mwifiex_ds_get_stats stats; + + if (!p) + return -ENOMEM; + + memset(&stats, 0, sizeof(stats)); + ret = mwifiex_get_stats_info(priv, &stats); + if (ret) + goto free_and_exit; + + p += sprintf(p, "\n" + "mcasttxframe %u\n" + "failed %u\n" + "retry %u\n" + "multiretry %u\n" + "framedup %u\n" + "rtssuccess %u\n" + "rtsfailure %u\n" + "ackfailure %u\n" + "rxfrag %u\n" + "mcastrxframe %u\n" + "fcserror %u\n" + "txframe %u\n" + "wepicverrcnt-1 %u\n" + "wepicverrcnt-2 %u\n" + "wepicverrcnt-3 %u\n" + "wepicverrcnt-4 %u\n", + stats.mcast_tx_frame, + stats.failed, + stats.retry, + stats.multi_retry, + stats.frame_dup, + stats.rts_success, + stats.rts_failure, + stats.ack_failure, + stats.rx_frag, + stats.mcast_rx_frame, + stats.fcs_error, + stats.tx_frame, + stats.wep_icv_error[0], + stats.wep_icv_error[1], + stats.wep_icv_error[2], + stats.wep_icv_error[3]); + + + ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page, + (unsigned long) p - page); + +free_and_exit: + free_page(page); + return ret; +} + +static struct mwifiex_debug_info info; + +/* + * Proc debug file read handler. + * + * This function is called when the 'debug' file is opened for reading + * It prints the following log information - + * - Interrupt count + * - WMM AC VO packets count + * - WMM AC VI packets count + * - WMM AC BE packets count + * - WMM AC BK packets count + * - Maximum Tx buffer size + * - Tx buffer size + * - Current Tx buffer size + * - Power Save mode + * - Power Save state + * - Deep Sleep status + * - Device wakeup required status + * - Number of wakeup tries + * - Host Sleep configured status + * - Host Sleep activated status + * - Number of Tx timeouts + * - Number of command timeouts + * - Last timed out command ID + * - Last timed out command action + * - Last command ID + * - Last command action + * - Last command index + * - Last command response ID + * - Last command response index + * - Last event + * - Last event index + * - Number of host to card command failures + * - Number of sleep confirm command failures + * - Number of host to card data failure + * - Number of deauthentication events + * - Number of disassociation events + * - Number of link lost events + * - Number of deauthentication commands + * - Number of association success commands + * - Number of association failure commands + * - Number of commands sent + * - Number of data packets sent + * - Number of command responses received + * - Number of events received + * - Tx BA stream table (TID, RA) + * - Rx reorder table (TID, TA, Start window, Window size, Buffer) + */ +static ssize_t +mwifiex_debug_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct mwifiex_private *priv = + (struct mwifiex_private *) file->private_data; + struct mwifiex_debug_data *d = &items[0]; + unsigned long page = get_zeroed_page(GFP_KERNEL); + char *p = (char *) page; + ssize_t ret = 0; + size_t size, addr; + long val; + int i, j; + + if (!p) + return -ENOMEM; + + ret = mwifiex_get_debug_info(priv, &info); + if (ret) + goto free_and_exit; + + for (i = 0; i < num_of_items; i++) { + p += sprintf(p, "%s=", d[i].name); + + size = d[i].size / d[i].num; + + if (i < (num_of_items - 3)) + addr = d[i].addr + (size_t) &info; + else /* The last 3 items are struct mwifiex_adapter variables */ + addr = d[i].addr + (size_t) priv->adapter; + + for (j = 0; j < d[i].num; j++) { + switch (size) { + case 1: + val = *((u8 *) addr); + break; + case 2: + val = *((u16 *) addr); + break; + case 4: + val = *((u32 *) addr); + break; + case 8: + val = *((long long *) addr); + break; + default: + val = -1; + break; + } + + p += sprintf(p, "%#lx ", val); + addr += size; + } + + p += sprintf(p, "\n"); + } + + if (info.tx_tbl_num) { + p += sprintf(p, "Tx BA stream table:\n"); + for (i = 0; i < info.tx_tbl_num; i++) + p += sprintf(p, "tid = %d, " + "ra = %02x:%02x:%02x:%02x:%02x:%02x\n", + info.tx_tbl[i].tid, info.tx_tbl[i].ra[0], + info.tx_tbl[i].ra[1], info.tx_tbl[i].ra[2], + info.tx_tbl[i].ra[3], info.tx_tbl[i].ra[4], + info.tx_tbl[i].ra[5]); + } + + if (info.rx_tbl_num) { + p += sprintf(p, "Rx reorder table:\n"); + for (i = 0; i < info.rx_tbl_num; i++) { + + p += sprintf(p, "tid = %d, " + "ta = %02x:%02x:%02x:%02x:%02x:%02x, " + "start_win = %d, " + "win_size = %d, buffer: ", + info.rx_tbl[i].tid, + info.rx_tbl[i].ta[0], info.rx_tbl[i].ta[1], + info.rx_tbl[i].ta[2], info.rx_tbl[i].ta[3], + info.rx_tbl[i].ta[4], info.rx_tbl[i].ta[5], + info.rx_tbl[i].start_win, + info.rx_tbl[i].win_size); + + for (j = 0; j < info.rx_tbl[i].win_size; j++) + p += sprintf(p, "%c ", + info.rx_tbl[i].buffer[j] ? + '1' : '0'); + + p += sprintf(p, "\n"); + } + } + + ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page, + (unsigned long) p - page); + +free_and_exit: + free_page(page); + return ret; +} + +static u32 saved_reg_type, saved_reg_offset, saved_reg_value; + +/* + * Proc regrdwr file write handler. + * + * This function is called when the 'regrdwr' file is opened for writing + * + * This function can be used to write to a register. + */ +static ssize_t +mwifiex_regrdwr_write(struct file *file, + const char __user *ubuf, size_t count, loff_t *ppos) +{ + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *) addr; + size_t buf_size = min(count, (size_t) (PAGE_SIZE - 1)); + int ret = 0; + u32 reg_type = 0, reg_offset = 0, reg_value = UINT_MAX; + + if (!buf) + return -ENOMEM; + + + if (copy_from_user(buf, ubuf, buf_size)) { + ret = -EFAULT; + goto done; + } + + sscanf(buf, "%u %x %x", ®_type, ®_offset, ®_value); + + if (reg_type == 0 || reg_offset == 0) { + ret = -EINVAL; + goto done; + } else { + saved_reg_type = reg_type; + saved_reg_offset = reg_offset; + saved_reg_value = reg_value; + ret = count; + } +done: + free_page(addr); + return ret; +} + +/* + * Proc regrdwr file read handler. + * + * This function is called when the 'regrdwr' file is opened for reading + * + * This function can be used to read from a register. + */ +static ssize_t +mwifiex_regrdwr_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct mwifiex_private *priv = + (struct mwifiex_private *) file->private_data; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *) addr; + int pos = 0, ret = 0; + u32 reg_value; + + if (!buf) + return -ENOMEM; + + if (!saved_reg_type) { + /* No command has been given */ + pos += snprintf(buf, PAGE_SIZE, "0"); + goto done; + } + /* Set command has been given */ + if (saved_reg_value != UINT_MAX) { + ret = mwifiex_reg_write(priv, saved_reg_type, saved_reg_offset, + saved_reg_value); + + pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", + saved_reg_type, saved_reg_offset, + saved_reg_value); + + ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); + + goto done; + } + /* Get command has been given */ + ret = mwifiex_reg_read(priv, saved_reg_type, + saved_reg_offset, ®_value); + if (ret) { + ret = -EINVAL; + goto done; + } + + pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", saved_reg_type, + saved_reg_offset, reg_value); + + ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); + +done: + free_page(addr); + return ret; +} + +static u32 saved_offset = -1, saved_bytes = -1; + +/* + * Proc rdeeprom file write handler. + * + * This function is called when the 'rdeeprom' file is opened for writing + * + * This function can be used to write to a RDEEPROM location. + */ +static ssize_t +mwifiex_rdeeprom_write(struct file *file, + const char __user *ubuf, size_t count, loff_t *ppos) +{ + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *) addr; + size_t buf_size = min(count, (size_t) (PAGE_SIZE - 1)); + int ret = 0; + int offset = -1, bytes = -1; + + if (!buf) + return -ENOMEM; + + + if (copy_from_user(buf, ubuf, buf_size)) { + ret = -EFAULT; + goto done; + } + + sscanf(buf, "%d %d", &offset, &bytes); + + if (offset == -1 || bytes == -1) { + ret = -EINVAL; + goto done; + } else { + saved_offset = offset; + saved_bytes = bytes; + ret = count; + } +done: + free_page(addr); + return ret; +} + +/* + * Proc rdeeprom read write handler. + * + * This function is called when the 'rdeeprom' file is opened for reading + * + * This function can be used to read from a RDEEPROM location. + */ +static ssize_t +mwifiex_rdeeprom_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct mwifiex_private *priv = + (struct mwifiex_private *) file->private_data; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *) addr; + int pos = 0, ret = 0, i = 0; + u8 value[MAX_EEPROM_DATA]; + + if (!buf) + return -ENOMEM; + + if (saved_offset == -1) { + /* No command has been given */ + pos += snprintf(buf, PAGE_SIZE, "0"); + goto done; + } + + /* Get command has been given */ + ret = mwifiex_eeprom_read(priv, (u16) saved_offset, + (u16) saved_bytes, value); + if (ret) { + ret = -EINVAL; + goto done; + } + + pos += snprintf(buf, PAGE_SIZE, "%d %d ", saved_offset, saved_bytes); + + for (i = 0; i < saved_bytes; i++) + pos += snprintf(buf + strlen(buf), PAGE_SIZE, "%d ", value[i]); + + ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); + +done: + free_page(addr); + return ret; +} + + +#define MWIFIEX_DFS_ADD_FILE(name) do { \ + if (!debugfs_create_file(#name, 0644, priv->dfs_dev_dir, \ + priv, &mwifiex_dfs_##name##_fops)) \ + return; \ +} while (0); + +#define MWIFIEX_DFS_FILE_OPS(name) \ +static const struct file_operations mwifiex_dfs_##name##_fops = { \ + .read = mwifiex_##name##_read, \ + .write = mwifiex_##name##_write, \ + .open = mwifiex_open_generic, \ +}; + +#define MWIFIEX_DFS_FILE_READ_OPS(name) \ +static const struct file_operations mwifiex_dfs_##name##_fops = { \ + .read = mwifiex_##name##_read, \ + .open = mwifiex_open_generic, \ +}; + +#define MWIFIEX_DFS_FILE_WRITE_OPS(name) \ +static const struct file_operations mwifiex_dfs_##name##_fops = { \ + .write = mwifiex_##name##_write, \ + .open = mwifiex_open_generic, \ +}; + + +MWIFIEX_DFS_FILE_READ_OPS(info); +MWIFIEX_DFS_FILE_READ_OPS(debug); +MWIFIEX_DFS_FILE_READ_OPS(getlog); +MWIFIEX_DFS_FILE_OPS(regrdwr); +MWIFIEX_DFS_FILE_OPS(rdeeprom); + +/* + * This function creates the debug FS directory structure and the files. + */ +void +mwifiex_dev_debugfs_init(struct mwifiex_private *priv) +{ + if (!mwifiex_dfs_dir || !priv) + return; + + priv->dfs_dev_dir = debugfs_create_dir(priv->netdev->name, + mwifiex_dfs_dir); + + if (!priv->dfs_dev_dir) + return; + + MWIFIEX_DFS_ADD_FILE(info); + MWIFIEX_DFS_ADD_FILE(debug); + MWIFIEX_DFS_ADD_FILE(getlog); + MWIFIEX_DFS_ADD_FILE(regrdwr); + MWIFIEX_DFS_ADD_FILE(rdeeprom); + + return; +} + +/* + * This function removes the debug FS directory structure and the files. + */ +void +mwifiex_dev_debugfs_remove(struct mwifiex_private *priv) +{ + if (!priv) + return; + + debugfs_remove_recursive(priv->dfs_dev_dir); + return; +} + +/* + * This function creates the top level proc directory. + */ +void +mwifiex_debugfs_init(void) +{ + if (!mwifiex_dfs_dir) + mwifiex_dfs_dir = debugfs_create_dir("mwifiex", NULL); +} + +/* + * This function removes the top level proc directory. + */ +void +mwifiex_debugfs_remove(void) +{ + if (mwifiex_dfs_dir) + debugfs_remove(mwifiex_dfs_dir); +} diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h new file mode 100644 index 000000000000..c3c15f9e757e --- /dev/null +++ b/drivers/net/wireless/mwifiex/decl.h @@ -0,0 +1,153 @@ +/* + * Marvell Wireless LAN device driver: generic data structures and APIs + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#ifndef _MWIFIEX_DECL_H_ +#define _MWIFIEX_DECL_H_ + +#undef pr_fmt +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/wait.h> +#include <linux/timer.h> +#include <linux/ieee80211.h> + + +#define MWIFIEX_MAX_BSS_NUM (1) + +#define MWIFIEX_MIN_DATA_HEADER_LEN 32 /* (sizeof(mwifiex_txpd)) */ + +#define MWIFIEX_MAX_TX_BASTREAM_SUPPORTED 2 +#define MWIFIEX_MAX_RX_BASTREAM_SUPPORTED 16 + +#define MWIFIEX_AMPDU_DEF_TXWINSIZE 32 +#define MWIFIEX_AMPDU_DEF_RXWINSIZE 16 +#define MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT 0xffff + +#define MWIFIEX_RATE_INDEX_HRDSSS0 0 +#define MWIFIEX_RATE_INDEX_HRDSSS3 3 +#define MWIFIEX_RATE_INDEX_OFDM0 4 +#define MWIFIEX_RATE_INDEX_OFDM7 11 +#define MWIFIEX_RATE_INDEX_MCS0 12 + +#define MWIFIEX_RATE_BITMAP_OFDM0 16 +#define MWIFIEX_RATE_BITMAP_OFDM7 23 +#define MWIFIEX_RATE_BITMAP_MCS0 32 +#define MWIFIEX_RATE_BITMAP_MCS127 159 + +#define MWIFIEX_RX_DATA_BUF_SIZE (4 * 1024) + +#define MWIFIEX_RTS_MIN_VALUE (0) +#define MWIFIEX_RTS_MAX_VALUE (2347) +#define MWIFIEX_FRAG_MIN_VALUE (256) +#define MWIFIEX_FRAG_MAX_VALUE (2346) + +#define MWIFIEX_SDIO_BLOCK_SIZE 256 + +#define MWIFIEX_BUF_FLAG_REQUEUED_PKT BIT(0) + +enum mwifiex_error_code { + MWIFIEX_ERROR_NO_ERROR = 0, + MWIFIEX_ERROR_FW_NOT_READY = 0x00000001, + MWIFIEX_ERROR_FW_BUSY, + MWIFIEX_ERROR_FW_CMDRESP, + MWIFIEX_ERROR_PKT_SIZE_INVALID = 0x80000001, + MWIFIEX_ERROR_PKT_TIMEOUT, + MWIFIEX_ERROR_CMD_INVALID, + MWIFIEX_ERROR_CMD_TIMEOUT, + MWIFIEX_ERROR_CMD_DNLD_FAIL, + MWIFIEX_ERROR_CMD_CANCEL, + MWIFIEX_ERROR_CMD_RESP_FAIL, + MWIFIEX_ERROR_ASSOC_FAIL, + MWIFIEX_ERROR_EVENT_UNKNOWN, + MWIFIEX_ERROR_INVALID_PARAMETER, +}; + +enum mwifiex_bss_type { + MWIFIEX_BSS_TYPE_STA = 0, + MWIFIEX_BSS_TYPE_UAP = 1, + MWIFIEX_BSS_TYPE_ANY = 0xff, +}; + +enum mwifiex_bss_role { + MWIFIEX_BSS_ROLE_STA = 0, + MWIFIEX_BSS_ROLE_UAP = 1, + MWIFIEX_BSS_ROLE_ANY = 0xff, +}; + +#define BSS_ROLE_BIT_MASK BIT(0) + +#define GET_BSS_ROLE(priv) ((priv)->bss_role & BSS_ROLE_BIT_MASK) + +enum mwifiex_data_frame_type { + MWIFIEX_DATA_FRAME_TYPE_ETH_II = 0, + MWIFIEX_DATA_FRAME_TYPE_802_11, +}; + +struct mwifiex_fw_image { + u8 *helper_buf; + u32 helper_len; + u8 *fw_buf; + u32 fw_len; +}; + +struct mwifiex_802_11_ssid { + u32 ssid_len; + u8 ssid[IEEE80211_MAX_SSID_LEN]; +}; + +struct mwifiex_wait_queue { + u32 bss_index; + wait_queue_head_t *wait; + u16 *condition; + u32 start_time; + int status; + u32 enabled; +}; + +struct mwifiex_rxinfo { + u8 bss_index; + struct sk_buff *parent; + u8 use_count; +}; + +struct mwifiex_txinfo { + u32 status_code; + u8 flags; + u8 bss_index; +}; + +struct mwifiex_bss_attr { + u32 bss_type; + u32 frame_type; + u32 active; + u32 bss_priority; + u32 bss_num; +}; + +enum mwifiex_wmm_ac_e { + WMM_AC_BK, + WMM_AC_BE, + WMM_AC_VI, + WMM_AC_VO +} __packed; + +struct mwifiex_device { + struct mwifiex_bss_attr bss_attr[MWIFIEX_MAX_BSS_NUM]; +}; +#endif /* !_MWIFIEX_DECL_H_ */ diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h new file mode 100644 index 000000000000..2b938115b26a --- /dev/null +++ b/drivers/net/wireless/mwifiex/fw.h @@ -0,0 +1,1229 @@ +/* + * Marvell Wireless LAN device driver: Firmware specific macros & structures + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#ifndef _MWIFIEX_FW_H_ +#define _MWIFIEX_FW_H_ + +#include <linux/if_ether.h> + + +#define INTF_HEADER_LEN 4 + +struct rfc_1042_hdr { + u8 llc_dsap; + u8 llc_ssap; + u8 llc_ctrl; + u8 snap_oui[3]; + u16 snap_type; +}; + +struct rx_packet_hdr { + struct ethhdr eth803_hdr; + struct rfc_1042_hdr rfc1042_hdr; +}; + +struct tx_packet_hdr { + struct ethhdr eth803_hdr; + struct rfc_1042_hdr rfc1042_hdr; +}; + +#define B_SUPPORTED_RATES 5 +#define G_SUPPORTED_RATES 9 +#define BG_SUPPORTED_RATES 13 +#define A_SUPPORTED_RATES 9 +#define HOSTCMD_SUPPORTED_RATES 14 +#define N_SUPPORTED_RATES 3 +#define ALL_802_11_BANDS (BAND_A | BAND_B | BAND_G | BAND_GN) + +#define FW_MULTI_BANDS_SUPPORT (BIT(8) | BIT(9) | BIT(10) | BIT(11)) +#define IS_SUPPORT_MULTI_BANDS(adapter) \ + (adapter->fw_cap_info & FW_MULTI_BANDS_SUPPORT) +#define GET_FW_DEFAULT_BANDS(adapter) \ + ((adapter->fw_cap_info >> 8) & ALL_802_11_BANDS) + +extern u8 supported_rates_b[B_SUPPORTED_RATES]; +extern u8 supported_rates_g[G_SUPPORTED_RATES]; +extern u8 supported_rates_bg[BG_SUPPORTED_RATES]; +extern u8 supported_rates_a[A_SUPPORTED_RATES]; +extern u8 supported_rates_n[N_SUPPORTED_RATES]; + +#define HostCmd_WEP_KEY_INDEX_MASK 0x3fff + +#define KEY_INFO_ENABLED 0x01 +enum KEY_TYPE_ID { + KEY_TYPE_ID_WEP = 0, + KEY_TYPE_ID_TKIP, + KEY_TYPE_ID_AES, + KEY_TYPE_ID_WAPI, +}; + +enum KEY_INFO_WEP { + KEY_INFO_WEP_MCAST = 0x01, + KEY_INFO_WEP_UNICAST = 0x02, + KEY_INFO_WEP_ENABLED = 0x04 +}; + +enum KEY_INFO_TKIP { + KEY_INFO_TKIP_MCAST = 0x01, + KEY_INFO_TKIP_UNICAST = 0x02, + KEY_INFO_TKIP_ENABLED = 0x04 +}; + +enum KEY_INFO_AES { + KEY_INFO_AES_MCAST = 0x01, + KEY_INFO_AES_UNICAST = 0x02, + KEY_INFO_AES_ENABLED = 0x04 +}; + +#define WAPI_KEY_LEN 50 + +enum KEY_INFO_WAPI { + KEY_INFO_WAPI_MCAST = 0x01, + KEY_INFO_WAPI_UNICAST = 0x02, + KEY_INFO_WAPI_ENABLED = 0x04 +}; + +#define MAX_POLL_TRIES 100 + +#define MAX_MULTI_INTERFACE_POLL_TRIES 1000 + +#define MAX_FIRMWARE_POLL_TRIES 100 + +#define FIRMWARE_READY 0xfedc + +enum MWIFIEX_802_11_PRIVACY_FILTER { + MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL, + MWIFIEX_802_11_PRIV_FILTER_8021X_WEP +}; + +enum MWIFIEX_802_11_WEP_STATUS { + MWIFIEX_802_11_WEP_ENABLED, + MWIFIEX_802_11_WEP_DISABLED, +}; + +#define CAL_SNR(RSSI, NF) ((s16)((s16)(RSSI)-(s16)(NF))) + +#define PROPRIETARY_TLV_BASE_ID 0x0100 +#define TLV_TYPE_KEY_MATERIAL (PROPRIETARY_TLV_BASE_ID + 0) +#define TLV_TYPE_CHANLIST (PROPRIETARY_TLV_BASE_ID + 1) +#define TLV_TYPE_NUMPROBES (PROPRIETARY_TLV_BASE_ID + 2) +#define TLV_TYPE_PASSTHROUGH (PROPRIETARY_TLV_BASE_ID + 10) +#define TLV_TYPE_WMMQSTATUS (PROPRIETARY_TLV_BASE_ID + 16) +#define TLV_TYPE_WILDCARDSSID (PROPRIETARY_TLV_BASE_ID + 18) +#define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19) +#define TLV_TYPE_AUTH_TYPE (PROPRIETARY_TLV_BASE_ID + 31) +#define TLV_TYPE_CHANNELBANDLIST (PROPRIETARY_TLV_BASE_ID + 42) +#define TLV_TYPE_RATE_DROP_CONTROL (PROPRIETARY_TLV_BASE_ID + 82) +#define TLV_TYPE_RATE_SCOPE (PROPRIETARY_TLV_BASE_ID + 83) +#define TLV_TYPE_POWER_GROUP (PROPRIETARY_TLV_BASE_ID + 84) +#define TLV_TYPE_WAPI_IE (PROPRIETARY_TLV_BASE_ID + 94) +#define TLV_TYPE_AUTO_DS_PARAM (PROPRIETARY_TLV_BASE_ID + 113) +#define TLV_TYPE_PS_PARAM (PROPRIETARY_TLV_BASE_ID + 114) + +#define MWIFIEX_TX_DATA_BUF_SIZE_2K 2048 + +#define SSN_MASK 0xfff0 + +#define BA_RESULT_SUCCESS 0x0 +#define BA_RESULT_TIMEOUT 0x2 + +#define IS_BASTREAM_SETUP(ptr) (ptr->ba_status) + +#define BA_STREAM_NOT_ALLOWED 0xff + +#define IS_11N_ENABLED(priv) ((priv->adapter->config_bands & BAND_GN || \ + priv->adapter->config_bands & BAND_AN) \ + && priv->curr_bss_params.bss_descriptor.bcn_ht_cap) +#define INITIATOR_BIT(DelBAParamSet) (((DelBAParamSet) &\ + BIT(DELBA_INITIATOR_POS)) >> DELBA_INITIATOR_POS) + +#define MWIFIEX_TX_DATA_BUF_SIZE_4K 4096 +#define MWIFIEX_TX_DATA_BUF_SIZE_8K 8192 +#define NON_GREENFIELD_STAS 0x04 + +#define ISSUPP_11NENABLED(FwCapInfo) (FwCapInfo & BIT(11)) + +/* dev_cap bitmap + * BIT + * 0-16 reserved + * 17 IEEE80211_HT_CAP_SUP_WIDTH_20_40 + * 18-22 reserved + * 23 IEEE80211_HT_CAP_SGI_20 + * 24 IEEE80211_HT_CAP_SGI_40 + * 25 IEEE80211_HT_CAP_TX_STBC + * 26 IEEE80211_HT_CAP_RX_STBC + * 27-28 reserved + * 29 IEEE80211_HT_CAP_GRN_FLD + * 30-31 reserved + */ +#define ISSUPP_CHANWIDTH40(Dot11nDevCap) (Dot11nDevCap & BIT(17)) +#define ISSUPP_SHORTGI20(Dot11nDevCap) (Dot11nDevCap & BIT(23)) +#define ISSUPP_SHORTGI40(Dot11nDevCap) (Dot11nDevCap & BIT(24)) +#define ISSUPP_TXSTBC(Dot11nDevCap) (Dot11nDevCap & BIT(25)) +#define ISSUPP_RXSTBC(Dot11nDevCap) (Dot11nDevCap & BIT(26)) +#define ISSUPP_GREENFIELD(Dot11nDevCap) (Dot11nDevCap & BIT(29)) + +#define GET_RXMCSSUPP(DevMCSSupported) (DevMCSSupported & 0x0f) +#define RESETHT_EXTCAP_RDG(HTExtCap) (HTExtCap &= ~BIT(11)) +#define SETHT_MCS32(x) (x[4] |= 1) + +#define SET_SECONDARYCHAN(RadioType, SECCHAN) (RadioType |= (SECCHAN << 4)) + +#define LLC_SNAP_LEN 8 + +#define MOD_CLASS_HR_DSSS 0x03 +#define MOD_CLASS_OFDM 0x07 +#define MOD_CLASS_HT 0x08 +#define HT_BW_20 0 +#define HT_BW_40 1 + +#define HostCmd_CMD_GET_HW_SPEC 0x0003 +#define HostCmd_CMD_802_11_SCAN 0x0006 +#define HostCmd_CMD_802_11_GET_LOG 0x000b +#define HostCmd_CMD_MAC_MULTICAST_ADR 0x0010 +#define HostCmd_CMD_802_11_EEPROM_ACCESS 0x0059 +#define HostCmd_CMD_802_11_ASSOCIATE 0x0012 +#define HostCmd_CMD_802_11_SNMP_MIB 0x0016 +#define HostCmd_CMD_MAC_REG_ACCESS 0x0019 +#define HostCmd_CMD_BBP_REG_ACCESS 0x001a +#define HostCmd_CMD_RF_REG_ACCESS 0x001b +#define HostCmd_CMD_PMIC_REG_ACCESS 0x00ad +#define HostCmd_CMD_802_11_RF_CHANNEL 0x001d +#define HostCmd_CMD_802_11_DEAUTHENTICATE 0x0024 +#define HostCmd_CMD_MAC_CONTROL 0x0028 +#define HostCmd_CMD_802_11_AD_HOC_START 0x002b +#define HostCmd_CMD_802_11_AD_HOC_JOIN 0x002c +#define HostCmd_CMD_802_11_AD_HOC_STOP 0x0040 +#define HostCmd_CMD_802_11_MAC_ADDRESS 0x004D +#define HostCmd_CMD_802_11D_DOMAIN_INFO 0x005b +#define HostCmd_CMD_802_11_KEY_MATERIAL 0x005e +#define HostCmd_CMD_802_11_BG_SCAN_QUERY 0x006c +#define HostCmd_CMD_WMM_GET_STATUS 0x0071 +#define HostCmd_CMD_802_11_TX_RATE_QUERY 0x007f +#define HostCmd_CMD_802_11_IBSS_COALESCING_STATUS 0x0083 +#define HostCmd_CMD_VERSION_EXT 0x0097 +#define HostCmd_CMD_RSSI_INFO 0x00a4 +#define HostCmd_CMD_FUNC_INIT 0x00a9 +#define HostCmd_CMD_FUNC_SHUTDOWN 0x00aa +#define HostCmd_CMD_11N_CFG 0x00cd +#define HostCmd_CMD_11N_ADDBA_REQ 0x00ce +#define HostCmd_CMD_11N_ADDBA_RSP 0x00cf +#define HostCmd_CMD_11N_DELBA 0x00d0 +#define HostCmd_CMD_RECONFIGURE_TX_BUFF 0x00d9 +#define HostCmd_CMD_AMSDU_AGGR_CTRL 0x00df +#define HostCmd_CMD_TXPWR_CFG 0x00d1 +#define HostCmd_CMD_TX_RATE_CFG 0x00d6 +#define HostCmd_CMD_802_11_PS_MODE_ENH 0x00e4 +#define HostCmd_CMD_802_11_HS_CFG_ENH 0x00e5 +#define HostCmd_CMD_CAU_REG_ACCESS 0x00ed +#define HostCmd_CMD_SET_BSS_MODE 0x00f7 + + +enum ENH_PS_MODES { + EN_PS = 1, + DIS_PS = 2, + EN_AUTO_DS = 3, + DIS_AUTO_DS = 4, + SLEEP_CONFIRM = 5, + GET_PS = 0, + EN_AUTO_PS = 0xff, + DIS_AUTO_PS = 0xfe, +}; + +#define HostCmd_RET_BIT 0x8000 +#define HostCmd_ACT_GEN_GET 0x0000 +#define HostCmd_ACT_GEN_SET 0x0001 +#define HostCmd_RESULT_OK 0x0000 + +#define HostCmd_ACT_MAC_RX_ON 0x0001 +#define HostCmd_ACT_MAC_TX_ON 0x0002 +#define HostCmd_ACT_MAC_WEP_ENABLE 0x0008 +#define HostCmd_ACT_MAC_ETHERNETII_ENABLE 0x0010 +#define HostCmd_ACT_MAC_PROMISCUOUS_ENABLE 0x0080 +#define HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100 +#define HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON 0x2000 + +#define HostCmd_BSS_MODE_IBSS 0x0002 +#define HostCmd_BSS_MODE_ANY 0x0003 + +#define HostCmd_SCAN_RADIO_TYPE_BG 0 +#define HostCmd_SCAN_RADIO_TYPE_A 1 + +#define HOST_SLEEP_CFG_CANCEL 0xffffffff +#define HOST_SLEEP_CFG_COND_DEF 0x0000000f +#define HOST_SLEEP_CFG_GPIO_DEF 0xff +#define HOST_SLEEP_CFG_GAP_DEF 0 + +#define CMD_F_HOSTCMD (1 << 0) +#define CMD_F_CANCELED (1 << 1) + +#define HostCmd_CMD_ID_MASK 0x0fff + +#define HostCmd_SEQ_NUM_MASK 0x00ff + +#define HostCmd_BSS_NUM_MASK 0x0f00 + +#define HostCmd_BSS_TYPE_MASK 0xf000 + +#define HostCmd_SET_SEQ_NO_BSS_INFO(seq, num, type) { \ + (((seq) & 0x00ff) | \ + (((num) & 0x000f) << 8)) | \ + (((type) & 0x000f) << 12); } + +#define HostCmd_GET_SEQ_NO(seq) \ + ((seq) & HostCmd_SEQ_NUM_MASK) + +#define HostCmd_GET_BSS_NO(seq) \ + (((seq) & HostCmd_BSS_NUM_MASK) >> 8) + +#define HostCmd_GET_BSS_TYPE(seq) \ + (((seq) & HostCmd_BSS_TYPE_MASK) >> 12) + +#define EVENT_DUMMY_HOST_WAKEUP_SIGNAL 0x00000001 +#define EVENT_LINK_LOST 0x00000003 +#define EVENT_LINK_SENSED 0x00000004 +#define EVENT_MIB_CHANGED 0x00000006 +#define EVENT_INIT_DONE 0x00000007 +#define EVENT_DEAUTHENTICATED 0x00000008 +#define EVENT_DISASSOCIATED 0x00000009 +#define EVENT_PS_AWAKE 0x0000000a +#define EVENT_PS_SLEEP 0x0000000b +#define EVENT_MIC_ERR_MULTICAST 0x0000000d +#define EVENT_MIC_ERR_UNICAST 0x0000000e +#define EVENT_DEEP_SLEEP_AWAKE 0x00000010 +#define EVENT_ADHOC_BCN_LOST 0x00000011 + +#define EVENT_WMM_STATUS_CHANGE 0x00000017 +#define EVENT_BG_SCAN_REPORT 0x00000018 +#define EVENT_RSSI_LOW 0x00000019 +#define EVENT_SNR_LOW 0x0000001a +#define EVENT_MAX_FAIL 0x0000001b +#define EVENT_RSSI_HIGH 0x0000001c +#define EVENT_SNR_HIGH 0x0000001d +#define EVENT_IBSS_COALESCED 0x0000001e +#define EVENT_DATA_RSSI_LOW 0x00000024 +#define EVENT_DATA_SNR_LOW 0x00000025 +#define EVENT_DATA_RSSI_HIGH 0x00000026 +#define EVENT_DATA_SNR_HIGH 0x00000027 +#define EVENT_LINK_QUALITY 0x00000028 +#define EVENT_PORT_RELEASE 0x0000002b +#define EVENT_PRE_BEACON_LOST 0x00000031 +#define EVENT_ADDBA 0x00000033 +#define EVENT_DELBA 0x00000034 +#define EVENT_BA_STREAM_TIEMOUT 0x00000037 +#define EVENT_AMSDU_AGGR_CTRL 0x00000042 +#define EVENT_WEP_ICV_ERR 0x00000046 +#define EVENT_HS_ACT_REQ 0x00000047 +#define EVENT_BW_CHANGE 0x00000048 + +#define EVENT_HOSTWAKE_STAIE 0x0000004d + +#define EVENT_ID_MASK 0xffff +#define BSS_NUM_MASK 0xf + +#define EVENT_GET_BSS_NUM(event_cause) \ + (((event_cause) >> 16) & BSS_NUM_MASK) + +#define EVENT_GET_BSS_TYPE(event_cause) \ + (((event_cause) >> 24) & 0x00ff) + +struct mwifiex_ie_types_header { + __le16 type; + __le16 len; +} __packed; + +struct mwifiex_ie_types_data { + struct mwifiex_ie_types_header header; + u8 data[1]; +} __packed; + +#define MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET 0x01 +#define MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET 0x08 + +struct txpd { + u8 bss_type; + u8 bss_num; + __le16 tx_pkt_length; + __le16 tx_pkt_offset; + __le16 tx_pkt_type; + __le32 tx_control; + u8 priority; + u8 flags; + u8 pkt_delay_2ms; + u8 reserved1; +} __packed; + +struct rxpd { + u8 bss_type; + u8 bss_num; + u16 rx_pkt_length; + u16 rx_pkt_offset; + u16 rx_pkt_type; + u16 seq_num; + u8 priority; + u8 rx_rate; + s8 snr; + s8 nf; + /* Ht Info [Bit 0] RxRate format: LG=0, HT=1 + * [Bit 1] HT Bandwidth: BW20 = 0, BW40 = 1 + * [Bit 2] HT Guard Interval: LGI = 0, SGI = 1 */ + u8 ht_info; + u8 reserved; +} __packed; + +enum mwifiex_chan_scan_mode_bitmasks { + MWIFIEX_PASSIVE_SCAN = BIT(0), + MWIFIEX_DISABLE_CHAN_FILT = BIT(1), +}; + +#define SECOND_CHANNEL_BELOW 0x30 +#define SECOND_CHANNEL_ABOVE 0x10 +struct mwifiex_chan_scan_param_set { + u8 radio_type; + u8 chan_number; + u8 chan_scan_mode_bitmap; + __le16 min_scan_time; + __le16 max_scan_time; +} __packed; + +struct mwifiex_ie_types_chan_list_param_set { + struct mwifiex_ie_types_header header; + struct mwifiex_chan_scan_param_set chan_scan_param[1]; +} __packed; + +struct chan_band_param_set { + u8 radio_type; + u8 chan_number; +}; + +struct mwifiex_ie_types_chan_band_list_param_set { + struct mwifiex_ie_types_header header; + struct chan_band_param_set chan_band_param[1]; +} __packed; + +struct mwifiex_ie_types_rates_param_set { + struct mwifiex_ie_types_header header; + u8 rates[1]; +} __packed; + +struct mwifiex_ie_types_ssid_param_set { + struct mwifiex_ie_types_header header; + u8 ssid[1]; +} __packed; + +struct mwifiex_ie_types_num_probes { + struct mwifiex_ie_types_header header; + __le16 num_probes; +} __packed; + +struct mwifiex_ie_types_wildcard_ssid_params { + struct mwifiex_ie_types_header header; + u8 max_ssid_length; + u8 ssid[1]; +} __packed; + +#define TSF_DATA_SIZE 8 +struct mwifiex_ie_types_tsf_timestamp { + struct mwifiex_ie_types_header header; + u8 tsf_data[1]; +} __packed; + +struct mwifiex_cf_param_set { + u8 cfp_cnt; + u8 cfp_period; + u16 cfp_max_duration; + u16 cfp_duration_remaining; +} __packed; + +struct mwifiex_ibss_param_set { + u16 atim_window; +} __packed; + +struct mwifiex_ie_types_ss_param_set { + struct mwifiex_ie_types_header header; + union { + struct mwifiex_cf_param_set cf_param_set[1]; + struct mwifiex_ibss_param_set ibss_param_set[1]; + } cf_ibss; +} __packed; + +struct mwifiex_fh_param_set { + u16 dwell_time; + u8 hop_set; + u8 hop_pattern; + u8 hop_index; +} __packed; + +struct mwifiex_ds_param_set { + u8 current_chan; +} __packed; + +struct mwifiex_ie_types_phy_param_set { + struct mwifiex_ie_types_header header; + union { + struct mwifiex_fh_param_set fh_param_set[1]; + struct mwifiex_ds_param_set ds_param_set[1]; + } fh_ds; +} __packed; + +struct mwifiex_ie_types_auth_type { + struct mwifiex_ie_types_header header; + __le16 auth_type; +} __packed; + +struct mwifiex_ie_types_vendor_param_set { + struct mwifiex_ie_types_header header; + u8 ie[MWIFIEX_MAX_VSIE_LEN]; +}; + +struct mwifiex_ie_types_rsn_param_set { + struct mwifiex_ie_types_header header; + u8 rsn_ie[1]; +} __packed; + +#define KEYPARAMSET_FIXED_LEN 6 + +struct mwifiex_ie_type_key_param_set { + __le16 type; + __le16 length; + __le16 key_type_id; + __le16 key_info; + __le16 key_len; + u8 key[50]; +} __packed; + +struct host_cmd_ds_802_11_key_material { + __le16 action; + struct mwifiex_ie_type_key_param_set key_param_set; +} __packed; + +struct host_cmd_ds_gen { + u16 command; + u16 size; + u16 seq_num; + u16 result; +}; + +#define S_DS_GEN sizeof(struct host_cmd_ds_gen) + +enum sleep_resp_ctrl { + RESP_NOT_NEEDED = 0, + RESP_NEEDED, +}; + +struct mwifiex_ps_param { + __le16 null_pkt_interval; + __le16 multiple_dtims; + __le16 bcn_miss_timeout; + __le16 local_listen_interval; + __le16 adhoc_wake_period; + __le16 mode; + __le16 delay_to_ps; +}; + +#define BITMAP_AUTO_DS 0x01 +#define BITMAP_STA_PS 0x10 + +struct mwifiex_ie_types_auto_ds_param { + struct mwifiex_ie_types_header header; + __le16 deep_sleep_timeout; +} __packed; + +struct mwifiex_ie_types_ps_param { + struct mwifiex_ie_types_header header; + struct mwifiex_ps_param param; +} __packed; + +struct host_cmd_ds_802_11_ps_mode_enh { + __le16 action; + + union { + struct mwifiex_ps_param opt_ps; + __le16 ps_bitmap; + } params; +} __packed; + +struct host_cmd_ds_get_hw_spec { + __le16 hw_if_version; + __le16 version; + __le16 reserved; + __le16 num_of_mcast_adr; + u8 permanent_addr[ETH_ALEN]; + __le16 region_code; + __le16 number_of_antenna; + __le32 fw_release_number; + __le32 reserved_1; + __le32 reserved_2; + __le32 reserved_3; + __le32 fw_cap_info; + __le32 dot_11n_dev_cap; + u8 dev_mcs_support; + __le16 mp_end_port; /* SDIO only, reserved for other interfacces */ + __le16 reserved_4; +} __packed; + +struct host_cmd_ds_802_11_rssi_info { + __le16 action; + __le16 ndata; + __le16 nbcn; + __le16 reserved[9]; + long long reserved_1; +}; + +struct host_cmd_ds_802_11_rssi_info_rsp { + __le16 action; + __le16 ndata; + __le16 nbcn; + __le16 data_rssi_last; + __le16 data_nf_last; + __le16 data_rssi_avg; + __le16 data_nf_avg; + __le16 bcn_rssi_last; + __le16 bcn_nf_last; + __le16 bcn_rssi_avg; + __le16 bcn_nf_avg; + long long tsf_bcn; +}; + +struct host_cmd_ds_802_11_mac_address { + __le16 action; + u8 mac_addr[ETH_ALEN]; +}; + +struct host_cmd_ds_mac_control { + __le16 action; + __le16 reserved; +}; + +struct host_cmd_ds_mac_multicast_adr { + __le16 action; + __le16 num_of_adrs; + u8 mac_list[MWIFIEX_MAX_MULTICAST_LIST_SIZE][ETH_ALEN]; +} __packed; + +struct host_cmd_ds_802_11_deauthenticate { + u8 mac_addr[ETH_ALEN]; + __le16 reason_code; +} __packed; + +struct host_cmd_ds_802_11_associate { + u8 peer_sta_addr[ETH_ALEN]; + __le16 cap_info_bitmap; + __le16 listen_interval; + __le16 beacon_period; + u8 dtim_period; +} __packed; + +struct ieee_types_assoc_rsp { + __le16 cap_info_bitmap; + __le16 status_code; + __le16 a_id; + u8 ie_buffer[1]; +} __packed; + +struct host_cmd_ds_802_11_associate_rsp { + struct ieee_types_assoc_rsp assoc_rsp; +} __packed; + +struct ieee_types_cf_param_set { + u8 element_id; + u8 len; + u8 cfp_cnt; + u8 cfp_period; + u16 cfp_max_duration; + u16 cfp_duration_remaining; +} __packed; + +struct ieee_types_ibss_param_set { + u8 element_id; + u8 len; + __le16 atim_window; +} __packed; + +union ieee_types_ss_param_set { + struct ieee_types_cf_param_set cf_param_set; + struct ieee_types_ibss_param_set ibss_param_set; +} __packed; + +struct ieee_types_fh_param_set { + u8 element_id; + u8 len; + __le16 dwell_time; + u8 hop_set; + u8 hop_pattern; + u8 hop_index; +} __packed; + +struct ieee_types_ds_param_set { + u8 element_id; + u8 len; + u8 current_chan; +} __packed; + +union ieee_types_phy_param_set { + struct ieee_types_fh_param_set fh_param_set; + struct ieee_types_ds_param_set ds_param_set; +} __packed; + +struct host_cmd_ds_802_11_ad_hoc_start { + u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 bss_mode; + __le16 beacon_period; + u8 dtim_period; + union ieee_types_ss_param_set ss_param_set; + union ieee_types_phy_param_set phy_param_set; + u16 reserved1; + __le16 cap_info_bitmap; + u8 DataRate[HOSTCMD_SUPPORTED_RATES]; +} __packed; + +struct host_cmd_ds_802_11_ad_hoc_result { + u8 pad[3]; + u8 bssid[ETH_ALEN]; +} __packed; + +struct adhoc_bss_desc { + u8 bssid[ETH_ALEN]; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 bss_mode; + __le16 beacon_period; + u8 dtim_period; + u8 time_stamp[8]; + u8 local_time[8]; + union ieee_types_phy_param_set phy_param_set; + union ieee_types_ss_param_set ss_param_set; + __le16 cap_info_bitmap; + u8 data_rates[HOSTCMD_SUPPORTED_RATES]; + + /* + * DO NOT ADD ANY FIELDS TO THIS STRUCTURE. + * It is used in the Adhoc join command and will cause a + * binary layout mismatch with the firmware + */ +} __packed; + +struct host_cmd_ds_802_11_ad_hoc_join { + struct adhoc_bss_desc bss_descriptor; + u16 reserved1; + u16 reserved2; +} __packed; + +struct host_cmd_ds_802_11_get_log { + __le32 mcast_tx_frame; + __le32 failed; + __le32 retry; + __le32 multi_retry; + __le32 frame_dup; + __le32 rts_success; + __le32 rts_failure; + __le32 ack_failure; + __le32 rx_frag; + __le32 mcast_rx_frame; + __le32 fcs_error; + __le32 tx_frame; + __le32 reserved; + __le32 wep_icv_err_cnt[4]; +}; + +struct host_cmd_ds_tx_rate_query { + u8 tx_rate; + /* Ht Info [Bit 0] RxRate format: LG=0, HT=1 + * [Bit 1] HT Bandwidth: BW20 = 0, BW40 = 1 + * [Bit 2] HT Guard Interval: LGI = 0, SGI = 1 */ + u8 ht_info; +} __packed; + +enum Host_Sleep_Action { + HS_CONFIGURE = 0x0001, + HS_ACTIVATE = 0x0002, +}; + +struct mwifiex_hs_config_param { + __le32 conditions; + u8 gpio; + u8 gap; +} __packed; + +struct hs_activate_param { + u16 resp_ctrl; +} __packed; + +struct host_cmd_ds_802_11_hs_cfg_enh { + __le16 action; + + union { + struct mwifiex_hs_config_param hs_config; + struct hs_activate_param hs_activate; + } params; +} __packed; + +enum SNMP_MIB_INDEX { + OP_RATE_SET_I = 1, + DTIM_PERIOD_I = 3, + RTS_THRESH_I = 5, + SHORT_RETRY_LIM_I = 6, + LONG_RETRY_LIM_I = 7, + FRAG_THRESH_I = 8, + DOT11D_I = 9, +}; + +#define MAX_SNMP_BUF_SIZE 128 + +struct host_cmd_ds_802_11_snmp_mib { + __le16 query_type; + __le16 oid; + __le16 buf_size; + u8 value[1]; +} __packed; + +struct mwifiex_rate_scope { + __le16 type; + __le16 length; + __le16 hr_dsss_rate_bitmap; + __le16 ofdm_rate_bitmap; + __le16 ht_mcs_rate_bitmap[8]; +} __packed; + +struct mwifiex_rate_drop_pattern { + __le16 type; + __le16 length; + __le32 rate_drop_mode; +} __packed; + +struct host_cmd_ds_tx_rate_cfg { + __le16 action; + __le16 cfg_index; +} __packed; + +struct mwifiex_power_group { + u8 modulation_class; + u8 first_rate_code; + u8 last_rate_code; + s8 power_step; + s8 power_min; + s8 power_max; + u8 ht_bandwidth; + u8 reserved; +} __packed; + +struct mwifiex_types_power_group { + u16 type; + u16 length; +} __packed; + +struct host_cmd_ds_txpwr_cfg { + __le16 action; + __le16 cfg_index; + __le32 mode; +} __packed; + +#define MWIFIEX_USER_SCAN_CHAN_MAX 50 + +#define MWIFIEX_MAX_SSID_LIST_LENGTH 10 + +struct mwifiex_scan_cmd_config { + /* + * BSS Type to be sent in the firmware command + * + * Field can be used to restrict the types of networks returned in the + * scan. Valid settings are: + * + * - MWIFIEX_SCAN_MODE_BSS (infrastructure) + * - MWIFIEX_SCAN_MODE_IBSS (adhoc) + * - MWIFIEX_SCAN_MODE_ANY (unrestricted, adhoc and infrastructure) + */ + u8 bss_mode; + + /* Specific BSSID used to filter scan results in the firmware */ + u8 specific_bssid[ETH_ALEN]; + + /* Length of TLVs sent in command starting at tlvBuffer */ + u32 tlv_buf_len; + + /* + * SSID TLV(s) and ChanList TLVs to be sent in the firmware command + * + * TLV_TYPE_CHANLIST, mwifiex_ie_types_chan_list_param_set + * WLAN_EID_SSID, mwifiex_ie_types_ssid_param_set + */ + u8 tlv_buf[1]; /* SSID TLV(s) and ChanList TLVs are stored + here */ +} __packed; + +struct mwifiex_user_scan_chan { + u8 chan_number; + u8 radio_type; + u8 scan_type; + u8 reserved; + u32 scan_time; +} __packed; + +struct mwifiex_user_scan_ssid { + u8 ssid[IEEE80211_MAX_SSID_LEN + 1]; + u8 max_len; +} __packed; + +struct mwifiex_user_scan_cfg { + /* + * Flag set to keep the previous scan table intact + * + * If set, the scan results will accumulate, replacing any previous + * matched entries for a BSS with the new scan data + */ + u8 keep_previous_scan; + /* + * BSS mode to be sent in the firmware command + * + * Field can be used to restrict the types of networks returned in the + * scan. Valid settings are: + * + * - MWIFIEX_SCAN_MODE_BSS (infrastructure) + * - MWIFIEX_SCAN_MODE_IBSS (adhoc) + * - MWIFIEX_SCAN_MODE_ANY (unrestricted, adhoc and infrastructure) + */ + u8 bss_mode; + /* Configure the number of probe requests for active chan scans */ + u8 num_probes; + u8 reserved; + /* BSSID filter sent in the firmware command to limit the results */ + u8 specific_bssid[ETH_ALEN]; + /* SSID filter list used in the to limit the scan results */ + struct mwifiex_user_scan_ssid ssid_list[MWIFIEX_MAX_SSID_LIST_LENGTH]; + /* Variable number (fixed maximum) of channels to scan up */ + struct mwifiex_user_scan_chan chan_list[MWIFIEX_USER_SCAN_CHAN_MAX]; +} __packed; + +struct ie_body { + u8 grp_key_oui[4]; + u8 ptk_cnt[2]; + u8 ptk_body[4]; +} __packed; + +struct host_cmd_ds_802_11_scan { + u8 bss_mode; + u8 bssid[ETH_ALEN]; + u8 tlv_buffer[1]; +} __packed; + +struct host_cmd_ds_802_11_scan_rsp { + __le16 bss_descript_size; + u8 number_of_sets; + u8 bss_desc_and_tlv_buffer[1]; +} __packed; + +struct host_cmd_ds_802_11_bg_scan_query { + u8 flush; +} __packed; + +struct host_cmd_ds_802_11_bg_scan_query_rsp { + u32 report_condition; + struct host_cmd_ds_802_11_scan_rsp scan_resp; +} __packed; + +struct mwifiex_ietypes_domain_param_set { + struct mwifiex_ie_types_header header; + u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; + struct ieee80211_country_ie_triplet triplet[1]; +} __packed; + +struct host_cmd_ds_802_11d_domain_info { + __le16 action; + struct mwifiex_ietypes_domain_param_set domain; +} __packed; + +struct host_cmd_ds_802_11d_domain_info_rsp { + __le16 action; + struct mwifiex_ietypes_domain_param_set domain; +} __packed; + +struct host_cmd_ds_11n_addba_req { + u8 add_req_result; + u8 peer_mac_addr[ETH_ALEN]; + u8 dialog_token; + __le16 block_ack_param_set; + __le16 block_ack_tmo; + __le16 ssn; +} __packed; + +struct host_cmd_ds_11n_addba_rsp { + u8 add_rsp_result; + u8 peer_mac_addr[ETH_ALEN]; + u8 dialog_token; + __le16 status_code; + __le16 block_ack_param_set; + __le16 block_ack_tmo; + __le16 ssn; +} __packed; + +struct host_cmd_ds_11n_delba { + u8 del_result; + u8 peer_mac_addr[ETH_ALEN]; + __le16 del_ba_param_set; + __le16 reason_code; + u8 reserved; +} __packed; + +struct host_cmd_ds_11n_batimeout { + u8 tid; + u8 peer_mac_addr[ETH_ALEN]; + u8 origninator; +} __packed; + +struct host_cmd_ds_11n_cfg { + __le16 action; + __le16 ht_tx_cap; + __le16 ht_tx_info; +} __packed; + +struct host_cmd_ds_txbuf_cfg { + __le16 action; + __le16 buff_size; + __le16 mp_end_port; /* SDIO only, reserved for other interfacces */ + __le16 reserved3; +} __packed; + +struct host_cmd_ds_amsdu_aggr_ctrl { + __le16 action; + __le16 enable; + __le16 curr_buf_size; +} __packed; + +struct mwifiex_ie_types_wmm_param_set { + struct mwifiex_ie_types_header header; + u8 wmm_ie[1]; +}; + +struct mwifiex_ie_types_wmm_queue_status { + struct mwifiex_ie_types_header header; + u8 queue_index; + u8 disabled; + u16 medium_time; + u8 flow_required; + u8 flow_created; + u32 reserved; +}; + +struct ieee_types_vendor_header { + u8 element_id; + u8 len; + u8 oui[3]; + u8 oui_type; + u8 oui_subtype; + u8 version; +} __packed; + +struct ieee_types_wmm_ac_parameters { + u8 aci_aifsn_bitmap; + u8 ecw_bitmap; + __le16 tx_op_limit; +} __packed; + +struct ieee_types_wmm_parameter { + /* + * WMM Parameter IE - Vendor Specific Header: + * element_id [221/0xdd] + * Len [24] + * Oui [00:50:f2] + * OuiType [2] + * OuiSubType [1] + * Version [1] + */ + struct ieee_types_vendor_header vend_hdr; + u8 qos_info_bitmap; + u8 reserved; + struct ieee_types_wmm_ac_parameters ac_params[IEEE80211_MAX_QUEUES]; +} __packed; + +struct ieee_types_wmm_info { + + /* + * WMM Info IE - Vendor Specific Header: + * element_id [221/0xdd] + * Len [7] + * Oui [00:50:f2] + * OuiType [2] + * OuiSubType [0] + * Version [1] + */ + struct ieee_types_vendor_header vend_hdr; + + u8 qos_info_bitmap; +} __packed; + +struct host_cmd_ds_wmm_get_status { + u8 queue_status_tlv[sizeof(struct mwifiex_ie_types_wmm_queue_status) * + IEEE80211_MAX_QUEUES]; + u8 wmm_param_tlv[sizeof(struct ieee_types_wmm_parameter) + 2]; +} __packed; + +struct mwifiex_wmm_ac_status { + u8 disabled; + u8 flow_required; + u8 flow_created; +}; + +struct mwifiex_ie_types_htcap { + struct mwifiex_ie_types_header header; + struct ieee80211_ht_cap ht_cap; +} __packed; + +struct mwifiex_ie_types_htinfo { + struct mwifiex_ie_types_header header; + struct ieee80211_ht_info ht_info; +} __packed; + +struct mwifiex_ie_types_2040bssco { + struct mwifiex_ie_types_header header; + u8 bss_co_2040; +} __packed; + +struct mwifiex_ie_types_extcap { + struct mwifiex_ie_types_header header; + u8 ext_cap; +} __packed; + +struct host_cmd_ds_mac_reg_access { + __le16 action; + __le16 offset; + __le32 value; +} __packed; + +struct host_cmd_ds_bbp_reg_access { + __le16 action; + __le16 offset; + u8 value; + u8 reserved[3]; +} __packed; + +struct host_cmd_ds_rf_reg_access { + __le16 action; + __le16 offset; + u8 value; + u8 reserved[3]; +} __packed; + +struct host_cmd_ds_pmic_reg_access { + __le16 action; + __le16 offset; + u8 value; + u8 reserved[3]; +} __packed; + +struct host_cmd_ds_802_11_eeprom_access { + __le16 action; + + __le16 offset; + __le16 byte_count; + u8 value; +} __packed; + +struct host_cmd_ds_802_11_rf_channel { + __le16 action; + __le16 current_channel; + __le16 rf_type; + __le16 reserved; + u8 reserved_1[32]; +} __packed; + +struct host_cmd_ds_version_ext { + u8 version_str_sel; + char version_str[128]; +} __packed; + +struct host_cmd_ds_802_11_ibss_status { + __le16 action; + __le16 enable; + u8 bssid[ETH_ALEN]; + __le16 beacon_interval; + __le16 atim_window; + __le16 use_g_rate_protect; +} __packed; + +#define CONNECTION_TYPE_INFRA 0 +#define CONNECTION_TYPE_ADHOC 1 + +struct host_cmd_ds_set_bss_mode { + u8 con_type; +} __packed; + +struct host_cmd_ds_command { + __le16 command; + __le16 size; + __le16 seq_num; + __le16 result; + union { + struct host_cmd_ds_get_hw_spec hw_spec; + struct host_cmd_ds_mac_control mac_ctrl; + struct host_cmd_ds_802_11_mac_address mac_addr; + struct host_cmd_ds_mac_multicast_adr mc_addr; + struct host_cmd_ds_802_11_get_log get_log; + struct host_cmd_ds_802_11_rssi_info rssi_info; + struct host_cmd_ds_802_11_rssi_info_rsp rssi_info_rsp; + struct host_cmd_ds_802_11_snmp_mib smib; + struct host_cmd_ds_802_11_rf_channel rf_channel; + struct host_cmd_ds_tx_rate_query tx_rate; + struct host_cmd_ds_tx_rate_cfg tx_rate_cfg; + struct host_cmd_ds_txpwr_cfg txp_cfg; + struct host_cmd_ds_802_11_ps_mode_enh psmode_enh; + struct host_cmd_ds_802_11_hs_cfg_enh opt_hs_cfg; + struct host_cmd_ds_802_11_scan scan; + struct host_cmd_ds_802_11_scan_rsp scan_resp; + struct host_cmd_ds_802_11_bg_scan_query bg_scan_query; + struct host_cmd_ds_802_11_bg_scan_query_rsp bg_scan_query_resp; + struct host_cmd_ds_802_11_associate associate; + struct host_cmd_ds_802_11_associate_rsp associate_rsp; + struct host_cmd_ds_802_11_deauthenticate deauth; + struct host_cmd_ds_802_11_ad_hoc_start adhoc_start; + struct host_cmd_ds_802_11_ad_hoc_result adhoc_result; + struct host_cmd_ds_802_11_ad_hoc_join adhoc_join; + struct host_cmd_ds_802_11d_domain_info domain_info; + struct host_cmd_ds_802_11d_domain_info_rsp domain_info_resp; + struct host_cmd_ds_11n_addba_req add_ba_req; + struct host_cmd_ds_11n_addba_rsp add_ba_rsp; + struct host_cmd_ds_11n_delba del_ba; + struct host_cmd_ds_txbuf_cfg tx_buf; + struct host_cmd_ds_amsdu_aggr_ctrl amsdu_aggr_ctrl; + struct host_cmd_ds_11n_cfg htcfg; + struct host_cmd_ds_wmm_get_status get_wmm_status; + struct host_cmd_ds_802_11_key_material key_material; + struct host_cmd_ds_version_ext verext; + struct host_cmd_ds_802_11_ibss_status ibss_coalescing; + struct host_cmd_ds_mac_reg_access mac_reg; + struct host_cmd_ds_bbp_reg_access bbp_reg; + struct host_cmd_ds_rf_reg_access rf_reg; + struct host_cmd_ds_pmic_reg_access pmic_reg; + struct host_cmd_ds_set_bss_mode bss_mode; + struct host_cmd_ds_802_11_eeprom_access eeprom; + } params; +} __packed; + +struct mwifiex_opt_sleep_confirm { + __le16 command; + __le16 size; + __le16 seq_num; + __le16 result; + __le16 action; + __le16 resp_ctrl; +} __packed; + +struct mwifiex_opt_sleep_confirm_buffer { + u8 hdr[4]; + struct mwifiex_opt_sleep_confirm ps_cfm_sleep; +} __packed; +#endif /* !_MWIFIEX_FW_H_ */ diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c new file mode 100644 index 000000000000..8189862da1f9 --- /dev/null +++ b/drivers/net/wireless/mwifiex/init.c @@ -0,0 +1,662 @@ +/* + * Marvell Wireless LAN device driver: HW/FW Initialization + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" + +/* + * This function adds a BSS priority table to the table list. + * + * The function allocates a new BSS priority table node and adds it to + * the end of BSS priority table list, kept in driver memory. + */ +static int mwifiex_add_bss_prio_tbl(struct mwifiex_private *priv) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_bss_prio_node *bss_prio; + int status = 0; + unsigned long flags; + + bss_prio = kzalloc(sizeof(struct mwifiex_bss_prio_node), GFP_KERNEL); + if (!bss_prio) { + dev_err(adapter->dev, "%s: failed to alloc bss_prio\n", + __func__); + return -1; + } + + bss_prio->priv = priv; + INIT_LIST_HEAD(&bss_prio->list); + if (!adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur) + adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur = + bss_prio; + + spin_lock_irqsave(&adapter->bss_prio_tbl[priv->bss_priority] + .bss_prio_lock, flags); + list_add_tail(&bss_prio->list, + &adapter->bss_prio_tbl[priv->bss_priority] + .bss_prio_head); + spin_unlock_irqrestore(&adapter->bss_prio_tbl[priv->bss_priority] + .bss_prio_lock, flags); + + return status; +} + +/* + * This function initializes the private structure and sets default + * values to the members. + * + * Additionally, it also initializes all the locks and sets up all the + * lists. + */ +static int mwifiex_init_priv(struct mwifiex_private *priv) +{ + u32 i; + int ret = 0; + + priv->media_connected = false; + memset(priv->curr_addr, 0xff, ETH_ALEN); + + priv->pkt_tx_ctrl = 0; + priv->bss_mode = NL80211_IFTYPE_STATION; + priv->data_rate = 0; /* Initially indicate the rate as auto */ + priv->is_data_rate_auto = true; + priv->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR; + priv->data_avg_factor = DEFAULT_DATA_AVG_FACTOR; + + priv->sec_info.wep_status = MWIFIEX_802_11_WEP_DISABLED; + priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM; + priv->sec_info.encryption_mode = 0; + for (i = 0; i < ARRAY_SIZE(priv->wep_key); i++) + memset(&priv->wep_key[i], 0, sizeof(struct mwifiex_wep_key)); + priv->wep_key_curr_index = 0; + priv->curr_pkt_filter = HostCmd_ACT_MAC_RX_ON | HostCmd_ACT_MAC_TX_ON | + HostCmd_ACT_MAC_ETHERNETII_ENABLE; + + priv->beacon_period = 100; /* beacon interval */ ; + priv->attempted_bss_desc = NULL; + memset(&priv->curr_bss_params, 0, sizeof(priv->curr_bss_params)); + priv->listen_interval = MWIFIEX_DEFAULT_LISTEN_INTERVAL; + + memset(&priv->prev_ssid, 0, sizeof(priv->prev_ssid)); + memset(&priv->prev_bssid, 0, sizeof(priv->prev_bssid)); + memset(&priv->assoc_rsp_buf, 0, sizeof(priv->assoc_rsp_buf)); + priv->assoc_rsp_size = 0; + priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL; + priv->atim_window = 0; + priv->adhoc_state = ADHOC_IDLE; + priv->tx_power_level = 0; + priv->max_tx_power_level = 0; + priv->min_tx_power_level = 0; + priv->tx_rate = 0; + priv->rxpd_htinfo = 0; + priv->rxpd_rate = 0; + priv->rate_bitmap = 0; + priv->data_rssi_last = 0; + priv->data_rssi_avg = 0; + priv->data_nf_avg = 0; + priv->data_nf_last = 0; + priv->bcn_rssi_last = 0; + priv->bcn_rssi_avg = 0; + priv->bcn_nf_avg = 0; + priv->bcn_nf_last = 0; + memset(&priv->wpa_ie, 0, sizeof(priv->wpa_ie)); + memset(&priv->aes_key, 0, sizeof(priv->aes_key)); + priv->wpa_ie_len = 0; + priv->wpa_is_gtk_set = false; + + memset(&priv->assoc_tlv_buf, 0, sizeof(priv->assoc_tlv_buf)); + priv->assoc_tlv_buf_len = 0; + memset(&priv->wps, 0, sizeof(priv->wps)); + memset(&priv->gen_ie_buf, 0, sizeof(priv->gen_ie_buf)); + priv->gen_ie_buf_len = 0; + memset(priv->vs_ie, 0, sizeof(priv->vs_ie)); + + priv->wmm_required = true; + priv->wmm_enabled = false; + priv->wmm_qosinfo = 0; + priv->curr_bcn_buf = NULL; + priv->curr_bcn_size = 0; + + priv->scan_block = false; + + ret = mwifiex_add_bss_prio_tbl(priv); + + return ret; +} + +/* + * This function allocates buffers for members of the adapter + * structure. + * + * The memory allocated includes scan table, command buffers, and + * sleep confirm command buffer. In addition, the queues are + * also initialized. + */ +static int mwifiex_allocate_adapter(struct mwifiex_adapter *adapter) +{ + int ret = 0; + u32 buf_size; + struct mwifiex_bssdescriptor *temp_scan_table; + + /* Allocate buffer to store the BSSID list */ + buf_size = sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP; + temp_scan_table = kzalloc(buf_size, GFP_KERNEL); + if (!temp_scan_table) { + dev_err(adapter->dev, "%s: failed to alloc temp_scan_table\n", + __func__); + return -1; + } + + adapter->scan_table = temp_scan_table; + + /* Allocate command buffer */ + ret = mwifiex_alloc_cmd_buffer(adapter); + if (ret) { + dev_err(adapter->dev, "%s: failed to alloc cmd buffer\n", + __func__); + return -1; + } + + adapter->sleep_cfm = + dev_alloc_skb(sizeof(struct mwifiex_opt_sleep_confirm_buffer) + + INTF_HEADER_LEN); + + if (!adapter->sleep_cfm) { + dev_err(adapter->dev, "%s: failed to alloc sleep cfm" + " cmd buffer\n", __func__); + return -1; + } + skb_reserve(adapter->sleep_cfm, INTF_HEADER_LEN); + + return 0; +} + +/* + * This function initializes the adapter structure and sets default + * values to the members of adapter. + * + * This also initializes the WMM related parameters in the driver private + * structures. + */ +static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) +{ + struct mwifiex_opt_sleep_confirm_buffer *sleep_cfm_buf = NULL; + + skb_put(adapter->sleep_cfm, sizeof(sleep_cfm_buf->ps_cfm_sleep)); + sleep_cfm_buf = (struct mwifiex_opt_sleep_confirm_buffer *) + (adapter->sleep_cfm->data); + + adapter->cmd_sent = false; + adapter->data_sent = true; + adapter->cmd_resp_received = false; + adapter->event_received = false; + adapter->data_received = false; + + adapter->surprise_removed = false; + + adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING; + + adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM; + adapter->ps_state = PS_STATE_AWAKE; + adapter->need_to_wakeup = false; + + adapter->scan_mode = HostCmd_BSS_MODE_ANY; + adapter->specific_scan_time = MWIFIEX_SPECIFIC_SCAN_CHAN_TIME; + adapter->active_scan_time = MWIFIEX_ACTIVE_SCAN_CHAN_TIME; + adapter->passive_scan_time = MWIFIEX_PASSIVE_SCAN_CHAN_TIME; + + adapter->num_in_scan_table = 0; + memset(adapter->scan_table, 0, + (sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP)); + adapter->scan_probes = 1; + + memset(adapter->bcn_buf, 0, sizeof(adapter->bcn_buf)); + adapter->bcn_buf_end = adapter->bcn_buf; + + adapter->multiple_dtim = 1; + + adapter->local_listen_interval = 0; /* default value in firmware + will be used */ + + adapter->is_deep_sleep = false; + + adapter->delay_null_pkt = false; + adapter->delay_to_ps = 1000; + adapter->enhanced_ps_mode = PS_MODE_AUTO; + + adapter->gen_null_pkt = false; /* Disable NULL Pkg generation by + default */ + adapter->pps_uapsd_mode = false; /* Disable pps/uapsd mode by + default */ + adapter->pm_wakeup_card_req = false; + + adapter->pm_wakeup_fw_try = false; + + adapter->max_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; + adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; + adapter->curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; + + adapter->is_hs_configured = false; + adapter->hs_cfg.conditions = cpu_to_le32(HOST_SLEEP_CFG_COND_DEF); + adapter->hs_cfg.gpio = HOST_SLEEP_CFG_GPIO_DEF; + adapter->hs_cfg.gap = HOST_SLEEP_CFG_GAP_DEF; + adapter->hs_activated = false; + + memset(adapter->event_body, 0, sizeof(adapter->event_body)); + adapter->hw_dot_11n_dev_cap = 0; + adapter->hw_dev_mcs_support = 0; + adapter->chan_offset = 0; + adapter->adhoc_11n_enabled = false; + + mwifiex_wmm_init(adapter); + + if (adapter->sleep_cfm) { + memset(&sleep_cfm_buf->ps_cfm_sleep, 0, + adapter->sleep_cfm->len); + sleep_cfm_buf->ps_cfm_sleep.command = + cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH); + sleep_cfm_buf->ps_cfm_sleep.size = + cpu_to_le16(adapter->sleep_cfm->len); + sleep_cfm_buf->ps_cfm_sleep.result = 0; + sleep_cfm_buf->ps_cfm_sleep.action = cpu_to_le16(SLEEP_CONFIRM); + sleep_cfm_buf->ps_cfm_sleep.resp_ctrl = + cpu_to_le16(RESP_NEEDED); + } + memset(&adapter->sleep_params, 0, sizeof(adapter->sleep_params)); + memset(&adapter->sleep_period, 0, sizeof(adapter->sleep_period)); + adapter->tx_lock_flag = false; + adapter->null_pkt_interval = 0; + adapter->fw_bands = 0; + adapter->config_bands = 0; + adapter->adhoc_start_band = 0; + adapter->scan_channels = NULL; + adapter->fw_release_number = 0; + adapter->fw_cap_info = 0; + memset(&adapter->upld_buf, 0, sizeof(adapter->upld_buf)); + adapter->event_cause = 0; + adapter->region_code = 0; + adapter->bcn_miss_time_out = DEFAULT_BCN_MISS_TIMEOUT; + adapter->adhoc_awake_period = 0; + memset(&adapter->arp_filter, 0, sizeof(adapter->arp_filter)); + adapter->arp_filter_size = 0; + + return; +} + +/* + * This function frees the adapter structure. + * + * The freeing operation is done recursively, by canceling all + * pending commands, freeing the member buffers previously + * allocated (command buffers, scan table buffer, sleep confirm + * command buffer), stopping the timers and calling the cleanup + * routines for every interface, before the actual adapter + * structure is freed. + */ +static void +mwifiex_free_adapter(struct mwifiex_adapter *adapter) +{ + if (!adapter) { + pr_err("%s: adapter is NULL\n", __func__); + return; + } + + mwifiex_cancel_all_pending_cmd(adapter); + + /* Free lock variables */ + mwifiex_free_lock_list(adapter); + + /* Free command buffer */ + dev_dbg(adapter->dev, "info: free cmd buffer\n"); + mwifiex_free_cmd_buffer(adapter); + + del_timer(&adapter->cmd_timer); + + dev_dbg(adapter->dev, "info: free scan table\n"); + kfree(adapter->scan_table); + adapter->scan_table = NULL; + + adapter->if_ops.cleanup_if(adapter); + + dev_kfree_skb_any(adapter->sleep_cfm); + + return; +} + +/* + * This function intializes the lock variables and + * the list heads. + */ +int mwifiex_init_lock_list(struct mwifiex_adapter *adapter) +{ + struct mwifiex_private *priv = NULL; + s32 i = 0; + u32 j = 0; + + spin_lock_init(&adapter->mwifiex_lock); + spin_lock_init(&adapter->int_lock); + spin_lock_init(&adapter->main_proc_lock); + spin_lock_init(&adapter->mwifiex_cmd_lock); + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + priv = adapter->priv[i]; + spin_lock_init(&priv->rx_pkt_lock); + spin_lock_init(&priv->wmm.ra_list_spinlock); + spin_lock_init(&priv->curr_bcn_buf_lock); + } + } + + /* Initialize cmd_free_q */ + INIT_LIST_HEAD(&adapter->cmd_free_q); + /* Initialize cmd_pending_q */ + INIT_LIST_HEAD(&adapter->cmd_pending_q); + /* Initialize scan_pending_q */ + INIT_LIST_HEAD(&adapter->scan_pending_q); + + spin_lock_init(&adapter->cmd_free_q_lock); + spin_lock_init(&adapter->cmd_pending_q_lock); + spin_lock_init(&adapter->scan_pending_q_lock); + + for (i = 0; i < adapter->priv_num; ++i) { + INIT_LIST_HEAD(&adapter->bss_prio_tbl[i].bss_prio_head); + adapter->bss_prio_tbl[i].bss_prio_cur = NULL; + spin_lock_init(&adapter->bss_prio_tbl[i].bss_prio_lock); + } + + for (i = 0; i < adapter->priv_num; i++) { + if (!adapter->priv[i]) + continue; + priv = adapter->priv[i]; + for (j = 0; j < MAX_NUM_TID; ++j) { + INIT_LIST_HEAD(&priv->wmm.tid_tbl_ptr[j].ra_list); + spin_lock_init(&priv->wmm.tid_tbl_ptr[j].tid_tbl_lock); + } + INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr); + INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr); + + spin_lock_init(&priv->tx_ba_stream_tbl_lock); + spin_lock_init(&priv->rx_reorder_tbl_lock); + } + + return 0; +} + +/* + * This function releases the lock variables and frees the locks and + * associated locks. + */ +void mwifiex_free_lock_list(struct mwifiex_adapter *adapter) +{ + struct mwifiex_private *priv = NULL; + s32 i = 0; + s32 j = 0; + + /* Free lists */ + list_del(&adapter->cmd_free_q); + list_del(&adapter->cmd_pending_q); + list_del(&adapter->scan_pending_q); + + for (i = 0; i < adapter->priv_num; i++) + list_del(&adapter->bss_prio_tbl[i].bss_prio_head); + + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + priv = adapter->priv[i]; + for (j = 0; j < MAX_NUM_TID; ++j) + list_del(&priv->wmm.tid_tbl_ptr[j].ra_list); + list_del(&priv->tx_ba_stream_tbl_ptr); + list_del(&priv->rx_reorder_tbl_ptr); + } + } + + return; +} + +/* + * This function initializes the firmware. + * + * The following operations are performed sequentially - + * - Allocate adapter structure + * - Initialize the adapter structure + * - Initialize the private structure + * - Add BSS priority tables to the adapter structure + * - For each interface, send the init commands to firmware + * - Send the first command in command pending queue, if available + */ +int mwifiex_init_fw(struct mwifiex_adapter *adapter) +{ + int ret = 0; + struct mwifiex_private *priv = NULL; + u8 i = 0; + u8 first_sta = true; + int is_cmd_pend_q_empty; + unsigned long flags; + + adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING; + + /* Allocate memory for member of adapter structure */ + ret = mwifiex_allocate_adapter(adapter); + if (ret) + return -1; + + /* Initialize adapter structure */ + mwifiex_init_adapter(adapter); + + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + priv = adapter->priv[i]; + + /* Initialize private structure */ + ret = mwifiex_init_priv(priv); + if (ret) + return -1; + } + } + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + ret = mwifiex_sta_init_cmd(adapter->priv[i], first_sta); + if (ret == -1) + return -1; + + first_sta = false; + } + } + + spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); + is_cmd_pend_q_empty = list_empty(&adapter->cmd_pending_q); + spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); + if (!is_cmd_pend_q_empty) { + /* Send the first command in queue and return */ + if (mwifiex_main_process(adapter) != -1) + ret = -EINPROGRESS; + } else { + adapter->hw_status = MWIFIEX_HW_STATUS_READY; + } + + return ret; +} + +/* + * This function deletes the BSS priority tables. + * + * The function traverses through all the allocated BSS priority nodes + * in every BSS priority table and frees them. + */ +static void mwifiex_delete_bss_prio_tbl(struct mwifiex_private *priv) +{ + int i; + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_bss_prio_node *bssprio_node = NULL, *tmp_node = NULL, + **cur = NULL; + struct list_head *head; + spinlock_t *lock; + unsigned long flags; + + for (i = 0; i < adapter->priv_num; ++i) { + head = &adapter->bss_prio_tbl[i].bss_prio_head; + cur = &adapter->bss_prio_tbl[i].bss_prio_cur; + lock = &adapter->bss_prio_tbl[i].bss_prio_lock; + dev_dbg(adapter->dev, "info: delete BSS priority table," + " index = %d, i = %d, head = %p, cur = %p\n", + priv->bss_index, i, head, *cur); + if (*cur) { + spin_lock_irqsave(lock, flags); + if (list_empty(head)) { + spin_unlock_irqrestore(lock, flags); + continue; + } + bssprio_node = list_first_entry(head, + struct mwifiex_bss_prio_node, list); + spin_unlock_irqrestore(lock, flags); + + list_for_each_entry_safe(bssprio_node, tmp_node, head, + list) { + if (bssprio_node->priv == priv) { + dev_dbg(adapter->dev, "info: Delete " + "node %p, next = %p\n", + bssprio_node, tmp_node); + spin_lock_irqsave(lock, flags); + list_del(&bssprio_node->list); + spin_unlock_irqrestore(lock, flags); + kfree(bssprio_node); + } + } + *cur = (struct mwifiex_bss_prio_node *)head; + } + } +} + +/* + * This function is used to shutdown the driver. + * + * The following operations are performed sequentially - + * - Check if already shut down + * - Make sure the main process has stopped + * - Clean up the Tx and Rx queues + * - Delete BSS priority tables + * - Free the adapter + * - Notify completion + */ +int +mwifiex_shutdown_drv(struct mwifiex_adapter *adapter) +{ + int ret = -EINPROGRESS; + struct mwifiex_private *priv = NULL; + s32 i = 0; + unsigned long flags; + + /* mwifiex already shutdown */ + if (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY) + return 0; + + adapter->hw_status = MWIFIEX_HW_STATUS_CLOSING; + /* wait for mwifiex_process to complete */ + if (adapter->mwifiex_processing) { + dev_warn(adapter->dev, "main process is still running\n"); + return ret; + } + + /* shut down mwifiex */ + dev_dbg(adapter->dev, "info: shutdown mwifiex...\n"); + + /* Clean up Tx/Rx queues and delete BSS priority table */ + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + priv = adapter->priv[i]; + + mwifiex_clean_txrx(priv); + mwifiex_delete_bss_prio_tbl(priv); + } + } + + spin_lock_irqsave(&adapter->mwifiex_lock, flags); + + /* Free adapter structure */ + mwifiex_free_adapter(adapter); + + spin_unlock_irqrestore(&adapter->mwifiex_lock, flags); + + /* Notify completion */ + ret = mwifiex_shutdown_fw_complete(adapter); + + return ret; +} + +/* + * This function downloads the firmware to the card. + * + * The actual download is preceded by two sanity checks - + * - Check if firmware is already running + * - Check if the interface is the winner to download the firmware + * + * ...and followed by another - + * - Check if the firmware is downloaded successfully + * + * After download is successfully completed, the host interrupts are enabled. + */ +int mwifiex_dnld_fw(struct mwifiex_adapter *adapter, + struct mwifiex_fw_image *pmfw) +{ + int ret = 0; + u32 poll_num = 1; + int winner; + + /* Check if firmware is already running */ + ret = adapter->if_ops.check_fw_status(adapter, poll_num, &winner); + if (!ret) { + dev_notice(adapter->dev, + "WLAN FW already running! Skip FW download\n"); + goto done; + } + poll_num = MAX_FIRMWARE_POLL_TRIES; + + /* Check if we are the winner for downloading FW */ + if (!winner) { + dev_notice(adapter->dev, + "Other interface already running!" + " Skip FW download\n"); + poll_num = MAX_MULTI_INTERFACE_POLL_TRIES; + goto poll_fw; + } + if (pmfw) { + /* Download firmware with helper */ + ret = adapter->if_ops.prog_fw(adapter, pmfw); + if (ret) { + dev_err(adapter->dev, "prog_fw failed ret=%#x\n", ret); + return ret; + } + } + +poll_fw: + /* Check if the firmware is downloaded successfully or not */ + ret = adapter->if_ops.check_fw_status(adapter, poll_num, NULL); + if (ret) { + dev_err(adapter->dev, "FW failed to be active in time\n"); + return -1; + } +done: + /* re-enable host interrupt for mwifiex after fw dnld is successful */ + adapter->if_ops.enable_int(adapter); + return ret; +} diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h new file mode 100644 index 000000000000..703a6d12ebf3 --- /dev/null +++ b/drivers/net/wireless/mwifiex/ioctl.h @@ -0,0 +1,411 @@ +/* + * Marvell Wireless LAN device driver: ioctl data structures & APIs + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#ifndef _MWIFIEX_IOCTL_H_ +#define _MWIFIEX_IOCTL_H_ + +#include <net/mac80211.h> + +enum { + MWIFIEX_SCAN_MODE_UNCHANGED = 0, + MWIFIEX_SCAN_MODE_BSS, + MWIFIEX_SCAN_MODE_IBSS, + MWIFIEX_SCAN_MODE_ANY +}; + +enum { + MWIFIEX_SCAN_TYPE_UNCHANGED = 0, + MWIFIEX_SCAN_TYPE_ACTIVE, + MWIFIEX_SCAN_TYPE_PASSIVE +}; + +struct mwifiex_get_scan_table_fixed { + u8 bssid[ETH_ALEN]; + u8 channel; + u8 rssi; + long long network_tsf; +}; + +struct mwifiex_scan_time_params { + u32 specific_scan_time; + u32 active_scan_time; + u32 passive_scan_time; +}; + +struct mwifiex_user_scan { + u32 scan_cfg_len; + u8 scan_cfg_buf[1]; +}; + +struct mwifiex_scan_req { + u32 scan_mode; + u32 scan_type; + struct mwifiex_802_11_ssid scan_ssid; + struct mwifiex_scan_time_params scan_time; + struct mwifiex_user_scan user_scan; +}; + +struct mwifiex_scan_resp { + u32 num_in_scan_table; + u8 *scan_table; +}; + +#define MWIFIEX_PROMISC_MODE 1 +#define MWIFIEX_MULTICAST_MODE 2 +#define MWIFIEX_ALL_MULTI_MODE 4 +#define MWIFIEX_MAX_MULTICAST_LIST_SIZE 32 + +struct mwifiex_multicast_list { + u32 mode; + u32 num_multicast_addr; + u8 mac_list[MWIFIEX_MAX_MULTICAST_LIST_SIZE][ETH_ALEN]; +}; + +#define MWIFIEX_MAX_CHANNEL_NUM 128 + +struct mwifiex_chan_freq { + u32 channel; + u32 freq; +}; + +struct mwifiex_chan_list { + u32 num_of_chan; + struct mwifiex_chan_freq cf[MWIFIEX_MAX_CHANNEL_NUM]; +}; + +struct mwifiex_ssid_bssid { + struct mwifiex_802_11_ssid ssid; + u8 bssid[ETH_ALEN]; +}; + +enum { + BAND_B = 1, + BAND_G = 2, + BAND_A = 4, + BAND_GN = 8, + BAND_AN = 16, +}; + +#define NO_SEC_CHANNEL 0 +#define SEC_CHANNEL_ABOVE 1 +#define SEC_CHANNEL_BELOW 3 + +struct mwifiex_ds_band_cfg { + u32 config_bands; + u32 adhoc_start_band; + u32 adhoc_channel; + u32 sec_chan_offset; +}; + +enum { + ADHOC_IDLE, + ADHOC_STARTED, + ADHOC_JOINED, + ADHOC_COALESCED +}; + +struct mwifiex_ds_get_stats { + u32 mcast_tx_frame; + u32 failed; + u32 retry; + u32 multi_retry; + u32 frame_dup; + u32 rts_success; + u32 rts_failure; + u32 ack_failure; + u32 rx_frag; + u32 mcast_rx_frame; + u32 fcs_error; + u32 tx_frame; + u32 wep_icv_error[4]; +}; + +#define BCN_RSSI_LAST_MASK 0x00000001 +#define BCN_RSSI_AVG_MASK 0x00000002 +#define DATA_RSSI_LAST_MASK 0x00000004 +#define DATA_RSSI_AVG_MASK 0x00000008 +#define BCN_SNR_LAST_MASK 0x00000010 +#define BCN_SNR_AVG_MASK 0x00000020 +#define DATA_SNR_LAST_MASK 0x00000040 +#define DATA_SNR_AVG_MASK 0x00000080 +#define BCN_NF_LAST_MASK 0x00000100 +#define BCN_NF_AVG_MASK 0x00000200 +#define DATA_NF_LAST_MASK 0x00000400 +#define DATA_NF_AVG_MASK 0x00000800 +#define ALL_RSSI_INFO_MASK 0x00000fff + +struct mwifiex_ds_get_signal { + /* + * Bit0: Last Beacon RSSI, Bit1: Average Beacon RSSI, + * Bit2: Last Data RSSI, Bit3: Average Data RSSI, + * Bit4: Last Beacon SNR, Bit5: Average Beacon SNR, + * Bit6: Last Data SNR, Bit7: Average Data SNR, + * Bit8: Last Beacon NF, Bit9: Average Beacon NF, + * Bit10: Last Data NF, Bit11: Average Data NF + */ + u16 selector; + s16 bcn_rssi_last; + s16 bcn_rssi_avg; + s16 data_rssi_last; + s16 data_rssi_avg; + s16 bcn_snr_last; + s16 bcn_snr_avg; + s16 data_snr_last; + s16 data_snr_avg; + s16 bcn_nf_last; + s16 bcn_nf_avg; + s16 data_nf_last; + s16 data_nf_avg; +}; + +struct mwifiex_fw_info { + u32 fw_ver; + u8 mac_addr[ETH_ALEN]; +}; + +#define MWIFIEX_MAX_VER_STR_LEN 128 + +struct mwifiex_ver_ext { + u32 version_str_sel; + char version_str[MWIFIEX_MAX_VER_STR_LEN]; +}; + +struct mwifiex_bss_info { + u32 bss_mode; + struct mwifiex_802_11_ssid ssid; + u32 scan_table_idx; + u32 bss_chan; + u32 region_code; + u32 media_connected; + u32 max_power_level; + u32 min_power_level; + u32 adhoc_state; + signed int bcn_nf_last; + u32 wep_status; + u32 is_hs_configured; + u32 is_deep_sleep; + u8 bssid[ETH_ALEN]; +}; + +#define MAX_NUM_TID 8 + +#define MAX_RX_WINSIZE 64 + +struct mwifiex_ds_rx_reorder_tbl { + u16 tid; + u8 ta[ETH_ALEN]; + u32 start_win; + u32 win_size; + u32 buffer[MAX_RX_WINSIZE]; +}; + +struct mwifiex_ds_tx_ba_stream_tbl { + u16 tid; + u8 ra[ETH_ALEN]; +}; + +#define DBG_CMD_NUM 5 + +struct mwifiex_debug_info { + u32 int_counter; + u32 packets_out[MAX_NUM_TID]; + u32 max_tx_buf_size; + u32 tx_buf_size; + u32 curr_tx_buf_size; + u32 tx_tbl_num; + struct mwifiex_ds_tx_ba_stream_tbl + tx_tbl[MWIFIEX_MAX_TX_BASTREAM_SUPPORTED]; + u32 rx_tbl_num; + struct mwifiex_ds_rx_reorder_tbl rx_tbl + [MWIFIEX_MAX_RX_BASTREAM_SUPPORTED]; + u16 ps_mode; + u32 ps_state; + u8 is_deep_sleep; + u8 pm_wakeup_card_req; + u32 pm_wakeup_fw_try; + u8 is_hs_configured; + u8 hs_activated; + u32 num_cmd_host_to_card_failure; + u32 num_cmd_sleep_cfm_host_to_card_failure; + u32 num_tx_host_to_card_failure; + u32 num_event_deauth; + u32 num_event_disassoc; + u32 num_event_link_lost; + u32 num_cmd_deauth; + u32 num_cmd_assoc_success; + u32 num_cmd_assoc_failure; + u32 num_tx_timeout; + u32 num_cmd_timeout; + u16 timeout_cmd_id; + u16 timeout_cmd_act; + u16 last_cmd_id[DBG_CMD_NUM]; + u16 last_cmd_act[DBG_CMD_NUM]; + u16 last_cmd_index; + u16 last_cmd_resp_id[DBG_CMD_NUM]; + u16 last_cmd_resp_index; + u16 last_event[DBG_CMD_NUM]; + u16 last_event_index; + u8 data_sent; + u8 cmd_sent; + u8 cmd_resp_received; + u8 event_received; +}; + +#define MWIFIEX_KEY_INDEX_UNICAST 0x40000000 +#define MWIFIEX_MAX_KEY_LENGTH 32 +#define WAPI_RXPN_LEN 16 + +struct mwifiex_ds_encrypt_key { + u32 key_disable; + u32 key_index; + u32 key_len; + u8 key_material[MWIFIEX_MAX_KEY_LENGTH]; + u8 mac_addr[ETH_ALEN]; + u32 is_wapi_key; + u8 wapi_rxpn[WAPI_RXPN_LEN]; +}; + +struct mwifiex_rate_cfg { + u32 action; + u32 is_rate_auto; + u32 rate; +}; + +struct mwifiex_data_rate { + u32 tx_data_rate; + u32 rx_data_rate; +}; + +struct mwifiex_power_cfg { + u32 is_power_auto; + u32 power_level; +}; + +struct mwifiex_ds_hs_cfg { + u32 is_invoke_hostcmd; + /* Bit0: non-unicast data + * Bit1: unicast data + * Bit2: mac events + * Bit3: magic packet + */ + u32 conditions; + u32 gpio; + u32 gap; +}; + +#define DEEP_SLEEP_ON 1 +#define DEEP_SLEEP_OFF 0 + +#define DEEP_SLEEP_IDLE_TIME 100 + +struct mwifiex_ds_auto_ds { + u16 auto_ds; + u16 idle_time; +}; + +#define PS_MODE_UNCHANGED 0 +#define PS_MODE_AUTO 1 +#define PS_MODE_POLL 2 +#define PS_MODE_NULL 3 + + +struct mwifiex_ds_pm_cfg { + union { + u32 ps_mode; + struct mwifiex_ds_hs_cfg hs_cfg; + struct mwifiex_ds_auto_ds auto_deep_sleep; + u32 sleep_period; + } param; +}; + +struct mwifiex_ioctl_wmm_queue_status_ac { + u8 wmm_acm; + u8 flow_required; + u8 flow_created; + u8 disabled; +}; + +struct mwifiex_ds_wmm_queue_status { + struct mwifiex_ioctl_wmm_queue_status_ac + ac_status[IEEE80211_MAX_QUEUES]; +}; + +struct mwifiex_ds_11n_tx_cfg { + u16 tx_htcap; + u16 tx_htinfo; +}; + +struct mwifiex_ds_11n_amsdu_aggr_ctrl { + u16 enable; + u16 curr_buf_size; +}; + +#define MWIFIEX_NUM_OF_CMD_BUFFER 20 +#define MWIFIEX_SIZE_OF_CMD_BUFFER 2048 + +enum { + MWIFIEX_IE_TYPE_GEN_IE = 0, + MWIFIEX_IE_TYPE_ARP_FILTER, +}; + +enum { + MWIFIEX_REG_MAC = 1, + MWIFIEX_REG_BBP, + MWIFIEX_REG_RF, + MWIFIEX_REG_PMIC, + MWIFIEX_REG_CAU, +}; + +struct mwifiex_ds_reg_rw { + __le32 type; + __le32 offset; + __le32 value; +}; + +#define MAX_EEPROM_DATA 256 + +struct mwifiex_ds_read_eeprom { + __le16 offset; + __le16 byte_count; + u8 value[MAX_EEPROM_DATA]; +}; + +struct mwifiex_ds_misc_gen_ie { + u32 type; + u32 len; + u8 ie_data[IW_CUSTOM_MAX]; +}; + +struct mwifiex_ds_misc_cmd { + u32 len; + u8 cmd[MWIFIEX_SIZE_OF_CMD_BUFFER]; +}; + +#define MWIFIEX_MAX_VSIE_LEN (256) +#define MWIFIEX_MAX_VSIE_NUM (8) +#define MWIFIEX_VSIE_MASK_SCAN 0x01 +#define MWIFIEX_VSIE_MASK_ASSOC 0x02 +#define MWIFIEX_VSIE_MASK_ADHOC 0x04 + +enum { + MWIFIEX_FUNC_INIT = 1, + MWIFIEX_FUNC_SHUTDOWN, +}; + +#endif /* !_MWIFIEX_IOCTL_H_ */ diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c new file mode 100644 index 000000000000..7a9e0b5962ed --- /dev/null +++ b/drivers/net/wireless/mwifiex/join.c @@ -0,0 +1,1462 @@ +/* + * Marvell Wireless LAN device driver: association and ad-hoc start/join + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" + +#define CAPINFO_MASK (~(BIT(15) | BIT(14) | BIT(12) | BIT(11) | BIT(9))) + +/* + * Append a generic IE as a pass through TLV to a TLV buffer. + * + * This function is called from the network join command preparation routine. + * + * If the IE buffer has been setup by the application, this routine appends + * the buffer as a pass through TLV type to the request. + */ +static int +mwifiex_cmd_append_generic_ie(struct mwifiex_private *priv, u8 **buffer) +{ + int ret_len = 0; + struct mwifiex_ie_types_header ie_header; + + /* Null Checks */ + if (!buffer) + return 0; + if (!(*buffer)) + return 0; + + /* + * If there is a generic ie buffer setup, append it to the return + * parameter buffer pointer. + */ + if (priv->gen_ie_buf_len) { + dev_dbg(priv->adapter->dev, "info: %s: append generic %d to %p\n", + __func__, priv->gen_ie_buf_len, *buffer); + + /* Wrap the generic IE buffer with a pass through TLV type */ + ie_header.type = cpu_to_le16(TLV_TYPE_PASSTHROUGH); + ie_header.len = cpu_to_le16(priv->gen_ie_buf_len); + memcpy(*buffer, &ie_header, sizeof(ie_header)); + + /* Increment the return size and the return buffer pointer + param */ + *buffer += sizeof(ie_header); + ret_len += sizeof(ie_header); + + /* Copy the generic IE buffer to the output buffer, advance + pointer */ + memcpy(*buffer, priv->gen_ie_buf, priv->gen_ie_buf_len); + + /* Increment the return size and the return buffer pointer + param */ + *buffer += priv->gen_ie_buf_len; + ret_len += priv->gen_ie_buf_len; + + /* Reset the generic IE buffer */ + priv->gen_ie_buf_len = 0; + } + + /* return the length appended to the buffer */ + return ret_len; +} + +/* + * Append TSF tracking info from the scan table for the target AP. + * + * This function is called from the network join command preparation routine. + * + * The TSF table TSF sent to the firmware contains two TSF values: + * - The TSF of the target AP from its previous beacon/probe response + * - The TSF timestamp of our local MAC at the time we observed the + * beacon/probe response. + * + * The firmware uses the timestamp values to set an initial TSF value + * in the MAC for the new association after a reassociation attempt. + */ +static int +mwifiex_cmd_append_tsf_tlv(struct mwifiex_private *priv, u8 **buffer, + struct mwifiex_bssdescriptor *bss_desc) +{ + struct mwifiex_ie_types_tsf_timestamp tsf_tlv; + long long tsf_val; + + /* Null Checks */ + if (buffer == NULL) + return 0; + if (*buffer == NULL) + return 0; + + memset(&tsf_tlv, 0x00, sizeof(struct mwifiex_ie_types_tsf_timestamp)); + + tsf_tlv.header.type = cpu_to_le16(TLV_TYPE_TSFTIMESTAMP); + tsf_tlv.header.len = cpu_to_le16(2 * sizeof(tsf_val)); + + memcpy(*buffer, &tsf_tlv, sizeof(tsf_tlv.header)); + *buffer += sizeof(tsf_tlv.header); + + memcpy(*buffer, &tsf_val, sizeof(tsf_val)); + *buffer += sizeof(tsf_val); + + memcpy(&tsf_val, bss_desc->time_stamp, sizeof(tsf_val)); + + dev_dbg(priv->adapter->dev, "info: %s: TSF offset calc: %016llx - " + "%016llx\n", __func__, tsf_val, bss_desc->network_tsf); + + memcpy(*buffer, &tsf_val, sizeof(tsf_val)); + *buffer += sizeof(tsf_val); + + return sizeof(tsf_tlv.header) + (2 * sizeof(tsf_val)); +} + +/* + * This function finds out the common rates between rate1 and rate2. + * + * It will fill common rates in rate1 as output if found. + * + * NOTE: Setting the MSB of the basic rates needs to be taken + * care of, either before or after calling this function. + */ +static int mwifiex_get_common_rates(struct mwifiex_private *priv, u8 *rate1, + u32 rate1_size, u8 *rate2, u32 rate2_size) +{ + int ret = 0; + u8 *ptr = rate1; + u8 *tmp = NULL; + u32 i, j; + + tmp = kmalloc(rate1_size, GFP_KERNEL); + if (!tmp) { + dev_err(priv->adapter->dev, "failed to alloc tmp buf\n"); + return -ENOMEM; + } + + memcpy(tmp, rate1, rate1_size); + memset(rate1, 0, rate1_size); + + for (i = 0; rate2[i] && i < rate2_size; i++) { + for (j = 0; tmp[j] && j < rate1_size; j++) { + /* Check common rate, excluding the bit for + basic rate */ + if ((rate2[i] & 0x7F) == (tmp[j] & 0x7F)) { + *rate1++ = tmp[j]; + break; + } + } + } + + dev_dbg(priv->adapter->dev, "info: Tx data rate set to %#x\n", + priv->data_rate); + + if (!priv->is_data_rate_auto) { + while (*ptr) { + if ((*ptr & 0x7f) == priv->data_rate) { + ret = 0; + goto done; + } + ptr++; + } + dev_err(priv->adapter->dev, "previously set fixed data rate %#x" + " is not compatible with the network\n", + priv->data_rate); + + ret = -1; + goto done; + } + + ret = 0; +done: + kfree(tmp); + return ret; +} + +/* + * This function creates the intersection of the rates supported by a + * target BSS and our adapter settings for use in an assoc/join command. + */ +static int +mwifiex_setup_rates_from_bssdesc(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc, + u8 *out_rates, u32 *out_rates_size) +{ + u8 card_rates[MWIFIEX_SUPPORTED_RATES]; + u32 card_rates_size = 0; + + /* Copy AP supported rates */ + memcpy(out_rates, bss_desc->supported_rates, MWIFIEX_SUPPORTED_RATES); + /* Get the STA supported rates */ + card_rates_size = mwifiex_get_active_data_rates(priv, card_rates); + /* Get the common rates between AP and STA supported rates */ + if (mwifiex_get_common_rates(priv, out_rates, MWIFIEX_SUPPORTED_RATES, + card_rates, card_rates_size)) { + *out_rates_size = 0; + dev_err(priv->adapter->dev, "%s: cannot get common rates\n", + __func__); + return -1; + } + + *out_rates_size = + min_t(size_t, strlen(out_rates), MWIFIEX_SUPPORTED_RATES); + + return 0; +} + +/* + * This function updates the scan entry TSF timestamps to reflect + * a new association. + */ +static void +mwifiex_update_tsf_timestamps(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *new_bss_desc) +{ + struct mwifiex_adapter *adapter = priv->adapter; + u32 table_idx; + long long new_tsf_base; + signed long long tsf_delta; + + memcpy(&new_tsf_base, new_bss_desc->time_stamp, sizeof(new_tsf_base)); + + tsf_delta = new_tsf_base - new_bss_desc->network_tsf; + + dev_dbg(adapter->dev, "info: TSF: update TSF timestamps, " + "0x%016llx -> 0x%016llx\n", + new_bss_desc->network_tsf, new_tsf_base); + + for (table_idx = 0; table_idx < adapter->num_in_scan_table; + table_idx++) + adapter->scan_table[table_idx].network_tsf += tsf_delta; +} + +/* + * This function appends a WAPI IE. + * + * This function is called from the network join command preparation routine. + * + * If the IE buffer has been setup by the application, this routine appends + * the buffer as a WAPI TLV type to the request. + */ +static int +mwifiex_cmd_append_wapi_ie(struct mwifiex_private *priv, u8 **buffer) +{ + int retLen = 0; + struct mwifiex_ie_types_header ie_header; + + /* Null Checks */ + if (buffer == NULL) + return 0; + if (*buffer == NULL) + return 0; + + /* + * If there is a wapi ie buffer setup, append it to the return + * parameter buffer pointer. + */ + if (priv->wapi_ie_len) { + dev_dbg(priv->adapter->dev, "cmd: append wapi ie %d to %p\n", + priv->wapi_ie_len, *buffer); + + /* Wrap the generic IE buffer with a pass through TLV type */ + ie_header.type = cpu_to_le16(TLV_TYPE_WAPI_IE); + ie_header.len = cpu_to_le16(priv->wapi_ie_len); + memcpy(*buffer, &ie_header, sizeof(ie_header)); + + /* Increment the return size and the return buffer pointer + param */ + *buffer += sizeof(ie_header); + retLen += sizeof(ie_header); + + /* Copy the wapi IE buffer to the output buffer, advance + pointer */ + memcpy(*buffer, priv->wapi_ie, priv->wapi_ie_len); + + /* Increment the return size and the return buffer pointer + param */ + *buffer += priv->wapi_ie_len; + retLen += priv->wapi_ie_len; + + } + /* return the length appended to the buffer */ + return retLen; +} + +/* + * This function appends rsn ie tlv for wpa/wpa2 security modes. + * It is called from the network join command preparation routine. + */ +static int mwifiex_append_rsn_ie_wpa_wpa2(struct mwifiex_private *priv, + u8 **buffer) +{ + struct mwifiex_ie_types_rsn_param_set *rsn_ie_tlv; + int rsn_ie_len; + + if (!buffer || !(*buffer)) + return 0; + + rsn_ie_tlv = (struct mwifiex_ie_types_rsn_param_set *) (*buffer); + rsn_ie_tlv->header.type = cpu_to_le16((u16) priv->wpa_ie[0]); + rsn_ie_tlv->header.type = cpu_to_le16( + le16_to_cpu(rsn_ie_tlv->header.type) & 0x00FF); + rsn_ie_tlv->header.len = cpu_to_le16((u16) priv->wpa_ie[1]); + rsn_ie_tlv->header.len = cpu_to_le16(le16_to_cpu(rsn_ie_tlv->header.len) + & 0x00FF); + if (le16_to_cpu(rsn_ie_tlv->header.len) <= (sizeof(priv->wpa_ie) - 2)) + memcpy(rsn_ie_tlv->rsn_ie, &priv->wpa_ie[2], + le16_to_cpu(rsn_ie_tlv->header.len)); + else + return -1; + + rsn_ie_len = sizeof(rsn_ie_tlv->header) + + le16_to_cpu(rsn_ie_tlv->header.len); + *buffer += rsn_ie_len; + + return rsn_ie_len; +} + +/* + * This function prepares command for association. + * + * This sets the following parameters - + * - Peer MAC address + * - Listen interval + * - Beacon interval + * - Capability information + * + * ...and the following TLVs, as required - + * - SSID TLV + * - PHY TLV + * - SS TLV + * - Rates TLV + * - Authentication TLV + * - Channel TLV + * - WPA/WPA2 IE + * - 11n TLV + * - Vendor specific TLV + * - WMM TLV + * - WAPI IE + * - Generic IE + * - TSF TLV + * + * Preparation also includes - + * - Setting command ID and proper size + * - Ensuring correct endian-ness + */ +int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf) +{ + struct host_cmd_ds_802_11_associate *assoc = &cmd->params.associate; + struct mwifiex_bssdescriptor *bss_desc; + struct mwifiex_ie_types_ssid_param_set *ssid_tlv; + struct mwifiex_ie_types_phy_param_set *phy_tlv; + struct mwifiex_ie_types_ss_param_set *ss_tlv; + struct mwifiex_ie_types_rates_param_set *rates_tlv; + struct mwifiex_ie_types_auth_type *auth_tlv; + struct mwifiex_ie_types_chan_list_param_set *chan_tlv; + u8 rates[MWIFIEX_SUPPORTED_RATES]; + u32 rates_size; + u16 tmp_cap; + u8 *pos; + int rsn_ie_len = 0; + + bss_desc = (struct mwifiex_bssdescriptor *) data_buf; + pos = (u8 *) assoc; + + mwifiex_cfg_tx_buf(priv, bss_desc); + + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_ASSOCIATE); + + /* Save so we know which BSS Desc to use in the response handler */ + priv->attempted_bss_desc = bss_desc; + + memcpy(assoc->peer_sta_addr, + bss_desc->mac_address, sizeof(assoc->peer_sta_addr)); + pos += sizeof(assoc->peer_sta_addr); + + /* Set the listen interval */ + assoc->listen_interval = cpu_to_le16(priv->listen_interval); + /* Set the beacon period */ + assoc->beacon_period = cpu_to_le16(bss_desc->beacon_period); + + pos += sizeof(assoc->cap_info_bitmap); + pos += sizeof(assoc->listen_interval); + pos += sizeof(assoc->beacon_period); + pos += sizeof(assoc->dtim_period); + + ssid_tlv = (struct mwifiex_ie_types_ssid_param_set *) pos; + ssid_tlv->header.type = cpu_to_le16(WLAN_EID_SSID); + ssid_tlv->header.len = cpu_to_le16((u16) bss_desc->ssid.ssid_len); + memcpy(ssid_tlv->ssid, bss_desc->ssid.ssid, + le16_to_cpu(ssid_tlv->header.len)); + pos += sizeof(ssid_tlv->header) + le16_to_cpu(ssid_tlv->header.len); + + phy_tlv = (struct mwifiex_ie_types_phy_param_set *) pos; + phy_tlv->header.type = cpu_to_le16(WLAN_EID_DS_PARAMS); + phy_tlv->header.len = cpu_to_le16(sizeof(phy_tlv->fh_ds.ds_param_set)); + memcpy(&phy_tlv->fh_ds.ds_param_set, + &bss_desc->phy_param_set.ds_param_set.current_chan, + sizeof(phy_tlv->fh_ds.ds_param_set)); + pos += sizeof(phy_tlv->header) + le16_to_cpu(phy_tlv->header.len); + + ss_tlv = (struct mwifiex_ie_types_ss_param_set *) pos; + ss_tlv->header.type = cpu_to_le16(WLAN_EID_CF_PARAMS); + ss_tlv->header.len = cpu_to_le16(sizeof(ss_tlv->cf_ibss.cf_param_set)); + pos += sizeof(ss_tlv->header) + le16_to_cpu(ss_tlv->header.len); + + /* Get the common rates supported between the driver and the BSS Desc */ + if (mwifiex_setup_rates_from_bssdesc + (priv, bss_desc, rates, &rates_size)) + return -1; + + /* Save the data rates into Current BSS state structure */ + priv->curr_bss_params.num_of_rates = rates_size; + memcpy(&priv->curr_bss_params.data_rates, rates, rates_size); + + /* Setup the Rates TLV in the association command */ + rates_tlv = (struct mwifiex_ie_types_rates_param_set *) pos; + rates_tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES); + rates_tlv->header.len = cpu_to_le16((u16) rates_size); + memcpy(rates_tlv->rates, rates, rates_size); + pos += sizeof(rates_tlv->header) + rates_size; + dev_dbg(priv->adapter->dev, "info: ASSOC_CMD: rates size = %d\n", + rates_size); + + /* Add the Authentication type to be used for Auth frames */ + auth_tlv = (struct mwifiex_ie_types_auth_type *) pos; + auth_tlv->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE); + auth_tlv->header.len = cpu_to_le16(sizeof(auth_tlv->auth_type)); + if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED) + auth_tlv->auth_type = cpu_to_le16( + (u16) priv->sec_info.authentication_mode); + else + auth_tlv->auth_type = cpu_to_le16(NL80211_AUTHTYPE_OPEN_SYSTEM); + + pos += sizeof(auth_tlv->header) + le16_to_cpu(auth_tlv->header.len); + + if (IS_SUPPORT_MULTI_BANDS(priv->adapter) + && !(ISSUPP_11NENABLED(priv->adapter->fw_cap_info) + && (!bss_desc->disable_11n) + && (priv->adapter->config_bands & BAND_GN + || priv->adapter->config_bands & BAND_AN) + && (bss_desc->bcn_ht_cap) + ) + ) { + /* Append a channel TLV for the channel the attempted AP was + found on */ + chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos; + chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); + chan_tlv->header.len = + cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set)); + + memset(chan_tlv->chan_scan_param, 0x00, + sizeof(struct mwifiex_chan_scan_param_set)); + chan_tlv->chan_scan_param[0].chan_number = + (bss_desc->phy_param_set.ds_param_set.current_chan); + dev_dbg(priv->adapter->dev, "info: Assoc: TLV Chan = %d\n", + chan_tlv->chan_scan_param[0].chan_number); + + chan_tlv->chan_scan_param[0].radio_type = + mwifiex_band_to_radio_type((u8) bss_desc->bss_band); + + dev_dbg(priv->adapter->dev, "info: Assoc: TLV Band = %d\n", + chan_tlv->chan_scan_param[0].radio_type); + pos += sizeof(chan_tlv->header) + + sizeof(struct mwifiex_chan_scan_param_set); + } + + if (!priv->wps.session_enable) { + if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) + rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos); + + if (rsn_ie_len == -1) + return -1; + } + + if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info) + && (!bss_desc->disable_11n) + && (priv->adapter->config_bands & BAND_GN + || priv->adapter->config_bands & BAND_AN)) + mwifiex_cmd_append_11n_tlv(priv, bss_desc, &pos); + + /* Append vendor specific IE TLV */ + mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_ASSOC, &pos); + + mwifiex_wmm_process_association_req(priv, &pos, &bss_desc->wmm_ie, + bss_desc->bcn_ht_cap); + if (priv->sec_info.wapi_enabled && priv->wapi_ie_len) + mwifiex_cmd_append_wapi_ie(priv, &pos); + + + mwifiex_cmd_append_generic_ie(priv, &pos); + + mwifiex_cmd_append_tsf_tlv(priv, &pos, bss_desc); + + cmd->size = cpu_to_le16((u16) (pos - (u8 *) assoc) + S_DS_GEN); + + /* Set the Capability info at last */ + tmp_cap = bss_desc->cap_info_bitmap; + + if (priv->adapter->config_bands == BAND_B) + tmp_cap &= ~WLAN_CAPABILITY_SHORT_SLOT_TIME; + + tmp_cap &= CAPINFO_MASK; + dev_dbg(priv->adapter->dev, "info: ASSOC_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n", + tmp_cap, CAPINFO_MASK); + assoc->cap_info_bitmap = cpu_to_le16(tmp_cap); + + return 0; +} + +/* + * Association firmware command response handler + * + * The response buffer for the association command has the following + * memory layout. + * + * For cases where an association response was not received (indicated + * by the CapInfo and AId field): + * + * .------------------------------------------------------------. + * | Header(4 * sizeof(t_u16)): Standard command response hdr | + * .------------------------------------------------------------. + * | cap_info/Error Return(t_u16): | + * | 0xFFFF(-1): Internal error | + * | 0xFFFE(-2): Authentication unhandled message | + * | 0xFFFD(-3): Authentication refused | + * | 0xFFFC(-4): Timeout waiting for AP response | + * .------------------------------------------------------------. + * | status_code(t_u16): | + * | If cap_info is -1: | + * | An internal firmware failure prevented the | + * | command from being processed. The status_code | + * | will be set to 1. | + * | | + * | If cap_info is -2: | + * | An authentication frame was received but was | + * | not handled by the firmware. IEEE Status | + * | code for the failure is returned. | + * | | + * | If cap_info is -3: | + * | An authentication frame was received and the | + * | status_code is the IEEE Status reported in the | + * | response. | + * | | + * | If cap_info is -4: | + * | (1) Association response timeout | + * | (2) Authentication response timeout | + * .------------------------------------------------------------. + * | a_id(t_u16): 0xFFFF | + * .------------------------------------------------------------. + * + * + * For cases where an association response was received, the IEEE + * standard association response frame is returned: + * + * .------------------------------------------------------------. + * | Header(4 * sizeof(t_u16)): Standard command response hdr | + * .------------------------------------------------------------. + * | cap_info(t_u16): IEEE Capability | + * .------------------------------------------------------------. + * | status_code(t_u16): IEEE Status Code | + * .------------------------------------------------------------. + * | a_id(t_u16): IEEE Association ID | + * .------------------------------------------------------------. + * | IEEE IEs(variable): Any received IEs comprising the | + * | remaining portion of a received | + * | association response frame. | + * .------------------------------------------------------------. + * + * For simplistic handling, the status_code field can be used to determine + * an association success (0) or failure (non-zero). + */ +int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, void *wq_buf) +{ + int ret = 0; + struct mwifiex_wait_queue *wait_queue = + (struct mwifiex_wait_queue *) wq_buf; + struct ieee_types_assoc_rsp *assoc_rsp; + struct mwifiex_bssdescriptor *bss_desc; + u8 enable_data = true; + + assoc_rsp = (struct ieee_types_assoc_rsp *) &resp->params; + + priv->assoc_rsp_size = min(le16_to_cpu(resp->size) - S_DS_GEN, + sizeof(priv->assoc_rsp_buf)); + + memcpy(priv->assoc_rsp_buf, &resp->params, priv->assoc_rsp_size); + + if (le16_to_cpu(assoc_rsp->status_code)) { + priv->adapter->dbg.num_cmd_assoc_failure++; + dev_err(priv->adapter->dev, "ASSOC_RESP: association failed, " + "status code = %d, error = 0x%x, a_id = 0x%x\n", + le16_to_cpu(assoc_rsp->status_code), + le16_to_cpu(assoc_rsp->cap_info_bitmap), + le16_to_cpu(assoc_rsp->a_id)); + + ret = -1; + goto done; + } + + /* Send a Media Connected event, according to the Spec */ + priv->media_connected = true; + + priv->adapter->ps_state = PS_STATE_AWAKE; + priv->adapter->pps_uapsd_mode = false; + priv->adapter->tx_lock_flag = false; + + /* Set the attempted BSSID Index to current */ + bss_desc = priv->attempted_bss_desc; + + dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: %s\n", + bss_desc->ssid.ssid); + + /* Make a copy of current BSSID descriptor */ + memcpy(&priv->curr_bss_params.bss_descriptor, + bss_desc, sizeof(struct mwifiex_bssdescriptor)); + + /* Update curr_bss_params */ + priv->curr_bss_params.bss_descriptor.channel + = bss_desc->phy_param_set.ds_param_set.current_chan; + + priv->curr_bss_params.band = (u8) bss_desc->bss_band; + + /* + * Adjust the timestamps in the scan table to be relative to the newly + * associated AP's TSF + */ + mwifiex_update_tsf_timestamps(priv, bss_desc); + + if (bss_desc->wmm_ie.vend_hdr.element_id == WLAN_EID_VENDOR_SPECIFIC) + priv->curr_bss_params.wmm_enabled = true; + else + priv->curr_bss_params.wmm_enabled = false; + + if ((priv->wmm_required || bss_desc->bcn_ht_cap) + && priv->curr_bss_params.wmm_enabled) + priv->wmm_enabled = true; + else + priv->wmm_enabled = false; + + priv->curr_bss_params.wmm_uapsd_enabled = false; + + if (priv->wmm_enabled) + priv->curr_bss_params.wmm_uapsd_enabled + = ((bss_desc->wmm_ie.qos_info_bitmap & + IEEE80211_WMM_IE_AP_QOSINFO_UAPSD) ? 1 : 0); + + dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: curr_pkt_filter is %#x\n", + priv->curr_pkt_filter); + if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) + priv->wpa_is_gtk_set = false; + + if (priv->wmm_enabled) { + /* Don't re-enable carrier until we get the WMM_GET_STATUS + event */ + enable_data = false; + } else { + /* Since WMM is not enabled, setup the queues with the + defaults */ + mwifiex_wmm_setup_queue_priorities(priv, NULL); + mwifiex_wmm_setup_ac_downgrade(priv); + } + + if (enable_data) + dev_dbg(priv->adapter->dev, + "info: post association, re-enabling data flow\n"); + + /* Reset SNR/NF/RSSI values */ + priv->data_rssi_last = 0; + priv->data_nf_last = 0; + priv->data_rssi_avg = 0; + priv->data_nf_avg = 0; + priv->bcn_rssi_last = 0; + priv->bcn_nf_last = 0; + priv->bcn_rssi_avg = 0; + priv->bcn_nf_avg = 0; + priv->rxpd_rate = 0; + priv->rxpd_htinfo = 0; + + mwifiex_save_curr_bcn(priv); + + priv->adapter->dbg.num_cmd_assoc_success++; + + dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: associated\n"); + + /* Add the ra_list here for infra mode as there will be only 1 ra + always */ + mwifiex_ralist_add(priv, + priv->curr_bss_params.bss_descriptor.mac_address); + + if (!netif_carrier_ok(priv->netdev)) + netif_carrier_on(priv->netdev); + if (netif_queue_stopped(priv->netdev)) + netif_wake_queue(priv->netdev); + + if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) + priv->scan_block = true; + +done: + /* Need to indicate IOCTL complete */ + if (wait_queue) { + if (ret) { + if (assoc_rsp->status_code) + wait_queue->status = + le16_to_cpu(assoc_rsp->status_code); + else + wait_queue->status = MWIFIEX_ERROR_ASSOC_FAIL; + } else { + wait_queue->status = MWIFIEX_ERROR_NO_ERROR; + } + } + + return ret; +} + +/* + * This function prepares command for ad-hoc start. + * + * Driver will fill up SSID, BSS mode, IBSS parameters, physical + * parameters, probe delay, and capability information. Firmware + * will fill up beacon period, basic rates and operational rates. + * + * In addition, the following TLVs are added - + * - Channel TLV + * - Vendor specific IE + * - WPA/WPA2 IE + * - HT Capabilities IE + * - HT Information IE + * + * Preparation also includes - + * - Setting command ID and proper size + * - Ensuring correct endian-ness + */ +int +mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, void *data_buf) +{ + int ret = 0, rsn_ie_len = 0; + struct mwifiex_adapter *adapter = priv->adapter; + struct host_cmd_ds_802_11_ad_hoc_start *adhoc_start = + &cmd->params.adhoc_start; + struct mwifiex_bssdescriptor *bss_desc; + u32 cmd_append_size = 0; + u32 i; + u16 tmp_cap; + uint16_t ht_cap_info; + struct mwifiex_ie_types_chan_list_param_set *chan_tlv; + + struct mwifiex_ie_types_htcap *ht_cap; + struct mwifiex_ie_types_htinfo *ht_info; + u8 *pos = (u8 *) adhoc_start + + sizeof(struct host_cmd_ds_802_11_ad_hoc_start); + + if (!adapter) + return -1; + + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_START); + + bss_desc = &priv->curr_bss_params.bss_descriptor; + priv->attempted_bss_desc = bss_desc; + + /* + * Fill in the parameters for 2 data structures: + * 1. struct host_cmd_ds_802_11_ad_hoc_start command + * 2. bss_desc + * Driver will fill up SSID, bss_mode,IBSS param, Physical Param, + * probe delay, and Cap info. + * Firmware will fill up beacon period, Basic rates + * and operational rates. + */ + + memset(adhoc_start->ssid, 0, IEEE80211_MAX_SSID_LEN); + + memcpy(adhoc_start->ssid, + ((struct mwifiex_802_11_ssid *) data_buf)->ssid, + ((struct mwifiex_802_11_ssid *) data_buf)->ssid_len); + + dev_dbg(adapter->dev, "info: ADHOC_S_CMD: SSID = %s\n", + adhoc_start->ssid); + + memset(bss_desc->ssid.ssid, 0, IEEE80211_MAX_SSID_LEN); + memcpy(bss_desc->ssid.ssid, + ((struct mwifiex_802_11_ssid *) data_buf)->ssid, + ((struct mwifiex_802_11_ssid *) data_buf)->ssid_len); + + bss_desc->ssid.ssid_len = + ((struct mwifiex_802_11_ssid *) data_buf)->ssid_len; + + /* Set the BSS mode */ + adhoc_start->bss_mode = HostCmd_BSS_MODE_IBSS; + bss_desc->bss_mode = NL80211_IFTYPE_ADHOC; + adhoc_start->beacon_period = cpu_to_le16(priv->beacon_period); + bss_desc->beacon_period = priv->beacon_period; + + /* Set Physical param set */ +/* Parameter IE Id */ +#define DS_PARA_IE_ID 3 +/* Parameter IE length */ +#define DS_PARA_IE_LEN 1 + + adhoc_start->phy_param_set.ds_param_set.element_id = DS_PARA_IE_ID; + adhoc_start->phy_param_set.ds_param_set.len = DS_PARA_IE_LEN; + + if (!mwifiex_get_cfp_by_band_and_channel_from_cfg80211 + (priv, adapter->adhoc_start_band, (u16) + priv->adhoc_channel)) { + struct mwifiex_chan_freq_power *cfp; + cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211(priv, + adapter->adhoc_start_band, FIRST_VALID_CHANNEL); + if (cfp) + priv->adhoc_channel = (u8) cfp->channel; + } + + if (!priv->adhoc_channel) { + dev_err(adapter->dev, "ADHOC_S_CMD: adhoc_channel cannot be 0\n"); + return -1; + } + + dev_dbg(adapter->dev, "info: ADHOC_S_CMD: creating ADHOC on channel %d\n", + priv->adhoc_channel); + + priv->curr_bss_params.bss_descriptor.channel = priv->adhoc_channel; + priv->curr_bss_params.band = adapter->adhoc_start_band; + + bss_desc->channel = priv->adhoc_channel; + adhoc_start->phy_param_set.ds_param_set.current_chan = + priv->adhoc_channel; + + memcpy(&bss_desc->phy_param_set, &adhoc_start->phy_param_set, + sizeof(union ieee_types_phy_param_set)); + + /* Set IBSS param set */ +/* IBSS parameter IE Id */ +#define IBSS_PARA_IE_ID 6 +/* IBSS parameter IE length */ +#define IBSS_PARA_IE_LEN 2 + + adhoc_start->ss_param_set.ibss_param_set.element_id = IBSS_PARA_IE_ID; + adhoc_start->ss_param_set.ibss_param_set.len = IBSS_PARA_IE_LEN; + adhoc_start->ss_param_set.ibss_param_set.atim_window + = cpu_to_le16(priv->atim_window); + memcpy(&bss_desc->ss_param_set, &adhoc_start->ss_param_set, + sizeof(union ieee_types_ss_param_set)); + + /* Set Capability info */ + bss_desc->cap_info_bitmap |= WLAN_CAPABILITY_IBSS; + tmp_cap = le16_to_cpu(adhoc_start->cap_info_bitmap); + tmp_cap &= ~WLAN_CAPABILITY_ESS; + tmp_cap |= WLAN_CAPABILITY_IBSS; + + /* Set up privacy in bss_desc */ + if (priv->sec_info.encryption_mode) { + /* Ad-Hoc capability privacy on */ + dev_dbg(adapter->dev, + "info: ADHOC_S_CMD: wep_status set privacy to WEP\n"); + bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP; + tmp_cap |= WLAN_CAPABILITY_PRIVACY; + } else { + dev_dbg(adapter->dev, "info: ADHOC_S_CMD: wep_status NOT set," + " setting privacy to ACCEPT ALL\n"); + bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL; + } + + memset(adhoc_start->DataRate, 0, sizeof(adhoc_start->DataRate)); + mwifiex_get_active_data_rates(priv, adhoc_start->DataRate); + if ((adapter->adhoc_start_band & BAND_G) && + (priv->curr_pkt_filter & HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON)) { + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_MAC_CONTROL, + HostCmd_ACT_GEN_SET, + 0, NULL, &priv->curr_pkt_filter); + + if (ret) { + dev_err(adapter->dev, + "ADHOC_S_CMD: G Protection config failed\n"); + return -1; + } + } + /* Find the last non zero */ + for (i = 0; i < sizeof(adhoc_start->DataRate) && + adhoc_start->DataRate[i]; + i++) + ; + + priv->curr_bss_params.num_of_rates = i; + + /* Copy the ad-hoc creating rates into Current BSS rate structure */ + memcpy(&priv->curr_bss_params.data_rates, + &adhoc_start->DataRate, priv->curr_bss_params.num_of_rates); + + dev_dbg(adapter->dev, "info: ADHOC_S_CMD: rates=%02x %02x %02x %02x\n", + adhoc_start->DataRate[0], adhoc_start->DataRate[1], + adhoc_start->DataRate[2], adhoc_start->DataRate[3]); + + dev_dbg(adapter->dev, "info: ADHOC_S_CMD: AD-HOC Start command is ready\n"); + + if (IS_SUPPORT_MULTI_BANDS(adapter)) { + /* Append a channel TLV */ + chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos; + chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); + chan_tlv->header.len = + cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set)); + + memset(chan_tlv->chan_scan_param, 0x00, + sizeof(struct mwifiex_chan_scan_param_set)); + chan_tlv->chan_scan_param[0].chan_number = + (u8) priv->curr_bss_params.bss_descriptor.channel; + + dev_dbg(adapter->dev, "info: ADHOC_S_CMD: TLV Chan = %d\n", + chan_tlv->chan_scan_param[0].chan_number); + + chan_tlv->chan_scan_param[0].radio_type + = mwifiex_band_to_radio_type(priv->curr_bss_params.band); + if (adapter->adhoc_start_band & BAND_GN + || adapter->adhoc_start_band & BAND_AN) { + if (adapter->chan_offset == SEC_CHANNEL_ABOVE) + chan_tlv->chan_scan_param[0].radio_type |= + SECOND_CHANNEL_ABOVE; + else if (adapter->chan_offset == SEC_CHANNEL_BELOW) + chan_tlv->chan_scan_param[0].radio_type |= + SECOND_CHANNEL_BELOW; + } + dev_dbg(adapter->dev, "info: ADHOC_S_CMD: TLV Band = %d\n", + chan_tlv->chan_scan_param[0].radio_type); + pos += sizeof(chan_tlv->header) + + sizeof(struct mwifiex_chan_scan_param_set); + cmd_append_size += + sizeof(chan_tlv->header) + + sizeof(struct mwifiex_chan_scan_param_set); + } + + /* Append vendor specific IE TLV */ + cmd_append_size += mwifiex_cmd_append_vsie_tlv(priv, + MWIFIEX_VSIE_MASK_ADHOC, &pos); + + if (priv->sec_info.wpa_enabled) { + rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos); + if (rsn_ie_len == -1) + return -1; + cmd_append_size += rsn_ie_len; + } + + if (adapter->adhoc_11n_enabled) { + { + ht_cap = (struct mwifiex_ie_types_htcap *) pos; + memset(ht_cap, 0, + sizeof(struct mwifiex_ie_types_htcap)); + ht_cap->header.type = + cpu_to_le16(WLAN_EID_HT_CAPABILITY); + ht_cap->header.len = + cpu_to_le16(sizeof(struct ieee80211_ht_cap)); + ht_cap_info = le16_to_cpu(ht_cap->ht_cap.cap_info); + + ht_cap_info |= IEEE80211_HT_CAP_SGI_20; + if (adapter->chan_offset) { + ht_cap_info |= IEEE80211_HT_CAP_SGI_40; + ht_cap_info |= IEEE80211_HT_CAP_DSSSCCK40; + ht_cap_info |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; + SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask); + } + + ht_cap->ht_cap.ampdu_params_info + = IEEE80211_HT_MAX_AMPDU_64K; + ht_cap->ht_cap.mcs.rx_mask[0] = 0xff; + pos += sizeof(struct mwifiex_ie_types_htcap); + cmd_append_size += + sizeof(struct mwifiex_ie_types_htcap); + } + { + ht_info = (struct mwifiex_ie_types_htinfo *) pos; + memset(ht_info, 0, + sizeof(struct mwifiex_ie_types_htinfo)); + ht_info->header.type = + cpu_to_le16(WLAN_EID_HT_INFORMATION); + ht_info->header.len = + cpu_to_le16(sizeof(struct ieee80211_ht_info)); + ht_info->ht_info.control_chan = + (u8) priv->curr_bss_params.bss_descriptor. + channel; + if (adapter->chan_offset) { + ht_info->ht_info.ht_param = + adapter->chan_offset; + ht_info->ht_info.ht_param |= + IEEE80211_HT_PARAM_CHAN_WIDTH_ANY; + } + ht_info->ht_info.operation_mode = + cpu_to_le16(NON_GREENFIELD_STAS); + ht_info->ht_info.basic_set[0] = 0xff; + pos += sizeof(struct mwifiex_ie_types_htinfo); + cmd_append_size += + sizeof(struct mwifiex_ie_types_htinfo); + } + } + + cmd->size = cpu_to_le16((u16) + (sizeof(struct host_cmd_ds_802_11_ad_hoc_start) + + S_DS_GEN + cmd_append_size)); + + if (adapter->adhoc_start_band == BAND_B) + tmp_cap &= ~WLAN_CAPABILITY_SHORT_SLOT_TIME; + else + tmp_cap |= WLAN_CAPABILITY_SHORT_SLOT_TIME; + + adhoc_start->cap_info_bitmap = cpu_to_le16(tmp_cap); + + return 0; +} + +/* + * This function prepares command for ad-hoc join. + * + * Most of the parameters are set up by copying from the target BSS descriptor + * from the scan response. + * + * In addition, the following TLVs are added - + * - Channel TLV + * - Vendor specific IE + * - WPA/WPA2 IE + * - 11n IE + * + * Preparation also includes - + * - Setting command ID and proper size + * - Ensuring correct endian-ness + */ +int +mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, void *data_buf) +{ + int ret = 0, rsn_ie_len = 0; + struct host_cmd_ds_802_11_ad_hoc_join *adhoc_join = + &cmd->params.adhoc_join; + struct mwifiex_bssdescriptor *bss_desc = + (struct mwifiex_bssdescriptor *) data_buf; + struct mwifiex_ie_types_chan_list_param_set *chan_tlv; + u32 cmd_append_size = 0; + u16 tmp_cap; + u32 i, rates_size = 0; + u16 curr_pkt_filter; + u8 *pos = + (u8 *) adhoc_join + + sizeof(struct host_cmd_ds_802_11_ad_hoc_join); + +/* Use G protection */ +#define USE_G_PROTECTION 0x02 + if (bss_desc->erp_flags & USE_G_PROTECTION) { + curr_pkt_filter = + priv-> + curr_pkt_filter | HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON; + + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_MAC_CONTROL, + HostCmd_ACT_GEN_SET, 0, NULL, + &curr_pkt_filter); + if (ret) { + dev_err(priv->adapter->dev, + "ADHOC_J_CMD: G Protection config failed\n"); + return -1; + } + } + + priv->attempted_bss_desc = bss_desc; + + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_JOIN); + + adhoc_join->bss_descriptor.bss_mode = HostCmd_BSS_MODE_IBSS; + + adhoc_join->bss_descriptor.beacon_period + = cpu_to_le16(bss_desc->beacon_period); + + memcpy(&adhoc_join->bss_descriptor.bssid, + &bss_desc->mac_address, ETH_ALEN); + + memcpy(&adhoc_join->bss_descriptor.ssid, + &bss_desc->ssid.ssid, bss_desc->ssid.ssid_len); + + memcpy(&adhoc_join->bss_descriptor.phy_param_set, + &bss_desc->phy_param_set, + sizeof(union ieee_types_phy_param_set)); + + memcpy(&adhoc_join->bss_descriptor.ss_param_set, + &bss_desc->ss_param_set, sizeof(union ieee_types_ss_param_set)); + + tmp_cap = bss_desc->cap_info_bitmap; + + tmp_cap &= CAPINFO_MASK; + + dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: tmp_cap=%4X" + " CAPINFO_MASK=%4lX\n", tmp_cap, CAPINFO_MASK); + + /* Information on BSSID descriptor passed to FW */ + dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: BSSID = %pM, SSID = %s\n", + adhoc_join->bss_descriptor.bssid, + adhoc_join->bss_descriptor.ssid); + + for (i = 0; bss_desc->supported_rates[i] && + i < MWIFIEX_SUPPORTED_RATES; + i++) + ; + rates_size = i; + + /* Copy Data Rates from the Rates recorded in scan response */ + memset(adhoc_join->bss_descriptor.data_rates, 0, + sizeof(adhoc_join->bss_descriptor.data_rates)); + memcpy(adhoc_join->bss_descriptor.data_rates, + bss_desc->supported_rates, rates_size); + + /* Copy the adhoc join rates into Current BSS state structure */ + priv->curr_bss_params.num_of_rates = rates_size; + memcpy(&priv->curr_bss_params.data_rates, bss_desc->supported_rates, + rates_size); + + /* Copy the channel information */ + priv->curr_bss_params.bss_descriptor.channel = bss_desc->channel; + priv->curr_bss_params.band = (u8) bss_desc->bss_band; + + if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED + || priv->sec_info.wpa_enabled) + tmp_cap |= WLAN_CAPABILITY_PRIVACY; + + if (IS_SUPPORT_MULTI_BANDS(priv->adapter)) { + /* Append a channel TLV */ + chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos; + chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); + chan_tlv->header.len = + cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set)); + + memset(chan_tlv->chan_scan_param, 0x00, + sizeof(struct mwifiex_chan_scan_param_set)); + chan_tlv->chan_scan_param[0].chan_number = + (bss_desc->phy_param_set.ds_param_set.current_chan); + dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: TLV Chan = %d\n", + chan_tlv->chan_scan_param[0].chan_number); + + chan_tlv->chan_scan_param[0].radio_type = + mwifiex_band_to_radio_type((u8) bss_desc->bss_band); + + dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: TLV Band = %d\n", + chan_tlv->chan_scan_param[0].radio_type); + pos += sizeof(chan_tlv->header) + + sizeof(struct mwifiex_chan_scan_param_set); + cmd_append_size += sizeof(chan_tlv->header) + + sizeof(struct mwifiex_chan_scan_param_set); + } + + if (priv->sec_info.wpa_enabled) + rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos); + if (rsn_ie_len == -1) + return -1; + cmd_append_size += rsn_ie_len; + + if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info)) + cmd_append_size += mwifiex_cmd_append_11n_tlv(priv, + bss_desc, &pos); + + /* Append vendor specific IE TLV */ + cmd_append_size += mwifiex_cmd_append_vsie_tlv(priv, + MWIFIEX_VSIE_MASK_ADHOC, &pos); + + cmd->size = cpu_to_le16((u16) + (sizeof(struct host_cmd_ds_802_11_ad_hoc_join) + + S_DS_GEN + cmd_append_size)); + + adhoc_join->bss_descriptor.cap_info_bitmap = cpu_to_le16(tmp_cap); + + return ret; +} + +/* + * This function handles the command response of ad-hoc start and + * ad-hoc join. + * + * The function generates a device-connected event to notify + * the applications, in case of successful ad-hoc start/join, and + * saves the beacon buffer. + */ +int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, void *wq_buf) +{ + int ret = 0; + struct mwifiex_wait_queue *wait_queue = + (struct mwifiex_wait_queue *) wq_buf; + struct host_cmd_ds_802_11_ad_hoc_result *adhoc_result; + struct mwifiex_bssdescriptor *bss_desc; + u16 command = le16_to_cpu(resp->command); + u16 result = le16_to_cpu(resp->result); + + adhoc_result = &resp->params.adhoc_result; + + bss_desc = priv->attempted_bss_desc; + + /* Join result code 0 --> SUCCESS */ + if (result) { + dev_err(priv->adapter->dev, "ADHOC_RESP: failed\n"); + if (priv->media_connected) + mwifiex_reset_connect_state(priv); + + memset(&priv->curr_bss_params.bss_descriptor, + 0x00, sizeof(struct mwifiex_bssdescriptor)); + + ret = -1; + goto done; + } + + /* Send a Media Connected event, according to the Spec */ + priv->media_connected = true; + + if (command == HostCmd_CMD_802_11_AD_HOC_START) { + dev_dbg(priv->adapter->dev, "info: ADHOC_S_RESP %s\n", + bss_desc->ssid.ssid); + + /* Update the created network descriptor with the new BSSID */ + memcpy(bss_desc->mac_address, + adhoc_result->bssid, ETH_ALEN); + + priv->adhoc_state = ADHOC_STARTED; + } else { + /* + * Now the join cmd should be successful. + * If BSSID has changed use SSID to compare instead of BSSID + */ + dev_dbg(priv->adapter->dev, "info: ADHOC_J_RESP %s\n", + bss_desc->ssid.ssid); + + /* + * Make a copy of current BSSID descriptor, only needed for + * join since the current descriptor is already being used + * for adhoc start + */ + memcpy(&priv->curr_bss_params.bss_descriptor, + bss_desc, sizeof(struct mwifiex_bssdescriptor)); + + priv->adhoc_state = ADHOC_JOINED; + } + + dev_dbg(priv->adapter->dev, "info: ADHOC_RESP: channel = %d\n", + priv->adhoc_channel); + dev_dbg(priv->adapter->dev, "info: ADHOC_RESP: BSSID = %pM\n", + priv->curr_bss_params.bss_descriptor.mac_address); + + if (!netif_carrier_ok(priv->netdev)) + netif_carrier_on(priv->netdev); + if (netif_queue_stopped(priv->netdev)) + netif_wake_queue(priv->netdev); + + mwifiex_save_curr_bcn(priv); + +done: + /* Need to indicate IOCTL complete */ + if (wait_queue) { + if (ret) + wait_queue->status = MWIFIEX_ERROR_ASSOC_FAIL; + else + wait_queue->status = MWIFIEX_ERROR_NO_ERROR; + + } + + return ret; +} + +/* + * This function associates to a specific BSS discovered in a scan. + * + * It clears any past association response stored for application + * retrieval and calls the command preparation routine to send the + * command to firmware. + */ +int mwifiex_associate(struct mwifiex_private *priv, + void *wait_queue, struct mwifiex_bssdescriptor *bss_desc) +{ + int ret = 0; + u8 current_bssid[ETH_ALEN]; + + /* Return error if the adapter or table entry is not marked as infra */ + if ((priv->bss_mode != NL80211_IFTYPE_STATION) || + (bss_desc->bss_mode != NL80211_IFTYPE_STATION)) + return -1; + + memcpy(¤t_bssid, + &priv->curr_bss_params.bss_descriptor.mac_address, + sizeof(current_bssid)); + + /* Clear any past association response stored for application + retrieval */ + priv->assoc_rsp_size = 0; + + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_ASSOCIATE, + HostCmd_ACT_GEN_SET, 0, wait_queue, + bss_desc); + + return ret; +} + +/* + * This function starts an ad-hoc network. + * + * It calls the command preparation routine to send the command to firmware. + */ +int +mwifiex_adhoc_start(struct mwifiex_private *priv, + void *wait_queue, struct mwifiex_802_11_ssid *adhoc_ssid) +{ + int ret = 0; + + dev_dbg(priv->adapter->dev, "info: Adhoc Channel = %d\n", + priv->adhoc_channel); + dev_dbg(priv->adapter->dev, "info: curr_bss_params.channel = %d\n", + priv->curr_bss_params.bss_descriptor.channel); + dev_dbg(priv->adapter->dev, "info: curr_bss_params.band = %d\n", + priv->curr_bss_params.band); + + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_AD_HOC_START, + HostCmd_ACT_GEN_SET, 0, wait_queue, + adhoc_ssid); + + return ret; +} + +/* + * This function joins an ad-hoc network found in a previous scan. + * + * It calls the command preparation routine to send the command to firmware, + * if already not connected to the requested SSID. + */ +int mwifiex_adhoc_join(struct mwifiex_private *priv, + void *wait_queue, struct mwifiex_bssdescriptor *bss_desc) +{ + int ret = 0; + + dev_dbg(priv->adapter->dev, "info: adhoc join: curr_bss ssid =%s\n", + priv->curr_bss_params.bss_descriptor.ssid.ssid); + dev_dbg(priv->adapter->dev, "info: adhoc join: curr_bss ssid_len =%u\n", + priv->curr_bss_params.bss_descriptor.ssid.ssid_len); + dev_dbg(priv->adapter->dev, "info: adhoc join: ssid =%s\n", + bss_desc->ssid.ssid); + dev_dbg(priv->adapter->dev, "info: adhoc join: ssid_len =%u\n", + bss_desc->ssid.ssid_len); + + /* Check if the requested SSID is already joined */ + if (priv->curr_bss_params.bss_descriptor.ssid.ssid_len && + !mwifiex_ssid_cmp(&bss_desc->ssid, + &priv->curr_bss_params.bss_descriptor.ssid) && + (priv->curr_bss_params.bss_descriptor.bss_mode == + NL80211_IFTYPE_ADHOC)) { + dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: new ad-hoc SSID" + " is the same as current; not attempting to re-join\n"); + return -1; + } + + dev_dbg(priv->adapter->dev, "info: curr_bss_params.channel = %d\n", + priv->curr_bss_params.bss_descriptor.channel); + dev_dbg(priv->adapter->dev, "info: curr_bss_params.band = %c\n", + priv->curr_bss_params.band); + + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_AD_HOC_JOIN, + HostCmd_ACT_GEN_SET, 0, wait_queue, + bss_desc); + + return ret; +} + +/* + * This function deauthenticates/disconnects from infra network by sending + * deauthentication request. + */ +static int mwifiex_deauthenticate_infra(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + u8 *mac) +{ + u8 mac_address[ETH_ALEN]; + int ret = 0; + u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; + + if (mac) { + if (!memcmp(mac, zero_mac, sizeof(zero_mac))) + memcpy((u8 *) &mac_address, + (u8 *) &priv->curr_bss_params.bss_descriptor. + mac_address, ETH_ALEN); + else + memcpy((u8 *) &mac_address, (u8 *) mac, ETH_ALEN); + } else { + memcpy((u8 *) &mac_address, (u8 *) &priv->curr_bss_params. + bss_descriptor.mac_address, ETH_ALEN); + } + + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_DEAUTHENTICATE, + HostCmd_ACT_GEN_SET, 0, wait, &mac_address); + + if (!ret && wait) + ret = -EINPROGRESS; + + return ret; +} + +/* + * This function deauthenticates/disconnects from a BSS. + * + * In case of infra made, it sends deauthentication request, and + * in case of ad-hoc mode, a stop network request is sent to the firmware. + */ +int mwifiex_deauthenticate(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, u8 *mac) +{ + int ret = 0; + + if (priv->media_connected) { + if (priv->bss_mode == NL80211_IFTYPE_STATION) { + ret = mwifiex_deauthenticate_infra(priv, wait, mac); + } else if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { + ret = mwifiex_prepare_cmd(priv, + HostCmd_CMD_802_11_AD_HOC_STOP, + HostCmd_ACT_GEN_SET, 0, wait, NULL); + + if (!ret && wait) + ret = -EINPROGRESS; + } + } + + return ret; +} + +/* + * This function converts band to radio type used in channel TLV. + */ +u8 +mwifiex_band_to_radio_type(u8 band) +{ + u8 ret_radio_type; + + switch (band) { + case BAND_A: + case BAND_AN: + case BAND_A | BAND_AN: + ret_radio_type = HostCmd_SCAN_RADIO_TYPE_A; + break; + case BAND_B: + case BAND_G: + case BAND_B | BAND_G: + default: + ret_radio_type = HostCmd_SCAN_RADIO_TYPE_BG; + break; + } + + return ret_radio_type; +} diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c new file mode 100644 index 000000000000..ed89ca41a902 --- /dev/null +++ b/drivers/net/wireless/mwifiex/main.c @@ -0,0 +1,1102 @@ +/* + * Marvell Wireless LAN device driver: major functions + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "main.h" +#include "wmm.h" +#include "cfg80211.h" +#include "11n.h" + +#define VERSION "1.0" + +const char driver_version[] = "mwifiex " VERSION " (%s) "; + +struct mwifiex_adapter *g_adapter; +EXPORT_SYMBOL_GPL(g_adapter); + +static struct mwifiex_bss_attr mwifiex_bss_sta[] = { + {MWIFIEX_BSS_TYPE_STA, MWIFIEX_DATA_FRAME_TYPE_ETH_II, true, 0, 0}, +}; + +static int drv_mode = DRV_MODE_STA; + +static char fw_name[32] = DEFAULT_FW_NAME; + +/* Supported drv_mode table */ +static struct mwifiex_drv_mode mwifiex_drv_mode_tbl[] = { + { + /* drv_mode */ + .drv_mode = DRV_MODE_STA, + /* intf number */ + .intf_num = ARRAY_SIZE(mwifiex_bss_sta), + /* bss_attr */ + .bss_attr = mwifiex_bss_sta, + } + , +}; + +/* + * This function registers the device and performs all the necessary + * initializations. + * + * The following initialization operations are performed - + * - Allocate adapter structure + * - Save interface specific operations table in adapter + * - Call interface specific initialization routine + * - Allocate private structures + * - Set default adapter structure parameters + * - Initialize locks + * + * In case of any errors during inittialization, this function also ensures + * proper cleanup before exiting. + */ +static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops, + struct mwifiex_device *mdevice, void **padapter) +{ + int ret = 0; + struct mwifiex_adapter *adapter = NULL; + u8 i = 0; + + adapter = kzalloc(sizeof(struct mwifiex_adapter), GFP_KERNEL); + /* Allocate memory for adapter structure */ + if (!adapter) + return -1; + + g_adapter = adapter; + adapter->card = card; + + /* Save interface specific operations in adapter */ + memmove(&adapter->if_ops, if_ops, sizeof(struct mwifiex_if_ops)); + + /* card specific initialization has been deferred until now .. */ + ret = adapter->if_ops.init_if(adapter); + if (ret) + goto error; + + adapter->priv_num = 0; + for (i = 0; i < MWIFIEX_MAX_BSS_NUM; i++) { + adapter->priv[i] = NULL; + + if (!mdevice->bss_attr[i].active) + continue; + + /* For valid bss_attr, + allocate memory for private structure */ + adapter->priv[i] = kzalloc(sizeof(struct mwifiex_private), + GFP_KERNEL); + if (!adapter->priv[i]) { + dev_err(adapter->dev, "%s: failed to alloc priv[%d]\n", + __func__, i); + goto error; + } + + adapter->priv_num++; + memset(adapter->priv[i], 0, + sizeof(struct mwifiex_private)); + adapter->priv[i]->adapter = adapter; + /* Save bss_type, frame_type & bss_priority */ + adapter->priv[i]->bss_type = (u8) mdevice->bss_attr[i].bss_type; + adapter->priv[i]->frame_type = + (u8) mdevice->bss_attr[i].frame_type; + adapter->priv[i]->bss_priority = + (u8) mdevice->bss_attr[i].bss_priority; + if (mdevice->bss_attr[i].bss_type == MWIFIEX_BSS_TYPE_STA) + adapter->priv[i]->bss_role = MWIFIEX_BSS_ROLE_STA; + else if (mdevice->bss_attr[i].bss_type == MWIFIEX_BSS_TYPE_UAP) + adapter->priv[i]->bss_role = MWIFIEX_BSS_ROLE_UAP; + + /* Save bss_index & bss_num */ + adapter->priv[i]->bss_index = i; + adapter->priv[i]->bss_num = mdevice->bss_attr[i].bss_num; + } + + /* Initialize lock variables */ + if (mwifiex_init_lock_list(adapter)) + goto error; + + init_timer(&adapter->cmd_timer); + adapter->cmd_timer.function = mwifiex_cmd_timeout_func; + adapter->cmd_timer.data = (unsigned long) adapter; + + /* Return pointer of struct mwifiex_adapter */ + *padapter = adapter; + return 0; + +error: + dev_dbg(adapter->dev, "info: leave mwifiex_register with error\n"); + + /* Free lock variables */ + mwifiex_free_lock_list(adapter); + for (i = 0; i < MWIFIEX_MAX_BSS_NUM; i++) + kfree(adapter->priv[i]); + kfree(adapter); + + return -1; +} + +/* + * This function unregisters the device and performs all the necessary + * cleanups. + * + * The following cleanup operations are performed - + * - Free the timers + * - Free beacon buffers + * - Free private structures + * - Free adapter structure + */ +static int mwifiex_unregister(struct mwifiex_adapter *adapter) +{ + s32 i = 0; + + del_timer(&adapter->cmd_timer); + + /* Free private structures */ + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + mwifiex_free_curr_bcn(adapter->priv[i]); + kfree(adapter->priv[i]); + } + } + + kfree(adapter); + return 0; +} + +/* + * The main process. + * + * This function is the main procedure of the driver and handles various driver + * operations. It runs in a loop and provides the core functionalities. + * + * The main responsibilities of this function are - + * - Ensure concurrency control + * - Handle pending interrupts and call interrupt handlers + * - Wake up the card if required + * - Handle command responses and call response handlers + * - Handle events and call event handlers + * - Execute pending commands + * - Transmit pending data packets + */ +int mwifiex_main_process(struct mwifiex_adapter *adapter) +{ + int ret = 0; + unsigned long flags; + + spin_lock_irqsave(&adapter->main_proc_lock, flags); + + /* Check if already processing */ + if (adapter->mwifiex_processing) { + spin_unlock_irqrestore(&adapter->main_proc_lock, flags); + goto exit_main_proc; + } else { + adapter->mwifiex_processing = true; + spin_unlock_irqrestore(&adapter->main_proc_lock, flags); + } +process_start: + do { + if ((adapter->hw_status == MWIFIEX_HW_STATUS_CLOSING) || + (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY)) + break; + + /* Handle pending interrupt if any */ + if (adapter->int_status) { + if (adapter->hs_activated) + mwifiex_process_hs_config(adapter); + adapter->if_ops.process_int_status(adapter); + } + + /* Need to wake up the card ? */ + if ((adapter->ps_state == PS_STATE_SLEEP) && + (adapter->pm_wakeup_card_req && + !adapter->pm_wakeup_fw_try) && + (is_command_pending(adapter) + || !mwifiex_wmm_lists_empty(adapter))) { + adapter->pm_wakeup_fw_try = true; + adapter->if_ops.wakeup(adapter); + continue; + } + if (IS_CARD_RX_RCVD(adapter)) { + adapter->pm_wakeup_fw_try = false; + if (adapter->ps_state == PS_STATE_SLEEP) + adapter->ps_state = PS_STATE_AWAKE; + } else { + /* We have tried to wakeup the card already */ + if (adapter->pm_wakeup_fw_try) + break; + if (adapter->ps_state != PS_STATE_AWAKE || + adapter->tx_lock_flag) + break; + + if (adapter->scan_processing || adapter->data_sent + || mwifiex_wmm_lists_empty(adapter)) { + if (adapter->cmd_sent || adapter->curr_cmd + || (!is_command_pending(adapter))) + break; + } + } + + /* Check for Cmd Resp */ + if (adapter->cmd_resp_received) { + adapter->cmd_resp_received = false; + mwifiex_process_cmdresp(adapter); + + /* call mwifiex back when init_fw is done */ + if (adapter->hw_status == MWIFIEX_HW_STATUS_INIT_DONE) { + adapter->hw_status = MWIFIEX_HW_STATUS_READY; + mwifiex_init_fw_complete(adapter); + } + } + + /* Check for event */ + if (adapter->event_received) { + adapter->event_received = false; + mwifiex_process_event(adapter); + } + + /* Check if we need to confirm Sleep Request + received previously */ + if (adapter->ps_state == PS_STATE_PRE_SLEEP) { + if (!adapter->cmd_sent && !adapter->curr_cmd) + mwifiex_check_ps_cond(adapter); + } + + /* * The ps_state may have been changed during processing of + * Sleep Request event. + */ + if ((adapter->ps_state == PS_STATE_SLEEP) + || (adapter->ps_state == PS_STATE_PRE_SLEEP) + || (adapter->ps_state == PS_STATE_SLEEP_CFM) + || adapter->tx_lock_flag) + continue; + + if (!adapter->cmd_sent && !adapter->curr_cmd) { + if (mwifiex_exec_next_cmd(adapter) == -1) { + ret = -1; + break; + } + } + + if (!adapter->scan_processing && !adapter->data_sent && + !mwifiex_wmm_lists_empty(adapter)) { + mwifiex_wmm_process_tx(adapter); + if (adapter->hs_activated) { + adapter->is_hs_configured = false; + mwifiex_hs_activated_event + (mwifiex_get_priv + (adapter, MWIFIEX_BSS_ROLE_ANY), + false); + } + } + + if (adapter->delay_null_pkt && !adapter->cmd_sent && + !adapter->curr_cmd && !is_command_pending(adapter) + && mwifiex_wmm_lists_empty(adapter)) { + if (!mwifiex_send_null_packet + (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), + MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET | + MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET)) { + adapter->delay_null_pkt = false; + adapter->ps_state = PS_STATE_SLEEP; + } + break; + } + } while (true); + + if ((adapter->int_status) || IS_CARD_RX_RCVD(adapter)) + goto process_start; + + spin_lock_irqsave(&adapter->main_proc_lock, flags); + adapter->mwifiex_processing = false; + spin_unlock_irqrestore(&adapter->main_proc_lock, flags); + +exit_main_proc: + if (adapter->hw_status == MWIFIEX_HW_STATUS_CLOSING) + mwifiex_shutdown_drv(adapter); + return ret; +} + +/* + * This function initializes the software. + * + * The main work includes allocating and initializing the adapter structure + * and initializing the private structures. + */ +static int +mwifiex_init_sw(void *card, struct mwifiex_if_ops *if_ops, void **pmwifiex) +{ + int i; + struct mwifiex_device device; + struct mwifiex_drv_mode *drv_mode_ptr; + + /* find mwifiex_drv_mode entry from mwifiex_drv_mode_tbl */ + drv_mode_ptr = NULL; + for (i = 0; i < ARRAY_SIZE(mwifiex_drv_mode_tbl); i++) { + if (mwifiex_drv_mode_tbl[i].drv_mode == drv_mode) { + drv_mode_ptr = &mwifiex_drv_mode_tbl[i]; + break; + } + } + + if (!drv_mode_ptr) { + pr_err("invalid drv_mode=%d\n", drv_mode); + return -1; + } + + memset(&device, 0, sizeof(struct mwifiex_device)); + + for (i = 0; i < drv_mode_ptr->intf_num; i++) { + device.bss_attr[i].bss_type = + drv_mode_ptr->bss_attr[i].bss_type; + device.bss_attr[i].frame_type = + drv_mode_ptr->bss_attr[i].frame_type; + device.bss_attr[i].active = drv_mode_ptr->bss_attr[i].active; + device.bss_attr[i].bss_priority = + drv_mode_ptr->bss_attr[i].bss_priority; + device.bss_attr[i].bss_num = drv_mode_ptr->bss_attr[i].bss_num; + } + + if (mwifiex_register(card, if_ops, &device, pmwifiex)) + return -1; + + return 0; +} + +/* + * This function frees the adapter structure. + * + * Additionally, this closes the netlink socket, frees the timers + * and private structures. + */ +static void mwifiex_free_adapter(struct mwifiex_adapter *adapter) +{ + if (!adapter) { + pr_err("%s: adapter is NULL\n", __func__); + return; + } + + mwifiex_unregister(adapter); + pr_debug("info: %s: free adapter\n", __func__); +} + +/* + * This function initializes the hardware and firmware. + * + * The main initialization steps followed are - + * - Download the correct firmware to card + * - Allocate and initialize the adapter structure + * - Initialize the private structures + * - Issue the init commands to firmware + */ +static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter) +{ + int ret = 0; + int err; + struct mwifiex_fw_image fw; + + memset(&fw, 0, sizeof(struct mwifiex_fw_image)); + + switch (adapter->revision_id) { + case SD8787_W0: + case SD8787_W1: + strcpy(fw_name, SD8787_W1_FW_NAME); + break; + case SD8787_A0: + case SD8787_A1: + strcpy(fw_name, SD8787_AX_FW_NAME); + break; + default: + break; + } + + err = request_firmware(&adapter->firmware, fw_name, adapter->dev); + if (err < 0) { + dev_err(adapter->dev, "request_firmware() returned" + " error code %#x\n", err); + ret = -1; + goto done; + } + fw.fw_buf = (u8 *) adapter->firmware->data; + fw.fw_len = adapter->firmware->size; + + ret = mwifiex_dnld_fw(adapter, &fw); + if (ret == -1) + goto done; + + dev_notice(adapter->dev, "WLAN FW is active\n"); + + adapter->init_wait_q_woken = false; + ret = mwifiex_init_fw(adapter); + if (ret == -1) { + goto done; + } else if (!ret) { + adapter->hw_status = MWIFIEX_HW_STATUS_READY; + goto done; + } + /* Wait for mwifiex_init to complete */ + wait_event_interruptible(adapter->init_wait_q, + adapter->init_wait_q_woken); + if (adapter->hw_status != MWIFIEX_HW_STATUS_READY) { + ret = -1; + goto done; + } + ret = 0; + +done: + if (adapter->firmware) + release_firmware(adapter->firmware); + if (ret) + ret = -1; + return ret; +} + +/* + * This function fills a driver buffer. + * + * The function associates a given SKB with the provided driver buffer + * and also updates some of the SKB parameters, including IP header, + * priority and timestamp. + */ +static void +mwifiex_fill_buffer(struct sk_buff *skb) +{ + struct ethhdr *eth = NULL; + struct iphdr *iph; + struct timeval tv; + u8 tid = 0; + + eth = (struct ethhdr *) skb->data; + switch (eth->h_proto) { + case __constant_htons(ETH_P_IP): + iph = ip_hdr(skb); + tid = IPTOS_PREC(iph->tos); + pr_debug("data: packet type ETH_P_IP: %04x, tid=%#x prio=%#x\n", + eth->h_proto, tid, skb->priority); + break; + case __constant_htons(ETH_P_ARP): + pr_debug("data: ARP packet: %04x\n", eth->h_proto); + default: + break; + } +/* Offset for TOS field in the IP header */ +#define IPTOS_OFFSET 5 + tid = (tid >> IPTOS_OFFSET); + skb->priority = tid; + /* Record the current time the packet was queued; used to + determine the amount of time the packet was queued in + the driver before it was sent to the firmware. + The delay is then sent along with the packet to the + firmware for aggregate delay calculation for stats and + MSDU lifetime expiry. + */ + do_gettimeofday(&tv); + skb->tstamp = timeval_to_ktime(tv); + return; +} + +/* + * CFG802.11 network device handler for open. + * + * Starts the data queue. + */ +static int +mwifiex_open(struct net_device *dev) +{ + netif_start_queue(dev); + return 0; +} + +/* + * CFG802.11 network device handler for close. + */ +static int +mwifiex_close(struct net_device *dev) +{ + return 0; +} + +/* + * CFG802.11 network device handler for data transmission. + */ +static int +mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + struct sk_buff *new_skb = NULL; + struct mwifiex_txinfo *tx_info; + + dev_dbg(priv->adapter->dev, "data: %lu BSS(%d): Data <= kernel\n", + jiffies, priv->bss_index); + + if (priv->adapter->surprise_removed) { + kfree(skb); + priv->stats.tx_dropped++; + return 0; + } + if (!skb->len || (skb->len > ETH_FRAME_LEN)) { + dev_err(priv->adapter->dev, "Tx: bad skb len %d\n", skb->len); + kfree(skb); + priv->stats.tx_dropped++; + return 0; + } + if (skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN) { + dev_dbg(priv->adapter->dev, + "data: Tx: insufficient skb headroom %d\n", + skb_headroom(skb)); + /* Insufficient skb headroom - allocate a new skb */ + new_skb = + skb_realloc_headroom(skb, MWIFIEX_MIN_DATA_HEADER_LEN); + if (unlikely(!new_skb)) { + dev_err(priv->adapter->dev, "Tx: cannot alloca new_skb\n"); + kfree(skb); + priv->stats.tx_dropped++; + return 0; + } + kfree_skb(skb); + skb = new_skb; + dev_dbg(priv->adapter->dev, "info: new skb headroomd %d\n", + skb_headroom(skb)); + } + + tx_info = MWIFIEX_SKB_TXCB(skb); + tx_info->bss_index = priv->bss_index; + mwifiex_fill_buffer(skb); + + mwifiex_wmm_add_buf_txqueue(priv->adapter, skb); + atomic_inc(&priv->adapter->tx_pending); + + if (atomic_read(&priv->adapter->tx_pending) >= MAX_TX_PENDING) { + netif_stop_queue(priv->netdev); + dev->trans_start = jiffies; + } + + queue_work(priv->adapter->workqueue, &priv->adapter->main_work); + + return 0; +} + +/* + * CFG802.11 network device handler for setting MAC address. + */ +static int +mwifiex_set_mac_address(struct net_device *dev, void *addr) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + struct sockaddr *hw_addr = (struct sockaddr *) addr; + + memcpy(priv->curr_addr, hw_addr->sa_data, ETH_ALEN); + + if (mwifiex_request_set_mac_address(priv)) { + dev_err(priv->adapter->dev, "set MAC address failed\n"); + return -EFAULT; + } + memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN); + + return 0; +} + +/* + * CFG802.11 network device handler for setting multicast list. + */ +static void mwifiex_set_multicast_list(struct net_device *dev) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + mwifiex_request_set_multicast_list(priv, dev); +} + +/* + * CFG802.11 network device handler for transmission timeout. + */ +static void +mwifiex_tx_timeout(struct net_device *dev) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + + dev_err(priv->adapter->dev, "%lu : Tx timeout, bss_index=%d\n", + jiffies, priv->bss_index); + dev->trans_start = jiffies; + priv->num_tx_timeout++; +} + +/* + * CFG802.11 network device handler for statistics retrieval. + */ +static struct net_device_stats *mwifiex_get_stats(struct net_device *dev) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + + return &priv->stats; +} + +/* Network device handlers */ +static const struct net_device_ops mwifiex_netdev_ops = { + .ndo_open = mwifiex_open, + .ndo_stop = mwifiex_close, + .ndo_start_xmit = mwifiex_hard_start_xmit, + .ndo_set_mac_address = mwifiex_set_mac_address, + .ndo_tx_timeout = mwifiex_tx_timeout, + .ndo_get_stats = mwifiex_get_stats, + .ndo_set_multicast_list = mwifiex_set_multicast_list, +}; + +/* + * This function initializes the private structure parameters. + * + * The following wait queues are initialized - + * - IOCTL wait queue + * - Command wait queue + * - Statistics wait queue + * + * ...and the following default parameters are set - + * - Current key index : Set to 0 + * - Rate index : Set to auto + * - Media connected : Set to disconnected + * - Adhoc link sensed : Set to false + * - Nick name : Set to null + * - Number of Tx timeout : Set to 0 + * - Device address : Set to current address + * + * In addition, the CFG80211 work queue is also created. + */ +static void +mwifiex_init_priv_params(struct mwifiex_private *priv, struct net_device *dev) +{ + dev->netdev_ops = &mwifiex_netdev_ops; + /* Initialize private structure */ + init_waitqueue_head(&priv->ioctl_wait_q); + init_waitqueue_head(&priv->cmd_wait_q); + init_waitqueue_head(&priv->w_stats_wait_q); + priv->current_key_index = 0; + priv->media_connected = false; + memset(&priv->nick_name, 0, sizeof(priv->nick_name)); + priv->num_tx_timeout = 0; + priv->workqueue = create_singlethread_workqueue("cfg80211_wq"); + INIT_WORK(&priv->cfg_workqueue, mwifiex_cfg80211_results); + memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN); +} + +/* + * This function adds a new logical interface. + * + * It allocates, initializes and registers the interface by performing + * the following opearations - + * - Allocate a new net device structure + * - Assign device name + * - Register the new device with CFG80211 subsystem + * - Initialize semaphore and private structure + * - Register the new device with kernel + * - Create the complete debug FS structure if configured + */ +static struct mwifiex_private *mwifiex_add_interface( + struct mwifiex_adapter *adapter, + u8 bss_index, u8 bss_type) +{ + struct net_device *dev = NULL; + struct mwifiex_private *priv = NULL; + void *mdev_priv = NULL; + + dev = alloc_netdev_mq(sizeof(struct mwifiex_private *), "mlan%d", + ether_setup, 1); + if (!dev) { + dev_err(adapter->dev, "no memory available for netdevice\n"); + goto error; + } + if (dev_alloc_name(dev, dev->name)) { + dev_err(adapter->dev, "unable to alloc name for netdevice\n"); + goto error; + } + + if (mwifiex_register_cfg80211(dev, adapter->priv[bss_index]->curr_addr, + adapter->priv[bss_index]) != 0) { + dev_err(adapter->dev, "cannot register netdevice with cfg80211\n"); + goto error; + } + /* Save the priv pointer in netdev */ + priv = adapter->priv[bss_index]; + mdev_priv = netdev_priv(dev); + *((unsigned long *) mdev_priv) = (unsigned long) priv; + + priv->netdev = dev; + + sema_init(&priv->async_sem, 1); + priv->scan_pending_on_block = false; + + mwifiex_init_priv_params(priv, dev); + + SET_NETDEV_DEV(dev, adapter->dev); + + /* Register network device */ + if (register_netdev(dev)) { + dev_err(adapter->dev, "cannot register virtual network device\n"); + goto error; + } + + dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name); +#ifdef CONFIG_DEBUG_FS + mwifiex_dev_debugfs_init(priv); +#endif + return priv; +error: + if (dev) + free_netdev(dev); + return NULL; +} + +/* + * This function removes a logical interface. + * + * It deregisters, resets and frees the interface by performing + * the following operations - + * - Disconnect the device if connected, send wireless event to + * notify applications. + * - Remove the debug FS structure if configured + * - Unregister the device from kernel + * - Free the net device structure + * - Cancel all works and destroy work queue + * - Unregister and free the wireless device from CFG80211 subsystem + */ +static void +mwifiex_remove_interface(struct mwifiex_adapter *adapter, u8 bss_index) +{ + struct net_device *dev = NULL; + struct mwifiex_private *priv = adapter->priv[bss_index]; + + if (!priv) + return; + dev = priv->netdev; + + if (priv->media_connected) + priv->media_connected = false; + +#ifdef CONFIG_DEBUG_FS + mwifiex_dev_debugfs_remove(priv); +#endif + /* Last reference is our one */ + dev_dbg(adapter->dev, "info: %s: refcnt = %d\n", + dev->name, netdev_refcnt_read(dev)); + + if (dev->reg_state == NETREG_REGISTERED) + unregister_netdev(dev); + + /* Clear the priv in adapter */ + priv->netdev = NULL; + if (dev) + free_netdev(dev); + + cancel_work_sync(&priv->cfg_workqueue); + flush_workqueue(priv->workqueue); + destroy_workqueue(priv->workqueue); + wiphy_unregister(priv->wdev->wiphy); + wiphy_free(priv->wdev->wiphy); + kfree(priv->wdev); + + return; +} + +/* + * Sends IOCTL request to shutdown firmware. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int mwifiex_shutdown_fw(struct mwifiex_private *priv, u8 wait_option) +{ + struct mwifiex_wait_queue *wait = NULL; + int status = 0; + + /* Allocate an IOCTL request buffer */ + wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); + if (!wait) + return -ENOMEM; + + status = mwifiex_misc_ioctl_init_shutdown(priv->adapter, wait, + MWIFIEX_FUNC_SHUTDOWN); + + status = mwifiex_request_ioctl(priv, wait, status, wait_option); + + kfree(wait); + return status; +} +EXPORT_SYMBOL_GPL(mwifiex_shutdown_fw); + +/* + * This function check if command is pending. + */ +int is_command_pending(struct mwifiex_adapter *adapter) +{ + unsigned long flags; + int is_cmd_pend_q_empty; + + spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); + is_cmd_pend_q_empty = list_empty(&adapter->cmd_pending_q); + spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); + + return !is_cmd_pend_q_empty; +} + +/* + * This function returns the correct private structure pointer based + * upon the BSS number. + */ +struct mwifiex_private * +mwifiex_bss_index_to_priv(struct mwifiex_adapter *adapter, u8 bss_index) +{ + if (!adapter || (bss_index >= adapter->priv_num)) + return NULL; + return adapter->priv[bss_index]; +} + +/* + * This is the main work queue function. + * + * It handles the main process, which in turn handles the complete + * driver operations. + */ +static void mwifiex_main_work_queue(struct work_struct *work) +{ + struct mwifiex_adapter *adapter = + container_of(work, struct mwifiex_adapter, main_work); + + if (adapter->surprise_removed) + return; + mwifiex_main_process(adapter); +} + +/* + * This function cancels all works in the queue and destroys + * the main workqueue. + */ +static void +mwifiex_terminate_workqueue(struct mwifiex_adapter *adapter) +{ + flush_workqueue(adapter->workqueue); + destroy_workqueue(adapter->workqueue); + adapter->workqueue = NULL; +} + +/* + * This function adds the card. + * + * This function follows the following major steps to set up the device - + * - Initialize software. This includes probing the card, registering + * the interface operations table, and allocating/initializing the + * adapter structure + * - Set up the netlink socket + * - Create and start the main work queue + * - Register the device + * - Initialize firmware and hardware + * - Add logical interfaces + */ +int +mwifiex_add_card(void *card, struct semaphore *sem, + struct mwifiex_if_ops *if_ops) +{ + int status = 0; + int i; + struct mwifiex_adapter *adapter = NULL; + struct mwifiex_drv_mode *drv_mode_info = &mwifiex_drv_mode_tbl[0]; + + if (down_interruptible(sem)) + goto exit_sem_err; + + if (mwifiex_init_sw(card, if_ops, (void **) &adapter)) { + pr_err("%s: software init failed\n", __func__); + goto err_init_sw; + } + + adapter->drv_mode = drv_mode_info; + + adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING; + /* PnP and power profile */ + adapter->surprise_removed = false; + init_waitqueue_head(&adapter->init_wait_q); + adapter->is_suspended = false; + adapter->hs_activated = false; + init_waitqueue_head(&adapter->hs_activate_wait_q); + + /* Create workqueue */ + adapter->workqueue = create_workqueue("MWIFIEX_WORK_QUEUE"); + if (!adapter->workqueue) + goto err_kmalloc; + + INIT_WORK(&adapter->main_work, mwifiex_main_work_queue); + + /* Register the device. Fill up the private data structure with relevant + information from the card and request for the required IRQ. */ + if (adapter->if_ops.register_dev(adapter)) { + pr_err("%s: failed to register mwifiex device\n", __func__); + goto err_registerdev; + } + + /* Init FW and HW */ + if (mwifiex_init_hw_fw(adapter)) { + pr_err("%s: firmware init failed\n", __func__); + goto err_init_fw; + } + /* Add interfaces */ + for (i = 0; i < drv_mode_info->intf_num; i++) { + if (!mwifiex_add_interface(adapter, i, + adapter->drv_mode->bss_attr[i].bss_type)) { + status = -1; + break; + } + } + if (status) + goto err_add_intf; + + up(sem); + + return 0; + +err_add_intf: + for (i = 0; i < adapter->priv_num; i++) + mwifiex_remove_interface(adapter, i); +err_init_fw: + /* Unregister device */ + pr_debug("info: %s: unregister device\n", __func__); + adapter->if_ops.unregister_dev(adapter); +err_registerdev: + adapter->surprise_removed = true; + mwifiex_terminate_workqueue(adapter); +err_kmalloc: + if ((adapter->hw_status == MWIFIEX_HW_STATUS_FW_READY) || + (adapter->hw_status == MWIFIEX_HW_STATUS_READY)) { + pr_debug("info: %s: shutdown mwifiex\n", __func__); + adapter->init_wait_q_woken = false; + status = mwifiex_shutdown_drv(adapter); + if (status == -EINPROGRESS) + wait_event_interruptible(adapter->init_wait_q, + adapter->init_wait_q_woken); + } + + mwifiex_free_adapter(adapter); + +err_init_sw: + up(sem); + +exit_sem_err: + return -1; +} +EXPORT_SYMBOL_GPL(mwifiex_add_card); + +/* + * This function removes the card. + * + * This function follows the following major steps to remove the device - + * - Stop data traffic + * - Shutdown firmware + * - Remove the logical interfaces + * - Terminate the work queue + * - Unregister the device + * - Free the adapter structure + */ +int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem) +{ + struct mwifiex_private *priv = NULL; + int status; + int i; + + if (down_interruptible(sem)) + goto exit_sem_err; + + if (!adapter) + goto exit_remove; + + adapter->surprise_removed = true; + + /* Stop data */ + for (i = 0; i < adapter->priv_num; i++) { + priv = adapter->priv[i]; + if (priv) { + if (!netif_queue_stopped(priv->netdev)) + netif_stop_queue(priv->netdev); + if (netif_carrier_ok(priv->netdev)) + netif_carrier_off(priv->netdev); + } + } + + dev_dbg(adapter->dev, "cmd: calling mwifiex_shutdown_drv...\n"); + adapter->init_wait_q_woken = false; + status = mwifiex_shutdown_drv(adapter); + if (status == -EINPROGRESS) + wait_event_interruptible(adapter->init_wait_q, + adapter->init_wait_q_woken); + dev_dbg(adapter->dev, "cmd: mwifiex_shutdown_drv done\n"); + if (atomic_read(&adapter->rx_pending) || + atomic_read(&adapter->tx_pending) || + atomic_read(&adapter->ioctl_pending)) { + dev_err(adapter->dev, "rx_pending=%d, tx_pending=%d, " + "ioctl_pending=%d\n", + atomic_read(&adapter->rx_pending), + atomic_read(&adapter->tx_pending), + atomic_read(&adapter->ioctl_pending)); + } + + /* Remove interface */ + for (i = 0; i < adapter->priv_num; i++) + mwifiex_remove_interface(adapter, i); + + mwifiex_terminate_workqueue(adapter); + + /* Unregister device */ + dev_dbg(adapter->dev, "info: unregister device\n"); + adapter->if_ops.unregister_dev(adapter); + /* Free adapter structure */ + dev_dbg(adapter->dev, "info: free adapter\n"); + mwifiex_free_adapter(adapter); + +exit_remove: + up(sem); +exit_sem_err: + return 0; +} +EXPORT_SYMBOL_GPL(mwifiex_remove_card); + +/* + * This function initializes the module. + * + * The debug FS is also initialized if configured. + */ +static int +mwifiex_init_module(void) +{ +#ifdef CONFIG_DEBUG_FS + mwifiex_debugfs_init(); +#endif + return 0; +} + +/* + * This function cleans up the module. + * + * The debug FS is removed if available. + */ +static void +mwifiex_cleanup_module(void) +{ +#ifdef CONFIG_DEBUG_FS + mwifiex_debugfs_remove(); +#endif +} + +module_init(mwifiex_init_module); +module_exit(mwifiex_cleanup_module); + +MODULE_AUTHOR("Marvell International Ltd."); +MODULE_DESCRIPTION("Marvell WiFi-Ex Driver version " VERSION); +MODULE_VERSION(VERSION); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h new file mode 100644 index 000000000000..43ff149de9db --- /dev/null +++ b/drivers/net/wireless/mwifiex/main.h @@ -0,0 +1,1058 @@ +/* + * Marvell Wireless LAN device driver: major data structures and prototypes + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#ifndef _MWIFIEX_MAIN_H_ +#define _MWIFIEX_MAIN_H_ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/semaphore.h> +#include <linux/ip.h> +#include <linux/skbuff.h> +#include <linux/if_arp.h> +#include <linux/etherdevice.h> +#include <net/sock.h> +#include <net/lib80211.h> +#include <linux/firmware.h> +#include <linux/ctype.h> + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" + +extern const char driver_version[]; +extern struct mwifiex_adapter *g_adapter; + +enum { + MWIFIEX_NO_WAIT, + MWIFIEX_IOCTL_WAIT, + MWIFIEX_CMD_WAIT, + MWIFIEX_PROC_WAIT, + MWIFIEX_WSTATS_WAIT +}; + +#define DRV_MODE_STA 0x1 + +#define SD8787_W0 0x30 +#define SD8787_W1 0x31 +#define SD8787_A0 0x40 +#define SD8787_A1 0x41 + +#define DEFAULT_FW_NAME "mrvl/sd8787_uapsta.bin" +#define SD8787_W1_FW_NAME "mrvl/sd8787_uapsta_w1.bin" +#define SD8787_AX_FW_NAME "mrvl/sd8787_uapsta.bin" + +struct mwifiex_drv_mode { + u16 drv_mode; + u16 intf_num; + struct mwifiex_bss_attr *bss_attr; +}; + + +#define MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT (5 * HZ) + +#define MWIFIEX_TIMER_10S 10000 +#define MWIFIEX_TIMER_1S 1000 + +#define MAX_TX_PENDING 60 + +#define MWIFIEX_UPLD_SIZE (2312) + +#define MAX_EVENT_SIZE 1024 + +#define ARP_FILTER_MAX_BUF_SIZE 68 + +#define MWIFIEX_KEY_BUFFER_SIZE 16 +#define MWIFIEX_DEFAULT_LISTEN_INTERVAL 10 +#define MWIFIEX_MAX_REGION_CODE 7 + +#define DEFAULT_BCN_AVG_FACTOR 8 +#define DEFAULT_DATA_AVG_FACTOR 8 + +#define FIRST_VALID_CHANNEL 0xff +#define DEFAULT_AD_HOC_CHANNEL 6 +#define DEFAULT_AD_HOC_CHANNEL_A 36 + +#define DEFAULT_BCN_MISS_TIMEOUT 5 + +#define MAX_SCAN_BEACON_BUFFER 8000 + +#define SCAN_BEACON_ENTRY_PAD 6 + +#define MWIFIEX_PASSIVE_SCAN_CHAN_TIME 200 +#define MWIFIEX_ACTIVE_SCAN_CHAN_TIME 200 +#define MWIFIEX_SPECIFIC_SCAN_CHAN_TIME 110 + +#define SCAN_RSSI(RSSI) (0x100 - ((u8)(RSSI))) + +#define MWIFIEX_MAX_TOTAL_SCAN_TIME (MWIFIEX_TIMER_10S - MWIFIEX_TIMER_1S) + +#define RSN_GTK_OUI_OFFSET 2 + +#define MWIFIEX_OUI_NOT_PRESENT 0 +#define MWIFIEX_OUI_PRESENT 1 + +#define IS_CARD_RX_RCVD(adapter) (adapter->cmd_resp_received || \ + adapter->event_received || \ + adapter->data_received) + +#define MWIFIEX_TYPE_CMD 1 +#define MWIFIEX_TYPE_DATA 0 +#define MWIFIEX_TYPE_EVENT 3 + +#define DBG_CMD_NUM 5 + +#define MAX_BITMAP_RATES_SIZE 10 + +#define MAX_CHANNEL_BAND_BG 14 + +#define MAX_FREQUENCY_BAND_BG 2484 + +struct mwifiex_dbg { + u32 num_cmd_host_to_card_failure; + u32 num_cmd_sleep_cfm_host_to_card_failure; + u32 num_tx_host_to_card_failure; + u32 num_event_deauth; + u32 num_event_disassoc; + u32 num_event_link_lost; + u32 num_cmd_deauth; + u32 num_cmd_assoc_success; + u32 num_cmd_assoc_failure; + u32 num_tx_timeout; + u32 num_cmd_timeout; + u16 timeout_cmd_id; + u16 timeout_cmd_act; + u16 last_cmd_id[DBG_CMD_NUM]; + u16 last_cmd_act[DBG_CMD_NUM]; + u16 last_cmd_index; + u16 last_cmd_resp_id[DBG_CMD_NUM]; + u16 last_cmd_resp_index; + u16 last_event[DBG_CMD_NUM]; + u16 last_event_index; +}; + +enum MWIFIEX_HARDWARE_STATUS { + MWIFIEX_HW_STATUS_READY, + MWIFIEX_HW_STATUS_INITIALIZING, + MWIFIEX_HW_STATUS_FW_READY, + MWIFIEX_HW_STATUS_INIT_DONE, + MWIFIEX_HW_STATUS_RESET, + MWIFIEX_HW_STATUS_CLOSING, + MWIFIEX_HW_STATUS_NOT_READY +}; + +enum MWIFIEX_802_11_POWER_MODE { + MWIFIEX_802_11_POWER_MODE_CAM, + MWIFIEX_802_11_POWER_MODE_PSP +}; + +struct mwifiex_tx_param { + u32 next_pkt_len; +}; + +enum MWIFIEX_PS_STATE { + PS_STATE_AWAKE, + PS_STATE_PRE_SLEEP, + PS_STATE_SLEEP_CFM, + PS_STATE_SLEEP +}; + +struct mwifiex_add_ba_param { + u32 tx_win_size; + u32 rx_win_size; + u32 timeout; +}; + +struct mwifiex_tx_aggr { + u8 ampdu_user; + u8 ampdu_ap; + u8 amsdu; +}; + +struct mwifiex_ra_list_tbl { + struct list_head list; + struct sk_buff_head skb_head; + u8 ra[ETH_ALEN]; + u32 total_pkts_size; + u32 is_11n_enabled; +}; + +struct mwifiex_tid_tbl { + struct list_head ra_list; + /* spin lock for tid table */ + spinlock_t tid_tbl_lock; + struct mwifiex_ra_list_tbl *ra_list_curr; +}; + +#define WMM_HIGHEST_PRIORITY 7 +#define HIGH_PRIO_TID 7 +#define LOW_PRIO_TID 0 + +struct mwifiex_wmm_desc { + struct mwifiex_tid_tbl tid_tbl_ptr[MAX_NUM_TID]; + u32 packets_out[MAX_NUM_TID]; + /* spin lock to protect ra_list */ + spinlock_t ra_list_spinlock; + struct mwifiex_wmm_ac_status ac_status[IEEE80211_MAX_QUEUES]; + enum mwifiex_wmm_ac_e ac_down_graded_vals[IEEE80211_MAX_QUEUES]; + u32 drv_pkt_delay_max; + u8 queue_priority[IEEE80211_MAX_QUEUES]; + u32 user_pri_pkt_tx_ctrl[WMM_HIGHEST_PRIORITY + 1]; /* UP: 0 to 7 */ + +}; + +struct mwifiex_802_11_security { + u8 wpa_enabled; + u8 wpa2_enabled; + u8 wapi_enabled; + u8 wapi_key_on; + enum MWIFIEX_802_11_WEP_STATUS wep_status; + u32 authentication_mode; + u32 encryption_mode; +}; + +struct ieee_types_header { + u8 element_id; + u8 len; +} __packed; + +struct ieee_obss_scan_param { + u16 obss_scan_passive_dwell; + u16 obss_scan_active_dwell; + u16 bss_chan_width_trigger_scan_int; + u16 obss_scan_passive_total; + u16 obss_scan_active_total; + u16 bss_width_chan_trans_delay; + u16 obss_scan_active_threshold; +} __packed; + +struct ieee_types_obss_scan_param { + struct ieee_types_header ieee_hdr; + struct ieee_obss_scan_param obss_scan; +} __packed; + +#define MWIFIEX_SUPPORTED_RATES 14 + +#define MWIFIEX_SUPPORTED_RATES_EXT 32 + +#define IEEE_MAX_IE_SIZE 256 + +struct ieee_types_vendor_specific { + struct ieee_types_vendor_header vend_hdr; + u8 data[IEEE_MAX_IE_SIZE - sizeof(struct ieee_types_vendor_header)]; +} __packed; + +struct ieee_types_generic { + struct ieee_types_header ieee_hdr; + u8 data[IEEE_MAX_IE_SIZE - sizeof(struct ieee_types_header)]; +} __packed; + +struct mwifiex_bssdescriptor { + u8 mac_address[ETH_ALEN]; + struct mwifiex_802_11_ssid ssid; + u32 privacy; + s32 rssi; + u32 channel; + u32 freq; + u16 beacon_period; + u8 erp_flags; + u32 bss_mode; + u8 supported_rates[MWIFIEX_SUPPORTED_RATES]; + u8 data_rates[MWIFIEX_SUPPORTED_RATES]; + /* Network band. + * BAND_B(0x01): 'b' band + * BAND_G(0x02): 'g' band + * BAND_A(0X04): 'a' band + */ + u16 bss_band; + long long network_tsf; + u8 time_stamp[8]; + union ieee_types_phy_param_set phy_param_set; + union ieee_types_ss_param_set ss_param_set; + u16 cap_info_bitmap; + struct ieee_types_wmm_parameter wmm_ie; + u8 disable_11n; + struct ieee80211_ht_cap *bcn_ht_cap; + u16 ht_cap_offset; + struct ieee80211_ht_info *bcn_ht_info; + u16 ht_info_offset; + u8 *bcn_bss_co_2040; + u16 bss_co_2040_offset; + u8 *bcn_ext_cap; + u16 ext_cap_offset; + struct ieee_types_obss_scan_param *bcn_obss_scan; + u16 overlap_bss_offset; + struct ieee_types_vendor_specific *bcn_wpa_ie; + u16 wpa_offset; + struct ieee_types_generic *bcn_rsn_ie; + u16 rsn_offset; + struct ieee_types_generic *bcn_wapi_ie; + u16 wapi_offset; + u8 *beacon_buf; + u32 beacon_buf_size; + u32 beacon_buf_size_max; + +}; + +struct mwifiex_current_bss_params { + struct mwifiex_bssdescriptor bss_descriptor; + u8 wmm_enabled; + u8 wmm_uapsd_enabled; + u8 band; + u32 num_of_rates; + u8 data_rates[MWIFIEX_SUPPORTED_RATES]; +}; + +struct mwifiex_sleep_params { + u16 sp_error; + u16 sp_offset; + u16 sp_stable_time; + u8 sp_cal_control; + u8 sp_ext_sleep_clk; + u16 sp_reserved; +}; + +struct mwifiex_sleep_period { + u16 period; + u16 reserved; +}; + +struct mwifiex_wep_key { + u32 length; + u32 key_index; + u32 key_length; + u8 key_material[MWIFIEX_KEY_BUFFER_SIZE]; +}; + +#define MAX_REGION_CHANNEL_NUM 2 + +struct mwifiex_chan_freq_power { + u16 channel; + u32 freq; + u16 max_tx_power; + u8 unsupported; +}; + +enum state_11d_t { + DISABLE_11D = 0, + ENABLE_11D = 1, +}; + +#define MWIFIEX_MAX_TRIPLET_802_11D 83 + +struct mwifiex_802_11d_domain_reg { + u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; + u8 no_of_triplet; + struct ieee80211_country_ie_triplet + triplet[MWIFIEX_MAX_TRIPLET_802_11D]; +}; + +struct mwifiex_vendor_spec_cfg_ie { + u16 mask; + u16 flag; + u8 ie[MWIFIEX_MAX_VSIE_LEN]; +}; + +struct wps { + u8 session_enable; +}; + +struct mwifiex_adapter; +struct mwifiex_private; + +struct mwifiex_private { + struct mwifiex_adapter *adapter; + u8 bss_index; + u8 bss_type; + u8 bss_role; + u8 bss_priority; + u8 bss_num; + u8 frame_type; + u8 curr_addr[ETH_ALEN]; + u8 media_connected; + u32 num_tx_timeout; + struct net_device *netdev; + struct net_device_stats stats; + u16 curr_pkt_filter; + u32 bss_mode; + u32 pkt_tx_ctrl; + u16 tx_power_level; + u8 max_tx_power_level; + u8 min_tx_power_level; + u8 tx_rate; + u8 tx_htinfo; + u8 rxpd_htinfo; + u8 rxpd_rate; + u16 rate_bitmap; + u16 bitmap_rates[MAX_BITMAP_RATES_SIZE]; + u32 data_rate; + u8 is_data_rate_auto; + u16 bcn_avg_factor; + u16 data_avg_factor; + s16 data_rssi_last; + s16 data_nf_last; + s16 data_rssi_avg; + s16 data_nf_avg; + s16 bcn_rssi_last; + s16 bcn_nf_last; + s16 bcn_rssi_avg; + s16 bcn_nf_avg; + struct mwifiex_bssdescriptor *attempted_bss_desc; + struct mwifiex_802_11_ssid prev_ssid; + u8 prev_bssid[ETH_ALEN]; + struct mwifiex_current_bss_params curr_bss_params; + u16 beacon_period; + u16 listen_interval; + u16 atim_window; + u8 adhoc_channel; + u8 adhoc_is_link_sensed; + u8 adhoc_state; + struct mwifiex_802_11_security sec_info; + struct mwifiex_wep_key wep_key[NUM_WEP_KEYS]; + u16 wep_key_curr_index; + u8 wpa_ie[256]; + u8 wpa_ie_len; + u8 wpa_is_gtk_set; + struct host_cmd_ds_802_11_key_material aes_key; + u8 wapi_ie[256]; + u8 wapi_ie_len; + u8 wmm_required; + u8 wmm_enabled; + u8 wmm_qosinfo; + struct mwifiex_wmm_desc wmm; + struct list_head tx_ba_stream_tbl_ptr; + /* spin lock for tx_ba_stream_tbl_ptr queue */ + spinlock_t tx_ba_stream_tbl_lock; + struct mwifiex_tx_aggr aggr_prio_tbl[MAX_NUM_TID]; + struct mwifiex_add_ba_param add_ba_param; + u16 rx_seq[MAX_NUM_TID]; + struct list_head rx_reorder_tbl_ptr; + /* spin lock for rx_reorder_tbl_ptr queue */ + spinlock_t rx_reorder_tbl_lock; + /* spin lock for Rx packets */ + spinlock_t rx_pkt_lock; + +#define MWIFIEX_ASSOC_RSP_BUF_SIZE 500 + u8 assoc_rsp_buf[MWIFIEX_ASSOC_RSP_BUF_SIZE]; + u32 assoc_rsp_size; + +#define MWIFIEX_GENIE_BUF_SIZE 256 + u8 gen_ie_buf[MWIFIEX_GENIE_BUF_SIZE]; + u8 gen_ie_buf_len; + + struct mwifiex_vendor_spec_cfg_ie vs_ie[MWIFIEX_MAX_VSIE_NUM]; + +#define MWIFIEX_ASSOC_TLV_BUF_SIZE 256 + u8 assoc_tlv_buf[MWIFIEX_ASSOC_TLV_BUF_SIZE]; + u8 assoc_tlv_buf_len; + + u8 *curr_bcn_buf; + u32 curr_bcn_size; + /* spin lock for beacon buffer */ + spinlock_t curr_bcn_buf_lock; + u16 ioctl_wait_q_woken; + wait_queue_head_t ioctl_wait_q; + u16 cmd_wait_q_woken; + wait_queue_head_t cmd_wait_q; + struct wireless_dev *wdev; + struct mwifiex_chan_freq_power cfp; + char version_str[128]; +#ifdef CONFIG_DEBUG_FS + struct dentry *dfs_dev_dir; +#endif + u8 nick_name[16]; + struct iw_statistics w_stats; + u16 w_stats_wait_q_woken; + wait_queue_head_t w_stats_wait_q; + u16 current_key_index; + struct semaphore async_sem; + u8 scan_pending_on_block; + u8 report_scan_result; + struct cfg80211_scan_request *scan_request; + int scan_result_status; + bool assoc_request; + u16 assoc_result; + bool ibss_join_request; + u16 ibss_join_result; + bool disconnect; + u8 cfg_bssid[6]; + struct workqueue_struct *workqueue; + struct work_struct cfg_workqueue; + u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; + struct wps wps; + u8 scan_block; +}; + +enum mwifiex_ba_status { + BA_STREAM_NOT_SETUP = 0, + BA_STREAM_SETUP_INPROGRESS, + BA_STREAM_SETUP_COMPLETE +}; + +struct mwifiex_tx_ba_stream_tbl { + struct list_head list; + int tid; + u8 ra[ETH_ALEN]; + enum mwifiex_ba_status ba_status; +}; + +struct mwifiex_rx_reorder_tbl; + +struct reorder_tmr_cnxt { + struct timer_list timer; + struct mwifiex_rx_reorder_tbl *ptr; + struct mwifiex_private *priv; +}; + +struct mwifiex_rx_reorder_tbl { + struct list_head list; + int tid; + u8 ta[ETH_ALEN]; + int start_win; + int win_size; + void **rx_reorder_ptr; + struct reorder_tmr_cnxt timer_context; +}; + +struct mwifiex_bss_prio_node { + struct list_head list; + struct mwifiex_private *priv; +}; + +struct mwifiex_bss_prio_tbl { + struct list_head bss_prio_head; + /* spin lock for bss priority */ + spinlock_t bss_prio_lock; + struct mwifiex_bss_prio_node *bss_prio_cur; +}; + +struct cmd_ctrl_node { + struct list_head list; + struct mwifiex_private *priv; + u32 cmd_oid; + u32 cmd_flag; + struct sk_buff *cmd_skb; + struct sk_buff *resp_skb; + void *data_buf; + void *wq_buf; + struct sk_buff *skb; +}; + +struct mwifiex_if_ops { + int (*init_if) (struct mwifiex_adapter *); + void (*cleanup_if) (struct mwifiex_adapter *); + int (*check_fw_status) (struct mwifiex_adapter *, u32, int *); + int (*prog_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *); + int (*register_dev) (struct mwifiex_adapter *); + void (*unregister_dev) (struct mwifiex_adapter *); + int (*enable_int) (struct mwifiex_adapter *); + int (*process_int_status) (struct mwifiex_adapter *); + int (*host_to_card) (struct mwifiex_adapter *, u8, + u8 *payload, u32 pkt_len, + struct mwifiex_tx_param *); + int (*wakeup) (struct mwifiex_adapter *); + int (*wakeup_complete) (struct mwifiex_adapter *); + + void (*update_mp_end_port) (struct mwifiex_adapter *, u16); + void (*cleanup_mpa_buf) (struct mwifiex_adapter *); +}; + +struct mwifiex_adapter { + struct mwifiex_private *priv[MWIFIEX_MAX_BSS_NUM]; + u8 priv_num; + struct mwifiex_drv_mode *drv_mode; + const struct firmware *firmware; + struct device *dev; + bool surprise_removed; + u32 fw_release_number; + u32 revision_id; + u16 init_wait_q_woken; + wait_queue_head_t init_wait_q; + void *card; + struct mwifiex_if_ops if_ops; + atomic_t rx_pending; + atomic_t tx_pending; + atomic_t ioctl_pending; + struct workqueue_struct *workqueue; + struct work_struct main_work; + struct mwifiex_bss_prio_tbl bss_prio_tbl[MWIFIEX_MAX_BSS_NUM]; + /* spin lock for init/shutdown */ + spinlock_t mwifiex_lock; + /* spin lock for main process */ + spinlock_t main_proc_lock; + u32 mwifiex_processing; + u16 max_tx_buf_size; + u16 tx_buf_size; + u16 curr_tx_buf_size; + u32 ioport; + enum MWIFIEX_HARDWARE_STATUS hw_status; + u16 number_of_antenna; + u32 fw_cap_info; + /* spin lock for interrupt handling */ + spinlock_t int_lock; + u8 int_status; + u32 event_cause; + struct sk_buff *event_skb; + u8 upld_buf[MWIFIEX_UPLD_SIZE]; + u8 data_sent; + u8 cmd_sent; + u8 cmd_resp_received; + u8 event_received; + u8 data_received; + u16 seq_num; + struct cmd_ctrl_node *cmd_pool; + struct cmd_ctrl_node *curr_cmd; + /* spin lock for command */ + spinlock_t mwifiex_cmd_lock; + u32 num_cmd_timeout; + u16 last_init_cmd; + struct timer_list cmd_timer; + struct list_head cmd_free_q; + /* spin lock for cmd_free_q */ + spinlock_t cmd_free_q_lock; + struct list_head cmd_pending_q; + /* spin lock for cmd_pending_q */ + spinlock_t cmd_pending_q_lock; + struct list_head scan_pending_q; + /* spin lock for scan_pending_q */ + spinlock_t scan_pending_q_lock; + u32 scan_processing; + u16 region_code; + struct mwifiex_802_11d_domain_reg domain_reg; + struct mwifiex_bssdescriptor *scan_table; + u32 num_in_scan_table; + u16 scan_probes; + u32 scan_mode; + u16 specific_scan_time; + u16 active_scan_time; + u16 passive_scan_time; + u8 bcn_buf[MAX_SCAN_BEACON_BUFFER]; + u8 *bcn_buf_end; + u8 fw_bands; + u8 adhoc_start_band; + u8 config_bands; + struct mwifiex_chan_scan_param_set *scan_channels; + u8 tx_lock_flag; + struct mwifiex_sleep_params sleep_params; + struct mwifiex_sleep_period sleep_period; + u16 ps_mode; + u32 ps_state; + u8 need_to_wakeup; + u16 multiple_dtim; + u16 local_listen_interval; + u16 null_pkt_interval; + struct sk_buff *sleep_cfm; + u16 bcn_miss_time_out; + u16 adhoc_awake_period; + u8 is_deep_sleep; + u8 delay_null_pkt; + u16 delay_to_ps; + u16 enhanced_ps_mode; + u8 pm_wakeup_card_req; + u16 gen_null_pkt; + u16 pps_uapsd_mode; + u32 pm_wakeup_fw_try; + u8 is_hs_configured; + struct mwifiex_hs_config_param hs_cfg; + u8 hs_activated; + u16 hs_activate_wait_q_woken; + wait_queue_head_t hs_activate_wait_q; + bool is_suspended; + u8 event_body[MAX_EVENT_SIZE]; + u32 hw_dot_11n_dev_cap; + u8 hw_dev_mcs_support; + u8 adhoc_11n_enabled; + u8 chan_offset; + struct mwifiex_dbg dbg; + u8 arp_filter[ARP_FILTER_MAX_BUF_SIZE]; + u32 arp_filter_size; +}; + +int mwifiex_init_lock_list(struct mwifiex_adapter *adapter); +void mwifiex_free_lock_list(struct mwifiex_adapter *adapter); + +int mwifiex_init_fw(struct mwifiex_adapter *adapter); + +int mwifiex_init_fw_complete(struct mwifiex_adapter *adapter); + +int mwifiex_shutdown_drv(struct mwifiex_adapter *adapter); + +int mwifiex_shutdown_fw_complete(struct mwifiex_adapter *adapter); + +int mwifiex_dnld_fw(struct mwifiex_adapter *, struct mwifiex_fw_image *); + +int mwifiex_recv_complete(struct mwifiex_adapter *, + struct sk_buff *skb, + int status); + +int mwifiex_recv_packet(struct mwifiex_adapter *, struct sk_buff *skb); + +int mwifiex_process_event(struct mwifiex_adapter *adapter); + +int mwifiex_ioctl_complete(struct mwifiex_adapter *adapter, + struct mwifiex_wait_queue *ioctl_wq, + int status); + +int mwifiex_prepare_cmd(struct mwifiex_private *priv, + uint16_t cmd_no, + u16 cmd_action, + u32 cmd_oid, + void *wait_queue, void *data_buf); + +void mwifiex_cmd_timeout_func(unsigned long function_context); + +int mwifiex_misc_ioctl_init_shutdown(struct mwifiex_adapter *adapter, + struct mwifiex_wait_queue *wait_queue, + u32 func_init_shutdown); +int mwifiex_get_debug_info(struct mwifiex_private *, + struct mwifiex_debug_info *); + +int mwifiex_alloc_cmd_buffer(struct mwifiex_adapter *adapter); +int mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter); +void mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter); +void mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter, + struct mwifiex_wait_queue *ioctl_wq); + +void mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter, + struct cmd_ctrl_node *cmd_node); + +void mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter, + struct cmd_ctrl_node *cmd_node, + u32 addtail); + +int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter); +int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter); +int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter, + struct sk_buff *skb); +int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, + struct mwifiex_tx_param *tx_param); +int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags); +int mwifiex_write_data_complete(struct mwifiex_adapter *adapter, + struct sk_buff *skb, int status); +int mwifiex_recv_packet_complete(struct mwifiex_adapter *, + struct sk_buff *skb, int status); +void mwifiex_clean_txrx(struct mwifiex_private *priv); +u8 mwifiex_check_last_packet_indication(struct mwifiex_private *priv); +void mwifiex_check_ps_cond(struct mwifiex_adapter *adapter); +void mwifiex_process_sleep_confirm_resp(struct mwifiex_adapter *, u8 *, + u32); +int mwifiex_cmd_enh_power_mode(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, uint16_t ps_bitmap, + void *data_buf); +int mwifiex_ret_enh_power_mode(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *data_buf); +void mwifiex_process_hs_config(struct mwifiex_adapter *adapter); +void mwifiex_hs_activated_event(struct mwifiex_private *priv, + u8 activated); +int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp); +int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter, + struct sk_buff *skb); +int mwifiex_sta_prepare_cmd(struct mwifiex_private *, uint16_t cmd_no, + u16 cmd_action, u32 cmd_oid, + void *data_buf, void *cmd_buf); +int mwifiex_process_sta_cmdresp(struct mwifiex_private *, u16 cmdresp_no, + void *cmd_buf, void *ioctl); +int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *, + struct sk_buff *skb); +int mwifiex_process_sta_event(struct mwifiex_private *); +void *mwifiex_process_sta_txpd(struct mwifiex_private *, struct sk_buff *skb); +int mwifiex_sta_init_cmd(struct mwifiex_private *, u8 first_sta); +int mwifiex_scan_networks(struct mwifiex_private *priv, void *wait_queue, + u16 action, + const struct mwifiex_user_scan_cfg + *user_scan_in, struct mwifiex_scan_resp *); +int mwifiex_cmd_802_11_scan(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf); +void mwifiex_queue_scan_cmd(struct mwifiex_private *priv, + struct cmd_ctrl_node *cmd_node); +int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *wait_queue); +s32 mwifiex_find_ssid_in_list(struct mwifiex_private *priv, + struct mwifiex_802_11_ssid *ssid, u8 *bssid, + u32 mode); +s32 mwifiex_find_bssid_in_list(struct mwifiex_private *priv, u8 *bssid, + u32 mode); +int mwifiex_find_best_network(struct mwifiex_private *priv, + struct mwifiex_ssid_bssid *req_ssid_bssid); +s32 mwifiex_ssid_cmp(struct mwifiex_802_11_ssid *ssid1, + struct mwifiex_802_11_ssid *ssid2); +int mwifiex_associate(struct mwifiex_private *priv, void *wait_queue, + struct mwifiex_bssdescriptor *bss_desc); +int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv, + struct host_cmd_ds_command + *cmd, void *data_buf); +int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *wait_queue); +void mwifiex_reset_connect_state(struct mwifiex_private *priv); +void mwifiex_2040_coex_event(struct mwifiex_private *priv); +u8 mwifiex_band_to_radio_type(u8 band); +int mwifiex_deauthenticate(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait_queue, + u8 *mac); +int mwifiex_adhoc_start(struct mwifiex_private *priv, void *wait_queue, + struct mwifiex_802_11_ssid *adhoc_ssid); +int mwifiex_adhoc_join(struct mwifiex_private *priv, void *wait_queue, + struct mwifiex_bssdescriptor *bss_desc); +int mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf); +int mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf); +int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *wait_queue); +int mwifiex_cmd_802_11_bg_scan_query(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf); +struct mwifiex_chan_freq_power * + mwifiex_get_cfp_by_band_and_channel_from_cfg80211( + struct mwifiex_private *priv, + u8 band, u16 channel); +struct mwifiex_chan_freq_power *mwifiex_get_cfp_by_band_and_freq_from_cfg80211( + struct mwifiex_private *priv, + u8 band, u32 freq); +u32 mwifiex_index_to_data_rate(struct mwifiex_adapter *adapter, u8 index, + u8 ht_info); +u32 mwifiex_find_freq_from_band_chan(u8, u8); +int mwifiex_cmd_append_vsie_tlv(struct mwifiex_private *priv, u16 vsie_mask, + u8 **buffer); +u32 mwifiex_index_to_data_rate(struct mwifiex_adapter *adapter, u8 index, + u8 ht_info); +u32 mwifiex_get_active_data_rates(struct mwifiex_private *priv, + u8 *rates); +u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates); +u8 mwifiex_data_rate_to_index(struct mwifiex_adapter *adapter, u32 rate); +u8 mwifiex_is_rate_auto(struct mwifiex_private *priv); +int mwifiex_get_rate_index(struct mwifiex_adapter *adapter, + u16 *rateBitmap, int size); +extern u16 region_code_index[MWIFIEX_MAX_REGION_CODE]; +void mwifiex_save_curr_bcn(struct mwifiex_private *priv); +void mwifiex_free_curr_bcn(struct mwifiex_private *priv); +int mwifiex_cmd_get_hw_spec(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd); +int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp); +int is_command_pending(struct mwifiex_adapter *adapter); + +/* + * This function checks if the queuing is RA based or not. + */ +static inline u8 +mwifiex_queuing_ra_based(struct mwifiex_private *priv) +{ + /* + * Currently we assume if we are in Infra, then DA=RA. This might not be + * true in the future + */ + if ((priv->bss_mode == NL80211_IFTYPE_STATION) && + (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA)) + return false; + + return true; +} + +/* + * This function copies rates. + */ +static inline u32 +mwifiex_copy_rates(u8 *dest, u32 pos, u8 *src, int len) +{ + int i; + + for (i = 0; i < len && src[i]; i++, pos++) { + if (pos >= MWIFIEX_SUPPORTED_RATES) + break; + dest[pos] = src[i]; + } + + return pos; +} + +/* + * This function returns the correct private structure pointer based + * upon the BSS type and BSS number. + */ +static inline struct mwifiex_private * +mwifiex_get_priv_by_id(struct mwifiex_adapter *adapter, + u32 bss_num, u32 bss_type) +{ + int i; + + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + if ((adapter->priv[i]->bss_num == bss_num) + && (adapter->priv[i]->bss_type == bss_type)) + break; + } + } + return ((i < adapter->priv_num) ? adapter->priv[i] : NULL); +} + +/* + * This function returns the first available private structure pointer + * based upon the BSS role. + */ +static inline struct mwifiex_private * +mwifiex_get_priv(struct mwifiex_adapter *adapter, + enum mwifiex_bss_role bss_role) +{ + int i; + + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + if (bss_role == MWIFIEX_BSS_ROLE_ANY || + GET_BSS_ROLE(adapter->priv[i]) == bss_role) + break; + } + } + + return ((i < adapter->priv_num) ? adapter->priv[i] : NULL); +} + +/* + * This function returns the driver private structure of a network device. + */ +static inline struct mwifiex_private * +mwifiex_netdev_get_priv(struct net_device *dev) +{ + return (struct mwifiex_private *) (*(unsigned long *) netdev_priv(dev)); +} + +struct mwifiex_wait_queue *mwifiex_alloc_fill_wait_queue( + struct mwifiex_private *, + u8 wait_option); +struct mwifiex_private *mwifiex_bss_index_to_priv(struct mwifiex_adapter + *adapter, u8 bss_index); +int mwifiex_shutdown_fw(struct mwifiex_private *, u8); + +int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *); +int mwifiex_remove_card(struct mwifiex_adapter *, struct semaphore *); + +void mwifiex_get_version(struct mwifiex_adapter *adapter, char *version, + int maxlen); +int mwifiex_request_set_mac_address(struct mwifiex_private *priv); +void mwifiex_request_set_multicast_list(struct mwifiex_private *priv, + struct net_device *dev); +int mwifiex_request_ioctl(struct mwifiex_private *priv, + struct mwifiex_wait_queue *req, + int, u8 wait_option); +int mwifiex_disconnect(struct mwifiex_private *, u8, u8 *); +int mwifiex_bss_start(struct mwifiex_private *priv, + u8 wait_option, + struct mwifiex_ssid_bssid *ssid_bssid); +int mwifiex_set_hs_params(struct mwifiex_private *priv, + u16 action, u8 wait_option, + struct mwifiex_ds_hs_cfg *hscfg); +int mwifiex_cancel_hs(struct mwifiex_private *priv, u8 wait_option); +int mwifiex_enable_hs(struct mwifiex_adapter *adapter); +void mwifiex_process_ioctl_resp(struct mwifiex_private *priv, + struct mwifiex_wait_queue *req); +u32 mwifiex_get_mode(struct mwifiex_private *priv, u8 wait_option); +int mwifiex_get_signal_info(struct mwifiex_private *priv, + u8 wait_option, + struct mwifiex_ds_get_signal *signal); +int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, + struct mwifiex_rate_cfg *rate); +int mwifiex_get_channel_list(struct mwifiex_private *priv, + u8 wait_option, + struct mwifiex_chan_list *chanlist); +int mwifiex_get_scan_table(struct mwifiex_private *priv, + u8 wait_option, + struct mwifiex_scan_resp *scanresp); +int mwifiex_enable_wep_key(struct mwifiex_private *priv, u8 wait_option); +int mwifiex_find_best_bss(struct mwifiex_private *priv, u8 wait_option, + struct mwifiex_ssid_bssid *ssid_bssid); +int mwifiex_request_scan(struct mwifiex_private *priv, + u8 wait_option, + struct mwifiex_802_11_ssid *req_ssid); +int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv, + struct mwifiex_user_scan_cfg *scan_req); +int mwifiex_change_adhoc_chan(struct mwifiex_private *priv, int channel); +int mwifiex_set_radio(struct mwifiex_private *priv, u8 option); + +int mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel); + +int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key, + int key_len, u8 key_index, int disable); + +int mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len); + +int mwifiex_get_ver_ext(struct mwifiex_private *priv); + +int mwifiex_get_stats_info(struct mwifiex_private *priv, + struct mwifiex_ds_get_stats *log); + +int mwifiex_reg_write(struct mwifiex_private *priv, u32 reg_type, + u32 reg_offset, u32 reg_value); + +int mwifiex_reg_read(struct mwifiex_private *priv, u32 reg_type, + u32 reg_offset, u32 *value); + +int mwifiex_eeprom_read(struct mwifiex_private *priv, u16 offset, u16 bytes, + u8 *value); + +int mwifiex_set_11n_httx_cfg(struct mwifiex_private *priv, int data); + +int mwifiex_get_11n_httx_cfg(struct mwifiex_private *priv, int *data); + +int mwifiex_set_tx_rate_cfg(struct mwifiex_private *priv, int tx_rate_index); + +int mwifiex_get_tx_rate_cfg(struct mwifiex_private *priv, int *tx_rate_index); + +int mwifiex_drv_set_power(struct mwifiex_private *priv, bool power_on); + +int mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter, + char *version, int max_len); + +int mwifiex_set_tx_power(struct mwifiex_private *priv, int type, int dbm); + +int mwifiex_main_process(struct mwifiex_adapter *); + +int mwifiex_bss_ioctl_channel(struct mwifiex_private *, + u16 action, + struct mwifiex_chan_freq_power *cfp); +int mwifiex_bss_ioctl_find_bss(struct mwifiex_private *, + struct mwifiex_wait_queue *, + struct mwifiex_ssid_bssid *); +int mwifiex_radio_ioctl_band_cfg(struct mwifiex_private *, + u16 action, + struct mwifiex_ds_band_cfg *); +int mwifiex_snmp_mib_ioctl(struct mwifiex_private *, + struct mwifiex_wait_queue *, + u32 cmd_oid, u16 action, u32 *value); +int mwifiex_get_bss_info(struct mwifiex_private *, + struct mwifiex_bss_info *); + +#ifdef CONFIG_DEBUG_FS +void mwifiex_debugfs_init(void); +void mwifiex_debugfs_remove(void); + +void mwifiex_dev_debugfs_init(struct mwifiex_private *priv); +void mwifiex_dev_debugfs_remove(struct mwifiex_private *priv); +#endif +#endif /* !_MWIFIEX_MAIN_H_ */ diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c new file mode 100644 index 000000000000..6bb52d0e6cfa --- /dev/null +++ b/drivers/net/wireless/mwifiex/scan.c @@ -0,0 +1,3097 @@ +/* + * Marvell Wireless LAN device driver: scan ioctl and command handling + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "11n.h" +#include "cfg80211.h" + +/* The maximum number of channels the firmware can scan per command */ +#define MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN 14 + +#define MWIFIEX_CHANNELS_PER_SCAN_CMD 4 + +/* Memory needed to store a max sized Channel List TLV for a firmware scan */ +#define CHAN_TLV_MAX_SIZE (sizeof(struct mwifiex_ie_types_header) \ + + (MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN \ + *sizeof(struct mwifiex_chan_scan_param_set))) + +/* Memory needed to store supported rate */ +#define RATE_TLV_MAX_SIZE (sizeof(struct mwifiex_ie_types_rates_param_set) \ + + HOSTCMD_SUPPORTED_RATES) + +/* Memory needed to store a max number/size WildCard SSID TLV for a firmware + scan */ +#define WILDCARD_SSID_TLV_MAX_SIZE \ + (MWIFIEX_MAX_SSID_LIST_LENGTH * \ + (sizeof(struct mwifiex_ie_types_wildcard_ssid_params) \ + + IEEE80211_MAX_SSID_LEN)) + +/* Maximum memory needed for a mwifiex_scan_cmd_config with all TLVs at max */ +#define MAX_SCAN_CFG_ALLOC (sizeof(struct mwifiex_scan_cmd_config) \ + + sizeof(struct mwifiex_ie_types_num_probes) \ + + sizeof(struct mwifiex_ie_types_htcap) \ + + CHAN_TLV_MAX_SIZE \ + + RATE_TLV_MAX_SIZE \ + + WILDCARD_SSID_TLV_MAX_SIZE) + + +union mwifiex_scan_cmd_config_tlv { + /* Scan configuration (variable length) */ + struct mwifiex_scan_cmd_config config; + /* Max allocated block */ + u8 config_alloc_buf[MAX_SCAN_CFG_ALLOC]; +}; + +enum cipher_suite { + CIPHER_SUITE_TKIP, + CIPHER_SUITE_CCMP, + CIPHER_SUITE_MAX +}; +static u8 mwifiex_wpa_oui[CIPHER_SUITE_MAX][4] = { + { 0x00, 0x50, 0xf2, 0x02 }, /* TKIP */ + { 0x00, 0x50, 0xf2, 0x04 }, /* AES */ +}; +static u8 mwifiex_rsn_oui[CIPHER_SUITE_MAX][4] = { + { 0x00, 0x0f, 0xac, 0x02 }, /* TKIP */ + { 0x00, 0x0f, 0xac, 0x04 }, /* AES */ +}; + +/* + * This function parses a given IE for a given OUI. + * + * This is used to parse a WPA/RSN IE to find if it has + * a given oui in PTK. + */ +static u8 +mwifiex_search_oui_in_ie(struct ie_body *iebody, u8 *oui) +{ + u8 count; + + count = iebody->ptk_cnt[0]; + + /* There could be multiple OUIs for PTK hence + 1) Take the length. + 2) Check all the OUIs for AES. + 3) If one of them is AES then pass success. */ + while (count) { + if (!memcmp(iebody->ptk_body, oui, sizeof(iebody->ptk_body))) + return MWIFIEX_OUI_PRESENT; + + --count; + if (count) + iebody = (struct ie_body *) ((u8 *) iebody + + sizeof(iebody->ptk_body)); + } + + pr_debug("info: %s: OUI is not found in PTK\n", __func__); + return MWIFIEX_OUI_NOT_PRESENT; +} + +/* + * This function checks if a given OUI is present in a RSN IE. + * + * The function first checks if a RSN IE is present or not in the + * BSS descriptor. It tries to locate the OUI only if such an IE is + * present. + */ +static u8 +mwifiex_is_rsn_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher) +{ + u8 *oui = NULL; + struct ie_body *iebody = NULL; + u8 ret = MWIFIEX_OUI_NOT_PRESENT; + + if (((bss_desc->bcn_rsn_ie) && ((*(bss_desc->bcn_rsn_ie)). + ieee_hdr.element_id == WLAN_EID_RSN))) { + iebody = (struct ie_body *) + (((u8 *) bss_desc->bcn_rsn_ie->data) + + RSN_GTK_OUI_OFFSET); + oui = &mwifiex_rsn_oui[cipher][0]; + ret = mwifiex_search_oui_in_ie(iebody, oui); + if (ret) + return ret; + } + return ret; +} + +/* + * This function checks if a given OUI is present in a WPA IE. + * + * The function first checks if a WPA IE is present or not in the + * BSS descriptor. It tries to locate the OUI only if such an IE is + * present. + */ +static u8 +mwifiex_is_wpa_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher) +{ + u8 *oui = NULL; + struct ie_body *iebody = NULL; + u8 ret = MWIFIEX_OUI_NOT_PRESENT; + + if (((bss_desc->bcn_wpa_ie) && ((*(bss_desc->bcn_wpa_ie)). + vend_hdr.element_id == WLAN_EID_WPA))) { + iebody = (struct ie_body *) bss_desc->bcn_wpa_ie->data; + oui = &mwifiex_wpa_oui[cipher][0]; + ret = mwifiex_search_oui_in_ie(iebody, oui); + if (ret) + return ret; + } + return ret; +} + +/* + * This function compares two SSIDs and checks if they match. + */ +s32 +mwifiex_ssid_cmp(struct mwifiex_802_11_ssid *ssid1, + struct mwifiex_802_11_ssid *ssid2) +{ + if (!ssid1 || !ssid2 || (ssid1->ssid_len != ssid2->ssid_len)) + return -1; + return memcmp(ssid1->ssid, ssid2->ssid, ssid1->ssid_len); +} + +/* + * Sends IOCTL request to get the best BSS. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int mwifiex_find_best_bss(struct mwifiex_private *priv, + u8 wait_option, struct mwifiex_ssid_bssid *ssid_bssid) +{ + struct mwifiex_wait_queue *wait = NULL; + struct mwifiex_ssid_bssid tmp_ssid_bssid; + int ret = 0; + u8 *mac = NULL; + + if (!ssid_bssid) + return -1; + + /* Allocate wait request buffer */ + wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); + if (!wait) + return -ENOMEM; + + memcpy(&tmp_ssid_bssid, ssid_bssid, + sizeof(struct mwifiex_ssid_bssid)); + ret = mwifiex_bss_ioctl_find_bss(priv, wait, &tmp_ssid_bssid); + + if (!ret) { + memcpy(ssid_bssid, &tmp_ssid_bssid, + sizeof(struct mwifiex_ssid_bssid)); + mac = (u8 *) &ssid_bssid->bssid; + dev_dbg(priv->adapter->dev, "cmd: found network: ssid=%s," + " %pM\n", ssid_bssid->ssid.ssid, mac); + } + + kfree(wait); + return ret; +} + +/* + * Sends IOCTL request to start a scan with user configurations. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + * + * Upon completion, it also generates a wireless event to notify + * applications. + */ +int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv, + struct mwifiex_user_scan_cfg *scan_req) +{ + struct mwifiex_wait_queue *wait = NULL; + int status = 0; + u8 wait_option = MWIFIEX_IOCTL_WAIT; + + /* Allocate an IOCTL request buffer */ + wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); + if (!wait) + return -ENOMEM; + + status = mwifiex_scan_networks(priv, wait, HostCmd_ACT_GEN_SET, + scan_req, NULL); + + status = mwifiex_request_ioctl(priv, wait, status, wait_option); + + if (wait && (status != -EINPROGRESS)) + kfree(wait); + return status; +} + +/* + * This function checks if wapi is enabled in driver and scanned network is + * compatible with it. + */ +static bool +mwifiex_is_network_compatible_for_wapi(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc) +{ + if (priv->sec_info.wapi_enabled && + (bss_desc->bcn_wapi_ie && + ((*(bss_desc->bcn_wapi_ie)).ieee_hdr.element_id == + WLAN_EID_BSS_AC_ACCESS_DELAY))) { + return true; + } + return false; +} + +/* + * This function checks if driver is configured with no security mode and + * scanned network is compatible with it. + */ +static bool +mwifiex_is_network_compatible_for_no_sec(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc) +{ + if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED + && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled + && ((!bss_desc->bcn_wpa_ie) || + ((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id != + WLAN_EID_WPA)) + && ((!bss_desc->bcn_rsn_ie) || + ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id != + WLAN_EID_RSN)) + && !priv->sec_info.encryption_mode + && !bss_desc->privacy) { + return true; + } + return false; +} + +/* + * This function checks if static WEP is enabled in driver and scanned network + * is compatible with it. + */ +static bool +mwifiex_is_network_compatible_for_static_wep(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc) +{ + if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED + && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled + && bss_desc->privacy) { + return true; + } + return false; +} + +/* + * This function checks if wpa is enabled in driver and scanned network is + * compatible with it. + */ +static bool +mwifiex_is_network_compatible_for_wpa(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc, + int index) +{ + if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED + && priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled + && ((bss_desc->bcn_wpa_ie) && ((*(bss_desc->bcn_wpa_ie)).vend_hdr. + element_id == WLAN_EID_WPA)) + /* + * Privacy bit may NOT be set in some APs like + * LinkSys WRT54G && bss_desc->privacy + */ + ) { + dev_dbg(priv->adapter->dev, "info: %s: WPA: index=%d" + " wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s " + "EncMode=%#x privacy=%#x\n", __func__, index, + (bss_desc->bcn_wpa_ie) ? + (*(bss_desc->bcn_wpa_ie)). + vend_hdr.element_id : 0, + (bss_desc->bcn_rsn_ie) ? + (*(bss_desc->bcn_rsn_ie)). + ieee_hdr.element_id : 0, + (priv->sec_info.wep_status == + MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d", + (priv->sec_info.wpa_enabled) ? "e" : "d", + (priv->sec_info.wpa2_enabled) ? "e" : "d", + priv->sec_info.encryption_mode, + bss_desc->privacy); + return true; + } + return false; +} + +/* + * This function checks if wpa2 is enabled in driver and scanned network is + * compatible with it. + */ +static bool +mwifiex_is_network_compatible_for_wpa2(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc, + int index) +{ + if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED + && !priv->sec_info.wpa_enabled && priv->sec_info.wpa2_enabled + && ((bss_desc->bcn_rsn_ie) && ((*(bss_desc->bcn_rsn_ie)).ieee_hdr. + element_id == WLAN_EID_RSN)) + /* + * Privacy bit may NOT be set in some APs like + * LinkSys WRT54G && bss_desc->privacy + */ + ) { + dev_dbg(priv->adapter->dev, "info: %s: WPA2: index=%d" + " wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s " + "EncMode=%#x privacy=%#x\n", __func__, index, + (bss_desc->bcn_wpa_ie) ? + (*(bss_desc->bcn_wpa_ie)). + vend_hdr.element_id : 0, + (bss_desc->bcn_rsn_ie) ? + (*(bss_desc->bcn_rsn_ie)). + ieee_hdr.element_id : 0, + (priv->sec_info.wep_status == + MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d", + (priv->sec_info.wpa_enabled) ? "e" : "d", + (priv->sec_info.wpa2_enabled) ? "e" : "d", + priv->sec_info.encryption_mode, + bss_desc->privacy); + return true; + } + return false; +} + +/* + * This function checks if adhoc AES is enabled in driver and scanned network is + * compatible with it. + */ +static bool +mwifiex_is_network_compatible_for_adhoc_aes(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc) +{ + if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED + && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled + && ((!bss_desc->bcn_wpa_ie) || ((*(bss_desc->bcn_wpa_ie)).vend_hdr. + element_id != WLAN_EID_WPA)) + && ((!bss_desc->bcn_rsn_ie) || ((*(bss_desc->bcn_rsn_ie)).ieee_hdr. + element_id != WLAN_EID_RSN)) + && !priv->sec_info.encryption_mode + && bss_desc->privacy) { + return true; + } + return false; +} + +/* + * This function checks if dynamic WEP is enabled in driver and scanned network + * is compatible with it. + */ +static bool +mwifiex_is_network_compatible_for_dynamic_wep(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc, + int index) +{ + if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED + && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled + && ((!bss_desc->bcn_wpa_ie) || ((*(bss_desc->bcn_wpa_ie)).vend_hdr. + element_id != WLAN_EID_WPA)) + && ((!bss_desc->bcn_rsn_ie) || ((*(bss_desc->bcn_rsn_ie)).ieee_hdr. + element_id != WLAN_EID_RSN)) + && priv->sec_info.encryption_mode + && bss_desc->privacy) { + dev_dbg(priv->adapter->dev, "info: %s: dynamic " + "WEP: index=%d wpa_ie=%#x wpa2_ie=%#x " + "EncMode=%#x privacy=%#x\n", + __func__, index, + (bss_desc->bcn_wpa_ie) ? + (*(bss_desc->bcn_wpa_ie)). + vend_hdr.element_id : 0, + (bss_desc->bcn_rsn_ie) ? + (*(bss_desc->bcn_rsn_ie)). + ieee_hdr.element_id : 0, + priv->sec_info.encryption_mode, + bss_desc->privacy); + return true; + } + return false; +} + +/* + * This function checks if a scanned network is compatible with the driver + * settings. + * + * WEP WPA WPA2 ad-hoc encrypt Network + * enabled enabled enabled AES mode Privacy WPA WPA2 Compatible + * 0 0 0 0 NONE 0 0 0 yes No security + * 0 1 0 0 x 1x 1 x yes WPA (disable + * HT if no AES) + * 0 0 1 0 x 1x x 1 yes WPA2 (disable + * HT if no AES) + * 0 0 0 1 NONE 1 0 0 yes Ad-hoc AES + * 1 0 0 0 NONE 1 0 0 yes Static WEP + * (disable HT) + * 0 0 0 0 !=NONE 1 0 0 yes Dynamic WEP + * + * Compatibility is not matched while roaming, except for mode. + */ +static s32 +mwifiex_is_network_compatible(struct mwifiex_private *priv, u32 index, u32 mode) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_bssdescriptor *bss_desc; + + bss_desc = &adapter->scan_table[index]; + bss_desc->disable_11n = false; + + /* Don't check for compatibility if roaming */ + if (priv->media_connected && (priv->bss_mode == NL80211_IFTYPE_STATION) + && (bss_desc->bss_mode == NL80211_IFTYPE_STATION)) + return index; + + if (priv->wps.session_enable) { + dev_dbg(adapter->dev, + "info: return success directly in WPS period\n"); + return index; + } + + if (mwifiex_is_network_compatible_for_wapi(priv, bss_desc)) { + dev_dbg(adapter->dev, "info: return success for WAPI AP\n"); + return index; + } + + if (bss_desc->bss_mode == mode) { + if (mwifiex_is_network_compatible_for_no_sec(priv, bss_desc)) { + /* No security */ + return index; + } else if (mwifiex_is_network_compatible_for_static_wep(priv, + bss_desc)) { + /* Static WEP enabled */ + dev_dbg(adapter->dev, "info: Disable 11n in WEP mode.\n"); + bss_desc->disable_11n = true; + return index; + } else if (mwifiex_is_network_compatible_for_wpa(priv, bss_desc, + index)) { + /* WPA enabled */ + if (((priv->adapter->config_bands & BAND_GN + || priv->adapter->config_bands & BAND_AN) + && bss_desc->bcn_ht_cap) + && !mwifiex_is_wpa_oui_present(bss_desc, + CIPHER_SUITE_CCMP)) { + + if (mwifiex_is_wpa_oui_present(bss_desc, + CIPHER_SUITE_TKIP)) { + dev_dbg(adapter->dev, + "info: Disable 11n if AES " + "is not supported by AP\n"); + bss_desc->disable_11n = true; + } else { + return -1; + } + } + return index; + } else if (mwifiex_is_network_compatible_for_wpa2(priv, + bss_desc, index)) { + /* WPA2 enabled */ + if (((priv->adapter->config_bands & BAND_GN + || priv->adapter->config_bands & BAND_AN) + && bss_desc->bcn_ht_cap) + && !mwifiex_is_rsn_oui_present(bss_desc, + CIPHER_SUITE_CCMP)) { + + if (mwifiex_is_rsn_oui_present(bss_desc, + CIPHER_SUITE_TKIP)) { + dev_dbg(adapter->dev, + "info: Disable 11n if AES " + "is not supported by AP\n"); + bss_desc->disable_11n = true; + } else { + return -1; + } + } + return index; + } else if (mwifiex_is_network_compatible_for_adhoc_aes(priv, + bss_desc)) { + /* Ad-hoc AES enabled */ + return index; + } else if (mwifiex_is_network_compatible_for_dynamic_wep(priv, + bss_desc, index)) { + /* Dynamic WEP enabled */ + return index; + } + + /* Security doesn't match */ + dev_dbg(adapter->dev, "info: %s: failed: index=%d " + "wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode" + "=%#x privacy=%#x\n", + __func__, index, + (bss_desc->bcn_wpa_ie) ? + (*(bss_desc->bcn_wpa_ie)).vend_hdr. + element_id : 0, + (bss_desc->bcn_rsn_ie) ? + (*(bss_desc->bcn_rsn_ie)).ieee_hdr. + element_id : 0, + (priv->sec_info.wep_status == + MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d", + (priv->sec_info.wpa_enabled) ? "e" : "d", + (priv->sec_info.wpa2_enabled) ? "e" : "d", + priv->sec_info.encryption_mode, bss_desc->privacy); + return -1; + } + + /* Mode doesn't match */ + return -1; +} + +/* + * This function finds the best SSID in the scan list. + * + * It searches the scan table for the best SSID that also matches the current + * adapter network preference (mode, security etc.). + */ +static s32 +mwifiex_find_best_network_in_list(struct mwifiex_private *priv) +{ + struct mwifiex_adapter *adapter = priv->adapter; + u32 mode = priv->bss_mode; + s32 best_net = -1; + s32 best_rssi = 0; + u32 i; + + dev_dbg(adapter->dev, "info: num of BSSIDs = %d\n", + adapter->num_in_scan_table); + + for (i = 0; i < adapter->num_in_scan_table; i++) { + switch (mode) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + if (mwifiex_is_network_compatible(priv, i, mode) >= 0) { + if (SCAN_RSSI(adapter->scan_table[i].rssi) > + best_rssi) { + best_rssi = SCAN_RSSI(adapter-> + scan_table[i].rssi); + best_net = i; + } + } + break; + case NL80211_IFTYPE_UNSPECIFIED: + default: + if (SCAN_RSSI(adapter->scan_table[i].rssi) > + best_rssi) { + best_rssi = SCAN_RSSI(adapter->scan_table[i]. + rssi); + best_net = i; + } + break; + } + } + + return best_net; +} + +/* + * This function creates a channel list for the driver to scan, based + * on region/band information. + * + * This routine is used for any scan that is not provided with a + * specific channel list to scan. + */ +static void +mwifiex_scan_create_channel_list(struct mwifiex_private *priv, + const struct mwifiex_user_scan_cfg + *user_scan_in, + struct mwifiex_chan_scan_param_set + *scan_chan_list, + u8 filtered_scan) +{ + enum ieee80211_band band; + struct ieee80211_supported_band *sband; + struct ieee80211_channel *ch; + struct mwifiex_adapter *adapter = priv->adapter; + int chan_idx = 0, i; + u8 scan_type; + + for (band = 0; (band < IEEE80211_NUM_BANDS) ; band++) { + + if (!priv->wdev->wiphy->bands[band]) + continue; + + sband = priv->wdev->wiphy->bands[band]; + + for (i = 0; (i < sband->n_channels) ; i++, chan_idx++) { + ch = &sband->channels[i]; + if (ch->flags & IEEE80211_CHAN_DISABLED) + continue; + scan_chan_list[chan_idx].radio_type = band; + scan_type = ch->flags & IEEE80211_CHAN_PASSIVE_SCAN; + if (user_scan_in && + user_scan_in->chan_list[0].scan_time) + scan_chan_list[chan_idx].max_scan_time = + cpu_to_le16((u16) user_scan_in-> + chan_list[0].scan_time); + else if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE) + scan_chan_list[chan_idx].max_scan_time = + cpu_to_le16(adapter->passive_scan_time); + else + scan_chan_list[chan_idx].max_scan_time = + cpu_to_le16(adapter->active_scan_time); + if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE) + scan_chan_list[chan_idx].chan_scan_mode_bitmap + |= MWIFIEX_PASSIVE_SCAN; + else + scan_chan_list[chan_idx].chan_scan_mode_bitmap + &= ~MWIFIEX_PASSIVE_SCAN; + scan_chan_list[chan_idx].chan_number = + (u32) ch->hw_value; + if (filtered_scan) { + scan_chan_list[chan_idx].max_scan_time = + cpu_to_le16(adapter->specific_scan_time); + scan_chan_list[chan_idx].chan_scan_mode_bitmap + |= MWIFIEX_DISABLE_CHAN_FILT; + } + } + + } +} + +/* + * This function constructs and sends multiple scan config commands to + * the firmware. + * + * Previous routines in the code flow have created a scan command configuration + * with any requested TLVs. This function splits the channel TLV into maximum + * channels supported per scan lists and sends the portion of the channel TLV, + * along with the other TLVs, to the firmware. + */ +static int +mwifiex_scan_channel_list(struct mwifiex_private *priv, void *wait_buf, + u32 max_chan_per_scan, u8 filtered_scan, + struct mwifiex_scan_cmd_config *scan_cfg_out, + struct mwifiex_ie_types_chan_list_param_set + *chan_tlv_out, + struct mwifiex_chan_scan_param_set *scan_chan_list) +{ + int ret = 0; + struct mwifiex_chan_scan_param_set *tmp_chan_list; + struct mwifiex_chan_scan_param_set *start_chan; + + u32 tlv_idx; + u32 total_scan_time; + u32 done_early; + + if (!scan_cfg_out || !chan_tlv_out || !scan_chan_list) { + dev_dbg(priv->adapter->dev, + "info: Scan: Null detect: %p, %p, %p\n", + scan_cfg_out, chan_tlv_out, scan_chan_list); + return -1; + } + + chan_tlv_out->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); + + /* Set the temp channel struct pointer to the start of the desired + list */ + tmp_chan_list = scan_chan_list; + + /* Loop through the desired channel list, sending a new firmware scan + commands for each max_chan_per_scan channels (or for 1,6,11 + individually if configured accordingly) */ + while (tmp_chan_list->chan_number) { + + tlv_idx = 0; + total_scan_time = 0; + chan_tlv_out->header.len = 0; + start_chan = tmp_chan_list; + done_early = false; + + /* + * Construct the Channel TLV for the scan command. Continue to + * insert channel TLVs until: + * - the tlv_idx hits the maximum configured per scan command + * - the next channel to insert is 0 (end of desired channel + * list) + * - done_early is set (controlling individual scanning of + * 1,6,11) + */ + while (tlv_idx < max_chan_per_scan + && tmp_chan_list->chan_number && !done_early) { + + dev_dbg(priv->adapter->dev, + "info: Scan: Chan(%3d), Radio(%d)," + " Mode(%d, %d), Dur(%d)\n", + tmp_chan_list->chan_number, + tmp_chan_list->radio_type, + tmp_chan_list->chan_scan_mode_bitmap + & MWIFIEX_PASSIVE_SCAN, + (tmp_chan_list->chan_scan_mode_bitmap + & MWIFIEX_DISABLE_CHAN_FILT) >> 1, + le16_to_cpu(tmp_chan_list->max_scan_time)); + + /* Copy the current channel TLV to the command being + prepared */ + memcpy(chan_tlv_out->chan_scan_param + tlv_idx, + tmp_chan_list, + sizeof(chan_tlv_out->chan_scan_param)); + + /* Increment the TLV header length by the size + appended */ + chan_tlv_out->header.len = + cpu_to_le16(le16_to_cpu(chan_tlv_out->header.len) + + (sizeof(chan_tlv_out->chan_scan_param))); + + /* + * The tlv buffer length is set to the number of bytes + * of the between the channel tlv pointer and the start + * of the tlv buffer. This compensates for any TLVs + * that were appended before the channel list. + */ + scan_cfg_out->tlv_buf_len = (u32) ((u8 *) chan_tlv_out - + scan_cfg_out->tlv_buf); + + /* Add the size of the channel tlv header and the data + length */ + scan_cfg_out->tlv_buf_len += + (sizeof(chan_tlv_out->header) + + le16_to_cpu(chan_tlv_out->header.len)); + + /* Increment the index to the channel tlv we are + constructing */ + tlv_idx++; + + /* Count the total scan time per command */ + total_scan_time += + le16_to_cpu(tmp_chan_list->max_scan_time); + + done_early = false; + + /* Stop the loop if the *current* channel is in the + 1,6,11 set and we are not filtering on a BSSID + or SSID. */ + if (!filtered_scan && (tmp_chan_list->chan_number == 1 + || tmp_chan_list->chan_number == 6 + || tmp_chan_list->chan_number == 11)) + done_early = true; + + /* Increment the tmp pointer to the next channel to + be scanned */ + tmp_chan_list++; + + /* Stop the loop if the *next* channel is in the 1,6,11 + set. This will cause it to be the only channel + scanned on the next interation */ + if (!filtered_scan && (tmp_chan_list->chan_number == 1 + || tmp_chan_list->chan_number == 6 + || tmp_chan_list->chan_number == 11)) + done_early = true; + } + + /* The total scan time should be less than scan command timeout + value */ + if (total_scan_time > MWIFIEX_MAX_TOTAL_SCAN_TIME) { + dev_err(priv->adapter->dev, "total scan time %dms" + " is over limit (%dms), scan skipped\n", + total_scan_time, MWIFIEX_MAX_TOTAL_SCAN_TIME); + ret = -1; + break; + } + + priv->adapter->scan_channels = start_chan; + + /* Send the scan command to the firmware with the specified + cfg */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_SCAN, + HostCmd_ACT_GEN_SET, + 0, wait_buf, scan_cfg_out); + if (ret) + break; + } + + if (ret) + return -1; + + return 0; +} + +/* + * This function constructs a scan command configuration structure to use + * in scan commands. + * + * Application layer or other functions can invoke network scanning + * with a scan configuration supplied in a user scan configuration structure. + * This structure is used as the basis of one or many scan command configuration + * commands that are sent to the command processing module and eventually to the + * firmware. + * + * This function creates a scan command configuration structure based on the + * following user supplied parameters (if present): + * - SSID filter + * - BSSID filter + * - Number of Probes to be sent + * - Channel list + * + * If the SSID or BSSID filter is not present, the filter is disabled/cleared. + * If the number of probes is not set, adapter default setting is used. + */ +static void +mwifiex_scan_setup_scan_config(struct mwifiex_private *priv, + const struct mwifiex_user_scan_cfg *user_scan_in, + struct mwifiex_scan_cmd_config *scan_cfg_out, + struct mwifiex_ie_types_chan_list_param_set + **chan_list_out, + struct mwifiex_chan_scan_param_set + *scan_chan_list, + u8 *max_chan_per_scan, u8 *filtered_scan, + u8 *scan_current_only) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_ie_types_num_probes *num_probes_tlv; + struct mwifiex_ie_types_wildcard_ssid_params *wildcard_ssid_tlv; + struct mwifiex_ie_types_rates_param_set *rates_tlv; + const u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; + u8 *tlv_pos; + u32 num_probes; + u32 ssid_len; + u32 chan_idx; + u32 scan_type; + u16 scan_dur; + u8 channel; + u8 radio_type; + u32 ssid_idx; + u8 ssid_filter; + u8 rates[MWIFIEX_SUPPORTED_RATES]; + u32 rates_size; + struct mwifiex_ie_types_htcap *ht_cap; + + /* The tlv_buf_len is calculated for each scan command. The TLVs added + in this routine will be preserved since the routine that sends the + command will append channelTLVs at *chan_list_out. The difference + between the *chan_list_out and the tlv_buf start will be used to + calculate the size of anything we add in this routine. */ + scan_cfg_out->tlv_buf_len = 0; + + /* Running tlv pointer. Assigned to chan_list_out at end of function + so later routines know where channels can be added to the command + buf */ + tlv_pos = scan_cfg_out->tlv_buf; + + /* Initialize the scan as un-filtered; the flag is later set to TRUE + below if a SSID or BSSID filter is sent in the command */ + *filtered_scan = false; + + /* Initialize the scan as not being only on the current channel. If + the channel list is customized, only contains one channel, and is + the active channel, this is set true and data flow is not halted. */ + *scan_current_only = false; + + if (user_scan_in) { + + /* Default the ssid_filter flag to TRUE, set false under + certain wildcard conditions and qualified by the existence + of an SSID list before marking the scan as filtered */ + ssid_filter = true; + + /* Set the BSS type scan filter, use Adapter setting if + unset */ + scan_cfg_out->bss_mode = + (user_scan_in->bss_mode ? (u8) user_scan_in-> + bss_mode : (u8) adapter->scan_mode); + + /* Set the number of probes to send, use Adapter setting + if unset */ + num_probes = + (user_scan_in->num_probes ? user_scan_in-> + num_probes : adapter->scan_probes); + + /* + * Set the BSSID filter to the incoming configuration, + * if non-zero. If not set, it will remain disabled + * (all zeros). + */ + memcpy(scan_cfg_out->specific_bssid, + user_scan_in->specific_bssid, + sizeof(scan_cfg_out->specific_bssid)); + + for (ssid_idx = 0; + ((ssid_idx < ARRAY_SIZE(user_scan_in->ssid_list)) + && (*user_scan_in->ssid_list[ssid_idx].ssid + || user_scan_in->ssid_list[ssid_idx].max_len)); + ssid_idx++) { + + ssid_len = strlen(user_scan_in->ssid_list[ssid_idx]. + ssid) + 1; + + wildcard_ssid_tlv = + (struct mwifiex_ie_types_wildcard_ssid_params *) + tlv_pos; + wildcard_ssid_tlv->header.type = + cpu_to_le16(TLV_TYPE_WILDCARDSSID); + wildcard_ssid_tlv->header.len = cpu_to_le16( + (u16) (ssid_len + sizeof(wildcard_ssid_tlv-> + max_ssid_length))); + wildcard_ssid_tlv->max_ssid_length = + user_scan_in->ssid_list[ssid_idx].max_len; + + memcpy(wildcard_ssid_tlv->ssid, + user_scan_in->ssid_list[ssid_idx].ssid, + ssid_len); + + tlv_pos += (sizeof(wildcard_ssid_tlv->header) + + le16_to_cpu(wildcard_ssid_tlv->header.len)); + + dev_dbg(adapter->dev, "info: scan: ssid_list[%d]: %s, %d\n", + ssid_idx, wildcard_ssid_tlv->ssid, + wildcard_ssid_tlv->max_ssid_length); + + /* Empty wildcard ssid with a maxlen will match many or + potentially all SSIDs (maxlen == 32), therefore do + not treat the scan as + filtered. */ + if (!ssid_len && wildcard_ssid_tlv->max_ssid_length) + ssid_filter = false; + + } + + /* + * The default number of channels sent in the command is low to + * ensure the response buffer from the firmware does not + * truncate scan results. That is not an issue with an SSID + * or BSSID filter applied to the scan results in the firmware. + */ + if ((ssid_idx && ssid_filter) + || memcmp(scan_cfg_out->specific_bssid, &zero_mac, + sizeof(zero_mac))) + *filtered_scan = true; + } else { + scan_cfg_out->bss_mode = (u8) adapter->scan_mode; + num_probes = adapter->scan_probes; + } + + /* + * If a specific BSSID or SSID is used, the number of channels in the + * scan command will be increased to the absolute maximum. + */ + if (*filtered_scan) + *max_chan_per_scan = MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN; + else + *max_chan_per_scan = MWIFIEX_CHANNELS_PER_SCAN_CMD; + + /* If the input config or adapter has the number of Probes set, + add tlv */ + if (num_probes) { + + dev_dbg(adapter->dev, "info: scan: num_probes = %d\n", + num_probes); + + num_probes_tlv = (struct mwifiex_ie_types_num_probes *) tlv_pos; + num_probes_tlv->header.type = cpu_to_le16(TLV_TYPE_NUMPROBES); + num_probes_tlv->header.len = + cpu_to_le16(sizeof(num_probes_tlv->num_probes)); + num_probes_tlv->num_probes = cpu_to_le16((u16) num_probes); + + tlv_pos += sizeof(num_probes_tlv->header) + + le16_to_cpu(num_probes_tlv->header.len); + + } + + /* Append rates tlv */ + memset(rates, 0, sizeof(rates)); + + rates_size = mwifiex_get_supported_rates(priv, rates); + + rates_tlv = (struct mwifiex_ie_types_rates_param_set *) tlv_pos; + rates_tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES); + rates_tlv->header.len = cpu_to_le16((u16) rates_size); + memcpy(rates_tlv->rates, rates, rates_size); + tlv_pos += sizeof(rates_tlv->header) + rates_size; + + dev_dbg(adapter->dev, "info: SCAN_CMD: Rates size = %d\n", rates_size); + + if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info) + && (priv->adapter->config_bands & BAND_GN + || priv->adapter->config_bands & BAND_AN)) { + ht_cap = (struct mwifiex_ie_types_htcap *) tlv_pos; + memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap)); + ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY); + ht_cap->header.len = + cpu_to_le16(sizeof(struct ieee80211_ht_cap)); + mwifiex_fill_cap_info(priv, ht_cap); + tlv_pos += sizeof(struct mwifiex_ie_types_htcap); + } + + /* Append vendor specific IE TLV */ + mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_SCAN, &tlv_pos); + + /* + * Set the output for the channel TLV to the address in the tlv buffer + * past any TLVs that were added in this function (SSID, num_probes). + * Channel TLVs will be added past this for each scan command, + * preserving the TLVs that were previously added. + */ + *chan_list_out = + (struct mwifiex_ie_types_chan_list_param_set *) tlv_pos; + + if (user_scan_in && user_scan_in->chan_list[0].chan_number) { + + dev_dbg(adapter->dev, "info: Scan: Using supplied channel list\n"); + + for (chan_idx = 0; + chan_idx < MWIFIEX_USER_SCAN_CHAN_MAX + && user_scan_in->chan_list[chan_idx].chan_number; + chan_idx++) { + + channel = user_scan_in->chan_list[chan_idx].chan_number; + (scan_chan_list + chan_idx)->chan_number = channel; + + radio_type = + user_scan_in->chan_list[chan_idx].radio_type; + (scan_chan_list + chan_idx)->radio_type = radio_type; + + scan_type = user_scan_in->chan_list[chan_idx].scan_type; + + if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE) + (scan_chan_list + + chan_idx)->chan_scan_mode_bitmap + |= MWIFIEX_PASSIVE_SCAN; + else + (scan_chan_list + + chan_idx)->chan_scan_mode_bitmap + &= ~MWIFIEX_PASSIVE_SCAN; + + if (user_scan_in->chan_list[chan_idx].scan_time) { + scan_dur = (u16) user_scan_in-> + chan_list[chan_idx].scan_time; + } else { + if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE) + scan_dur = adapter->passive_scan_time; + else if (*filtered_scan) + scan_dur = adapter->specific_scan_time; + else + scan_dur = adapter->active_scan_time; + } + + (scan_chan_list + chan_idx)->min_scan_time = + cpu_to_le16(scan_dur); + (scan_chan_list + chan_idx)->max_scan_time = + cpu_to_le16(scan_dur); + } + + /* Check if we are only scanning the current channel */ + if ((chan_idx == 1) + && (user_scan_in->chan_list[0].chan_number + == priv->curr_bss_params.bss_descriptor.channel)) { + *scan_current_only = true; + dev_dbg(adapter->dev, + "info: Scan: Scanning current channel only\n"); + } + + } else { + dev_dbg(adapter->dev, + "info: Scan: Creating full region channel list\n"); + mwifiex_scan_create_channel_list(priv, user_scan_in, + scan_chan_list, + *filtered_scan); + } +} + +/* + * This function inspects the scan response buffer for pointers to + * expected TLVs. + * + * TLVs can be included at the end of the scan response BSS information. + * + * Data in the buffer is parsed pointers to TLVs that can potentially + * be passed back in the response. + */ +static void +mwifiex_ret_802_11_scan_get_tlv_ptrs(struct mwifiex_adapter *adapter, + struct mwifiex_ie_types_data *tlv, + u32 tlv_buf_size, u32 req_tlv_type, + struct mwifiex_ie_types_data **tlv_data) +{ + struct mwifiex_ie_types_data *current_tlv; + u32 tlv_buf_left; + u32 tlv_type; + u32 tlv_len; + + current_tlv = tlv; + tlv_buf_left = tlv_buf_size; + *tlv_data = NULL; + + dev_dbg(adapter->dev, "info: SCAN_RESP: tlv_buf_size = %d\n", + tlv_buf_size); + + while (tlv_buf_left >= sizeof(struct mwifiex_ie_types_header)) { + + tlv_type = le16_to_cpu(current_tlv->header.type); + tlv_len = le16_to_cpu(current_tlv->header.len); + + if (sizeof(tlv->header) + tlv_len > tlv_buf_left) { + dev_err(adapter->dev, "SCAN_RESP: TLV buffer corrupt\n"); + break; + } + + if (req_tlv_type == tlv_type) { + switch (tlv_type) { + case TLV_TYPE_TSFTIMESTAMP: + dev_dbg(adapter->dev, "info: SCAN_RESP: TSF " + "timestamp TLV, len = %d\n", tlv_len); + *tlv_data = (struct mwifiex_ie_types_data *) + current_tlv; + break; + case TLV_TYPE_CHANNELBANDLIST: + dev_dbg(adapter->dev, "info: SCAN_RESP: channel" + " band list TLV, len = %d\n", tlv_len); + *tlv_data = (struct mwifiex_ie_types_data *) + current_tlv; + break; + default: + dev_err(adapter->dev, + "SCAN_RESP: unhandled TLV = %d\n", + tlv_type); + /* Give up, this seems corrupted */ + return; + } + } + + if (*tlv_data) + break; + + + tlv_buf_left -= (sizeof(tlv->header) + tlv_len); + current_tlv = + (struct mwifiex_ie_types_data *) (current_tlv->data + + tlv_len); + + } /* while */ +} + +/* + * This function interprets a BSS scan response returned from the firmware. + * + * The various fixed fields and IEs are parsed and passed back for a BSS + * probe response or beacon from scan command. Information is recorded as + * needed in the scan table for that entry. + * + * The following IE types are recognized and parsed - + * - SSID + * - Supported rates + * - FH parameters set + * - DS parameters set + * - CF parameters set + * - IBSS parameters set + * - ERP information + * - Extended supported rates + * - Vendor specific (221) + * - RSN IE + * - WAPI IE + * - HT capability + * - HT operation + * - BSS Coexistence 20/40 + * - Extended capability + * - Overlapping BSS scan parameters + */ +static int +mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter, + struct mwifiex_bssdescriptor *bss_entry, + u8 **beacon_info, u32 *bytes_left) +{ + int ret = 0; + u8 element_id; + struct ieee_types_fh_param_set *fh_param_set; + struct ieee_types_ds_param_set *ds_param_set; + struct ieee_types_cf_param_set *cf_param_set; + struct ieee_types_ibss_param_set *ibss_param_set; + __le16 beacon_interval; + __le16 capabilities; + u8 *current_ptr; + u8 *rate; + u8 element_len; + u16 total_ie_len; + u8 bytes_to_copy; + u8 rate_size; + u16 beacon_size; + u8 found_data_rate_ie; + u32 bytes_left_for_current_beacon; + struct ieee_types_vendor_specific *vendor_ie; + const u8 wpa_oui[4] = { 0x00, 0x50, 0xf2, 0x01 }; + const u8 wmm_oui[4] = { 0x00, 0x50, 0xf2, 0x02 }; + + found_data_rate_ie = false; + rate_size = 0; + beacon_size = 0; + + if (*bytes_left >= sizeof(beacon_size)) { + /* Extract & convert beacon size from the command buffer */ + memcpy(&beacon_size, *beacon_info, sizeof(beacon_size)); + *bytes_left -= sizeof(beacon_size); + *beacon_info += sizeof(beacon_size); + } + + if (!beacon_size || beacon_size > *bytes_left) { + *beacon_info += *bytes_left; + *bytes_left = 0; + return -1; + } + + /* Initialize the current working beacon pointer for this BSS + iteration */ + current_ptr = *beacon_info; + + /* Advance the return beacon pointer past the current beacon */ + *beacon_info += beacon_size; + *bytes_left -= beacon_size; + + bytes_left_for_current_beacon = beacon_size; + + memcpy(bss_entry->mac_address, current_ptr, ETH_ALEN); + dev_dbg(adapter->dev, "info: InterpretIE: AP MAC Addr: %pM\n", + bss_entry->mac_address); + + current_ptr += ETH_ALEN; + bytes_left_for_current_beacon -= ETH_ALEN; + + if (bytes_left_for_current_beacon < 12) { + dev_err(adapter->dev, "InterpretIE: not enough bytes left\n"); + return -1; + } + + /* + * Next 4 fields are RSSI, time stamp, beacon interval, + * and capability information + */ + + /* RSSI is 1 byte long */ + bss_entry->rssi = (s32) (*current_ptr); + dev_dbg(adapter->dev, "info: InterpretIE: RSSI=%02X\n", *current_ptr); + current_ptr += 1; + bytes_left_for_current_beacon -= 1; + + /* + * The RSSI is not part of the beacon/probe response. After we have + * advanced current_ptr past the RSSI field, save the remaining + * data for use at the application layer + */ + bss_entry->beacon_buf = current_ptr; + bss_entry->beacon_buf_size = bytes_left_for_current_beacon; + + /* Time stamp is 8 bytes long */ + memcpy(bss_entry->time_stamp, current_ptr, 8); + current_ptr += 8; + bytes_left_for_current_beacon -= 8; + + /* Beacon interval is 2 bytes long */ + memcpy(&beacon_interval, current_ptr, 2); + bss_entry->beacon_period = le16_to_cpu(beacon_interval); + current_ptr += 2; + bytes_left_for_current_beacon -= 2; + + /* Capability information is 2 bytes long */ + memcpy(&capabilities, current_ptr, 2); + dev_dbg(adapter->dev, "info: InterpretIE: capabilities=0x%X\n", + capabilities); + bss_entry->cap_info_bitmap = le16_to_cpu(capabilities); + current_ptr += 2; + bytes_left_for_current_beacon -= 2; + + /* Rest of the current buffer are IE's */ + dev_dbg(adapter->dev, "info: InterpretIE: IELength for this AP = %d\n", + bytes_left_for_current_beacon); + + if (bss_entry->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) { + dev_dbg(adapter->dev, "info: InterpretIE: AP WEP enabled\n"); + bss_entry->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP; + } else { + bss_entry->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL; + } + + if (bss_entry->cap_info_bitmap & WLAN_CAPABILITY_IBSS) + bss_entry->bss_mode = NL80211_IFTYPE_ADHOC; + else + bss_entry->bss_mode = NL80211_IFTYPE_STATION; + + + /* Process variable IE */ + while (bytes_left_for_current_beacon >= 2) { + element_id = *current_ptr; + element_len = *(current_ptr + 1); + total_ie_len = element_len + sizeof(struct ieee_types_header); + + if (bytes_left_for_current_beacon < total_ie_len) { + dev_err(adapter->dev, "err: InterpretIE: in processing" + " IE, bytes left < IE length\n"); + bytes_left_for_current_beacon = 0; + ret = -1; + continue; + } + switch (element_id) { + case WLAN_EID_SSID: + bss_entry->ssid.ssid_len = element_len; + memcpy(bss_entry->ssid.ssid, (current_ptr + 2), + element_len); + dev_dbg(adapter->dev, "info: InterpretIE: ssid: %-32s\n", + bss_entry->ssid.ssid); + break; + + case WLAN_EID_SUPP_RATES: + memcpy(bss_entry->data_rates, current_ptr + 2, + element_len); + memcpy(bss_entry->supported_rates, current_ptr + 2, + element_len); + rate_size = element_len; + found_data_rate_ie = true; + break; + + case WLAN_EID_FH_PARAMS: + fh_param_set = + (struct ieee_types_fh_param_set *) current_ptr; + memcpy(&bss_entry->phy_param_set.fh_param_set, + fh_param_set, + sizeof(struct ieee_types_fh_param_set)); + break; + + case WLAN_EID_DS_PARAMS: + ds_param_set = + (struct ieee_types_ds_param_set *) current_ptr; + + bss_entry->channel = ds_param_set->current_chan; + + memcpy(&bss_entry->phy_param_set.ds_param_set, + ds_param_set, + sizeof(struct ieee_types_ds_param_set)); + break; + + case WLAN_EID_CF_PARAMS: + cf_param_set = + (struct ieee_types_cf_param_set *) current_ptr; + memcpy(&bss_entry->ss_param_set.cf_param_set, + cf_param_set, + sizeof(struct ieee_types_cf_param_set)); + break; + + case WLAN_EID_IBSS_PARAMS: + ibss_param_set = + (struct ieee_types_ibss_param_set *) + current_ptr; + memcpy(&bss_entry->ss_param_set.ibss_param_set, + ibss_param_set, + sizeof(struct ieee_types_ibss_param_set)); + break; + + case WLAN_EID_ERP_INFO: + bss_entry->erp_flags = *(current_ptr + 2); + break; + + case WLAN_EID_EXT_SUPP_RATES: + /* + * Only process extended supported rate + * if data rate is already found. + * Data rate IE should come before + * extended supported rate IE + */ + if (found_data_rate_ie) { + if ((element_len + rate_size) > + MWIFIEX_SUPPORTED_RATES) + bytes_to_copy = + (MWIFIEX_SUPPORTED_RATES - + rate_size); + else + bytes_to_copy = element_len; + + rate = (u8 *) bss_entry->data_rates; + rate += rate_size; + memcpy(rate, current_ptr + 2, bytes_to_copy); + + rate = (u8 *) bss_entry->supported_rates; + rate += rate_size; + memcpy(rate, current_ptr + 2, bytes_to_copy); + } + break; + + case WLAN_EID_VENDOR_SPECIFIC: + vendor_ie = (struct ieee_types_vendor_specific *) + current_ptr; + + if (!memcmp + (vendor_ie->vend_hdr.oui, wpa_oui, + sizeof(wpa_oui))) { + bss_entry->bcn_wpa_ie = + (struct ieee_types_vendor_specific *) + current_ptr; + bss_entry->wpa_offset = (u16) (current_ptr - + bss_entry->beacon_buf); + } else if (!memcmp(vendor_ie->vend_hdr.oui, wmm_oui, + sizeof(wmm_oui))) { + if (total_ie_len == + sizeof(struct ieee_types_wmm_parameter) + || total_ie_len == + sizeof(struct ieee_types_wmm_info)) + /* + * Only accept and copy the WMM IE if + * it matches the size expected for the + * WMM Info IE or the WMM Parameter IE. + */ + memcpy((u8 *) &bss_entry->wmm_ie, + current_ptr, total_ie_len); + } + break; + case WLAN_EID_RSN: + bss_entry->bcn_rsn_ie = + (struct ieee_types_generic *) current_ptr; + bss_entry->rsn_offset = (u16) (current_ptr - + bss_entry->beacon_buf); + break; + case WLAN_EID_BSS_AC_ACCESS_DELAY: + bss_entry->bcn_wapi_ie = + (struct ieee_types_generic *) current_ptr; + bss_entry->wapi_offset = (u16) (current_ptr - + bss_entry->beacon_buf); + break; + case WLAN_EID_HT_CAPABILITY: + bss_entry->bcn_ht_cap = (struct ieee80211_ht_cap *) + (current_ptr + + sizeof(struct ieee_types_header)); + bss_entry->ht_cap_offset = (u16) (current_ptr + + sizeof(struct ieee_types_header) - + bss_entry->beacon_buf); + break; + case WLAN_EID_HT_INFORMATION: + bss_entry->bcn_ht_info = (struct ieee80211_ht_info *) + (current_ptr + + sizeof(struct ieee_types_header)); + bss_entry->ht_info_offset = (u16) (current_ptr + + sizeof(struct ieee_types_header) - + bss_entry->beacon_buf); + break; + case WLAN_EID_BSS_COEX_2040: + bss_entry->bcn_bss_co_2040 = (u8 *) (current_ptr + + sizeof(struct ieee_types_header)); + bss_entry->bss_co_2040_offset = (u16) (current_ptr + + sizeof(struct ieee_types_header) - + bss_entry->beacon_buf); + break; + case WLAN_EID_EXT_CAPABILITY: + bss_entry->bcn_ext_cap = (u8 *) (current_ptr + + sizeof(struct ieee_types_header)); + bss_entry->ext_cap_offset = (u16) (current_ptr + + sizeof(struct ieee_types_header) - + bss_entry->beacon_buf); + break; + case WLAN_EID_OVERLAP_BSS_SCAN_PARAM: + bss_entry->bcn_obss_scan = + (struct ieee_types_obss_scan_param *) + current_ptr; + bss_entry->overlap_bss_offset = (u16) (current_ptr - + bss_entry->beacon_buf); + break; + default: + break; + } + + current_ptr += element_len + 2; + + /* Need to account for IE ID and IE Len */ + bytes_left_for_current_beacon -= (element_len + 2); + + } /* while (bytes_left_for_current_beacon > 2) */ + return ret; +} + +/* + * This function adjusts the pointers used in beacon buffers to reflect + * shifts. + * + * The memory allocated for beacon buffers is of fixed sizes where all the + * saved beacons must be stored. New beacons are added in the free portion + * of this memory, space permitting; while duplicate beacon buffers are + * placed at the same start location. However, since duplicate beacon + * buffers may not match the size of the old one, all the following buffers + * in the memory must be shifted to either make space, or to fill up freed + * up space. + * + * This function is used to update the beacon buffer pointers that are past + * an existing beacon buffer that is updated with a new one of different + * size. The pointers are shifted by a fixed amount, either forward or + * backward. + * + * the following pointers in every affected beacon buffers are changed, if + * present - + * - WPA IE pointer + * - RSN IE pointer + * - WAPI IE pointer + * - HT capability IE pointer + * - HT information IE pointer + * - BSS coexistence 20/40 IE pointer + * - Extended capability IE pointer + * - Overlapping BSS scan parameter IE pointer + */ +static void +mwifiex_adjust_beacon_buffer_ptrs(struct mwifiex_private *priv, u8 advance, + u8 *bcn_store, u32 rem_bcn_size, + u32 num_of_ent) +{ + struct mwifiex_adapter *adapter = priv->adapter; + u32 adj_idx; + for (adj_idx = 0; adj_idx < num_of_ent; adj_idx++) { + if (adapter->scan_table[adj_idx].beacon_buf > bcn_store) { + + if (advance) + adapter->scan_table[adj_idx].beacon_buf += + rem_bcn_size; + else + adapter->scan_table[adj_idx].beacon_buf -= + rem_bcn_size; + + if (adapter->scan_table[adj_idx].bcn_wpa_ie) + adapter->scan_table[adj_idx].bcn_wpa_ie = + (struct ieee_types_vendor_specific *) + (adapter->scan_table[adj_idx].beacon_buf + + adapter->scan_table[adj_idx].wpa_offset); + if (adapter->scan_table[adj_idx].bcn_rsn_ie) + adapter->scan_table[adj_idx].bcn_rsn_ie = + (struct ieee_types_generic *) + (adapter->scan_table[adj_idx].beacon_buf + + adapter->scan_table[adj_idx].rsn_offset); + if (adapter->scan_table[adj_idx].bcn_wapi_ie) + adapter->scan_table[adj_idx].bcn_wapi_ie = + (struct ieee_types_generic *) + (adapter->scan_table[adj_idx].beacon_buf + + adapter->scan_table[adj_idx].wapi_offset); + if (adapter->scan_table[adj_idx].bcn_ht_cap) + adapter->scan_table[adj_idx].bcn_ht_cap = + (struct ieee80211_ht_cap *) + (adapter->scan_table[adj_idx].beacon_buf + + adapter->scan_table[adj_idx].ht_cap_offset); + + if (adapter->scan_table[adj_idx].bcn_ht_info) + adapter->scan_table[adj_idx].bcn_ht_info = + (struct ieee80211_ht_info *) + (adapter->scan_table[adj_idx].beacon_buf + + adapter->scan_table[adj_idx].ht_info_offset); + if (adapter->scan_table[adj_idx].bcn_bss_co_2040) + adapter->scan_table[adj_idx].bcn_bss_co_2040 = + (u8 *) + (adapter->scan_table[adj_idx].beacon_buf + + adapter->scan_table[adj_idx].bss_co_2040_offset); + if (adapter->scan_table[adj_idx].bcn_ext_cap) + adapter->scan_table[adj_idx].bcn_ext_cap = + (u8 *) + (adapter->scan_table[adj_idx].beacon_buf + + adapter->scan_table[adj_idx].ext_cap_offset); + if (adapter->scan_table[adj_idx].bcn_obss_scan) + adapter->scan_table[adj_idx].bcn_obss_scan = + (struct ieee_types_obss_scan_param *) + (adapter->scan_table[adj_idx].beacon_buf + + adapter->scan_table[adj_idx].overlap_bss_offset); + } + } +} + +/* + * This function updates the pointers used in beacon buffer for given bss + * descriptor to reflect shifts + * + * Following pointers are updated + * - WPA IE pointer + * - RSN IE pointer + * - WAPI IE pointer + * - HT capability IE pointer + * - HT information IE pointer + * - BSS coexistence 20/40 IE pointer + * - Extended capability IE pointer + * - Overlapping BSS scan parameter IE pointer + */ +static void +mwifiex_update_beacon_buffer_ptrs(struct mwifiex_bssdescriptor *beacon) +{ + if (beacon->bcn_wpa_ie) + beacon->bcn_wpa_ie = (struct ieee_types_vendor_specific *) + (beacon->beacon_buf + beacon->wpa_offset); + if (beacon->bcn_rsn_ie) + beacon->bcn_rsn_ie = (struct ieee_types_generic *) + (beacon->beacon_buf + beacon->rsn_offset); + if (beacon->bcn_wapi_ie) + beacon->bcn_wapi_ie = (struct ieee_types_generic *) + (beacon->beacon_buf + beacon->wapi_offset); + if (beacon->bcn_ht_cap) + beacon->bcn_ht_cap = (struct ieee80211_ht_cap *) + (beacon->beacon_buf + beacon->ht_cap_offset); + if (beacon->bcn_ht_info) + beacon->bcn_ht_info = (struct ieee80211_ht_info *) + (beacon->beacon_buf + beacon->ht_info_offset); + if (beacon->bcn_bss_co_2040) + beacon->bcn_bss_co_2040 = (u8 *) (beacon->beacon_buf + + beacon->bss_co_2040_offset); + if (beacon->bcn_ext_cap) + beacon->bcn_ext_cap = (u8 *) (beacon->beacon_buf + + beacon->ext_cap_offset); + if (beacon->bcn_obss_scan) + beacon->bcn_obss_scan = (struct ieee_types_obss_scan_param *) + (beacon->beacon_buf + beacon->overlap_bss_offset); +} + +/* + * This function stores a beacon or probe response for a BSS returned + * in the scan. + * + * This stores a new scan response or an update for a previous scan response. + * New entries need to verify that they do not exceed the total amount of + * memory allocated for the table. + * + * Replacement entries need to take into consideration the amount of space + * currently allocated for the beacon/probe response and adjust the entry + * as needed. + * + * A small amount of extra pad (SCAN_BEACON_ENTRY_PAD) is generally reserved + * for an entry in case it is a beacon since a probe response for the + * network will by larger per the standard. This helps to reduce the + * amount of memory copying to fit a new probe response into an entry + * already occupied by a network's previously stored beacon. + */ +static void +mwifiex_ret_802_11_scan_store_beacon(struct mwifiex_private *priv, + u32 beacon_idx, u32 num_of_ent, + struct mwifiex_bssdescriptor *new_beacon) +{ + struct mwifiex_adapter *adapter = priv->adapter; + u8 *bcn_store; + u32 new_bcn_size; + u32 old_bcn_size; + u32 bcn_space; + + if (adapter->scan_table[beacon_idx].beacon_buf) { + + new_bcn_size = new_beacon->beacon_buf_size; + old_bcn_size = adapter->scan_table[beacon_idx].beacon_buf_size; + bcn_space = adapter->scan_table[beacon_idx].beacon_buf_size_max; + bcn_store = adapter->scan_table[beacon_idx].beacon_buf; + + /* Set the max to be the same as current entry unless changed + below */ + new_beacon->beacon_buf_size_max = bcn_space; + if (new_bcn_size == old_bcn_size) { + /* + * Beacon is the same size as the previous entry. + * Replace the previous contents with the scan result + */ + memcpy(bcn_store, new_beacon->beacon_buf, + new_beacon->beacon_buf_size); + + } else if (new_bcn_size <= bcn_space) { + /* + * New beacon size will fit in the amount of space + * we have previously allocated for it + */ + + /* Copy the new beacon buffer entry over the old one */ + memcpy(bcn_store, new_beacon->beacon_buf, new_bcn_size); + + /* + * If the old beacon size was less than the maximum + * we had alloted for the entry, and the new entry + * is even smaller, reset the max size to the old + * beacon entry and compress the storage space + * (leaving a new pad space of (old_bcn_size - + * new_bcn_size). + */ + if (old_bcn_size < bcn_space + && new_bcn_size <= old_bcn_size) { + /* + * Old Beacon size is smaller than the alloted + * storage size. Shrink the alloted storage + * space. + */ + dev_dbg(adapter->dev, "info: AppControl:" + " smaller duplicate beacon " + "(%d), old = %d, new = %d, space = %d," + "left = %d\n", + beacon_idx, old_bcn_size, new_bcn_size, + bcn_space, + (int)(sizeof(adapter->bcn_buf) - + (adapter->bcn_buf_end - + adapter->bcn_buf))); + + /* + * memmove (since the memory overlaps) the + * data after the beacon we just stored to the + * end of the current beacon. This cleans up + * any unused space the old larger beacon was + * using in the buffer + */ + memmove(bcn_store + old_bcn_size, + bcn_store + bcn_space, + adapter->bcn_buf_end - (bcn_store + + bcn_space)); + + /* + * Decrement the end pointer by the difference + * between the old larger size and the new + * smaller size since we are using less space + * due to the new beacon being smaller + */ + adapter->bcn_buf_end -= + (bcn_space - old_bcn_size); + + /* Set the maximum storage size to the old + beacon size */ + new_beacon->beacon_buf_size_max = old_bcn_size; + + /* Adjust beacon buffer pointers that are past + the current */ + mwifiex_adjust_beacon_buffer_ptrs(priv, 0, + bcn_store, (bcn_space - old_bcn_size), + num_of_ent); + } + } else if (adapter->bcn_buf_end + (new_bcn_size - bcn_space) + < (adapter->bcn_buf + sizeof(adapter->bcn_buf))) { + /* + * Beacon is larger than space previously allocated + * (bcn_space) and there is enough space left in the + * beaconBuffer to store the additional data + */ + dev_dbg(adapter->dev, "info: AppControl:" + " larger duplicate beacon (%d), " + "old = %d, new = %d, space = %d, left = %d\n", + beacon_idx, old_bcn_size, new_bcn_size, + bcn_space, + (int)(sizeof(adapter->bcn_buf) - + (adapter->bcn_buf_end - + adapter->bcn_buf))); + + /* + * memmove (since the memory overlaps) the data + * after the beacon we just stored to the end of + * the current beacon. This moves the data for + * the beacons after this further in memory to + * make space for the new larger beacon we are + * about to copy in. + */ + memmove(bcn_store + new_bcn_size, + bcn_store + bcn_space, + adapter->bcn_buf_end - (bcn_store + bcn_space)); + + /* Copy the new beacon buffer entry over the old one */ + memcpy(bcn_store, new_beacon->beacon_buf, new_bcn_size); + + /* Move the beacon end pointer by the amount of new + beacon data we are adding */ + adapter->bcn_buf_end += (new_bcn_size - bcn_space); + + /* + * This entry is bigger than the alloted max space + * previously reserved. Increase the max space to + * be equal to the new beacon size + */ + new_beacon->beacon_buf_size_max = new_bcn_size; + + /* Adjust beacon buffer pointers that are past the + current */ + mwifiex_adjust_beacon_buffer_ptrs(priv, 1, bcn_store, + (new_bcn_size - bcn_space), + num_of_ent); + } else { + /* + * Beacon is larger than the previously allocated space, + * but there is not enough free space to store the + * additional data. + */ + dev_err(adapter->dev, "AppControl: larger duplicate " + " beacon (%d), old = %d new = %d, space = %d," + " left = %d\n", beacon_idx, old_bcn_size, + new_bcn_size, bcn_space, + (int)(sizeof(adapter->bcn_buf) - + (adapter->bcn_buf_end - adapter->bcn_buf))); + + /* Storage failure, keep old beacon intact */ + new_beacon->beacon_buf_size = old_bcn_size; + if (new_beacon->bcn_wpa_ie) + new_beacon->wpa_offset = + adapter->scan_table[beacon_idx]. + wpa_offset; + if (new_beacon->bcn_rsn_ie) + new_beacon->rsn_offset = + adapter->scan_table[beacon_idx]. + rsn_offset; + if (new_beacon->bcn_wapi_ie) + new_beacon->wapi_offset = + adapter->scan_table[beacon_idx]. + wapi_offset; + if (new_beacon->bcn_ht_cap) + new_beacon->ht_cap_offset = + adapter->scan_table[beacon_idx]. + ht_cap_offset; + if (new_beacon->bcn_ht_info) + new_beacon->ht_info_offset = + adapter->scan_table[beacon_idx]. + ht_info_offset; + if (new_beacon->bcn_bss_co_2040) + new_beacon->bss_co_2040_offset = + adapter->scan_table[beacon_idx]. + bss_co_2040_offset; + if (new_beacon->bcn_ext_cap) + new_beacon->ext_cap_offset = + adapter->scan_table[beacon_idx]. + ext_cap_offset; + if (new_beacon->bcn_obss_scan) + new_beacon->overlap_bss_offset = + adapter->scan_table[beacon_idx]. + overlap_bss_offset; + } + /* Point the new entry to its permanent storage space */ + new_beacon->beacon_buf = bcn_store; + mwifiex_update_beacon_buffer_ptrs(new_beacon); + } else { + /* + * No existing beacon data exists for this entry, check to see + * if we can fit it in the remaining space + */ + if (adapter->bcn_buf_end + new_beacon->beacon_buf_size + + SCAN_BEACON_ENTRY_PAD < (adapter->bcn_buf + + sizeof(adapter->bcn_buf))) { + + /* + * Copy the beacon buffer data from the local entry to + * the adapter dev struct buffer space used to store + * the raw beacon data for each entry in the scan table + */ + memcpy(adapter->bcn_buf_end, new_beacon->beacon_buf, + new_beacon->beacon_buf_size); + + /* Update the beacon ptr to point to the table save + area */ + new_beacon->beacon_buf = adapter->bcn_buf_end; + new_beacon->beacon_buf_size_max = + (new_beacon->beacon_buf_size + + SCAN_BEACON_ENTRY_PAD); + + mwifiex_update_beacon_buffer_ptrs(new_beacon); + + /* Increment the end pointer by the size reserved */ + adapter->bcn_buf_end += new_beacon->beacon_buf_size_max; + + dev_dbg(adapter->dev, "info: AppControl: beacon[%02d]" + " sz=%03d, used = %04d, left = %04d\n", + beacon_idx, + new_beacon->beacon_buf_size, + (int)(adapter->bcn_buf_end - adapter->bcn_buf), + (int)(sizeof(adapter->bcn_buf) - + (adapter->bcn_buf_end - + adapter->bcn_buf))); + } else { + /* No space for new beacon */ + dev_dbg(adapter->dev, "info: AppControl: no space for" + " beacon (%d): %pM sz=%03d, left=%03d\n", + beacon_idx, new_beacon->mac_address, + new_beacon->beacon_buf_size, + (int)(sizeof(adapter->bcn_buf) - + (adapter->bcn_buf_end - + adapter->bcn_buf))); + + /* Storage failure; clear storage records for this + bcn */ + new_beacon->beacon_buf = NULL; + new_beacon->beacon_buf_size = 0; + new_beacon->beacon_buf_size_max = 0; + new_beacon->bcn_wpa_ie = NULL; + new_beacon->wpa_offset = 0; + new_beacon->bcn_rsn_ie = NULL; + new_beacon->rsn_offset = 0; + new_beacon->bcn_wapi_ie = NULL; + new_beacon->wapi_offset = 0; + new_beacon->bcn_ht_cap = NULL; + new_beacon->ht_cap_offset = 0; + new_beacon->bcn_ht_info = NULL; + new_beacon->ht_info_offset = 0; + new_beacon->bcn_bss_co_2040 = NULL; + new_beacon->bss_co_2040_offset = 0; + new_beacon->bcn_ext_cap = NULL; + new_beacon->ext_cap_offset = 0; + new_beacon->bcn_obss_scan = NULL; + new_beacon->overlap_bss_offset = 0; + } + } +} + +/* + * This function restores a beacon buffer of the current BSS descriptor. + */ +static void mwifiex_restore_curr_bcn(struct mwifiex_private *priv) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_bssdescriptor *curr_bss = + &priv->curr_bss_params.bss_descriptor; + unsigned long flags; + + if (priv->curr_bcn_buf && + ((adapter->bcn_buf_end + priv->curr_bcn_size) < + (adapter->bcn_buf + sizeof(adapter->bcn_buf)))) { + spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags); + + /* restore the current beacon buffer */ + memcpy(adapter->bcn_buf_end, priv->curr_bcn_buf, + priv->curr_bcn_size); + curr_bss->beacon_buf = adapter->bcn_buf_end; + curr_bss->beacon_buf_size = priv->curr_bcn_size; + adapter->bcn_buf_end += priv->curr_bcn_size; + + /* adjust the pointers in the current BSS descriptor */ + if (curr_bss->bcn_wpa_ie) + curr_bss->bcn_wpa_ie = + (struct ieee_types_vendor_specific *) + (curr_bss->beacon_buf + + curr_bss->wpa_offset); + + if (curr_bss->bcn_rsn_ie) + curr_bss->bcn_rsn_ie = (struct ieee_types_generic *) + (curr_bss->beacon_buf + + curr_bss->rsn_offset); + + if (curr_bss->bcn_ht_cap) + curr_bss->bcn_ht_cap = (struct ieee80211_ht_cap *) + (curr_bss->beacon_buf + + curr_bss->ht_cap_offset); + + if (curr_bss->bcn_ht_info) + curr_bss->bcn_ht_info = (struct ieee80211_ht_info *) + (curr_bss->beacon_buf + + curr_bss->ht_info_offset); + + if (curr_bss->bcn_bss_co_2040) + curr_bss->bcn_bss_co_2040 = + (u8 *) (curr_bss->beacon_buf + + curr_bss->bss_co_2040_offset); + + if (curr_bss->bcn_ext_cap) + curr_bss->bcn_ext_cap = (u8 *) (curr_bss->beacon_buf + + curr_bss->ext_cap_offset); + + if (curr_bss->bcn_obss_scan) + curr_bss->bcn_obss_scan = + (struct ieee_types_obss_scan_param *) + (curr_bss->beacon_buf + + curr_bss->overlap_bss_offset); + + spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags); + + dev_dbg(adapter->dev, "info: current beacon restored %d\n", + priv->curr_bcn_size); + } else { + dev_warn(adapter->dev, + "curr_bcn_buf not saved or bcn_buf has no space\n"); + } +} + +/* + * This function post processes the scan table after a new scan command has + * completed. + * + * It inspects each entry of the scan table and tries to find an entry that + * matches with our current associated/joined network from the scan. If + * one is found, the stored copy of the BSS descriptor of our current network + * is updated. + * + * It also debug dumps the current scan table contents after processing is over. + */ +static void +mwifiex_process_scan_results(struct mwifiex_private *priv) +{ + struct mwifiex_adapter *adapter = priv->adapter; + s32 j; + u32 i; + unsigned long flags; + + if (priv->media_connected) { + + j = mwifiex_find_ssid_in_list(priv, &priv->curr_bss_params. + bss_descriptor.ssid, + priv->curr_bss_params. + bss_descriptor.mac_address, + priv->bss_mode); + + if (j >= 0) { + spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags); + priv->curr_bss_params.bss_descriptor.bcn_wpa_ie = NULL; + priv->curr_bss_params.bss_descriptor.wpa_offset = 0; + priv->curr_bss_params.bss_descriptor.bcn_rsn_ie = NULL; + priv->curr_bss_params.bss_descriptor.rsn_offset = 0; + priv->curr_bss_params.bss_descriptor.bcn_wapi_ie = NULL; + priv->curr_bss_params.bss_descriptor.wapi_offset = 0; + priv->curr_bss_params.bss_descriptor.bcn_ht_cap = NULL; + priv->curr_bss_params.bss_descriptor.ht_cap_offset = + 0; + priv->curr_bss_params.bss_descriptor.bcn_ht_info = NULL; + priv->curr_bss_params.bss_descriptor.ht_info_offset = + 0; + priv->curr_bss_params.bss_descriptor.bcn_bss_co_2040 = + NULL; + priv->curr_bss_params.bss_descriptor. + bss_co_2040_offset = 0; + priv->curr_bss_params.bss_descriptor.bcn_ext_cap = NULL; + priv->curr_bss_params.bss_descriptor.ext_cap_offset = 0; + priv->curr_bss_params.bss_descriptor. + bcn_obss_scan = NULL; + priv->curr_bss_params.bss_descriptor. + overlap_bss_offset = 0; + priv->curr_bss_params.bss_descriptor.beacon_buf = NULL; + priv->curr_bss_params.bss_descriptor.beacon_buf_size = + 0; + priv->curr_bss_params.bss_descriptor. + beacon_buf_size_max = 0; + + dev_dbg(adapter->dev, "info: Found current ssid/bssid" + " in list @ index #%d\n", j); + /* Make a copy of current BSSID descriptor */ + memcpy(&priv->curr_bss_params.bss_descriptor, + &adapter->scan_table[j], + sizeof(priv->curr_bss_params.bss_descriptor)); + + mwifiex_save_curr_bcn(priv); + spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags); + + } else { + mwifiex_restore_curr_bcn(priv); + } + } + + for (i = 0; i < adapter->num_in_scan_table; i++) + dev_dbg(adapter->dev, "info: scan:(%02d) %pM " + "RSSI[%03d], SSID[%s]\n", + i, adapter->scan_table[i].mac_address, + (s32) adapter->scan_table[i].rssi, + adapter->scan_table[i].ssid.ssid); +} + +/* + * This function converts radio type scan parameter to a band configuration + * to be used in join command. + */ +static u8 +mwifiex_radio_type_to_band(u8 radio_type) +{ + u8 ret_band; + + switch (radio_type) { + case HostCmd_SCAN_RADIO_TYPE_A: + ret_band = BAND_A; + break; + case HostCmd_SCAN_RADIO_TYPE_BG: + default: + ret_band = BAND_G; + break; + } + + return ret_band; +} + +/* + * This function deletes a specific indexed entry from the scan table. + * + * This also compacts the remaining entries and adjusts any buffering + * of beacon/probe response data if needed. + */ +static void +mwifiex_scan_delete_table_entry(struct mwifiex_private *priv, s32 table_idx) +{ + struct mwifiex_adapter *adapter = priv->adapter; + u32 del_idx; + u32 beacon_buf_adj; + u8 *beacon_buf; + + /* + * Shift the saved beacon buffer data for the scan table back over the + * entry being removed. Update the end of buffer pointer. Save the + * deleted buffer allocation size for pointer adjustments for entries + * compacted after the deleted index. + */ + beacon_buf_adj = adapter->scan_table[table_idx].beacon_buf_size_max; + + dev_dbg(adapter->dev, "info: Scan: Delete Entry %d, beacon buffer " + "removal = %d bytes\n", table_idx, beacon_buf_adj); + + /* Check if the table entry had storage allocated for its beacon */ + if (beacon_buf_adj) { + beacon_buf = adapter->scan_table[table_idx].beacon_buf; + + /* + * Remove the entry's buffer space, decrement the table end + * pointer by the amount we are removing + */ + adapter->bcn_buf_end -= beacon_buf_adj; + + dev_dbg(adapter->dev, "info: scan: delete entry %d," + " compact data: %p <- %p (sz = %d)\n", + table_idx, beacon_buf, + beacon_buf + beacon_buf_adj, + (int)(adapter->bcn_buf_end - beacon_buf)); + + /* + * Compact data storage. Copy all data after the deleted + * entry's end address (beacon_buf + beacon_buf_adj) back + * to the original start address (beacon_buf). + * + * Scan table entries affected by the move will have their + * entry pointer adjusted below. + * + * Use memmove since the dest/src memory regions overlap. + */ + memmove(beacon_buf, beacon_buf + beacon_buf_adj, + adapter->bcn_buf_end - beacon_buf); + } + + dev_dbg(adapter->dev, + "info: Scan: Delete Entry %d, num_in_scan_table = %d\n", + table_idx, adapter->num_in_scan_table); + + /* Shift all of the entries after the table_idx back by one, compacting + the table and removing the requested entry */ + for (del_idx = table_idx; (del_idx + 1) < adapter->num_in_scan_table; + del_idx++) { + /* Copy the next entry over this one */ + memcpy(adapter->scan_table + del_idx, + adapter->scan_table + del_idx + 1, + sizeof(struct mwifiex_bssdescriptor)); + + /* + * Adjust this entry's pointer to its beacon buffer based on + * the removed/compacted entry from the deleted index. Don't + * decrement if the buffer pointer is NULL (no data stored for + * this entry). + */ + if (adapter->scan_table[del_idx].beacon_buf) { + adapter->scan_table[del_idx].beacon_buf -= + beacon_buf_adj; + if (adapter->scan_table[del_idx].bcn_wpa_ie) + adapter->scan_table[del_idx].bcn_wpa_ie = + (struct ieee_types_vendor_specific *) + (adapter->scan_table[del_idx]. + beacon_buf + + adapter->scan_table[del_idx]. + wpa_offset); + if (adapter->scan_table[del_idx].bcn_rsn_ie) + adapter->scan_table[del_idx].bcn_rsn_ie = + (struct ieee_types_generic *) + (adapter->scan_table[del_idx]. + beacon_buf + + adapter->scan_table[del_idx]. + rsn_offset); + if (adapter->scan_table[del_idx].bcn_wapi_ie) + adapter->scan_table[del_idx].bcn_wapi_ie = + (struct ieee_types_generic *) + (adapter->scan_table[del_idx].beacon_buf + + adapter->scan_table[del_idx]. + wapi_offset); + if (adapter->scan_table[del_idx].bcn_ht_cap) + adapter->scan_table[del_idx].bcn_ht_cap = + (struct ieee80211_ht_cap *) + (adapter->scan_table[del_idx].beacon_buf + + adapter->scan_table[del_idx]. + ht_cap_offset); + + if (adapter->scan_table[del_idx].bcn_ht_info) + adapter->scan_table[del_idx].bcn_ht_info = + (struct ieee80211_ht_info *) + (adapter->scan_table[del_idx].beacon_buf + + adapter->scan_table[del_idx]. + ht_info_offset); + if (adapter->scan_table[del_idx].bcn_bss_co_2040) + adapter->scan_table[del_idx].bcn_bss_co_2040 = + (u8 *) + (adapter->scan_table[del_idx].beacon_buf + + adapter->scan_table[del_idx]. + bss_co_2040_offset); + if (adapter->scan_table[del_idx].bcn_ext_cap) + adapter->scan_table[del_idx].bcn_ext_cap = + (u8 *) + (adapter->scan_table[del_idx].beacon_buf + + adapter->scan_table[del_idx]. + ext_cap_offset); + if (adapter->scan_table[del_idx].bcn_obss_scan) + adapter->scan_table[del_idx]. + bcn_obss_scan = + (struct ieee_types_obss_scan_param *) + (adapter->scan_table[del_idx].beacon_buf + + adapter->scan_table[del_idx]. + overlap_bss_offset); + } + } + + /* The last entry is invalid now that it has been deleted or moved + back */ + memset(adapter->scan_table + adapter->num_in_scan_table - 1, + 0x00, sizeof(struct mwifiex_bssdescriptor)); + + adapter->num_in_scan_table--; +} + +/* + * This function deletes all occurrences of a given SSID from the scan table. + * + * This iterates through the scan table and deletes all entries that match + * the given SSID. It also compacts the remaining scan table entries. + */ +static int +mwifiex_scan_delete_ssid_table_entry(struct mwifiex_private *priv, + struct mwifiex_802_11_ssid *del_ssid) +{ + int ret = -1; + s32 table_idx; + + dev_dbg(priv->adapter->dev, "info: scan: delete ssid entry: %-32s\n", + del_ssid->ssid); + + /* If the requested SSID is found in the table, delete it. Then keep + searching the table for multiple entires for the SSID until no + more are found */ + while ((table_idx = mwifiex_find_ssid_in_list(priv, del_ssid, NULL, + NL80211_IFTYPE_UNSPECIFIED)) >= 0) { + dev_dbg(priv->adapter->dev, + "info: Scan: Delete SSID Entry: Found Idx = %d\n", + table_idx); + ret = 0; + mwifiex_scan_delete_table_entry(priv, table_idx); + } + + return ret; +} + +/* + * This is an internal function used to start a scan based on an input + * configuration. + * + * This uses the input user scan configuration information when provided in + * order to send the appropriate scan commands to firmware to populate or + * update the internal driver scan table. + */ +int mwifiex_scan_networks(struct mwifiex_private *priv, + void *wait_buf, u16 action, + const struct mwifiex_user_scan_cfg *user_scan_in, + struct mwifiex_scan_resp *scan_resp) +{ + int ret = 0; + struct mwifiex_adapter *adapter = priv->adapter; + struct cmd_ctrl_node *cmd_node = NULL; + union mwifiex_scan_cmd_config_tlv *scan_cfg_out = NULL; + struct mwifiex_ie_types_chan_list_param_set *chan_list_out; + u32 buf_size; + struct mwifiex_chan_scan_param_set *scan_chan_list; + u8 keep_previous_scan; + u8 filtered_scan; + u8 scan_current_chan_only; + u8 max_chan_per_scan; + unsigned long flags; + + if (action == HostCmd_ACT_GEN_GET) { + if (scan_resp) { + scan_resp->scan_table = (u8 *) adapter->scan_table; + scan_resp->num_in_scan_table = + adapter->num_in_scan_table; + } else { + ret = -1; + } + return ret; + } + + if (adapter->scan_processing && action == HostCmd_ACT_GEN_SET) { + dev_dbg(adapter->dev, "cmd: Scan already in process...\n"); + return ret; + } + + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->scan_processing = true; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + + if (priv->scan_block && action == HostCmd_ACT_GEN_SET) { + dev_dbg(adapter->dev, + "cmd: Scan is blocked during association...\n"); + return ret; + } + + scan_cfg_out = kzalloc(sizeof(union mwifiex_scan_cmd_config_tlv), + GFP_KERNEL); + if (!scan_cfg_out) { + dev_err(adapter->dev, "failed to alloc scan_cfg_out\n"); + return -1; + } + + buf_size = sizeof(struct mwifiex_chan_scan_param_set) * + MWIFIEX_USER_SCAN_CHAN_MAX; + scan_chan_list = kzalloc(buf_size, GFP_KERNEL); + if (!scan_chan_list) { + dev_err(adapter->dev, "failed to alloc scan_chan_list\n"); + kfree(scan_cfg_out); + return -1; + } + + keep_previous_scan = false; + + mwifiex_scan_setup_scan_config(priv, user_scan_in, + &scan_cfg_out->config, &chan_list_out, + scan_chan_list, &max_chan_per_scan, + &filtered_scan, &scan_current_chan_only); + + if (user_scan_in) + keep_previous_scan = user_scan_in->keep_previous_scan; + + + if (!keep_previous_scan) { + memset(adapter->scan_table, 0x00, + sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP); + adapter->num_in_scan_table = 0; + adapter->bcn_buf_end = adapter->bcn_buf; + } + + ret = mwifiex_scan_channel_list(priv, wait_buf, max_chan_per_scan, + filtered_scan, &scan_cfg_out->config, + chan_list_out, scan_chan_list); + + /* Get scan command from scan_pending_q and put to cmd_pending_q */ + if (!ret) { + spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); + if (!list_empty(&adapter->scan_pending_q)) { + cmd_node = list_first_entry(&adapter->scan_pending_q, + struct cmd_ctrl_node, list); + list_del(&cmd_node->list); + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, + flags); + mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, + true); + } else { + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, + flags); + } + ret = -EINPROGRESS; + } else { + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->scan_processing = true; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + } + + kfree(scan_cfg_out); + kfree(scan_chan_list); + return ret; +} + +/* + * This function prepares a scan command to be sent to the firmware. + * + * This uses the scan command configuration sent to the command processing + * module in command preparation stage to configure a scan command structure + * to send to firmware. + * + * The fixed fields specifying the BSS type and BSSID filters as well as a + * variable number/length of TLVs are sent in the command to firmware. + * + * Preparation also includes - + * - Setting command ID, and proper size + * - Ensuring correct endian-ness + */ +int mwifiex_cmd_802_11_scan(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, void *data_buf) +{ + struct host_cmd_ds_802_11_scan *scan_cmd = &cmd->params.scan; + struct mwifiex_scan_cmd_config *scan_cfg; + + scan_cfg = (struct mwifiex_scan_cmd_config *) data_buf; + + /* Set fixed field variables in scan command */ + scan_cmd->bss_mode = scan_cfg->bss_mode; + memcpy(scan_cmd->bssid, scan_cfg->specific_bssid, + sizeof(scan_cmd->bssid)); + memcpy(scan_cmd->tlv_buffer, scan_cfg->tlv_buf, scan_cfg->tlv_buf_len); + + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SCAN); + + /* Size is equal to the sizeof(fixed portions) + the TLV len + header */ + cmd->size = cpu_to_le16((u16) (sizeof(scan_cmd->bss_mode) + + sizeof(scan_cmd->bssid) + + scan_cfg->tlv_buf_len + S_DS_GEN)); + + return 0; +} + +/* + * This function handles the command response of scan. + * + * The response buffer for the scan command has the following + * memory layout: + * + * .-------------------------------------------------------------. + * | Header (4 * sizeof(t_u16)): Standard command response hdr | + * .-------------------------------------------------------------. + * | BufSize (t_u16) : sizeof the BSS Description data | + * .-------------------------------------------------------------. + * | NumOfSet (t_u8) : Number of BSS Descs returned | + * .-------------------------------------------------------------. + * | BSSDescription data (variable, size given in BufSize) | + * .-------------------------------------------------------------. + * | TLV data (variable, size calculated using Header->Size, | + * | BufSize and sizeof the fixed fields above) | + * .-------------------------------------------------------------. + */ +int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, void *wq_buf) +{ + int ret = 0; + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_wait_queue *wait_queue = NULL; + struct cmd_ctrl_node *cmd_node = NULL; + struct host_cmd_ds_802_11_scan_rsp *scan_rsp = NULL; + struct mwifiex_bssdescriptor *bss_new_entry = NULL; + struct mwifiex_ie_types_data *tlv_data; + struct mwifiex_ie_types_tsf_timestamp *tsf_tlv; + u8 *bss_info; + u32 scan_resp_size; + u32 bytes_left; + u32 num_in_table; + u32 bss_idx; + u32 idx; + u32 tlv_buf_size; + long long tsf_val; + struct mwifiex_chan_freq_power *cfp; + struct mwifiex_ie_types_chan_band_list_param_set *chan_band_tlv; + struct chan_band_param_set *chan_band; + u8 band; + u8 is_bgscan_resp; + unsigned long flags; + + is_bgscan_resp = (le16_to_cpu(resp->command) + == HostCmd_CMD_802_11_BG_SCAN_QUERY); + if (is_bgscan_resp) + scan_rsp = &resp->params.bg_scan_query_resp.scan_resp; + else + scan_rsp = &resp->params.scan_resp; + + + if (scan_rsp->number_of_sets > IW_MAX_AP) { + dev_err(adapter->dev, "SCAN_RESP: too many AP returned (%d)\n", + scan_rsp->number_of_sets); + ret = -1; + goto done; + } + + bytes_left = le16_to_cpu(scan_rsp->bss_descript_size); + dev_dbg(adapter->dev, "info: SCAN_RESP: bss_descript_size %d\n", + bytes_left); + + scan_resp_size = le16_to_cpu(resp->size); + + dev_dbg(adapter->dev, + "info: SCAN_RESP: returned %d APs before parsing\n", + scan_rsp->number_of_sets); + + num_in_table = adapter->num_in_scan_table; + bss_info = scan_rsp->bss_desc_and_tlv_buffer; + + /* + * The size of the TLV buffer is equal to the entire command response + * size (scan_resp_size) minus the fixed fields (sizeof()'s), the + * BSS Descriptions (bss_descript_size as bytesLef) and the command + * response header (S_DS_GEN) + */ + tlv_buf_size = scan_resp_size - (bytes_left + + sizeof(scan_rsp->bss_descript_size) + + sizeof(scan_rsp->number_of_sets) + + S_DS_GEN); + + tlv_data = (struct mwifiex_ie_types_data *) (scan_rsp-> + bss_desc_and_tlv_buffer + + bytes_left); + + /* Search the TLV buffer space in the scan response for any valid + TLVs */ + mwifiex_ret_802_11_scan_get_tlv_ptrs(adapter, tlv_data, tlv_buf_size, + TLV_TYPE_TSFTIMESTAMP, + (struct mwifiex_ie_types_data **) + &tsf_tlv); + + /* Search the TLV buffer space in the scan response for any valid + TLVs */ + mwifiex_ret_802_11_scan_get_tlv_ptrs(adapter, tlv_data, tlv_buf_size, + TLV_TYPE_CHANNELBANDLIST, + (struct mwifiex_ie_types_data **) + &chan_band_tlv); + + /* + * Process each scan response returned (scan_rsp->number_of_sets). + * Save the information in the bss_new_entry and then insert into the + * driver scan table either as an update to an existing entry + * or as an addition at the end of the table + */ + bss_new_entry = kzalloc(sizeof(struct mwifiex_bssdescriptor), + GFP_KERNEL); + if (!bss_new_entry) { + dev_err(adapter->dev, " failed to alloc bss_new_entry\n"); + return -1; + } + + for (idx = 0; idx < scan_rsp->number_of_sets && bytes_left; idx++) { + /* Zero out the bss_new_entry we are about to store info in */ + memset(bss_new_entry, 0x00, + sizeof(struct mwifiex_bssdescriptor)); + + if (mwifiex_interpret_bss_desc_with_ie(adapter, bss_new_entry, + &bss_info, + &bytes_left)) { + /* Error parsing/interpreting scan response, skipped */ + dev_err(adapter->dev, "SCAN_RESP: " + "mwifiex_interpret_bss_desc_with_ie " + "returned ERROR\n"); + continue; + } + + /* Process the data fields and IEs returned for this BSS */ + dev_dbg(adapter->dev, "info: SCAN_RESP: BSSID = %pM\n", + bss_new_entry->mac_address); + + /* Search the scan table for the same bssid */ + for (bss_idx = 0; bss_idx < num_in_table; bss_idx++) { + if (memcmp(bss_new_entry->mac_address, + adapter->scan_table[bss_idx].mac_address, + sizeof(bss_new_entry->mac_address))) { + continue; + } + /* + * If the SSID matches as well, it is a + * duplicate of this entry. Keep the bss_idx + * set to this entry so we replace the old + * contents in the table + */ + if ((bss_new_entry->ssid.ssid_len + == adapter->scan_table[bss_idx]. ssid.ssid_len) + && (!memcmp(bss_new_entry->ssid.ssid, + adapter->scan_table[bss_idx].ssid.ssid, + bss_new_entry->ssid.ssid_len))) { + dev_dbg(adapter->dev, "info: SCAN_RESP:" + " duplicate of index: %d\n", bss_idx); + break; + } + } + /* + * If the bss_idx is equal to the number of entries in + * the table, the new entry was not a duplicate; append + * it to the scan table + */ + if (bss_idx == num_in_table) { + /* Range check the bss_idx, keep it limited to + the last entry */ + if (bss_idx == IW_MAX_AP) + bss_idx--; + else + num_in_table++; + } + + /* + * Save the beacon/probe response returned for later application + * retrieval. Duplicate beacon/probe responses are updated if + * possible + */ + mwifiex_ret_802_11_scan_store_beacon(priv, bss_idx, + num_in_table, bss_new_entry); + /* + * If the TSF TLV was appended to the scan results, save this + * entry's TSF value in the networkTSF field.The networkTSF is + * the firmware's TSF value at the time the beacon or probe + * response was received. + */ + if (tsf_tlv) { + memcpy(&tsf_val, &tsf_tlv->tsf_data[idx * TSF_DATA_SIZE] + , sizeof(tsf_val)); + memcpy(&bss_new_entry->network_tsf, &tsf_val, + sizeof(bss_new_entry->network_tsf)); + } + band = BAND_G; + if (chan_band_tlv) { + chan_band = &chan_band_tlv->chan_band_param[idx]; + band = mwifiex_radio_type_to_band(chan_band->radio_type + & (BIT(0) | BIT(1))); + } + + /* Save the band designation for this entry for use in join */ + bss_new_entry->bss_band = band; + cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211(priv, + (u8) bss_new_entry->bss_band, + (u16)bss_new_entry->channel); + + if (cfp) + bss_new_entry->freq = cfp->freq; + else + bss_new_entry->freq = 0; + + /* Copy the locally created bss_new_entry to the scan table */ + memcpy(&adapter->scan_table[bss_idx], bss_new_entry, + sizeof(adapter->scan_table[bss_idx])); + + } + + dev_dbg(adapter->dev, + "info: SCAN_RESP: Scanned %2d APs, %d valid, %d total\n", + scan_rsp->number_of_sets, + num_in_table - adapter->num_in_scan_table, num_in_table); + + /* Update the total number of BSSIDs in the scan table */ + adapter->num_in_scan_table = num_in_table; + + spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); + if (list_empty(&adapter->scan_pending_q)) { + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->scan_processing = false; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + /* + * Process the resulting scan table: + * - Remove any bad ssids + * - Update our current BSS information from scan data + */ + mwifiex_process_scan_results(priv); + + /* Need to indicate IOCTL complete */ + wait_queue = (struct mwifiex_wait_queue *) wq_buf; + if (wait_queue) { + wait_queue->status = MWIFIEX_ERROR_NO_ERROR; + + /* Indicate ioctl complete */ + mwifiex_ioctl_complete(adapter, + (struct mwifiex_wait_queue *) wait_queue, 0); + } + if (priv->report_scan_result) + priv->report_scan_result = false; + if (priv->scan_pending_on_block) { + priv->scan_pending_on_block = false; + up(&priv->async_sem); + } + + } else { + /* Get scan command from scan_pending_q and put to + cmd_pending_q */ + cmd_node = list_first_entry(&adapter->scan_pending_q, + struct cmd_ctrl_node, list); + list_del(&cmd_node->list); + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); + + mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true); + } + +done: + kfree((u8 *) bss_new_entry); + return ret; +} + +/* + * This function prepares command for background scan query. + * + * Preparation includes - + * - Setting command ID and proper size + * - Setting background scan flush parameter + * - Ensuring correct endian-ness + */ +int mwifiex_cmd_802_11_bg_scan_query(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf) +{ + struct host_cmd_ds_802_11_bg_scan_query *bg_query = + &cmd->params.bg_scan_query; + + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_BG_SCAN_QUERY); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_bg_scan_query) + + S_DS_GEN); + + bg_query->flush = 1; + + return 0; +} + +/* + * This function finds a SSID in the scan table. + * + * A BSSID may optionally be provided to qualify the SSID. + * For non-Auto mode, further check is made to make sure the + * BSS found in the scan table is compatible with the current + * settings of the driver. + */ +s32 +mwifiex_find_ssid_in_list(struct mwifiex_private *priv, + struct mwifiex_802_11_ssid *ssid, u8 *bssid, + u32 mode) +{ + struct mwifiex_adapter *adapter = priv->adapter; + s32 net = -1, j; + u8 best_rssi = 0; + u32 i; + + dev_dbg(adapter->dev, "info: num of entries in table = %d\n", + adapter->num_in_scan_table); + + /* + * Loop through the table until the maximum is reached or until a match + * is found based on the bssid field comparison + */ + for (i = 0; + i < adapter->num_in_scan_table && (!bssid || (bssid && net < 0)); + i++) { + if (!mwifiex_ssid_cmp(&adapter->scan_table[i].ssid, ssid) && + (!bssid + || !memcmp(adapter->scan_table[i].mac_address, bssid, + ETH_ALEN)) + && + (mwifiex_get_cfp_by_band_and_channel_from_cfg80211 + (priv, (u8) adapter->scan_table[i].bss_band, + (u16) adapter->scan_table[i].channel))) { + switch (mode) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + j = mwifiex_is_network_compatible(priv, i, + mode); + + if (j >= 0) { + if (SCAN_RSSI + (adapter->scan_table[i].rssi) > + best_rssi) { + best_rssi = SCAN_RSSI(adapter-> + scan_table + [i].rssi); + net = i; + } + } else { + if (net == -1) + net = j; + } + break; + case NL80211_IFTYPE_UNSPECIFIED: + default: + /* + * Do not check compatibility if the mode + * requested is Auto/Unknown. Allows generic + * find to work without verifying against the + * Adapter security settings + */ + if (SCAN_RSSI(adapter->scan_table[i].rssi) > + best_rssi) { + best_rssi = SCAN_RSSI(adapter-> + scan_table[i].rssi); + net = i; + } + break; + } + } + } + + return net; +} + +/* + * This function finds a specific compatible BSSID in the scan list. + * + * This function loops through the scan table looking for a compatible + * match. If a BSSID matches, but the BSS is found to be not compatible + * the function ignores it and continues to search through the rest of + * the entries in case there is an AP with multiple SSIDs assigned to + * the same BSSID. + */ +s32 +mwifiex_find_bssid_in_list(struct mwifiex_private *priv, u8 *bssid, + u32 mode) +{ + struct mwifiex_adapter *adapter = priv->adapter; + s32 net = -1; + u32 i; + + if (!bssid) + return -1; + + dev_dbg(adapter->dev, "info: FindBSSID: Num of BSSIDs = %d\n", + adapter->num_in_scan_table); + + /* + * Look through the scan table for a compatible match. The ret return + * variable will be equal to the index in the scan table (greater + * than zero) if the network is compatible. The loop will continue + * past a matched bssid that is not compatible in case there is an + * AP with multiple SSIDs assigned to the same BSSID + */ + for (i = 0; net < 0 && i < adapter->num_in_scan_table; i++) { + if (!memcmp + (adapter->scan_table[i].mac_address, bssid, ETH_ALEN) + && mwifiex_get_cfp_by_band_and_channel_from_cfg80211 + (priv, + (u8) adapter-> + scan_table[i]. + bss_band, + (u16) adapter-> + scan_table[i]. + channel)) { + switch (mode) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + net = mwifiex_is_network_compatible(priv, i, + mode); + break; + default: + net = i; + break; + } + } + } + + return net; +} + +/* + * This function inserts scan command node to the scan pending queue. + */ +void +mwifiex_queue_scan_cmd(struct mwifiex_private *priv, + struct cmd_ctrl_node *cmd_node) +{ + struct mwifiex_adapter *adapter = priv->adapter; + unsigned long flags; + + spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); + list_add_tail(&cmd_node->list, &adapter->scan_pending_q); + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); +} + +/* + * This function finds an AP with specific ssid in the scan list. + */ +int mwifiex_find_best_network(struct mwifiex_private *priv, + struct mwifiex_ssid_bssid *req_ssid_bssid) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_bssdescriptor *req_bss; + s32 i; + + memset(req_ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid)); + + i = mwifiex_find_best_network_in_list(priv); + + if (i >= 0) { + req_bss = &adapter->scan_table[i]; + memcpy(&req_ssid_bssid->ssid, &req_bss->ssid, + sizeof(struct mwifiex_802_11_ssid)); + memcpy((u8 *) &req_ssid_bssid->bssid, + (u8 *) &req_bss->mac_address, ETH_ALEN); + + /* Make sure we are in the right mode */ + if (priv->bss_mode == NL80211_IFTYPE_UNSPECIFIED) + priv->bss_mode = req_bss->bss_mode; + } + + if (!req_ssid_bssid->ssid.ssid_len) + return -1; + + dev_dbg(adapter->dev, "info: Best network found = [%s], " + "[%pM]\n", req_ssid_bssid->ssid.ssid, + req_ssid_bssid->bssid); + + return 0; +} + +/* + * This function sends a scan command for all available channels to the + * firmware, filtered on a specific SSID. + */ +static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv, + void *wait_buf, u16 action, + struct mwifiex_802_11_ssid *req_ssid, + struct mwifiex_scan_resp *scan_resp) +{ + struct mwifiex_adapter *adapter = priv->adapter; + int ret = 0; + struct mwifiex_user_scan_cfg *scan_cfg; + + if (!req_ssid) + return -1; + + if (action == HostCmd_ACT_GEN_GET) { + if (scan_resp) { + scan_resp->scan_table = + (u8 *) &priv->curr_bss_params.bss_descriptor; + scan_resp->num_in_scan_table = + adapter->num_in_scan_table; + } else { + ret = -1; + } + return ret; + } + + if (adapter->scan_processing && action == HostCmd_ACT_GEN_SET) { + dev_dbg(adapter->dev, "cmd: Scan already in process...\n"); + return ret; + } + + if (priv->scan_block && action == HostCmd_ACT_GEN_SET) { + dev_dbg(adapter->dev, + "cmd: Scan is blocked during association...\n"); + return ret; + } + + mwifiex_scan_delete_ssid_table_entry(priv, req_ssid); + + scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg), GFP_KERNEL); + if (!scan_cfg) { + dev_err(adapter->dev, "failed to alloc scan_cfg\n"); + return -1; + } + + memcpy(scan_cfg->ssid_list[0].ssid, req_ssid->ssid, + req_ssid->ssid_len); + scan_cfg->keep_previous_scan = true; + + ret = mwifiex_scan_networks(priv, wait_buf, action, scan_cfg, NULL); + + kfree(scan_cfg); + return ret; +} + +/* + * Sends IOCTL request to start a scan. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + * + * Scan command can be issued for both normal scan and specific SSID + * scan, depending upon whether an SSID is provided or not. + */ +int mwifiex_request_scan(struct mwifiex_private *priv, u8 wait_option, + struct mwifiex_802_11_ssid *req_ssid) +{ + int ret = 0; + struct mwifiex_wait_queue *wait = NULL; + int status = 0; + + if (down_interruptible(&priv->async_sem)) { + dev_err(priv->adapter->dev, "%s: acquire semaphore\n", + __func__); + return -1; + } + priv->scan_pending_on_block = true; + + /* Allocate wait request buffer */ + wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); + if (!wait) { + ret = -1; + goto done; + } + + if (req_ssid && req_ssid->ssid_len != 0) + /* Specific SSID scan */ + status = mwifiex_scan_specific_ssid(priv, wait, + HostCmd_ACT_GEN_SET, + req_ssid, NULL); + else + /* Normal scan */ + status = mwifiex_scan_networks(priv, wait, HostCmd_ACT_GEN_SET, + NULL, NULL); + status = mwifiex_request_ioctl(priv, wait, status, wait_option); + if (status == -1) + ret = -1; +done: + if ((wait) && (status != -EINPROGRESS)) + kfree(wait); + if (ret == -1) { + priv->scan_pending_on_block = false; + up(&priv->async_sem); + } + return ret; +} + +/* + * This function appends the vendor specific IE TLV to a buffer. + */ +int +mwifiex_cmd_append_vsie_tlv(struct mwifiex_private *priv, + u16 vsie_mask, u8 **buffer) +{ + int id, ret_len = 0; + struct mwifiex_ie_types_vendor_param_set *vs_param_set; + + if (!buffer) + return 0; + if (!(*buffer)) + return 0; + + /* + * Traverse through the saved vendor specific IE array and append + * the selected(scan/assoc/adhoc) IE as TLV to the command + */ + for (id = 0; id < MWIFIEX_MAX_VSIE_NUM; id++) { + if (priv->vs_ie[id].mask & vsie_mask) { + vs_param_set = + (struct mwifiex_ie_types_vendor_param_set *) + *buffer; + vs_param_set->header.type = + cpu_to_le16(TLV_TYPE_PASSTHROUGH); + vs_param_set->header.len = + cpu_to_le16((((u16) priv->vs_ie[id].ie[1]) + & 0x00FF) + 2); + memcpy(vs_param_set->ie, priv->vs_ie[id].ie, + le16_to_cpu(vs_param_set->header.len)); + *buffer += le16_to_cpu(vs_param_set->header.len) + + sizeof(struct mwifiex_ie_types_header); + ret_len += le16_to_cpu(vs_param_set->header.len) + + sizeof(struct mwifiex_ie_types_header); + } + } + return ret_len; +} + +/* + * This function saves a beacon buffer of the current BSS descriptor. + * + * The current beacon buffer is saved so that it can be restored in the + * following cases that makes the beacon buffer not to contain the current + * ssid's beacon buffer. + * - The current ssid was not found somehow in the last scan. + * - The current ssid was the last entry of the scan table and overloaded. + */ +void +mwifiex_save_curr_bcn(struct mwifiex_private *priv) +{ + struct mwifiex_bssdescriptor *curr_bss = + &priv->curr_bss_params.bss_descriptor; + + /* save the beacon buffer if it is not saved or updated */ + if ((priv->curr_bcn_buf == NULL) || + (priv->curr_bcn_size != curr_bss->beacon_buf_size) || + (memcmp(priv->curr_bcn_buf, curr_bss->beacon_buf, + curr_bss->beacon_buf_size))) { + + kfree(priv->curr_bcn_buf); + priv->curr_bcn_buf = NULL; + + priv->curr_bcn_size = curr_bss->beacon_buf_size; + if (!priv->curr_bcn_size) + return; + + priv->curr_bcn_buf = kzalloc(curr_bss->beacon_buf_size, + GFP_KERNEL); + if (!priv->curr_bcn_buf) { + dev_err(priv->adapter->dev, + "failed to alloc curr_bcn_buf\n"); + } else { + memcpy(priv->curr_bcn_buf, curr_bss->beacon_buf, + curr_bss->beacon_buf_size); + dev_dbg(priv->adapter->dev, + "info: current beacon saved %d\n", + priv->curr_bcn_size); + } + } +} + +/* + * This function frees the current BSS descriptor beacon buffer. + */ +void +mwifiex_free_curr_bcn(struct mwifiex_private *priv) +{ + kfree(priv->curr_bcn_buf); + priv->curr_bcn_buf = NULL; +} diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c new file mode 100644 index 000000000000..f21e5cd19839 --- /dev/null +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -0,0 +1,1770 @@ +/* + * Marvell Wireless LAN device driver: SDIO specific handling + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include <linux/firmware.h> + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" +#include "sdio.h" + + +#define SDIO_VERSION "1.0" + +static struct mwifiex_if_ops sdio_ops; + +static struct semaphore add_remove_card_sem; + +/* + * SDIO probe. + * + * This function probes an mwifiex device and registers it. It allocates + * the card structure, enables SDIO function number and initiates the + * device registration and initialization procedure by adding a logical + * interface. + */ +static int +mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) +{ + int ret = 0; + struct sdio_mmc_card *card = NULL; + + pr_debug("info: vendor=0x%4.04X device=0x%4.04X class=%d function=%d\n", + func->vendor, func->device, func->class, func->num); + + card = kzalloc(sizeof(struct sdio_mmc_card), GFP_KERNEL); + if (!card) { + pr_err("%s: failed to alloc memory\n", __func__); + return -ENOMEM; + } + + card->func = func; + + func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; + + sdio_claim_host(func); + ret = sdio_enable_func(func); + sdio_release_host(func); + + if (ret) { + pr_err("%s: failed to enable function\n", __func__); + return -EIO; + } + + if (mwifiex_add_card(card, &add_remove_card_sem, &sdio_ops)) { + pr_err("%s: add card failed\n", __func__); + kfree(card); + sdio_claim_host(func); + ret = sdio_disable_func(func); + sdio_release_host(func); + ret = -1; + } + + return ret; +} + +/* + * SDIO remove. + * + * This function removes the interface and frees up the card structure. + */ +static void +mwifiex_sdio_remove(struct sdio_func *func) +{ + struct sdio_mmc_card *card; + + pr_debug("info: SDIO func num=%d\n", func->num); + + if (func) { + card = sdio_get_drvdata(func); + if (card) { + mwifiex_remove_card(card->adapter, + &add_remove_card_sem); + kfree(card); + } + } +} + +/* + * SDIO suspend. + * + * Kernel needs to suspend all functions separately. Therefore all + * registered functions must have drivers with suspend and resume + * methods. Failing that the kernel simply removes the whole card. + * + * If already not suspended, this function allocates and sends a host + * sleep activate request to the firmware and turns off the traffic. + */ +static int mwifiex_sdio_suspend(struct device *dev) +{ + struct sdio_func *func = dev_to_sdio_func(dev); + struct sdio_mmc_card *card; + struct mwifiex_adapter *adapter = NULL; + mmc_pm_flag_t pm_flag = 0; + int hs_actived = 0; + int i; + int ret = 0; + + if (func) { + pm_flag = sdio_get_host_pm_caps(func); + pr_debug("cmd: %s: suspend: PM flag = 0x%x\n", + sdio_func_id(func), pm_flag); + if (!(pm_flag & MMC_PM_KEEP_POWER)) { + pr_err("%s: cannot remain alive while host is" + " suspended\n", sdio_func_id(func)); + return -ENOSYS; + } + + card = sdio_get_drvdata(func); + if (!card || !card->adapter) { + pr_err("suspend: invalid card or adapter\n"); + return 0; + } + } else { + pr_err("suspend: sdio_func is not specified\n"); + return 0; + } + + adapter = card->adapter; + + /* Enable the Host Sleep */ + hs_actived = mwifiex_enable_hs(adapter); + if (hs_actived) { + pr_debug("cmd: suspend with MMC_PM_KEEP_POWER\n"); + ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); + } + + /* Indicate device suspended */ + adapter->is_suspended = true; + + for (i = 0; i < adapter->priv_num; i++) + netif_carrier_off(adapter->priv[i]->netdev); + + return ret; +} + +/* + * SDIO resume. + * + * Kernel needs to suspend all functions separately. Therefore all + * registered functions must have drivers with suspend and resume + * methods. Failing that the kernel simply removes the whole card. + * + * If already not resumed, this function turns on the traffic and + * sends a host sleep cancel request to the firmware. + */ +static int mwifiex_sdio_resume(struct device *dev) +{ + struct sdio_func *func = dev_to_sdio_func(dev); + struct sdio_mmc_card *card; + struct mwifiex_adapter *adapter = NULL; + mmc_pm_flag_t pm_flag = 0; + int i; + + if (func) { + pm_flag = sdio_get_host_pm_caps(func); + card = sdio_get_drvdata(func); + if (!card || !card->adapter) { + pr_err("resume: invalid card or adapter\n"); + return 0; + } + } else { + pr_err("resume: sdio_func is not specified\n"); + return 0; + } + + adapter = card->adapter; + + if (!adapter->is_suspended) { + dev_warn(adapter->dev, "device already resumed\n"); + return 0; + } + + adapter->is_suspended = false; + + for (i = 0; i < adapter->priv_num; i++) + if (adapter->priv[i]->media_connected) + netif_carrier_on(adapter->priv[i]->netdev); + + /* Disable Host Sleep */ + mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), + MWIFIEX_NO_WAIT); + + return 0; +} + +/* Device ID for SD8787 */ +#define SDIO_DEVICE_ID_MARVELL_8787 (0x9119) + +/* WLAN IDs */ +static const struct sdio_device_id mwifiex_ids[] = { + {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8787)}, + {}, +}; + +MODULE_DEVICE_TABLE(sdio, mwifiex_ids); + +static const struct dev_pm_ops mwifiex_sdio_pm_ops = { + .suspend = mwifiex_sdio_suspend, + .resume = mwifiex_sdio_resume, +}; + +static struct sdio_driver mwifiex_sdio = { + .name = "mwifiex_sdio", + .id_table = mwifiex_ids, + .probe = mwifiex_sdio_probe, + .remove = mwifiex_sdio_remove, + .drv = { + .owner = THIS_MODULE, + .pm = &mwifiex_sdio_pm_ops, + } +}; + +/* + * This function writes data into SDIO card register. + */ +static int +mwifiex_write_reg(struct mwifiex_adapter *adapter, u32 reg, u32 data) +{ + struct sdio_mmc_card *card = adapter->card; + int ret = -1; + + sdio_claim_host(card->func); + sdio_writeb(card->func, (u8) data, reg, &ret); + sdio_release_host(card->func); + + return ret; +} + +/* + * This function reads data from SDIO card register. + */ +static int +mwifiex_read_reg(struct mwifiex_adapter *adapter, u32 reg, u32 *data) +{ + struct sdio_mmc_card *card = adapter->card; + int ret = -1; + u8 val; + + sdio_claim_host(card->func); + val = sdio_readb(card->func, reg, &ret); + sdio_release_host(card->func); + + *data = val; + + return ret; +} + +/* + * This function writes multiple data into SDIO card memory. + * + * This does not work in suspended mode. + */ +static int +mwifiex_write_data_sync(struct mwifiex_adapter *adapter, + u8 *buffer, u32 pkt_len, u32 port, u32 timeout) +{ + struct sdio_mmc_card *card = adapter->card; + int ret = -1; + u8 blk_mode = + (port & MWIFIEX_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE; + u32 blk_size = (blk_mode == BLOCK_MODE) ? MWIFIEX_SDIO_BLOCK_SIZE : 1; + u32 blk_cnt = + (blk_mode == + BLOCK_MODE) ? (pkt_len / + MWIFIEX_SDIO_BLOCK_SIZE) : pkt_len; + u32 ioport = (port & MWIFIEX_SDIO_IO_PORT_MASK); + + if (adapter->is_suspended) { + dev_err(adapter->dev, + "%s: not allowed while suspended\n", __func__); + return -1; + } + + sdio_claim_host(card->func); + + if (!sdio_writesb(card->func, ioport, buffer, blk_cnt * blk_size)) + ret = 0; + + sdio_release_host(card->func); + + return ret; +} + +/* + * This function reads multiple data from SDIO card memory. + */ +static int mwifiex_read_data_sync(struct mwifiex_adapter *adapter, + u8 *buffer, u32 len, + u32 port, u32 timeout, u8 claim) +{ + struct sdio_mmc_card *card = adapter->card; + int ret = -1; + u8 blk_mode = + (port & MWIFIEX_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE; + u32 blk_size = (blk_mode == BLOCK_MODE) ? MWIFIEX_SDIO_BLOCK_SIZE : 1; + u32 blk_cnt = + (blk_mode == + BLOCK_MODE) ? (len / MWIFIEX_SDIO_BLOCK_SIZE) : len; + u32 ioport = (port & MWIFIEX_SDIO_IO_PORT_MASK); + + if (claim) + sdio_claim_host(card->func); + + if (!sdio_readsb(card->func, buffer, ioport, blk_cnt * blk_size)) + ret = 0; + + if (claim) + sdio_release_host(card->func); + + return ret; +} + +/* + * This function wakes up the card. + * + * A host power up command is written to the card configuration + * register to wake up the card. + */ +static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter) +{ + int ret; + + dev_dbg(adapter->dev, "event: wakeup device...\n"); + ret = mwifiex_write_reg(adapter, CONFIGURATION_REG, HOST_POWER_UP); + + return ret; +} + +/* + * This function is called after the card has woken up. + * + * The card configuration register is reset. + */ +static int mwifiex_pm_wakeup_card_complete(struct mwifiex_adapter *adapter) +{ + int ret; + + dev_dbg(adapter->dev, "cmd: wakeup device completed\n"); + ret = mwifiex_write_reg(adapter, CONFIGURATION_REG, 0); + + return ret; +} + +/* + * This function initializes the IO ports. + * + * The following operations are performed - + * - Read the IO ports (0, 1 and 2) + * - Set host interrupt Reset-To-Read to clear + * - Set auto re-enable interrupt + */ +static int mwifiex_init_sdio_ioport(struct mwifiex_adapter *adapter) +{ + u32 reg; + + adapter->ioport = 0; + + /* Read the IO port */ + if (!mwifiex_read_reg(adapter, IO_PORT_0_REG, ®)) + adapter->ioport |= (reg & 0xff); + else + return -1; + + if (!mwifiex_read_reg(adapter, IO_PORT_1_REG, ®)) + adapter->ioport |= ((reg & 0xff) << 8); + else + return -1; + + if (!mwifiex_read_reg(adapter, IO_PORT_2_REG, ®)) + adapter->ioport |= ((reg & 0xff) << 16); + else + return -1; + + pr_debug("info: SDIO FUNC1 IO port: %#x\n", adapter->ioport); + + /* Set Host interrupt reset to read to clear */ + if (!mwifiex_read_reg(adapter, HOST_INT_RSR_REG, ®)) + mwifiex_write_reg(adapter, HOST_INT_RSR_REG, + reg | SDIO_INT_MASK); + else + return -1; + + /* Dnld/Upld ready set to auto reset */ + if (!mwifiex_read_reg(adapter, CARD_MISC_CFG_REG, ®)) + mwifiex_write_reg(adapter, CARD_MISC_CFG_REG, + reg | AUTO_RE_ENABLE_INT); + else + return -1; + + return 0; +} + +/* + * This function sends data to the card. + */ +static int mwifiex_write_data_to_card(struct mwifiex_adapter *adapter, + u8 *payload, u32 pkt_len, u32 port) +{ + u32 i = 0; + int ret = 0; + + do { + ret = mwifiex_write_data_sync(adapter, payload, pkt_len, + port, 0); + if (ret) { + i++; + dev_err(adapter->dev, "host_to_card, write iomem" + " (%d) failed: %d\n", i, ret); + if (mwifiex_write_reg(adapter, + CONFIGURATION_REG, 0x04)) + dev_err(adapter->dev, "write CFG reg failed\n"); + + ret = -1; + if (i > MAX_WRITE_IOMEM_RETRY) + return ret; + } + } while (ret == -1); + + return ret; +} + +/* + * This function gets the read port. + * + * If control port bit is set in MP read bitmap, the control port + * is returned, otherwise the current read port is returned and + * the value is increased (provided it does not reach the maximum + * limit, in which case it is reset to 1) + */ +static int mwifiex_get_rd_port(struct mwifiex_adapter *adapter, u8 *port) +{ + struct sdio_mmc_card *card = adapter->card; + u16 rd_bitmap = card->mp_rd_bitmap; + + dev_dbg(adapter->dev, "data: mp_rd_bitmap=0x%04x\n", rd_bitmap); + + if (!(rd_bitmap & (CTRL_PORT_MASK | DATA_PORT_MASK))) + return -1; + + if (card->mp_rd_bitmap & CTRL_PORT_MASK) { + card->mp_rd_bitmap &= (u16) (~CTRL_PORT_MASK); + *port = CTRL_PORT; + dev_dbg(adapter->dev, "data: port=%d mp_rd_bitmap=0x%04x\n", + *port, card->mp_rd_bitmap); + } else { + if (card->mp_rd_bitmap & (1 << card->curr_rd_port)) { + card->mp_rd_bitmap &= + (u16) (~(1 << card->curr_rd_port)); + *port = card->curr_rd_port; + + if (++card->curr_rd_port == MAX_PORT) + card->curr_rd_port = 1; + } else { + return -1; + } + + dev_dbg(adapter->dev, + "data: port=%d mp_rd_bitmap=0x%04x -> 0x%04x\n", + *port, rd_bitmap, card->mp_rd_bitmap); + } + return 0; +} + +/* + * This function gets the write port for data. + * + * The current write port is returned if available and the value is + * increased (provided it does not reach the maximum limit, in which + * case it is reset to 1) + */ +static int mwifiex_get_wr_port_data(struct mwifiex_adapter *adapter, u8 *port) +{ + struct sdio_mmc_card *card = adapter->card; + u16 wr_bitmap = card->mp_wr_bitmap; + + dev_dbg(adapter->dev, "data: mp_wr_bitmap=0x%04x\n", wr_bitmap); + + if (!(wr_bitmap & card->mp_data_port_mask)) + return -1; + + if (card->mp_wr_bitmap & (1 << card->curr_wr_port)) { + card->mp_wr_bitmap &= (u16) (~(1 << card->curr_wr_port)); + *port = card->curr_wr_port; + if (++card->curr_wr_port == card->mp_end_port) + card->curr_wr_port = 1; + } else { + adapter->data_sent = true; + return -EBUSY; + } + + if (*port == CTRL_PORT) { + dev_err(adapter->dev, "invalid data port=%d cur port=%d" + " mp_wr_bitmap=0x%04x -> 0x%04x\n", + *port, card->curr_wr_port, wr_bitmap, + card->mp_wr_bitmap); + return -1; + } + + dev_dbg(adapter->dev, "data: port=%d mp_wr_bitmap=0x%04x -> 0x%04x\n", + *port, wr_bitmap, card->mp_wr_bitmap); + + return 0; +} + +/* + * This function polls the card status. + */ +static int +mwifiex_sdio_poll_card_status(struct mwifiex_adapter *adapter, u8 bits) +{ + u32 tries; + u32 cs = 0; + + for (tries = 0; tries < MAX_POLL_TRIES; tries++) { + if (mwifiex_read_reg(adapter, CARD_STATUS_REG, &cs)) + break; + else if ((cs & bits) == bits) + return 0; + + udelay(10); + } + + dev_err(adapter->dev, "poll card status failed, tries = %d\n", + tries); + return -1; +} + +/* + * This function reads the firmware status. + */ +static int +mwifiex_sdio_read_fw_status(struct mwifiex_adapter *adapter, u16 *dat) +{ + u32 fws0 = 0, fws1 = 0; + + if (mwifiex_read_reg(adapter, CARD_FW_STATUS0_REG, &fws0)) + return -1; + + if (mwifiex_read_reg(adapter, CARD_FW_STATUS1_REG, &fws1)) + return -1; + + *dat = (u16) ((fws1 << 8) | fws0); + + return 0; +} + +/* + * This function disables the host interrupt. + * + * The host interrupt mask is read, the disable bit is reset and + * written back to the card host interrupt mask register. + */ +static int mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter) +{ + u32 host_int_mask = 0; + + /* Read back the host_int_mask register */ + if (mwifiex_read_reg(adapter, HOST_INT_MASK_REG, &host_int_mask)) + return -1; + + /* Update with the mask and write back to the register */ + host_int_mask &= ~HOST_INT_DISABLE; + + if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG, host_int_mask)) { + dev_err(adapter->dev, "disable host interrupt failed\n"); + return -1; + } + + return 0; +} + +/* + * This function enables the host interrupt. + * + * The host interrupt enable mask is written to the card + * host interrupt mask register. + */ +static int mwifiex_sdio_enable_host_int(struct mwifiex_adapter *adapter) +{ + /* Simply write the mask to the register */ + if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG, HOST_INT_ENABLE)) { + dev_err(adapter->dev, "enable host interrupt failed\n"); + return -1; + } + return 0; +} + +/* + * This function sends a data buffer to the card. + */ +static int mwifiex_sdio_card_to_host(struct mwifiex_adapter *adapter, + u32 *type, u8 *buffer, + u32 npayload, u32 ioport) +{ + int ret = 0; + u32 nb; + + if (!buffer) { + dev_err(adapter->dev, "%s: buffer is NULL\n", __func__); + return -1; + } + + ret = mwifiex_read_data_sync(adapter, buffer, npayload, ioport, 0, 1); + + if (ret) { + dev_err(adapter->dev, "%s: read iomem failed: %d\n", __func__, + ret); + return -1; + } + + nb = le16_to_cpu(*(__le16 *) (buffer)); + if (nb > npayload) { + dev_err(adapter->dev, "%s: invalid packet, nb=%d, npayload=%d\n", + __func__, nb, npayload); + return -1; + } + + *type = le16_to_cpu(*(__le16 *) (buffer + 2)); + + return ret; +} + +/* + * This function downloads the firmware to the card. + * + * Firmware is downloaded to the card in blocks. Every block download + * is tested for CRC errors, and retried a number of times before + * returning failure. + */ +static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, + struct mwifiex_fw_image *fw) +{ + int ret = 0; + u8 *firmware = fw->fw_buf; + u32 firmware_len = fw->fw_len; + u32 offset = 0; + u32 base0, base1; + u8 *fwbuf; + u16 len = 0; + u32 txlen = 0, tx_blocks = 0, tries = 0; + u32 i = 0; + + if (!firmware_len) { + dev_err(adapter->dev, "firmware image not found!" + " Terminating download\n"); + return -1; + } + + dev_dbg(adapter->dev, "info: downloading FW image (%d bytes)\n", + firmware_len); + + /* Assume that the allocated buffer is 8-byte aligned */ + fwbuf = kzalloc(MWIFIEX_UPLD_SIZE, GFP_KERNEL); + if (!fwbuf) { + dev_err(adapter->dev, "unable to alloc buffer for firmware." + " Terminating download\n"); + return -1; + } + + /* Perform firmware data transfer */ + do { + /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY + bits */ + ret = mwifiex_sdio_poll_card_status(adapter, CARD_IO_READY | + DN_LD_CARD_RDY); + if (ret) { + dev_err(adapter->dev, "FW download with helper:" + " poll status timeout @ %d\n", offset); + goto done; + } + + /* More data? */ + if (offset >= firmware_len) + break; + + for (tries = 0; tries < MAX_POLL_TRIES; tries++) { + ret = mwifiex_read_reg(adapter, HOST_F1_RD_BASE_0, + &base0); + if (ret) { + dev_err(adapter->dev, "dev BASE0 register read" + " failed: base0=0x%04X(%d). Terminating " + "download\n", base0, base0); + goto done; + } + ret = mwifiex_read_reg(adapter, HOST_F1_RD_BASE_1, + &base1); + if (ret) { + dev_err(adapter->dev, "dev BASE1 register read" + " failed: base1=0x%04X(%d). Terminating " + "download\n", base1, base1); + goto done; + } + len = (u16) (((base1 & 0xff) << 8) | (base0 & 0xff)); + + if (len) + break; + + udelay(10); + } + + if (!len) { + break; + } else if (len > MWIFIEX_UPLD_SIZE) { + dev_err(adapter->dev, "FW download failed @ %d," + " invalid length %d\n", offset, len); + ret = -1; + goto done; + } + + txlen = len; + + if (len & BIT(0)) { + i++; + if (i > MAX_WRITE_IOMEM_RETRY) { + dev_err(adapter->dev, "FW download failed @" + " %d, over max retry count\n", offset); + ret = -1; + goto done; + } + dev_err(adapter->dev, "CRC indicated by the helper:" + " len = 0x%04X, txlen = %d\n", len, txlen); + len &= ~BIT(0); + /* Setting this to 0 to resend from same offset */ + txlen = 0; + } else { + i = 0; + + /* Set blocksize to transfer - checking for last + block */ + if (firmware_len - offset < txlen) + txlen = firmware_len - offset; + + tx_blocks = (txlen + MWIFIEX_SDIO_BLOCK_SIZE - + 1) / MWIFIEX_SDIO_BLOCK_SIZE; + + /* Copy payload to buffer */ + memmove(fwbuf, &firmware[offset], txlen); + } + + ret = mwifiex_write_data_sync(adapter, fwbuf, tx_blocks * + MWIFIEX_SDIO_BLOCK_SIZE, + adapter->ioport, 0); + if (ret) { + dev_err(adapter->dev, "FW download, write iomem (%d)" + " failed @ %d\n", i, offset); + if (mwifiex_write_reg(adapter, CONFIGURATION_REG, 0x04)) + dev_err(adapter->dev, "write CFG reg failed\n"); + + ret = -1; + goto done; + } + + offset += txlen; + } while (true); + + dev_dbg(adapter->dev, "info: FW download over, size %d bytes\n", + offset); + + ret = 0; +done: + kfree(fwbuf); + return ret; +} + +/* + * This function checks the firmware status in card. + * + * The winner interface is also determined by this function. + */ +static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter, + u32 poll_num, int *winner) +{ + int ret = 0; + u16 firmware_stat; + u32 tries; + u32 winner_status; + + /* Wait for firmware initialization event */ + for (tries = 0; tries < poll_num; tries++) { + ret = mwifiex_sdio_read_fw_status(adapter, &firmware_stat); + if (ret) + continue; + if (firmware_stat == FIRMWARE_READY) { + ret = 0; + break; + } else { + mdelay(100); + ret = -1; + } + } + + if (winner && ret) { + if (mwifiex_read_reg + (adapter, CARD_FW_STATUS0_REG, &winner_status)) + winner_status = 0; + + if (winner_status) + *winner = 0; + else + *winner = 1; + } + return ret; +} + +/* + * This function reads the interrupt status from card. + */ +static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter) +{ + struct sdio_mmc_card *card = adapter->card; + u32 sdio_ireg = 0; + unsigned long flags; + + if (mwifiex_read_data_sync(adapter, card->mp_regs, MAX_MP_REGS, + REG_PORT | MWIFIEX_SDIO_BYTE_MODE_MASK, 0, + 0)) { + dev_err(adapter->dev, "read mp_regs failed\n"); + return; + } + + sdio_ireg = card->mp_regs[HOST_INTSTATUS_REG]; + if (sdio_ireg) { + /* + * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS + * Clear the interrupt status register + */ + dev_dbg(adapter->dev, "int: sdio_ireg = %#x\n", sdio_ireg); + spin_lock_irqsave(&adapter->int_lock, flags); + adapter->int_status |= sdio_ireg; + spin_unlock_irqrestore(&adapter->int_lock, flags); + } + + return; +} + +/* + * SDIO interrupt handler. + * + * This function reads the interrupt status from firmware and assigns + * the main process in workqueue which will handle the interrupt. + */ +static void +mwifiex_sdio_interrupt(struct sdio_func *func) +{ + struct mwifiex_adapter *adapter; + struct sdio_mmc_card *card; + + card = sdio_get_drvdata(func); + if (!card || !card->adapter) { + pr_debug("int: func=%p card=%p adapter=%p\n", + func, card, card ? card->adapter : NULL); + return; + } + adapter = card->adapter; + + if (adapter->surprise_removed) + return; + + if (!adapter->pps_uapsd_mode && adapter->ps_state == PS_STATE_SLEEP) + adapter->ps_state = PS_STATE_AWAKE; + + mwifiex_interrupt_status(adapter); + queue_work(adapter->workqueue, &adapter->main_work); + + return; +} + +/* + * This function decodes a received packet. + * + * Based on the type, the packet is treated as either a data, or + * a command response, or an event, and the correct handler + * function is invoked. + */ +static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter, + struct sk_buff *skb, u32 upld_typ) +{ + u8 *cmd_buf; + + skb_pull(skb, INTF_HEADER_LEN); + + switch (upld_typ) { + case MWIFIEX_TYPE_DATA: + dev_dbg(adapter->dev, "info: --- Rx: Data packet ---\n"); + mwifiex_handle_rx_packet(adapter, skb); + break; + + case MWIFIEX_TYPE_CMD: + dev_dbg(adapter->dev, "info: --- Rx: Cmd Response ---\n"); + /* take care of curr_cmd = NULL case */ + if (!adapter->curr_cmd) { + cmd_buf = adapter->upld_buf; + + if (adapter->ps_state == PS_STATE_SLEEP_CFM) + mwifiex_process_sleep_confirm_resp(adapter, + skb->data, skb->len); + + memcpy(cmd_buf, skb->data, min_t(u32, + MWIFIEX_SIZE_OF_CMD_BUFFER, skb->len)); + + dev_kfree_skb_any(skb); + } else { + adapter->cmd_resp_received = true; + adapter->curr_cmd->resp_skb = skb; + } + break; + + case MWIFIEX_TYPE_EVENT: + dev_dbg(adapter->dev, "info: --- Rx: Event ---\n"); + adapter->event_cause = *(u32 *) skb->data; + + skb_pull(skb, MWIFIEX_EVENT_HEADER_LEN); + + if ((skb->len > 0) && (skb->len < MAX_EVENT_SIZE)) + memcpy(adapter->event_body, skb->data, skb->len); + + /* event cause has been saved to adapter->event_cause */ + adapter->event_received = true; + adapter->event_skb = skb; + + break; + + default: + dev_err(adapter->dev, "unknown upload type %#x\n", upld_typ); + dev_kfree_skb_any(skb); + break; + } + + return 0; +} + +/* + * This function transfers received packets from card to driver, performing + * aggregation if required. + * + * For data received on control port, or if aggregation is disabled, the + * received buffers are uploaded as separate packets. However, if aggregation + * is enabled and required, the buffers are copied onto an aggregation buffer, + * provided there is space left, processed and finally uploaded. + */ +static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, + struct sk_buff *skb, u8 port) +{ + struct sdio_mmc_card *card = adapter->card; + s32 f_do_rx_aggr = 0; + s32 f_do_rx_cur = 0; + s32 f_aggr_cur = 0; + struct sk_buff *skb_deaggr; + u32 pind = 0; + u32 pkt_len, pkt_type = 0; + u8 *curr_ptr; + u32 rx_len = skb->len; + + if (port == CTRL_PORT) { + /* Read the command Resp without aggr */ + dev_dbg(adapter->dev, "info: %s: no aggregation for cmd " + "response\n", __func__); + + f_do_rx_cur = 1; + goto rx_curr_single; + } + + if (!card->mpa_rx.enabled) { + dev_dbg(adapter->dev, "info: %s: rx aggregation disabled\n", + __func__); + + f_do_rx_cur = 1; + goto rx_curr_single; + } + + if (card->mp_rd_bitmap & (~((u16) CTRL_PORT_MASK))) { + /* Some more data RX pending */ + dev_dbg(adapter->dev, "info: %s: not last packet\n", __func__); + + if (MP_RX_AGGR_IN_PROGRESS(card)) { + if (MP_RX_AGGR_BUF_HAS_ROOM(card, skb->len)) { + f_aggr_cur = 1; + } else { + /* No room in Aggr buf, do rx aggr now */ + f_do_rx_aggr = 1; + f_do_rx_cur = 1; + } + } else { + /* Rx aggr not in progress */ + f_aggr_cur = 1; + } + + } else { + /* No more data RX pending */ + dev_dbg(adapter->dev, "info: %s: last packet\n", __func__); + + if (MP_RX_AGGR_IN_PROGRESS(card)) { + f_do_rx_aggr = 1; + if (MP_RX_AGGR_BUF_HAS_ROOM(card, skb->len)) + f_aggr_cur = 1; + else + /* No room in Aggr buf, do rx aggr now */ + f_do_rx_cur = 1; + } else { + f_do_rx_cur = 1; + } + } + + if (f_aggr_cur) { + dev_dbg(adapter->dev, "info: current packet aggregation\n"); + /* Curr pkt can be aggregated */ + MP_RX_AGGR_SETUP(card, skb, port); + + if (MP_RX_AGGR_PKT_LIMIT_REACHED(card) || + MP_RX_AGGR_PORT_LIMIT_REACHED(card)) { + dev_dbg(adapter->dev, "info: %s: aggregated packet " + "limit reached\n", __func__); + /* No more pkts allowed in Aggr buf, rx it */ + f_do_rx_aggr = 1; + } + } + + if (f_do_rx_aggr) { + /* do aggr RX now */ + dev_dbg(adapter->dev, "info: do_rx_aggr: num of packets: %d\n", + card->mpa_rx.pkt_cnt); + + if (mwifiex_read_data_sync(adapter, card->mpa_rx.buf, + card->mpa_rx.buf_len, + (adapter->ioport | 0x1000 | + (card->mpa_rx.ports << 4)) + + card->mpa_rx.start_port, 0, 1)) + return -1; + + curr_ptr = card->mpa_rx.buf; + + for (pind = 0; pind < card->mpa_rx.pkt_cnt; pind++) { + + /* get curr PKT len & type */ + pkt_len = *(u16 *) &curr_ptr[0]; + pkt_type = *(u16 *) &curr_ptr[2]; + + /* copy pkt to deaggr buf */ + skb_deaggr = card->mpa_rx.skb_arr[pind]; + + if ((pkt_type == MWIFIEX_TYPE_DATA) && (pkt_len <= + card->mpa_rx.len_arr[pind])) { + + memcpy(skb_deaggr->data, curr_ptr, pkt_len); + + skb_trim(skb_deaggr, pkt_len); + + /* Process de-aggr packet */ + mwifiex_decode_rx_packet(adapter, skb_deaggr, + pkt_type); + } else { + dev_err(adapter->dev, "wrong aggr pkt:" + " type=%d len=%d max_len=%d\n", + pkt_type, pkt_len, + card->mpa_rx.len_arr[pind]); + dev_kfree_skb_any(skb_deaggr); + } + curr_ptr += card->mpa_rx.len_arr[pind]; + } + MP_RX_AGGR_BUF_RESET(card); + } + +rx_curr_single: + if (f_do_rx_cur) { + dev_dbg(adapter->dev, "info: RX: port: %d, rx_len: %d\n", + port, rx_len); + + if (mwifiex_sdio_card_to_host(adapter, &pkt_type, + skb->data, skb->len, + adapter->ioport + port)) + return -1; + + mwifiex_decode_rx_packet(adapter, skb, pkt_type); + } + + return 0; +} + +/* + * This function checks the current interrupt status. + * + * The following interrupts are checked and handled by this function - + * - Data sent + * - Command sent + * - Packets received + * + * Since the firmware does not generate download ready interrupt if the + * port updated is command port only, command sent interrupt checking + * should be done manually, and for every SDIO interrupt. + * + * In case of Rx packets received, the packets are uploaded from card to + * host and processed accordingly. + */ +static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) +{ + struct sdio_mmc_card *card = adapter->card; + int ret = 0; + u8 sdio_ireg; + struct sk_buff *skb = NULL; + u8 port = CTRL_PORT; + u32 len_reg_l, len_reg_u; + u32 rx_blocks; + u16 rx_len; + unsigned long flags; + + spin_lock_irqsave(&adapter->int_lock, flags); + sdio_ireg = adapter->int_status; + adapter->int_status = 0; + spin_unlock_irqrestore(&adapter->int_lock, flags); + + if (!sdio_ireg) + return ret; + + if (sdio_ireg & DN_LD_HOST_INT_STATUS) { + card->mp_wr_bitmap = ((u16) card->mp_regs[WR_BITMAP_U]) << 8; + card->mp_wr_bitmap |= (u16) card->mp_regs[WR_BITMAP_L]; + dev_dbg(adapter->dev, "int: DNLD: wr_bitmap=0x%04x\n", + card->mp_wr_bitmap); + if (adapter->data_sent && + (card->mp_wr_bitmap & card->mp_data_port_mask)) { + dev_dbg(adapter->dev, + "info: <--- Tx DONE Interrupt --->\n"); + adapter->data_sent = false; + } + } + + /* As firmware will not generate download ready interrupt if the port + updated is command port only, cmd_sent should be done for any SDIO + interrupt. */ + if (adapter->cmd_sent) { + /* Check if firmware has attach buffer at command port and + update just that in wr_bit_map. */ + card->mp_wr_bitmap |= + (u16) card->mp_regs[WR_BITMAP_L] & CTRL_PORT_MASK; + if (card->mp_wr_bitmap & CTRL_PORT_MASK) + adapter->cmd_sent = false; + } + + dev_dbg(adapter->dev, "info: cmd_sent=%d data_sent=%d\n", + adapter->cmd_sent, adapter->data_sent); + if (sdio_ireg & UP_LD_HOST_INT_STATUS) { + card->mp_rd_bitmap = ((u16) card->mp_regs[RD_BITMAP_U]) << 8; + card->mp_rd_bitmap |= (u16) card->mp_regs[RD_BITMAP_L]; + dev_dbg(adapter->dev, "int: UPLD: rd_bitmap=0x%04x\n", + card->mp_rd_bitmap); + + while (true) { + ret = mwifiex_get_rd_port(adapter, &port); + if (ret) { + dev_dbg(adapter->dev, + "info: no more rd_port available\n"); + break; + } + len_reg_l = RD_LEN_P0_L + (port << 1); + len_reg_u = RD_LEN_P0_U + (port << 1); + rx_len = ((u16) card->mp_regs[len_reg_u]) << 8; + rx_len |= (u16) card->mp_regs[len_reg_l]; + dev_dbg(adapter->dev, "info: RX: port=%d rx_len=%u\n", + port, rx_len); + rx_blocks = + (rx_len + MWIFIEX_SDIO_BLOCK_SIZE - + 1) / MWIFIEX_SDIO_BLOCK_SIZE; + if (rx_len <= INTF_HEADER_LEN + || (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE) > + MWIFIEX_RX_DATA_BUF_SIZE) { + dev_err(adapter->dev, "invalid rx_len=%d\n", + rx_len); + return -1; + } + rx_len = (u16) (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE); + + skb = dev_alloc_skb(rx_len); + + if (!skb) { + dev_err(adapter->dev, "%s: failed to alloc skb", + __func__); + return -1; + } + + skb_put(skb, rx_len); + + dev_dbg(adapter->dev, "info: rx_len = %d skb->len = %d\n", + rx_len, skb->len); + + if (mwifiex_sdio_card_to_host_mp_aggr(adapter, skb, + port)) { + u32 cr = 0; + + dev_err(adapter->dev, "card_to_host_mpa failed:" + " int status=%#x\n", sdio_ireg); + if (mwifiex_read_reg(adapter, + CONFIGURATION_REG, &cr)) + dev_err(adapter->dev, + "read CFG reg failed\n"); + + dev_dbg(adapter->dev, + "info: CFG reg val = %d\n", cr); + if (mwifiex_write_reg(adapter, + CONFIGURATION_REG, + (cr | 0x04))) + dev_err(adapter->dev, + "write CFG reg failed\n"); + + dev_dbg(adapter->dev, "info: write success\n"); + if (mwifiex_read_reg(adapter, + CONFIGURATION_REG, &cr)) + dev_err(adapter->dev, + "read CFG reg failed\n"); + + dev_dbg(adapter->dev, + "info: CFG reg val =%x\n", cr); + dev_kfree_skb_any(skb); + return -1; + } + } + } + + return 0; +} + +/* + * This function aggregates transmission buffers in driver and downloads + * the aggregated packet to card. + * + * The individual packets are aggregated by copying into an aggregation + * buffer and then downloaded to the card. Previous unsent packets in the + * aggregation buffer are pre-copied first before new packets are added. + * Aggregation is done till there is space left in the aggregation buffer, + * or till new packets are available. + * + * The function will only download the packet to the card when aggregation + * stops, otherwise it will just aggregate the packet in aggregation buffer + * and return. + */ +static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter, + u8 *payload, u32 pkt_len, u8 port, + u32 next_pkt_len) +{ + struct sdio_mmc_card *card = adapter->card; + int ret = 0; + s32 f_send_aggr_buf = 0; + s32 f_send_cur_buf = 0; + s32 f_precopy_cur_buf = 0; + s32 f_postcopy_cur_buf = 0; + + if ((!card->mpa_tx.enabled) || (port == CTRL_PORT)) { + dev_dbg(adapter->dev, "info: %s: tx aggregation disabled\n", + __func__); + + f_send_cur_buf = 1; + goto tx_curr_single; + } + + if (next_pkt_len) { + /* More pkt in TX queue */ + dev_dbg(adapter->dev, "info: %s: more packets in queue.\n", + __func__); + + if (MP_TX_AGGR_IN_PROGRESS(card)) { + if (!MP_TX_AGGR_PORT_LIMIT_REACHED(card) && + MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)) { + f_precopy_cur_buf = 1; + + if (!(card->mp_wr_bitmap & + (1 << card->curr_wr_port)) + || !MP_TX_AGGR_BUF_HAS_ROOM( + card, next_pkt_len)) + f_send_aggr_buf = 1; + } else { + /* No room in Aggr buf, send it */ + f_send_aggr_buf = 1; + + if (MP_TX_AGGR_PORT_LIMIT_REACHED(card) || + !(card->mp_wr_bitmap & + (1 << card->curr_wr_port))) + f_send_cur_buf = 1; + else + f_postcopy_cur_buf = 1; + } + } else { + if (MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len) + && (card->mp_wr_bitmap & (1 << card->curr_wr_port))) + f_precopy_cur_buf = 1; + else + f_send_cur_buf = 1; + } + } else { + /* Last pkt in TX queue */ + dev_dbg(adapter->dev, "info: %s: Last packet in Tx Queue.\n", + __func__); + + if (MP_TX_AGGR_IN_PROGRESS(card)) { + /* some packs in Aggr buf already */ + f_send_aggr_buf = 1; + + if (MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)) + f_precopy_cur_buf = 1; + else + /* No room in Aggr buf, send it */ + f_send_cur_buf = 1; + } else { + f_send_cur_buf = 1; + } + } + + if (f_precopy_cur_buf) { + dev_dbg(adapter->dev, "data: %s: precopy current buffer\n", + __func__); + MP_TX_AGGR_BUF_PUT(card, payload, pkt_len, port); + + if (MP_TX_AGGR_PKT_LIMIT_REACHED(card) || + MP_TX_AGGR_PORT_LIMIT_REACHED(card)) + /* No more pkts allowed in Aggr buf, send it */ + f_send_aggr_buf = 1; + } + + if (f_send_aggr_buf) { + dev_dbg(adapter->dev, "data: %s: send aggr buffer: %d %d\n", + __func__, + card->mpa_tx.start_port, card->mpa_tx.ports); + ret = mwifiex_write_data_to_card(adapter, card->mpa_tx.buf, + card->mpa_tx.buf_len, + (adapter->ioport | 0x1000 | + (card->mpa_tx.ports << 4)) + + card->mpa_tx.start_port); + + MP_TX_AGGR_BUF_RESET(card); + } + +tx_curr_single: + if (f_send_cur_buf) { + dev_dbg(adapter->dev, "data: %s: send current buffer %d\n", + __func__, port); + ret = mwifiex_write_data_to_card(adapter, payload, pkt_len, + adapter->ioport + port); + } + + if (f_postcopy_cur_buf) { + dev_dbg(adapter->dev, "data: %s: postcopy current buffer\n", + __func__); + MP_TX_AGGR_BUF_PUT(card, payload, pkt_len, port); + } + + return ret; +} + +/* + * This function downloads data from driver to card. + * + * Both commands and data packets are transferred to the card by this + * function. + * + * This function adds the SDIO specific header to the front of the buffer + * before transferring. The header contains the length of the packet and + * the type. The firmware handles the packets based upon this set type. + */ +static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter, + u8 type, u8 *payload, u32 pkt_len, + struct mwifiex_tx_param *tx_param) +{ + struct sdio_mmc_card *card = adapter->card; + int ret = 0; + u32 buf_block_len; + u32 blk_size; + u8 port = CTRL_PORT; + + /* Allocate buffer and copy payload */ + blk_size = MWIFIEX_SDIO_BLOCK_SIZE; + buf_block_len = (pkt_len + blk_size - 1) / blk_size; + *(u16 *) &payload[0] = (u16) pkt_len; + *(u16 *) &payload[2] = type; + + /* + * This is SDIO specific header + * u16 length, + * u16 type (MWIFIEX_TYPE_DATA = 0, MWIFIEX_TYPE_CMD = 1, + * MWIFIEX_TYPE_EVENT = 3) + */ + if (type == MWIFIEX_TYPE_DATA) { + ret = mwifiex_get_wr_port_data(adapter, &port); + if (ret) { + dev_err(adapter->dev, "%s: no wr_port available\n", + __func__); + return ret; + } + } else { + adapter->cmd_sent = true; + /* Type must be MWIFIEX_TYPE_CMD */ + + if (pkt_len <= INTF_HEADER_LEN || + pkt_len > MWIFIEX_UPLD_SIZE) + dev_err(adapter->dev, "%s: payload=%p, nb=%d\n", + __func__, payload, pkt_len); + } + + /* Transfer data to card */ + pkt_len = buf_block_len * blk_size; + + if (tx_param) + ret = mwifiex_host_to_card_mp_aggr(adapter, payload, pkt_len, + port, tx_param->next_pkt_len); + else + ret = mwifiex_host_to_card_mp_aggr(adapter, payload, pkt_len, + port, 0); + + if (ret) { + if (type == MWIFIEX_TYPE_CMD) + adapter->cmd_sent = false; + if (type == MWIFIEX_TYPE_DATA) + adapter->data_sent = false; + } else { + if (type == MWIFIEX_TYPE_DATA) { + if (!(card->mp_wr_bitmap & (1 << card->curr_wr_port))) + adapter->data_sent = true; + else + adapter->data_sent = false; + } + } + + return ret; +} + +/* + * This function allocates the MPA Tx and Rx buffers. + */ +static int mwifiex_alloc_sdio_mpa_buffers(struct mwifiex_adapter *adapter, + u32 mpa_tx_buf_size, u32 mpa_rx_buf_size) +{ + struct sdio_mmc_card *card = adapter->card; + int ret = 0; + + card->mpa_tx.buf = kzalloc(mpa_tx_buf_size, GFP_KERNEL); + if (!card->mpa_tx.buf) { + dev_err(adapter->dev, "could not alloc buffer for MP-A TX\n"); + ret = -1; + goto error; + } + + card->mpa_tx.buf_size = mpa_tx_buf_size; + + card->mpa_rx.buf = kzalloc(mpa_rx_buf_size, GFP_KERNEL); + if (!card->mpa_rx.buf) { + dev_err(adapter->dev, "could not alloc buffer for MP-A RX\n"); + ret = -1; + goto error; + } + + card->mpa_rx.buf_size = mpa_rx_buf_size; + +error: + if (ret) { + kfree(card->mpa_tx.buf); + kfree(card->mpa_rx.buf); + } + + return ret; +} + +/* + * This function unregisters the SDIO device. + * + * The SDIO IRQ is released, the function is disabled and driver + * data is set to null. + */ +static void +mwifiex_unregister_dev(struct mwifiex_adapter *adapter) +{ + struct sdio_mmc_card *card = adapter->card; + + if (adapter->card) { + /* Release the SDIO IRQ */ + sdio_claim_host(card->func); + sdio_release_irq(card->func); + sdio_disable_func(card->func); + sdio_release_host(card->func); + sdio_set_drvdata(card->func, NULL); + } +} + +/* + * This function registers the SDIO device. + * + * SDIO IRQ is claimed, block size is set and driver data is initialized. + */ +static int mwifiex_register_dev(struct mwifiex_adapter *adapter) +{ + int ret = 0; + struct sdio_mmc_card *card = adapter->card; + struct sdio_func *func = card->func; + + /* save adapter pointer in card */ + card->adapter = adapter; + + sdio_claim_host(func); + + /* Request the SDIO IRQ */ + ret = sdio_claim_irq(func, mwifiex_sdio_interrupt); + if (ret) { + pr_err("claim irq failed: ret=%d\n", ret); + goto disable_func; + } + + /* Set block size */ + ret = sdio_set_block_size(card->func, MWIFIEX_SDIO_BLOCK_SIZE); + if (ret) { + pr_err("cannot set SDIO block size\n"); + ret = -1; + goto release_irq; + } + + sdio_release_host(func); + sdio_set_drvdata(func, card); + + adapter->dev = &func->dev; + + return 0; + +release_irq: + sdio_release_irq(func); +disable_func: + sdio_disable_func(func); + sdio_release_host(func); + adapter->card = NULL; + + return -1; +} + +/* + * This function initializes the SDIO driver. + * + * The following initializations steps are followed - + * - Read the Host interrupt status register to acknowledge + * the first interrupt got from bootloader + * - Disable host interrupt mask register + * - Get SDIO port + * - Get revision ID + * - Initialize SDIO variables in card + * - Allocate MP registers + * - Allocate MPA Tx and Rx buffers + */ +static int mwifiex_init_sdio(struct mwifiex_adapter *adapter) +{ + struct sdio_mmc_card *card = adapter->card; + int ret; + u32 sdio_ireg = 0; + + /* + * Read the HOST_INT_STATUS_REG for ACK the first interrupt got + * from the bootloader. If we don't do this we get a interrupt + * as soon as we register the irq. + */ + mwifiex_read_reg(adapter, HOST_INTSTATUS_REG, &sdio_ireg); + + /* Disable host interrupt mask register for SDIO */ + mwifiex_sdio_disable_host_int(adapter); + + /* Get SDIO ioport */ + mwifiex_init_sdio_ioport(adapter); + + /* Get revision ID */ +#define REV_ID_REG 0x5c + mwifiex_read_reg(adapter, REV_ID_REG, &adapter->revision_id); + + /* Initialize SDIO variables in card */ + card->mp_rd_bitmap = 0; + card->mp_wr_bitmap = 0; + card->curr_rd_port = 1; + card->curr_wr_port = 1; + + card->mp_data_port_mask = DATA_PORT_MASK; + + card->mpa_tx.buf_len = 0; + card->mpa_tx.pkt_cnt = 0; + card->mpa_tx.start_port = 0; + + card->mpa_tx.enabled = 0; + card->mpa_tx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT; + + card->mpa_rx.buf_len = 0; + card->mpa_rx.pkt_cnt = 0; + card->mpa_rx.start_port = 0; + + card->mpa_rx.enabled = 0; + card->mpa_rx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT; + + /* Allocate buffers for SDIO MP-A */ + card->mp_regs = kzalloc(MAX_MP_REGS, GFP_KERNEL); + if (!card->mp_regs) { + dev_err(adapter->dev, "failed to alloc mp_regs\n"); + return -1; + } + + ret = mwifiex_alloc_sdio_mpa_buffers(adapter, + SDIO_MP_TX_AGGR_DEF_BUF_SIZE, + SDIO_MP_RX_AGGR_DEF_BUF_SIZE); + if (ret) { + dev_err(adapter->dev, "failed to alloc sdio mp-a buffers\n"); + kfree(card->mp_regs); + return -1; + } + + return ret; +} + +/* + * This function resets the MPA Tx and Rx buffers. + */ +static void mwifiex_cleanup_mpa_buf(struct mwifiex_adapter *adapter) +{ + struct sdio_mmc_card *card = adapter->card; + + MP_TX_AGGR_BUF_RESET(card); + MP_RX_AGGR_BUF_RESET(card); +} + +/* + * This function cleans up the allocated card buffers. + * + * The following are freed by this function - + * - MP registers + * - MPA Tx buffer + * - MPA Rx buffer + */ +static void mwifiex_cleanup_sdio(struct mwifiex_adapter *adapter) +{ + struct sdio_mmc_card *card = adapter->card; + + kfree(card->mp_regs); + kfree(card->mpa_tx.buf); + kfree(card->mpa_rx.buf); +} + +/* + * This function updates the MP end port in card. + */ +static void +mwifiex_update_mp_end_port(struct mwifiex_adapter *adapter, u16 port) +{ + struct sdio_mmc_card *card = adapter->card; + int i; + + card->mp_end_port = port; + + card->mp_data_port_mask = DATA_PORT_MASK; + + for (i = 1; i <= MAX_PORT - card->mp_end_port; i++) + card->mp_data_port_mask &= ~(1 << (MAX_PORT - i)); + + card->curr_wr_port = 1; + + dev_dbg(adapter->dev, "cmd: mp_end_port %d, data port mask 0x%x\n", + port, card->mp_data_port_mask); +} + +static struct mwifiex_if_ops sdio_ops = { + .init_if = mwifiex_init_sdio, + .cleanup_if = mwifiex_cleanup_sdio, + .check_fw_status = mwifiex_check_fw_status, + .prog_fw = mwifiex_prog_fw_w_helper, + .register_dev = mwifiex_register_dev, + .unregister_dev = mwifiex_unregister_dev, + .enable_int = mwifiex_sdio_enable_host_int, + .process_int_status = mwifiex_process_int_status, + .host_to_card = mwifiex_sdio_host_to_card, + .wakeup = mwifiex_pm_wakeup_card, + .wakeup_complete = mwifiex_pm_wakeup_card_complete, + + /* SDIO specific */ + .update_mp_end_port = mwifiex_update_mp_end_port, + .cleanup_mpa_buf = mwifiex_cleanup_mpa_buf, +}; + +/* + * This function initializes the SDIO driver. + * + * This initiates the semaphore and registers the device with + * SDIO bus. + */ +static int +mwifiex_sdio_init_module(void) +{ + int ret; + + sema_init(&add_remove_card_sem, 1); + + ret = sdio_register_driver(&mwifiex_sdio); + + return ret; +} + +/* + * This function cleans up the SDIO driver. + * + * The following major steps are followed for cleanup - + * - Resume the device if its suspended + * - Disconnect the device if connected + * - Shutdown the firmware + * - Unregister the device from SDIO bus. + */ +static void +mwifiex_sdio_cleanup_module(void) +{ + struct mwifiex_adapter *adapter = g_adapter; + int i; + + if (down_interruptible(&add_remove_card_sem)) + goto exit_sem_err; + + if (!adapter || !adapter->priv_num) + goto exit; + + if (adapter->is_suspended) + mwifiex_sdio_resume(adapter->dev); + + for (i = 0; i < adapter->priv_num; i++) + if ((GET_BSS_ROLE(adapter->priv[i]) == MWIFIEX_BSS_ROLE_STA) && + adapter->priv[i]->media_connected) + mwifiex_disconnect(adapter->priv[i], MWIFIEX_CMD_WAIT, + NULL); + + if (!adapter->surprise_removed) + mwifiex_shutdown_fw(mwifiex_get_priv + (adapter, MWIFIEX_BSS_ROLE_ANY), + MWIFIEX_CMD_WAIT); + +exit: + up(&add_remove_card_sem); + +exit_sem_err: + sdio_unregister_driver(&mwifiex_sdio); +} + +module_init(mwifiex_sdio_init_module); +module_exit(mwifiex_sdio_cleanup_module); + +MODULE_AUTHOR("Marvell International Ltd."); +MODULE_DESCRIPTION("Marvell WiFi-Ex SDIO Driver version " SDIO_VERSION); +MODULE_VERSION(SDIO_VERSION); +MODULE_LICENSE("GPL v2"); +MODULE_FIRMWARE("sd8787.bin"); diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h new file mode 100644 index 000000000000..a0e9bc5253e0 --- /dev/null +++ b/drivers/net/wireless/mwifiex/sdio.h @@ -0,0 +1,305 @@ +/* + * Marvell Wireless LAN device driver: SDIO specific definitions + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#ifndef _MWIFIEX_SDIO_H +#define _MWIFIEX_SDIO_H + + +#include <linux/mmc/sdio.h> +#include <linux/mmc/sdio_ids.h> +#include <linux/mmc/sdio_func.h> +#include <linux/mmc/card.h> + +#include "main.h" + +#define BLOCK_MODE 1 +#define BYTE_MODE 0 + +#define REG_PORT 0 +#define RD_BITMAP_L 0x04 +#define RD_BITMAP_U 0x05 +#define WR_BITMAP_L 0x06 +#define WR_BITMAP_U 0x07 +#define RD_LEN_P0_L 0x08 +#define RD_LEN_P0_U 0x09 + +#define MWIFIEX_SDIO_IO_PORT_MASK 0xfffff + +#define MWIFIEX_SDIO_BYTE_MODE_MASK 0x80000000 + +#define CTRL_PORT 0 +#define CTRL_PORT_MASK 0x0001 +#define DATA_PORT_MASK 0xfffe + +#define MAX_MP_REGS 64 +#define MAX_PORT 16 + +#define SDIO_MP_AGGR_DEF_PKT_LIMIT 8 + +#define SDIO_MP_TX_AGGR_DEF_BUF_SIZE (4096) /* 4K */ + +/* Multi port RX aggregation buffer size */ +#define SDIO_MP_RX_AGGR_DEF_BUF_SIZE (4096) /* 4K */ + +/* Misc. Config Register : Auto Re-enable interrupts */ +#define AUTO_RE_ENABLE_INT BIT(4) + +/* Host Control Registers */ +/* Host Control Registers : I/O port 0 */ +#define IO_PORT_0_REG 0x78 +/* Host Control Registers : I/O port 1 */ +#define IO_PORT_1_REG 0x79 +/* Host Control Registers : I/O port 2 */ +#define IO_PORT_2_REG 0x7A + +/* Host Control Registers : Configuration */ +#define CONFIGURATION_REG 0x00 +/* Host Control Registers : Host without Command 53 finish host*/ +#define HOST_TO_CARD_EVENT (0x1U << 3) +/* Host Control Registers : Host without Command 53 finish host */ +#define HOST_WO_CMD53_FINISH_HOST (0x1U << 2) +/* Host Control Registers : Host power up */ +#define HOST_POWER_UP (0x1U << 1) +/* Host Control Registers : Host power down */ +#define HOST_POWER_DOWN (0x1U << 0) + +/* Host Control Registers : Host interrupt mask */ +#define HOST_INT_MASK_REG 0x02 +/* Host Control Registers : Upload host interrupt mask */ +#define UP_LD_HOST_INT_MASK (0x1U) +/* Host Control Registers : Download host interrupt mask */ +#define DN_LD_HOST_INT_MASK (0x2U) +/* Enable Host interrupt mask */ +#define HOST_INT_ENABLE (UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK) +/* Disable Host interrupt mask */ +#define HOST_INT_DISABLE 0xff + +/* Host Control Registers : Host interrupt status */ +#define HOST_INTSTATUS_REG 0x03 +/* Host Control Registers : Upload host interrupt status */ +#define UP_LD_HOST_INT_STATUS (0x1U) +/* Host Control Registers : Download host interrupt status */ +#define DN_LD_HOST_INT_STATUS (0x2U) + +/* Host Control Registers : Host interrupt RSR */ +#define HOST_INT_RSR_REG 0x01 +/* Host Control Registers : Upload host interrupt RSR */ +#define UP_LD_HOST_INT_RSR (0x1U) +#define SDIO_INT_MASK 0x3F + +/* Host Control Registers : Host interrupt status */ +#define HOST_INT_STATUS_REG 0x28 +/* Host Control Registers : Upload CRC error */ +#define UP_LD_CRC_ERR (0x1U << 2) +/* Host Control Registers : Upload restart */ +#define UP_LD_RESTART (0x1U << 1) +/* Host Control Registers : Download restart */ +#define DN_LD_RESTART (0x1U << 0) + +/* Card Control Registers : Card status register */ +#define CARD_STATUS_REG 0x30 +/* Card Control Registers : Card I/O ready */ +#define CARD_IO_READY (0x1U << 3) +/* Card Control Registers : CIS card ready */ +#define CIS_CARD_RDY (0x1U << 2) +/* Card Control Registers : Upload card ready */ +#define UP_LD_CARD_RDY (0x1U << 1) +/* Card Control Registers : Download card ready */ +#define DN_LD_CARD_RDY (0x1U << 0) + +/* Card Control Registers : Host interrupt mask register */ +#define HOST_INTERRUPT_MASK_REG 0x34 +/* Card Control Registers : Host power interrupt mask */ +#define HOST_POWER_INT_MASK (0x1U << 3) +/* Card Control Registers : Abort card interrupt mask */ +#define ABORT_CARD_INT_MASK (0x1U << 2) +/* Card Control Registers : Upload card interrupt mask */ +#define UP_LD_CARD_INT_MASK (0x1U << 1) +/* Card Control Registers : Download card interrupt mask */ +#define DN_LD_CARD_INT_MASK (0x1U << 0) + +/* Card Control Registers : Card interrupt status register */ +#define CARD_INTERRUPT_STATUS_REG 0x38 +/* Card Control Registers : Power up interrupt */ +#define POWER_UP_INT (0x1U << 4) +/* Card Control Registers : Power down interrupt */ +#define POWER_DOWN_INT (0x1U << 3) + +/* Card Control Registers : Card interrupt RSR register */ +#define CARD_INTERRUPT_RSR_REG 0x3c +/* Card Control Registers : Power up RSR */ +#define POWER_UP_RSR (0x1U << 4) +/* Card Control Registers : Power down RSR */ +#define POWER_DOWN_RSR (0x1U << 3) + +/* Card Control Registers : Miscellaneous Configuration Register */ +#define CARD_MISC_CFG_REG 0x6C + +/* Host F1 read base 0 */ +#define HOST_F1_RD_BASE_0 0x0040 +/* Host F1 read base 1 */ +#define HOST_F1_RD_BASE_1 0x0041 +/* Host F1 card ready */ +#define HOST_F1_CARD_RDY 0x0020 + +/* Firmware status 0 register */ +#define CARD_FW_STATUS0_REG 0x60 +/* Firmware status 1 register */ +#define CARD_FW_STATUS1_REG 0x61 +/* Rx length register */ +#define CARD_RX_LEN_REG 0x62 +/* Rx unit register */ +#define CARD_RX_UNIT_REG 0x63 + +/* Event header Len*/ +#define MWIFIEX_EVENT_HEADER_LEN 8 + +/* Max retry number of CMD53 write */ +#define MAX_WRITE_IOMEM_RETRY 2 + +/* SDIO Tx aggregation in progress ? */ +#define MP_TX_AGGR_IN_PROGRESS(a) (a->mpa_tx.pkt_cnt > 0) + +/* SDIO Tx aggregation buffer room for next packet ? */ +#define MP_TX_AGGR_BUF_HAS_ROOM(a, len) ((a->mpa_tx.buf_len+len) \ + <= a->mpa_tx.buf_size) + +/* Copy current packet (SDIO Tx aggregation buffer) to SDIO buffer */ +#define MP_TX_AGGR_BUF_PUT(a, payload, pkt_len, port) do { \ + memmove(&a->mpa_tx.buf[a->mpa_tx.buf_len], \ + payload, pkt_len); \ + a->mpa_tx.buf_len += pkt_len; \ + if (!a->mpa_tx.pkt_cnt) \ + a->mpa_tx.start_port = port; \ + if (a->mpa_tx.start_port <= port) \ + a->mpa_tx.ports |= (1<<(a->mpa_tx.pkt_cnt)); \ + else \ + a->mpa_tx.ports |= (1<<(a->mpa_tx.pkt_cnt+1+(MAX_PORT - \ + a->mp_end_port))); \ + a->mpa_tx.pkt_cnt++; \ +} while (0); + +/* SDIO Tx aggregation limit ? */ +#define MP_TX_AGGR_PKT_LIMIT_REACHED(a) \ + (a->mpa_tx.pkt_cnt == a->mpa_tx.pkt_aggr_limit) + +/* SDIO Tx aggregation port limit ? */ +#define MP_TX_AGGR_PORT_LIMIT_REACHED(a) ((a->curr_wr_port < \ + a->mpa_tx.start_port) && (((MAX_PORT - \ + a->mpa_tx.start_port) + a->curr_wr_port) >= \ + SDIO_MP_AGGR_DEF_PKT_LIMIT)) + +/* Reset SDIO Tx aggregation buffer parameters */ +#define MP_TX_AGGR_BUF_RESET(a) do { \ + a->mpa_tx.pkt_cnt = 0; \ + a->mpa_tx.buf_len = 0; \ + a->mpa_tx.ports = 0; \ + a->mpa_tx.start_port = 0; \ +} while (0); + +/* SDIO Rx aggregation limit ? */ +#define MP_RX_AGGR_PKT_LIMIT_REACHED(a) \ + (a->mpa_rx.pkt_cnt == a->mpa_rx.pkt_aggr_limit) + +/* SDIO Tx aggregation port limit ? */ +#define MP_RX_AGGR_PORT_LIMIT_REACHED(a) ((a->curr_rd_port < \ + a->mpa_rx.start_port) && (((MAX_PORT - \ + a->mpa_rx.start_port) + a->curr_rd_port) >= \ + SDIO_MP_AGGR_DEF_PKT_LIMIT)) + +/* SDIO Rx aggregation in progress ? */ +#define MP_RX_AGGR_IN_PROGRESS(a) (a->mpa_rx.pkt_cnt > 0) + +/* SDIO Rx aggregation buffer room for next packet ? */ +#define MP_RX_AGGR_BUF_HAS_ROOM(a, rx_len) \ + ((a->mpa_rx.buf_len+rx_len) <= a->mpa_rx.buf_size) + +/* Prepare to copy current packet from card to SDIO Rx aggregation buffer */ +#define MP_RX_AGGR_SETUP(a, skb, port) do { \ + a->mpa_rx.buf_len += skb->len; \ + if (!a->mpa_rx.pkt_cnt) \ + a->mpa_rx.start_port = port; \ + if (a->mpa_rx.start_port <= port) \ + a->mpa_rx.ports |= (1<<(a->mpa_rx.pkt_cnt)); \ + else \ + a->mpa_rx.ports |= (1<<(a->mpa_rx.pkt_cnt+1)); \ + a->mpa_rx.skb_arr[a->mpa_rx.pkt_cnt] = skb; \ + a->mpa_rx.len_arr[a->mpa_rx.pkt_cnt] = skb->len; \ + a->mpa_rx.pkt_cnt++; \ +} while (0); + +/* Reset SDIO Rx aggregation buffer parameters */ +#define MP_RX_AGGR_BUF_RESET(a) do { \ + a->mpa_rx.pkt_cnt = 0; \ + a->mpa_rx.buf_len = 0; \ + a->mpa_rx.ports = 0; \ + a->mpa_rx.start_port = 0; \ +} while (0); + + +/* data structure for SDIO MPA TX */ +struct mwifiex_sdio_mpa_tx { + /* multiport tx aggregation buffer pointer */ + u8 *buf; + u32 buf_len; + u32 pkt_cnt; + u16 ports; + u16 start_port; + u8 enabled; + u32 buf_size; + u32 pkt_aggr_limit; +}; + +struct mwifiex_sdio_mpa_rx { + u8 *buf; + u32 buf_len; + u32 pkt_cnt; + u16 ports; + u16 start_port; + + struct sk_buff *skb_arr[SDIO_MP_AGGR_DEF_PKT_LIMIT]; + u32 len_arr[SDIO_MP_AGGR_DEF_PKT_LIMIT]; + + u8 enabled; + u32 buf_size; + u32 pkt_aggr_limit; +}; + +int mwifiex_bus_register(void); +void mwifiex_bus_unregister(void); + +struct sdio_mmc_card { + struct sdio_func *func; + struct mwifiex_adapter *adapter; + + u16 mp_rd_bitmap; + u16 mp_wr_bitmap; + + u16 mp_end_port; + u16 mp_data_port_mask; + + u8 curr_rd_port; + u8 curr_wr_port; + + u8 *mp_regs; + + struct mwifiex_sdio_mpa_tx mpa_tx; + struct mwifiex_sdio_mpa_rx mpa_rx; +}; +#endif /* _MWIFIEX_SDIO_H */ diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c new file mode 100644 index 000000000000..6fff26153e26 --- /dev/null +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -0,0 +1,1226 @@ +/* + * Marvell Wireless LAN device driver: station command handling + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" + +/* + * This function prepares command to set/get RSSI information. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting data/beacon average factors + * - Resetting SNR/NF/RSSI values in private structure + * - Ensuring correct endian-ness + */ +static int +mwifiex_cmd_802_11_rssi_info(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, u16 cmd_action) +{ + cmd->command = cpu_to_le16(HostCmd_CMD_RSSI_INFO); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_rssi_info) + + S_DS_GEN); + cmd->params.rssi_info.action = cpu_to_le16(cmd_action); + cmd->params.rssi_info.ndata = cpu_to_le16(priv->data_avg_factor); + cmd->params.rssi_info.nbcn = cpu_to_le16(priv->bcn_avg_factor); + + /* Reset SNR/NF/RSSI values in private structure */ + priv->data_rssi_last = 0; + priv->data_nf_last = 0; + priv->data_rssi_avg = 0; + priv->data_nf_avg = 0; + priv->bcn_rssi_last = 0; + priv->bcn_nf_last = 0; + priv->bcn_rssi_avg = 0; + priv->bcn_nf_avg = 0; + + return 0; +} + +/* + * This function prepares command to set MAC control. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Ensuring correct endian-ness + */ +static int mwifiex_cmd_mac_control(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf) +{ + struct host_cmd_ds_mac_control *mac_ctrl = &cmd->params.mac_ctrl; + u16 action = *((u16 *) data_buf); + + if (cmd_action != HostCmd_ACT_GEN_SET) { + dev_err(priv->adapter->dev, + "mac_control: only support set cmd\n"); + return -1; + } + + cmd->command = cpu_to_le16(HostCmd_CMD_MAC_CONTROL); + cmd->size = + cpu_to_le16(sizeof(struct host_cmd_ds_mac_control) + S_DS_GEN); + mac_ctrl->action = cpu_to_le16(action); + + return 0; +} + +/* + * This function prepares command to set/get SNMP MIB. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting SNMP MIB OID number and value + * (as required) + * - Ensuring correct endian-ness + * + * The following SNMP MIB OIDs are supported - + * - FRAG_THRESH_I : Fragmentation threshold + * - RTS_THRESH_I : RTS threshold + * - SHORT_RETRY_LIM_I : Short retry limit + * - DOT11D_I : 11d support + */ +static int mwifiex_cmd_802_11_snmp_mib(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, u32 cmd_oid, + void *data_buf) +{ + struct host_cmd_ds_802_11_snmp_mib *snmp_mib = &cmd->params.smib; + u32 ul_temp; + + dev_dbg(priv->adapter->dev, "cmd: SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid); + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SNMP_MIB); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_snmp_mib) + - 1 + S_DS_GEN); + + if (cmd_action == HostCmd_ACT_GEN_GET) { + snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_GET); + snmp_mib->buf_size = cpu_to_le16(MAX_SNMP_BUF_SIZE); + cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) + + MAX_SNMP_BUF_SIZE); + } + + switch (cmd_oid) { + case FRAG_THRESH_I: + snmp_mib->oid = cpu_to_le16((u16) FRAG_THRESH_I); + if (cmd_action == HostCmd_ACT_GEN_SET) { + snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET); + snmp_mib->buf_size = cpu_to_le16(sizeof(u16)); + ul_temp = *((u32 *) data_buf); + *((__le16 *) (snmp_mib->value)) = + cpu_to_le16((u16) ul_temp); + cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) + + sizeof(u16)); + } + break; + case RTS_THRESH_I: + snmp_mib->oid = cpu_to_le16((u16) RTS_THRESH_I); + if (cmd_action == HostCmd_ACT_GEN_SET) { + snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET); + snmp_mib->buf_size = cpu_to_le16(sizeof(u16)); + ul_temp = *((u32 *) data_buf); + *(__le16 *) (snmp_mib->value) = + cpu_to_le16((u16) ul_temp); + cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) + + sizeof(u16)); + } + break; + + case SHORT_RETRY_LIM_I: + snmp_mib->oid = cpu_to_le16((u16) SHORT_RETRY_LIM_I); + if (cmd_action == HostCmd_ACT_GEN_SET) { + snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET); + snmp_mib->buf_size = cpu_to_le16(sizeof(u16)); + ul_temp = (*(u32 *) data_buf); + *((__le16 *) (snmp_mib->value)) = + cpu_to_le16((u16) ul_temp); + cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) + + sizeof(u16)); + } + break; + case DOT11D_I: + snmp_mib->oid = cpu_to_le16((u16) DOT11D_I); + if (cmd_action == HostCmd_ACT_GEN_SET) { + snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET); + snmp_mib->buf_size = cpu_to_le16(sizeof(u16)); + ul_temp = *(u32 *) data_buf; + *((__le16 *) (snmp_mib->value)) = + cpu_to_le16((u16) ul_temp); + cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) + + sizeof(u16)); + } + break; + default: + break; + } + dev_dbg(priv->adapter->dev, + "cmd: SNMP_CMD: Action=0x%x, OID=0x%x, OIDSize=0x%x," + " Value=0x%x\n", + cmd_action, cmd_oid, le16_to_cpu(snmp_mib->buf_size), + le16_to_cpu(*(__le16 *) snmp_mib->value)); + return 0; +} + +/* + * This function prepares command to get log. + * + * Preparation includes - + * - Setting command ID and proper size + * - Ensuring correct endian-ness + */ +static int +mwifiex_cmd_802_11_get_log(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd) +{ + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_GET_LOG); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_get_log) + + S_DS_GEN); + return 0; +} + +/* + * This function prepares command to set/get Tx data rate configuration. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting configuration index, rate scope and rate drop pattern + * parameters (as required) + * - Ensuring correct endian-ness + */ +static int mwifiex_cmd_tx_rate_cfg(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf) +{ + struct host_cmd_ds_tx_rate_cfg *rate_cfg = &cmd->params.tx_rate_cfg; + struct mwifiex_rate_scope *rate_scope; + struct mwifiex_rate_drop_pattern *rate_drop; + u16 *pbitmap_rates = (u16 *) data_buf; + + u32 i; + + cmd->command = cpu_to_le16(HostCmd_CMD_TX_RATE_CFG); + + rate_cfg->action = cpu_to_le16(cmd_action); + rate_cfg->cfg_index = 0; + + rate_scope = (struct mwifiex_rate_scope *) ((u8 *) rate_cfg + + sizeof(struct host_cmd_ds_tx_rate_cfg)); + rate_scope->type = cpu_to_le16(TLV_TYPE_RATE_SCOPE); + rate_scope->length = cpu_to_le16(sizeof(struct mwifiex_rate_scope) - + sizeof(struct mwifiex_ie_types_header)); + if (pbitmap_rates != NULL) { + rate_scope->hr_dsss_rate_bitmap = cpu_to_le16(pbitmap_rates[0]); + rate_scope->ofdm_rate_bitmap = cpu_to_le16(pbitmap_rates[1]); + for (i = 0; + i < sizeof(rate_scope->ht_mcs_rate_bitmap) / sizeof(u16); + i++) + rate_scope->ht_mcs_rate_bitmap[i] = + cpu_to_le16(pbitmap_rates[2 + i]); + } else { + rate_scope->hr_dsss_rate_bitmap = + cpu_to_le16(priv->bitmap_rates[0]); + rate_scope->ofdm_rate_bitmap = + cpu_to_le16(priv->bitmap_rates[1]); + for (i = 0; + i < sizeof(rate_scope->ht_mcs_rate_bitmap) / sizeof(u16); + i++) + rate_scope->ht_mcs_rate_bitmap[i] = + cpu_to_le16(priv->bitmap_rates[2 + i]); + } + + rate_drop = (struct mwifiex_rate_drop_pattern *) ((u8 *) rate_scope + + sizeof(struct mwifiex_rate_scope)); + rate_drop->type = cpu_to_le16(TLV_TYPE_RATE_DROP_CONTROL); + rate_drop->length = cpu_to_le16(sizeof(rate_drop->rate_drop_mode)); + rate_drop->rate_drop_mode = 0; + + cmd->size = + cpu_to_le16(S_DS_GEN + sizeof(struct host_cmd_ds_tx_rate_cfg) + + sizeof(struct mwifiex_rate_scope) + + sizeof(struct mwifiex_rate_drop_pattern)); + + return 0; +} + +/* + * This function prepares command to set/get Tx power configuration. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting Tx power mode, power group TLV + * (as required) + * - Ensuring correct endian-ness + */ +static int mwifiex_cmd_tx_power_cfg(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf) +{ + struct mwifiex_types_power_group *pg_tlv = NULL; + struct host_cmd_ds_txpwr_cfg *txp = NULL; + struct host_cmd_ds_txpwr_cfg *cmd_txp_cfg = &cmd->params.txp_cfg; + + cmd->command = cpu_to_le16(HostCmd_CMD_TXPWR_CFG); + cmd->size = + cpu_to_le16(S_DS_GEN + sizeof(struct host_cmd_ds_txpwr_cfg)); + switch (cmd_action) { + case HostCmd_ACT_GEN_SET: + txp = (struct host_cmd_ds_txpwr_cfg *) data_buf; + if (txp->mode) { + pg_tlv = (struct mwifiex_types_power_group + *) ((unsigned long) data_buf + + sizeof(struct host_cmd_ds_txpwr_cfg)); + memmove(cmd_txp_cfg, data_buf, + sizeof(struct host_cmd_ds_txpwr_cfg) + + sizeof(struct mwifiex_types_power_group) + + pg_tlv->length); + + pg_tlv = (struct mwifiex_types_power_group *) ((u8 *) + cmd_txp_cfg + + sizeof(struct host_cmd_ds_txpwr_cfg)); + cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) + + sizeof(struct mwifiex_types_power_group) + + pg_tlv->length); + } else { + memmove(cmd_txp_cfg, data_buf, + sizeof(struct host_cmd_ds_txpwr_cfg)); + } + cmd_txp_cfg->action = cpu_to_le16(cmd_action); + break; + case HostCmd_ACT_GEN_GET: + cmd_txp_cfg->action = cpu_to_le16(cmd_action); + break; + } + + return 0; +} + +/* + * This function prepares command to set Host Sleep configuration. + * + * Preparation includes - + * - Setting command ID and proper size + * - Setting Host Sleep action, conditions, ARP filters + * (as required) + * - Ensuring correct endian-ness + */ +static int mwifiex_cmd_802_11_hs_cfg(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, + struct mwifiex_hs_config_param *data_buf) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct host_cmd_ds_802_11_hs_cfg_enh *hs_cfg = &cmd->params.opt_hs_cfg; + u16 hs_activate = false; + + if (data_buf == NULL) + /* New Activate command */ + hs_activate = true; + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH); + + if (!hs_activate && + (data_buf->conditions + != cpu_to_le32(HOST_SLEEP_CFG_CANCEL)) + && ((adapter->arp_filter_size > 0) + && (adapter->arp_filter_size <= ARP_FILTER_MAX_BUF_SIZE))) { + dev_dbg(adapter->dev, + "cmd: Attach %d bytes ArpFilter to HSCfg cmd\n", + adapter->arp_filter_size); + memcpy(((u8 *) hs_cfg) + + sizeof(struct host_cmd_ds_802_11_hs_cfg_enh), + adapter->arp_filter, adapter->arp_filter_size); + cmd->size = cpu_to_le16(adapter->arp_filter_size + + sizeof(struct host_cmd_ds_802_11_hs_cfg_enh) + + S_DS_GEN); + } else { + cmd->size = cpu_to_le16(S_DS_GEN + sizeof(struct + host_cmd_ds_802_11_hs_cfg_enh)); + } + if (hs_activate) { + hs_cfg->action = cpu_to_le16(HS_ACTIVATE); + hs_cfg->params.hs_activate.resp_ctrl = RESP_NEEDED; + } else { + hs_cfg->action = cpu_to_le16(HS_CONFIGURE); + hs_cfg->params.hs_config.conditions = data_buf->conditions; + hs_cfg->params.hs_config.gpio = data_buf->gpio; + hs_cfg->params.hs_config.gap = data_buf->gap; + dev_dbg(adapter->dev, + "cmd: HS_CFG_CMD: condition:0x%x gpio:0x%x gap:0x%x\n", + hs_cfg->params.hs_config.conditions, + hs_cfg->params.hs_config.gpio, + hs_cfg->params.hs_config.gap); + } + + return 0; +} + +/* + * This function prepares command to set/get MAC address. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting MAC address (for SET only) + * - Ensuring correct endian-ness + */ +static int mwifiex_cmd_802_11_mac_address(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action) +{ + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_MAC_ADDRESS); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_mac_address) + + S_DS_GEN); + cmd->result = 0; + + cmd->params.mac_addr.action = cpu_to_le16(cmd_action); + + if (cmd_action == HostCmd_ACT_GEN_SET) + memcpy(cmd->params.mac_addr.mac_addr, priv->curr_addr, + ETH_ALEN); + return 0; +} + +/* + * This function prepares command to set MAC multicast address. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting MAC multicast address + * - Ensuring correct endian-ness + */ +static int mwifiex_cmd_mac_multicast_adr(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf) +{ + struct mwifiex_multicast_list *mcast_list = + (struct mwifiex_multicast_list *) data_buf; + struct host_cmd_ds_mac_multicast_adr *mcast_addr = &cmd->params.mc_addr; + + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_mac_multicast_adr) + + S_DS_GEN); + cmd->command = cpu_to_le16(HostCmd_CMD_MAC_MULTICAST_ADR); + + mcast_addr->action = cpu_to_le16(cmd_action); + mcast_addr->num_of_adrs = + cpu_to_le16((u16) mcast_list->num_multicast_addr); + memcpy(mcast_addr->mac_list, mcast_list->mac_list, + mcast_list->num_multicast_addr * ETH_ALEN); + + return 0; +} + +/* + * This function prepares command to deauthenticate. + * + * Preparation includes - + * - Setting command ID and proper size + * - Setting AP MAC address and reason code + * - Ensuring correct endian-ness + */ +static int mwifiex_cmd_802_11_deauthenticate(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf) +{ + struct host_cmd_ds_802_11_deauthenticate *deauth = &cmd->params.deauth; + + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_DEAUTHENTICATE); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_deauthenticate) + + S_DS_GEN); + + /* Set AP MAC address */ + memcpy(deauth->mac_addr, (u8 *) data_buf, ETH_ALEN); + + dev_dbg(priv->adapter->dev, "cmd: Deauth: %pM\n", deauth->mac_addr); + + deauth->reason_code = cpu_to_le16(WLAN_REASON_DEAUTH_LEAVING); + + return 0; +} + +/* + * This function prepares command to stop Ad-Hoc network. + * + * Preparation includes - + * - Setting command ID and proper size + * - Ensuring correct endian-ness + */ +static int mwifiex_cmd_802_11_ad_hoc_stop(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd) +{ + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_STOP); + cmd->size = cpu_to_le16(S_DS_GEN); + return 0; +} + +/* + * This function sets WEP key(s) to key parameter TLV(s). + * + * Multi-key parameter TLVs are supported, so we can send multiple + * WEP keys in a single buffer. + */ +static int +mwifiex_set_keyparamset_wep(struct mwifiex_private *priv, + struct mwifiex_ie_type_key_param_set *key_param_set, + u16 *key_param_len) +{ + int cur_key_param_len = 0; + u8 i; + + /* Multi-key_param_set TLV is supported */ + for (i = 0; i < NUM_WEP_KEYS; i++) { + if ((priv->wep_key[i].key_length == WLAN_KEY_LEN_WEP40) || + (priv->wep_key[i].key_length == WLAN_KEY_LEN_WEP104)) { + key_param_set->type = + cpu_to_le16(TLV_TYPE_KEY_MATERIAL); +/* Key_param_set WEP fixed length */ +#define KEYPARAMSET_WEP_FIXED_LEN 8 + key_param_set->length = cpu_to_le16((u16) + (priv->wep_key[i]. + key_length + + KEYPARAMSET_WEP_FIXED_LEN)); + key_param_set->key_type_id = + cpu_to_le16(KEY_TYPE_ID_WEP); + key_param_set->key_info = + cpu_to_le16(KEY_INFO_WEP_ENABLED | + KEY_INFO_WEP_UNICAST | + KEY_INFO_WEP_MCAST); + key_param_set->key_len = + cpu_to_le16(priv->wep_key[i].key_length); + /* Set WEP key index */ + key_param_set->key[0] = i; + /* Set default Tx key flag */ + if (i == + (priv-> + wep_key_curr_index & HostCmd_WEP_KEY_INDEX_MASK)) + key_param_set->key[1] = 1; + else + key_param_set->key[1] = 0; + memmove(&key_param_set->key[2], + priv->wep_key[i].key_material, + priv->wep_key[i].key_length); + + cur_key_param_len = priv->wep_key[i].key_length + + KEYPARAMSET_WEP_FIXED_LEN + + sizeof(struct mwifiex_ie_types_header); + *key_param_len += (u16) cur_key_param_len; + key_param_set = + (struct mwifiex_ie_type_key_param_set *) + ((u8 *)key_param_set + + cur_key_param_len); + } else if (!priv->wep_key[i].key_length) { + continue; + } else { + dev_err(priv->adapter->dev, + "key%d Length = %d is incorrect\n", + (i + 1), priv->wep_key[i].key_length); + return -1; + } + } + + return 0; +} + +/* + * This function prepares command to set/get/reset network key(s). + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting WEP keys, WAPI keys or WPA keys along with required + * encryption (TKIP, AES) (as required) + * - Ensuring correct endian-ness + */ +static int mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, + u32 cmd_oid, void *data_buf) +{ + struct host_cmd_ds_802_11_key_material *key_material = + &cmd->params.key_material; + struct mwifiex_ds_encrypt_key *enc_key = + (struct mwifiex_ds_encrypt_key *) data_buf; + u16 key_param_len = 0; + int ret = 0; + const u8 bc_mac[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_KEY_MATERIAL); + key_material->action = cpu_to_le16(cmd_action); + + if (cmd_action == HostCmd_ACT_GEN_GET) { + cmd->size = + cpu_to_le16(sizeof(key_material->action) + S_DS_GEN); + return ret; + } + + if (!enc_key) { + memset(&key_material->key_param_set, 0, + (NUM_WEP_KEYS * + sizeof(struct mwifiex_ie_type_key_param_set))); + ret = mwifiex_set_keyparamset_wep(priv, + &key_material->key_param_set, + &key_param_len); + cmd->size = cpu_to_le16(key_param_len + + sizeof(key_material->action) + S_DS_GEN); + return ret; + } else + memset(&key_material->key_param_set, 0, + sizeof(struct mwifiex_ie_type_key_param_set)); + if (enc_key->is_wapi_key) { + dev_dbg(priv->adapter->dev, "info: Set WAPI Key\n"); + key_material->key_param_set.key_type_id = + cpu_to_le16(KEY_TYPE_ID_WAPI); + if (cmd_oid == KEY_INFO_ENABLED) + key_material->key_param_set.key_info = + cpu_to_le16(KEY_INFO_WAPI_ENABLED); + else + key_material->key_param_set.key_info = + cpu_to_le16(!KEY_INFO_WAPI_ENABLED); + + key_material->key_param_set.key[0] = enc_key->key_index; + if (!priv->sec_info.wapi_key_on) + key_material->key_param_set.key[1] = 1; + else + /* set 0 when re-key */ + key_material->key_param_set.key[1] = 0; + + if (0 != memcmp(enc_key->mac_addr, bc_mac, sizeof(bc_mac))) { + /* WAPI pairwise key: unicast */ + key_material->key_param_set.key_info |= + cpu_to_le16(KEY_INFO_WAPI_UNICAST); + } else { /* WAPI group key: multicast */ + key_material->key_param_set.key_info |= + cpu_to_le16(KEY_INFO_WAPI_MCAST); + priv->sec_info.wapi_key_on = true; + } + + key_material->key_param_set.type = + cpu_to_le16(TLV_TYPE_KEY_MATERIAL); + key_material->key_param_set.key_len = + cpu_to_le16(WAPI_KEY_LEN); + memcpy(&key_material->key_param_set.key[2], + enc_key->key_material, enc_key->key_len); + memcpy(&key_material->key_param_set.key[2 + enc_key->key_len], + enc_key->wapi_rxpn, WAPI_RXPN_LEN); + key_material->key_param_set.length = + cpu_to_le16(WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN); + + key_param_len = (WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN) + + sizeof(struct mwifiex_ie_types_header); + cmd->size = cpu_to_le16(key_param_len + + sizeof(key_material->action) + S_DS_GEN); + return ret; + } + if (enc_key->key_len == WLAN_KEY_LEN_CCMP) { + dev_dbg(priv->adapter->dev, "cmd: WPA_AES\n"); + key_material->key_param_set.key_type_id = + cpu_to_le16(KEY_TYPE_ID_AES); + if (cmd_oid == KEY_INFO_ENABLED) + key_material->key_param_set.key_info = + cpu_to_le16(KEY_INFO_AES_ENABLED); + else + key_material->key_param_set.key_info = + cpu_to_le16(!KEY_INFO_AES_ENABLED); + + if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST) + /* AES pairwise key: unicast */ + key_material->key_param_set.key_info |= + cpu_to_le16(KEY_INFO_AES_UNICAST); + else /* AES group key: multicast */ + key_material->key_param_set.key_info |= + cpu_to_le16(KEY_INFO_AES_MCAST); + } else if (enc_key->key_len == WLAN_KEY_LEN_TKIP) { + dev_dbg(priv->adapter->dev, "cmd: WPA_TKIP\n"); + key_material->key_param_set.key_type_id = + cpu_to_le16(KEY_TYPE_ID_TKIP); + key_material->key_param_set.key_info = + cpu_to_le16(KEY_INFO_TKIP_ENABLED); + + if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST) + /* TKIP pairwise key: unicast */ + key_material->key_param_set.key_info |= + cpu_to_le16(KEY_INFO_TKIP_UNICAST); + else /* TKIP group key: multicast */ + key_material->key_param_set.key_info |= + cpu_to_le16(KEY_INFO_TKIP_MCAST); + } + + if (key_material->key_param_set.key_type_id) { + key_material->key_param_set.type = + cpu_to_le16(TLV_TYPE_KEY_MATERIAL); + key_material->key_param_set.key_len = + cpu_to_le16((u16) enc_key->key_len); + memcpy(key_material->key_param_set.key, enc_key->key_material, + enc_key->key_len); + key_material->key_param_set.length = + cpu_to_le16((u16) enc_key->key_len + + KEYPARAMSET_FIXED_LEN); + + key_param_len = (u16) (enc_key->key_len + KEYPARAMSET_FIXED_LEN) + + sizeof(struct mwifiex_ie_types_header); + + cmd->size = cpu_to_le16(key_param_len + + sizeof(key_material->action) + S_DS_GEN); + } + + return ret; +} + +/* + * This function prepares command to set/get 11d domain information. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting domain information fields (for SET only) + * - Ensuring correct endian-ness + */ +static int mwifiex_cmd_802_11d_domain_info(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct host_cmd_ds_802_11d_domain_info *domain_info = + &cmd->params.domain_info; + struct mwifiex_ietypes_domain_param_set *domain = + &domain_info->domain; + u8 no_of_triplet = adapter->domain_reg.no_of_triplet; + + dev_dbg(adapter->dev, "info: 11D: no_of_triplet=0x%x\n", no_of_triplet); + + cmd->command = cpu_to_le16(HostCmd_CMD_802_11D_DOMAIN_INFO); + domain_info->action = cpu_to_le16(cmd_action); + if (cmd_action == HostCmd_ACT_GEN_GET) { + cmd->size = cpu_to_le16(sizeof(domain_info->action) + S_DS_GEN); + return 0; + } + + /* Set domain info fields */ + domain->header.type = cpu_to_le16(WLAN_EID_COUNTRY); + memcpy(domain->country_code, adapter->domain_reg.country_code, + sizeof(domain->country_code)); + + domain->header.len = cpu_to_le16((no_of_triplet * + sizeof(struct ieee80211_country_ie_triplet)) + + sizeof(domain->country_code)); + + if (no_of_triplet) { + memcpy(domain->triplet, adapter->domain_reg.triplet, + no_of_triplet * + sizeof(struct ieee80211_country_ie_triplet)); + + cmd->size = cpu_to_le16(sizeof(domain_info->action) + + le16_to_cpu(domain->header.len) + + sizeof(struct mwifiex_ie_types_header) + + S_DS_GEN); + } else { + cmd->size = cpu_to_le16(sizeof(domain_info->action) + S_DS_GEN); + } + + return 0; +} + +/* + * This function prepares command to set/get RF channel. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting RF type and current RF channel (for SET only) + * - Ensuring correct endian-ness + */ +static int mwifiex_cmd_802_11_rf_channel(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf) +{ + struct host_cmd_ds_802_11_rf_channel *rf_chan = + &cmd->params.rf_channel; + uint16_t rf_type = le16_to_cpu(rf_chan->rf_type); + + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_RF_CHANNEL); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_rf_channel) + + S_DS_GEN); + + if (cmd_action == HostCmd_ACT_GEN_SET) { + if ((priv->adapter->adhoc_start_band & BAND_A) + || (priv->adapter->adhoc_start_band & BAND_AN)) + rf_chan->rf_type = + cpu_to_le16(HostCmd_SCAN_RADIO_TYPE_A); + + rf_type = le16_to_cpu(rf_chan->rf_type); + SET_SECONDARYCHAN(rf_type, priv->adapter->chan_offset); + rf_chan->current_channel = cpu_to_le16(*((u16 *) data_buf)); + } + rf_chan->action = cpu_to_le16(cmd_action); + return 0; +} + +/* + * This function prepares command to set/get IBSS coalescing status. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting status to enable or disable (for SET only) + * - Ensuring correct endian-ness + */ +static int mwifiex_cmd_ibss_coalescing_status(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf) +{ + struct host_cmd_ds_802_11_ibss_status *ibss_coal = + &(cmd->params.ibss_coalescing); + u16 enable = 0; + + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_IBSS_COALESCING_STATUS); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_ibss_status) + + S_DS_GEN); + cmd->result = 0; + ibss_coal->action = cpu_to_le16(cmd_action); + + switch (cmd_action) { + case HostCmd_ACT_GEN_SET: + if (data_buf != NULL) + enable = *(u16 *) data_buf; + ibss_coal->enable = cpu_to_le16(enable); + break; + + /* In other case.. Nothing to do */ + case HostCmd_ACT_GEN_GET: + default: + break; + } + + return 0; +} + +/* + * This function prepares command to set/get register value. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting register offset (for both GET and SET) and + * register value (for SET only) + * - Ensuring correct endian-ness + * + * The following type of registers can be accessed with this function - + * - MAC register + * - BBP register + * - RF register + * - PMIC register + * - CAU register + * - EEPROM + */ +static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf) +{ + struct mwifiex_ds_reg_rw *reg_rw; + + reg_rw = (struct mwifiex_ds_reg_rw *) data_buf; + switch (le16_to_cpu(cmd->command)) { + case HostCmd_CMD_MAC_REG_ACCESS: + { + struct host_cmd_ds_mac_reg_access *mac_reg; + + cmd->size = cpu_to_le16(sizeof(*mac_reg) + S_DS_GEN); + mac_reg = (struct host_cmd_ds_mac_reg_access *) &cmd-> + params.mac_reg; + mac_reg->action = cpu_to_le16(cmd_action); + mac_reg->offset = + cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); + mac_reg->value = reg_rw->value; + break; + } + case HostCmd_CMD_BBP_REG_ACCESS: + { + struct host_cmd_ds_bbp_reg_access *bbp_reg; + + cmd->size = cpu_to_le16(sizeof(*bbp_reg) + S_DS_GEN); + bbp_reg = (struct host_cmd_ds_bbp_reg_access *) &cmd-> + params.bbp_reg; + bbp_reg->action = cpu_to_le16(cmd_action); + bbp_reg->offset = + cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); + bbp_reg->value = (u8) le32_to_cpu(reg_rw->value); + break; + } + case HostCmd_CMD_RF_REG_ACCESS: + { + struct host_cmd_ds_rf_reg_access *rf_reg; + + cmd->size = cpu_to_le16(sizeof(*rf_reg) + S_DS_GEN); + rf_reg = (struct host_cmd_ds_rf_reg_access *) &cmd-> + params.rf_reg; + rf_reg->action = cpu_to_le16(cmd_action); + rf_reg->offset = + cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); + rf_reg->value = (u8) le32_to_cpu(reg_rw->value); + break; + } + case HostCmd_CMD_PMIC_REG_ACCESS: + { + struct host_cmd_ds_pmic_reg_access *pmic_reg; + + cmd->size = cpu_to_le16(sizeof(*pmic_reg) + S_DS_GEN); + pmic_reg = (struct host_cmd_ds_pmic_reg_access *) &cmd-> + params.pmic_reg; + pmic_reg->action = cpu_to_le16(cmd_action); + pmic_reg->offset = + cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); + pmic_reg->value = (u8) le32_to_cpu(reg_rw->value); + break; + } + case HostCmd_CMD_CAU_REG_ACCESS: + { + struct host_cmd_ds_rf_reg_access *cau_reg; + + cmd->size = cpu_to_le16(sizeof(*cau_reg) + S_DS_GEN); + cau_reg = (struct host_cmd_ds_rf_reg_access *) &cmd-> + params.rf_reg; + cau_reg->action = cpu_to_le16(cmd_action); + cau_reg->offset = + cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); + cau_reg->value = (u8) le32_to_cpu(reg_rw->value); + break; + } + case HostCmd_CMD_802_11_EEPROM_ACCESS: + { + struct mwifiex_ds_read_eeprom *rd_eeprom = + (struct mwifiex_ds_read_eeprom *) data_buf; + struct host_cmd_ds_802_11_eeprom_access *cmd_eeprom = + (struct host_cmd_ds_802_11_eeprom_access *) + &cmd->params.eeprom; + + cmd->size = cpu_to_le16(sizeof(*cmd_eeprom) + S_DS_GEN); + cmd_eeprom->action = cpu_to_le16(cmd_action); + cmd_eeprom->offset = rd_eeprom->offset; + cmd_eeprom->byte_count = rd_eeprom->byte_count; + cmd_eeprom->value = 0; + break; + } + default: + return -1; + } + + return 0; +} + +/* + * This function prepares the commands before sending them to the firmware. + * + * This is a generic function which calls specific command preparation + * routines based upon the command number. + */ +int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, + u16 cmd_action, u32 cmd_oid, + void *data_buf, void *cmd_buf) +{ + struct host_cmd_ds_command *cmd_ptr = + (struct host_cmd_ds_command *) cmd_buf; + int ret = 0; + + /* Prepare command */ + switch (cmd_no) { + case HostCmd_CMD_GET_HW_SPEC: + ret = mwifiex_cmd_get_hw_spec(priv, cmd_ptr); + break; + case HostCmd_CMD_MAC_CONTROL: + ret = mwifiex_cmd_mac_control(priv, cmd_ptr, cmd_action, + data_buf); + break; + case HostCmd_CMD_802_11_MAC_ADDRESS: + ret = mwifiex_cmd_802_11_mac_address(priv, cmd_ptr, + cmd_action); + break; + case HostCmd_CMD_MAC_MULTICAST_ADR: + ret = mwifiex_cmd_mac_multicast_adr(priv, cmd_ptr, cmd_action, + data_buf); + break; + case HostCmd_CMD_TX_RATE_CFG: + ret = mwifiex_cmd_tx_rate_cfg(priv, cmd_ptr, cmd_action, + data_buf); + break; + case HostCmd_CMD_TXPWR_CFG: + ret = mwifiex_cmd_tx_power_cfg(priv, cmd_ptr, cmd_action, + data_buf); + break; + case HostCmd_CMD_802_11_PS_MODE_ENH: + ret = mwifiex_cmd_enh_power_mode(priv, cmd_ptr, cmd_action, + (uint16_t)cmd_oid, data_buf); + break; + case HostCmd_CMD_802_11_HS_CFG_ENH: + ret = mwifiex_cmd_802_11_hs_cfg(priv, cmd_ptr, cmd_action, + (struct mwifiex_hs_config_param *) data_buf); + break; + case HostCmd_CMD_802_11_SCAN: + ret = mwifiex_cmd_802_11_scan(priv, cmd_ptr, data_buf); + break; + case HostCmd_CMD_802_11_BG_SCAN_QUERY: + ret = mwifiex_cmd_802_11_bg_scan_query(priv, cmd_ptr, + data_buf); + break; + case HostCmd_CMD_802_11_ASSOCIATE: + ret = mwifiex_cmd_802_11_associate(priv, cmd_ptr, data_buf); + break; + case HostCmd_CMD_802_11_DEAUTHENTICATE: + ret = mwifiex_cmd_802_11_deauthenticate(priv, cmd_ptr, + data_buf); + break; + case HostCmd_CMD_802_11_AD_HOC_START: + ret = mwifiex_cmd_802_11_ad_hoc_start(priv, cmd_ptr, + data_buf); + break; + case HostCmd_CMD_802_11_GET_LOG: + ret = mwifiex_cmd_802_11_get_log(priv, cmd_ptr); + break; + case HostCmd_CMD_802_11_AD_HOC_JOIN: + ret = mwifiex_cmd_802_11_ad_hoc_join(priv, cmd_ptr, + data_buf); + break; + case HostCmd_CMD_802_11_AD_HOC_STOP: + ret = mwifiex_cmd_802_11_ad_hoc_stop(priv, cmd_ptr); + break; + case HostCmd_CMD_RSSI_INFO: + ret = mwifiex_cmd_802_11_rssi_info(priv, cmd_ptr, cmd_action); + break; + case HostCmd_CMD_802_11_SNMP_MIB: + ret = mwifiex_cmd_802_11_snmp_mib(priv, cmd_ptr, cmd_action, + cmd_oid, data_buf); + break; + case HostCmd_CMD_802_11_TX_RATE_QUERY: + cmd_ptr->command = + cpu_to_le16(HostCmd_CMD_802_11_TX_RATE_QUERY); + cmd_ptr->size = + cpu_to_le16(sizeof(struct host_cmd_ds_tx_rate_query) + + S_DS_GEN); + priv->tx_rate = 0; + ret = 0; + break; + case HostCmd_CMD_VERSION_EXT: + cmd_ptr->command = cpu_to_le16(cmd_no); + cmd_ptr->params.verext.version_str_sel = + (u8) (*((u32 *) data_buf)); + memcpy(&cmd_ptr->params, data_buf, + sizeof(struct host_cmd_ds_version_ext)); + cmd_ptr->size = + cpu_to_le16(sizeof(struct host_cmd_ds_version_ext) + + S_DS_GEN); + ret = 0; + break; + case HostCmd_CMD_802_11_RF_CHANNEL: + ret = mwifiex_cmd_802_11_rf_channel(priv, cmd_ptr, cmd_action, + data_buf); + break; + case HostCmd_CMD_FUNC_INIT: + if (priv->adapter->hw_status == MWIFIEX_HW_STATUS_RESET) + priv->adapter->hw_status = MWIFIEX_HW_STATUS_READY; + cmd_ptr->command = cpu_to_le16(cmd_no); + cmd_ptr->size = cpu_to_le16(S_DS_GEN); + break; + case HostCmd_CMD_FUNC_SHUTDOWN: + priv->adapter->hw_status = MWIFIEX_HW_STATUS_RESET; + cmd_ptr->command = cpu_to_le16(cmd_no); + cmd_ptr->size = cpu_to_le16(S_DS_GEN); + break; + case HostCmd_CMD_11N_ADDBA_REQ: + ret = mwifiex_cmd_11n_addba_req(priv, cmd_ptr, data_buf); + break; + case HostCmd_CMD_11N_DELBA: + ret = mwifiex_cmd_11n_delba(priv, cmd_ptr, data_buf); + break; + case HostCmd_CMD_11N_ADDBA_RSP: + ret = mwifiex_cmd_11n_addba_rsp_gen(priv, cmd_ptr, data_buf); + break; + case HostCmd_CMD_802_11_KEY_MATERIAL: + ret = mwifiex_cmd_802_11_key_material(priv, cmd_ptr, + cmd_action, cmd_oid, + data_buf); + break; + case HostCmd_CMD_802_11D_DOMAIN_INFO: + ret = mwifiex_cmd_802_11d_domain_info(priv, cmd_ptr, + cmd_action); + break; + case HostCmd_CMD_RECONFIGURE_TX_BUFF: + ret = mwifiex_cmd_recfg_tx_buf(priv, cmd_ptr, cmd_action, + data_buf); + break; + case HostCmd_CMD_AMSDU_AGGR_CTRL: + ret = mwifiex_cmd_amsdu_aggr_ctrl(priv, cmd_ptr, cmd_action, + data_buf); + break; + case HostCmd_CMD_11N_CFG: + ret = mwifiex_cmd_11n_cfg(priv, cmd_ptr, cmd_action, + data_buf); + break; + case HostCmd_CMD_WMM_GET_STATUS: + dev_dbg(priv->adapter->dev, + "cmd: WMM: WMM_GET_STATUS cmd sent\n"); + cmd_ptr->command = cpu_to_le16(HostCmd_CMD_WMM_GET_STATUS); + cmd_ptr->size = + cpu_to_le16(sizeof(struct host_cmd_ds_wmm_get_status) + + S_DS_GEN); + ret = 0; + break; + case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS: + ret = mwifiex_cmd_ibss_coalescing_status(priv, cmd_ptr, + cmd_action, data_buf); + break; + case HostCmd_CMD_MAC_REG_ACCESS: + case HostCmd_CMD_BBP_REG_ACCESS: + case HostCmd_CMD_RF_REG_ACCESS: + case HostCmd_CMD_PMIC_REG_ACCESS: + case HostCmd_CMD_CAU_REG_ACCESS: + case HostCmd_CMD_802_11_EEPROM_ACCESS: + ret = mwifiex_cmd_reg_access(cmd_ptr, cmd_action, data_buf); + break; + case HostCmd_CMD_SET_BSS_MODE: + cmd_ptr->command = cpu_to_le16(cmd_no); + if (priv->bss_mode == NL80211_IFTYPE_ADHOC) + cmd_ptr->params.bss_mode.con_type = + CONNECTION_TYPE_ADHOC; + else if (priv->bss_mode == NL80211_IFTYPE_STATION) + cmd_ptr->params.bss_mode.con_type = + CONNECTION_TYPE_INFRA; + cmd_ptr->size = cpu_to_le16(sizeof(struct + host_cmd_ds_set_bss_mode) + S_DS_GEN); + ret = 0; + break; + default: + dev_err(priv->adapter->dev, + "PREP_CMD: unknown cmd- %#x\n", cmd_no); + ret = -1; + break; + } + return ret; +} + +/* + * This function issues commands to initialize firmware. + * + * This is called after firmware download to bring the card to + * working state. + * + * The following commands are issued sequentially - + * - Function init (for first interface only) + * - Read MAC address (for first interface only) + * - Reconfigure Tx buffer size (for first interface only) + * - Enable auto deep sleep (for first interface only) + * - Get Tx rate + * - Get Tx power + * - Set IBSS coalescing status + * - Set AMSDU aggregation control + * - Set 11d control + * - Set MAC control (this must be the last command to initialize firmware) + */ +int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta) +{ + int ret = 0; + u16 enable = true; + struct mwifiex_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl; + struct mwifiex_ds_auto_ds auto_ds; + enum state_11d_t state_11d; + + if (first_sta) { + + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_FUNC_INIT, + HostCmd_ACT_GEN_SET, 0, NULL, NULL); + if (ret) + return -1; + /* Read MAC address from HW */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_GET_HW_SPEC, + HostCmd_ACT_GEN_GET, 0, NULL, NULL); + if (ret) + return -1; + + /* Reconfigure tx buf size */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF, + HostCmd_ACT_GEN_SET, 0, NULL, + &priv->adapter->tx_buf_size); + if (ret) + return -1; + + /* Enable IEEE PS by default */ + priv->adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP; + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH, + EN_AUTO_PS, BITMAP_STA_PS, NULL, + NULL); + if (ret) + return -1; + } + + /* get tx rate */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_TX_RATE_CFG, + HostCmd_ACT_GEN_GET, 0, NULL, NULL); + if (ret) + return -1; + priv->data_rate = 0; + + /* get tx power */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_TXPWR_CFG, + HostCmd_ACT_GEN_GET, 0, NULL, NULL); + if (ret) + return -1; + + /* set ibss coalescing_status */ + ret = mwifiex_prepare_cmd(priv, + HostCmd_CMD_802_11_IBSS_COALESCING_STATUS, + HostCmd_ACT_GEN_SET, 0, NULL, &enable); + if (ret) + return -1; + + memset(&amsdu_aggr_ctrl, 0, sizeof(amsdu_aggr_ctrl)); + amsdu_aggr_ctrl.enable = true; + /* Send request to firmware */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_AMSDU_AGGR_CTRL, + HostCmd_ACT_GEN_SET, 0, NULL, + (void *) &amsdu_aggr_ctrl); + if (ret) + return -1; + /* MAC Control must be the last command in init_fw */ + /* set MAC Control */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_MAC_CONTROL, + HostCmd_ACT_GEN_SET, 0, NULL, + &priv->curr_pkt_filter); + if (ret) + return -1; + + if (first_sta) { + /* Enable auto deep sleep */ + auto_ds.auto_ds = DEEP_SLEEP_ON; + auto_ds.idle_time = DEEP_SLEEP_IDLE_TIME; + ret = mwifiex_prepare_cmd(priv, + HostCmd_CMD_802_11_PS_MODE_ENH, + EN_AUTO_PS, BITMAP_AUTO_DS, NULL, + &auto_ds); + if (ret) + return -1; + } + + /* Send cmd to FW to enable/disable 11D function */ + state_11d = ENABLE_11D; + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, + HostCmd_ACT_GEN_SET, DOT11D_I, + NULL, &state_11d); + if (ret) + dev_err(priv->adapter->dev, "11D: failed to enable 11D\n"); + + /* set last_init_cmd */ + priv->adapter->last_init_cmd = HostCmd_CMD_802_11_SNMP_MIB; + ret = -EINPROGRESS; + + return ret; +} diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c new file mode 100644 index 000000000000..74add45b99b6 --- /dev/null +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -0,0 +1,983 @@ +/* + * Marvell Wireless LAN device driver: station command response handling + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" + + +/* + * This function handles the command response error case. + * + * For scan response error, the function cancels all the pending + * scan commands and generates an event to inform the applications + * of the scan completion. + * + * For Power Save command failure, we do not retry enter PS + * command in case of Ad-hoc mode. + * + * For all other response errors, the current command buffer is freed + * and returned to the free command queue. + */ +static void +mwifiex_process_cmdresp_error(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + struct mwifiex_wait_queue *wq_buf) +{ + struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL; + struct mwifiex_adapter *adapter = priv->adapter; + struct host_cmd_ds_802_11_ps_mode_enh *pm; + unsigned long flags; + + dev_err(adapter->dev, "CMD_RESP: cmd %#x error, result=%#x\n", + resp->command, resp->result); + if (wq_buf) + wq_buf->status = MWIFIEX_ERROR_FW_CMDRESP; + + switch (le16_to_cpu(resp->command)) { + case HostCmd_CMD_802_11_PS_MODE_ENH: + pm = &resp->params.psmode_enh; + dev_err(adapter->dev, "PS_MODE_ENH cmd failed: " + "result=0x%x action=0x%X\n", + resp->result, le16_to_cpu(pm->action)); + /* We do not re-try enter-ps command in ad-hoc mode. */ + if (le16_to_cpu(pm->action) == EN_AUTO_PS && + (le16_to_cpu(pm->params.ps_bitmap) & BITMAP_STA_PS) && + priv->bss_mode == NL80211_IFTYPE_ADHOC) + adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM; + + break; + case HostCmd_CMD_802_11_SCAN: + /* Cancel all pending scan command */ + spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); + list_for_each_entry_safe(cmd_node, tmp_node, + &adapter->scan_pending_q, list) { + list_del(&cmd_node->list); + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, + flags); + mwifiex_insert_cmd_to_free_q(adapter, cmd_node); + spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); + } + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); + + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->scan_processing = false; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + if (priv->report_scan_result) + priv->report_scan_result = false; + if (priv->scan_pending_on_block) { + priv->scan_pending_on_block = false; + up(&priv->async_sem); + } + break; + + case HostCmd_CMD_MAC_CONTROL: + break; + + default: + break; + } + /* Handling errors here */ + mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); + + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->curr_cmd = NULL; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + + return; +} + +/* + * This function handles the command response of get RSSI info. + * + * Handling includes changing the header fields into CPU format + * and saving the following parameters in driver - + * - Last data and beacon RSSI value + * - Average data and beacon RSSI value + * - Last data and beacon NF value + * - Average data and beacon NF value + * + * The parameters are send to the application as well, along with + * calculated SNR values. + */ +static int mwifiex_ret_802_11_rssi_info(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *data_buf) +{ + struct host_cmd_ds_802_11_rssi_info_rsp *rssi_info_rsp = + &resp->params.rssi_info_rsp; + struct mwifiex_ds_get_signal *signal = NULL; + + priv->data_rssi_last = le16_to_cpu(rssi_info_rsp->data_rssi_last); + priv->data_nf_last = le16_to_cpu(rssi_info_rsp->data_nf_last); + + priv->data_rssi_avg = le16_to_cpu(rssi_info_rsp->data_rssi_avg); + priv->data_nf_avg = le16_to_cpu(rssi_info_rsp->data_nf_avg); + + priv->bcn_rssi_last = le16_to_cpu(rssi_info_rsp->bcn_rssi_last); + priv->bcn_nf_last = le16_to_cpu(rssi_info_rsp->bcn_nf_last); + + priv->bcn_rssi_avg = le16_to_cpu(rssi_info_rsp->bcn_rssi_avg); + priv->bcn_nf_avg = le16_to_cpu(rssi_info_rsp->bcn_nf_avg); + + /* Need to indicate IOCTL complete */ + if (data_buf) { + signal = (struct mwifiex_ds_get_signal *) data_buf; + memset(signal, 0, sizeof(struct mwifiex_ds_get_signal)); + + signal->selector = ALL_RSSI_INFO_MASK; + + /* RSSI */ + signal->bcn_rssi_last = priv->bcn_rssi_last; + signal->bcn_rssi_avg = priv->bcn_rssi_avg; + signal->data_rssi_last = priv->data_rssi_last; + signal->data_rssi_avg = priv->data_rssi_avg; + + /* SNR */ + signal->bcn_snr_last = + CAL_SNR(priv->bcn_rssi_last, priv->bcn_nf_last); + signal->bcn_snr_avg = + CAL_SNR(priv->bcn_rssi_avg, priv->bcn_nf_avg); + signal->data_snr_last = + CAL_SNR(priv->data_rssi_last, priv->data_nf_last); + signal->data_snr_avg = + CAL_SNR(priv->data_rssi_avg, priv->data_nf_avg); + + /* NF */ + signal->bcn_nf_last = priv->bcn_nf_last; + signal->bcn_nf_avg = priv->bcn_nf_avg; + signal->data_nf_last = priv->data_nf_last; + signal->data_nf_avg = priv->data_nf_avg; + } + + return 0; +} + +/* + * This function handles the command response of set/get SNMP + * MIB parameters. + * + * Handling includes changing the header fields into CPU format + * and saving the parameter in driver. + * + * The following parameters are supported - + * - Fragmentation threshold + * - RTS threshold + * - Short retry limit + */ +static int mwifiex_ret_802_11_snmp_mib(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *data_buf) +{ + struct host_cmd_ds_802_11_snmp_mib *smib = &resp->params.smib; + u16 oid = le16_to_cpu(smib->oid); + u16 query_type = le16_to_cpu(smib->query_type); + u32 ul_temp; + + dev_dbg(priv->adapter->dev, "info: SNMP_RESP: oid value = %#x," + " query_type = %#x, buf size = %#x\n", + oid, query_type, le16_to_cpu(smib->buf_size)); + if (query_type == HostCmd_ACT_GEN_GET) { + ul_temp = le16_to_cpu(*((__le16 *) (smib->value))); + if (data_buf) + *(u32 *)data_buf = ul_temp; + switch (oid) { + case FRAG_THRESH_I: + dev_dbg(priv->adapter->dev, + "info: SNMP_RESP: FragThsd =%u\n", ul_temp); + break; + case RTS_THRESH_I: + dev_dbg(priv->adapter->dev, + "info: SNMP_RESP: RTSThsd =%u\n", ul_temp); + break; + case SHORT_RETRY_LIM_I: + dev_dbg(priv->adapter->dev, + "info: SNMP_RESP: TxRetryCount=%u\n", ul_temp); + break; + default: + break; + } + } + + return 0; +} + +/* + * This function handles the command response of get log request + * + * Handling includes changing the header fields into CPU format + * and sending the received parameters to application. + */ +static int mwifiex_ret_get_log(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *data_buf) +{ + struct host_cmd_ds_802_11_get_log *get_log = + (struct host_cmd_ds_802_11_get_log *) &resp->params.get_log; + struct mwifiex_ds_get_stats *stats = NULL; + + if (data_buf) { + stats = (struct mwifiex_ds_get_stats *) data_buf; + stats->mcast_tx_frame = le32_to_cpu(get_log->mcast_tx_frame); + stats->failed = le32_to_cpu(get_log->failed); + stats->retry = le32_to_cpu(get_log->retry); + stats->multi_retry = le32_to_cpu(get_log->multi_retry); + stats->frame_dup = le32_to_cpu(get_log->frame_dup); + stats->rts_success = le32_to_cpu(get_log->rts_success); + stats->rts_failure = le32_to_cpu(get_log->rts_failure); + stats->ack_failure = le32_to_cpu(get_log->ack_failure); + stats->rx_frag = le32_to_cpu(get_log->rx_frag); + stats->mcast_rx_frame = le32_to_cpu(get_log->mcast_rx_frame); + stats->fcs_error = le32_to_cpu(get_log->fcs_error); + stats->tx_frame = le32_to_cpu(get_log->tx_frame); + stats->wep_icv_error[0] = + le32_to_cpu(get_log->wep_icv_err_cnt[0]); + stats->wep_icv_error[1] = + le32_to_cpu(get_log->wep_icv_err_cnt[1]); + stats->wep_icv_error[2] = + le32_to_cpu(get_log->wep_icv_err_cnt[2]); + stats->wep_icv_error[3] = + le32_to_cpu(get_log->wep_icv_err_cnt[3]); + } + + return 0; +} + +/* + * This function handles the command response of set/get Tx rate + * configurations. + * + * Handling includes changing the header fields into CPU format + * and saving the following parameters in driver - + * - DSSS rate bitmap + * - OFDM rate bitmap + * - HT MCS rate bitmaps + * + * Based on the new rate bitmaps, the function re-evaluates if + * auto data rate has been activated. If not, it sends another + * query to the firmware to get the current Tx data rate and updates + * the driver value. + */ +static int mwifiex_ret_tx_rate_cfg(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *data_buf) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_rate_cfg *ds_rate = NULL; + struct host_cmd_ds_tx_rate_cfg *rate_cfg = &resp->params.tx_rate_cfg; + struct mwifiex_rate_scope *rate_scope; + struct mwifiex_ie_types_header *head = NULL; + u16 tlv, tlv_buf_len; + u8 *tlv_buf; + u32 i; + int ret = 0; + + tlv_buf = (u8 *) ((u8 *) rate_cfg) + + sizeof(struct host_cmd_ds_tx_rate_cfg); + tlv_buf_len = *(u16 *) (tlv_buf + sizeof(u16)); + + while (tlv_buf && tlv_buf_len > 0) { + tlv = (*tlv_buf); + tlv = tlv | (*(tlv_buf + 1) << 8); + + switch (tlv) { + case TLV_TYPE_RATE_SCOPE: + rate_scope = (struct mwifiex_rate_scope *) tlv_buf; + priv->bitmap_rates[0] = + le16_to_cpu(rate_scope->hr_dsss_rate_bitmap); + priv->bitmap_rates[1] = + le16_to_cpu(rate_scope->ofdm_rate_bitmap); + for (i = 0; + i < + sizeof(rate_scope->ht_mcs_rate_bitmap) / + sizeof(u16); i++) + priv->bitmap_rates[2 + i] = + le16_to_cpu(rate_scope-> + ht_mcs_rate_bitmap[i]); + break; + /* Add RATE_DROP tlv here */ + } + + head = (struct mwifiex_ie_types_header *) tlv_buf; + tlv_buf += le16_to_cpu(head->len) + sizeof(*head); + tlv_buf_len -= le16_to_cpu(head->len); + } + + priv->is_data_rate_auto = mwifiex_is_rate_auto(priv); + + if (priv->is_data_rate_auto) + priv->data_rate = 0; + else + ret = mwifiex_prepare_cmd(priv, + HostCmd_CMD_802_11_TX_RATE_QUERY, + HostCmd_ACT_GEN_GET, 0, NULL, NULL); + + if (data_buf) { + ds_rate = (struct mwifiex_rate_cfg *) data_buf; + if (le16_to_cpu(rate_cfg->action) == HostCmd_ACT_GEN_GET) { + if (priv->is_data_rate_auto) { + ds_rate->is_rate_auto = 1; + } else { + ds_rate->rate = + mwifiex_get_rate_index(adapter, + priv-> + bitmap_rates, + sizeof(priv-> + bitmap_rates)); + if (ds_rate->rate >= + MWIFIEX_RATE_BITMAP_OFDM0 + && ds_rate->rate <= + MWIFIEX_RATE_BITMAP_OFDM7) + ds_rate->rate -= + (MWIFIEX_RATE_BITMAP_OFDM0 - + MWIFIEX_RATE_INDEX_OFDM0); + if (ds_rate->rate >= + MWIFIEX_RATE_BITMAP_MCS0 + && ds_rate->rate <= + MWIFIEX_RATE_BITMAP_MCS127) + ds_rate->rate -= + (MWIFIEX_RATE_BITMAP_MCS0 - + MWIFIEX_RATE_INDEX_MCS0); + } + } + } + + return ret; +} + +/* + * This function handles the command response of get Tx power level. + * + * Handling includes saving the maximum and minimum Tx power levels + * in driver, as well as sending the values to user. + */ +static int mwifiex_get_power_level(struct mwifiex_private *priv, void *data_buf) +{ + int length = -1, max_power = -1, min_power = -1; + struct mwifiex_types_power_group *pg_tlv_hdr = NULL; + struct mwifiex_power_group *pg = NULL; + + if (data_buf) { + pg_tlv_hdr = + (struct mwifiex_types_power_group *) ((u8 *) data_buf + + sizeof(struct host_cmd_ds_txpwr_cfg)); + pg = (struct mwifiex_power_group *) ((u8 *) pg_tlv_hdr + + sizeof(struct mwifiex_types_power_group)); + length = pg_tlv_hdr->length; + if (length > 0) { + max_power = pg->power_max; + min_power = pg->power_min; + length -= sizeof(struct mwifiex_power_group); + } + while (length) { + pg++; + if (max_power < pg->power_max) + max_power = pg->power_max; + + if (min_power > pg->power_min) + min_power = pg->power_min; + + length -= sizeof(struct mwifiex_power_group); + } + if (pg_tlv_hdr->length > 0) { + priv->min_tx_power_level = (u8) min_power; + priv->max_tx_power_level = (u8) max_power; + } + } else { + return -1; + } + + return 0; +} + +/* + * This function handles the command response of set/get Tx power + * configurations. + * + * Handling includes changing the header fields into CPU format + * and saving the current Tx power level in driver. + */ +static int mwifiex_ret_tx_power_cfg(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *data_buf) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct host_cmd_ds_txpwr_cfg *txp_cfg = &resp->params.txp_cfg; + struct mwifiex_types_power_group *pg_tlv_hdr = NULL; + struct mwifiex_power_group *pg = NULL; + u16 action = le16_to_cpu(txp_cfg->action); + + switch (action) { + case HostCmd_ACT_GEN_GET: + { + pg_tlv_hdr = + (struct mwifiex_types_power_group *) ((u8 *) + txp_cfg + + sizeof + (struct + host_cmd_ds_txpwr_cfg)); + pg = (struct mwifiex_power_group *) ((u8 *) + pg_tlv_hdr + + sizeof(struct + mwifiex_types_power_group)); + if (adapter->hw_status == + MWIFIEX_HW_STATUS_INITIALIZING) + mwifiex_get_power_level(priv, txp_cfg); + priv->tx_power_level = (u16) pg->power_min; + break; + } + case HostCmd_ACT_GEN_SET: + if (le32_to_cpu(txp_cfg->mode)) { + pg_tlv_hdr = + (struct mwifiex_types_power_group *) ((u8 *) + txp_cfg + + sizeof + (struct + host_cmd_ds_txpwr_cfg)); + pg = (struct mwifiex_power_group *) ((u8 *) pg_tlv_hdr + + + sizeof(struct + mwifiex_types_power_group)); + if (pg->power_max == pg->power_min) + priv->tx_power_level = (u16) pg->power_min; + } + break; + default: + dev_err(adapter->dev, "CMD_RESP: unknown cmd action %d\n", + action); + return 0; + } + dev_dbg(adapter->dev, + "info: Current TxPower Level = %d, Max Power=%d, Min Power=%d\n", + priv->tx_power_level, priv->max_tx_power_level, + priv->min_tx_power_level); + + return 0; +} + +/* + * This function handles the command response of set/get MAC address. + * + * Handling includes saving the MAC address in driver. + */ +static int mwifiex_ret_802_11_mac_address(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + struct host_cmd_ds_802_11_mac_address *cmd_mac_addr = + &resp->params.mac_addr; + + memcpy(priv->curr_addr, cmd_mac_addr->mac_addr, ETH_ALEN); + + dev_dbg(priv->adapter->dev, + "info: set mac address: %pM\n", priv->curr_addr); + + return 0; +} + +/* + * This function handles the command response of set/get MAC multicast + * address. + */ +static int mwifiex_ret_mac_multicast_adr(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + return 0; +} + +/* + * This function handles the command response of get Tx rate query. + * + * Handling includes changing the header fields into CPU format + * and saving the Tx rate and HT information parameters in driver. + * + * Both rate configuration and current data rate can be retrieved + * with this request. + */ +static int mwifiex_ret_802_11_tx_rate_query(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + struct mwifiex_adapter *adapter = priv->adapter; + + priv->tx_rate = resp->params.tx_rate.tx_rate; + priv->tx_htinfo = resp->params.tx_rate.ht_info; + if (!priv->is_data_rate_auto) + priv->data_rate = + mwifiex_index_to_data_rate(adapter, priv->tx_rate, + priv->tx_htinfo); + + return 0; +} + +/* + * This function handles the command response of a deauthenticate + * command. + * + * If the deauthenticated MAC matches the current BSS MAC, the connection + * state is reset. + */ +static int mwifiex_ret_802_11_deauthenticate(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + struct mwifiex_adapter *adapter = priv->adapter; + + adapter->dbg.num_cmd_deauth++; + if (!memcmp(resp->params.deauth.mac_addr, + &priv->curr_bss_params.bss_descriptor.mac_address, + sizeof(resp->params.deauth.mac_addr))) + mwifiex_reset_connect_state(priv); + + return 0; +} + +/* + * This function handles the command response of ad-hoc stop. + * + * The function resets the connection state in driver. + */ +static int mwifiex_ret_802_11_ad_hoc_stop(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + mwifiex_reset_connect_state(priv); + return 0; +} + +/* + * This function handles the command response of set/get key material. + * + * Handling includes updating the driver parameters to reflect the + * changes. + */ +static int mwifiex_ret_802_11_key_material(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + struct host_cmd_ds_802_11_key_material *key = + &resp->params.key_material; + + if (le16_to_cpu(key->action) == HostCmd_ACT_GEN_SET) { + if ((le16_to_cpu(key->key_param_set.key_info) & + KEY_INFO_TKIP_MCAST)) { + dev_dbg(priv->adapter->dev, "info: key: GTK is set\n"); + priv->wpa_is_gtk_set = true; + priv->scan_block = false; + } + } + + memset(priv->aes_key.key_param_set.key, 0, + sizeof(key->key_param_set.key)); + priv->aes_key.key_param_set.key_len = key->key_param_set.key_len; + memcpy(priv->aes_key.key_param_set.key, key->key_param_set.key, + le16_to_cpu(priv->aes_key.key_param_set.key_len)); + + return 0; +} + +/* + * This function handles the command response of get 11d domain information. + */ +static int mwifiex_ret_802_11d_domain_info(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + struct host_cmd_ds_802_11d_domain_info_rsp *domain_info = + &resp->params.domain_info_resp; + struct mwifiex_ietypes_domain_param_set *domain = &domain_info->domain; + u16 action = le16_to_cpu(domain_info->action); + u8 no_of_triplet = 0; + + no_of_triplet = (u8) ((le16_to_cpu(domain->header.len) - + IEEE80211_COUNTRY_STRING_LEN) / + sizeof(struct ieee80211_country_ie_triplet)); + + dev_dbg(priv->adapter->dev, "info: 11D Domain Info Resp:" + " no_of_triplet=%d\n", no_of_triplet); + + if (no_of_triplet > MWIFIEX_MAX_TRIPLET_802_11D) { + dev_warn(priv->adapter->dev, + "11D: invalid number of triplets %d " + "returned!!\n", no_of_triplet); + return -1; + } + + switch (action) { + case HostCmd_ACT_GEN_SET: /* Proc Set Action */ + break; + case HostCmd_ACT_GEN_GET: + break; + default: + dev_err(priv->adapter->dev, + "11D: invalid action:%d\n", domain_info->action); + return -1; + } + + return 0; +} + +/* + * This function handles the command response of get RF channel. + * + * Handling includes changing the header fields into CPU format + * and saving the new channel in driver. + */ +static int mwifiex_ret_802_11_rf_channel(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *data_buf) +{ + struct host_cmd_ds_802_11_rf_channel *rf_channel = + &resp->params.rf_channel; + u16 new_channel = le16_to_cpu(rf_channel->current_channel); + + if (priv->curr_bss_params.bss_descriptor.channel != new_channel) { + dev_dbg(priv->adapter->dev, "cmd: Channel Switch: %d to %d\n", + priv->curr_bss_params.bss_descriptor.channel, + new_channel); + /* Update the channel again */ + priv->curr_bss_params.bss_descriptor.channel = new_channel; + } + if (data_buf) + *((u16 *)data_buf) = new_channel; + + return 0; +} + +/* + * This function handles the command response of get extended version. + * + * Handling includes forming the extended version string and sending it + * to application. + */ +static int mwifiex_ret_ver_ext(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *data_buf) +{ + struct host_cmd_ds_version_ext *ver_ext = &resp->params.verext; + struct host_cmd_ds_version_ext *version_ext = NULL; + + if (data_buf) { + version_ext = (struct host_cmd_ds_version_ext *)data_buf; + version_ext->version_str_sel = ver_ext->version_str_sel; + memcpy(version_ext->version_str, ver_ext->version_str, + sizeof(char) * 128); + memcpy(priv->version_str, ver_ext->version_str, 128); + } + return 0; +} + +/* + * This function handles the command response of register access. + * + * The register value and offset are returned to the user. For EEPROM + * access, the byte count is also returned. + */ +static int mwifiex_ret_reg_access(u16 type, struct host_cmd_ds_command *resp, + void *data_buf) +{ + struct mwifiex_ds_reg_rw *reg_rw = NULL; + struct mwifiex_ds_read_eeprom *eeprom = NULL; + + if (data_buf) { + reg_rw = (struct mwifiex_ds_reg_rw *) data_buf; + eeprom = (struct mwifiex_ds_read_eeprom *) data_buf; + switch (type) { + case HostCmd_CMD_MAC_REG_ACCESS: + { + struct host_cmd_ds_mac_reg_access *reg; + reg = (struct host_cmd_ds_mac_reg_access *) + &resp->params.mac_reg; + reg_rw->offset = cpu_to_le32( + (u32) le16_to_cpu(reg->offset)); + reg_rw->value = reg->value; + break; + } + case HostCmd_CMD_BBP_REG_ACCESS: + { + struct host_cmd_ds_bbp_reg_access *reg; + reg = (struct host_cmd_ds_bbp_reg_access *) + &resp->params.bbp_reg; + reg_rw->offset = cpu_to_le32( + (u32) le16_to_cpu(reg->offset)); + reg_rw->value = cpu_to_le32((u32) reg->value); + break; + } + + case HostCmd_CMD_RF_REG_ACCESS: + { + struct host_cmd_ds_rf_reg_access *reg; + reg = (struct host_cmd_ds_rf_reg_access *) + &resp->params.rf_reg; + reg_rw->offset = cpu_to_le32( + (u32) le16_to_cpu(reg->offset)); + reg_rw->value = cpu_to_le32((u32) reg->value); + break; + } + case HostCmd_CMD_PMIC_REG_ACCESS: + { + struct host_cmd_ds_pmic_reg_access *reg; + reg = (struct host_cmd_ds_pmic_reg_access *) + &resp->params.pmic_reg; + reg_rw->offset = cpu_to_le32( + (u32) le16_to_cpu(reg->offset)); + reg_rw->value = cpu_to_le32((u32) reg->value); + break; + } + case HostCmd_CMD_CAU_REG_ACCESS: + { + struct host_cmd_ds_rf_reg_access *reg; + reg = (struct host_cmd_ds_rf_reg_access *) + &resp->params.rf_reg; + reg_rw->offset = cpu_to_le32( + (u32) le16_to_cpu(reg->offset)); + reg_rw->value = cpu_to_le32((u32) reg->value); + break; + } + case HostCmd_CMD_802_11_EEPROM_ACCESS: + { + struct host_cmd_ds_802_11_eeprom_access + *cmd_eeprom = + (struct host_cmd_ds_802_11_eeprom_access + *) &resp->params.eeprom; + pr_debug("info: EEPROM read len=%x\n", + cmd_eeprom->byte_count); + if (le16_to_cpu(eeprom->byte_count) < + le16_to_cpu( + cmd_eeprom->byte_count)) { + eeprom->byte_count = cpu_to_le16(0); + pr_debug("info: EEPROM read " + "length is too big\n"); + return -1; + } + eeprom->offset = cmd_eeprom->offset; + eeprom->byte_count = cmd_eeprom->byte_count; + if (le16_to_cpu(eeprom->byte_count) > 0) + memcpy(&eeprom->value, + &cmd_eeprom->value, + le16_to_cpu(eeprom->byte_count)); + + break; + } + default: + return -1; + } + } + return 0; +} + +/* + * This function handles the command response of get IBSS coalescing status. + * + * If the received BSSID is different than the current one, the current BSSID, + * beacon interval, ATIM window and ERP information are updated, along with + * changing the ad-hoc state accordingly. + */ +static int mwifiex_ret_ibss_coalescing_status(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + struct host_cmd_ds_802_11_ibss_status *ibss_coal_resp = + &(resp->params.ibss_coalescing); + u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; + + if (le16_to_cpu(ibss_coal_resp->action) == HostCmd_ACT_GEN_SET) + return 0; + + dev_dbg(priv->adapter->dev, + "info: new BSSID %pM\n", ibss_coal_resp->bssid); + + /* If rsp has NULL BSSID, Just return..... No Action */ + if (!memcmp(ibss_coal_resp->bssid, zero_mac, ETH_ALEN)) { + dev_warn(priv->adapter->dev, "new BSSID is NULL\n"); + return 0; + } + + /* If BSSID is diff, modify current BSS parameters */ + if (memcmp(priv->curr_bss_params.bss_descriptor.mac_address, + ibss_coal_resp->bssid, ETH_ALEN)) { + /* BSSID */ + memcpy(priv->curr_bss_params.bss_descriptor.mac_address, + ibss_coal_resp->bssid, ETH_ALEN); + + /* Beacon Interval */ + priv->curr_bss_params.bss_descriptor.beacon_period + = le16_to_cpu(ibss_coal_resp->beacon_interval); + + /* ERP Information */ + priv->curr_bss_params.bss_descriptor.erp_flags = + (u8) le16_to_cpu(ibss_coal_resp->use_g_rate_protect); + + priv->adhoc_state = ADHOC_COALESCED; + } + + return 0; +} + +/* + * This function handles the command responses. + * + * This is a generic function, which calls command specific + * response handlers based on the command ID. + */ +int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, + u16 cmdresp_no, void *cmd_buf, void *wq_buf) +{ + int ret = 0; + struct mwifiex_adapter *adapter = priv->adapter; + struct host_cmd_ds_command *resp = + (struct host_cmd_ds_command *) cmd_buf; + struct mwifiex_wait_queue *wait_queue = + (struct mwifiex_wait_queue *) wq_buf; + void *data_buf = adapter->curr_cmd->data_buf; + + /* If the command is not successful, cleanup and return failure */ + if (resp->result != HostCmd_RESULT_OK) { + mwifiex_process_cmdresp_error(priv, resp, wait_queue); + return -1; + } + /* Command successful, handle response */ + switch (cmdresp_no) { + case HostCmd_CMD_GET_HW_SPEC: + ret = mwifiex_ret_get_hw_spec(priv, resp); + break; + case HostCmd_CMD_MAC_CONTROL: + break; + case HostCmd_CMD_802_11_MAC_ADDRESS: + ret = mwifiex_ret_802_11_mac_address(priv, resp); + break; + case HostCmd_CMD_MAC_MULTICAST_ADR: + ret = mwifiex_ret_mac_multicast_adr(priv, resp); + break; + case HostCmd_CMD_TX_RATE_CFG: + ret = mwifiex_ret_tx_rate_cfg(priv, resp, data_buf); + break; + case HostCmd_CMD_802_11_SCAN: + ret = mwifiex_ret_802_11_scan(priv, resp, wait_queue); + wait_queue = NULL; + adapter->curr_cmd->wq_buf = NULL; + break; + case HostCmd_CMD_802_11_BG_SCAN_QUERY: + ret = mwifiex_ret_802_11_scan(priv, resp, wait_queue); + dev_dbg(adapter->dev, + "info: CMD_RESP: BG_SCAN result is ready!\n"); + break; + case HostCmd_CMD_TXPWR_CFG: + ret = mwifiex_ret_tx_power_cfg(priv, resp, data_buf); + break; + case HostCmd_CMD_802_11_PS_MODE_ENH: + ret = mwifiex_ret_enh_power_mode(priv, resp, data_buf); + break; + case HostCmd_CMD_802_11_HS_CFG_ENH: + ret = mwifiex_ret_802_11_hs_cfg(priv, resp); + break; + case HostCmd_CMD_802_11_ASSOCIATE: + ret = mwifiex_ret_802_11_associate(priv, resp, wait_queue); + break; + case HostCmd_CMD_802_11_DEAUTHENTICATE: + ret = mwifiex_ret_802_11_deauthenticate(priv, resp); + break; + case HostCmd_CMD_802_11_AD_HOC_START: + case HostCmd_CMD_802_11_AD_HOC_JOIN: + ret = mwifiex_ret_802_11_ad_hoc(priv, resp, wait_queue); + break; + case HostCmd_CMD_802_11_AD_HOC_STOP: + ret = mwifiex_ret_802_11_ad_hoc_stop(priv, resp); + break; + case HostCmd_CMD_802_11_GET_LOG: + ret = mwifiex_ret_get_log(priv, resp, data_buf); + break; + case HostCmd_CMD_RSSI_INFO: + ret = mwifiex_ret_802_11_rssi_info(priv, resp, data_buf); + break; + case HostCmd_CMD_802_11_SNMP_MIB: + ret = mwifiex_ret_802_11_snmp_mib(priv, resp, data_buf); + break; + case HostCmd_CMD_802_11_TX_RATE_QUERY: + ret = mwifiex_ret_802_11_tx_rate_query(priv, resp); + break; + case HostCmd_CMD_802_11_RF_CHANNEL: + ret = mwifiex_ret_802_11_rf_channel(priv, resp, data_buf); + break; + case HostCmd_CMD_VERSION_EXT: + ret = mwifiex_ret_ver_ext(priv, resp, data_buf); + break; + case HostCmd_CMD_FUNC_INIT: + case HostCmd_CMD_FUNC_SHUTDOWN: + break; + case HostCmd_CMD_802_11_KEY_MATERIAL: + ret = mwifiex_ret_802_11_key_material(priv, resp); + break; + case HostCmd_CMD_802_11D_DOMAIN_INFO: + ret = mwifiex_ret_802_11d_domain_info(priv, resp); + break; + case HostCmd_CMD_11N_ADDBA_REQ: + ret = mwifiex_ret_11n_addba_req(priv, resp); + break; + case HostCmd_CMD_11N_DELBA: + ret = mwifiex_ret_11n_delba(priv, resp); + break; + case HostCmd_CMD_11N_ADDBA_RSP: + ret = mwifiex_ret_11n_addba_resp(priv, resp); + break; + case HostCmd_CMD_RECONFIGURE_TX_BUFF: + adapter->tx_buf_size = (u16) le16_to_cpu(resp->params. + tx_buf.buff_size); + adapter->tx_buf_size = (adapter->tx_buf_size / + MWIFIEX_SDIO_BLOCK_SIZE) * + MWIFIEX_SDIO_BLOCK_SIZE; + adapter->curr_tx_buf_size = adapter->tx_buf_size; + dev_dbg(adapter->dev, + "cmd: max_tx_buf_size=%d, tx_buf_size=%d\n", + adapter->max_tx_buf_size, adapter->tx_buf_size); + + if (adapter->if_ops.update_mp_end_port) + adapter->if_ops.update_mp_end_port(adapter, + le16_to_cpu(resp-> + params. + tx_buf. + mp_end_port)); + break; + case HostCmd_CMD_AMSDU_AGGR_CTRL: + ret = mwifiex_ret_amsdu_aggr_ctrl(priv, resp, data_buf); + break; + case HostCmd_CMD_WMM_GET_STATUS: + ret = mwifiex_ret_wmm_get_status(priv, resp); + break; + case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS: + ret = mwifiex_ret_ibss_coalescing_status(priv, resp); + break; + case HostCmd_CMD_MAC_REG_ACCESS: + case HostCmd_CMD_BBP_REG_ACCESS: + case HostCmd_CMD_RF_REG_ACCESS: + case HostCmd_CMD_PMIC_REG_ACCESS: + case HostCmd_CMD_CAU_REG_ACCESS: + case HostCmd_CMD_802_11_EEPROM_ACCESS: + ret = mwifiex_ret_reg_access(cmdresp_no, resp, data_buf); + break; + case HostCmd_CMD_SET_BSS_MODE: + break; + case HostCmd_CMD_11N_CFG: + ret = mwifiex_ret_11n_cfg(priv, resp, data_buf); + break; + default: + dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n", + resp->command); + break; + } + + return ret; +} diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c new file mode 100644 index 000000000000..936d7c175e75 --- /dev/null +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -0,0 +1,405 @@ +/* + * Marvell Wireless LAN device driver: station event handling + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" + +/* + * This function resets the connection state. + * + * The function is invoked after receiving a disconnect event from firmware, + * and performs the following actions - + * - Set media status to disconnected + * - Clean up Tx and Rx packets + * - Resets SNR/NF/RSSI value in driver + * - Resets security configurations in driver + * - Enables auto data rate + * - Saves the previous SSID and BSSID so that they can + * be used for re-association, if required + * - Erases current SSID and BSSID information + * - Sends a disconnect event to upper layers/applications. + */ +void +mwifiex_reset_connect_state(struct mwifiex_private *priv) +{ + struct mwifiex_adapter *adapter = priv->adapter; + + if (!priv->media_connected) + return; + + dev_dbg(adapter->dev, "info: handles disconnect event\n"); + + priv->media_connected = false; + + priv->scan_block = false; + + /* Free Tx and Rx packets, report disconnect to upper layer */ + mwifiex_clean_txrx(priv); + + /* Reset SNR/NF/RSSI values */ + priv->data_rssi_last = 0; + priv->data_nf_last = 0; + priv->data_rssi_avg = 0; + priv->data_nf_avg = 0; + priv->bcn_rssi_last = 0; + priv->bcn_nf_last = 0; + priv->bcn_rssi_avg = 0; + priv->bcn_nf_avg = 0; + priv->rxpd_rate = 0; + priv->rxpd_htinfo = 0; + priv->sec_info.wpa_enabled = false; + priv->sec_info.wpa2_enabled = false; + priv->wpa_ie_len = 0; + + priv->sec_info.wapi_enabled = false; + priv->wapi_ie_len = 0; + priv->sec_info.wapi_key_on = false; + + priv->sec_info.encryption_mode = 0; + + /* Enable auto data rate */ + priv->is_data_rate_auto = true; + priv->data_rate = 0; + + if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { + priv->adhoc_state = ADHOC_IDLE; + priv->adhoc_is_link_sensed = false; + } + + /* + * Memorize the previous SSID and BSSID so + * it could be used for re-assoc + */ + + dev_dbg(adapter->dev, "info: previous SSID=%s, SSID len=%u\n", + priv->prev_ssid.ssid, priv->prev_ssid.ssid_len); + + dev_dbg(adapter->dev, "info: current SSID=%s, SSID len=%u\n", + priv->curr_bss_params.bss_descriptor.ssid.ssid, + priv->curr_bss_params.bss_descriptor.ssid.ssid_len); + + memcpy(&priv->prev_ssid, + &priv->curr_bss_params.bss_descriptor.ssid, + sizeof(struct mwifiex_802_11_ssid)); + + memcpy(priv->prev_bssid, + priv->curr_bss_params.bss_descriptor.mac_address, ETH_ALEN); + + /* Need to erase the current SSID and BSSID info */ + memset(&priv->curr_bss_params, 0x00, sizeof(priv->curr_bss_params)); + + adapter->tx_lock_flag = false; + adapter->pps_uapsd_mode = false; + + if (adapter->num_cmd_timeout && adapter->curr_cmd) + return; + priv->media_connected = false; + if (!priv->disconnect) { + priv->disconnect = 1; + dev_dbg(adapter->dev, "info: successfully disconnected from" + " %pM: reason code %d\n", priv->cfg_bssid, + WLAN_REASON_DEAUTH_LEAVING); + cfg80211_disconnected(priv->netdev, + WLAN_REASON_DEAUTH_LEAVING, NULL, 0, + GFP_KERNEL); + queue_work(priv->workqueue, &priv->cfg_workqueue); + } + if (!netif_queue_stopped(priv->netdev)) + netif_stop_queue(priv->netdev); + if (netif_carrier_ok(priv->netdev)) + netif_carrier_off(priv->netdev); + /* Reset wireless stats signal info */ + priv->w_stats.qual.level = 0; + priv->w_stats.qual.noise = 0; +} + +/* + * This function handles events generated by firmware. + * + * This is a generic function and handles all events. + * + * Event specific routines are called by this function based + * upon the generated event cause. + * + * For the following events, the function just forwards them to upper + * layers, optionally recording the change - + * - EVENT_LINK_SENSED + * - EVENT_MIC_ERR_UNICAST + * - EVENT_MIC_ERR_MULTICAST + * - EVENT_PORT_RELEASE + * - EVENT_RSSI_LOW + * - EVENT_SNR_LOW + * - EVENT_MAX_FAIL + * - EVENT_RSSI_HIGH + * - EVENT_SNR_HIGH + * - EVENT_DATA_RSSI_LOW + * - EVENT_DATA_SNR_LOW + * - EVENT_DATA_RSSI_HIGH + * - EVENT_DATA_SNR_HIGH + * - EVENT_LINK_QUALITY + * - EVENT_PRE_BEACON_LOST + * - EVENT_IBSS_COALESCED + * - EVENT_WEP_ICV_ERR + * - EVENT_BW_CHANGE + * - EVENT_HOSTWAKE_STAIE + * + * For the following events, no action is taken - + * - EVENT_MIB_CHANGED + * - EVENT_INIT_DONE + * - EVENT_DUMMY_HOST_WAKEUP_SIGNAL + * + * Rest of the supported events requires driver handling - + * - EVENT_DEAUTHENTICATED + * - EVENT_DISASSOCIATED + * - EVENT_LINK_LOST + * - EVENT_PS_SLEEP + * - EVENT_PS_AWAKE + * - EVENT_DEEP_SLEEP_AWAKE + * - EVENT_HS_ACT_REQ + * - EVENT_ADHOC_BCN_LOST + * - EVENT_BG_SCAN_REPORT + * - EVENT_WMM_STATUS_CHANGE + * - EVENT_ADDBA + * - EVENT_DELBA + * - EVENT_BA_STREAM_TIEMOUT + * - EVENT_AMSDU_AGGR_CTRL + */ +int mwifiex_process_sta_event(struct mwifiex_private *priv) +{ + struct mwifiex_adapter *adapter = priv->adapter; + int ret = 0; + u32 eventcause = adapter->event_cause; + + switch (eventcause) { + case EVENT_DUMMY_HOST_WAKEUP_SIGNAL: + dev_err(adapter->dev, "invalid EVENT: DUMMY_HOST_WAKEUP_SIGNAL," + " ignoring it\n"); + break; + case EVENT_LINK_SENSED: + dev_dbg(adapter->dev, "event: LINK_SENSED\n"); + if (!netif_carrier_ok(priv->netdev)) + netif_carrier_on(priv->netdev); + if (netif_queue_stopped(priv->netdev)) + netif_wake_queue(priv->netdev); + break; + + case EVENT_DEAUTHENTICATED: + dev_dbg(adapter->dev, "event: Deauthenticated\n"); + adapter->dbg.num_event_deauth++; + if (priv->media_connected) + mwifiex_reset_connect_state(priv); + break; + + case EVENT_DISASSOCIATED: + dev_dbg(adapter->dev, "event: Disassociated\n"); + adapter->dbg.num_event_disassoc++; + if (priv->media_connected) + mwifiex_reset_connect_state(priv); + break; + + case EVENT_LINK_LOST: + dev_dbg(adapter->dev, "event: Link lost\n"); + adapter->dbg.num_event_link_lost++; + if (priv->media_connected) + mwifiex_reset_connect_state(priv); + break; + + case EVENT_PS_SLEEP: + dev_dbg(adapter->dev, "info: EVENT: SLEEP\n"); + + adapter->ps_state = PS_STATE_PRE_SLEEP; + + mwifiex_check_ps_cond(adapter); + break; + + case EVENT_PS_AWAKE: + dev_dbg(adapter->dev, "info: EVENT: AWAKE\n"); + if (!adapter->pps_uapsd_mode && + priv->media_connected && + adapter->sleep_period.period) { + adapter->pps_uapsd_mode = true; + dev_dbg(adapter->dev, + "event: PPS/UAPSD mode activated\n"); + } + adapter->tx_lock_flag = false; + if (adapter->pps_uapsd_mode && adapter->gen_null_pkt) { + if (mwifiex_check_last_packet_indication(priv)) { + if (!adapter->data_sent) { + if (!mwifiex_send_null_packet(priv, + MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET + | + MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET)) + adapter->ps_state = + PS_STATE_SLEEP; + return 0; + } + } + } + adapter->ps_state = PS_STATE_AWAKE; + adapter->pm_wakeup_card_req = false; + adapter->pm_wakeup_fw_try = false; + + break; + + case EVENT_DEEP_SLEEP_AWAKE: + adapter->if_ops.wakeup_complete(adapter); + dev_dbg(adapter->dev, "event: DS_AWAKE\n"); + if (adapter->is_deep_sleep) + adapter->is_deep_sleep = false; + break; + + case EVENT_HS_ACT_REQ: + dev_dbg(adapter->dev, "event: HS_ACT_REQ\n"); + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_HS_CFG_ENH, + 0, 0, NULL, NULL); + break; + + case EVENT_MIC_ERR_UNICAST: + dev_dbg(adapter->dev, "event: UNICAST MIC ERROR\n"); + break; + + case EVENT_MIC_ERR_MULTICAST: + dev_dbg(adapter->dev, "event: MULTICAST MIC ERROR\n"); + break; + case EVENT_MIB_CHANGED: + case EVENT_INIT_DONE: + break; + + case EVENT_ADHOC_BCN_LOST: + dev_dbg(adapter->dev, "event: ADHOC_BCN_LOST\n"); + priv->adhoc_is_link_sensed = false; + mwifiex_clean_txrx(priv); + if (!netif_queue_stopped(priv->netdev)) + netif_stop_queue(priv->netdev); + if (netif_carrier_ok(priv->netdev)) + netif_carrier_off(priv->netdev); + break; + + case EVENT_BG_SCAN_REPORT: + dev_dbg(adapter->dev, "event: BGS_REPORT\n"); + /* Clear the previous scan result */ + memset(adapter->scan_table, 0x00, + sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP); + adapter->num_in_scan_table = 0; + adapter->bcn_buf_end = adapter->bcn_buf; + ret = mwifiex_prepare_cmd(priv, + HostCmd_CMD_802_11_BG_SCAN_QUERY, + HostCmd_ACT_GEN_GET, 0, NULL, NULL); + break; + + case EVENT_PORT_RELEASE: + dev_dbg(adapter->dev, "event: PORT RELEASE\n"); + break; + + case EVENT_WMM_STATUS_CHANGE: + dev_dbg(adapter->dev, "event: WMM status changed\n"); + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_WMM_GET_STATUS, + 0, 0, NULL, NULL); + break; + + case EVENT_RSSI_LOW: + dev_dbg(adapter->dev, "event: Beacon RSSI_LOW\n"); + break; + case EVENT_SNR_LOW: + dev_dbg(adapter->dev, "event: Beacon SNR_LOW\n"); + break; + case EVENT_MAX_FAIL: + dev_dbg(adapter->dev, "event: MAX_FAIL\n"); + break; + case EVENT_RSSI_HIGH: + dev_dbg(adapter->dev, "event: Beacon RSSI_HIGH\n"); + break; + case EVENT_SNR_HIGH: + dev_dbg(adapter->dev, "event: Beacon SNR_HIGH\n"); + break; + case EVENT_DATA_RSSI_LOW: + dev_dbg(adapter->dev, "event: Data RSSI_LOW\n"); + break; + case EVENT_DATA_SNR_LOW: + dev_dbg(adapter->dev, "event: Data SNR_LOW\n"); + break; + case EVENT_DATA_RSSI_HIGH: + dev_dbg(adapter->dev, "event: Data RSSI_HIGH\n"); + break; + case EVENT_DATA_SNR_HIGH: + dev_dbg(adapter->dev, "event: Data SNR_HIGH\n"); + break; + case EVENT_LINK_QUALITY: + dev_dbg(adapter->dev, "event: Link Quality\n"); + break; + case EVENT_PRE_BEACON_LOST: + dev_dbg(adapter->dev, "event: Pre-Beacon Lost\n"); + break; + case EVENT_IBSS_COALESCED: + dev_dbg(adapter->dev, "event: IBSS_COALESCED\n"); + ret = mwifiex_prepare_cmd(priv, + HostCmd_CMD_802_11_IBSS_COALESCING_STATUS, + HostCmd_ACT_GEN_GET, 0, NULL, NULL); + break; + case EVENT_ADDBA: + dev_dbg(adapter->dev, "event: ADDBA Request\n"); + mwifiex_prepare_cmd(priv, HostCmd_CMD_11N_ADDBA_RSP, + HostCmd_ACT_GEN_SET, 0, NULL, + adapter->event_body); + break; + case EVENT_DELBA: + dev_dbg(adapter->dev, "event: DELBA Request\n"); + mwifiex_11n_delete_ba_stream(priv, adapter->event_body); + break; + case EVENT_BA_STREAM_TIEMOUT: + dev_dbg(adapter->dev, "event: BA Stream timeout\n"); + mwifiex_11n_ba_stream_timeout(priv, + (struct host_cmd_ds_11n_batimeout + *) + adapter->event_body); + break; + case EVENT_AMSDU_AGGR_CTRL: + dev_dbg(adapter->dev, "event: AMSDU_AGGR_CTRL %d\n", + *(u16 *) adapter->event_body); + adapter->tx_buf_size = + min(adapter->curr_tx_buf_size, + le16_to_cpu(*(__le16 *) adapter->event_body)); + dev_dbg(adapter->dev, "event: tx_buf_size %d\n", + adapter->tx_buf_size); + break; + + case EVENT_WEP_ICV_ERR: + dev_dbg(adapter->dev, "event: WEP ICV error\n"); + break; + + case EVENT_BW_CHANGE: + dev_dbg(adapter->dev, "event: BW Change\n"); + break; + + case EVENT_HOSTWAKE_STAIE: + dev_dbg(adapter->dev, "event: HOSTWAKE_STAIE %d\n", eventcause); + break; + default: + dev_dbg(adapter->dev, "event: unknown event id: %#x\n", + eventcause); + break; + } + + return ret; +} diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c new file mode 100644 index 000000000000..b163507b1fe0 --- /dev/null +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -0,0 +1,2360 @@ +/* + * Marvell Wireless LAN device driver: functions for station ioctl + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" +#include "cfg80211.h" + +/* + * Copies the multicast address list from device to driver. + * + * This function does not validate the destination memory for + * size, and the calling function must ensure enough memory is + * available. + */ +static int +mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist, + struct net_device *dev) +{ + int i = 0; + struct netdev_hw_addr *ha; + + netdev_for_each_mc_addr(ha, dev) + memcpy(&mlist->mac_list[i++], ha->addr, ETH_ALEN); + + return i; +} + +/* + * Allocate and fills a wait queue with proper parameters. + * + * This function needs to be called before an IOCTL request can be made. + * It can handle the following wait options: + * MWIFIEX_NO_WAIT - Waiting is disabled + * MWIFIEX_IOCTL_WAIT - Waiting is done on IOCTL wait queue + * MWIFIEX_CMD_WAIT - Waiting is done on command wait queue + * MWIFIEX_WSTATS_WAIT - Waiting is done on stats wait queue + */ +struct mwifiex_wait_queue * +mwifiex_alloc_fill_wait_queue(struct mwifiex_private *priv, + u8 wait_option) +{ + struct mwifiex_wait_queue *wait = NULL; + + wait = (struct mwifiex_wait_queue *) + kzalloc(sizeof(struct mwifiex_wait_queue), GFP_ATOMIC); + if (!wait) { + dev_err(priv->adapter->dev, "%s: fail to alloc buffer\n", + __func__); + return wait; + } + + wait->bss_index = priv->bss_index; + + switch (wait_option) { + case MWIFIEX_NO_WAIT: + wait->enabled = 0; + break; + case MWIFIEX_IOCTL_WAIT: + priv->ioctl_wait_q_woken = false; + wait->start_time = jiffies; + wait->wait = &priv->ioctl_wait_q; + wait->condition = &priv->ioctl_wait_q_woken; + wait->enabled = 1; + break; + case MWIFIEX_CMD_WAIT: + priv->cmd_wait_q_woken = false; + wait->start_time = jiffies; + wait->wait = &priv->cmd_wait_q; + wait->condition = &priv->cmd_wait_q_woken; + wait->enabled = 1; + break; + case MWIFIEX_WSTATS_WAIT: + priv->w_stats_wait_q_woken = false; + wait->start_time = jiffies; + wait->wait = &priv->w_stats_wait_q; + wait->condition = &priv->w_stats_wait_q_woken; + wait->enabled = 1; + break; + } + + return wait; +} + +/* + * Wait queue completion handler. + * + * This function waits on a particular wait queue. + * For NO_WAIT option, it returns immediately. It also cancels the + * pending IOCTL request after waking up, in case of errors. + */ +static void +mwifiex_wait_ioctl_complete(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + u8 wait_option) +{ + bool cancel_flag = false; + + switch (wait_option) { + case MWIFIEX_NO_WAIT: + break; + case MWIFIEX_IOCTL_WAIT: + wait_event_interruptible(priv->ioctl_wait_q, + priv->ioctl_wait_q_woken); + if (!priv->ioctl_wait_q_woken) + cancel_flag = true; + break; + case MWIFIEX_CMD_WAIT: + wait_event_interruptible(priv->cmd_wait_q, + priv->cmd_wait_q_woken); + if (!priv->cmd_wait_q_woken) + cancel_flag = true; + break; + case MWIFIEX_WSTATS_WAIT: + wait_event_interruptible(priv->w_stats_wait_q, + priv->w_stats_wait_q_woken); + if (!priv->w_stats_wait_q_woken) + cancel_flag = true; + break; + } + if (cancel_flag) { + mwifiex_cancel_pending_ioctl(priv->adapter, wait); + dev_dbg(priv->adapter->dev, "cmd: IOCTL cancel: wait=%p, wait_option=%d\n", + wait, wait_option); + } + + return; +} + +/* + * The function waits for the request to complete and issues the + * completion handler, if required. + */ +int mwifiex_request_ioctl(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + int status, u8 wait_option) +{ + switch (status) { + case -EINPROGRESS: + dev_dbg(priv->adapter->dev, "cmd: IOCTL pending: wait=%p, wait_option=%d\n", + wait, wait_option); + atomic_inc(&priv->adapter->ioctl_pending); + /* Status pending, wake up main process */ + queue_work(priv->adapter->workqueue, &priv->adapter->main_work); + + /* Wait for completion */ + if (wait_option) { + mwifiex_wait_ioctl_complete(priv, wait, wait_option); + status = wait->status; + } + break; + case 0: + case -1: + case -EBUSY: + default: + break; + } + return status; +} +EXPORT_SYMBOL_GPL(mwifiex_request_ioctl); + +/* + * IOCTL request handler to set/get MAC address. + * + * This function prepares the correct firmware command and + * issues it to get the extended version information. + */ +static int mwifiex_bss_ioctl_mac_address(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + u8 action, u8 *mac) +{ + int ret = 0; + + if ((action == HostCmd_ACT_GEN_GET) && mac) { + memcpy(mac, priv->curr_addr, ETH_ALEN); + return 0; + } + + /* Send request to firmware */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_MAC_ADDRESS, + action, 0, wait, mac); + if (!ret) + ret = -EINPROGRESS; + + return ret; +} + +/* + * Sends IOCTL request to set MAC address. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int mwifiex_request_set_mac_address(struct mwifiex_private *priv) +{ + struct mwifiex_wait_queue *wait = NULL; + int status = 0; + u8 wait_option = MWIFIEX_CMD_WAIT; + + /* Allocate wait buffer */ + wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); + if (!wait) + return -ENOMEM; + + status = mwifiex_bss_ioctl_mac_address(priv, wait, HostCmd_ACT_GEN_SET, + NULL); + + status = mwifiex_request_ioctl(priv, wait, status, wait_option); + if (!status) + memcpy(priv->netdev->dev_addr, priv->curr_addr, ETH_ALEN); + else + dev_err(priv->adapter->dev, "set mac address failed: status=%d" + " error_code=%#x\n", status, wait->status); + + kfree(wait); + return status; +} + +/* + * IOCTL request handler to set multicast list. + * + * This function prepares the correct firmware command and + * issues it to set the multicast list. + * + * This function can be used to enable promiscuous mode, or enable all + * multicast packets, or to enable selective multicast. + */ +static int +mwifiex_bss_ioctl_multicast_list(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + u16 action, + struct mwifiex_multicast_list *mcast_list) +{ + int ret = 0; + u16 old_pkt_filter; + + old_pkt_filter = priv->curr_pkt_filter; + if (action == HostCmd_ACT_GEN_GET) + return -1; + + if (mcast_list->mode == MWIFIEX_PROMISC_MODE) { + dev_dbg(priv->adapter->dev, "info: Enable Promiscuous mode\n"); + priv->curr_pkt_filter |= HostCmd_ACT_MAC_PROMISCUOUS_ENABLE; + priv->curr_pkt_filter &= + ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE; + } else { + /* Multicast */ + priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_PROMISCUOUS_ENABLE; + if (mcast_list->mode == MWIFIEX_MULTICAST_MODE) { + dev_dbg(priv->adapter->dev, + "info: Enabling All Multicast!\n"); + priv->curr_pkt_filter |= + HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE; + } else { + priv->curr_pkt_filter &= + ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE; + if (mcast_list->num_multicast_addr) { + dev_dbg(priv->adapter->dev, + "info: Set multicast list=%d\n", + mcast_list->num_multicast_addr); + /* Set multicast addresses to firmware */ + if (old_pkt_filter == priv->curr_pkt_filter) { + /* Send request to firmware */ + ret = mwifiex_prepare_cmd(priv, + HostCmd_CMD_MAC_MULTICAST_ADR, + action, 0, wait, mcast_list); + if (!ret) + ret = -EINPROGRESS; + } else { + /* Send request to firmware */ + ret = mwifiex_prepare_cmd(priv, + HostCmd_CMD_MAC_MULTICAST_ADR, + action, 0, NULL, + mcast_list); + } + } + } + } + dev_dbg(priv->adapter->dev, + "info: old_pkt_filter=%#x, curr_pkt_filter=%#x\n", + old_pkt_filter, priv->curr_pkt_filter); + if (old_pkt_filter != priv->curr_pkt_filter) { + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_MAC_CONTROL, action, + 0, wait, &priv->curr_pkt_filter); + if (!ret) + ret = -EINPROGRESS; + } + + return ret; +} + +/* + * Sends IOCTL request to set multicast list. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +void +mwifiex_request_set_multicast_list(struct mwifiex_private *priv, + struct net_device *dev) +{ + struct mwifiex_wait_queue *wait = NULL; + struct mwifiex_multicast_list mcast_list; + u8 wait_option = MWIFIEX_NO_WAIT; + int status = 0; + + /* Allocate wait buffer */ + wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); + if (!wait) + return; + + if (dev->flags & IFF_PROMISC) { + mcast_list.mode = MWIFIEX_PROMISC_MODE; + } else if (dev->flags & IFF_ALLMULTI || + netdev_mc_count(dev) > MWIFIEX_MAX_MULTICAST_LIST_SIZE) { + mcast_list.mode = MWIFIEX_ALL_MULTI_MODE; + } else { + mcast_list.mode = MWIFIEX_MULTICAST_MODE; + if (netdev_mc_count(dev)) + mcast_list.num_multicast_addr = + mwifiex_copy_mcast_addr(&mcast_list, dev); + } + status = mwifiex_bss_ioctl_multicast_list(priv, wait, + HostCmd_ACT_GEN_SET, + &mcast_list); + + status = mwifiex_request_ioctl(priv, wait, status, wait_option); + if (wait && status != -EINPROGRESS) + kfree(wait); + + return; +} + +/* + * IOCTL request handler to disconnect from a BSS/IBSS. + */ +static int mwifiex_bss_ioctl_stop(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, u8 *mac) +{ + return mwifiex_deauthenticate(priv, wait, mac); +} + +/* + * Sends IOCTL request to disconnect from a BSS. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int mwifiex_disconnect(struct mwifiex_private *priv, u8 wait_option, u8 *mac) +{ + struct mwifiex_wait_queue *wait = NULL; + int status = 0; + + /* Allocate wait buffer */ + wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); + if (!wait) + return -ENOMEM; + + status = mwifiex_bss_ioctl_stop(priv, wait, mac); + + status = mwifiex_request_ioctl(priv, wait, status, wait_option); + + kfree(wait); + return status; +} +EXPORT_SYMBOL_GPL(mwifiex_disconnect); + +/* + * IOCTL request handler to join a BSS/IBSS. + * + * In Ad-Hoc mode, the IBSS is created if not found in scan list. + * In both Ad-Hoc and infra mode, an deauthentication is performed + * first. + */ +static int mwifiex_bss_ioctl_start(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + struct mwifiex_ssid_bssid *ssid_bssid) +{ + int ret = 0; + struct mwifiex_adapter *adapter = priv->adapter; + s32 i = -1; + + priv->scan_block = false; + if (!ssid_bssid) + return -1; + + if (priv->bss_mode == NL80211_IFTYPE_STATION) { + /* Infra mode */ + ret = mwifiex_deauthenticate(priv, NULL, NULL); + if (ret) + return ret; + + /* Search for the requested SSID in the scan table */ + if (ssid_bssid->ssid.ssid_len) + i = mwifiex_find_ssid_in_list(priv, &ssid_bssid->ssid, + NULL, NL80211_IFTYPE_STATION); + else + i = mwifiex_find_bssid_in_list(priv, + (u8 *) &ssid_bssid->bssid, + NL80211_IFTYPE_STATION); + if (i < 0) + return -1; + + dev_dbg(adapter->dev, + "info: SSID found in scan list ... associating...\n"); + + /* Clear any past association response stored for + * application retrieval */ + priv->assoc_rsp_size = 0; + ret = mwifiex_associate(priv, wait, &adapter->scan_table[i]); + if (ret) + return ret; + } else { + /* Adhoc mode */ + /* If the requested SSID matches current SSID, return */ + if (ssid_bssid->ssid.ssid_len && + (!mwifiex_ssid_cmp + (&priv->curr_bss_params.bss_descriptor.ssid, + &ssid_bssid->ssid))) + return 0; + + /* Exit Adhoc mode first */ + dev_dbg(adapter->dev, "info: Sending Adhoc Stop\n"); + ret = mwifiex_deauthenticate(priv, NULL, NULL); + if (ret) + return ret; + + priv->adhoc_is_link_sensed = false; + + /* Search for the requested network in the scan table */ + if (ssid_bssid->ssid.ssid_len) + i = mwifiex_find_ssid_in_list(priv, + &ssid_bssid->ssid, NULL, + NL80211_IFTYPE_ADHOC); + else + i = mwifiex_find_bssid_in_list(priv, + (u8 *)&ssid_bssid->bssid, + NL80211_IFTYPE_ADHOC); + + if (i >= 0) { + dev_dbg(adapter->dev, "info: network found in scan" + " list. Joining...\n"); + ret = mwifiex_adhoc_join(priv, wait, + &adapter->scan_table[i]); + if (ret) + return ret; + } else { /* i >= 0 */ + dev_dbg(adapter->dev, "info: Network not found in " + "the list, creating adhoc with ssid = %s\n", + ssid_bssid->ssid.ssid); + ret = mwifiex_adhoc_start(priv, wait, + &ssid_bssid->ssid); + if (ret) + return ret; + } + } + + if (!ret) + ret = -EINPROGRESS; + + return ret; +} + +/* + * Sends IOCTL request to connect with a BSS. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int mwifiex_bss_start(struct mwifiex_private *priv, u8 wait_option, + struct mwifiex_ssid_bssid *ssid_bssid) +{ + struct mwifiex_wait_queue *wait = NULL; + struct mwifiex_ssid_bssid tmp_ssid_bssid; + int status = 0; + + /* Stop the O.S. TX queue if needed */ + if (!netif_queue_stopped(priv->netdev)) + netif_stop_queue(priv->netdev); + + /* Allocate wait buffer */ + wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); + if (!wait) + return -ENOMEM; + + if (ssid_bssid) + memcpy(&tmp_ssid_bssid, ssid_bssid, + sizeof(struct mwifiex_ssid_bssid)); + status = mwifiex_bss_ioctl_start(priv, wait, &tmp_ssid_bssid); + + status = mwifiex_request_ioctl(priv, wait, status, wait_option); + + kfree(wait); + return status; +} + +/* + * IOCTL request handler to set host sleep configuration. + * + * This function prepares the correct firmware command and + * issues it. + */ +static int +mwifiex_pm_ioctl_hs_cfg(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + u16 action, struct mwifiex_ds_hs_cfg *hs_cfg) +{ + struct mwifiex_adapter *adapter = priv->adapter; + int status = 0; + u32 prev_cond = 0; + + switch (action) { + case HostCmd_ACT_GEN_SET: + if (adapter->pps_uapsd_mode) { + dev_dbg(adapter->dev, "info: Host Sleep IOCTL" + " is blocked in UAPSD/PPS mode\n"); + status = -1; + break; + } + if (hs_cfg->is_invoke_hostcmd) { + if (hs_cfg->conditions == HOST_SLEEP_CFG_CANCEL) { + if (!adapter->is_hs_configured) + /* Already cancelled */ + break; + /* Save previous condition */ + prev_cond = le32_to_cpu(adapter->hs_cfg + .conditions); + adapter->hs_cfg.conditions = + cpu_to_le32(hs_cfg->conditions); + } else if (hs_cfg->conditions) { + adapter->hs_cfg.conditions = + cpu_to_le32(hs_cfg->conditions); + adapter->hs_cfg.gpio = (u8)hs_cfg->gpio; + if (hs_cfg->gap) + adapter->hs_cfg.gap = (u8)hs_cfg->gap; + } else if (adapter->hs_cfg.conditions == + cpu_to_le32( + HOST_SLEEP_CFG_CANCEL)) { + /* Return failure if no parameters for HS + enable */ + status = -1; + break; + } + status = mwifiex_prepare_cmd(priv, + HostCmd_CMD_802_11_HS_CFG_ENH, + HostCmd_ACT_GEN_SET, + 0, wait, &adapter->hs_cfg); + if (!status) + status = -EINPROGRESS; + if (hs_cfg->conditions == HOST_SLEEP_CFG_CANCEL) + /* Restore previous condition */ + adapter->hs_cfg.conditions = + cpu_to_le32(prev_cond); + } else { + adapter->hs_cfg.conditions = + cpu_to_le32(hs_cfg->conditions); + adapter->hs_cfg.gpio = (u8)hs_cfg->gpio; + adapter->hs_cfg.gap = (u8)hs_cfg->gap; + } + break; + case HostCmd_ACT_GEN_GET: + hs_cfg->conditions = le32_to_cpu(adapter->hs_cfg.conditions); + hs_cfg->gpio = adapter->hs_cfg.gpio; + hs_cfg->gap = adapter->hs_cfg.gap; + break; + default: + status = -1; + break; + } + + return status; +} + +/* + * Sends IOCTL request to set Host Sleep parameters. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action, + u8 wait_option, + struct mwifiex_ds_hs_cfg *hscfg) +{ + int ret = 0; + struct mwifiex_wait_queue *wait = NULL; + + if (!hscfg) + return -ENOMEM; + + /* Allocate wait buffer */ + wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); + if (!wait) + return -ENOMEM; + + ret = mwifiex_pm_ioctl_hs_cfg(priv, wait, action, hscfg); + + ret = mwifiex_request_ioctl(priv, wait, ret, wait_option); + + if (wait && (ret != -EINPROGRESS)) + kfree(wait); + return ret; +} + +/* + * Sends IOCTL request to cancel the existing Host Sleep configuration. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int mwifiex_cancel_hs(struct mwifiex_private *priv, u8 wait_option) +{ + int ret = 0; + struct mwifiex_ds_hs_cfg hscfg; + + /* Cancel Host Sleep */ + hscfg.conditions = HOST_SLEEP_CFG_CANCEL; + hscfg.is_invoke_hostcmd = true; + ret = mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET, + wait_option, &hscfg); + + return ret; +} +EXPORT_SYMBOL_GPL(mwifiex_cancel_hs); + +/* + * Sends IOCTL request to cancel the existing Host Sleep configuration. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int mwifiex_enable_hs(struct mwifiex_adapter *adapter) +{ + struct mwifiex_ds_hs_cfg hscfg; + + if (adapter->hs_activated) { + dev_dbg(adapter->dev, "cmd: HS Already actived\n"); + return true; + } + + /* Enable Host Sleep */ + adapter->hs_activate_wait_q_woken = false; + + memset(&hscfg, 0, sizeof(struct mwifiex_hs_config_param)); + hscfg.is_invoke_hostcmd = true; + + if (mwifiex_set_hs_params(mwifiex_get_priv(adapter, + MWIFIEX_BSS_ROLE_STA), + HostCmd_ACT_GEN_SET, + MWIFIEX_IOCTL_WAIT, &hscfg)) { + dev_err(adapter->dev, "IOCTL request HS enable failed\n"); + return false; + } + + wait_event_interruptible(adapter->hs_activate_wait_q, + adapter->hs_activate_wait_q_woken); + + return true; +} +EXPORT_SYMBOL_GPL(mwifiex_enable_hs); + +/* + * IOCTL request handler to get signal information. + * + * This function prepares the correct firmware command and + * issues it to get the signal (RSSI) information. + * + * This only works in the connected mode. + */ +static int mwifiex_get_info_signal(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + struct mwifiex_ds_get_signal *signal) +{ + int ret = 0; + + if (!wait) { + dev_err(priv->adapter->dev, "WAIT information is not present\n"); + return -1; + } + + /* Signal info can be obtained only if connected */ + if (!priv->media_connected) { + dev_dbg(priv->adapter->dev, + "info: Can not get signal in disconnected state\n"); + return -1; + } + + /* Send request to firmware */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_RSSI_INFO, + HostCmd_ACT_GEN_GET, 0, wait, signal); + + if (!ret) + ret = -EINPROGRESS; + + return ret; +} + +/* + * IOCTL request handler to get statistics. + * + * This function prepares the correct firmware command and + * issues it to get the statistics (RSSI) information. + */ +static int mwifiex_get_info_stats(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + struct mwifiex_ds_get_stats *log) +{ + int ret = 0; + + if (!wait) { + dev_err(priv->adapter->dev, "MWIFIEX IOCTL information is not present\n"); + return -1; + } + + /* Send request to firmware */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_GET_LOG, + HostCmd_ACT_GEN_GET, 0, wait, log); + + if (!ret) + ret = -EINPROGRESS; + + return ret; +} + +/* + * IOCTL request handler to get BSS information. + * + * This function collates the information from different driver structures + * to send to the user. + */ +int mwifiex_get_bss_info(struct mwifiex_private *priv, + struct mwifiex_bss_info *info) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_bssdescriptor *bss_desc; + s32 tbl_idx = 0; + + if (!info) + return -1; + + /* Get current BSS info */ + bss_desc = &priv->curr_bss_params.bss_descriptor; + + /* BSS mode */ + info->bss_mode = priv->bss_mode; + + /* SSID */ + memcpy(&info->ssid, &bss_desc->ssid, + sizeof(struct mwifiex_802_11_ssid)); + + /* BSSID */ + memcpy(&info->bssid, &bss_desc->mac_address, ETH_ALEN); + + /* Channel */ + info->bss_chan = bss_desc->channel; + + /* Region code */ + info->region_code = adapter->region_code; + + /* Scan table index if connected */ + info->scan_table_idx = 0; + if (priv->media_connected) { + tbl_idx = + mwifiex_find_ssid_in_list(priv, &bss_desc->ssid, + bss_desc->mac_address, + priv->bss_mode); + if (tbl_idx >= 0) + info->scan_table_idx = tbl_idx; + } + + /* Connection status */ + info->media_connected = priv->media_connected; + + /* Tx power information */ + info->max_power_level = priv->max_tx_power_level; + info->min_power_level = priv->min_tx_power_level; + + /* AdHoc state */ + info->adhoc_state = priv->adhoc_state; + + /* Last beacon NF */ + info->bcn_nf_last = priv->bcn_nf_last; + + /* wep status */ + if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED) + info->wep_status = true; + else + info->wep_status = false; + + info->is_hs_configured = adapter->is_hs_configured; + info->is_deep_sleep = adapter->is_deep_sleep; + + return 0; +} + +/* + * IOCTL request handler to get extended version information. + * + * This function prepares the correct firmware command and + * issues it to get the extended version information. + */ +static int mwifiex_get_info_ver_ext(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + struct mwifiex_ver_ext *ver_ext) +{ + int ret = 0; + + /* Send request to firmware */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_VERSION_EXT, + HostCmd_ACT_GEN_GET, 0, wait, ver_ext); + if (!ret) + ret = -EINPROGRESS; + + return ret; +} + +/* + * IOCTL request handler to set/get SNMP MIB parameters. + * + * This function prepares the correct firmware command and + * issues it. + * + * Currently the following parameters are supported - + * Set/get RTS Threshold + * Set/get fragmentation threshold + * Set/get retry count + */ +int mwifiex_snmp_mib_ioctl(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + u32 cmd_oid, u16 action, u32 *value) +{ + int ret = 0; + + if (!value) + return -1; + + /* Send request to firmware */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, + action, cmd_oid, wait, value); + + if (!ret) + ret = -EINPROGRESS; + + return ret; +} + +/* + * IOCTL request handler to set/get band configurations. + * + * For SET operation, it performs extra checks to make sure the Ad-Hoc + * band and channel are compatible. Otherwise it returns an error. + * + * For GET operation, this function retrieves the following information - + * - Infra bands + * - Ad-hoc band + * - Ad-hoc channel + * - Secondary channel offset + */ +int mwifiex_radio_ioctl_band_cfg(struct mwifiex_private *priv, + u16 action, + struct mwifiex_ds_band_cfg *radio_cfg) +{ + struct mwifiex_adapter *adapter = priv->adapter; + u8 infra_band = 0; + u8 adhoc_band = 0; + u32 adhoc_channel = 0; + + if (action == HostCmd_ACT_GEN_GET) { + /* Infra Bands */ + radio_cfg->config_bands = adapter->config_bands; + /* Adhoc Band */ + radio_cfg->adhoc_start_band = adapter->adhoc_start_band; + /* Adhoc channel */ + radio_cfg->adhoc_channel = priv->adhoc_channel; + /* Secondary channel offset */ + radio_cfg->sec_chan_offset = adapter->chan_offset; + return 0; + } + + /* For action = SET */ + infra_band = (u8) radio_cfg->config_bands; + adhoc_band = (u8) radio_cfg->adhoc_start_band; + adhoc_channel = radio_cfg->adhoc_channel; + + /* SET Infra band */ + if ((infra_band | adapter->fw_bands) & ~adapter->fw_bands) + return -1; + + adapter->config_bands = infra_band; + + /* SET Ad-hoc Band */ + if ((adhoc_band | adapter->fw_bands) & ~adapter->fw_bands) + return -1; + + if (adhoc_band) + adapter->adhoc_start_band = adhoc_band; + adapter->chan_offset = (u8) radio_cfg->sec_chan_offset; + /* + * If no adhoc_channel is supplied verify if the existing adhoc + * channel compiles with new adhoc_band + */ + if (!adhoc_channel) { + if (!mwifiex_get_cfp_by_band_and_channel_from_cfg80211 + (priv, adapter->adhoc_start_band, + priv->adhoc_channel)) { + /* Pass back the default channel */ + radio_cfg->adhoc_channel = DEFAULT_AD_HOC_CHANNEL; + if ((adapter->adhoc_start_band & BAND_A) + || (adapter->adhoc_start_band & BAND_AN)) + radio_cfg->adhoc_channel = + DEFAULT_AD_HOC_CHANNEL_A; + } + } else { /* Retrurn error if adhoc_band and + adhoc_channel combination is invalid */ + if (!mwifiex_get_cfp_by_band_and_channel_from_cfg80211 + (priv, adapter->adhoc_start_band, (u16) adhoc_channel)) + return -1; + priv->adhoc_channel = (u8) adhoc_channel; + } + if ((adhoc_band & BAND_GN) || (adhoc_band & BAND_AN)) + adapter->adhoc_11n_enabled = true; + else + adapter->adhoc_11n_enabled = false; + + return 0; +} + +/* + * IOCTL request handler to set/get active channel. + * + * This function performs validity checking on channel/frequency + * compatibility and returns failure if not valid. + */ +int mwifiex_bss_ioctl_channel(struct mwifiex_private *priv, u16 action, + struct mwifiex_chan_freq_power *chan) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_chan_freq_power *cfp = NULL; + + if (!chan) + return -1; + + if (action == HostCmd_ACT_GEN_GET) { + cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211(priv, + priv->curr_bss_params.band, + (u16) priv->curr_bss_params.bss_descriptor. + channel); + chan->channel = cfp->channel; + chan->freq = cfp->freq; + + return 0; + } + if (!chan->channel && !chan->freq) + return -1; + if (adapter->adhoc_start_band & BAND_AN) + adapter->adhoc_start_band = BAND_G | BAND_B | BAND_GN; + else if (adapter->adhoc_start_band & BAND_A) + adapter->adhoc_start_band = BAND_G | BAND_B; + if (chan->channel) { + if (chan->channel <= MAX_CHANNEL_BAND_BG) + cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211 + (priv, 0, (u16) chan->channel); + if (!cfp) { + cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211 + (priv, BAND_A, (u16) chan->channel); + if (cfp) { + if (adapter->adhoc_11n_enabled) + adapter->adhoc_start_band = BAND_A + | BAND_AN; + else + adapter->adhoc_start_band = BAND_A; + } + } + } else { + if (chan->freq <= MAX_FREQUENCY_BAND_BG) + cfp = mwifiex_get_cfp_by_band_and_freq_from_cfg80211( + priv, 0, chan->freq); + if (!cfp) { + cfp = mwifiex_get_cfp_by_band_and_freq_from_cfg80211 + (priv, BAND_A, chan->freq); + if (cfp) { + if (adapter->adhoc_11n_enabled) + adapter->adhoc_start_band = BAND_A + | BAND_AN; + else + adapter->adhoc_start_band = BAND_A; + } + } + } + if (!cfp || !cfp->channel) { + dev_err(adapter->dev, "invalid channel/freq\n"); + return -1; + } + priv->adhoc_channel = (u8) cfp->channel; + chan->channel = cfp->channel; + chan->freq = cfp->freq; + + return 0; +} + +/* + * IOCTL request handler to set/get Ad-Hoc channel. + * + * This function prepares the correct firmware command and + * issues it to set or get the ad-hoc channel. + */ +static int mwifiex_bss_ioctl_ibss_channel(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + u16 action, u16 *channel) +{ + int ret = 0; + + if (action == HostCmd_ACT_GEN_GET) { + if (!priv->media_connected) { + *channel = priv->adhoc_channel; + return ret; + } + } else { + priv->adhoc_channel = (u8) *channel; + } + + /* Send request to firmware */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_RF_CHANNEL, + action, 0, wait, channel); + if (!ret) + ret = -EINPROGRESS; + + return ret; +} + +/* + * IOCTL request handler to find a particular BSS. + * + * The BSS can be searched with either a BSSID or a SSID. If none of + * these are provided, just the best BSS (best RSSI) is returned. + */ +int mwifiex_bss_ioctl_find_bss(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + struct mwifiex_ssid_bssid *ssid_bssid) +{ + struct mwifiex_adapter *adapter = priv->adapter; + int ret = 0; + struct mwifiex_bssdescriptor *bss_desc; + u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; + u8 mac[ETH_ALEN]; + int i = 0; + + if (memcmp(ssid_bssid->bssid, zero_mac, sizeof(zero_mac))) { + i = mwifiex_find_bssid_in_list(priv, + (u8 *) ssid_bssid->bssid, + priv->bss_mode); + if (i < 0) { + memcpy(mac, ssid_bssid->bssid, sizeof(mac)); + dev_err(adapter->dev, "cannot find bssid %pM\n", mac); + return -1; + } + bss_desc = &adapter->scan_table[i]; + memcpy(&ssid_bssid->ssid, &bss_desc->ssid, + sizeof(struct mwifiex_802_11_ssid)); + } else if (ssid_bssid->ssid.ssid_len) { + i = mwifiex_find_ssid_in_list(priv, &ssid_bssid->ssid, NULL, + priv->bss_mode); + if (i < 0) { + dev_err(adapter->dev, "cannot find ssid %s\n", + ssid_bssid->ssid.ssid); + return -1; + } + bss_desc = &adapter->scan_table[i]; + memcpy(ssid_bssid->bssid, bss_desc->mac_address, ETH_ALEN); + } else { + ret = mwifiex_find_best_network(priv, ssid_bssid); + } + + return ret; +} + +/* + * IOCTL request handler to change Ad-Hoc channel. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + * + * The function follows the following steps to perform the change - + * - Get current IBSS information + * - Get current channel + * - If no change is required, return + * - If not connected, change channel and return + * - If connected, + * - Disconnect + * - Change channel + * - Perform specific SSID scan with same SSID + * - Start/Join the IBSS + */ +int +mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel) +{ + int ret = 0; + int status = 0; + struct mwifiex_bss_info bss_info; + struct mwifiex_wait_queue *wait = NULL; + u8 wait_option = MWIFIEX_IOCTL_WAIT; + struct mwifiex_ssid_bssid ssid_bssid; + u16 curr_chan = 0; + + memset(&bss_info, 0, sizeof(bss_info)); + + /* Get BSS information */ + if (mwifiex_get_bss_info(priv, &bss_info)) + return -1; + + /* Allocate wait buffer */ + wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); + if (!wait) + return -ENOMEM; + + /* Get current channel */ + status = mwifiex_bss_ioctl_ibss_channel(priv, wait, HostCmd_ACT_GEN_GET, + &curr_chan); + + if (mwifiex_request_ioctl(priv, wait, status, wait_option)) { + ret = -1; + goto done; + } + if (curr_chan == channel) { + ret = 0; + goto done; + } + dev_dbg(priv->adapter->dev, "cmd: updating channel from %d to %d\n", + curr_chan, channel); + + if (!bss_info.media_connected) { + ret = 0; + goto done; + } + + /* Do disonnect */ + memset(&ssid_bssid, 0, ETH_ALEN); + status = mwifiex_bss_ioctl_stop(priv, wait, ssid_bssid.bssid); + + if (mwifiex_request_ioctl(priv, wait, status, wait_option)) { + ret = -1; + goto done; + } + + status = mwifiex_bss_ioctl_ibss_channel(priv, wait, HostCmd_ACT_GEN_SET, + (u16 *) &channel); + + if (mwifiex_request_ioctl(priv, wait, status, wait_option)) { + ret = -1; + goto done; + } + + /* Do specific SSID scanning */ + if (mwifiex_request_scan(priv, wait_option, &bss_info.ssid)) { + ret = -1; + goto done; + } + /* Start/Join Adhoc network */ + memset(&ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid)); + memcpy(&ssid_bssid.ssid, &bss_info.ssid, + sizeof(struct mwifiex_802_11_ssid)); + + status = mwifiex_bss_ioctl_start(priv, wait, &ssid_bssid); + + if (mwifiex_request_ioctl(priv, wait, status, wait_option)) + ret = -1; + +done: + kfree(wait); + return ret; +} + +/* + * IOCTL request handler to get rate. + * + * This function prepares the correct firmware command and + * issues it to get the current rate if it is connected, + * otherwise, the function returns the lowest supported rate + * for the band. + */ +static int mwifiex_rate_ioctl_get_rate_value(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + struct mwifiex_rate_cfg *rate_cfg) +{ + struct mwifiex_adapter *adapter = priv->adapter; + int ret = 0; + + rate_cfg->is_rate_auto = priv->is_data_rate_auto; + if (!priv->media_connected) { + switch (adapter->config_bands) { + case BAND_B: + /* Return the lowest supported rate for B band */ + rate_cfg->rate = supported_rates_b[0] & 0x7f; + break; + case BAND_G: + case BAND_G | BAND_GN: + /* Return the lowest supported rate for G band */ + rate_cfg->rate = supported_rates_g[0] & 0x7f; + break; + case BAND_B | BAND_G: + case BAND_A | BAND_B | BAND_G: + case BAND_A | BAND_B: + case BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN: + case BAND_B | BAND_G | BAND_GN: + /* Return the lowest supported rate for BG band */ + rate_cfg->rate = supported_rates_bg[0] & 0x7f; + break; + case BAND_A: + case BAND_A | BAND_G: + case BAND_A | BAND_G | BAND_AN | BAND_GN: + case BAND_A | BAND_AN: + /* Return the lowest supported rate for A band */ + rate_cfg->rate = supported_rates_a[0] & 0x7f; + break; + case BAND_GN: + /* Return the lowest supported rate for N band */ + rate_cfg->rate = supported_rates_n[0] & 0x7f; + break; + default: + dev_warn(adapter->dev, "invalid band %#x\n", + adapter->config_bands); + break; + } + } else { + /* Send request to firmware */ + ret = mwifiex_prepare_cmd(priv, + HostCmd_CMD_802_11_TX_RATE_QUERY, + HostCmd_ACT_GEN_GET, 0, wait, NULL); + if (!ret) + ret = -EINPROGRESS; + } + + return ret; +} + +/* + * IOCTL request handler to set rate. + * + * This function prepares the correct firmware command and + * issues it to set the current rate. + * + * The function also performs validation checking on the supplied value. + */ +static int mwifiex_rate_ioctl_set_rate_value(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + struct mwifiex_rate_cfg *rate_cfg) +{ + u8 rates[MWIFIEX_SUPPORTED_RATES]; + u8 *rate = NULL; + int rate_index = 0; + u16 bitmap_rates[MAX_BITMAP_RATES_SIZE]; + u32 i = 0; + int ret = 0; + struct mwifiex_adapter *adapter = priv->adapter; + + if (rate_cfg->is_rate_auto) { + memset(bitmap_rates, 0, sizeof(bitmap_rates)); + /* Support all HR/DSSS rates */ + bitmap_rates[0] = 0x000F; + /* Support all OFDM rates */ + bitmap_rates[1] = 0x00FF; + /* Support all HT-MCSs rate */ + for (i = 0; i < ARRAY_SIZE(priv->bitmap_rates) - 3; i++) + bitmap_rates[i + 2] = 0xFFFF; + bitmap_rates[9] = 0x3FFF; + } else { + memset(rates, 0, sizeof(rates)); + mwifiex_get_active_data_rates(priv, rates); + rate = rates; + for (i = 0; (rate[i] && i < MWIFIEX_SUPPORTED_RATES); i++) { + dev_dbg(adapter->dev, "info: rate=%#x wanted=%#x\n", + rate[i], rate_cfg->rate); + if ((rate[i] & 0x7f) == (rate_cfg->rate & 0x7f)) + break; + } + if (!rate[i] || (i == MWIFIEX_SUPPORTED_RATES)) { + dev_err(adapter->dev, "fixed data rate %#x is out " + "of range\n", rate_cfg->rate); + return -1; + } + memset(bitmap_rates, 0, sizeof(bitmap_rates)); + + rate_index = + mwifiex_data_rate_to_index(adapter, rate_cfg->rate); + + /* Only allow b/g rates to be set */ + if (rate_index >= MWIFIEX_RATE_INDEX_HRDSSS0 && + rate_index <= MWIFIEX_RATE_INDEX_HRDSSS3) { + bitmap_rates[0] = 1 << rate_index; + } else { + rate_index -= 1; /* There is a 0x00 in the table */ + if (rate_index >= MWIFIEX_RATE_INDEX_OFDM0 && + rate_index <= MWIFIEX_RATE_INDEX_OFDM7) + bitmap_rates[1] = 1 << (rate_index - + MWIFIEX_RATE_INDEX_OFDM0); + } + } + + /* Send request to firmware */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_TX_RATE_CFG, + HostCmd_ACT_GEN_SET, 0, wait, bitmap_rates); + if (!ret) + ret = -EINPROGRESS; + + return ret; +} + +/* + * IOCTL request handler to set/get rate. + * + * This function can be used to set/get either the rate value or the + * rate index. + */ +static int mwifiex_rate_ioctl_cfg(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + struct mwifiex_rate_cfg *rate_cfg) +{ + int status = 0; + + if (!rate_cfg) + return -1; + + if (rate_cfg->action == HostCmd_ACT_GEN_GET) + status = mwifiex_rate_ioctl_get_rate_value( + priv, wait, rate_cfg); + else + status = mwifiex_rate_ioctl_set_rate_value( + priv, wait, rate_cfg); + + return status; +} + +/* + * Sends IOCTL request to get the data rate. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, + struct mwifiex_rate_cfg *rate) +{ + int ret = 0; + struct mwifiex_wait_queue *wait = NULL; + u8 wait_option = MWIFIEX_IOCTL_WAIT; + + /* Allocate wait buffer */ + wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); + if (!wait) + return -ENOMEM; + + memset(rate, 0, sizeof(struct mwifiex_rate_cfg)); + rate->action = HostCmd_ACT_GEN_GET; + ret = mwifiex_rate_ioctl_cfg(priv, wait, rate); + + ret = mwifiex_request_ioctl(priv, wait, ret, wait_option); + if (!ret) { + if (rate && rate->is_rate_auto) + rate->rate = mwifiex_index_to_data_rate(priv->adapter, + priv->tx_rate, priv->tx_htinfo); + else if (rate) + rate->rate = priv->data_rate; + } else { + ret = -1; + } + + kfree(wait); + return ret; +} + +/* + * IOCTL request handler to set tx power configuration. + * + * This function prepares the correct firmware command and + * issues it. + * + * For non-auto power mode, all the following power groups are set - + * - Modulation class HR/DSSS + * - Modulation class OFDM + * - Modulation class HTBW20 + * - Modulation class HTBW40 + */ +static int mwifiex_power_ioctl_set_power(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + struct mwifiex_power_cfg *power_cfg) +{ + int ret = 0; + struct host_cmd_ds_txpwr_cfg *txp_cfg = NULL; + struct mwifiex_types_power_group *pg_tlv = NULL; + struct mwifiex_power_group *pg = NULL; + u8 *buf = NULL; + u16 dbm = 0; + + if (!power_cfg->is_power_auto) { + dbm = (u16) power_cfg->power_level; + if ((dbm < priv->min_tx_power_level) || + (dbm > priv->max_tx_power_level)) { + dev_err(priv->adapter->dev, "txpower value %d dBm" + " is out of range (%d dBm-%d dBm)\n", + dbm, priv->min_tx_power_level, + priv->max_tx_power_level); + return -1; + } + } + buf = kzalloc(MWIFIEX_SIZE_OF_CMD_BUFFER, GFP_KERNEL); + if (!buf) { + dev_err(priv->adapter->dev, "%s: failed to alloc cmd buffer\n", + __func__); + return -1; + } + + txp_cfg = (struct host_cmd_ds_txpwr_cfg *) buf; + txp_cfg->action = cpu_to_le16(HostCmd_ACT_GEN_SET); + if (!power_cfg->is_power_auto) { + txp_cfg->mode = cpu_to_le32(1); + pg_tlv = (struct mwifiex_types_power_group *) (buf + + sizeof(struct host_cmd_ds_txpwr_cfg)); + pg_tlv->type = TLV_TYPE_POWER_GROUP; + pg_tlv->length = 4 * sizeof(struct mwifiex_power_group); + pg = (struct mwifiex_power_group *) (buf + + sizeof(struct host_cmd_ds_txpwr_cfg) + + sizeof(struct mwifiex_types_power_group)); + /* Power group for modulation class HR/DSSS */ + pg->first_rate_code = 0x00; + pg->last_rate_code = 0x03; + pg->modulation_class = MOD_CLASS_HR_DSSS; + pg->power_step = 0; + pg->power_min = (s8) dbm; + pg->power_max = (s8) dbm; + pg++; + /* Power group for modulation class OFDM */ + pg->first_rate_code = 0x00; + pg->last_rate_code = 0x07; + pg->modulation_class = MOD_CLASS_OFDM; + pg->power_step = 0; + pg->power_min = (s8) dbm; + pg->power_max = (s8) dbm; + pg++; + /* Power group for modulation class HTBW20 */ + pg->first_rate_code = 0x00; + pg->last_rate_code = 0x20; + pg->modulation_class = MOD_CLASS_HT; + pg->power_step = 0; + pg->power_min = (s8) dbm; + pg->power_max = (s8) dbm; + pg->ht_bandwidth = HT_BW_20; + pg++; + /* Power group for modulation class HTBW40 */ + pg->first_rate_code = 0x00; + pg->last_rate_code = 0x20; + pg->modulation_class = MOD_CLASS_HT; + pg->power_step = 0; + pg->power_min = (s8) dbm; + pg->power_max = (s8) dbm; + pg->ht_bandwidth = HT_BW_40; + } + /* Send request to firmware */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_TXPWR_CFG, + HostCmd_ACT_GEN_SET, 0, wait, buf); + if (!ret) + ret = -EINPROGRESS; + kfree(buf); + + return ret; +} + +/* + * IOCTL request handler to get power save mode. + * + * This function prepares the correct firmware command and + * issues it. + */ +static int mwifiex_pm_ioctl_ps_mode(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + u32 *ps_mode, u16 action) +{ + int ret = 0; + struct mwifiex_adapter *adapter = priv->adapter; + u16 sub_cmd; + + if (action == HostCmd_ACT_GEN_SET) { + if (*ps_mode) + adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP; + else + adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM; + sub_cmd = (*ps_mode) ? EN_AUTO_PS : DIS_AUTO_PS; + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH, + sub_cmd, BITMAP_STA_PS, wait, NULL); + if ((!ret) && (sub_cmd == DIS_AUTO_PS)) + ret = mwifiex_prepare_cmd(priv, + HostCmd_CMD_802_11_PS_MODE_ENH, GET_PS, + 0, NULL, NULL); + } else { + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH, + GET_PS, 0, wait, NULL); + } + + if (!ret) + ret = -EINPROGRESS; + + return ret; +} + +/* + * IOCTL request handler to set/reset WPA IE. + * + * The supplied WPA IE is treated as a opaque buffer. Only the first field + * is checked to determine WPA version. If buffer length is zero, the existing + * WPA IE is reset. + */ +static int mwifiex_set_wpa_ie_helper(struct mwifiex_private *priv, + u8 *ie_data_ptr, u16 ie_len) +{ + if (ie_len) { + if (ie_len > sizeof(priv->wpa_ie)) { + dev_err(priv->adapter->dev, + "failed to copy WPA IE, too big\n"); + return -1; + } + memcpy(priv->wpa_ie, ie_data_ptr, ie_len); + priv->wpa_ie_len = (u8) ie_len; + dev_dbg(priv->adapter->dev, "cmd: Set Wpa_ie_len=%d IE=%#x\n", + priv->wpa_ie_len, priv->wpa_ie[0]); + + if (priv->wpa_ie[0] == WLAN_EID_WPA) { + priv->sec_info.wpa_enabled = true; + } else if (priv->wpa_ie[0] == WLAN_EID_RSN) { + priv->sec_info.wpa2_enabled = true; + } else { + priv->sec_info.wpa_enabled = false; + priv->sec_info.wpa2_enabled = false; + } + } else { + memset(priv->wpa_ie, 0, sizeof(priv->wpa_ie)); + priv->wpa_ie_len = 0; + dev_dbg(priv->adapter->dev, "info: reset wpa_ie_len=%d IE=%#x\n", + priv->wpa_ie_len, priv->wpa_ie[0]); + priv->sec_info.wpa_enabled = false; + priv->sec_info.wpa2_enabled = false; + } + + return 0; +} + +/* + * IOCTL request handler to set/reset WAPI IE. + * + * The supplied WAPI IE is treated as a opaque buffer. Only the first field + * is checked to internally enable WAPI. If buffer length is zero, the existing + * WAPI IE is reset. + */ +static int mwifiex_set_wapi_ie(struct mwifiex_private *priv, + u8 *ie_data_ptr, u16 ie_len) +{ + if (ie_len) { + if (ie_len > sizeof(priv->wapi_ie)) { + dev_dbg(priv->adapter->dev, + "info: failed to copy WAPI IE, too big\n"); + return -1; + } + memcpy(priv->wapi_ie, ie_data_ptr, ie_len); + priv->wapi_ie_len = ie_len; + dev_dbg(priv->adapter->dev, "cmd: Set wapi_ie_len=%d IE=%#x\n", + priv->wapi_ie_len, priv->wapi_ie[0]); + + if (priv->wapi_ie[0] == WLAN_EID_BSS_AC_ACCESS_DELAY) + priv->sec_info.wapi_enabled = true; + } else { + memset(priv->wapi_ie, 0, sizeof(priv->wapi_ie)); + priv->wapi_ie_len = ie_len; + dev_dbg(priv->adapter->dev, + "info: Reset wapi_ie_len=%d IE=%#x\n", + priv->wapi_ie_len, priv->wapi_ie[0]); + priv->sec_info.wapi_enabled = false; + } + return 0; +} + +/* + * IOCTL request handler to set WAPI key. + * + * This function prepares the correct firmware command and + * issues it. + */ +static int mwifiex_sec_ioctl_set_wapi_key(struct mwifiex_adapter *adapter, + struct mwifiex_wait_queue *wait, + struct mwifiex_ds_encrypt_key *encrypt_key) +{ + int ret = 0; + struct mwifiex_private *priv = adapter->priv[wait->bss_index]; + + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL, + HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED, + wait, encrypt_key); + if (!ret) + ret = -EINPROGRESS; + + return ret; +} + +/* + * IOCTL request handler to set WEP network key. + * + * This function prepares the correct firmware command and + * issues it, after validation checks. + */ +static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_adapter *adapter, + struct mwifiex_wait_queue *wait, + struct mwifiex_ds_encrypt_key *encrypt_key) +{ + int ret = 0; + struct mwifiex_private *priv = adapter->priv[wait->bss_index]; + struct mwifiex_wep_key *wep_key = NULL; + int index; + + if (priv->wep_key_curr_index >= NUM_WEP_KEYS) + priv->wep_key_curr_index = 0; + wep_key = &priv->wep_key[priv->wep_key_curr_index]; + index = encrypt_key->key_index; + if (encrypt_key->key_disable) { + priv->sec_info.wep_status = MWIFIEX_802_11_WEP_DISABLED; + } else if (!encrypt_key->key_len) { + /* Copy the required key as the current key */ + wep_key = &priv->wep_key[index]; + if (!wep_key->key_length) { + dev_err(adapter->dev, + "key not set, so cannot enable it\n"); + return -1; + } + priv->wep_key_curr_index = (u16) index; + priv->sec_info.wep_status = MWIFIEX_802_11_WEP_ENABLED; + } else { + wep_key = &priv->wep_key[index]; + /* Cleanup */ + memset(wep_key, 0, sizeof(struct mwifiex_wep_key)); + /* Copy the key in the driver */ + memcpy(wep_key->key_material, + encrypt_key->key_material, + encrypt_key->key_len); + wep_key->key_index = index; + wep_key->key_length = encrypt_key->key_len; + priv->sec_info.wep_status = MWIFIEX_802_11_WEP_ENABLED; + } + if (wep_key->key_length) { + /* Send request to firmware */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL, + HostCmd_ACT_GEN_SET, 0, NULL, NULL); + if (ret) + return ret; + } + if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED) + priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE; + else + priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE; + + /* Send request to firmware */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_MAC_CONTROL, + HostCmd_ACT_GEN_SET, 0, wait, + &priv->curr_pkt_filter); + if (!ret) + ret = -EINPROGRESS; + + return ret; +} + +/* + * IOCTL request handler to set WPA key. + * + * This function prepares the correct firmware command and + * issues it, after validation checks. + * + * Current driver only supports key length of up to 32 bytes. + * + * This function can also be used to disable a currently set key. + */ +static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_adapter *adapter, + struct mwifiex_wait_queue *wait, + struct mwifiex_ds_encrypt_key *encrypt_key) +{ + int ret = 0; + struct mwifiex_private *priv = adapter->priv[wait->bss_index]; + u8 remove_key = false; + struct host_cmd_ds_802_11_key_material *ibss_key; + + /* Current driver only supports key length of up to 32 bytes */ + if (encrypt_key->key_len > MWIFIEX_MAX_KEY_LENGTH) { + dev_err(adapter->dev, "key length too long\n"); + return -1; + } + + if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { + /* + * IBSS/WPA-None uses only one key (Group) for both receiving + * and sending unicast and multicast packets. + */ + /* Send the key as PTK to firmware */ + encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST; + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL, + HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED, + NULL, encrypt_key); + if (ret) + return ret; + + ibss_key = &priv->aes_key; + memset(ibss_key, 0, + sizeof(struct host_cmd_ds_802_11_key_material)); + /* Copy the key in the driver */ + memcpy(ibss_key->key_param_set.key, encrypt_key->key_material, + encrypt_key->key_len); + memcpy(&ibss_key->key_param_set.key_len, &encrypt_key->key_len, + sizeof(ibss_key->key_param_set.key_len)); + ibss_key->key_param_set.key_type_id + = cpu_to_le16(KEY_TYPE_ID_TKIP); + ibss_key->key_param_set.key_info + = cpu_to_le16(KEY_INFO_TKIP_ENABLED); + + /* Send the key as GTK to firmware */ + encrypt_key->key_index = ~MWIFIEX_KEY_INDEX_UNICAST; + } + + if (!encrypt_key->key_index) + encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST; + + if (remove_key) + /* Send request to firmware */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL, + HostCmd_ACT_GEN_SET, + !(KEY_INFO_ENABLED), + wait, encrypt_key); + else + /* Send request to firmware */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL, + HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED, + wait, encrypt_key); + + if (!ret) + ret = -EINPROGRESS; + + return ret; +} + +/* + * IOCTL request handler to set/get network keys. + * + * This is a generic key handling function which supports WEP, WPA + * and WAPI. + */ +static int +mwifiex_sec_ioctl_encrypt_key(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + struct mwifiex_ds_encrypt_key *encrypt_key) +{ + int status = 0; + struct mwifiex_adapter *adapter = priv->adapter; + + if (encrypt_key->is_wapi_key) + status = mwifiex_sec_ioctl_set_wapi_key(adapter, wait, + encrypt_key); + else if (encrypt_key->key_len > WLAN_KEY_LEN_WEP104) + status = mwifiex_sec_ioctl_set_wpa_key(adapter, wait, + encrypt_key); + else + status = mwifiex_sec_ioctl_set_wep_key(adapter, wait, + encrypt_key); + return status; +} + +/* + * This function returns the driver version. + */ +int +mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter, char *version, + int max_len) +{ + union { + u32 l; + u8 c[4]; + } ver; + char fw_ver[32]; + + ver.l = adapter->fw_release_number; + sprintf(fw_ver, "%u.%u.%u.p%u", ver.c[2], ver.c[1], ver.c[0], ver.c[3]); + + snprintf(version, max_len, driver_version, fw_ver); + + dev_dbg(adapter->dev, "info: MWIFIEX VERSION: %s\n", version); + + return 0; +} + +/* + * Sends IOCTL request to set Tx power. It can be set to either auto + * or a fixed value. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int +mwifiex_set_tx_power(struct mwifiex_private *priv, int type, int dbm) +{ + struct mwifiex_power_cfg power_cfg; + struct mwifiex_wait_queue *wait = NULL; + int status = 0; + int ret = 0; + + wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT); + if (!wait) + return -ENOMEM; + + if (type == NL80211_TX_POWER_FIXED) { + power_cfg.is_power_auto = 0; + power_cfg.power_level = dbm; + } else { + power_cfg.is_power_auto = 1; + } + status = mwifiex_power_ioctl_set_power(priv, wait, &power_cfg); + + ret = mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT); + + kfree(wait); + return ret; +} + +/* + * Sends IOCTL request to get scan table. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int mwifiex_get_scan_table(struct mwifiex_private *priv, u8 wait_option, + struct mwifiex_scan_resp *scan_resp) +{ + struct mwifiex_wait_queue *wait = NULL; + struct mwifiex_scan_resp scan; + int status = 0; + + /* Allocate wait buffer */ + wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); + if (!wait) + return -ENOMEM; + + status = mwifiex_scan_networks(priv, wait, HostCmd_ACT_GEN_GET, + NULL, &scan); + + status = mwifiex_request_ioctl(priv, wait, status, wait_option); + if (!status) { + if (scan_resp) + memcpy(scan_resp, &scan, + sizeof(struct mwifiex_scan_resp)); + } + + if (wait && (status != -EINPROGRESS)) + kfree(wait); + return status; +} + +/* + * Sends IOCTL request to get signal information. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int mwifiex_get_signal_info(struct mwifiex_private *priv, u8 wait_option, + struct mwifiex_ds_get_signal *signal) +{ + struct mwifiex_ds_get_signal info; + struct mwifiex_wait_queue *wait = NULL; + int status = 0; + + /* Allocate wait buffer */ + wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); + if (!wait) + return -ENOMEM; + + info.selector = ALL_RSSI_INFO_MASK; + + status = mwifiex_get_info_signal(priv, wait, &info); + + status = mwifiex_request_ioctl(priv, wait, status, wait_option); + if (!status) { + if (signal) + memcpy(signal, &info, + sizeof(struct mwifiex_ds_get_signal)); + if (info.selector & BCN_RSSI_AVG_MASK) + priv->w_stats.qual.level = info.bcn_rssi_avg; + if (info.selector & BCN_NF_AVG_MASK) + priv->w_stats.qual.noise = info.bcn_nf_avg; + } + + if (wait && (status != -EINPROGRESS)) + kfree(wait); + return status; +} + +/* + * Sends IOCTL request to set encoding parameters. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key, + int key_len, u8 key_index, int disable) +{ + struct mwifiex_wait_queue *wait = NULL; + struct mwifiex_ds_encrypt_key encrypt_key; + int status = 0; + int ret = 0; + + wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT); + if (!wait) + return -ENOMEM; + + memset(&encrypt_key, 0, sizeof(struct mwifiex_ds_encrypt_key)); + encrypt_key.key_len = key_len; + if (!disable) { + encrypt_key.key_index = key_index; + if (key_len) + memcpy(encrypt_key.key_material, key, key_len); + } else { + encrypt_key.key_disable = true; + } + + status = mwifiex_sec_ioctl_encrypt_key(priv, wait, &encrypt_key); + + if (mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT)) + ret = -EFAULT; + + kfree(wait); + return ret; +} + +/* + * Sends IOCTL request to set power management parameters. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int +mwifiex_drv_set_power(struct mwifiex_private *priv, bool power_on) +{ + int ret = 0; + int status = 0; + struct mwifiex_wait_queue *wait = NULL; + u32 ps_mode; + + wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT); + if (!wait) + return -ENOMEM; + + ps_mode = power_on; + status = mwifiex_pm_ioctl_ps_mode(priv, wait, &ps_mode, + HostCmd_ACT_GEN_SET); + + ret = mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT); + + kfree(wait); + return ret; +} + +/* + * Sends IOCTL request to get extended version. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int +mwifiex_get_ver_ext(struct mwifiex_private *priv) +{ + struct mwifiex_ver_ext ver_ext; + struct mwifiex_wait_queue *wait = NULL; + int status = 0; + int ret = 0; + u8 wait_option = MWIFIEX_IOCTL_WAIT; + + /* Allocate wait buffer */ + wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); + if (!wait) + return -ENOMEM; + + /* get fw version */ + memset(&ver_ext, 0, sizeof(struct host_cmd_ds_version_ext)); + status = mwifiex_get_info_ver_ext(priv, wait, &ver_ext); + + ret = mwifiex_request_ioctl(priv, wait, status, wait_option); + + if (ret) + ret = -1; + + kfree(wait); + return ret; +} + +/* + * Sends IOCTL request to get statistics information. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int +mwifiex_get_stats_info(struct mwifiex_private *priv, + struct mwifiex_ds_get_stats *log) +{ + int ret = 0; + int status = 0; + struct mwifiex_wait_queue *wait = NULL; + struct mwifiex_ds_get_stats get_log; + u8 wait_option = MWIFIEX_IOCTL_WAIT; + + /* Allocate wait buffer */ + wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); + if (!wait) + return -ENOMEM; + + memset(&get_log, 0, sizeof(struct mwifiex_ds_get_stats)); + status = mwifiex_get_info_stats(priv, wait, &get_log); + + /* Send IOCTL request to MWIFIEX */ + ret = mwifiex_request_ioctl(priv, wait, status, wait_option); + if (!ret) { + if (log) + memcpy(log, &get_log, sizeof(struct + mwifiex_ds_get_stats)); + priv->w_stats.discard.fragment = get_log.fcs_error; + priv->w_stats.discard.retries = get_log.retry; + priv->w_stats.discard.misc = get_log.ack_failure; + } + + kfree(wait); + return ret; +} + +/* + * IOCTL request handler to read/write register. + * + * This function prepares the correct firmware command and + * issues it. + * + * Access to the following registers are supported - + * - MAC + * - BBP + * - RF + * - PMIC + * - CAU + */ +static int mwifiex_reg_mem_ioctl_reg_rw(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + struct mwifiex_ds_reg_rw *reg_rw, + u16 action) +{ + int ret = 0; + u16 cmd_no; + + switch (le32_to_cpu(reg_rw->type)) { + case MWIFIEX_REG_MAC: + cmd_no = HostCmd_CMD_MAC_REG_ACCESS; + break; + case MWIFIEX_REG_BBP: + cmd_no = HostCmd_CMD_BBP_REG_ACCESS; + break; + case MWIFIEX_REG_RF: + cmd_no = HostCmd_CMD_RF_REG_ACCESS; + break; + case MWIFIEX_REG_PMIC: + cmd_no = HostCmd_CMD_PMIC_REG_ACCESS; + break; + case MWIFIEX_REG_CAU: + cmd_no = HostCmd_CMD_CAU_REG_ACCESS; + break; + default: + return -1; + } + + /* Send request to firmware */ + ret = mwifiex_prepare_cmd(priv, cmd_no, action, 0, wait, reg_rw); + + if (!ret) + ret = -EINPROGRESS; + + return ret; +} + +/* + * Sends IOCTL request to write to a register. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int +mwifiex_reg_write(struct mwifiex_private *priv, u32 reg_type, + u32 reg_offset, u32 reg_value) +{ + int ret = 0; + int status = 0; + struct mwifiex_wait_queue *wait = NULL; + struct mwifiex_ds_reg_rw reg_rw; + + wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT); + if (!wait) + return -ENOMEM; + + reg_rw.type = cpu_to_le32(reg_type); + reg_rw.offset = cpu_to_le32(reg_offset); + reg_rw.value = cpu_to_le32(reg_value); + status = mwifiex_reg_mem_ioctl_reg_rw(priv, wait, ®_rw, + HostCmd_ACT_GEN_SET); + + ret = mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT); + + kfree(wait); + return ret; +} + +/* + * Sends IOCTL request to read from a register. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int +mwifiex_reg_read(struct mwifiex_private *priv, u32 reg_type, + u32 reg_offset, u32 *value) +{ + int ret = 0; + int status = 0; + struct mwifiex_wait_queue *wait = NULL; + struct mwifiex_ds_reg_rw reg_rw; + + wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT); + if (!wait) + return -ENOMEM; + + reg_rw.type = cpu_to_le32(reg_type); + reg_rw.offset = cpu_to_le32(reg_offset); + status = mwifiex_reg_mem_ioctl_reg_rw(priv, wait, ®_rw, + HostCmd_ACT_GEN_GET); + + ret = mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT); + if (ret) + goto done; + + *value = le32_to_cpu(reg_rw.value); + +done: + kfree(wait); + return ret; +} + +/* + * IOCTL request handler to read EEPROM. + * + * This function prepares the correct firmware command and + * issues it. + */ +static int +mwifiex_reg_mem_ioctl_read_eeprom(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + struct mwifiex_ds_read_eeprom *rd_eeprom) +{ + int ret = 0; + + /* Send request to firmware */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_EEPROM_ACCESS, + HostCmd_ACT_GEN_GET, 0, wait, rd_eeprom); + + if (!ret) + ret = -EINPROGRESS; + + return ret; +} + +/* + * Sends IOCTL request to read from EEPROM. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int +mwifiex_eeprom_read(struct mwifiex_private *priv, u16 offset, u16 bytes, + u8 *value) +{ + int ret = 0; + int status = 0; + struct mwifiex_wait_queue *wait = NULL; + struct mwifiex_ds_read_eeprom rd_eeprom; + + wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT); + if (!wait) + return -ENOMEM; + + rd_eeprom.offset = cpu_to_le16((u16) offset); + rd_eeprom.byte_count = cpu_to_le16((u16) bytes); + status = mwifiex_reg_mem_ioctl_read_eeprom(priv, wait, &rd_eeprom); + + ret = mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT); + if (ret) + goto done; + + memcpy(value, rd_eeprom.value, MAX_EEPROM_DATA); +done: + kfree(wait); + return ret; +} + +/* + * This function sets a generic IE. In addition to generic IE, it can + * also handle WPA, WPA2 and WAPI IEs. + */ +static int +mwifiex_set_gen_ie_helper(struct mwifiex_private *priv, u8 *ie_data_ptr, + u16 ie_len) +{ + int ret = 0; + struct ieee_types_vendor_header *pvendor_ie; + const u8 wpa_oui[] = { 0x00, 0x50, 0xf2, 0x01 }; + const u8 wps_oui[] = { 0x00, 0x50, 0xf2, 0x04 }; + + /* If the passed length is zero, reset the buffer */ + if (!ie_len) { + priv->gen_ie_buf_len = 0; + priv->wps.session_enable = false; + + return 0; + } else if (!ie_data_ptr) { + return -1; + } + pvendor_ie = (struct ieee_types_vendor_header *) ie_data_ptr; + /* Test to see if it is a WPA IE, if not, then it is a gen IE */ + if (((pvendor_ie->element_id == WLAN_EID_WPA) + && (!memcmp(pvendor_ie->oui, wpa_oui, sizeof(wpa_oui)))) + || (pvendor_ie->element_id == WLAN_EID_RSN)) { + + /* IE is a WPA/WPA2 IE so call set_wpa function */ + ret = mwifiex_set_wpa_ie_helper(priv, ie_data_ptr, ie_len); + priv->wps.session_enable = false; + + return ret; + } else if (pvendor_ie->element_id == WLAN_EID_BSS_AC_ACCESS_DELAY) { + /* IE is a WAPI IE so call set_wapi function */ + ret = mwifiex_set_wapi_ie(priv, ie_data_ptr, ie_len); + + return ret; + } + /* + * Verify that the passed length is not larger than the + * available space remaining in the buffer + */ + if (ie_len < (sizeof(priv->gen_ie_buf) - priv->gen_ie_buf_len)) { + + /* Test to see if it is a WPS IE, if so, enable + * wps session flag + */ + pvendor_ie = (struct ieee_types_vendor_header *) ie_data_ptr; + if ((pvendor_ie->element_id == WLAN_EID_VENDOR_SPECIFIC) + && (!memcmp(pvendor_ie->oui, wps_oui, + sizeof(wps_oui)))) { + priv->wps.session_enable = true; + dev_dbg(priv->adapter->dev, + "info: WPS Session Enabled.\n"); + } + + /* Append the passed data to the end of the + genIeBuffer */ + memcpy(priv->gen_ie_buf + priv->gen_ie_buf_len, ie_data_ptr, + ie_len); + /* Increment the stored buffer length by the + size passed */ + priv->gen_ie_buf_len += ie_len; + } else { + /* Passed data does not fit in the remaining + buffer space */ + ret = -1; + } + + /* Return 0, or -1 for error case */ + return ret; +} + +/* + * IOCTL request handler to set/get generic IE. + * + * In addition to various generic IEs, this function can also be + * used to set the ARP filter. + */ +static int mwifiex_misc_ioctl_gen_ie(struct mwifiex_private *priv, + struct mwifiex_ds_misc_gen_ie *gen_ie, + u16 action) +{ + struct mwifiex_adapter *adapter = priv->adapter; + + switch (gen_ie->type) { + case MWIFIEX_IE_TYPE_GEN_IE: + if (action == HostCmd_ACT_GEN_GET) { + gen_ie->len = priv->wpa_ie_len; + memcpy(gen_ie->ie_data, priv->wpa_ie, gen_ie->len); + } else { + mwifiex_set_gen_ie_helper(priv, gen_ie->ie_data, + (u16) gen_ie->len); + } + break; + case MWIFIEX_IE_TYPE_ARP_FILTER: + memset(adapter->arp_filter, 0, sizeof(adapter->arp_filter)); + if (gen_ie->len > ARP_FILTER_MAX_BUF_SIZE) { + adapter->arp_filter_size = 0; + dev_err(adapter->dev, "invalid ARP filter size\n"); + return -1; + } else { + memcpy(adapter->arp_filter, gen_ie->ie_data, + gen_ie->len); + adapter->arp_filter_size = gen_ie->len; + } + break; + default: + dev_err(adapter->dev, "invalid IE type\n"); + return -1; + } + return 0; +} + +/* + * Sends IOCTL request to set a generic IE. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int +mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len) +{ + struct mwifiex_ds_misc_gen_ie gen_ie; + int status = 0; + + if (ie_len > IW_CUSTOM_MAX) + return -EFAULT; + + gen_ie.type = MWIFIEX_IE_TYPE_GEN_IE; + gen_ie.len = ie_len; + memcpy(gen_ie.ie_data, ie, ie_len); + status = mwifiex_misc_ioctl_gen_ie(priv, &gen_ie, HostCmd_ACT_GEN_SET); + if (status) + return -EFAULT; + + return 0; +} diff --git a/drivers/net/wireless/mwifiex/sta_rx.c b/drivers/net/wireless/mwifiex/sta_rx.c new file mode 100644 index 000000000000..8282679e64fd --- /dev/null +++ b/drivers/net/wireless/mwifiex/sta_rx.c @@ -0,0 +1,182 @@ +/* + * Marvell Wireless LAN device driver: station RX data handling + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "11n_aggr.h" +#include "11n_rxreorder.h" + +/* + * This function processes the received packet and forwards it + * to kernel/upper layer. + * + * This function parses through the received packet and determines + * if it is a debug packet or normal packet. + * + * For non-debug packets, the function chops off unnecessary leading + * header bytes, reconstructs the packet as an ethernet frame or + * 802.2/llc/snap frame as required, and sends it to kernel/upper layer. + * + * The completion callback is called after processing in complete. + */ +int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter, + struct sk_buff *skb) +{ + int ret = 0; + struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); + struct mwifiex_private *priv = adapter->priv[rx_info->bss_index]; + struct rx_packet_hdr *rx_pkt_hdr; + struct rxpd *local_rx_pd; + int hdr_chop; + struct ethhdr *eth_hdr; + u8 rfc1042_eth_hdr[ETH_ALEN] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; + + local_rx_pd = (struct rxpd *) (skb->data); + + rx_pkt_hdr = (struct rx_packet_hdr *) ((u8 *) local_rx_pd + + local_rx_pd->rx_pkt_offset); + + if (!memcmp(&rx_pkt_hdr->rfc1042_hdr, + rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr))) { + /* + * Replace the 803 header and rfc1042 header (llc/snap) with an + * EthernetII header, keep the src/dst and snap_type + * (ethertype). + * The firmware only passes up SNAP frames converting + * all RX Data from 802.11 to 802.2/LLC/SNAP frames. + * To create the Ethernet II, just move the src, dst address + * right before the snap_type. + */ + eth_hdr = (struct ethhdr *) + ((u8 *) &rx_pkt_hdr->eth803_hdr + + sizeof(rx_pkt_hdr->eth803_hdr) + + sizeof(rx_pkt_hdr->rfc1042_hdr) + - sizeof(rx_pkt_hdr->eth803_hdr.h_dest) + - sizeof(rx_pkt_hdr->eth803_hdr.h_source) + - sizeof(rx_pkt_hdr->rfc1042_hdr.snap_type)); + + memcpy(eth_hdr->h_source, rx_pkt_hdr->eth803_hdr.h_source, + sizeof(eth_hdr->h_source)); + memcpy(eth_hdr->h_dest, rx_pkt_hdr->eth803_hdr.h_dest, + sizeof(eth_hdr->h_dest)); + + /* Chop off the rxpd + the excess memory from the 802.2/llc/snap + header that was removed. */ + hdr_chop = (u8 *) eth_hdr - (u8 *) local_rx_pd; + } else { + /* Chop off the rxpd */ + hdr_chop = (u8 *) &rx_pkt_hdr->eth803_hdr - + (u8 *) local_rx_pd; + } + + /* Chop off the leading header bytes so the it points to the start of + either the reconstructed EthII frame or the 802.2/llc/snap frame */ + skb_pull(skb, hdr_chop); + + priv->rxpd_rate = local_rx_pd->rx_rate; + + priv->rxpd_htinfo = local_rx_pd->ht_info; + + ret = mwifiex_recv_packet(adapter, skb); + if (ret == -1) + dev_err(adapter->dev, "recv packet failed\n"); + + return ret; +} + +/* + * This function processes the received buffer. + * + * The function looks into the RxPD and performs sanity tests on the + * received buffer to ensure its a valid packet, before processing it + * further. If the packet is determined to be aggregated, it is + * de-aggregated accordingly. Non-unicast packets are sent directly to + * the kernel/upper layers. Unicast packets are handed over to the + * Rx reordering routine if 11n is enabled. + * + * The completion callback is called after processing in complete. + */ +int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter, + struct sk_buff *skb) +{ + int ret = 0; + struct rxpd *local_rx_pd; + struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); + struct rx_packet_hdr *rx_pkt_hdr; + u8 ta[ETH_ALEN]; + u16 rx_pkt_type = 0; + struct mwifiex_private *priv = adapter->priv[rx_info->bss_index]; + + local_rx_pd = (struct rxpd *) (skb->data); + rx_pkt_type = local_rx_pd->rx_pkt_type; + + rx_pkt_hdr = (struct rx_packet_hdr *) ((u8 *) local_rx_pd + + local_rx_pd->rx_pkt_offset); + + if ((local_rx_pd->rx_pkt_offset + local_rx_pd->rx_pkt_length) > + (u16) skb->len) { + dev_err(adapter->dev, "wrong rx packet: len=%d," + " rx_pkt_offset=%d, rx_pkt_length=%d\n", skb->len, + local_rx_pd->rx_pkt_offset, local_rx_pd->rx_pkt_length); + priv->stats.rx_dropped++; + dev_kfree_skb_any(skb); + return ret; + } + if (local_rx_pd->rx_pkt_type == PKT_TYPE_AMSDU) { + mwifiex_11n_deaggregate_pkt(priv, skb); + return ret; + } + /* + * If the packet is not an unicast packet then send the packet + * directly to os. Don't pass thru rx reordering + */ + if (!IS_11N_ENABLED(priv) || + memcmp(priv->curr_addr, rx_pkt_hdr->eth803_hdr.h_dest, ETH_ALEN)) { + mwifiex_process_rx_packet(adapter, skb); + return ret; + } + + if (mwifiex_queuing_ra_based(priv)) { + memcpy(ta, rx_pkt_hdr->eth803_hdr.h_source, ETH_ALEN); + } else { + if (rx_pkt_type != PKT_TYPE_BAR) + priv->rx_seq[local_rx_pd->priority] = + local_rx_pd->seq_num; + memcpy(ta, priv->curr_bss_params.bss_descriptor.mac_address, + ETH_ALEN); + } + + /* Reorder and send to OS */ + ret = mwifiex_11n_rx_reorder_pkt(priv, local_rx_pd->seq_num, + local_rx_pd->priority, ta, + (u8) local_rx_pd->rx_pkt_type, + (void *) skb); + + if (ret || (rx_pkt_type == PKT_TYPE_BAR)) { + if (priv && (ret == -1)) + priv->stats.rx_dropped++; + + dev_kfree_skb_any(skb); + } + + return ret; +} diff --git a/drivers/net/wireless/mwifiex/sta_tx.c b/drivers/net/wireless/mwifiex/sta_tx.c new file mode 100644 index 000000000000..e8db6bd021c6 --- /dev/null +++ b/drivers/net/wireless/mwifiex/sta_tx.c @@ -0,0 +1,202 @@ +/* + * Marvell Wireless LAN device driver: station TX data handling + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" + +/* + * This function fills the TxPD for tx packets. + * + * The Tx buffer received by this function should already have the + * header space allocated for TxPD. + * + * This function inserts the TxPD in between interface header and actual + * data and adjusts the buffer pointers accordingly. + * + * The following TxPD fields are set by this function, as required - + * - BSS number + * - Tx packet length and offset + * - Priority + * - Packet delay + * - Priority specific Tx control + * - Flags + */ +void *mwifiex_process_sta_txpd(struct mwifiex_private *priv, + struct sk_buff *skb) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct txpd *local_tx_pd; + struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb); + + if (!skb->len) { + dev_err(adapter->dev, "Tx: bad packet length: %d\n", + skb->len); + tx_info->status_code = MWIFIEX_ERROR_PKT_SIZE_INVALID; + return skb->data; + } + + BUG_ON(skb_headroom(skb) < (sizeof(*local_tx_pd) + INTF_HEADER_LEN)); + skb_push(skb, sizeof(*local_tx_pd)); + + local_tx_pd = (struct txpd *) skb->data; + memset(local_tx_pd, 0, sizeof(struct txpd)); + local_tx_pd->bss_num = priv->bss_num; + local_tx_pd->bss_type = priv->bss_type; + local_tx_pd->tx_pkt_length = cpu_to_le16((u16) (skb->len - + sizeof(struct txpd))); + + local_tx_pd->priority = (u8) skb->priority; + local_tx_pd->pkt_delay_2ms = + mwifiex_wmm_compute_drv_pkt_delay(priv, skb); + + if (local_tx_pd->priority < + ARRAY_SIZE(priv->wmm.user_pri_pkt_tx_ctrl)) + /* + * Set the priority specific tx_control field, setting of 0 will + * cause the default value to be used later in this function + */ + local_tx_pd->tx_control = + cpu_to_le32(priv->wmm.user_pri_pkt_tx_ctrl[local_tx_pd-> + priority]); + + if (adapter->pps_uapsd_mode) { + if (mwifiex_check_last_packet_indication(priv)) { + adapter->tx_lock_flag = true; + local_tx_pd->flags = + MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET; + } + } + + /* Offset of actual data */ + local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd)); + + /* make space for INTF_HEADER_LEN */ + skb_push(skb, INTF_HEADER_LEN); + + if (!local_tx_pd->tx_control) + /* TxCtrl set by user or default */ + local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl); + + return skb->data; +} + +/* + * This function tells firmware to send a NULL data packet. + * + * The function creates a NULL data packet with TxPD and sends to the + * firmware for transmission, with highest priority setting. + */ +int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct txpd *local_tx_pd; +/* sizeof(struct txpd) + Interface specific header */ +#define NULL_PACKET_HDR 64 + u32 data_len = NULL_PACKET_HDR; + struct sk_buff *skb = NULL; + int ret = 0; + struct mwifiex_txinfo *tx_info = NULL; + + if (adapter->surprise_removed) + return -1; + + if (!priv->media_connected) + return -1; + + if (adapter->data_sent) + return -1; + + skb = dev_alloc_skb(data_len); + if (!skb) + return -1; + + tx_info = MWIFIEX_SKB_TXCB(skb); + tx_info->bss_index = priv->bss_index; + skb_reserve(skb, sizeof(struct txpd) + INTF_HEADER_LEN); + skb_push(skb, sizeof(struct txpd)); + + local_tx_pd = (struct txpd *) skb->data; + local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl); + local_tx_pd->flags = flags; + local_tx_pd->priority = WMM_HIGHEST_PRIORITY; + local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd)); + local_tx_pd->bss_num = priv->bss_num; + local_tx_pd->bss_type = priv->bss_type; + + skb_push(skb, INTF_HEADER_LEN); + + ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, + skb->data, skb->len, NULL); + switch (ret) { + case -EBUSY: + adapter->data_sent = true; + /* Fall through FAILURE handling */ + case -1: + dev_kfree_skb_any(skb); + dev_err(adapter->dev, "%s: host_to_card failed: ret=%d\n", + __func__, ret); + adapter->dbg.num_tx_host_to_card_failure++; + break; + case 0: + dev_kfree_skb_any(skb); + dev_dbg(adapter->dev, "data: %s: host_to_card succeeded\n", + __func__); + adapter->tx_lock_flag = true; + break; + case -EINPROGRESS: + break; + default: + break; + } + + return ret; +} + +/* + * This function checks if we need to send last packet indication. + */ +u8 +mwifiex_check_last_packet_indication(struct mwifiex_private *priv) +{ + struct mwifiex_adapter *adapter = priv->adapter; + u8 ret = false; + u8 prop_ps = true; + + if (!adapter->sleep_period.period) + return ret; + if (mwifiex_wmm_lists_empty(adapter)) { + if ((priv->curr_bss_params.wmm_uapsd_enabled && + priv->wmm_qosinfo) || prop_ps) + ret = true; + } + + if (ret && !adapter->cmd_sent && !adapter->curr_cmd + && !is_command_pending(adapter)) { + adapter->delay_null_pkt = false; + ret = true; + } else { + ret = false; + adapter->delay_null_pkt = true; + } + return ret; +} diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c new file mode 100644 index 000000000000..f06923cb1c4b --- /dev/null +++ b/drivers/net/wireless/mwifiex/txrx.c @@ -0,0 +1,202 @@ +/* + * Marvell Wireless LAN device driver: generic TX/RX data handling + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" + +/* + * This function processes the received buffer. + * + * Main responsibility of this function is to parse the RxPD to + * identify the correct interface this packet is headed for and + * forwarding it to the associated handling function, where the + * packet will be further processed and sent to kernel/upper layer + * if required. + */ +int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter, + struct sk_buff *skb) +{ + int ret = 0; + struct mwifiex_private *priv = + mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + struct rxpd *local_rx_pd; + struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); + + local_rx_pd = (struct rxpd *) (skb->data); + /* Get the BSS number from rxpd, get corresponding priv */ + priv = mwifiex_get_priv_by_id(adapter, local_rx_pd->bss_num & + BSS_NUM_MASK, local_rx_pd->bss_type); + if (!priv) + priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + + rx_info->bss_index = priv->bss_index; + ret = mwifiex_process_sta_rx_packet(adapter, skb); + + return ret; +} +EXPORT_SYMBOL_GPL(mwifiex_handle_rx_packet); + +/* + * This function sends a packet to device. + * + * It processes the packet to add the TxPD, checks condition and + * sends the processed packet to firmware for transmission. + * + * On successful completion, the function calls the completion callback + * and logs the time. + */ +int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, + struct mwifiex_tx_param *tx_param) +{ + int ret = -1; + struct mwifiex_adapter *adapter = priv->adapter; + u8 *head_ptr = NULL; + struct txpd *local_tx_pd = NULL; + + head_ptr = (u8 *) mwifiex_process_sta_txpd(priv, skb); + if (head_ptr) { + if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) + local_tx_pd = + (struct txpd *) (head_ptr + INTF_HEADER_LEN); + + ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, + skb->data, skb->len, tx_param); + } + + switch (ret) { + case -EBUSY: + if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && + (adapter->pps_uapsd_mode) && + (adapter->tx_lock_flag)) { + priv->adapter->tx_lock_flag = false; + local_tx_pd->flags = 0; + } + dev_dbg(adapter->dev, "data: -EBUSY is returned\n"); + break; + case -1: + adapter->data_sent = false; + dev_err(adapter->dev, "mwifiex_write_data_async failed: 0x%X\n", + ret); + adapter->dbg.num_tx_host_to_card_failure++; + mwifiex_write_data_complete(adapter, skb, ret); + break; + case -EINPROGRESS: + adapter->data_sent = false; + break; + case 0: + mwifiex_write_data_complete(adapter, skb, ret); + break; + default: + break; + } + + return ret; +} + +/* + * Packet send completion callback handler. + * + * It either frees the buffer directly or forwards it to another + * completion callback which checks conditions, updates statistics, + * wakes up stalled traffic queue if required, and then frees the buffer. + */ +int mwifiex_write_data_complete(struct mwifiex_adapter *adapter, + struct sk_buff *skb, int status) +{ + struct mwifiex_private *priv = NULL, *tpriv = NULL; + struct mwifiex_txinfo *tx_info = NULL; + int i; + + if (!skb) + return 0; + + tx_info = MWIFIEX_SKB_TXCB(skb); + priv = mwifiex_bss_index_to_priv(adapter, tx_info->bss_index); + if (!priv) + goto done; + + priv->netdev->trans_start = jiffies; + if (!status) { + priv->stats.tx_packets++; + priv->stats.tx_bytes += skb->len; + } else { + priv->stats.tx_errors++; + } + atomic_dec(&adapter->tx_pending); + + for (i = 0; i < adapter->priv_num; i++) { + + tpriv = adapter->priv[i]; + + if ((GET_BSS_ROLE(tpriv) == MWIFIEX_BSS_ROLE_STA) + && (tpriv->media_connected)) { + if (netif_queue_stopped(tpriv->netdev)) + netif_wake_queue(tpriv->netdev); + } + } +done: + dev_kfree_skb_any(skb); + + return 0; +} + +/* + * Packet receive completion callback handler. + * + * This function calls another completion callback handler which + * updates the statistics, and optionally updates the parent buffer + * use count before freeing the received packet. + */ +int mwifiex_recv_packet_complete(struct mwifiex_adapter *adapter, + struct sk_buff *skb, int status) +{ + struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); + struct mwifiex_rxinfo *rx_info_parent = NULL; + struct mwifiex_private *priv; + struct sk_buff *skb_parent = NULL; + unsigned long flags; + + priv = adapter->priv[rx_info->bss_index]; + + if (priv && (status == -1)) + priv->stats.rx_dropped++; + + if (rx_info->parent) { + skb_parent = rx_info->parent; + rx_info_parent = MWIFIEX_SKB_RXCB(skb_parent); + + spin_lock_irqsave(&priv->rx_pkt_lock, flags); + --rx_info_parent->use_count; + + if (!rx_info_parent->use_count) { + spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); + dev_kfree_skb_any(skb_parent); + } else { + spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); + } + } else { + dev_kfree_skb_any(skb); + } + + return 0; +} diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c new file mode 100644 index 000000000000..205022aa52f5 --- /dev/null +++ b/drivers/net/wireless/mwifiex/util.c @@ -0,0 +1,252 @@ +/* + * Marvell Wireless LAN device driver: utility functions + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" + +/* + * Firmware initialization complete callback handler. + * + * This function wakes up the function waiting on the init + * wait queue for the firmware initialization to complete. + */ +int mwifiex_init_fw_complete(struct mwifiex_adapter *adapter) +{ + + adapter->init_wait_q_woken = true; + wake_up_interruptible(&adapter->init_wait_q); + return 0; +} + +/* + * Firmware shutdown complete callback handler. + * + * This function sets the hardware status to not ready and wakes up + * the function waiting on the init wait queue for the firmware + * shutdown to complete. + */ +int mwifiex_shutdown_fw_complete(struct mwifiex_adapter *adapter) +{ + adapter->hw_status = MWIFIEX_HW_STATUS_NOT_READY; + adapter->init_wait_q_woken = true; + wake_up_interruptible(&adapter->init_wait_q); + return 0; +} + +/* + * IOCTL request handler to send function init/shutdown command + * to firmware. + * + * This function prepares the correct firmware command and + * issues it. + */ +int mwifiex_misc_ioctl_init_shutdown(struct mwifiex_adapter *adapter, + struct mwifiex_wait_queue *wait, + u32 func_init_shutdown) +{ + struct mwifiex_private *priv = adapter->priv[wait->bss_index]; + int ret; + u16 cmd; + + if (func_init_shutdown == MWIFIEX_FUNC_INIT) { + cmd = HostCmd_CMD_FUNC_INIT; + } else if (func_init_shutdown == MWIFIEX_FUNC_SHUTDOWN) { + cmd = HostCmd_CMD_FUNC_SHUTDOWN; + } else { + dev_err(adapter->dev, "unsupported parameter\n"); + return -1; + } + + /* Send command to firmware */ + ret = mwifiex_prepare_cmd(priv, cmd, HostCmd_ACT_GEN_SET, + 0, wait, NULL); + + if (!ret) + ret = -EINPROGRESS; + + return ret; +} + +/* + * IOCTL request handler to set/get debug information. + * + * This function collates/sets the information from/to different driver + * structures. + */ +int mwifiex_get_debug_info(struct mwifiex_private *priv, + struct mwifiex_debug_info *info) +{ + struct mwifiex_adapter *adapter = priv->adapter; + + if (info) { + memcpy(info->packets_out, + priv->wmm.packets_out, + sizeof(priv->wmm.packets_out)); + info->max_tx_buf_size = (u32) adapter->max_tx_buf_size; + info->tx_buf_size = (u32) adapter->tx_buf_size; + info->rx_tbl_num = mwifiex_get_rx_reorder_tbl( + priv, info->rx_tbl); + info->tx_tbl_num = mwifiex_get_tx_ba_stream_tbl( + priv, info->tx_tbl); + info->ps_mode = adapter->ps_mode; + info->ps_state = adapter->ps_state; + info->is_deep_sleep = adapter->is_deep_sleep; + info->pm_wakeup_card_req = adapter->pm_wakeup_card_req; + info->pm_wakeup_fw_try = adapter->pm_wakeup_fw_try; + info->is_hs_configured = adapter->is_hs_configured; + info->hs_activated = adapter->hs_activated; + info->num_cmd_host_to_card_failure + = adapter->dbg.num_cmd_host_to_card_failure; + info->num_cmd_sleep_cfm_host_to_card_failure + = adapter->dbg.num_cmd_sleep_cfm_host_to_card_failure; + info->num_tx_host_to_card_failure + = adapter->dbg.num_tx_host_to_card_failure; + info->num_event_deauth = adapter->dbg.num_event_deauth; + info->num_event_disassoc = adapter->dbg.num_event_disassoc; + info->num_event_link_lost = adapter->dbg.num_event_link_lost; + info->num_cmd_deauth = adapter->dbg.num_cmd_deauth; + info->num_cmd_assoc_success = + adapter->dbg.num_cmd_assoc_success; + info->num_cmd_assoc_failure = + adapter->dbg.num_cmd_assoc_failure; + info->num_tx_timeout = adapter->dbg.num_tx_timeout; + info->num_cmd_timeout = adapter->dbg.num_cmd_timeout; + info->timeout_cmd_id = adapter->dbg.timeout_cmd_id; + info->timeout_cmd_act = adapter->dbg.timeout_cmd_act; + memcpy(info->last_cmd_id, adapter->dbg.last_cmd_id, + sizeof(adapter->dbg.last_cmd_id)); + memcpy(info->last_cmd_act, adapter->dbg.last_cmd_act, + sizeof(adapter->dbg.last_cmd_act)); + info->last_cmd_index = adapter->dbg.last_cmd_index; + memcpy(info->last_cmd_resp_id, adapter->dbg.last_cmd_resp_id, + sizeof(adapter->dbg.last_cmd_resp_id)); + info->last_cmd_resp_index = adapter->dbg.last_cmd_resp_index; + memcpy(info->last_event, adapter->dbg.last_event, + sizeof(adapter->dbg.last_event)); + info->last_event_index = adapter->dbg.last_event_index; + info->data_sent = adapter->data_sent; + info->cmd_sent = adapter->cmd_sent; + info->cmd_resp_received = adapter->cmd_resp_received; + } + + return 0; +} + +/* + * This function processes the received packet before sending it to the + * kernel. + * + * It extracts the SKB from the received buffer and sends it to kernel. + * In case the received buffer does not contain the data in SKB format, + * the function creates a blank SKB, fills it with the data from the + * received buffer and then sends this new SKB to the kernel. + */ +int mwifiex_recv_packet(struct mwifiex_adapter *adapter, struct sk_buff *skb) +{ + struct mwifiex_rxinfo *rx_info = NULL; + struct mwifiex_private *priv = NULL; + + if (!skb) + return -1; + + rx_info = MWIFIEX_SKB_RXCB(skb); + priv = mwifiex_bss_index_to_priv(adapter, rx_info->bss_index); + if (!priv) + return -1; + + skb->dev = priv->netdev; + skb->protocol = eth_type_trans(skb, priv->netdev); + skb->ip_summed = CHECKSUM_NONE; + priv->stats.rx_bytes += skb->len; + priv->stats.rx_packets++; + if (in_interrupt()) + netif_rx(skb); + else + netif_rx_ni(skb); + + return 0; +} + +/* + * Receive packet completion callback handler. + * + * This function updates the statistics and frees the buffer SKB. + */ +int mwifiex_recv_complete(struct mwifiex_adapter *adapter, + struct sk_buff *skb, int status) +{ + struct mwifiex_private *priv = NULL; + struct mwifiex_rxinfo *rx_info = NULL; + + if (!skb) + return 0; + + rx_info = MWIFIEX_SKB_RXCB(skb); + priv = mwifiex_bss_index_to_priv(adapter, rx_info->bss_index); + + if (priv && (status == -1)) + priv->stats.rx_dropped++; + + dev_kfree_skb_any(skb); + + return 0; +} + +/* + * IOCTL completion callback handler. + * + * This function is called when a pending IOCTL is completed. + * + * If work queue support is enabled, the function wakes up the + * corresponding waiting function. Otherwise, it processes the + * IOCTL response and frees the response buffer. + */ +int mwifiex_ioctl_complete(struct mwifiex_adapter *adapter, + struct mwifiex_wait_queue *wait_queue, + int status) +{ + enum mwifiex_error_code status_code = + (enum mwifiex_error_code) wait_queue->status; + + atomic_dec(&adapter->ioctl_pending); + + dev_dbg(adapter->dev, "cmd: IOCTL completed: status=%d," + " status_code=%#x\n", status, status_code); + + if (wait_queue->enabled) { + *wait_queue->condition = true; + wait_queue->status = status; + if (status && (status_code == MWIFIEX_ERROR_CMD_TIMEOUT)) + dev_err(adapter->dev, "cmd timeout\n"); + else + wake_up_interruptible(wait_queue->wait); + } else { + if (status) + dev_err(adapter->dev, "cmd failed: status_code=%#x\n", + status_code); + kfree(wait_queue); + } + + return 0; +} diff --git a/drivers/net/wireless/mwifiex/util.h b/drivers/net/wireless/mwifiex/util.h new file mode 100644 index 000000000000..9506afc6c0e4 --- /dev/null +++ b/drivers/net/wireless/mwifiex/util.h @@ -0,0 +1,32 @@ +/* + * Marvell Wireless LAN device driver: utility functions + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#ifndef _MWIFIEX_UTIL_H_ +#define _MWIFIEX_UTIL_H_ + +static inline struct mwifiex_rxinfo *MWIFIEX_SKB_RXCB(struct sk_buff *skb) +{ + return (struct mwifiex_rxinfo *)skb->cb; +} + +static inline struct mwifiex_txinfo *MWIFIEX_SKB_TXCB(struct sk_buff *skb) +{ + return (struct mwifiex_txinfo *)skb->cb; +} +#endif /* !_MWIFIEX_UTIL_H_ */ diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c new file mode 100644 index 000000000000..1cfbc6bed692 --- /dev/null +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -0,0 +1,1237 @@ +/* + * Marvell Wireless LAN device driver: WMM + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" + + +/* Maximum value FW can accept for driver delay in packet transmission */ +#define DRV_PKT_DELAY_TO_FW_MAX 512 + + +#define WMM_QUEUED_PACKET_LOWER_LIMIT 180 + +#define WMM_QUEUED_PACKET_UPPER_LIMIT 200 + +/* Offset for TOS field in the IP header */ +#define IPTOS_OFFSET 5 + +/* WMM information IE */ +static const u8 wmm_info_ie[] = { WLAN_EID_VENDOR_SPECIFIC, 0x07, + 0x00, 0x50, 0xf2, 0x02, + 0x00, 0x01, 0x00 +}; + +static const u8 wmm_aci_to_qidx_map[] = { WMM_AC_BE, + WMM_AC_BK, + WMM_AC_VI, + WMM_AC_VO +}; + +static u8 tos_to_tid[] = { + /* TID DSCP_P2 DSCP_P1 DSCP_P0 WMM_AC */ + 0x01, /* 0 1 0 AC_BK */ + 0x02, /* 0 0 0 AC_BK */ + 0x00, /* 0 0 1 AC_BE */ + 0x03, /* 0 1 1 AC_BE */ + 0x04, /* 1 0 0 AC_VI */ + 0x05, /* 1 0 1 AC_VI */ + 0x06, /* 1 1 0 AC_VO */ + 0x07 /* 1 1 1 AC_VO */ +}; + +/* + * This table inverses the tos_to_tid operation to get a priority + * which is in sequential order, and can be compared. + * Use this to compare the priority of two different TIDs. + */ +static u8 tos_to_tid_inv[] = { + 0x02, /* from tos_to_tid[2] = 0 */ + 0x00, /* from tos_to_tid[0] = 1 */ + 0x01, /* from tos_to_tid[1] = 2 */ + 0x03, + 0x04, + 0x05, + 0x06, + 0x07}; + +static u8 ac_to_tid[4][2] = { {1, 2}, {0, 3}, {4, 5}, {6, 7} }; + +/* + * This function debug prints the priority parameters for a WMM AC. + */ +static void +mwifiex_wmm_ac_debug_print(const struct ieee_types_wmm_ac_parameters *ac_param) +{ + const char *ac_str[] = { "BK", "BE", "VI", "VO" }; + + pr_debug("info: WMM AC_%s: ACI=%d, ACM=%d, Aifsn=%d, " + "EcwMin=%d, EcwMax=%d, TxopLimit=%d\n", + ac_str[wmm_aci_to_qidx_map[(ac_param->aci_aifsn_bitmap + & MWIFIEX_ACI) >> 5]], + (ac_param->aci_aifsn_bitmap & MWIFIEX_ACI) >> 5, + (ac_param->aci_aifsn_bitmap & MWIFIEX_ACM) >> 4, + ac_param->aci_aifsn_bitmap & MWIFIEX_AIFSN, + ac_param->ecw_bitmap & MWIFIEX_ECW_MIN, + (ac_param->ecw_bitmap & MWIFIEX_ECW_MAX) >> 4, + le16_to_cpu(ac_param->tx_op_limit)); +} + +/* + * This function allocates a route address list. + * + * The function also initializes the list with the provided RA. + */ +static struct mwifiex_ra_list_tbl * +mwifiex_wmm_allocate_ralist_node(struct mwifiex_adapter *adapter, u8 *ra) +{ + struct mwifiex_ra_list_tbl *ra_list; + + ra_list = kzalloc(sizeof(struct mwifiex_ra_list_tbl), GFP_ATOMIC); + + if (!ra_list) { + dev_err(adapter->dev, "%s: failed to alloc ra_list\n", + __func__); + return NULL; + } + INIT_LIST_HEAD(&ra_list->list); + skb_queue_head_init(&ra_list->skb_head); + + memcpy(ra_list->ra, ra, ETH_ALEN); + + ra_list->total_pkts_size = 0; + + dev_dbg(adapter->dev, "info: allocated ra_list %p\n", ra_list); + + return ra_list; +} + +/* + * This function allocates and adds a RA list for all TIDs + * with the given RA. + */ +void +mwifiex_ralist_add(struct mwifiex_private *priv, u8 *ra) +{ + int i; + struct mwifiex_ra_list_tbl *ra_list; + struct mwifiex_adapter *adapter = priv->adapter; + + for (i = 0; i < MAX_NUM_TID; ++i) { + ra_list = mwifiex_wmm_allocate_ralist_node(adapter, ra); + dev_dbg(adapter->dev, "info: created ra_list %p\n", ra_list); + + if (!ra_list) + break; + + if (!mwifiex_queuing_ra_based(priv)) + ra_list->is_11n_enabled = IS_11N_ENABLED(priv); + else + ra_list->is_11n_enabled = false; + + dev_dbg(adapter->dev, "data: ralist %p: is_11n_enabled=%d\n", + ra_list, ra_list->is_11n_enabled); + + list_add_tail(&ra_list->list, + &priv->wmm.tid_tbl_ptr[i].ra_list); + + if (!priv->wmm.tid_tbl_ptr[i].ra_list_curr) + priv->wmm.tid_tbl_ptr[i].ra_list_curr = ra_list; + } +} + +/* + * This function sets the WMM queue priorities to their default values. + */ +static void mwifiex_wmm_default_queue_priorities(struct mwifiex_private *priv) +{ + /* Default queue priorities: VO->VI->BE->BK */ + priv->wmm.queue_priority[0] = WMM_AC_VO; + priv->wmm.queue_priority[1] = WMM_AC_VI; + priv->wmm.queue_priority[2] = WMM_AC_BE; + priv->wmm.queue_priority[3] = WMM_AC_BK; +} + +/* + * This function map ACs to TIDs. + */ +static void +mwifiex_wmm_queue_priorities_tid(struct mwifiex_private *priv, + u8 queue_priority[]) +{ + int i; + + for (i = 0; i < 4; ++i) { + tos_to_tid[7 - (i * 2)] = ac_to_tid[queue_priority[i]][1]; + tos_to_tid[6 - (i * 2)] = ac_to_tid[queue_priority[i]][0]; + } +} + +/* + * This function initializes WMM priority queues. + */ +void +mwifiex_wmm_setup_queue_priorities(struct mwifiex_private *priv, + struct ieee_types_wmm_parameter *wmm_ie) +{ + u16 cw_min, avg_back_off, tmp[4]; + u32 i, j, num_ac; + u8 ac_idx; + + if (!wmm_ie || !priv->wmm_enabled) { + /* WMM is not enabled, just set the defaults and return */ + mwifiex_wmm_default_queue_priorities(priv); + return; + } + + dev_dbg(priv->adapter->dev, "info: WMM Parameter IE: version=%d, " + "qos_info Parameter Set Count=%d, Reserved=%#x\n", + wmm_ie->vend_hdr.version, wmm_ie->qos_info_bitmap & + IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK, + wmm_ie->reserved); + + for (num_ac = 0; num_ac < ARRAY_SIZE(wmm_ie->ac_params); num_ac++) { + cw_min = (1 << (wmm_ie->ac_params[num_ac].ecw_bitmap & + MWIFIEX_ECW_MIN)) - 1; + avg_back_off = (cw_min >> 1) + + (wmm_ie->ac_params[num_ac].aci_aifsn_bitmap & + MWIFIEX_AIFSN); + + ac_idx = wmm_aci_to_qidx_map[(wmm_ie->ac_params[num_ac]. + aci_aifsn_bitmap & + MWIFIEX_ACI) >> 5]; + priv->wmm.queue_priority[ac_idx] = ac_idx; + tmp[ac_idx] = avg_back_off; + + dev_dbg(priv->adapter->dev, "info: WMM: CWmax=%d CWmin=%d Avg Back-off=%d\n", + (1 << ((wmm_ie->ac_params[num_ac].ecw_bitmap & + MWIFIEX_ECW_MAX) >> 4)) - 1, + cw_min, avg_back_off); + mwifiex_wmm_ac_debug_print(&wmm_ie->ac_params[num_ac]); + } + + /* Bubble sort */ + for (i = 0; i < num_ac; i++) { + for (j = 1; j < num_ac - i; j++) { + if (tmp[j - 1] > tmp[j]) { + swap(tmp[j - 1], tmp[j]); + swap(priv->wmm.queue_priority[j - 1], + priv->wmm.queue_priority[j]); + } else if (tmp[j - 1] == tmp[j]) { + if (priv->wmm.queue_priority[j - 1] + < priv->wmm.queue_priority[j]) + swap(priv->wmm.queue_priority[j - 1], + priv->wmm.queue_priority[j]); + } + } + } + + mwifiex_wmm_queue_priorities_tid(priv, priv->wmm.queue_priority); +} + +/* + * This function evaluates whether or not an AC is to be downgraded. + * + * In case the AC is not enabled, the highest AC is returned that is + * enabled and does not require admission control. + */ +static enum mwifiex_wmm_ac_e +mwifiex_wmm_eval_downgrade_ac(struct mwifiex_private *priv, + enum mwifiex_wmm_ac_e eval_ac) +{ + int down_ac; + enum mwifiex_wmm_ac_e ret_ac; + struct mwifiex_wmm_ac_status *ac_status; + + ac_status = &priv->wmm.ac_status[eval_ac]; + + if (!ac_status->disabled) + /* Okay to use this AC, its enabled */ + return eval_ac; + + /* Setup a default return value of the lowest priority */ + ret_ac = WMM_AC_BK; + + /* + * Find the highest AC that is enabled and does not require + * admission control. The spec disallows downgrading to an AC, + * which is enabled due to a completed admission control. + * Unadmitted traffic is not to be sent on an AC with admitted + * traffic. + */ + for (down_ac = WMM_AC_BK; down_ac < eval_ac; down_ac++) { + ac_status = &priv->wmm.ac_status[down_ac]; + + if (!ac_status->disabled && !ac_status->flow_required) + /* AC is enabled and does not require admission + control */ + ret_ac = (enum mwifiex_wmm_ac_e) down_ac; + } + + return ret_ac; +} + +/* + * This function downgrades WMM priority queue. + */ +void +mwifiex_wmm_setup_ac_downgrade(struct mwifiex_private *priv) +{ + int ac_val; + + dev_dbg(priv->adapter->dev, "info: WMM: AC Priorities:" + "BK(0), BE(1), VI(2), VO(3)\n"); + + if (!priv->wmm_enabled) { + /* WMM is not enabled, default priorities */ + for (ac_val = WMM_AC_BK; ac_val <= WMM_AC_VO; ac_val++) + priv->wmm.ac_down_graded_vals[ac_val] = + (enum mwifiex_wmm_ac_e) ac_val; + } else { + for (ac_val = WMM_AC_BK; ac_val <= WMM_AC_VO; ac_val++) { + priv->wmm.ac_down_graded_vals[ac_val] + = mwifiex_wmm_eval_downgrade_ac(priv, + (enum mwifiex_wmm_ac_e) ac_val); + dev_dbg(priv->adapter->dev, "info: WMM: AC PRIO %d maps to %d\n", + ac_val, priv->wmm.ac_down_graded_vals[ac_val]); + } + } +} + +/* + * This function converts the IP TOS field to an WMM AC + * Queue assignment. + */ +static enum mwifiex_wmm_ac_e +mwifiex_wmm_convert_tos_to_ac(struct mwifiex_adapter *adapter, u32 tos) +{ + /* Map of TOS UP values to WMM AC */ + const enum mwifiex_wmm_ac_e tos_to_ac[] = { WMM_AC_BE, + WMM_AC_BK, + WMM_AC_BK, + WMM_AC_BE, + WMM_AC_VI, + WMM_AC_VI, + WMM_AC_VO, + WMM_AC_VO + }; + + if (tos >= ARRAY_SIZE(tos_to_ac)) + return WMM_AC_BE; + + return tos_to_ac[tos]; +} + +/* + * This function evaluates a given TID and downgrades it to a lower + * TID if the WMM Parameter IE received from the AP indicates that the + * AP is disabled (due to call admission control (ACM bit). Mapping + * of TID to AC is taken care of internally. + */ +static u8 +mwifiex_wmm_downgrade_tid(struct mwifiex_private *priv, u32 tid) +{ + enum mwifiex_wmm_ac_e ac, ac_down; + u8 new_tid; + + ac = mwifiex_wmm_convert_tos_to_ac(priv->adapter, tid); + ac_down = priv->wmm.ac_down_graded_vals[ac]; + + /* Send the index to tid array, picking from the array will be + * taken care by dequeuing function + */ + new_tid = ac_to_tid[ac_down][tid % 2]; + + return new_tid; +} + +/* + * This function initializes the WMM state information and the + * WMM data path queues. + */ +void +mwifiex_wmm_init(struct mwifiex_adapter *adapter) +{ + int i, j; + struct mwifiex_private *priv; + + for (j = 0; j < adapter->priv_num; ++j) { + priv = adapter->priv[j]; + if (!priv) + continue; + + for (i = 0; i < MAX_NUM_TID; ++i) { + priv->aggr_prio_tbl[i].amsdu = tos_to_tid_inv[i]; + priv->aggr_prio_tbl[i].ampdu_ap = tos_to_tid_inv[i]; + priv->aggr_prio_tbl[i].ampdu_user = tos_to_tid_inv[i]; + priv->wmm.tid_tbl_ptr[i].ra_list_curr = NULL; + } + + priv->aggr_prio_tbl[6].amsdu + = priv->aggr_prio_tbl[6].ampdu_ap + = priv->aggr_prio_tbl[6].ampdu_user + = BA_STREAM_NOT_ALLOWED; + + priv->aggr_prio_tbl[7].amsdu = priv->aggr_prio_tbl[7].ampdu_ap + = priv->aggr_prio_tbl[7].ampdu_user + = BA_STREAM_NOT_ALLOWED; + + priv->add_ba_param.timeout = MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT; + priv->add_ba_param.tx_win_size = MWIFIEX_AMPDU_DEF_TXWINSIZE; + priv->add_ba_param.rx_win_size = MWIFIEX_AMPDU_DEF_RXWINSIZE; + } +} + +/* + * This function checks if WMM Tx queue is empty. + */ +int +mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter) +{ + int i, j; + struct mwifiex_private *priv; + + for (j = 0; j < adapter->priv_num; ++j) { + priv = adapter->priv[j]; + if (priv) { + for (i = 0; i < MAX_NUM_TID; i++) + if (!mwifiex_wmm_is_ra_list_empty(adapter, + &priv->wmm.tid_tbl_ptr[i].ra_list)) + return false; + } + } + + return true; +} + +/* + * This function deletes all packets in an RA list node. + * + * The packet sent completion callback handler are called with + * status failure, after they are dequeued to ensure proper + * cleanup. The RA list node itself is freed at the end. + */ +static void +mwifiex_wmm_del_pkts_in_ralist_node(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *ra_list) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct sk_buff *skb, *tmp; + + skb_queue_walk_safe(&ra_list->skb_head, skb, tmp) + mwifiex_write_data_complete(adapter, skb, -1); +} + +/* + * This function deletes all packets in an RA list. + * + * Each nodes in the RA list are freed individually first, and then + * the RA list itself is freed. + */ +static void +mwifiex_wmm_del_pkts_in_ralist(struct mwifiex_private *priv, + struct list_head *ra_list_head) +{ + struct mwifiex_ra_list_tbl *ra_list; + + list_for_each_entry(ra_list, ra_list_head, list) + mwifiex_wmm_del_pkts_in_ralist_node(priv, ra_list); +} + +/* + * This function deletes all packets in all RA lists. + */ +static void mwifiex_wmm_cleanup_queues(struct mwifiex_private *priv) +{ + int i; + + for (i = 0; i < MAX_NUM_TID; i++) + mwifiex_wmm_del_pkts_in_ralist(priv, &priv->wmm.tid_tbl_ptr[i]. + ra_list); +} + +/* + * This function deletes all route addresses from all RA lists. + */ +static void mwifiex_wmm_delete_all_ralist(struct mwifiex_private *priv) +{ + struct mwifiex_ra_list_tbl *ra_list, *tmp_node; + int i; + + for (i = 0; i < MAX_NUM_TID; ++i) { + dev_dbg(priv->adapter->dev, + "info: ra_list: freeing buf for tid %d\n", i); + list_for_each_entry_safe(ra_list, tmp_node, + &priv->wmm.tid_tbl_ptr[i].ra_list, list) { + list_del(&ra_list->list); + kfree(ra_list); + } + + INIT_LIST_HEAD(&priv->wmm.tid_tbl_ptr[i].ra_list); + + priv->wmm.tid_tbl_ptr[i].ra_list_curr = NULL; + } +} + +/* + * This function cleans up the Tx and Rx queues. + * + * Cleanup includes - + * - All packets in RA lists + * - All entries in Rx reorder table + * - All entries in Tx BA stream table + * - MPA buffer (if required) + * - All RA lists + */ +void +mwifiex_clean_txrx(struct mwifiex_private *priv) +{ + unsigned long flags; + + mwifiex_11n_cleanup_reorder_tbl(priv); + spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags); + + mwifiex_wmm_cleanup_queues(priv); + mwifiex_11n_delete_all_tx_ba_stream_tbl(priv); + + if (priv->adapter->if_ops.cleanup_mpa_buf) + priv->adapter->if_ops.cleanup_mpa_buf(priv->adapter); + + mwifiex_wmm_delete_all_ralist(priv); + memcpy(tos_to_tid, ac_to_tid, sizeof(tos_to_tid)); + + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); +} + +/* + * This function retrieves a particular RA list node, matching with the + * given TID and RA address. + */ +static struct mwifiex_ra_list_tbl * +mwifiex_wmm_get_ralist_node(struct mwifiex_private *priv, u8 tid, + u8 *ra_addr) +{ + struct mwifiex_ra_list_tbl *ra_list; + + list_for_each_entry(ra_list, &priv->wmm.tid_tbl_ptr[tid].ra_list, + list) { + if (!memcmp(ra_list->ra, ra_addr, ETH_ALEN)) + return ra_list; + } + + return NULL; +} + +/* + * This function retrieves an RA list node for a given TID and + * RA address pair. + * + * If no such node is found, a new node is added first and then + * retrieved. + */ +static struct mwifiex_ra_list_tbl * +mwifiex_wmm_get_queue_raptr(struct mwifiex_private *priv, u8 tid, u8 *ra_addr) +{ + struct mwifiex_ra_list_tbl *ra_list; + + ra_list = mwifiex_wmm_get_ralist_node(priv, tid, ra_addr); + if (ra_list) + return ra_list; + mwifiex_ralist_add(priv, ra_addr); + + return mwifiex_wmm_get_ralist_node(priv, tid, ra_addr); +} + +/* + * This function checks if a particular RA list node exists in a given TID + * table index. + */ +int +mwifiex_is_ralist_valid(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *ra_list, int ptr_index) +{ + struct mwifiex_ra_list_tbl *rlist; + + list_for_each_entry(rlist, &priv->wmm.tid_tbl_ptr[ptr_index].ra_list, + list) { + if (rlist == ra_list) + return true; + } + + return false; +} + +/* + * This function adds a packet to WMM queue. + * + * In disconnected state the packet is immediately dropped and the + * packet send completion callback is called with status failure. + * + * Otherwise, the correct RA list node is located and the packet + * is queued at the list tail. + */ +void +mwifiex_wmm_add_buf_txqueue(struct mwifiex_adapter *adapter, + struct sk_buff *skb) +{ + struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb); + struct mwifiex_private *priv = adapter->priv[tx_info->bss_index]; + u32 tid; + struct mwifiex_ra_list_tbl *ra_list; + u8 ra[ETH_ALEN], tid_down; + unsigned long flags; + + if (!priv->media_connected) { + dev_dbg(adapter->dev, "data: drop packet in disconnect\n"); + mwifiex_write_data_complete(adapter, skb, -1); + return; + } + + tid = skb->priority; + + spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags); + + tid_down = mwifiex_wmm_downgrade_tid(priv, tid); + + /* In case of infra as we have already created the list during + association we just don't have to call get_queue_raptr, we will + have only 1 raptr for a tid in case of infra */ + if (!mwifiex_queuing_ra_based(priv)) { + if (!list_empty(&priv->wmm.tid_tbl_ptr[tid_down].ra_list)) + ra_list = list_first_entry( + &priv->wmm.tid_tbl_ptr[tid_down].ra_list, + struct mwifiex_ra_list_tbl, list); + else + ra_list = NULL; + } else { + memcpy(ra, skb->data, ETH_ALEN); + ra_list = mwifiex_wmm_get_queue_raptr(priv, tid_down, ra); + } + + if (!ra_list) { + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); + mwifiex_write_data_complete(adapter, skb, -1); + return; + } + + skb_queue_tail(&ra_list->skb_head, skb); + + ra_list->total_pkts_size += skb->len; + + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); +} + +/* + * This function processes the get WMM status command response from firmware. + * + * The response may contain multiple TLVs - + * - AC Queue status TLVs + * - Current WMM Parameter IE TLV + * - Admission Control action frame TLVs + * + * This function parses the TLVs and then calls further specific functions + * to process any changes in the queue prioritize or state. + */ +int mwifiex_ret_wmm_get_status(struct mwifiex_private *priv, + const struct host_cmd_ds_command *resp) +{ + u8 *curr = (u8 *) &resp->params.get_wmm_status; + uint16_t resp_len = le16_to_cpu(resp->size), tlv_len; + int valid = true; + + struct mwifiex_ie_types_data *tlv_hdr; + struct mwifiex_ie_types_wmm_queue_status *tlv_wmm_qstatus; + struct ieee_types_wmm_parameter *wmm_param_ie = NULL; + struct mwifiex_wmm_ac_status *ac_status; + + dev_dbg(priv->adapter->dev, "info: WMM: WMM_GET_STATUS cmdresp received: %d\n", + resp_len); + + while ((resp_len >= sizeof(tlv_hdr->header)) && valid) { + tlv_hdr = (struct mwifiex_ie_types_data *) curr; + tlv_len = le16_to_cpu(tlv_hdr->header.len); + + switch (le16_to_cpu(tlv_hdr->header.type)) { + case TLV_TYPE_WMMQSTATUS: + tlv_wmm_qstatus = + (struct mwifiex_ie_types_wmm_queue_status *) + tlv_hdr; + dev_dbg(priv->adapter->dev, + "info: CMD_RESP: WMM_GET_STATUS:" + " QSTATUS TLV: %d, %d, %d\n", + tlv_wmm_qstatus->queue_index, + tlv_wmm_qstatus->flow_required, + tlv_wmm_qstatus->disabled); + + ac_status = &priv->wmm.ac_status[tlv_wmm_qstatus-> + queue_index]; + ac_status->disabled = tlv_wmm_qstatus->disabled; + ac_status->flow_required = + tlv_wmm_qstatus->flow_required; + ac_status->flow_created = tlv_wmm_qstatus->flow_created; + break; + + case WLAN_EID_VENDOR_SPECIFIC: + /* + * Point the regular IEEE IE 2 bytes into the Marvell IE + * and setup the IEEE IE type and length byte fields + */ + + wmm_param_ie = + (struct ieee_types_wmm_parameter *) (curr + + 2); + wmm_param_ie->vend_hdr.len = (u8) tlv_len; + wmm_param_ie->vend_hdr.element_id = + WLAN_EID_VENDOR_SPECIFIC; + + dev_dbg(priv->adapter->dev, + "info: CMD_RESP: WMM_GET_STATUS:" + " WMM Parameter Set Count: %d\n", + wmm_param_ie->qos_info_bitmap & + IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK); + + memcpy((u8 *) &priv->curr_bss_params.bss_descriptor. + wmm_ie, wmm_param_ie, + wmm_param_ie->vend_hdr.len + 2); + + break; + + default: + valid = false; + break; + } + + curr += (tlv_len + sizeof(tlv_hdr->header)); + resp_len -= (tlv_len + sizeof(tlv_hdr->header)); + } + + mwifiex_wmm_setup_queue_priorities(priv, wmm_param_ie); + mwifiex_wmm_setup_ac_downgrade(priv); + + return 0; +} + +/* + * Callback handler from the command module to allow insertion of a WMM TLV. + * + * If the BSS we are associating to supports WMM, this function adds the + * required WMM Information IE to the association request command buffer in + * the form of a Marvell extended IEEE IE. + */ +u32 +mwifiex_wmm_process_association_req(struct mwifiex_private *priv, + u8 **assoc_buf, + struct ieee_types_wmm_parameter *wmm_ie, + struct ieee80211_ht_cap *ht_cap) +{ + struct mwifiex_ie_types_wmm_param_set *wmm_tlv; + u32 ret_len = 0; + + /* Null checks */ + if (!assoc_buf) + return 0; + if (!(*assoc_buf)) + return 0; + + if (!wmm_ie) + return 0; + + dev_dbg(priv->adapter->dev, "info: WMM: process assoc req:" + "bss->wmmIe=0x%x\n", + wmm_ie->vend_hdr.element_id); + + if ((priv->wmm_required + || (ht_cap && (priv->adapter->config_bands & BAND_GN + || priv->adapter->config_bands & BAND_AN)) + ) + && wmm_ie->vend_hdr.element_id == WLAN_EID_VENDOR_SPECIFIC) { + wmm_tlv = (struct mwifiex_ie_types_wmm_param_set *) *assoc_buf; + wmm_tlv->header.type = cpu_to_le16((u16) wmm_info_ie[0]); + wmm_tlv->header.len = cpu_to_le16((u16) wmm_info_ie[1]); + memcpy(wmm_tlv->wmm_ie, &wmm_info_ie[2], + le16_to_cpu(wmm_tlv->header.len)); + if (wmm_ie->qos_info_bitmap & IEEE80211_WMM_IE_AP_QOSINFO_UAPSD) + memcpy((u8 *) (wmm_tlv->wmm_ie + + le16_to_cpu(wmm_tlv->header.len) + - sizeof(priv->wmm_qosinfo)), + &priv->wmm_qosinfo, + sizeof(priv->wmm_qosinfo)); + + ret_len = sizeof(wmm_tlv->header) + + le16_to_cpu(wmm_tlv->header.len); + + *assoc_buf += ret_len; + } + + return ret_len; +} + +/* + * This function computes the time delay in the driver queues for a + * given packet. + * + * When the packet is received at the OS/Driver interface, the current + * time is set in the packet structure. The difference between the present + * time and that received time is computed in this function and limited + * based on pre-compiled limits in the driver. + */ +u8 +mwifiex_wmm_compute_drv_pkt_delay(struct mwifiex_private *priv, + const struct sk_buff *skb) +{ + u8 ret_val = 0; + struct timeval out_tstamp, in_tstamp; + u32 queue_delay; + + do_gettimeofday(&out_tstamp); + in_tstamp = ktime_to_timeval(skb->tstamp); + + queue_delay = (out_tstamp.tv_sec - in_tstamp.tv_sec) * 1000; + queue_delay += (out_tstamp.tv_usec - in_tstamp.tv_usec) / 1000; + + /* + * Queue delay is passed as a uint8 in units of 2ms (ms shifted + * by 1). Min value (other than 0) is therefore 2ms, max is 510ms. + * + * Pass max value if queue_delay is beyond the uint8 range + */ + ret_val = (u8) (min(queue_delay, priv->wmm.drv_pkt_delay_max) >> 1); + + dev_dbg(priv->adapter->dev, "data: WMM: Pkt Delay: %d ms," + " %d ms sent to FW\n", queue_delay, ret_val); + + return ret_val; +} + +/* + * This function retrieves the highest priority RA list table pointer. + */ +static struct mwifiex_ra_list_tbl * +mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter, + struct mwifiex_private **priv, int *tid) +{ + struct mwifiex_private *priv_tmp; + struct mwifiex_ra_list_tbl *ptr, *head; + struct mwifiex_bss_prio_node *bssprio_node, *bssprio_head; + struct mwifiex_tid_tbl *tid_ptr; + int is_list_empty; + unsigned long flags; + int i, j; + + for (j = adapter->priv_num - 1; j >= 0; --j) { + spin_lock_irqsave(&adapter->bss_prio_tbl[j].bss_prio_lock, + flags); + is_list_empty = list_empty(&adapter->bss_prio_tbl[j] + .bss_prio_head); + spin_unlock_irqrestore(&adapter->bss_prio_tbl[j].bss_prio_lock, + flags); + if (is_list_empty) + continue; + + if (adapter->bss_prio_tbl[j].bss_prio_cur == + (struct mwifiex_bss_prio_node *) + &adapter->bss_prio_tbl[j].bss_prio_head) { + bssprio_node = + list_first_entry(&adapter->bss_prio_tbl[j] + .bss_prio_head, + struct mwifiex_bss_prio_node, + list); + bssprio_head = bssprio_node; + } else { + bssprio_node = adapter->bss_prio_tbl[j].bss_prio_cur; + bssprio_head = bssprio_node; + } + + do { + priv_tmp = bssprio_node->priv; + + for (i = HIGH_PRIO_TID; i >= LOW_PRIO_TID; --i) { + + tid_ptr = &(priv_tmp)->wmm. + tid_tbl_ptr[tos_to_tid[i]]; + + spin_lock_irqsave(&tid_ptr->tid_tbl_lock, + flags); + is_list_empty = + list_empty(&adapter->bss_prio_tbl[j] + .bss_prio_head); + spin_unlock_irqrestore(&tid_ptr->tid_tbl_lock, + flags); + if (is_list_empty) + continue; + + /* + * Always choose the next ra we transmitted + * last time, this way we pick the ra's in + * round robin fashion. + */ + ptr = list_first_entry( + &tid_ptr->ra_list_curr->list, + struct mwifiex_ra_list_tbl, + list); + + head = ptr; + if (ptr == (struct mwifiex_ra_list_tbl *) + &tid_ptr->ra_list) { + /* Get next ra */ + ptr = list_first_entry(&ptr->list, + struct mwifiex_ra_list_tbl, list); + head = ptr; + } + + do { + is_list_empty = + skb_queue_empty(&ptr->skb_head); + if (!is_list_empty) { + *priv = priv_tmp; + *tid = tos_to_tid[i]; + return ptr; + } + /* Get next ra */ + ptr = list_first_entry(&ptr->list, + struct mwifiex_ra_list_tbl, + list); + if (ptr == + (struct mwifiex_ra_list_tbl *) + &tid_ptr->ra_list) + ptr = list_first_entry( + &ptr->list, + struct mwifiex_ra_list_tbl, + list); + } while (ptr != head); + } + + /* Get next bss priority node */ + bssprio_node = list_first_entry(&bssprio_node->list, + struct mwifiex_bss_prio_node, + list); + + if (bssprio_node == + (struct mwifiex_bss_prio_node *) + &adapter->bss_prio_tbl[j].bss_prio_head) + /* Get next bss priority node */ + bssprio_node = list_first_entry( + &bssprio_node->list, + struct mwifiex_bss_prio_node, + list); + } while (bssprio_node != bssprio_head); + } + return NULL; +} + +/* + * This function gets the number of packets in the Tx queue of a + * particular RA list. + */ +static int +mwifiex_num_pkts_in_txq(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *ptr, int max_buf_size) +{ + int count = 0, total_size = 0; + struct sk_buff *skb, *tmp; + + skb_queue_walk_safe(&ptr->skb_head, skb, tmp) { + total_size += skb->len; + if (total_size < max_buf_size) + ++count; + else + break; + } + + return count; +} + +/* + * This function sends a single packet to firmware for transmission. + */ +static void +mwifiex_send_single_packet(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *ptr, int ptr_index, + unsigned long ra_list_flags) + __releases(&priv->wmm.ra_list_spinlock) +{ + struct sk_buff *skb, *skb_next; + struct mwifiex_tx_param tx_param; + struct mwifiex_adapter *adapter = priv->adapter; + int status = 0; + struct mwifiex_txinfo *tx_info; + + if (skb_queue_empty(&ptr->skb_head)) { + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + dev_dbg(adapter->dev, "data: nothing to send\n"); + return; + } + + skb = skb_dequeue(&ptr->skb_head); + + tx_info = MWIFIEX_SKB_TXCB(skb); + dev_dbg(adapter->dev, "data: dequeuing the packet %p %p\n", ptr, skb); + + ptr->total_pkts_size -= skb->len; + + if (!skb_queue_empty(&ptr->skb_head)) + skb_next = skb_peek(&ptr->skb_head); + else + skb_next = NULL; + + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags); + + tx_param.next_pkt_len = ((skb_next) ? skb_next->len + + sizeof(struct txpd) : 0); + + status = mwifiex_process_tx(priv, skb, &tx_param); + + if (status == -EBUSY) { + /* Queue the packet back at the head */ + spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); + + if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) { + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + mwifiex_write_data_complete(adapter, skb, -1); + return; + } + + skb_queue_tail(&ptr->skb_head, skb); + + ptr->total_pkts_size += skb->len; + tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT; + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + } else { + spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); + if (mwifiex_is_ralist_valid(priv, ptr, ptr_index)) { + priv->wmm.packets_out[ptr_index]++; + priv->wmm.tid_tbl_ptr[ptr_index].ra_list_curr = ptr; + } + adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur = + list_first_entry( + &adapter->bss_prio_tbl[priv->bss_priority] + .bss_prio_cur->list, + struct mwifiex_bss_prio_node, + list); + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + } +} + +/* + * This function checks if the first packet in the given RA list + * is already processed or not. + */ +static int +mwifiex_is_ptr_processed(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *ptr) +{ + struct sk_buff *skb; + struct mwifiex_txinfo *tx_info; + + if (skb_queue_empty(&ptr->skb_head)) + return false; + + skb = skb_peek(&ptr->skb_head); + + tx_info = MWIFIEX_SKB_TXCB(skb); + if (tx_info->flags & MWIFIEX_BUF_FLAG_REQUEUED_PKT) + return true; + + return false; +} + +/* + * This function sends a single processed packet to firmware for + * transmission. + */ +static void +mwifiex_send_processed_packet(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *ptr, int ptr_index, + unsigned long ra_list_flags) + __releases(&priv->wmm.ra_list_spinlock) +{ + struct mwifiex_tx_param tx_param; + struct mwifiex_adapter *adapter = priv->adapter; + int ret = -1; + struct sk_buff *skb, *skb_next; + struct mwifiex_txinfo *tx_info; + + if (skb_queue_empty(&ptr->skb_head)) { + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + return; + } + + skb = skb_dequeue(&ptr->skb_head); + + if (!skb_queue_empty(&ptr->skb_head)) + skb_next = skb_peek(&ptr->skb_head); + else + skb_next = NULL; + + tx_info = MWIFIEX_SKB_TXCB(skb); + + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags); + tx_param.next_pkt_len = + ((skb_next) ? skb_next->len + + sizeof(struct txpd) : 0); + ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, + skb->data, skb->len, &tx_param); + switch (ret) { + case -EBUSY: + dev_dbg(adapter->dev, "data: -EBUSY is returned\n"); + spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); + + if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) { + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + mwifiex_write_data_complete(adapter, skb, -1); + return; + } + + skb_queue_tail(&ptr->skb_head, skb); + + tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT; + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + break; + case -1: + adapter->data_sent = false; + dev_err(adapter->dev, "host_to_card failed: %#x\n", ret); + adapter->dbg.num_tx_host_to_card_failure++; + mwifiex_write_data_complete(adapter, skb, ret); + break; + case -EINPROGRESS: + adapter->data_sent = false; + default: + break; + } + if (ret != -EBUSY) { + spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); + if (mwifiex_is_ralist_valid(priv, ptr, ptr_index)) { + priv->wmm.packets_out[ptr_index]++; + priv->wmm.tid_tbl_ptr[ptr_index].ra_list_curr = ptr; + } + adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur = + list_first_entry( + &adapter->bss_prio_tbl[priv->bss_priority] + .bss_prio_cur->list, + struct mwifiex_bss_prio_node, + list); + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + } +} + +/* + * This function dequeues a packet from the highest priority list + * and transmits it. + */ +static int +mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter) +{ + struct mwifiex_ra_list_tbl *ptr; + struct mwifiex_private *priv = NULL; + int ptr_index = 0; + u8 ra[ETH_ALEN]; + int tid_del = 0, tid = 0; + unsigned long flags; + + ptr = mwifiex_wmm_get_highest_priolist_ptr(adapter, &priv, &ptr_index); + if (!ptr) + return -1; + + tid = mwifiex_get_tid(priv->adapter, ptr); + + dev_dbg(adapter->dev, "data: tid=%d\n", tid); + + spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags); + if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) { + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); + return -1; + } + + if (mwifiex_is_ptr_processed(priv, ptr)) { + mwifiex_send_processed_packet(priv, ptr, ptr_index, flags); + /* ra_list_spinlock has been freed in + mwifiex_send_processed_packet() */ + return 0; + } + + if (!ptr->is_11n_enabled || mwifiex_is_ba_stream_setup(priv, ptr, tid) + || ((priv->sec_info.wpa_enabled + || priv->sec_info.wpa2_enabled) && !priv->wpa_is_gtk_set) + ) { + mwifiex_send_single_packet(priv, ptr, ptr_index, flags); + /* ra_list_spinlock has been freed in + mwifiex_send_single_packet() */ + } else { + if (mwifiex_is_ampdu_allowed(priv, ptr, tid)) { + if (mwifiex_is_ba_stream_avail(priv)) { + mwifiex_11n_create_tx_ba_stream_tbl(priv, + ptr->ra, tid, + BA_STREAM_SETUP_INPROGRESS); + mwifiex_send_addba(priv, tid, ptr->ra); + } else if (mwifiex_find_stream_to_delete + (priv, ptr, tid, &tid_del, ra)) { + mwifiex_11n_create_tx_ba_stream_tbl(priv, + ptr->ra, tid, + BA_STREAM_SETUP_INPROGRESS); + mwifiex_send_delba(priv, tid_del, ra, 1); + } + } +/* Minimum number of AMSDU */ +#define MIN_NUM_AMSDU 2 + if (mwifiex_is_amsdu_allowed(priv, ptr, tid) && + (mwifiex_num_pkts_in_txq(priv, ptr, adapter->tx_buf_size) >= + MIN_NUM_AMSDU)) + mwifiex_11n_aggregate_pkt(priv, ptr, INTF_HEADER_LEN, + ptr_index, flags); + /* ra_list_spinlock has been freed in + mwifiex_11n_aggregate_pkt() */ + else + mwifiex_send_single_packet(priv, ptr, ptr_index, flags); + /* ra_list_spinlock has been freed in + mwifiex_send_single_packet() */ + } + return 0; +} + +/* + * This function transmits the highest priority packet awaiting in the + * WMM Queues. + */ +void +mwifiex_wmm_process_tx(struct mwifiex_adapter *adapter) +{ + do { + /* Check if busy */ + if (adapter->data_sent || adapter->tx_lock_flag) + break; + + if (mwifiex_dequeue_tx_packet(adapter)) + break; + } while (true); + + return; +} diff --git a/drivers/net/wireless/mwifiex/wmm.h b/drivers/net/wireless/mwifiex/wmm.h new file mode 100644 index 000000000000..241f1b0b77f9 --- /dev/null +++ b/drivers/net/wireless/mwifiex/wmm.h @@ -0,0 +1,112 @@ +/* + * Marvell Wireless LAN device driver: WMM + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#ifndef _MWIFIEX_WMM_H_ +#define _MWIFIEX_WMM_H_ + +enum ieee_types_wmm_aciaifsn_bitmasks { + MWIFIEX_AIFSN = (BIT(0) | BIT(1) | BIT(2) | BIT(3)), + MWIFIEX_ACM = BIT(4), + MWIFIEX_ACI = (BIT(5) | BIT(6)), +}; + +enum ieee_types_wmm_ecw_bitmasks { + MWIFIEX_ECW_MIN = (BIT(0) | BIT(1) | BIT(2) | BIT(3)), + MWIFIEX_ECW_MAX = (BIT(4) | BIT(5) | BIT(6) | BIT(7)), +}; + +/* + * This function retrieves the TID of the given RA list. + */ +static inline int +mwifiex_get_tid(struct mwifiex_adapter *adapter, + struct mwifiex_ra_list_tbl *ptr) +{ + struct sk_buff *skb; + + if (skb_queue_empty(&ptr->skb_head)) + return 0; + + skb = skb_peek(&ptr->skb_head); + + return skb->priority; +} + +/* + * This function gets the length of a list. + */ +static inline int +mwifiex_wmm_list_len(struct mwifiex_adapter *adapter, struct list_head *head) +{ + struct list_head *pos; + int count = 0; + + list_for_each(pos, head) + ++count; + + return count; +} + +/* + * This function checks if a RA list is empty or not. + */ +static inline u8 +mwifiex_wmm_is_ra_list_empty(struct mwifiex_adapter *adapter, + struct list_head *ra_list_hhead) +{ + struct mwifiex_ra_list_tbl *ra_list; + int is_list_empty; + + list_for_each_entry(ra_list, ra_list_hhead, list) { + is_list_empty = skb_queue_empty(&ra_list->skb_head); + if (!is_list_empty) + return false; + } + + return true; +} + +void mwifiex_wmm_add_buf_txqueue(struct mwifiex_adapter *adapter, + struct sk_buff *skb); +void mwifiex_ralist_add(struct mwifiex_private *priv, u8 *ra); + +int mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter); +void mwifiex_wmm_process_tx(struct mwifiex_adapter *adapter); +int mwifiex_is_ralist_valid(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *ra_list, int tid); + +u8 mwifiex_wmm_compute_drv_pkt_delay(struct mwifiex_private *priv, + const struct sk_buff *skb); +void mwifiex_wmm_init(struct mwifiex_adapter *adapter); + +extern u32 mwifiex_wmm_process_association_req(struct mwifiex_private *priv, + u8 **assoc_buf, + struct ieee_types_wmm_parameter + *wmmie, + struct ieee80211_ht_cap + *htcap); + +void mwifiex_wmm_setup_queue_priorities(struct mwifiex_private *priv, + struct ieee_types_wmm_parameter + *wmm_ie); +void mwifiex_wmm_setup_ac_downgrade(struct mwifiex_private *priv); +extern int mwifiex_ret_wmm_get_status(struct mwifiex_private *priv, + const struct host_cmd_ds_command *resp); + +#endif /* !_MWIFIEX_WMM_H_ */ diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index c1ceb4b23971..8913180a7bd3 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -63,6 +63,7 @@ MODULE_PARM_DESC(ap_mode_default, #define MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL 0x00000c38 #define MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK 0x00000c3c #define MWL8K_A2H_INT_DUMMY (1 << 20) +#define MWL8K_A2H_INT_BA_WATCHDOG (1 << 14) #define MWL8K_A2H_INT_CHNL_SWITCHED (1 << 11) #define MWL8K_A2H_INT_QUEUE_EMPTY (1 << 10) #define MWL8K_A2H_INT_RADAR_DETECT (1 << 7) @@ -82,10 +83,14 @@ MODULE_PARM_DESC(ap_mode_default, MWL8K_A2H_INT_MAC_EVENT | \ MWL8K_A2H_INT_OPC_DONE | \ MWL8K_A2H_INT_RX_READY | \ - MWL8K_A2H_INT_TX_DONE) + MWL8K_A2H_INT_TX_DONE | \ + MWL8K_A2H_INT_BA_WATCHDOG) #define MWL8K_RX_QUEUES 1 -#define MWL8K_TX_QUEUES 4 +#define MWL8K_TX_WMM_QUEUES 4 +#define MWL8K_MAX_AMPDU_QUEUES 8 +#define MWL8K_MAX_TX_QUEUES (MWL8K_TX_WMM_QUEUES + MWL8K_MAX_AMPDU_QUEUES) +#define mwl8k_tx_queues(priv) (MWL8K_TX_WMM_QUEUES + (priv)->num_ampdu_queues) struct rxd_ops { int rxd_size; @@ -134,6 +139,21 @@ struct mwl8k_tx_queue { struct sk_buff **skb; }; +enum { + AMPDU_NO_STREAM, + AMPDU_STREAM_NEW, + AMPDU_STREAM_IN_PROGRESS, + AMPDU_STREAM_ACTIVE, +}; + +struct mwl8k_ampdu_stream { + struct ieee80211_sta *sta; + u8 tid; + u8 state; + u8 idx; + u8 txq_idx; /* index of this stream in priv->txq */ +}; + struct mwl8k_priv { struct ieee80211_hw *hw; struct pci_dev *pdev; @@ -160,6 +180,12 @@ struct mwl8k_priv { u32 ap_macids_supported; u32 sta_macids_supported; + /* Ampdu stream information */ + u8 num_ampdu_queues; + spinlock_t stream_lock; + struct mwl8k_ampdu_stream ampdu[MWL8K_MAX_AMPDU_QUEUES]; + struct work_struct watchdog_ba_handle; + /* firmware access */ struct mutex fw_mutex; struct task_struct *fw_mutex_owner; @@ -191,7 +217,8 @@ struct mwl8k_priv { int pending_tx_pkts; struct mwl8k_rx_queue rxq[MWL8K_RX_QUEUES]; - struct mwl8k_tx_queue txq[MWL8K_TX_QUEUES]; + struct mwl8k_tx_queue txq[MWL8K_MAX_TX_QUEUES]; + u32 txq_offset[MWL8K_MAX_TX_QUEUES]; bool radio_on; bool radio_short_preamble; @@ -224,7 +251,7 @@ struct mwl8k_priv { * preserve the queue configurations so they can be restored if/when * the firmware image is swapped. */ - struct ieee80211_tx_queue_params wmm_params[MWL8K_TX_QUEUES]; + struct ieee80211_tx_queue_params wmm_params[MWL8K_TX_WMM_QUEUES]; /* async firmware loading state */ unsigned fw_state; @@ -265,6 +292,7 @@ struct mwl8k_vif { struct mwl8k_sta { /* Index into station database. Returned by UPDATE_STADB. */ u8 peer_id; + u8 is_ampdu_allowed; }; #define MWL8K_STA(_sta) ((struct mwl8k_sta *)&((_sta)->drv_priv)) @@ -352,10 +380,12 @@ static const struct ieee80211_rate mwl8k_rates_50[] = { #define MWL8K_CMD_ENABLE_SNIFFER 0x0150 #define MWL8K_CMD_SET_MAC_ADDR 0x0202 /* per-vif */ #define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203 +#define MWL8K_CMD_GET_WATCHDOG_BITMAP 0x0205 #define MWL8K_CMD_BSS_START 0x1100 /* per-vif */ #define MWL8K_CMD_SET_NEW_STN 0x1111 /* per-vif */ #define MWL8K_CMD_UPDATE_ENCRYPTION 0x1122 /* per-vif */ #define MWL8K_CMD_UPDATE_STADB 0x1123 +#define MWL8K_CMD_BASTREAM 0x1125 static const char *mwl8k_cmd_name(__le16 cmd, char *buf, int bufsize) { @@ -395,6 +425,8 @@ static const char *mwl8k_cmd_name(__le16 cmd, char *buf, int bufsize) MWL8K_CMDNAME(SET_NEW_STN); MWL8K_CMDNAME(UPDATE_ENCRYPTION); MWL8K_CMDNAME(UPDATE_STADB); + MWL8K_CMDNAME(BASTREAM); + MWL8K_CMDNAME(GET_WATCHDOG_BITMAP); default: snprintf(buf, bufsize, "0x%x", cmd); } @@ -1127,6 +1159,9 @@ static void mwl8k_rxq_deinit(struct ieee80211_hw *hw, int index) struct mwl8k_rx_queue *rxq = priv->rxq + index; int i; + if (rxq->rxd == NULL) + return; + for (i = 0; i < MWL8K_RX_DESCS; i++) { if (rxq->buf[i].skb != NULL) { pci_unmap_single(priv->pdev, @@ -1319,7 +1354,7 @@ struct mwl8k_tx_desc { __le16 pkt_len; __u8 dest_MAC_addr[ETH_ALEN]; __le32 next_txd_phys_addr; - __le32 reserved; + __le32 timestamp; __le16 rate_info; __u8 peer_id; __u8 tx_frag_cnt; @@ -1383,7 +1418,7 @@ static void mwl8k_dump_tx_rings(struct ieee80211_hw *hw) struct mwl8k_priv *priv = hw->priv; int i; - for (i = 0; i < MWL8K_TX_QUEUES; i++) { + for (i = 0; i < mwl8k_tx_queues(priv); i++) { struct mwl8k_tx_queue *txq = priv->txq + i; int fw_owned = 0; int drv_owned = 0; @@ -1484,6 +1519,54 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) MWL8K_TXD_STATUS_OK_RETRY | \ MWL8K_TXD_STATUS_OK_MORE_RETRY)) +static int mwl8k_tid_queue_mapping(u8 tid) +{ + BUG_ON(tid > 7); + + switch (tid) { + case 0: + case 3: + return IEEE80211_AC_BE; + break; + case 1: + case 2: + return IEEE80211_AC_BK; + break; + case 4: + case 5: + return IEEE80211_AC_VI; + break; + case 6: + case 7: + return IEEE80211_AC_VO; + break; + default: + return -1; + break; + } +} + +/* The firmware will fill in the rate information + * for each packet that gets queued in the hardware + * in this structure + */ + +struct rateinfo { + __le16 format:1; + __le16 short_gi:1; + __le16 band_width:1; + __le16 rate_id_mcs:6; + __le16 adv_coding:2; + __le16 antenna:2; + __le16 act_sub_chan:2; + __le16 preamble_type:1; + __le16 power_id:4; + __le16 antenna2:1; + __le16 reserved:1; + __le16 tx_bf_frame:1; + __le16 green_field:1; +} __packed; + static int mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) { @@ -1500,6 +1583,11 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) struct sk_buff *skb; struct ieee80211_tx_info *info; u32 status; + struct ieee80211_sta *sta; + struct mwl8k_sta *sta_info = NULL; + u16 rate_info; + struct rateinfo *rate; + struct ieee80211_hdr *wh; tx = txq->head; tx_desc = txq->txd + tx; @@ -1528,11 +1616,34 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) mwl8k_remove_dma_header(skb, tx_desc->qos_control); + wh = (struct ieee80211_hdr *) skb->data; + /* Mark descriptor as unused */ tx_desc->pkt_phys_addr = 0; tx_desc->pkt_len = 0; info = IEEE80211_SKB_CB(skb); + if (ieee80211_is_data(wh->frame_control)) { + sta = info->control.sta; + if (sta) { + sta_info = MWL8K_STA(sta); + BUG_ON(sta_info == NULL); + rate_info = le16_to_cpu(tx_desc->rate_info); + rate = (struct rateinfo *)&rate_info; + /* If rate is < 6.5 Mpbs for an ht station + * do not form an ampdu. If the station is a + * legacy station (format = 0), do not form an + * ampdu + */ + if (rate->rate_id_mcs < 1 || + rate->format == 0) { + sta_info->is_ampdu_allowed = false; + } else { + sta_info->is_ampdu_allowed = true; + } + } + } + ieee80211_tx_info_clear_status(info); /* Rate control is happening in the firmware. @@ -1549,7 +1660,8 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) processed++; } - if (processed && priv->radio_on && !mutex_is_locked(&priv->fw_mutex)) + if (index < MWL8K_TX_WMM_QUEUES && processed && priv->radio_on && + !mutex_is_locked(&priv->fw_mutex)) ieee80211_wake_queue(hw, index); return processed; @@ -1561,6 +1673,9 @@ static void mwl8k_txq_deinit(struct ieee80211_hw *hw, int index) struct mwl8k_priv *priv = hw->priv; struct mwl8k_tx_queue *txq = priv->txq + index; + if (txq->txd == NULL) + return; + mwl8k_txq_reclaim(hw, index, INT_MAX, 1); kfree(txq->skb); @@ -1572,12 +1687,81 @@ static void mwl8k_txq_deinit(struct ieee80211_hw *hw, int index) txq->txd = NULL; } +/* caller must hold priv->stream_lock when calling the stream functions */ +struct mwl8k_ampdu_stream * +mwl8k_add_stream(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u8 tid) +{ + struct mwl8k_ampdu_stream *stream; + struct mwl8k_priv *priv = hw->priv; + int i; + + for (i = 0; i < priv->num_ampdu_queues; i++) { + stream = &priv->ampdu[i]; + if (stream->state == AMPDU_NO_STREAM) { + stream->sta = sta; + stream->state = AMPDU_STREAM_NEW; + stream->tid = tid; + stream->idx = i; + stream->txq_idx = MWL8K_TX_WMM_QUEUES + i; + wiphy_debug(hw->wiphy, "Added a new stream for %pM %d", + sta->addr, tid); + return stream; + } + } + return NULL; +} + +static int +mwl8k_start_stream(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream) +{ + int ret; + + /* if the stream has already been started, don't start it again */ + if (stream->state != AMPDU_STREAM_NEW) + return 0; + ret = ieee80211_start_tx_ba_session(stream->sta, stream->tid, 0); + if (ret) + wiphy_debug(hw->wiphy, "Failed to start stream for %pM %d: " + "%d\n", stream->sta->addr, stream->tid, ret); + else + wiphy_debug(hw->wiphy, "Started stream for %pM %d\n", + stream->sta->addr, stream->tid); + return ret; +} + +static void +mwl8k_remove_stream(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream) +{ + wiphy_debug(hw->wiphy, "Remove stream for %pM %d\n", stream->sta->addr, + stream->tid); + memset(stream, 0, sizeof(*stream)); +} + +static struct mwl8k_ampdu_stream * +mwl8k_lookup_stream(struct ieee80211_hw *hw, u8 *addr, u8 tid) +{ + struct mwl8k_priv *priv = hw->priv; + int i; + + for (i = 0 ; i < priv->num_ampdu_queues; i++) { + struct mwl8k_ampdu_stream *stream; + stream = &priv->ampdu[i]; + if (stream->state == AMPDU_NO_STREAM) + continue; + if (!memcmp(stream->sta->addr, addr, ETH_ALEN) && + stream->tid == tid) + return stream; + } + return NULL; +} + static void mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) { struct mwl8k_priv *priv = hw->priv; struct ieee80211_tx_info *tx_info; struct mwl8k_vif *mwl8k_vif; + struct ieee80211_sta *sta; struct ieee80211_hdr *wh; struct mwl8k_tx_queue *txq; struct mwl8k_tx_desc *tx; @@ -1585,6 +1769,11 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) u32 txstatus; u8 txdatarate; u16 qos; + int txpriority; + u8 tid = 0; + struct mwl8k_ampdu_stream *stream = NULL; + bool start_ba_session = false; + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; wh = (struct ieee80211_hdr *)skb->data; if (ieee80211_is_data_qos(wh->frame_control)) @@ -1600,6 +1789,7 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) wh = &((struct mwl8k_dma_data *)skb->data)->wh; tx_info = IEEE80211_SKB_CB(skb); + sta = tx_info->control.sta; mwl8k_vif = MWL8K_VIF(tx_info->control.vif); if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { @@ -1627,12 +1817,90 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) qos |= MWL8K_QOS_ACK_POLICY_NORMAL; } + /* Queue ADDBA request in the respective data queue. While setting up + * the ampdu stream, mac80211 queues further packets for that + * particular ra/tid pair. However, packets piled up in the hardware + * for that ra/tid pair will still go out. ADDBA request and the + * related data packets going out from different queues asynchronously + * will cause a shift in the receiver window which might result in + * ampdu packets getting dropped at the receiver after the stream has + * been setup. + */ + if (unlikely(ieee80211_is_action(wh->frame_control) && + mgmt->u.action.category == WLAN_CATEGORY_BACK && + mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ && + priv->ap_fw)) { + u16 capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); + tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; + index = mwl8k_tid_queue_mapping(tid); + } + + txpriority = index; + + if (ieee80211_is_data_qos(wh->frame_control) && + skb->protocol != cpu_to_be16(ETH_P_PAE) && + sta->ht_cap.ht_supported && priv->ap_fw) { + tid = qos & 0xf; + spin_lock(&priv->stream_lock); + stream = mwl8k_lookup_stream(hw, sta->addr, tid); + if (stream != NULL) { + if (stream->state == AMPDU_STREAM_ACTIVE) { + txpriority = stream->txq_idx; + index = stream->txq_idx; + } else if (stream->state == AMPDU_STREAM_NEW) { + /* We get here if the driver sends us packets + * after we've initiated a stream, but before + * our ampdu_action routine has been called + * with IEEE80211_AMPDU_TX_START to get the SSN + * for the ADDBA request. So this packet can + * go out with no risk of sequence number + * mismatch. No special handling is required. + */ + } else { + /* Drop packets that would go out after the + * ADDBA request was sent but before the ADDBA + * response is received. If we don't do this, + * the recipient would probably receive it + * after the ADDBA request with SSN 0. This + * will cause the recipient's BA receive window + * to shift, which would cause the subsequent + * packets in the BA stream to be discarded. + * mac80211 queues our packets for us in this + * case, so this is really just a safety check. + */ + wiphy_warn(hw->wiphy, + "Cannot send packet while ADDBA " + "dialog is underway.\n"); + spin_unlock(&priv->stream_lock); + dev_kfree_skb(skb); + return; + } + } else { + /* Defer calling mwl8k_start_stream so that the current + * skb can go out before the ADDBA request. This + * prevents sequence number mismatch at the recepient + * as described above. + */ + if (MWL8K_STA(sta)->is_ampdu_allowed) { + stream = mwl8k_add_stream(hw, sta, tid); + if (stream != NULL) + start_ba_session = true; + } + } + spin_unlock(&priv->stream_lock); + } + dma = pci_map_single(priv->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); if (pci_dma_mapping_error(priv->pdev, dma)) { wiphy_debug(hw->wiphy, "failed to dma map skb, dropping TX frame.\n"); + if (start_ba_session) { + spin_lock(&priv->stream_lock); + mwl8k_remove_stream(hw, stream); + spin_unlock(&priv->stream_lock); + } dev_kfree_skb(skb); return; } @@ -1641,12 +1909,22 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) txq = priv->txq + index; + if (index >= MWL8K_TX_WMM_QUEUES && txq->len >= MWL8K_TX_DESCS) { + /* This is the case in which the tx packet is destined for an + * AMPDU queue and that AMPDU queue is full. Because we don't + * start and stop the AMPDU queues, we must drop these packets. + */ + dev_kfree_skb(skb); + spin_unlock_bh(&priv->tx_lock); + return; + } + BUG_ON(txq->skb[txq->tail] != NULL); txq->skb[txq->tail] = skb; tx = txq->txd + txq->tail; tx->data_rate = txdatarate; - tx->tx_priority = index; + tx->tx_priority = txpriority; tx->qos_control = cpu_to_le16(qos); tx->pkt_phys_addr = cpu_to_le32(dma); tx->pkt_len = cpu_to_le16(skb->len); @@ -1665,12 +1943,20 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) if (txq->tail == MWL8K_TX_DESCS) txq->tail = 0; - if (txq->head == txq->tail) + if (txq->head == txq->tail && index < MWL8K_TX_WMM_QUEUES) ieee80211_stop_queue(hw, index); mwl8k_tx_start(priv); spin_unlock_bh(&priv->tx_lock); + + /* Initiate the ampdu session here */ + if (start_ba_session) { + spin_lock(&priv->stream_lock); + if (mwl8k_start_stream(hw, stream)) + mwl8k_remove_stream(hw, stream); + spin_unlock(&priv->stream_lock); + } } @@ -1868,7 +2154,7 @@ struct mwl8k_cmd_get_hw_spec_sta { __u8 mcs_bitmap[16]; __le32 rx_queue_ptr; __le32 num_tx_queues; - __le32 tx_queue_ptrs[MWL8K_TX_QUEUES]; + __le32 tx_queue_ptrs[MWL8K_TX_WMM_QUEUES]; __le32 caps2; __le32 num_tx_desc_per_queue; __le32 total_rxd; @@ -1974,8 +2260,8 @@ static int mwl8k_cmd_get_hw_spec_sta(struct ieee80211_hw *hw) memset(cmd->perm_addr, 0xff, sizeof(cmd->perm_addr)); cmd->ps_cookie = cpu_to_le32(priv->cookie_dma); cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rxd_dma); - cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES); - for (i = 0; i < MWL8K_TX_QUEUES; i++) + cmd->num_tx_queues = cpu_to_le32(mwl8k_tx_queues(priv)); + for (i = 0; i < mwl8k_tx_queues(priv); i++) cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[i].txd_dma); cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS); cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS); @@ -2017,13 +2303,16 @@ struct mwl8k_cmd_get_hw_spec_ap { __le32 wcbbase2; __le32 wcbbase3; __le32 fw_api_version; + __le32 caps; + __le32 num_of_ampdu_queues; + __le32 wcbbase_ampdu[MWL8K_MAX_AMPDU_QUEUES]; } __packed; static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw) { struct mwl8k_priv *priv = hw->priv; struct mwl8k_cmd_get_hw_spec_ap *cmd; - int rc; + int rc, i; u32 api_version; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); @@ -2055,27 +2344,31 @@ static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw) priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs); priv->fw_rev = le32_to_cpu(cmd->fw_rev); priv->hw_rev = cmd->hw_rev; - mwl8k_setup_2ghz_band(hw); + mwl8k_set_caps(hw, le32_to_cpu(cmd->caps)); priv->ap_macids_supported = 0x000000ff; priv->sta_macids_supported = 0x00000000; - - off = le32_to_cpu(cmd->wcbbase0) & 0xffff; - iowrite32(priv->txq[0].txd_dma, priv->sram + off); - + priv->num_ampdu_queues = le32_to_cpu(cmd->num_of_ampdu_queues); + if (priv->num_ampdu_queues > MWL8K_MAX_AMPDU_QUEUES) { + wiphy_warn(hw->wiphy, "fw reported %d ampdu queues" + " but we only support %d.\n", + priv->num_ampdu_queues, + MWL8K_MAX_AMPDU_QUEUES); + priv->num_ampdu_queues = MWL8K_MAX_AMPDU_QUEUES; + } off = le32_to_cpu(cmd->rxwrptr) & 0xffff; iowrite32(priv->rxq[0].rxd_dma, priv->sram + off); off = le32_to_cpu(cmd->rxrdptr) & 0xffff; iowrite32(priv->rxq[0].rxd_dma, priv->sram + off); - off = le32_to_cpu(cmd->wcbbase1) & 0xffff; - iowrite32(priv->txq[1].txd_dma, priv->sram + off); + priv->txq_offset[0] = le32_to_cpu(cmd->wcbbase0) & 0xffff; + priv->txq_offset[1] = le32_to_cpu(cmd->wcbbase1) & 0xffff; + priv->txq_offset[2] = le32_to_cpu(cmd->wcbbase2) & 0xffff; + priv->txq_offset[3] = le32_to_cpu(cmd->wcbbase3) & 0xffff; - off = le32_to_cpu(cmd->wcbbase2) & 0xffff; - iowrite32(priv->txq[2].txd_dma, priv->sram + off); - - off = le32_to_cpu(cmd->wcbbase3) & 0xffff; - iowrite32(priv->txq[3].txd_dma, priv->sram + off); + for (i = 0; i < priv->num_ampdu_queues; i++) + priv->txq_offset[i + MWL8K_TX_WMM_QUEUES] = + le32_to_cpu(cmd->wcbbase_ampdu[i]) & 0xffff; } done: @@ -2098,12 +2391,20 @@ struct mwl8k_cmd_set_hw_spec { __le32 caps; __le32 rx_queue_ptr; __le32 num_tx_queues; - __le32 tx_queue_ptrs[MWL8K_TX_QUEUES]; + __le32 tx_queue_ptrs[MWL8K_MAX_TX_QUEUES]; __le32 flags; __le32 num_tx_desc_per_queue; __le32 total_rxd; } __packed; +/* If enabled, MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY will cause + * packets to expire 500 ms after the timestamp in the tx descriptor. That is, + * the packets that are queued for more than 500ms, will be dropped in the + * hardware. This helps minimizing the issues caused due to head-of-line + * blocking where a slow client can hog the bandwidth and affect traffic to a + * faster client. + */ +#define MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY 0x00000400 #define MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT 0x00000080 #define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP 0x00000020 #define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON 0x00000010 @@ -2124,7 +2425,7 @@ static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw) cmd->ps_cookie = cpu_to_le32(priv->cookie_dma); cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rxd_dma); - cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES); + cmd->num_tx_queues = cpu_to_le32(mwl8k_tx_queues(priv)); /* * Mac80211 stack has Q0 as highest priority and Q3 as lowest in @@ -2132,8 +2433,8 @@ static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw) * in that order. Map Q3 of mac80211 to Q0 of firmware so that the * priority is interpreted the right way in firmware. */ - for (i = 0; i < MWL8K_TX_QUEUES; i++) { - int j = MWL8K_TX_QUEUES - 1 - i; + for (i = 0; i < mwl8k_tx_queues(priv); i++) { + int j = mwl8k_tx_queues(priv) - 1 - i; cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[j].txd_dma); } @@ -3123,6 +3424,65 @@ static int mwl8k_cmd_set_rateadapt_mode(struct ieee80211_hw *hw, __u16 mode) } /* + * CMD_GET_WATCHDOG_BITMAP. + */ +struct mwl8k_cmd_get_watchdog_bitmap { + struct mwl8k_cmd_pkt header; + u8 bitmap; +} __packed; + +static int mwl8k_cmd_get_watchdog_bitmap(struct ieee80211_hw *hw, u8 *bitmap) +{ + struct mwl8k_cmd_get_watchdog_bitmap *cmd; + int rc; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + + cmd->header.code = cpu_to_le16(MWL8K_CMD_GET_WATCHDOG_BITMAP); + cmd->header.length = cpu_to_le16(sizeof(*cmd)); + + rc = mwl8k_post_cmd(hw, &cmd->header); + if (!rc) + *bitmap = cmd->bitmap; + + kfree(cmd); + + return rc; +} + +#define INVALID_BA 0xAA +static void mwl8k_watchdog_ba_events(struct work_struct *work) +{ + int rc; + u8 bitmap = 0, stream_index; + struct mwl8k_ampdu_stream *streams; + struct mwl8k_priv *priv = + container_of(work, struct mwl8k_priv, watchdog_ba_handle); + + rc = mwl8k_cmd_get_watchdog_bitmap(priv->hw, &bitmap); + if (rc) + return; + + if (bitmap == INVALID_BA) + return; + + /* the bitmap is the hw queue number. Map it to the ampdu queue. */ + stream_index = bitmap - MWL8K_TX_WMM_QUEUES; + + BUG_ON(stream_index >= priv->num_ampdu_queues); + + streams = &priv->ampdu[stream_index]; + + if (streams->state == AMPDU_STREAM_ACTIVE) + ieee80211_stop_tx_ba_session(streams->sta, streams->tid); + + return; +} + + +/* * CMD_BSS_START. */ struct mwl8k_cmd_bss_start { @@ -3151,6 +3511,152 @@ static int mwl8k_cmd_bss_start(struct ieee80211_hw *hw, } /* + * CMD_BASTREAM. + */ + +/* + * UPSTREAM is tx direction + */ +#define BASTREAM_FLAG_DIRECTION_UPSTREAM 0x00 +#define BASTREAM_FLAG_IMMEDIATE_TYPE 0x01 + +enum { + MWL8K_BA_CREATE, + MWL8K_BA_UPDATE, + MWL8K_BA_DESTROY, + MWL8K_BA_FLUSH, + MWL8K_BA_CHECK, +} ba_stream_action_type; + + +struct mwl8k_create_ba_stream { + __le32 flags; + __le32 idle_thrs; + __le32 bar_thrs; + __le32 window_size; + u8 peer_mac_addr[6]; + u8 dialog_token; + u8 tid; + u8 queue_id; + u8 param_info; + __le32 ba_context; + u8 reset_seq_no_flag; + __le16 curr_seq_no; + u8 sta_src_mac_addr[6]; +} __packed; + +struct mwl8k_destroy_ba_stream { + __le32 flags; + __le32 ba_context; +} __packed; + +struct mwl8k_cmd_bastream { + struct mwl8k_cmd_pkt header; + __le32 action; + union { + struct mwl8k_create_ba_stream create_params; + struct mwl8k_destroy_ba_stream destroy_params; + }; +} __packed; + +static int +mwl8k_check_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream) +{ + struct mwl8k_cmd_bastream *cmd; + int rc; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + + cmd->header.code = cpu_to_le16(MWL8K_CMD_BASTREAM); + cmd->header.length = cpu_to_le16(sizeof(*cmd)); + + cmd->action = cpu_to_le32(MWL8K_BA_CHECK); + + cmd->create_params.queue_id = stream->idx; + memcpy(&cmd->create_params.peer_mac_addr[0], stream->sta->addr, + ETH_ALEN); + cmd->create_params.tid = stream->tid; + + cmd->create_params.flags = + cpu_to_le32(BASTREAM_FLAG_IMMEDIATE_TYPE) | + cpu_to_le32(BASTREAM_FLAG_DIRECTION_UPSTREAM); + + rc = mwl8k_post_cmd(hw, &cmd->header); + + kfree(cmd); + + return rc; +} + +static int +mwl8k_create_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream, + u8 buf_size) +{ + struct mwl8k_cmd_bastream *cmd; + int rc; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + + + cmd->header.code = cpu_to_le16(MWL8K_CMD_BASTREAM); + cmd->header.length = cpu_to_le16(sizeof(*cmd)); + + cmd->action = cpu_to_le32(MWL8K_BA_CREATE); + + cmd->create_params.bar_thrs = cpu_to_le32((u32)buf_size); + cmd->create_params.window_size = cpu_to_le32((u32)buf_size); + cmd->create_params.queue_id = stream->idx; + + memcpy(cmd->create_params.peer_mac_addr, stream->sta->addr, ETH_ALEN); + cmd->create_params.tid = stream->tid; + cmd->create_params.curr_seq_no = cpu_to_le16(0); + cmd->create_params.reset_seq_no_flag = 1; + + cmd->create_params.param_info = + (stream->sta->ht_cap.ampdu_factor & + IEEE80211_HT_AMPDU_PARM_FACTOR) | + ((stream->sta->ht_cap.ampdu_density << 2) & + IEEE80211_HT_AMPDU_PARM_DENSITY); + + cmd->create_params.flags = + cpu_to_le32(BASTREAM_FLAG_IMMEDIATE_TYPE | + BASTREAM_FLAG_DIRECTION_UPSTREAM); + + rc = mwl8k_post_cmd(hw, &cmd->header); + + wiphy_debug(hw->wiphy, "Created a BA stream for %pM : tid %d\n", + stream->sta->addr, stream->tid); + kfree(cmd); + + return rc; +} + +static void mwl8k_destroy_ba(struct ieee80211_hw *hw, + struct mwl8k_ampdu_stream *stream) +{ + struct mwl8k_cmd_bastream *cmd; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (cmd == NULL) + return; + + cmd->header.code = cpu_to_le16(MWL8K_CMD_BASTREAM); + cmd->header.length = cpu_to_le16(sizeof(*cmd)); + cmd->action = cpu_to_le32(MWL8K_BA_DESTROY); + + cmd->destroy_params.ba_context = cpu_to_le32(stream->idx); + mwl8k_post_cmd(hw, &cmd->header); + + wiphy_debug(hw->wiphy, "Deleted BA stream index %d\n", stream->idx); + + kfree(cmd); +} + +/* * CMD_SET_NEW_STN. */ struct mwl8k_cmd_set_new_stn { @@ -3671,6 +4177,11 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id) tasklet_schedule(&priv->poll_rx_task); } + if (status & MWL8K_A2H_INT_BA_WATCHDOG) { + status &= ~MWL8K_A2H_INT_BA_WATCHDOG; + ieee80211_queue_work(hw, &priv->watchdog_ba_handle); + } + if (status) iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); @@ -3699,7 +4210,7 @@ static void mwl8k_tx_poll(unsigned long data) spin_lock_bh(&priv->tx_lock); - for (i = 0; i < MWL8K_TX_QUEUES; i++) + for (i = 0; i < mwl8k_tx_queues(priv); i++) limit -= mwl8k_txq_reclaim(hw, i, limit, 0); if (!priv->pending_tx_pkts && priv->tx_wait != NULL) { @@ -3829,6 +4340,7 @@ static void mwl8k_stop(struct ieee80211_hw *hw) /* Stop finalize join worker */ cancel_work_sync(&priv->finalize_join_worker); + cancel_work_sync(&priv->watchdog_ba_handle); if (priv->beacon_skb != NULL) dev_kfree_skb(priv->beacon_skb); @@ -3837,7 +4349,7 @@ static void mwl8k_stop(struct ieee80211_hw *hw) tasklet_disable(&priv->poll_rx_task); /* Return all skbs to mac80211 */ - for (i = 0; i < MWL8K_TX_QUEUES; i++) + for (i = 0; i < mwl8k_tx_queues(priv); i++) mwl8k_txq_reclaim(hw, i, INT_MAX, 1); } @@ -3958,9 +4470,12 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) conf->power_level = 18; if (priv->ap_fw) { - rc = mwl8k_cmd_tx_power(hw, conf, conf->power_level); - if (rc) - goto out; + + if (conf->flags & IEEE80211_CONF_CHANGE_POWER) { + rc = mwl8k_cmd_tx_power(hw, conf, conf->power_level); + if (rc) + goto out; + } rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_RX, 0x3); if (rc) @@ -4312,6 +4827,8 @@ static int mwl8k_sta_add(struct ieee80211_hw *hw, ret = mwl8k_cmd_update_stadb_add(hw, vif, sta); if (ret >= 0) { MWL8K_STA(sta)->peer_id = ret; + if (sta->ht_cap.ht_supported) + MWL8K_STA(sta)->is_ampdu_allowed = true; ret = 0; } @@ -4335,14 +4852,14 @@ static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue, rc = mwl8k_fw_lock(hw); if (!rc) { - BUG_ON(queue > MWL8K_TX_QUEUES - 1); + BUG_ON(queue > MWL8K_TX_WMM_QUEUES - 1); memcpy(&priv->wmm_params[queue], params, sizeof(*params)); if (!priv->wmm_enabled) rc = mwl8k_cmd_set_wmm_mode(hw, 1); if (!rc) { - int q = MWL8K_TX_QUEUES - 1 - queue; + int q = MWL8K_TX_WMM_QUEUES - 1 - queue; rc = mwl8k_cmd_set_edca_params(hw, q, params->cw_min, params->cw_max, @@ -4378,21 +4895,118 @@ static int mwl8k_get_survey(struct ieee80211_hw *hw, int idx, return 0; } +#define MAX_AMPDU_ATTEMPTS 5 + static int mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size) { + + int i, rc = 0; + struct mwl8k_priv *priv = hw->priv; + struct mwl8k_ampdu_stream *stream; + u8 *addr = sta->addr; + + if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION)) + return -ENOTSUPP; + + spin_lock(&priv->stream_lock); + stream = mwl8k_lookup_stream(hw, addr, tid); + switch (action) { case IEEE80211_AMPDU_RX_START: case IEEE80211_AMPDU_RX_STOP: - if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION)) - return -ENOTSUPP; - return 0; + break; + case IEEE80211_AMPDU_TX_START: + /* By the time we get here the hw queues may contain outgoing + * packets for this RA/TID that are not part of this BA + * session. The hw will assign sequence numbers to these + * packets as they go out. So if we query the hw for its next + * sequence number and use that for the SSN here, it may end up + * being wrong, which will lead to sequence number mismatch at + * the recipient. To avoid this, we reset the sequence number + * to O for the first MPDU in this BA stream. + */ + *ssn = 0; + if (stream == NULL) { + /* This means that somebody outside this driver called + * ieee80211_start_tx_ba_session. This is unexpected + * because we do our own rate control. Just warn and + * move on. + */ + wiphy_warn(hw->wiphy, "Unexpected call to %s. " + "Proceeding anyway.\n", __func__); + stream = mwl8k_add_stream(hw, sta, tid); + } + if (stream == NULL) { + wiphy_debug(hw->wiphy, "no free AMPDU streams\n"); + rc = -EBUSY; + break; + } + stream->state = AMPDU_STREAM_IN_PROGRESS; + + /* Release the lock before we do the time consuming stuff */ + spin_unlock(&priv->stream_lock); + for (i = 0; i < MAX_AMPDU_ATTEMPTS; i++) { + rc = mwl8k_check_ba(hw, stream); + + if (!rc) + break; + /* + * HW queues take time to be flushed, give them + * sufficient time + */ + + msleep(1000); + } + spin_lock(&priv->stream_lock); + if (rc) { + wiphy_err(hw->wiphy, "Stream for tid %d busy after %d" + " attempts\n", tid, MAX_AMPDU_ATTEMPTS); + mwl8k_remove_stream(hw, stream); + rc = -EBUSY; + break; + } + ieee80211_start_tx_ba_cb_irqsafe(vif, addr, tid); + break; + case IEEE80211_AMPDU_TX_STOP: + if (stream == NULL) + break; + if (stream->state == AMPDU_STREAM_ACTIVE) { + spin_unlock(&priv->stream_lock); + mwl8k_destroy_ba(hw, stream); + spin_lock(&priv->stream_lock); + } + mwl8k_remove_stream(hw, stream); + ieee80211_stop_tx_ba_cb_irqsafe(vif, addr, tid); + break; + case IEEE80211_AMPDU_TX_OPERATIONAL: + BUG_ON(stream == NULL); + BUG_ON(stream->state != AMPDU_STREAM_IN_PROGRESS); + spin_unlock(&priv->stream_lock); + rc = mwl8k_create_ba(hw, stream, buf_size); + spin_lock(&priv->stream_lock); + if (!rc) + stream->state = AMPDU_STREAM_ACTIVE; + else { + spin_unlock(&priv->stream_lock); + mwl8k_destroy_ba(hw, stream); + spin_lock(&priv->stream_lock); + wiphy_debug(hw->wiphy, + "Failed adding stream for sta %pM tid %d\n", + addr, tid); + mwl8k_remove_stream(hw, stream); + } + break; + default: - return -ENOTSUPP; + rc = -ENOTSUPP; } + + spin_unlock(&priv->stream_lock); + return rc; } static const struct ieee80211_ops mwl8k_ops = { @@ -4441,7 +5055,7 @@ enum { MWL8366, }; -#define MWL8K_8366_AP_FW_API 1 +#define MWL8K_8366_AP_FW_API 2 #define _MWL8K_8366_AP_FW(api) "mwl8k/fmimage_8366_ap-" #api ".fw" #define MWL8K_8366_AP_FW(api) _MWL8K_8366_AP_FW(api) @@ -4607,6 +5221,23 @@ static int mwl8k_init_firmware(struct ieee80211_hw *hw, char *fw_image, return rc; } +static int mwl8k_init_txqs(struct ieee80211_hw *hw) +{ + struct mwl8k_priv *priv = hw->priv; + int rc = 0; + int i; + + for (i = 0; i < mwl8k_tx_queues(priv); i++) { + rc = mwl8k_txq_init(hw, i); + if (rc) + break; + if (priv->ap_fw) + iowrite32(priv->txq[i].txd_dma, + priv->sram + priv->txq_offset[i]); + } + return rc; +} + /* initialize hw after successfully loading a firmware image */ static int mwl8k_probe_hw(struct ieee80211_hw *hw) { @@ -4634,15 +5265,23 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw) goto err_stop_firmware; rxq_refill(hw, 0, INT_MAX); - for (i = 0; i < MWL8K_TX_QUEUES; i++) { - rc = mwl8k_txq_init(hw, i); + /* For the sta firmware, we need to know the dma addresses of tx queues + * before sending MWL8K_CMD_GET_HW_SPEC. So we must initialize them + * prior to issuing this command. But for the AP case, we learn the + * total number of queues from the result CMD_GET_HW_SPEC, so for this + * case we must initialize the tx queues after. + */ + priv->num_ampdu_queues = 0; + if (!priv->ap_fw) { + rc = mwl8k_init_txqs(hw); if (rc) goto err_free_queues; } iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); - iowrite32(MWL8K_A2H_INT_TX_DONE | MWL8K_A2H_INT_RX_READY, + iowrite32(MWL8K_A2H_INT_TX_DONE|MWL8K_A2H_INT_RX_READY| + MWL8K_A2H_INT_BA_WATCHDOG, priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL); iowrite32(0xffffffff, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); @@ -4653,6 +5292,8 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw) goto err_free_queues; } + memset(priv->ampdu, 0, sizeof(priv->ampdu)); + /* * Temporarily enable interrupts. Initial firmware host * commands use interrupts and avoid polling. Disable @@ -4664,6 +5305,8 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw) if (priv->ap_fw) { rc = mwl8k_cmd_get_hw_spec_ap(hw); if (!rc) + rc = mwl8k_init_txqs(hw); + if (!rc) rc = mwl8k_cmd_set_hw_spec(hw); } else { rc = mwl8k_cmd_get_hw_spec_sta(hw); @@ -4705,7 +5348,7 @@ err_free_irq: free_irq(priv->pdev->irq, hw); err_free_queues: - for (i = 0; i < MWL8K_TX_QUEUES; i++) + for (i = 0; i < mwl8k_tx_queues(priv); i++) mwl8k_txq_deinit(hw, i); mwl8k_rxq_deinit(hw, 0); @@ -4727,7 +5370,7 @@ static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image) mwl8k_stop(hw); mwl8k_rxq_deinit(hw, 0); - for (i = 0; i < MWL8K_TX_QUEUES; i++) + for (i = 0; i < mwl8k_tx_queues(priv); i++) mwl8k_txq_deinit(hw, i); rc = mwl8k_init_firmware(hw, fw_image, false); @@ -4746,7 +5389,7 @@ static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image) if (rc) goto fail; - for (i = 0; i < MWL8K_TX_QUEUES; i++) { + for (i = 0; i < MWL8K_TX_WMM_QUEUES; i++) { rc = mwl8k_conf_tx(hw, i, &priv->wmm_params[i]); if (rc) goto fail; @@ -4780,7 +5423,7 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) hw->channel_change_time = 10; - hw->queues = MWL8K_TX_QUEUES; + hw->queues = MWL8K_TX_WMM_QUEUES; /* Set rssi values to dBm */ hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_HAS_RATE_CONTROL; @@ -4796,6 +5439,8 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) /* Finalize join worker */ INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker); + /* Handle watchdog ba events */ + INIT_WORK(&priv->watchdog_ba_handle, mwl8k_watchdog_ba_events); /* TX reclaim and RX tasklets. */ tasklet_init(&priv->poll_tx_task, mwl8k_tx_poll, (unsigned long)hw); @@ -4815,6 +5460,8 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) spin_lock_init(&priv->tx_lock); + spin_lock_init(&priv->stream_lock); + priv->tx_wait = NULL; rc = mwl8k_probe_hw(hw); @@ -4836,7 +5483,7 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) return 0; err_unprobe_hw: - for (i = 0; i < MWL8K_TX_QUEUES; i++) + for (i = 0; i < mwl8k_tx_queues(priv); i++) mwl8k_txq_deinit(hw, i); mwl8k_rxq_deinit(hw, 0); @@ -4995,10 +5642,10 @@ static void __devexit mwl8k_remove(struct pci_dev *pdev) mwl8k_hw_reset(priv); /* Return all skbs to mac80211 */ - for (i = 0; i < MWL8K_TX_QUEUES; i++) + for (i = 0; i < mwl8k_tx_queues(priv); i++) mwl8k_txq_reclaim(hw, i, INT_MAX, 1); - for (i = 0; i < MWL8K_TX_QUEUES; i++) + for (i = 0; i < mwl8k_tx_queues(priv); i++) mwl8k_txq_deinit(hw, i); mwl8k_rxq_deinit(hw, 0); diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 329f3283697b..137a24e520da 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1368,8 +1368,10 @@ static void rt2400pci_tbtt_tasklet(unsigned long data) static void rt2400pci_rxdone_tasklet(unsigned long data) { struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; - rt2x00pci_rxdone(rt2x00dev); - rt2400pci_enable_interrupt(rt2x00dev, CSR8_RXDONE); + if (rt2x00pci_rxdone(rt2x00dev)) + tasklet_schedule(&rt2x00dev->rxdone_tasklet); + else + rt2400pci_enable_interrupt(rt2x00dev, CSR8_RXDONE); } static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance) diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 58277878889e..198fc0a0d77c 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1500,8 +1500,10 @@ static void rt2500pci_tbtt_tasklet(unsigned long data) static void rt2500pci_rxdone_tasklet(unsigned long data) { struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; - rt2x00pci_rxdone(rt2x00dev); - rt2500pci_enable_interrupt(rt2x00dev, CSR8_RXDONE); + if (rt2x00pci_rxdone(rt2x00dev)) + tasklet_schedule(&rt2x00dev->rxdone_tasklet); + else + rt2500pci_enable_interrupt(rt2x00dev, CSR8_RXDONE); } static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance) diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 979fe6596a2d..eac788160f55 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1796,7 +1796,6 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_COPY_IV, &rt2x00dev->flags); } - __set_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_SW_SEQNO, &rt2x00dev->flags); /* @@ -1910,13 +1909,10 @@ static struct usb_device_id rt2500usb_device_table[] = { /* Belkin */ { USB_DEVICE(0x050d, 0x7050), USB_DEVICE_DATA(&rt2500usb_ops) }, { USB_DEVICE(0x050d, 0x7051), USB_DEVICE_DATA(&rt2500usb_ops) }, - { USB_DEVICE(0x050d, 0x705a), USB_DEVICE_DATA(&rt2500usb_ops) }, /* Cisco Systems */ { USB_DEVICE(0x13b1, 0x000d), USB_DEVICE_DATA(&rt2500usb_ops) }, { USB_DEVICE(0x13b1, 0x0011), USB_DEVICE_DATA(&rt2500usb_ops) }, { USB_DEVICE(0x13b1, 0x001a), USB_DEVICE_DATA(&rt2500usb_ops) }, - /* CNet */ - { USB_DEVICE(0x1371, 0x9022), USB_DEVICE_DATA(&rt2500usb_ops) }, /* Conceptronic */ { USB_DEVICE(0x14b2, 0x3c02), USB_DEVICE_DATA(&rt2500usb_ops) }, /* D-LINK */ @@ -1939,7 +1935,6 @@ static struct usb_device_id rt2500usb_device_table[] = { /* Ralink */ { USB_DEVICE(0x148f, 0x1706), USB_DEVICE_DATA(&rt2500usb_ops) }, { USB_DEVICE(0x148f, 0x2570), USB_DEVICE_DATA(&rt2500usb_ops) }, - { USB_DEVICE(0x148f, 0x2573), USB_DEVICE_DATA(&rt2500usb_ops) }, { USB_DEVICE(0x148f, 0x9020), USB_DEVICE_DATA(&rt2500usb_ops) }, /* Sagem */ { USB_DEVICE(0x079b, 0x004b), USB_DEVICE_DATA(&rt2500usb_ops) }, diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index 8fbc5fa965e0..ce2010952886 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -2104,6 +2104,59 @@ struct mac_iveiv_entry { #define EEPROM_TXPOWER_BG_2 FIELD16(0xff00) /* + * EEPROM temperature compensation boundaries 802.11BG + * MINUS4: If the actual TSSI is below this boundary, tx power needs to be + * reduced by (agc_step * -4) + * MINUS3: If the actual TSSI is below this boundary, tx power needs to be + * reduced by (agc_step * -3) + */ +#define EEPROM_TSSI_BOUND_BG1 0x0037 +#define EEPROM_TSSI_BOUND_BG1_MINUS4 FIELD16(0x00ff) +#define EEPROM_TSSI_BOUND_BG1_MINUS3 FIELD16(0xff00) + +/* + * EEPROM temperature compensation boundaries 802.11BG + * MINUS2: If the actual TSSI is below this boundary, tx power needs to be + * reduced by (agc_step * -2) + * MINUS1: If the actual TSSI is below this boundary, tx power needs to be + * reduced by (agc_step * -1) + */ +#define EEPROM_TSSI_BOUND_BG2 0x0038 +#define EEPROM_TSSI_BOUND_BG2_MINUS2 FIELD16(0x00ff) +#define EEPROM_TSSI_BOUND_BG2_MINUS1 FIELD16(0xff00) + +/* + * EEPROM temperature compensation boundaries 802.11BG + * REF: Reference TSSI value, no tx power changes needed + * PLUS1: If the actual TSSI is above this boundary, tx power needs to be + * increased by (agc_step * 1) + */ +#define EEPROM_TSSI_BOUND_BG3 0x0039 +#define EEPROM_TSSI_BOUND_BG3_REF FIELD16(0x00ff) +#define EEPROM_TSSI_BOUND_BG3_PLUS1 FIELD16(0xff00) + +/* + * EEPROM temperature compensation boundaries 802.11BG + * PLUS2: If the actual TSSI is above this boundary, tx power needs to be + * increased by (agc_step * 2) + * PLUS3: If the actual TSSI is above this boundary, tx power needs to be + * increased by (agc_step * 3) + */ +#define EEPROM_TSSI_BOUND_BG4 0x003a +#define EEPROM_TSSI_BOUND_BG4_PLUS2 FIELD16(0x00ff) +#define EEPROM_TSSI_BOUND_BG4_PLUS3 FIELD16(0xff00) + +/* + * EEPROM temperature compensation boundaries 802.11BG + * PLUS4: If the actual TSSI is above this boundary, tx power needs to be + * increased by (agc_step * 4) + * AGC_STEP: Temperature compensation step. + */ +#define EEPROM_TSSI_BOUND_BG5 0x003b +#define EEPROM_TSSI_BOUND_BG5_PLUS4 FIELD16(0x00ff) +#define EEPROM_TSSI_BOUND_BG5_AGC_STEP FIELD16(0xff00) + +/* * EEPROM TXPOWER 802.11A */ #define EEPROM_TXPOWER_A1 0x003c @@ -2113,6 +2166,59 @@ struct mac_iveiv_entry { #define EEPROM_TXPOWER_A_2 FIELD16(0xff00) /* + * EEPROM temperature compensation boundaries 802.11A + * MINUS4: If the actual TSSI is below this boundary, tx power needs to be + * reduced by (agc_step * -4) + * MINUS3: If the actual TSSI is below this boundary, tx power needs to be + * reduced by (agc_step * -3) + */ +#define EEPROM_TSSI_BOUND_A1 0x006a +#define EEPROM_TSSI_BOUND_A1_MINUS4 FIELD16(0x00ff) +#define EEPROM_TSSI_BOUND_A1_MINUS3 FIELD16(0xff00) + +/* + * EEPROM temperature compensation boundaries 802.11A + * MINUS2: If the actual TSSI is below this boundary, tx power needs to be + * reduced by (agc_step * -2) + * MINUS1: If the actual TSSI is below this boundary, tx power needs to be + * reduced by (agc_step * -1) + */ +#define EEPROM_TSSI_BOUND_A2 0x006b +#define EEPROM_TSSI_BOUND_A2_MINUS2 FIELD16(0x00ff) +#define EEPROM_TSSI_BOUND_A2_MINUS1 FIELD16(0xff00) + +/* + * EEPROM temperature compensation boundaries 802.11A + * REF: Reference TSSI value, no tx power changes needed + * PLUS1: If the actual TSSI is above this boundary, tx power needs to be + * increased by (agc_step * 1) + */ +#define EEPROM_TSSI_BOUND_A3 0x006c +#define EEPROM_TSSI_BOUND_A3_REF FIELD16(0x00ff) +#define EEPROM_TSSI_BOUND_A3_PLUS1 FIELD16(0xff00) + +/* + * EEPROM temperature compensation boundaries 802.11A + * PLUS2: If the actual TSSI is above this boundary, tx power needs to be + * increased by (agc_step * 2) + * PLUS3: If the actual TSSI is above this boundary, tx power needs to be + * increased by (agc_step * 3) + */ +#define EEPROM_TSSI_BOUND_A4 0x006d +#define EEPROM_TSSI_BOUND_A4_PLUS2 FIELD16(0x00ff) +#define EEPROM_TSSI_BOUND_A4_PLUS3 FIELD16(0xff00) + +/* + * EEPROM temperature compensation boundaries 802.11A + * PLUS4: If the actual TSSI is above this boundary, tx power needs to be + * increased by (agc_step * 4) + * AGC_STEP: Temperature compensation step. + */ +#define EEPROM_TSSI_BOUND_A5 0x006e +#define EEPROM_TSSI_BOUND_A5_PLUS4 FIELD16(0x00ff) +#define EEPROM_TSSI_BOUND_A5_AGC_STEP FIELD16(0xff00) + +/* * EEPROM TXPOWER by rate: tx power per tx rate for HT20 mode */ #define EEPROM_TXPOWER_BYRATE 0x006f diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index dbf74d07d947..6331c61957a3 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -687,6 +687,9 @@ void rt2800_txdone_entry(struct queue_entry *entry, u32 status) mcs = real_mcs; } + if (aggr == 1 || ampdu == 1) + __set_bit(TXDONE_AMPDU, &txdesc.flags); + /* * Ralink has a retry mechanism using a global fallback * table. We setup this fallback table to try the immediate @@ -1813,17 +1816,131 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC, ®); } +static int rt2800_get_gain_calibration_delta(struct rt2x00_dev *rt2x00dev) +{ + u8 tssi_bounds[9]; + u8 current_tssi; + u16 eeprom; + u8 step; + int i; + + /* + * Read TSSI boundaries for temperature compensation from + * the EEPROM. + * + * Array idx 0 1 2 3 4 5 6 7 8 + * Matching Delta value -4 -3 -2 -1 0 +1 +2 +3 +4 + * Example TSSI bounds 0xF0 0xD0 0xB5 0xA0 0x88 0x45 0x25 0x15 0x00 + */ + if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) { + rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG1, &eeprom); + tssi_bounds[0] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_BG1_MINUS4); + tssi_bounds[1] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_BG1_MINUS3); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG2, &eeprom); + tssi_bounds[2] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_BG2_MINUS2); + tssi_bounds[3] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_BG2_MINUS1); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG3, &eeprom); + tssi_bounds[4] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_BG3_REF); + tssi_bounds[5] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_BG3_PLUS1); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG4, &eeprom); + tssi_bounds[6] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_BG4_PLUS2); + tssi_bounds[7] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_BG4_PLUS3); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG5, &eeprom); + tssi_bounds[8] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_BG5_PLUS4); + + step = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_BG5_AGC_STEP); + } else { + rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A1, &eeprom); + tssi_bounds[0] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_A1_MINUS4); + tssi_bounds[1] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_A1_MINUS3); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A2, &eeprom); + tssi_bounds[2] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_A2_MINUS2); + tssi_bounds[3] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_A2_MINUS1); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A3, &eeprom); + tssi_bounds[4] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_A3_REF); + tssi_bounds[5] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_A3_PLUS1); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A4, &eeprom); + tssi_bounds[6] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_A4_PLUS2); + tssi_bounds[7] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_A4_PLUS3); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A5, &eeprom); + tssi_bounds[8] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_A5_PLUS4); + + step = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_A5_AGC_STEP); + } + + /* + * Check if temperature compensation is supported. + */ + if (tssi_bounds[4] == 0xff) + return 0; + + /* + * Read current TSSI (BBP 49). + */ + rt2800_bbp_read(rt2x00dev, 49, ¤t_tssi); + + /* + * Compare TSSI value (BBP49) with the compensation boundaries + * from the EEPROM and increase or decrease tx power. + */ + for (i = 0; i <= 3; i++) { + if (current_tssi > tssi_bounds[i]) + break; + } + + if (i == 4) { + for (i = 8; i >= 5; i--) { + if (current_tssi < tssi_bounds[i]) + break; + } + } + + return (i - 4) * step; +} + static int rt2800_get_txpower_bw_comp(struct rt2x00_dev *rt2x00dev, enum ieee80211_band band) { u16 eeprom; u8 comp_en; u8 comp_type; - int comp_value; + int comp_value = 0; rt2x00_eeprom_read(rt2x00dev, EEPROM_TXPOWER_DELTA, &eeprom); - if (eeprom == 0xffff) + /* + * HT40 compensation not required. + */ + if (eeprom == 0xffff || + !test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags)) return 0; if (band == IEEE80211_BAND_2GHZ) { @@ -1853,11 +1970,9 @@ static int rt2800_get_txpower_bw_comp(struct rt2x00_dev *rt2x00dev, return comp_value; } -static u8 rt2800_compesate_txpower(struct rt2x00_dev *rt2x00dev, - int is_rate_b, - enum ieee80211_band band, - int power_level, - u8 txpower) +static u8 rt2800_compensate_txpower(struct rt2x00_dev *rt2x00dev, int is_rate_b, + enum ieee80211_band band, int power_level, + u8 txpower, int delta) { u32 reg; u16 eeprom; @@ -1865,14 +1980,10 @@ static u8 rt2800_compesate_txpower(struct rt2x00_dev *rt2x00dev, u8 eirp_txpower; u8 eirp_txpower_criterion; u8 reg_limit; - int bw_comp = 0; if (!((band == IEEE80211_BAND_5GHZ) && is_rate_b)) return txpower; - if (test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags)) - bw_comp = rt2800_get_txpower_bw_comp(rt2x00dev, band); - if (test_bit(CONFIG_SUPPORT_POWER_LIMIT, &rt2x00dev->flags)) { /* * Check if eirp txpower exceed txpower_limit. @@ -1895,18 +2006,19 @@ static u8 rt2800_compesate_txpower(struct rt2x00_dev *rt2x00dev, EEPROM_EIRP_MAX_TX_POWER_5GHZ); eirp_txpower = eirp_txpower_criterion + (txpower - criterion) + - (is_rate_b ? 4 : 0) + bw_comp; + (is_rate_b ? 4 : 0) + delta; reg_limit = (eirp_txpower > power_level) ? (eirp_txpower - power_level) : 0; } else reg_limit = 0; - return txpower + bw_comp - reg_limit; + return txpower + delta - reg_limit; } static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, - struct ieee80211_conf *conf) + enum ieee80211_band band, + int power_level) { u8 txpower; u16 eeprom; @@ -1914,8 +2026,17 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, u32 reg; u8 r1; u32 offset; - enum ieee80211_band band = conf->channel->band; - int power_level = conf->power_level; + int delta; + + /* + * Calculate HT40 compensation delta + */ + delta = rt2800_get_txpower_bw_comp(rt2x00dev, band); + + /* + * calculate temperature compensation delta + */ + delta += rt2800_get_gain_calibration_delta(rt2x00dev); /* * set to normal bbp tx power control mode: +/- 0dBm @@ -1944,8 +2065,8 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0); - txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, - power_level, txpower); + txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, + power_level, txpower, delta); rt2x00_set_field32(®, TX_PWR_CFG_RATE0, txpower); /* @@ -1955,8 +2076,8 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE1); - txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, - power_level, txpower); + txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, + power_level, txpower, delta); rt2x00_set_field32(®, TX_PWR_CFG_RATE1, txpower); /* @@ -1966,8 +2087,8 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE2); - txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, - power_level, txpower); + txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, + power_level, txpower, delta); rt2x00_set_field32(®, TX_PWR_CFG_RATE2, txpower); /* @@ -1977,8 +2098,8 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE3); - txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, - power_level, txpower); + txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, + power_level, txpower, delta); rt2x00_set_field32(®, TX_PWR_CFG_RATE3, txpower); /* read the next four txpower values */ @@ -1993,8 +2114,8 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0); - txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, - power_level, txpower); + txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, + power_level, txpower, delta); rt2x00_set_field32(®, TX_PWR_CFG_RATE4, txpower); /* @@ -2004,8 +2125,8 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE1); - txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, - power_level, txpower); + txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, + power_level, txpower, delta); rt2x00_set_field32(®, TX_PWR_CFG_RATE5, txpower); /* @@ -2015,8 +2136,8 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE2); - txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, - power_level, txpower); + txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, + power_level, txpower, delta); rt2x00_set_field32(®, TX_PWR_CFG_RATE6, txpower); /* @@ -2026,8 +2147,8 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE3); - txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, - power_level, txpower); + txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, + power_level, txpower, delta); rt2x00_set_field32(®, TX_PWR_CFG_RATE7, txpower); rt2800_register_write(rt2x00dev, offset, reg); @@ -2037,6 +2158,13 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, } } +void rt2800_gain_calibration(struct rt2x00_dev *rt2x00dev) +{ + rt2800_config_txpower(rt2x00dev, rt2x00dev->curr_band, + rt2x00dev->tx_power); +} +EXPORT_SYMBOL_GPL(rt2800_gain_calibration); + static void rt2800_config_retry_limit(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf) { @@ -2090,10 +2218,12 @@ void rt2800_config(struct rt2x00_dev *rt2x00dev, if (flags & IEEE80211_CONF_CHANGE_CHANNEL) { rt2800_config_channel(rt2x00dev, libconf->conf, &libconf->rf, &libconf->channel); - rt2800_config_txpower(rt2x00dev, libconf->conf); + rt2800_config_txpower(rt2x00dev, libconf->conf->channel->band, + libconf->conf->power_level); } if (flags & IEEE80211_CONF_CHANGE_POWER) - rt2800_config_txpower(rt2x00dev, libconf->conf); + rt2800_config_txpower(rt2x00dev, libconf->conf->channel->band, + libconf->conf->power_level); if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) rt2800_config_retry_limit(rt2x00dev, libconf); if (flags & IEEE80211_CONF_CHANGE_PS) diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h index 0c92d86a36f4..f2d15941c71a 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/rt2x00/rt2800lib.h @@ -181,6 +181,7 @@ void rt2800_link_stats(struct rt2x00_dev *rt2x00dev, struct link_qual *qual); void rt2800_reset_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual); void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual, const u32 count); +void rt2800_gain_calibration(struct rt2x00_dev *rt2x00dev); int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev); void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev); diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 808073aa9dcc..adc3534254df 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -717,12 +717,13 @@ static void rt2800pci_wakeup(struct rt2x00_dev *rt2x00dev) rt2800_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS); } -static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev) +static bool rt2800pci_txdone(struct rt2x00_dev *rt2x00dev) { struct data_queue *queue; struct queue_entry *entry; u32 status; u8 qid; + int max_tx_done = 16; while (kfifo_get(&rt2x00dev->txstatus_fifo, &status)) { qid = rt2x00_get_field32(status, TX_STA_FIFO_PID_QUEUE); @@ -759,7 +760,12 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev) entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); rt2800_txdone_entry(entry, status); + + if (--max_tx_done == 0) + break; } + + return !max_tx_done; } static void rt2800pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, @@ -780,7 +786,9 @@ static void rt2800pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, static void rt2800pci_txstatus_tasklet(unsigned long data) { - rt2800pci_txdone((struct rt2x00_dev *)data); + struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; + if (rt2800pci_txdone(rt2x00dev)) + tasklet_schedule(&rt2x00dev->txstatus_tasklet); /* * No need to enable the tx status interrupt here as we always @@ -806,8 +814,10 @@ static void rt2800pci_tbtt_tasklet(unsigned long data) static void rt2800pci_rxdone_tasklet(unsigned long data) { struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; - rt2x00pci_rxdone(rt2x00dev); - rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RX_DONE); + if (rt2x00pci_rxdone(rt2x00dev)) + tasklet_schedule(&rt2x00dev->rxdone_tasklet); + else + rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RX_DONE); } static void rt2800pci_autowake_tasklet(unsigned long data) @@ -1043,6 +1053,7 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = { .link_stats = rt2800_link_stats, .reset_tuner = rt2800_reset_tuner, .link_tuner = rt2800_link_tuner, + .gain_calibration = rt2800_gain_calibration, .start_queue = rt2800pci_start_queue, .kick_queue = rt2800pci_kick_queue, .stop_queue = rt2800pci_stop_queue, diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 37509d019910..6ba31a0e8f78 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -564,7 +564,6 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) if (!modparam_nohwcrypt) __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags); - __set_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_HT_TX_DESC, &rt2x00dev->flags); /* @@ -630,6 +629,7 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = { .link_stats = rt2800_link_stats, .reset_tuner = rt2800_reset_tuner, .link_tuner = rt2800_link_tuner, + .gain_calibration = rt2800_gain_calibration, .watchdog = rt2800usb_watchdog, .start_queue = rt2800usb_start_queue, .kick_queue = rt2x00usb_kick_queue, @@ -882,6 +882,7 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x5a57, 0x5257), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Zyxel */ { USB_DEVICE(0x0586, 0x3416), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0586, 0x3418), USB_DEVICE_DATA(&rt2800usb_ops) }, #ifdef CONFIG_RT2800USB_RT33XX /* Ralink */ { USB_DEVICE(0x148f, 0x3370), USB_DEVICE_DATA(&rt2800usb_ops) }, diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 7f10239f56a8..a2bd5feb9d5c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -348,6 +348,11 @@ struct link { * to bring the device/driver back into the desired state. */ struct delayed_work watchdog_work; + + /* + * Work structure for scheduling periodic AGC adjustments. + */ + struct delayed_work agc_work; }; enum rt2x00_delayed_flags { @@ -556,6 +561,7 @@ struct rt2x00lib_ops { struct link_qual *qual); void (*link_tuner) (struct rt2x00_dev *rt2x00dev, struct link_qual *qual, const u32 count); + void (*gain_calibration) (struct rt2x00_dev *rt2x00dev); /* * Data queue handlers. @@ -674,7 +680,6 @@ enum rt2x00_flags { DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, DRIVER_SUPPORT_PRE_TBTT_INTERRUPT, DRIVER_SUPPORT_LINK_TUNING, - DRIVER_SUPPORT_WATCHDOG, /* * Driver configuration diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index c92db3264741..66166ef037f5 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c @@ -568,7 +568,6 @@ static struct dentry *rt2x00debug_create_file_driver(const char *name, blob->data = data; data += sprintf(data, "driver:\t%s\n", intf->rt2x00dev->ops->name); data += sprintf(data, "version:\t%s\n", DRV_VERSION); - data += sprintf(data, "compiled:\t%s %s\n", __DATE__, __TIME__); blob->size = strlen(blob->data); return debugfs_create_blob(name, S_IRUSR, intf->driver_folder, blob); diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 84eb6ad36377..9bffe8438d1f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -27,6 +27,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/slab.h> +#include <linux/log2.h> #include "rt2x00.h" #include "rt2x00lib.h" @@ -70,6 +71,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) */ rt2x00queue_start_queues(rt2x00dev); rt2x00link_start_tuner(rt2x00dev); + rt2x00link_start_agc(rt2x00dev); /* * Start watchdog monitoring. @@ -92,6 +94,7 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev) /* * Stop all queues */ + rt2x00link_stop_agc(rt2x00dev); rt2x00link_stop_tuner(rt2x00dev); rt2x00queue_stop_queues(rt2x00dev); rt2x00queue_flush_queues(rt2x00dev, true); @@ -350,10 +353,14 @@ void rt2x00lib_txdone(struct queue_entry *entry, * which would allow the rc algorithm to better decide on * which rates are suitable. */ - if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { + if (test_bit(TXDONE_AMPDU, &txdesc->flags) || + tx_info->flags & IEEE80211_TX_CTL_AMPDU) { tx_info->flags |= IEEE80211_TX_STAT_AMPDU; tx_info->status.ampdu_len = 1; tx_info->status.ampdu_ack_len = success ? 1 : 0; + + if (!success) + tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; } if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) { @@ -511,8 +518,6 @@ void rt2x00lib_rxdone(struct queue_entry *entry) (rxdesc.size > header_length) && (rxdesc.dev_flags & RXDONE_L2PAD)) rt2x00queue_remove_l2pad(entry->skb, header_length); - else - rt2x00queue_align_payload(entry->skb, header_length); /* Trim buffer to correct size */ skb_trim(entry->skb, rxdesc.size); @@ -811,13 +816,18 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) */ if (test_bit(DRIVER_REQUIRE_TXSTATUS_FIFO, &rt2x00dev->flags)) { /* - * Allocate txstatus fifo and tasklet, we use a size of 512 - * for the kfifo which is big enough to store 512/4=128 tx - * status reports. In the worst case (tx status for all tx - * queues gets reported before we've got a chance to handle - * them) 24*4=384 tx status reports need to be cached. + * Allocate the txstatus fifo. In the worst case the tx + * status fifo has to hold the tx status of all entries + * in all tx queues. Hence, calculate the kfifo size as + * tx_queues * entry_num and round up to the nearest + * power of 2. */ - status = kfifo_alloc(&rt2x00dev->txstatus_fifo, 512, + int kfifo_size = + roundup_pow_of_two(rt2x00dev->ops->tx_queues * + rt2x00dev->ops->tx->entry_num * + sizeof(u32)); + + status = kfifo_alloc(&rt2x00dev->txstatus_fifo, kfifo_size, GFP_KERNEL); if (status) return status; diff --git a/drivers/net/wireless/rt2x00/rt2x00ht.c b/drivers/net/wireless/rt2x00/rt2x00ht.c index ae1219dffaae..e8c0c3e92c2f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00ht.c +++ b/drivers/net/wireless/rt2x00/rt2x00ht.c @@ -43,8 +43,11 @@ void rt2x00ht_create_tx_descriptor(struct queue_entry *entry, txdesc->u.ht.ba_size = 7; /* FIXME: What value is needed? */ - txdesc->u.ht.stbc = - (tx_info->flags & IEEE80211_TX_CTL_STBC) >> IEEE80211_TX_CTL_STBC_SHIFT; + /* + * Only one STBC stream is supported for now. + */ + if (tx_info->flags & IEEE80211_TX_CTL_STBC) + txdesc->u.ht.stbc = 1; /* * If IEEE80211_TX_RC_MCS is set txrate->idx just contains the diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 2d94cbaf5f4a..88f2f9275528 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -32,6 +32,7 @@ */ #define WATCHDOG_INTERVAL round_jiffies_relative(HZ) #define LINK_TUNE_INTERVAL round_jiffies_relative(HZ) +#define AGC_INTERVAL round_jiffies_relative(4 * HZ) /* * rt2x00_rate: Per rate device information @@ -119,16 +120,6 @@ void rt2x00queue_free_skb(struct queue_entry *entry); void rt2x00queue_align_frame(struct sk_buff *skb); /** - * rt2x00queue_align_payload - Align 802.11 payload to 4-byte boundary - * @skb: The skb to align - * @header_length: Length of 802.11 header - * - * Align the 802.11 payload to a 4-byte boundary, this could - * mean the header is not aligned properly though. - */ -void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_length); - -/** * rt2x00queue_insert_l2pad - Align 802.11 header & payload to 4-byte boundary * @skb: The skb to align * @header_length: Length of 802.11 header @@ -281,6 +272,18 @@ void rt2x00link_start_watchdog(struct rt2x00_dev *rt2x00dev); void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev); /** + * rt2x00link_start_agc - Start periodic gain calibration + * @rt2x00dev: Pointer to &struct rt2x00_dev. + */ +void rt2x00link_start_agc(struct rt2x00_dev *rt2x00dev); + +/** + * rt2x00link_stop_agc - Stop periodic gain calibration + * @rt2x00dev: Pointer to &struct rt2x00_dev. + */ +void rt2x00link_stop_agc(struct rt2x00_dev *rt2x00dev); + +/** * rt2x00link_register - Initialize link tuning & watchdog functionality * @rt2x00dev: Pointer to &struct rt2x00_dev. * diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index 29abfdeb0b65..1435976b8779 100644 --- a/drivers/net/wireless/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/rt2x00/rt2x00link.c @@ -413,12 +413,11 @@ void rt2x00link_start_watchdog(struct rt2x00_dev *rt2x00dev) { struct link *link = &rt2x00dev->link; - if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) || - !test_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags)) - return; - - ieee80211_queue_delayed_work(rt2x00dev->hw, - &link->watchdog_work, WATCHDOG_INTERVAL); + if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) && + rt2x00dev->ops->lib->watchdog) + ieee80211_queue_delayed_work(rt2x00dev->hw, + &link->watchdog_work, + WATCHDOG_INTERVAL); } void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev) @@ -447,8 +446,46 @@ static void rt2x00link_watchdog(struct work_struct *work) WATCHDOG_INTERVAL); } +void rt2x00link_start_agc(struct rt2x00_dev *rt2x00dev) +{ + struct link *link = &rt2x00dev->link; + + if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) && + rt2x00dev->ops->lib->gain_calibration) + ieee80211_queue_delayed_work(rt2x00dev->hw, + &link->agc_work, + AGC_INTERVAL); +} + +void rt2x00link_stop_agc(struct rt2x00_dev *rt2x00dev) +{ + cancel_delayed_work_sync(&rt2x00dev->link.agc_work); +} + +static void rt2x00link_agc(struct work_struct *work) +{ + struct rt2x00_dev *rt2x00dev = + container_of(work, struct rt2x00_dev, link.agc_work.work); + struct link *link = &rt2x00dev->link; + + /* + * When the radio is shutting down we should + * immediately cease the watchdog monitoring. + */ + if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) + return; + + rt2x00dev->ops->lib->gain_calibration(rt2x00dev); + + if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) + ieee80211_queue_delayed_work(rt2x00dev->hw, + &link->agc_work, + AGC_INTERVAL); +} + void rt2x00link_register(struct rt2x00_dev *rt2x00dev) { + INIT_DELAYED_WORK(&rt2x00dev->link.agc_work, rt2x00link_agc); INIT_DELAYED_WORK(&rt2x00dev->link.watchdog_work, rt2x00link_watchdog); INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00link_tuner); } diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index 4dd82b0b0520..9649bd0cd718 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -60,14 +60,15 @@ int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev, } EXPORT_SYMBOL_GPL(rt2x00pci_regbusy_read); -void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) +bool rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) { struct data_queue *queue = rt2x00dev->rx; struct queue_entry *entry; struct queue_entry_priv_pci *entry_priv; struct skb_frame_desc *skbdesc; + int max_rx = 16; - while (1) { + while (--max_rx) { entry = rt2x00queue_get_entry(queue, Q_INDEX); entry_priv = entry->priv_data; @@ -93,6 +94,8 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) */ rt2x00lib_rxdone(entry); } + + return !max_rx; } EXPORT_SYMBOL_GPL(rt2x00pci_rxdone); diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h index 746ce8fe8cf4..07961b8b369a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.h +++ b/drivers/net/wireless/rt2x00/rt2x00pci.h @@ -101,8 +101,11 @@ struct queue_entry_priv_pci { /** * rt2x00pci_rxdone - Handle RX done events * @rt2x00dev: Device pointer, see &struct rt2x00_dev. + * + * Returns true if there are still rx frames pending and false if all + * pending rx frames were processed. */ -void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev); +bool rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev); /* * Device initialization handlers. diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 4358051bfe1a..94b8bbb7ad80 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -148,19 +148,6 @@ void rt2x00queue_align_frame(struct sk_buff *skb) skb_trim(skb, frame_length); } -void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_length) -{ - unsigned int frame_length = skb->len; - unsigned int align = ALIGN_SIZE(skb, header_length); - - if (!align) - return; - - skb_push(skb, align); - memmove(skb->data, skb->data + align, frame_length); - skb_trim(skb, frame_length); -} - void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length) { unsigned int payload_length = skb->len - header_length; @@ -495,8 +482,11 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, struct skb_frame_desc *skbdesc; u8 rate_idx, rate_flags; - if (unlikely(rt2x00queue_full(queue))) + if (unlikely(rt2x00queue_full(queue))) { + ERROR(queue->rt2x00dev, + "Dropping frame due to full tx queue %d.\n", queue->qid); return -ENOBUFS; + } if (unlikely(test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))) { diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 217861f8d95f..5db6a99fce7d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -217,6 +217,7 @@ enum txdone_entry_desc_flags { TXDONE_FALLBACK, TXDONE_FAILURE, TXDONE_EXCESSIVE_RETRY, + TXDONE_AMPDU, }; /** diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 77e8113b91e1..8ee1514a7943 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2313,8 +2313,10 @@ static void rt61pci_tbtt_tasklet(unsigned long data) static void rt61pci_rxdone_tasklet(unsigned long data) { struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; - rt2x00pci_rxdone(rt2x00dev); - rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RXDONE); + if (rt2x00pci_rxdone(rt2x00dev)) + rt2x00pci_rxdone(rt2x00dev); + else + rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RXDONE); } static void rt61pci_autowake_tasklet(unsigned long data) diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 02f1148c577e..6593059f9c7e 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2209,7 +2209,6 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) if (!modparam_nohwcrypt) __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags); - __set_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags); /* * Set the rssi offset. @@ -2407,7 +2406,6 @@ static struct usb_device_id rt73usb_device_table[] = { { USB_DEVICE(0x0b05, 0x1723), USB_DEVICE_DATA(&rt73usb_ops) }, { USB_DEVICE(0x0b05, 0x1724), USB_DEVICE_DATA(&rt73usb_ops) }, /* Belkin */ - { USB_DEVICE(0x050d, 0x7050), USB_DEVICE_DATA(&rt73usb_ops) }, { USB_DEVICE(0x050d, 0x705a), USB_DEVICE_DATA(&rt73usb_ops) }, { USB_DEVICE(0x050d, 0x905b), USB_DEVICE_DATA(&rt73usb_ops) }, { USB_DEVICE(0x050d, 0x905c), USB_DEVICE_DATA(&rt73usb_ops) }, diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index 0d7d93e1d398..4803f54842e4 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c @@ -432,7 +432,7 @@ static void _rtl_txrate_selectmode(struct ieee80211_hw *hw, } if (rtlpriv->dm.useramask) { - /* TODO we will differentiate adhoc and station futrue */ + /* TODO adhoc and station handled differently in the future */ tcb_desc->mac_id = 0; if ((mac->mode == WIRELESS_MODE_N_24G) || @@ -630,7 +630,7 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) const struct iphdr *ip; if (!ieee80211_is_data(fc)) - goto end; + return false; if (ieee80211_is_nullfunc(fc)) return true; @@ -686,7 +686,6 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) return true; } -end: return false; } diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index e4f4aee8f298..8fed3c687619 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c @@ -35,7 +35,7 @@ /*mutex for start & stop is must here. */ static int rtl_op_start(struct ieee80211_hw *hw) { - int err = 0; + int err; struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); @@ -45,10 +45,8 @@ static int rtl_op_start(struct ieee80211_hw *hw) return 0; mutex_lock(&rtlpriv->locks.conf_mutex); err = rtlpriv->intf_ops->adapter_start(hw); - if (err) - goto out; - rtl_watch_dog_timer_callback((unsigned long)hw); -out: + if (!err) + rtl_watch_dog_timer_callback((unsigned long)hw); mutex_unlock(&rtlpriv->locks.conf_mutex); return err; } diff --git a/drivers/net/wireless/rtlwifi/efuse.c b/drivers/net/wireless/rtlwifi/efuse.c index 590f14f45a89..5d73c0f7012c 100644 --- a/drivers/net/wireless/rtlwifi/efuse.c +++ b/drivers/net/wireless/rtlwifi/efuse.c @@ -338,11 +338,11 @@ bool efuse_shadow_update_chk(struct ieee80211_hw *hw) struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); u8 section_idx, i, Base; u16 words_need = 0, hdr_num = 0, totalbytes, efuse_used; - bool bwordchanged, bresult = true; + bool wordchanged, result = true; for (section_idx = 0; section_idx < 16; section_idx++) { Base = section_idx * 8; - bwordchanged = false; + wordchanged = false; for (i = 0; i < 8; i = i + 2) { if ((rtlefuse->efuse_map[EFUSE_INIT_MAP][Base + i] != @@ -351,11 +351,11 @@ bool efuse_shadow_update_chk(struct ieee80211_hw *hw) rtlefuse->efuse_map[EFUSE_MODIFY_MAP][Base + i + 1])) { words_need++; - bwordchanged = true; + wordchanged = true; } } - if (bwordchanged == true) + if (wordchanged == true) hdr_num++; } @@ -364,14 +364,14 @@ bool efuse_shadow_update_chk(struct ieee80211_hw *hw) if ((totalbytes + efuse_used) >= (EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES)) - bresult = false; + result = false; RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, ("efuse_shadow_update_chk(): totalbytes(%#x), " "hdr_num(%#x), words_need(%#x), efuse_used(%d)\n", totalbytes, hdr_num, words_need, efuse_used)); - return bresult; + return result; } void efuse_shadow_read(struct ieee80211_hw *hw, u8 type, @@ -394,7 +394,7 @@ void efuse_shadow_write(struct ieee80211_hw *hw, u8 type, u16 offset, else if (type == 2) efuse_shadow_write_2byte(hw, offset, (u16) value); else if (type == 4) - efuse_shadow_write_4byte(hw, offset, (u32) value); + efuse_shadow_write_4byte(hw, offset, value); } @@ -572,7 +572,7 @@ static int efuse_one_byte_read(struct ieee80211_hw *hw, u16 addr, u8 *data) { struct rtl_priv *rtlpriv = rtl_priv(hw); u8 tmpidx = 0; - int bresult; + int result; rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1, (u8) (addr & 0xff)); @@ -592,19 +592,18 @@ static int efuse_one_byte_read(struct ieee80211_hw *hw, u16 addr, u8 *data) if (tmpidx < 100) { *data = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]); - bresult = true; + result = true; } else { *data = 0xff; - bresult = false; + result = false; } - return bresult; + return result; } static int efuse_one_byte_write(struct ieee80211_hw *hw, u16 addr, u8 data) { struct rtl_priv *rtlpriv = rtl_priv(hw); u8 tmpidx = 0; - bool bresult; RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, ("Addr = %x Data=%x\n", addr, data)); @@ -626,11 +625,9 @@ static int efuse_one_byte_write(struct ieee80211_hw *hw, u16 addr, u8 data) } if (tmpidx < 100) - bresult = true; - else - bresult = false; + return true; - return bresult; + return false; } static void efuse_read_all_map(struct ieee80211_hw *hw, u8 * efuse) @@ -681,11 +678,10 @@ static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data) { u8 readstate = PG_STATE_HEADER; - bool bcontinual = true; + bool continual = true; u8 efuse_data, word_cnts = 0; u16 efuse_addr = 0; - u8 hworden = 0; u8 tmpdata[8]; if (data == NULL) @@ -696,7 +692,7 @@ static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data) memset(data, 0xff, PGPKT_DATA_SIZE * sizeof(u8)); memset(tmpdata, 0xff, PGPKT_DATA_SIZE * sizeof(u8)); - while (bcontinual && (efuse_addr < EFUSE_MAX_SIZE)) { + while (continual && (efuse_addr < EFUSE_MAX_SIZE)) { if (readstate & PG_STATE_HEADER) { if (efuse_one_byte_read(hw, efuse_addr, &efuse_data) && (efuse_data != 0xFF)) @@ -705,9 +701,9 @@ static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data) offset, tmpdata, &readstate); else - bcontinual = false; + continual = false; } else if (readstate & PG_STATE_DATA) { - efuse_word_enable_data_read(hworden, tmpdata, data); + efuse_word_enable_data_read(0, tmpdata, data); efuse_addr = efuse_addr + (word_cnts * 2) + 1; readstate = PG_STATE_HEADER; } @@ -725,13 +721,13 @@ static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data) } static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, - u8 efuse_data, u8 offset, int *bcontinual, + u8 efuse_data, u8 offset, int *continual, u8 *write_state, struct pgpkt_struct *target_pkt, - int *repeat_times, int *bresult, u8 word_en) + int *repeat_times, int *result, u8 word_en) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct pgpkt_struct tmp_pkt; - int bdataempty = true; + bool dataempty = true; u8 originaldata[8 * sizeof(u8)]; u8 badworden = 0x0F; u8 match_word_en, tmp_word_en; @@ -751,10 +747,10 @@ static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, u16 address = *efuse_addr + 1 + tmpindex; if (efuse_one_byte_read(hw, address, &efuse_data) && (efuse_data != 0xFF)) - bdataempty = false; + dataempty = false; } - if (bdataempty == false) { + if (dataempty == false) { *efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1; *write_state = PG_STATE_HEADER; } else { @@ -811,12 +807,12 @@ static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, target_pkt->offset = offset; target_pkt->word_en = tmp_word_en; } else - *bcontinual = false; + *continual = false; *write_state = PG_STATE_HEADER; *repeat_times += 1; if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { - *bcontinual = false; - *bresult = false; + *continual = false; + *result = false; } } else { *efuse_addr += (2 * tmp_word_cnts) + 1; @@ -830,9 +826,9 @@ static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, } static void efuse_write_data_case2(struct ieee80211_hw *hw, u16 *efuse_addr, - int *bcontinual, u8 *write_state, + int *continual, u8 *write_state, struct pgpkt_struct target_pkt, - int *repeat_times, int *bresult) + int *repeat_times, int *result) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct pgpkt_struct tmp_pkt; @@ -852,8 +848,8 @@ static void efuse_write_data_case2(struct ieee80211_hw *hw, u16 *efuse_addr, *write_state = PG_STATE_HEADER; *repeat_times += 1; if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { - *bcontinual = false; - *bresult = false; + *continual = false; + *result = false; } } else { tmp_pkt.offset = (tmp_header >> 4) & 0x0F; @@ -884,8 +880,8 @@ static void efuse_write_data_case2(struct ieee80211_hw *hw, u16 *efuse_addr, *write_state = PG_STATE_HEADER; *repeat_times += 1; if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { - *bcontinual = false; - *bresult = false; + *continual = false; + *result = false; } RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, @@ -899,7 +895,7 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv = rtl_priv(hw); struct pgpkt_struct target_pkt; u8 write_state = PG_STATE_HEADER; - int bcontinual = true, bdataempty = true, bresult = true; + int continual = true, dataempty = true, result = true; u16 efuse_addr = 0; u8 efuse_data; u8 target_word_cnts = 0; @@ -923,11 +919,11 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw, RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, ("efuse Power ON\n")); - while (bcontinual && (efuse_addr < + while (continual && (efuse_addr < (EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES))) { if (write_state == PG_STATE_HEADER) { - bdataempty = true; + dataempty = true; badworden = 0x0F; RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, ("efuse PG_STATE_HEADER\n")); @@ -936,32 +932,30 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw, (efuse_data != 0xFF)) efuse_write_data_case1(hw, &efuse_addr, efuse_data, offset, - &bcontinual, + &continual, &write_state, &target_pkt, - &repeat_times, &bresult, + &repeat_times, &result, word_en); else efuse_write_data_case2(hw, &efuse_addr, - &bcontinual, + &continual, &write_state, target_pkt, &repeat_times, - &bresult); + &result); } else if (write_state == PG_STATE_DATA) { RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, ("efuse PG_STATE_DATA\n")); - badworden = 0x0f; badworden = efuse_word_enable_data_write(hw, efuse_addr + 1, target_pkt.word_en, target_pkt.data); if ((badworden & 0x0F) == 0x0F) { - bcontinual = false; + continual = false; } else { - efuse_addr = - efuse_addr + (2 * target_word_cnts) + 1; + efuse_addr += (2 * target_word_cnts) + 1; target_pkt.offset = offset; target_pkt.word_en = badworden; @@ -971,8 +965,8 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw, write_state = PG_STATE_HEADER; repeat_times++; if (repeat_times > EFUSE_REPEAT_THRESHOLD_) { - bcontinual = false; - bresult = false; + continual = false; + result = false; } RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, ("efuse PG_STATE_HEADER-3\n")); @@ -1072,13 +1066,13 @@ static u8 efuse_word_enable_data_write(struct ieee80211_hw *hw, return badworden; } -static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, u8 pwrstate) +static void efuse_power_switch(struct ieee80211_hw *hw, u8 write, u8 pwrstate) { struct rtl_priv *rtlpriv = rtl_priv(hw); u8 tempval; u16 tmpV16; - if (pwrstate == true) { + if (pwrstate) { tmpV16 = rtl_read_word(rtlpriv, rtlpriv->cfg->maps[SYS_ISO_CTRL]); if (!(tmpV16 & rtlpriv->cfg->maps[EFUSE_PWC_EV12V])) { @@ -1106,8 +1100,8 @@ static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, u8 pwrstate) } } - if (pwrstate == true) { - if (bwrite == true) { + if (pwrstate) { + if (write) { tempval = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST] + 3); @@ -1119,7 +1113,7 @@ static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, u8 pwrstate) } } else { - if (bwrite == true) { + if (write) { tempval = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST] + 3); @@ -1134,12 +1128,12 @@ static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, u8 pwrstate) static u16 efuse_get_current_size(struct ieee80211_hw *hw) { - int bcontinual = true; + int continual = true; u16 efuse_addr = 0; u8 hoffset, hworden; u8 efuse_data, word_cnts; - while (bcontinual && efuse_one_byte_read(hw, efuse_addr, &efuse_data) + while (continual && efuse_one_byte_read(hw, efuse_addr, &efuse_data) && (efuse_addr < EFUSE_MAX_SIZE)) { if (efuse_data != 0xFF) { hoffset = (efuse_data >> 4) & 0x0F; @@ -1147,7 +1141,7 @@ static u16 efuse_get_current_size(struct ieee80211_hw *hw) word_cnts = efuse_calculate_word_cnts(hworden); efuse_addr = efuse_addr + (word_cnts * 2) + 1; } else { - bcontinual = false; + continual = false; } } diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index 5938f6ee21e4..fbde52d83424 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -113,32 +113,19 @@ static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw) /*Set HW definition to determine if it supports ASPM. */ switch (rtlpci->const_support_pciaspm) { - case 0:{ - /*Not support ASPM. */ - bool support_aspm = false; - ppsc->support_aspm = support_aspm; - break; - } - case 1:{ - /*Support ASPM. */ - bool support_aspm = true; - bool support_backdoor = true; - ppsc->support_aspm = support_aspm; - - /*if(priv->oem_id == RT_CID_TOSHIBA && - !priv->ndis_adapter.amd_l1_patch) - support_backdoor = false; */ - - ppsc->support_backdoor = support_backdoor; - - break; - } + case 0: + /*Not support ASPM. */ + ppsc->support_aspm = false; + break; + case 1: + /*Support ASPM. */ + ppsc->support_aspm = true; + ppsc->support_backdoor = true; + break; case 2: /*ASPM value set by chipset. */ - if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL) { - bool support_aspm = true; - ppsc->support_aspm = support_aspm; - } + if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL) + ppsc->support_aspm = true; break; default: RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, @@ -152,13 +139,11 @@ static bool _rtl_pci_platform_switch_device_pci_aspm( u8 value) { struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - bool bresult = false; value |= 0x40; - pci_write_config_byte(rtlpci->pdev, 0x80, value); - return bresult; + return false; } /*When we set 0x01 to enable clk request. Set 0x0 to disable clk req.*/ @@ -166,14 +151,11 @@ static bool _rtl_pci_switch_clk_req(struct ieee80211_hw *hw, u8 value) { struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); u8 buffer; - bool bresult = false; buffer = value; - pci_write_config_byte(rtlpci->pdev, 0x81, value); - bresult = true; - return bresult; + return true; } /*Disable RTL8192SE ASPM & Disable Pci Bridge ASPM*/ @@ -191,6 +173,7 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw) u16 pcibridge_linkctrlreg = pcipriv->ndis_adapter. pcibridge_linkctrlreg; u16 aspmlevel = 0; + u8 tmp_u1b = 0; if (pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) { RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, @@ -204,11 +187,8 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw) _rtl_pci_switch_clk_req(hw, 0x0); } - if (1) { - /*for promising device will in L0 state after an I/O. */ - u8 tmp_u1b; - pci_read_config_byte(rtlpci->pdev, 0x80, &tmp_u1b); - } + /*for promising device will in L0 state after an I/O. */ + pci_read_config_byte(rtlpci->pdev, 0x80, &tmp_u1b); /*Set corresponding value. */ aspmlevel |= BIT(0) | BIT(1); @@ -224,7 +204,6 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw) rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, pcibridge_linkctrlreg); udelay(50); - } /* diff --git a/drivers/net/wireless/rtlwifi/pci.h b/drivers/net/wireless/rtlwifi/pci.h index 0caa81429726..12747b9c71e1 100644 --- a/drivers/net/wireless/rtlwifi/pci.h +++ b/drivers/net/wireless/rtlwifi/pci.h @@ -192,8 +192,8 @@ struct rtl_pci { u8 const_devicepci_aspm_setting; /*If it supports ASPM, Offset[560h] = 0x40, otherwise Offset[560h] = 0x00. */ - bool b_support_aspm; - bool b_support_backdoor; + bool support_aspm; + bool support_backdoor; /*QOS & EDCA */ enum acm_method acm_method; diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c index 6b7e217b6b89..c8395fb0c050 100644 --- a/drivers/net/wireless/rtlwifi/ps.c +++ b/drivers/net/wireless/rtlwifi/ps.c @@ -63,7 +63,6 @@ EXPORT_SYMBOL(rtl_ps_enable_nic); bool rtl_ps_disable_nic(struct ieee80211_hw *hw) { - bool status = true; struct rtl_priv *rtlpriv = rtl_priv(hw); /*<1> Stop all timer */ @@ -75,7 +74,7 @@ bool rtl_ps_disable_nic(struct ieee80211_hw *hw) /*<3> Disable Adapter */ rtlpriv->cfg->ops->hw_disable(hw); - return status; + return true; } EXPORT_SYMBOL(rtl_ps_disable_nic); diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c index 28a6ce3bc239..f107660f545d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c @@ -171,7 +171,6 @@ static void _rtl92c_write_fw(struct ieee80211_hw *hw, static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); - int err = -EIO; u32 counter = 0; u32 value32; @@ -184,7 +183,7 @@ static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw) RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("chksum report faill ! REG_MCUFWDL:0x%08x .\n", value32)); - goto exit; + return -EIO; } RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, @@ -204,8 +203,7 @@ static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw) ("Polling FW ready success!!" " REG_MCUFWDL:0x%08x .\n", value32)); - err = 0; - goto exit; + return 0; } mdelay(FW_8192C_POLLING_DELAY); @@ -214,9 +212,7 @@ static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw) RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32)); - -exit: - return err; + return -EIO; } int rtl92c_download_fw(struct ieee80211_hw *hw) @@ -226,16 +222,14 @@ int rtl92c_download_fw(struct ieee80211_hw *hw) struct rtl92c_firmware_header *pfwheader; u8 *pfwdata; u32 fwsize; - int err; enum version_8192c version = rtlhal->version; const struct firmware *firmware; - printk(KERN_INFO "rtl8192cu: Loading firmware file %s\n", + printk(KERN_INFO "rtl8192c: Loading firmware file %s\n", rtlpriv->cfg->fw_name); - err = request_firmware(&firmware, rtlpriv->cfg->fw_name, - rtlpriv->io.dev); - if (err) { - printk(KERN_ERR "rtl8192cu: Firmware loading failed\n"); + if (request_firmware(&firmware, rtlpriv->cfg->fw_name, + rtlpriv->io.dev)) { + printk(KERN_ERR "rtl8192c: Firmware loading failed\n"); return 1; } @@ -267,8 +261,7 @@ int rtl92c_download_fw(struct ieee80211_hw *hw) _rtl92c_write_fw(hw, version, pfwdata, fwsize); _rtl92c_enable_fw_download(hw, false); - err = _rtl92c_fw_free_to_go(hw); - if (err) { + if (_rtl92c_fw_free_to_go(hw)) { RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("Firmware is not ready to run!\n")); } else { @@ -303,7 +296,6 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw, u16 box_reg, box_extreg; u8 u1b_tmp; bool isfw_read = false; - u8 buf_index = 0; bool bwrite_sucess = false; u8 wait_h2c_limmit = 100; u8 wait_writeh2c_limmit = 100; @@ -414,7 +406,7 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw, case 1: boxcontent[0] &= ~(BIT(7)); memcpy((u8 *) (boxcontent) + 1, - p_cmdbuffer + buf_index, 1); + p_cmdbuffer, 1); for (idx = 0; idx < 4; idx++) { rtl_write_byte(rtlpriv, box_reg + idx, @@ -424,7 +416,7 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw, case 2: boxcontent[0] &= ~(BIT(7)); memcpy((u8 *) (boxcontent) + 1, - p_cmdbuffer + buf_index, 2); + p_cmdbuffer, 2); for (idx = 0; idx < 4; idx++) { rtl_write_byte(rtlpriv, box_reg + idx, @@ -434,7 +426,7 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw, case 3: boxcontent[0] &= ~(BIT(7)); memcpy((u8 *) (boxcontent) + 1, - p_cmdbuffer + buf_index, 3); + p_cmdbuffer, 3); for (idx = 0; idx < 4; idx++) { rtl_write_byte(rtlpriv, box_reg + idx, @@ -444,9 +436,9 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw, case 4: boxcontent[0] |= (BIT(7)); memcpy((u8 *) (boxextcontent), - p_cmdbuffer + buf_index, 2); + p_cmdbuffer, 2); memcpy((u8 *) (boxcontent) + 1, - p_cmdbuffer + buf_index + 2, 2); + p_cmdbuffer + 2, 2); for (idx = 0; idx < 2; idx++) { rtl_write_byte(rtlpriv, box_extreg + idx, @@ -461,9 +453,9 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw, case 5: boxcontent[0] |= (BIT(7)); memcpy((u8 *) (boxextcontent), - p_cmdbuffer + buf_index, 2); + p_cmdbuffer, 2); memcpy((u8 *) (boxcontent) + 1, - p_cmdbuffer + buf_index + 2, 3); + p_cmdbuffer + 2, 3); for (idx = 0; idx < 2; idx++) { rtl_write_byte(rtlpriv, box_extreg + idx, diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h index 803adcc80c96..b0b0b13dd0ae 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h @@ -532,9 +532,9 @@ #define CLEAR_PCI_TX_DESC_CONTENT(__pdesc, _size) \ do { \ if (_size > TX_DESC_NEXT_DESC_OFFSET) \ - memset((void *)__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET); \ + memset(__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET); \ else \ - memset((void *)__pdesc, 0, _size); \ + memset(__pdesc, 0, _size); \ } while (0); #define RX_HAL_IS_CCK_RATE(_pdesc)\ diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c index d0b0d43b9a6d..3f0cb81c424f 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c @@ -656,7 +656,7 @@ void rtl92cu_tx_fill_cmddesc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); __le16 fc = hdr->frame_control; - memset((void *)pdesc, 0, RTL_TX_HEADER_SIZE); + memset(pdesc, 0, RTL_TX_HEADER_SIZE); if (firstseg) SET_TX_DESC_OFFSET(pdesc, RTL_TX_HEADER_SIZE); SET_TX_DESC_TX_RATE(pdesc, DESC92C_RATE1M); diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 07db95ff9bc5..2713efe07ce5 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -766,7 +766,7 @@ struct rtl_rfkill { #define IQK_MATRIX_REG_NUM 8 #define IQK_MATRIX_SETTINGS_NUM (1 + 24 + 21) struct iqk_matrix_regs { - bool b_iqk_done; + bool iqk_done; long value[1][IQK_MATRIX_REG_NUM]; }; @@ -1621,19 +1621,19 @@ struct bt_coexist_info { u32 bt_edca_ul; u32 bt_edca_dl; - bool b_init_set; - bool b_bt_busy_traffic; - bool b_bt_traffic_mode_set; - bool b_bt_non_traffic_mode_set; + bool init_set; + bool bt_busy_traffic; + bool bt_traffic_mode_set; + bool bt_non_traffic_mode_set; - bool b_fw_coexist_all_off; - bool b_sw_coexist_all_off; + bool fw_coexist_all_off; + bool sw_coexist_all_off; u32 current_state; u32 previous_state; u8 bt_pre_rssi_state; - u8 b_reg_bt_iso; - u8 b_reg_bt_sco; + u8 reg_bt_iso; + u8 reg_bt_sco; }; diff --git a/drivers/net/wireless/wl1251/cmd.h b/drivers/net/wireless/wl1251/cmd.h index e5c74c631374..79ca5273c9e9 100644 --- a/drivers/net/wireless/wl1251/cmd.h +++ b/drivers/net/wireless/wl1251/cmd.h @@ -313,8 +313,8 @@ struct wl1251_cmd_vbm_update { } __packed; enum wl1251_cmd_ps_mode { - STATION_ACTIVE_MODE, - STATION_POWER_SAVE_MODE + CHIP_ACTIVE_MODE, + CHIP_POWER_SAVE_MODE }; struct wl1251_cmd_ps_params { diff --git a/drivers/net/wireless/wl1251/event.c b/drivers/net/wireless/wl1251/event.c index dfc4579acb06..9f15ccaf8f05 100644 --- a/drivers/net/wireless/wl1251/event.c +++ b/drivers/net/wireless/wl1251/event.c @@ -68,14 +68,16 @@ static int wl1251_event_process(struct wl1251 *wl, struct event_mailbox *mbox) if (vector & BSS_LOSE_EVENT_ID) { wl1251_debug(DEBUG_EVENT, "BSS_LOSE_EVENT"); - if (wl->psm_requested && wl->psm) { + if (wl->psm_requested && + wl->station_mode != STATION_ACTIVE_MODE) { ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); if (ret < 0) return ret; } } - if (vector & SYNCHRONIZATION_TIMEOUT_EVENT_ID && wl->psm) { + if (vector & SYNCHRONIZATION_TIMEOUT_EVENT_ID && + wl->station_mode != STATION_ACTIVE_MODE) { wl1251_debug(DEBUG_EVENT, "SYNCHRONIZATION_TIMEOUT_EVENT"); /* indicate to the stack, that beacons have been lost */ diff --git a/drivers/net/wireless/wl1251/main.c b/drivers/net/wireless/wl1251/main.c index 12c9e635a6d6..a14a48c99cdc 100644 --- a/drivers/net/wireless/wl1251/main.c +++ b/drivers/net/wireless/wl1251/main.c @@ -497,7 +497,7 @@ static void wl1251_op_stop(struct ieee80211_hw *hw) wl->rx_last_id = 0; wl->next_tx_complete = 0; wl->elp = false; - wl->psm = 0; + wl->station_mode = STATION_ACTIVE_MODE; wl->tx_queue_stopped = false; wl->power_level = WL1251_DEFAULT_POWER_LEVEL; wl->rssi_thold = 0; @@ -632,13 +632,29 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) wl->psm_requested = false; - if (wl->psm) { + if (wl->station_mode != STATION_ACTIVE_MODE) { ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); if (ret < 0) goto out_sleep; } } + if (changed & IEEE80211_CONF_CHANGE_IDLE) { + if (conf->flags & IEEE80211_CONF_IDLE) { + ret = wl1251_ps_set_mode(wl, STATION_IDLE); + if (ret < 0) + goto out_sleep; + } else { + ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); + if (ret < 0) + goto out_sleep; + ret = wl1251_join(wl, wl->bss_type, wl->channel, + wl->beacon_int, wl->dtim_period); + if (ret < 0) + goto out_sleep; + } + } + if (conf->power_level != wl->power_level) { ret = wl1251_acx_tx_power(wl, conf->power_level); if (ret < 0) @@ -1384,7 +1400,7 @@ struct ieee80211_hw *wl1251_alloc_hw(void) wl->rx_config = WL1251_DEFAULT_RX_CONFIG; wl->rx_filter = WL1251_DEFAULT_RX_FILTER; wl->elp = false; - wl->psm = 0; + wl->station_mode = STATION_ACTIVE_MODE; wl->psm_requested = false; wl->tx_queue_stopped = false; wl->power_level = WL1251_DEFAULT_POWER_LEVEL; diff --git a/drivers/net/wireless/wl1251/ps.c b/drivers/net/wireless/wl1251/ps.c index 9cc514703d2a..db719f7d2692 100644 --- a/drivers/net/wireless/wl1251/ps.c +++ b/drivers/net/wireless/wl1251/ps.c @@ -39,7 +39,7 @@ void wl1251_elp_work(struct work_struct *work) mutex_lock(&wl->mutex); - if (wl->elp || !wl->psm) + if (wl->elp || wl->station_mode == STATION_ACTIVE_MODE) goto out; wl1251_debug(DEBUG_PSM, "chip to elp"); @@ -57,7 +57,7 @@ void wl1251_ps_elp_sleep(struct wl1251 *wl) { unsigned long delay; - if (wl->psm) { + if (wl->station_mode != STATION_ACTIVE_MODE) { delay = msecs_to_jiffies(ELP_ENTRY_DELAY); ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, delay); } @@ -104,7 +104,7 @@ int wl1251_ps_elp_wakeup(struct wl1251 *wl) return 0; } -int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode) +int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_station_mode mode) { int ret; @@ -128,15 +128,24 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode) if (ret < 0) return ret; - ret = wl1251_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); + ret = wl1251_cmd_ps_mode(wl, CHIP_POWER_SAVE_MODE); if (ret < 0) return ret; ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP); if (ret < 0) return ret; + break; + case STATION_IDLE: + wl1251_debug(DEBUG_PSM, "entering idle"); - wl->psm = 1; + ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP); + if (ret < 0) + return ret; + + ret = wl1251_cmd_template_set(wl, CMD_DISCONNECT, NULL, 0); + if (ret < 0) + return ret; break; case STATION_ACTIVE_MODE: default: @@ -163,13 +172,13 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode) if (ret < 0) return ret; - ret = wl1251_cmd_ps_mode(wl, STATION_ACTIVE_MODE); + ret = wl1251_cmd_ps_mode(wl, CHIP_ACTIVE_MODE); if (ret < 0) return ret; - wl->psm = 0; break; } + wl->station_mode = mode; return ret; } diff --git a/drivers/net/wireless/wl1251/ps.h b/drivers/net/wireless/wl1251/ps.h index 55c3dda75e69..75efad246d67 100644 --- a/drivers/net/wireless/wl1251/ps.h +++ b/drivers/net/wireless/wl1251/ps.h @@ -26,7 +26,7 @@ #include "wl1251.h" #include "acx.h" -int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode); +int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_station_mode mode); void wl1251_ps_elp_sleep(struct wl1251 *wl); int wl1251_ps_elp_wakeup(struct wl1251 *wl); void wl1251_elp_work(struct work_struct *work); diff --git a/drivers/net/wireless/wl1251/wl1251.h b/drivers/net/wireless/wl1251/wl1251.h index bb23cd522b22..a77f1bbbed0a 100644 --- a/drivers/net/wireless/wl1251/wl1251.h +++ b/drivers/net/wireless/wl1251/wl1251.h @@ -129,6 +129,12 @@ enum wl1251_partition_type { PART_TABLE_LEN }; +enum wl1251_station_mode { + STATION_ACTIVE_MODE, + STATION_POWER_SAVE_MODE, + STATION_IDLE, +}; + struct wl1251_partition { u32 size; u32 start; @@ -358,8 +364,7 @@ struct wl1251 { struct delayed_work elp_work; - /* we can be in psm, but not in elp, we have to differentiate */ - bool psm; + enum wl1251_station_mode station_mode; /* PSM mode requested */ bool psm_requested; diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index a73a305d3cba..ff306d763e37 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c @@ -557,7 +557,7 @@ int zd_chip_unlock_phy_regs(struct zd_chip *chip) return r; } -/* CR157 can be optionally patched by the EEPROM for original ZD1211 */ +/* ZD_CR157 can be optionally patched by the EEPROM for original ZD1211 */ static int patch_cr157(struct zd_chip *chip) { int r; @@ -571,7 +571,7 @@ static int patch_cr157(struct zd_chip *chip) return r; dev_dbg_f(zd_chip_dev(chip), "patching value %x\n", value >> 8); - return zd_iowrite32_locked(chip, value >> 8, CR157); + return zd_iowrite32_locked(chip, value >> 8, ZD_CR157); } /* @@ -593,8 +593,8 @@ static int patch_6m_band_edge(struct zd_chip *chip, u8 channel) int zd_chip_generic_patch_6m_band(struct zd_chip *chip, int channel) { struct zd_ioreq16 ioreqs[] = { - { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, - { CR47, 0x1e }, + { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, + { ZD_CR47, 0x1e }, }; /* FIXME: Channel 11 is not the edge for all regulatory domains. */ @@ -608,69 +608,69 @@ int zd_chip_generic_patch_6m_band(struct zd_chip *chip, int channel) static int zd1211_hw_reset_phy(struct zd_chip *chip) { static const struct zd_ioreq16 ioreqs[] = { - { CR0, 0x0a }, { CR1, 0x06 }, { CR2, 0x26 }, - { CR3, 0x38 }, { CR4, 0x80 }, { CR9, 0xa0 }, - { CR10, 0x81 }, { CR11, 0x00 }, { CR12, 0x7f }, - { CR13, 0x8c }, { CR14, 0x80 }, { CR15, 0x3d }, - { CR16, 0x20 }, { CR17, 0x1e }, { CR18, 0x0a }, - { CR19, 0x48 }, { CR20, 0x0c }, { CR21, 0x0c }, - { CR22, 0x23 }, { CR23, 0x90 }, { CR24, 0x14 }, - { CR25, 0x40 }, { CR26, 0x10 }, { CR27, 0x19 }, - { CR28, 0x7f }, { CR29, 0x80 }, { CR30, 0x4b }, - { CR31, 0x60 }, { CR32, 0x43 }, { CR33, 0x08 }, - { CR34, 0x06 }, { CR35, 0x0a }, { CR36, 0x00 }, - { CR37, 0x00 }, { CR38, 0x38 }, { CR39, 0x0c }, - { CR40, 0x84 }, { CR41, 0x2a }, { CR42, 0x80 }, - { CR43, 0x10 }, { CR44, 0x12 }, { CR46, 0xff }, - { CR47, 0x1E }, { CR48, 0x26 }, { CR49, 0x5b }, - { CR64, 0xd0 }, { CR65, 0x04 }, { CR66, 0x58 }, - { CR67, 0xc9 }, { CR68, 0x88 }, { CR69, 0x41 }, - { CR70, 0x23 }, { CR71, 0x10 }, { CR72, 0xff }, - { CR73, 0x32 }, { CR74, 0x30 }, { CR75, 0x65 }, - { CR76, 0x41 }, { CR77, 0x1b }, { CR78, 0x30 }, - { CR79, 0x68 }, { CR80, 0x64 }, { CR81, 0x64 }, - { CR82, 0x00 }, { CR83, 0x00 }, { CR84, 0x00 }, - { CR85, 0x02 }, { CR86, 0x00 }, { CR87, 0x00 }, - { CR88, 0xff }, { CR89, 0xfc }, { CR90, 0x00 }, - { CR91, 0x00 }, { CR92, 0x00 }, { CR93, 0x08 }, - { CR94, 0x00 }, { CR95, 0x00 }, { CR96, 0xff }, - { CR97, 0xe7 }, { CR98, 0x00 }, { CR99, 0x00 }, - { CR100, 0x00 }, { CR101, 0xae }, { CR102, 0x02 }, - { CR103, 0x00 }, { CR104, 0x03 }, { CR105, 0x65 }, - { CR106, 0x04 }, { CR107, 0x00 }, { CR108, 0x0a }, - { CR109, 0xaa }, { CR110, 0xaa }, { CR111, 0x25 }, - { CR112, 0x25 }, { CR113, 0x00 }, { CR119, 0x1e }, - { CR125, 0x90 }, { CR126, 0x00 }, { CR127, 0x00 }, + { ZD_CR0, 0x0a }, { ZD_CR1, 0x06 }, { ZD_CR2, 0x26 }, + { ZD_CR3, 0x38 }, { ZD_CR4, 0x80 }, { ZD_CR9, 0xa0 }, + { ZD_CR10, 0x81 }, { ZD_CR11, 0x00 }, { ZD_CR12, 0x7f }, + { ZD_CR13, 0x8c }, { ZD_CR14, 0x80 }, { ZD_CR15, 0x3d }, + { ZD_CR16, 0x20 }, { ZD_CR17, 0x1e }, { ZD_CR18, 0x0a }, + { ZD_CR19, 0x48 }, { ZD_CR20, 0x0c }, { ZD_CR21, 0x0c }, + { ZD_CR22, 0x23 }, { ZD_CR23, 0x90 }, { ZD_CR24, 0x14 }, + { ZD_CR25, 0x40 }, { ZD_CR26, 0x10 }, { ZD_CR27, 0x19 }, + { ZD_CR28, 0x7f }, { ZD_CR29, 0x80 }, { ZD_CR30, 0x4b }, + { ZD_CR31, 0x60 }, { ZD_CR32, 0x43 }, { ZD_CR33, 0x08 }, + { ZD_CR34, 0x06 }, { ZD_CR35, 0x0a }, { ZD_CR36, 0x00 }, + { ZD_CR37, 0x00 }, { ZD_CR38, 0x38 }, { ZD_CR39, 0x0c }, + { ZD_CR40, 0x84 }, { ZD_CR41, 0x2a }, { ZD_CR42, 0x80 }, + { ZD_CR43, 0x10 }, { ZD_CR44, 0x12 }, { ZD_CR46, 0xff }, + { ZD_CR47, 0x1E }, { ZD_CR48, 0x26 }, { ZD_CR49, 0x5b }, + { ZD_CR64, 0xd0 }, { ZD_CR65, 0x04 }, { ZD_CR66, 0x58 }, + { ZD_CR67, 0xc9 }, { ZD_CR68, 0x88 }, { ZD_CR69, 0x41 }, + { ZD_CR70, 0x23 }, { ZD_CR71, 0x10 }, { ZD_CR72, 0xff }, + { ZD_CR73, 0x32 }, { ZD_CR74, 0x30 }, { ZD_CR75, 0x65 }, + { ZD_CR76, 0x41 }, { ZD_CR77, 0x1b }, { ZD_CR78, 0x30 }, + { ZD_CR79, 0x68 }, { ZD_CR80, 0x64 }, { ZD_CR81, 0x64 }, + { ZD_CR82, 0x00 }, { ZD_CR83, 0x00 }, { ZD_CR84, 0x00 }, + { ZD_CR85, 0x02 }, { ZD_CR86, 0x00 }, { ZD_CR87, 0x00 }, + { ZD_CR88, 0xff }, { ZD_CR89, 0xfc }, { ZD_CR90, 0x00 }, + { ZD_CR91, 0x00 }, { ZD_CR92, 0x00 }, { ZD_CR93, 0x08 }, + { ZD_CR94, 0x00 }, { ZD_CR95, 0x00 }, { ZD_CR96, 0xff }, + { ZD_CR97, 0xe7 }, { ZD_CR98, 0x00 }, { ZD_CR99, 0x00 }, + { ZD_CR100, 0x00 }, { ZD_CR101, 0xae }, { ZD_CR102, 0x02 }, + { ZD_CR103, 0x00 }, { ZD_CR104, 0x03 }, { ZD_CR105, 0x65 }, + { ZD_CR106, 0x04 }, { ZD_CR107, 0x00 }, { ZD_CR108, 0x0a }, + { ZD_CR109, 0xaa }, { ZD_CR110, 0xaa }, { ZD_CR111, 0x25 }, + { ZD_CR112, 0x25 }, { ZD_CR113, 0x00 }, { ZD_CR119, 0x1e }, + { ZD_CR125, 0x90 }, { ZD_CR126, 0x00 }, { ZD_CR127, 0x00 }, { }, - { CR5, 0x00 }, { CR6, 0x00 }, { CR7, 0x00 }, - { CR8, 0x00 }, { CR9, 0x20 }, { CR12, 0xf0 }, - { CR20, 0x0e }, { CR21, 0x0e }, { CR27, 0x10 }, - { CR44, 0x33 }, { CR47, 0x1E }, { CR83, 0x24 }, - { CR84, 0x04 }, { CR85, 0x00 }, { CR86, 0x0C }, - { CR87, 0x12 }, { CR88, 0x0C }, { CR89, 0x00 }, - { CR90, 0x10 }, { CR91, 0x08 }, { CR93, 0x00 }, - { CR94, 0x01 }, { CR95, 0x00 }, { CR96, 0x50 }, - { CR97, 0x37 }, { CR98, 0x35 }, { CR101, 0x13 }, - { CR102, 0x27 }, { CR103, 0x27 }, { CR104, 0x18 }, - { CR105, 0x12 }, { CR109, 0x27 }, { CR110, 0x27 }, - { CR111, 0x27 }, { CR112, 0x27 }, { CR113, 0x27 }, - { CR114, 0x27 }, { CR115, 0x26 }, { CR116, 0x24 }, - { CR117, 0xfc }, { CR118, 0xfa }, { CR120, 0x4f }, - { CR125, 0xaa }, { CR127, 0x03 }, { CR128, 0x14 }, - { CR129, 0x12 }, { CR130, 0x10 }, { CR131, 0x0C }, - { CR136, 0xdf }, { CR137, 0x40 }, { CR138, 0xa0 }, - { CR139, 0xb0 }, { CR140, 0x99 }, { CR141, 0x82 }, - { CR142, 0x54 }, { CR143, 0x1c }, { CR144, 0x6c }, - { CR147, 0x07 }, { CR148, 0x4c }, { CR149, 0x50 }, - { CR150, 0x0e }, { CR151, 0x18 }, { CR160, 0xfe }, - { CR161, 0xee }, { CR162, 0xaa }, { CR163, 0xfa }, - { CR164, 0xfa }, { CR165, 0xea }, { CR166, 0xbe }, - { CR167, 0xbe }, { CR168, 0x6a }, { CR169, 0xba }, - { CR170, 0xba }, { CR171, 0xba }, - /* Note: CR204 must lead the CR203 */ - { CR204, 0x7d }, + { ZD_CR5, 0x00 }, { ZD_CR6, 0x00 }, { ZD_CR7, 0x00 }, + { ZD_CR8, 0x00 }, { ZD_CR9, 0x20 }, { ZD_CR12, 0xf0 }, + { ZD_CR20, 0x0e }, { ZD_CR21, 0x0e }, { ZD_CR27, 0x10 }, + { ZD_CR44, 0x33 }, { ZD_CR47, 0x1E }, { ZD_CR83, 0x24 }, + { ZD_CR84, 0x04 }, { ZD_CR85, 0x00 }, { ZD_CR86, 0x0C }, + { ZD_CR87, 0x12 }, { ZD_CR88, 0x0C }, { ZD_CR89, 0x00 }, + { ZD_CR90, 0x10 }, { ZD_CR91, 0x08 }, { ZD_CR93, 0x00 }, + { ZD_CR94, 0x01 }, { ZD_CR95, 0x00 }, { ZD_CR96, 0x50 }, + { ZD_CR97, 0x37 }, { ZD_CR98, 0x35 }, { ZD_CR101, 0x13 }, + { ZD_CR102, 0x27 }, { ZD_CR103, 0x27 }, { ZD_CR104, 0x18 }, + { ZD_CR105, 0x12 }, { ZD_CR109, 0x27 }, { ZD_CR110, 0x27 }, + { ZD_CR111, 0x27 }, { ZD_CR112, 0x27 }, { ZD_CR113, 0x27 }, + { ZD_CR114, 0x27 }, { ZD_CR115, 0x26 }, { ZD_CR116, 0x24 }, + { ZD_CR117, 0xfc }, { ZD_CR118, 0xfa }, { ZD_CR120, 0x4f }, + { ZD_CR125, 0xaa }, { ZD_CR127, 0x03 }, { ZD_CR128, 0x14 }, + { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, { ZD_CR131, 0x0C }, + { ZD_CR136, 0xdf }, { ZD_CR137, 0x40 }, { ZD_CR138, 0xa0 }, + { ZD_CR139, 0xb0 }, { ZD_CR140, 0x99 }, { ZD_CR141, 0x82 }, + { ZD_CR142, 0x54 }, { ZD_CR143, 0x1c }, { ZD_CR144, 0x6c }, + { ZD_CR147, 0x07 }, { ZD_CR148, 0x4c }, { ZD_CR149, 0x50 }, + { ZD_CR150, 0x0e }, { ZD_CR151, 0x18 }, { ZD_CR160, 0xfe }, + { ZD_CR161, 0xee }, { ZD_CR162, 0xaa }, { ZD_CR163, 0xfa }, + { ZD_CR164, 0xfa }, { ZD_CR165, 0xea }, { ZD_CR166, 0xbe }, + { ZD_CR167, 0xbe }, { ZD_CR168, 0x6a }, { ZD_CR169, 0xba }, + { ZD_CR170, 0xba }, { ZD_CR171, 0xba }, + /* Note: ZD_CR204 must lead the ZD_CR203 */ + { ZD_CR204, 0x7d }, { }, - { CR203, 0x30 }, + { ZD_CR203, 0x30 }, }; int r, t; @@ -697,62 +697,62 @@ out: static int zd1211b_hw_reset_phy(struct zd_chip *chip) { static const struct zd_ioreq16 ioreqs[] = { - { CR0, 0x14 }, { CR1, 0x06 }, { CR2, 0x26 }, - { CR3, 0x38 }, { CR4, 0x80 }, { CR9, 0xe0 }, - { CR10, 0x81 }, - /* power control { { CR11, 1 << 6 }, */ - { CR11, 0x00 }, - { CR12, 0xf0 }, { CR13, 0x8c }, { CR14, 0x80 }, - { CR15, 0x3d }, { CR16, 0x20 }, { CR17, 0x1e }, - { CR18, 0x0a }, { CR19, 0x48 }, - { CR20, 0x10 }, /* Org:0x0E, ComTrend:RalLink AP */ - { CR21, 0x0e }, { CR22, 0x23 }, { CR23, 0x90 }, - { CR24, 0x14 }, { CR25, 0x40 }, { CR26, 0x10 }, - { CR27, 0x10 }, { CR28, 0x7f }, { CR29, 0x80 }, - { CR30, 0x4b }, /* ASIC/FWT, no jointly decoder */ - { CR31, 0x60 }, { CR32, 0x43 }, { CR33, 0x08 }, - { CR34, 0x06 }, { CR35, 0x0a }, { CR36, 0x00 }, - { CR37, 0x00 }, { CR38, 0x38 }, { CR39, 0x0c }, - { CR40, 0x84 }, { CR41, 0x2a }, { CR42, 0x80 }, - { CR43, 0x10 }, { CR44, 0x33 }, { CR46, 0xff }, - { CR47, 0x1E }, { CR48, 0x26 }, { CR49, 0x5b }, - { CR64, 0xd0 }, { CR65, 0x04 }, { CR66, 0x58 }, - { CR67, 0xc9 }, { CR68, 0x88 }, { CR69, 0x41 }, - { CR70, 0x23 }, { CR71, 0x10 }, { CR72, 0xff }, - { CR73, 0x32 }, { CR74, 0x30 }, { CR75, 0x65 }, - { CR76, 0x41 }, { CR77, 0x1b }, { CR78, 0x30 }, - { CR79, 0xf0 }, { CR80, 0x64 }, { CR81, 0x64 }, - { CR82, 0x00 }, { CR83, 0x24 }, { CR84, 0x04 }, - { CR85, 0x00 }, { CR86, 0x0c }, { CR87, 0x12 }, - { CR88, 0x0c }, { CR89, 0x00 }, { CR90, 0x58 }, - { CR91, 0x04 }, { CR92, 0x00 }, { CR93, 0x00 }, - { CR94, 0x01 }, - { CR95, 0x20 }, /* ZD1211B */ - { CR96, 0x50 }, { CR97, 0x37 }, { CR98, 0x35 }, - { CR99, 0x00 }, { CR100, 0x01 }, { CR101, 0x13 }, - { CR102, 0x27 }, { CR103, 0x27 }, { CR104, 0x18 }, - { CR105, 0x12 }, { CR106, 0x04 }, { CR107, 0x00 }, - { CR108, 0x0a }, { CR109, 0x27 }, { CR110, 0x27 }, - { CR111, 0x27 }, { CR112, 0x27 }, { CR113, 0x27 }, - { CR114, 0x27 }, { CR115, 0x26 }, { CR116, 0x24 }, - { CR117, 0xfc }, { CR118, 0xfa }, { CR119, 0x1e }, - { CR125, 0x90 }, { CR126, 0x00 }, { CR127, 0x00 }, - { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, - { CR131, 0x0c }, { CR136, 0xdf }, { CR137, 0xa0 }, - { CR138, 0xa8 }, { CR139, 0xb4 }, { CR140, 0x98 }, - { CR141, 0x82 }, { CR142, 0x53 }, { CR143, 0x1c }, - { CR144, 0x6c }, { CR147, 0x07 }, { CR148, 0x40 }, - { CR149, 0x40 }, /* Org:0x50 ComTrend:RalLink AP */ - { CR150, 0x14 }, /* Org:0x0E ComTrend:RalLink AP */ - { CR151, 0x18 }, { CR159, 0x70 }, { CR160, 0xfe }, - { CR161, 0xee }, { CR162, 0xaa }, { CR163, 0xfa }, - { CR164, 0xfa }, { CR165, 0xea }, { CR166, 0xbe }, - { CR167, 0xbe }, { CR168, 0x6a }, { CR169, 0xba }, - { CR170, 0xba }, { CR171, 0xba }, - /* Note: CR204 must lead the CR203 */ - { CR204, 0x7d }, + { ZD_CR0, 0x14 }, { ZD_CR1, 0x06 }, { ZD_CR2, 0x26 }, + { ZD_CR3, 0x38 }, { ZD_CR4, 0x80 }, { ZD_CR9, 0xe0 }, + { ZD_CR10, 0x81 }, + /* power control { { ZD_CR11, 1 << 6 }, */ + { ZD_CR11, 0x00 }, + { ZD_CR12, 0xf0 }, { ZD_CR13, 0x8c }, { ZD_CR14, 0x80 }, + { ZD_CR15, 0x3d }, { ZD_CR16, 0x20 }, { ZD_CR17, 0x1e }, + { ZD_CR18, 0x0a }, { ZD_CR19, 0x48 }, + { ZD_CR20, 0x10 }, /* Org:0x0E, ComTrend:RalLink AP */ + { ZD_CR21, 0x0e }, { ZD_CR22, 0x23 }, { ZD_CR23, 0x90 }, + { ZD_CR24, 0x14 }, { ZD_CR25, 0x40 }, { ZD_CR26, 0x10 }, + { ZD_CR27, 0x10 }, { ZD_CR28, 0x7f }, { ZD_CR29, 0x80 }, + { ZD_CR30, 0x4b }, /* ASIC/FWT, no jointly decoder */ + { ZD_CR31, 0x60 }, { ZD_CR32, 0x43 }, { ZD_CR33, 0x08 }, + { ZD_CR34, 0x06 }, { ZD_CR35, 0x0a }, { ZD_CR36, 0x00 }, + { ZD_CR37, 0x00 }, { ZD_CR38, 0x38 }, { ZD_CR39, 0x0c }, + { ZD_CR40, 0x84 }, { ZD_CR41, 0x2a }, { ZD_CR42, 0x80 }, + { ZD_CR43, 0x10 }, { ZD_CR44, 0x33 }, { ZD_CR46, 0xff }, + { ZD_CR47, 0x1E }, { ZD_CR48, 0x26 }, { ZD_CR49, 0x5b }, + { ZD_CR64, 0xd0 }, { ZD_CR65, 0x04 }, { ZD_CR66, 0x58 }, + { ZD_CR67, 0xc9 }, { ZD_CR68, 0x88 }, { ZD_CR69, 0x41 }, + { ZD_CR70, 0x23 }, { ZD_CR71, 0x10 }, { ZD_CR72, 0xff }, + { ZD_CR73, 0x32 }, { ZD_CR74, 0x30 }, { ZD_CR75, 0x65 }, + { ZD_CR76, 0x41 }, { ZD_CR77, 0x1b }, { ZD_CR78, 0x30 }, + { ZD_CR79, 0xf0 }, { ZD_CR80, 0x64 }, { ZD_CR81, 0x64 }, + { ZD_CR82, 0x00 }, { ZD_CR83, 0x24 }, { ZD_CR84, 0x04 }, + { ZD_CR85, 0x00 }, { ZD_CR86, 0x0c }, { ZD_CR87, 0x12 }, + { ZD_CR88, 0x0c }, { ZD_CR89, 0x00 }, { ZD_CR90, 0x58 }, + { ZD_CR91, 0x04 }, { ZD_CR92, 0x00 }, { ZD_CR93, 0x00 }, + { ZD_CR94, 0x01 }, + { ZD_CR95, 0x20 }, /* ZD1211B */ + { ZD_CR96, 0x50 }, { ZD_CR97, 0x37 }, { ZD_CR98, 0x35 }, + { ZD_CR99, 0x00 }, { ZD_CR100, 0x01 }, { ZD_CR101, 0x13 }, + { ZD_CR102, 0x27 }, { ZD_CR103, 0x27 }, { ZD_CR104, 0x18 }, + { ZD_CR105, 0x12 }, { ZD_CR106, 0x04 }, { ZD_CR107, 0x00 }, + { ZD_CR108, 0x0a }, { ZD_CR109, 0x27 }, { ZD_CR110, 0x27 }, + { ZD_CR111, 0x27 }, { ZD_CR112, 0x27 }, { ZD_CR113, 0x27 }, + { ZD_CR114, 0x27 }, { ZD_CR115, 0x26 }, { ZD_CR116, 0x24 }, + { ZD_CR117, 0xfc }, { ZD_CR118, 0xfa }, { ZD_CR119, 0x1e }, + { ZD_CR125, 0x90 }, { ZD_CR126, 0x00 }, { ZD_CR127, 0x00 }, + { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, + { ZD_CR131, 0x0c }, { ZD_CR136, 0xdf }, { ZD_CR137, 0xa0 }, + { ZD_CR138, 0xa8 }, { ZD_CR139, 0xb4 }, { ZD_CR140, 0x98 }, + { ZD_CR141, 0x82 }, { ZD_CR142, 0x53 }, { ZD_CR143, 0x1c }, + { ZD_CR144, 0x6c }, { ZD_CR147, 0x07 }, { ZD_CR148, 0x40 }, + { ZD_CR149, 0x40 }, /* Org:0x50 ComTrend:RalLink AP */ + { ZD_CR150, 0x14 }, /* Org:0x0E ComTrend:RalLink AP */ + { ZD_CR151, 0x18 }, { ZD_CR159, 0x70 }, { ZD_CR160, 0xfe }, + { ZD_CR161, 0xee }, { ZD_CR162, 0xaa }, { ZD_CR163, 0xfa }, + { ZD_CR164, 0xfa }, { ZD_CR165, 0xea }, { ZD_CR166, 0xbe }, + { ZD_CR167, 0xbe }, { ZD_CR168, 0x6a }, { ZD_CR169, 0xba }, + { ZD_CR170, 0xba }, { ZD_CR171, 0xba }, + /* Note: ZD_CR204 must lead the ZD_CR203 */ + { ZD_CR204, 0x7d }, {}, - { CR203, 0x30 }, + { ZD_CR203, 0x30 }, }; int r, t; @@ -1200,24 +1200,24 @@ out: static int update_pwr_int(struct zd_chip *chip, u8 channel) { u8 value = chip->pwr_int_values[channel - 1]; - return zd_iowrite16_locked(chip, value, CR31); + return zd_iowrite16_locked(chip, value, ZD_CR31); } static int update_pwr_cal(struct zd_chip *chip, u8 channel) { u8 value = chip->pwr_cal_values[channel-1]; - return zd_iowrite16_locked(chip, value, CR68); + return zd_iowrite16_locked(chip, value, ZD_CR68); } static int update_ofdm_cal(struct zd_chip *chip, u8 channel) { struct zd_ioreq16 ioreqs[3]; - ioreqs[0].addr = CR67; + ioreqs[0].addr = ZD_CR67; ioreqs[0].value = chip->ofdm_cal_values[OFDM_36M_INDEX][channel-1]; - ioreqs[1].addr = CR66; + ioreqs[1].addr = ZD_CR66; ioreqs[1].value = chip->ofdm_cal_values[OFDM_48M_INDEX][channel-1]; - ioreqs[2].addr = CR65; + ioreqs[2].addr = ZD_CR65; ioreqs[2].value = chip->ofdm_cal_values[OFDM_54M_INDEX][channel-1]; return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); @@ -1236,9 +1236,9 @@ static int update_channel_integration_and_calibration(struct zd_chip *chip, return r; if (zd_chip_is_zd1211b(chip)) { static const struct zd_ioreq16 ioreqs[] = { - { CR69, 0x28 }, + { ZD_CR69, 0x28 }, {}, - { CR69, 0x2a }, + { ZD_CR69, 0x2a }, }; r = update_ofdm_cal(chip, channel); @@ -1269,7 +1269,7 @@ static int patch_cck_gain(struct zd_chip *chip) if (r) return r; dev_dbg_f(zd_chip_dev(chip), "patching value %x\n", value & 0xff); - return zd_iowrite16_locked(chip, value & 0xff, CR47); + return zd_iowrite16_locked(chip, value & 0xff, ZD_CR47); } int zd_chip_set_channel(struct zd_chip *chip, u8 channel) @@ -1505,9 +1505,9 @@ int zd_rfwritev_locked(struct zd_chip *chip, int zd_rfwrite_cr_locked(struct zd_chip *chip, u32 value) { const struct zd_ioreq16 ioreqs[] = { - { CR244, (value >> 16) & 0xff }, - { CR243, (value >> 8) & 0xff }, - { CR242, value & 0xff }, + { ZD_CR244, (value >> 16) & 0xff }, + { ZD_CR243, (value >> 8) & 0xff }, + { ZD_CR242, value & 0xff }, }; ZD_ASSERT(mutex_is_locked(&chip->mutex)); return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h index 14e4402a6111..4be7c3b5b265 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.h +++ b/drivers/net/wireless/zd1211rw/zd_chip.h @@ -61,277 +61,288 @@ enum { #define FWRAW_DATA(offset) ((zd_addr_t)(FW_START + (offset))) /* 8-bit hardware registers */ -#define CR0 CTL_REG(0x0000) -#define CR1 CTL_REG(0x0004) -#define CR2 CTL_REG(0x0008) -#define CR3 CTL_REG(0x000C) +#define ZD_CR0 CTL_REG(0x0000) +#define ZD_CR1 CTL_REG(0x0004) +#define ZD_CR2 CTL_REG(0x0008) +#define ZD_CR3 CTL_REG(0x000C) -#define CR5 CTL_REG(0x0010) +#define ZD_CR5 CTL_REG(0x0010) /* bit 5: if set short preamble used * bit 6: filter band - Japan channel 14 on, else off */ -#define CR6 CTL_REG(0x0014) -#define CR7 CTL_REG(0x0018) -#define CR8 CTL_REG(0x001C) +#define ZD_CR6 CTL_REG(0x0014) +#define ZD_CR7 CTL_REG(0x0018) +#define ZD_CR8 CTL_REG(0x001C) -#define CR4 CTL_REG(0x0020) +#define ZD_CR4 CTL_REG(0x0020) -#define CR9 CTL_REG(0x0024) -/* bit 2: antenna switch (together with CR10) */ -#define CR10 CTL_REG(0x0028) -/* bit 1: antenna switch (together with CR9) - * RF2959 controls with CR11 radion on and off +#define ZD_CR9 CTL_REG(0x0024) +/* bit 2: antenna switch (together with ZD_CR10) */ +#define ZD_CR10 CTL_REG(0x0028) +/* bit 1: antenna switch (together with ZD_CR9) + * RF2959 controls with ZD_CR11 radion on and off */ -#define CR11 CTL_REG(0x002C) +#define ZD_CR11 CTL_REG(0x002C) /* bit 6: TX power control for OFDM - * RF2959 controls with CR10 radio on and off + * RF2959 controls with ZD_CR10 radio on and off */ -#define CR12 CTL_REG(0x0030) -#define CR13 CTL_REG(0x0034) -#define CR14 CTL_REG(0x0038) -#define CR15 CTL_REG(0x003C) -#define CR16 CTL_REG(0x0040) -#define CR17 CTL_REG(0x0044) -#define CR18 CTL_REG(0x0048) -#define CR19 CTL_REG(0x004C) -#define CR20 CTL_REG(0x0050) -#define CR21 CTL_REG(0x0054) -#define CR22 CTL_REG(0x0058) -#define CR23 CTL_REG(0x005C) -#define CR24 CTL_REG(0x0060) /* CCA threshold */ -#define CR25 CTL_REG(0x0064) -#define CR26 CTL_REG(0x0068) -#define CR27 CTL_REG(0x006C) -#define CR28 CTL_REG(0x0070) -#define CR29 CTL_REG(0x0074) -#define CR30 CTL_REG(0x0078) -#define CR31 CTL_REG(0x007C) /* TX power control for RF in CCK mode */ -#define CR32 CTL_REG(0x0080) -#define CR33 CTL_REG(0x0084) -#define CR34 CTL_REG(0x0088) -#define CR35 CTL_REG(0x008C) -#define CR36 CTL_REG(0x0090) -#define CR37 CTL_REG(0x0094) -#define CR38 CTL_REG(0x0098) -#define CR39 CTL_REG(0x009C) -#define CR40 CTL_REG(0x00A0) -#define CR41 CTL_REG(0x00A4) -#define CR42 CTL_REG(0x00A8) -#define CR43 CTL_REG(0x00AC) -#define CR44 CTL_REG(0x00B0) -#define CR45 CTL_REG(0x00B4) -#define CR46 CTL_REG(0x00B8) -#define CR47 CTL_REG(0x00BC) /* CCK baseband gain - * (patch value might be in EEPROM) - */ -#define CR48 CTL_REG(0x00C0) -#define CR49 CTL_REG(0x00C4) -#define CR50 CTL_REG(0x00C8) -#define CR51 CTL_REG(0x00CC) /* TX power control for RF in 6-36M modes */ -#define CR52 CTL_REG(0x00D0) /* TX power control for RF in 48M mode */ -#define CR53 CTL_REG(0x00D4) /* TX power control for RF in 54M mode */ -#define CR54 CTL_REG(0x00D8) -#define CR55 CTL_REG(0x00DC) -#define CR56 CTL_REG(0x00E0) -#define CR57 CTL_REG(0x00E4) -#define CR58 CTL_REG(0x00E8) -#define CR59 CTL_REG(0x00EC) -#define CR60 CTL_REG(0x00F0) -#define CR61 CTL_REG(0x00F4) -#define CR62 CTL_REG(0x00F8) -#define CR63 CTL_REG(0x00FC) -#define CR64 CTL_REG(0x0100) -#define CR65 CTL_REG(0x0104) /* OFDM 54M calibration */ -#define CR66 CTL_REG(0x0108) /* OFDM 48M calibration */ -#define CR67 CTL_REG(0x010C) /* OFDM 36M calibration */ -#define CR68 CTL_REG(0x0110) /* CCK calibration */ -#define CR69 CTL_REG(0x0114) -#define CR70 CTL_REG(0x0118) -#define CR71 CTL_REG(0x011C) -#define CR72 CTL_REG(0x0120) -#define CR73 CTL_REG(0x0124) -#define CR74 CTL_REG(0x0128) -#define CR75 CTL_REG(0x012C) -#define CR76 CTL_REG(0x0130) -#define CR77 CTL_REG(0x0134) -#define CR78 CTL_REG(0x0138) -#define CR79 CTL_REG(0x013C) -#define CR80 CTL_REG(0x0140) -#define CR81 CTL_REG(0x0144) -#define CR82 CTL_REG(0x0148) -#define CR83 CTL_REG(0x014C) -#define CR84 CTL_REG(0x0150) -#define CR85 CTL_REG(0x0154) -#define CR86 CTL_REG(0x0158) -#define CR87 CTL_REG(0x015C) -#define CR88 CTL_REG(0x0160) -#define CR89 CTL_REG(0x0164) -#define CR90 CTL_REG(0x0168) -#define CR91 CTL_REG(0x016C) -#define CR92 CTL_REG(0x0170) -#define CR93 CTL_REG(0x0174) -#define CR94 CTL_REG(0x0178) -#define CR95 CTL_REG(0x017C) -#define CR96 CTL_REG(0x0180) -#define CR97 CTL_REG(0x0184) -#define CR98 CTL_REG(0x0188) -#define CR99 CTL_REG(0x018C) -#define CR100 CTL_REG(0x0190) -#define CR101 CTL_REG(0x0194) -#define CR102 CTL_REG(0x0198) -#define CR103 CTL_REG(0x019C) -#define CR104 CTL_REG(0x01A0) -#define CR105 CTL_REG(0x01A4) -#define CR106 CTL_REG(0x01A8) -#define CR107 CTL_REG(0x01AC) -#define CR108 CTL_REG(0x01B0) -#define CR109 CTL_REG(0x01B4) -#define CR110 CTL_REG(0x01B8) -#define CR111 CTL_REG(0x01BC) -#define CR112 CTL_REG(0x01C0) -#define CR113 CTL_REG(0x01C4) -#define CR114 CTL_REG(0x01C8) -#define CR115 CTL_REG(0x01CC) -#define CR116 CTL_REG(0x01D0) -#define CR117 CTL_REG(0x01D4) -#define CR118 CTL_REG(0x01D8) -#define CR119 CTL_REG(0x01DC) -#define CR120 CTL_REG(0x01E0) -#define CR121 CTL_REG(0x01E4) -#define CR122 CTL_REG(0x01E8) -#define CR123 CTL_REG(0x01EC) -#define CR124 CTL_REG(0x01F0) -#define CR125 CTL_REG(0x01F4) -#define CR126 CTL_REG(0x01F8) -#define CR127 CTL_REG(0x01FC) -#define CR128 CTL_REG(0x0200) -#define CR129 CTL_REG(0x0204) -#define CR130 CTL_REG(0x0208) -#define CR131 CTL_REG(0x020C) -#define CR132 CTL_REG(0x0210) -#define CR133 CTL_REG(0x0214) -#define CR134 CTL_REG(0x0218) -#define CR135 CTL_REG(0x021C) -#define CR136 CTL_REG(0x0220) -#define CR137 CTL_REG(0x0224) -#define CR138 CTL_REG(0x0228) -#define CR139 CTL_REG(0x022C) -#define CR140 CTL_REG(0x0230) -#define CR141 CTL_REG(0x0234) -#define CR142 CTL_REG(0x0238) -#define CR143 CTL_REG(0x023C) -#define CR144 CTL_REG(0x0240) -#define CR145 CTL_REG(0x0244) -#define CR146 CTL_REG(0x0248) -#define CR147 CTL_REG(0x024C) -#define CR148 CTL_REG(0x0250) -#define CR149 CTL_REG(0x0254) -#define CR150 CTL_REG(0x0258) -#define CR151 CTL_REG(0x025C) -#define CR152 CTL_REG(0x0260) -#define CR153 CTL_REG(0x0264) -#define CR154 CTL_REG(0x0268) -#define CR155 CTL_REG(0x026C) -#define CR156 CTL_REG(0x0270) -#define CR157 CTL_REG(0x0274) -#define CR158 CTL_REG(0x0278) -#define CR159 CTL_REG(0x027C) -#define CR160 CTL_REG(0x0280) -#define CR161 CTL_REG(0x0284) -#define CR162 CTL_REG(0x0288) -#define CR163 CTL_REG(0x028C) -#define CR164 CTL_REG(0x0290) -#define CR165 CTL_REG(0x0294) -#define CR166 CTL_REG(0x0298) -#define CR167 CTL_REG(0x029C) -#define CR168 CTL_REG(0x02A0) -#define CR169 CTL_REG(0x02A4) -#define CR170 CTL_REG(0x02A8) -#define CR171 CTL_REG(0x02AC) -#define CR172 CTL_REG(0x02B0) -#define CR173 CTL_REG(0x02B4) -#define CR174 CTL_REG(0x02B8) -#define CR175 CTL_REG(0x02BC) -#define CR176 CTL_REG(0x02C0) -#define CR177 CTL_REG(0x02C4) -#define CR178 CTL_REG(0x02C8) -#define CR179 CTL_REG(0x02CC) -#define CR180 CTL_REG(0x02D0) -#define CR181 CTL_REG(0x02D4) -#define CR182 CTL_REG(0x02D8) -#define CR183 CTL_REG(0x02DC) -#define CR184 CTL_REG(0x02E0) -#define CR185 CTL_REG(0x02E4) -#define CR186 CTL_REG(0x02E8) -#define CR187 CTL_REG(0x02EC) -#define CR188 CTL_REG(0x02F0) -#define CR189 CTL_REG(0x02F4) -#define CR190 CTL_REG(0x02F8) -#define CR191 CTL_REG(0x02FC) -#define CR192 CTL_REG(0x0300) -#define CR193 CTL_REG(0x0304) -#define CR194 CTL_REG(0x0308) -#define CR195 CTL_REG(0x030C) -#define CR196 CTL_REG(0x0310) -#define CR197 CTL_REG(0x0314) -#define CR198 CTL_REG(0x0318) -#define CR199 CTL_REG(0x031C) -#define CR200 CTL_REG(0x0320) -#define CR201 CTL_REG(0x0324) -#define CR202 CTL_REG(0x0328) -#define CR203 CTL_REG(0x032C) /* I2C bus template value & flash control */ -#define CR204 CTL_REG(0x0330) -#define CR205 CTL_REG(0x0334) -#define CR206 CTL_REG(0x0338) -#define CR207 CTL_REG(0x033C) -#define CR208 CTL_REG(0x0340) -#define CR209 CTL_REG(0x0344) -#define CR210 CTL_REG(0x0348) -#define CR211 CTL_REG(0x034C) -#define CR212 CTL_REG(0x0350) -#define CR213 CTL_REG(0x0354) -#define CR214 CTL_REG(0x0358) -#define CR215 CTL_REG(0x035C) -#define CR216 CTL_REG(0x0360) -#define CR217 CTL_REG(0x0364) -#define CR218 CTL_REG(0x0368) -#define CR219 CTL_REG(0x036C) -#define CR220 CTL_REG(0x0370) -#define CR221 CTL_REG(0x0374) -#define CR222 CTL_REG(0x0378) -#define CR223 CTL_REG(0x037C) -#define CR224 CTL_REG(0x0380) -#define CR225 CTL_REG(0x0384) -#define CR226 CTL_REG(0x0388) -#define CR227 CTL_REG(0x038C) -#define CR228 CTL_REG(0x0390) -#define CR229 CTL_REG(0x0394) -#define CR230 CTL_REG(0x0398) -#define CR231 CTL_REG(0x039C) -#define CR232 CTL_REG(0x03A0) -#define CR233 CTL_REG(0x03A4) -#define CR234 CTL_REG(0x03A8) -#define CR235 CTL_REG(0x03AC) -#define CR236 CTL_REG(0x03B0) - -#define CR240 CTL_REG(0x03C0) -/* bit 7: host-controlled RF register writes - * CR241-CR245: for hardware controlled writing of RF bits, not needed for - * USB +#define ZD_CR12 CTL_REG(0x0030) +#define ZD_CR13 CTL_REG(0x0034) +#define ZD_CR14 CTL_REG(0x0038) +#define ZD_CR15 CTL_REG(0x003C) +#define ZD_CR16 CTL_REG(0x0040) +#define ZD_CR17 CTL_REG(0x0044) +#define ZD_CR18 CTL_REG(0x0048) +#define ZD_CR19 CTL_REG(0x004C) +#define ZD_CR20 CTL_REG(0x0050) +#define ZD_CR21 CTL_REG(0x0054) +#define ZD_CR22 CTL_REG(0x0058) +#define ZD_CR23 CTL_REG(0x005C) +#define ZD_CR24 CTL_REG(0x0060) /* CCA threshold */ +#define ZD_CR25 CTL_REG(0x0064) +#define ZD_CR26 CTL_REG(0x0068) +#define ZD_CR27 CTL_REG(0x006C) +#define ZD_CR28 CTL_REG(0x0070) +#define ZD_CR29 CTL_REG(0x0074) +#define ZD_CR30 CTL_REG(0x0078) +#define ZD_CR31 CTL_REG(0x007C) /* TX power control for RF in + * CCK mode + */ +#define ZD_CR32 CTL_REG(0x0080) +#define ZD_CR33 CTL_REG(0x0084) +#define ZD_CR34 CTL_REG(0x0088) +#define ZD_CR35 CTL_REG(0x008C) +#define ZD_CR36 CTL_REG(0x0090) +#define ZD_CR37 CTL_REG(0x0094) +#define ZD_CR38 CTL_REG(0x0098) +#define ZD_CR39 CTL_REG(0x009C) +#define ZD_CR40 CTL_REG(0x00A0) +#define ZD_CR41 CTL_REG(0x00A4) +#define ZD_CR42 CTL_REG(0x00A8) +#define ZD_CR43 CTL_REG(0x00AC) +#define ZD_CR44 CTL_REG(0x00B0) +#define ZD_CR45 CTL_REG(0x00B4) +#define ZD_CR46 CTL_REG(0x00B8) +#define ZD_CR47 CTL_REG(0x00BC) /* CCK baseband gain + * (patch value might be in EEPROM) + */ +#define ZD_CR48 CTL_REG(0x00C0) +#define ZD_CR49 CTL_REG(0x00C4) +#define ZD_CR50 CTL_REG(0x00C8) +#define ZD_CR51 CTL_REG(0x00CC) /* TX power control for RF in + * 6-36M modes + */ +#define ZD_CR52 CTL_REG(0x00D0) /* TX power control for RF in + * 48M mode + */ +#define ZD_CR53 CTL_REG(0x00D4) /* TX power control for RF in + * 54M mode + */ +#define ZD_CR54 CTL_REG(0x00D8) +#define ZD_CR55 CTL_REG(0x00DC) +#define ZD_CR56 CTL_REG(0x00E0) +#define ZD_CR57 CTL_REG(0x00E4) +#define ZD_CR58 CTL_REG(0x00E8) +#define ZD_CR59 CTL_REG(0x00EC) +#define ZD_CR60 CTL_REG(0x00F0) +#define ZD_CR61 CTL_REG(0x00F4) +#define ZD_CR62 CTL_REG(0x00F8) +#define ZD_CR63 CTL_REG(0x00FC) +#define ZD_CR64 CTL_REG(0x0100) +#define ZD_CR65 CTL_REG(0x0104) /* OFDM 54M calibration */ +#define ZD_CR66 CTL_REG(0x0108) /* OFDM 48M calibration */ +#define ZD_CR67 CTL_REG(0x010C) /* OFDM 36M calibration */ +#define ZD_CR68 CTL_REG(0x0110) /* CCK calibration */ +#define ZD_CR69 CTL_REG(0x0114) +#define ZD_CR70 CTL_REG(0x0118) +#define ZD_CR71 CTL_REG(0x011C) +#define ZD_CR72 CTL_REG(0x0120) +#define ZD_CR73 CTL_REG(0x0124) +#define ZD_CR74 CTL_REG(0x0128) +#define ZD_CR75 CTL_REG(0x012C) +#define ZD_CR76 CTL_REG(0x0130) +#define ZD_CR77 CTL_REG(0x0134) +#define ZD_CR78 CTL_REG(0x0138) +#define ZD_CR79 CTL_REG(0x013C) +#define ZD_CR80 CTL_REG(0x0140) +#define ZD_CR81 CTL_REG(0x0144) +#define ZD_CR82 CTL_REG(0x0148) +#define ZD_CR83 CTL_REG(0x014C) +#define ZD_CR84 CTL_REG(0x0150) +#define ZD_CR85 CTL_REG(0x0154) +#define ZD_CR86 CTL_REG(0x0158) +#define ZD_CR87 CTL_REG(0x015C) +#define ZD_CR88 CTL_REG(0x0160) +#define ZD_CR89 CTL_REG(0x0164) +#define ZD_CR90 CTL_REG(0x0168) +#define ZD_CR91 CTL_REG(0x016C) +#define ZD_CR92 CTL_REG(0x0170) +#define ZD_CR93 CTL_REG(0x0174) +#define ZD_CR94 CTL_REG(0x0178) +#define ZD_CR95 CTL_REG(0x017C) +#define ZD_CR96 CTL_REG(0x0180) +#define ZD_CR97 CTL_REG(0x0184) +#define ZD_CR98 CTL_REG(0x0188) +#define ZD_CR99 CTL_REG(0x018C) +#define ZD_CR100 CTL_REG(0x0190) +#define ZD_CR101 CTL_REG(0x0194) +#define ZD_CR102 CTL_REG(0x0198) +#define ZD_CR103 CTL_REG(0x019C) +#define ZD_CR104 CTL_REG(0x01A0) +#define ZD_CR105 CTL_REG(0x01A4) +#define ZD_CR106 CTL_REG(0x01A8) +#define ZD_CR107 CTL_REG(0x01AC) +#define ZD_CR108 CTL_REG(0x01B0) +#define ZD_CR109 CTL_REG(0x01B4) +#define ZD_CR110 CTL_REG(0x01B8) +#define ZD_CR111 CTL_REG(0x01BC) +#define ZD_CR112 CTL_REG(0x01C0) +#define ZD_CR113 CTL_REG(0x01C4) +#define ZD_CR114 CTL_REG(0x01C8) +#define ZD_CR115 CTL_REG(0x01CC) +#define ZD_CR116 CTL_REG(0x01D0) +#define ZD_CR117 CTL_REG(0x01D4) +#define ZD_CR118 CTL_REG(0x01D8) +#define ZD_CR119 CTL_REG(0x01DC) +#define ZD_CR120 CTL_REG(0x01E0) +#define ZD_CR121 CTL_REG(0x01E4) +#define ZD_CR122 CTL_REG(0x01E8) +#define ZD_CR123 CTL_REG(0x01EC) +#define ZD_CR124 CTL_REG(0x01F0) +#define ZD_CR125 CTL_REG(0x01F4) +#define ZD_CR126 CTL_REG(0x01F8) +#define ZD_CR127 CTL_REG(0x01FC) +#define ZD_CR128 CTL_REG(0x0200) +#define ZD_CR129 CTL_REG(0x0204) +#define ZD_CR130 CTL_REG(0x0208) +#define ZD_CR131 CTL_REG(0x020C) +#define ZD_CR132 CTL_REG(0x0210) +#define ZD_CR133 CTL_REG(0x0214) +#define ZD_CR134 CTL_REG(0x0218) +#define ZD_CR135 CTL_REG(0x021C) +#define ZD_CR136 CTL_REG(0x0220) +#define ZD_CR137 CTL_REG(0x0224) +#define ZD_CR138 CTL_REG(0x0228) +#define ZD_CR139 CTL_REG(0x022C) +#define ZD_CR140 CTL_REG(0x0230) +#define ZD_CR141 CTL_REG(0x0234) +#define ZD_CR142 CTL_REG(0x0238) +#define ZD_CR143 CTL_REG(0x023C) +#define ZD_CR144 CTL_REG(0x0240) +#define ZD_CR145 CTL_REG(0x0244) +#define ZD_CR146 CTL_REG(0x0248) +#define ZD_CR147 CTL_REG(0x024C) +#define ZD_CR148 CTL_REG(0x0250) +#define ZD_CR149 CTL_REG(0x0254) +#define ZD_CR150 CTL_REG(0x0258) +#define ZD_CR151 CTL_REG(0x025C) +#define ZD_CR152 CTL_REG(0x0260) +#define ZD_CR153 CTL_REG(0x0264) +#define ZD_CR154 CTL_REG(0x0268) +#define ZD_CR155 CTL_REG(0x026C) +#define ZD_CR156 CTL_REG(0x0270) +#define ZD_CR157 CTL_REG(0x0274) +#define ZD_CR158 CTL_REG(0x0278) +#define ZD_CR159 CTL_REG(0x027C) +#define ZD_CR160 CTL_REG(0x0280) +#define ZD_CR161 CTL_REG(0x0284) +#define ZD_CR162 CTL_REG(0x0288) +#define ZD_CR163 CTL_REG(0x028C) +#define ZD_CR164 CTL_REG(0x0290) +#define ZD_CR165 CTL_REG(0x0294) +#define ZD_CR166 CTL_REG(0x0298) +#define ZD_CR167 CTL_REG(0x029C) +#define ZD_CR168 CTL_REG(0x02A0) +#define ZD_CR169 CTL_REG(0x02A4) +#define ZD_CR170 CTL_REG(0x02A8) +#define ZD_CR171 CTL_REG(0x02AC) +#define ZD_CR172 CTL_REG(0x02B0) +#define ZD_CR173 CTL_REG(0x02B4) +#define ZD_CR174 CTL_REG(0x02B8) +#define ZD_CR175 CTL_REG(0x02BC) +#define ZD_CR176 CTL_REG(0x02C0) +#define ZD_CR177 CTL_REG(0x02C4) +#define ZD_CR178 CTL_REG(0x02C8) +#define ZD_CR179 CTL_REG(0x02CC) +#define ZD_CR180 CTL_REG(0x02D0) +#define ZD_CR181 CTL_REG(0x02D4) +#define ZD_CR182 CTL_REG(0x02D8) +#define ZD_CR183 CTL_REG(0x02DC) +#define ZD_CR184 CTL_REG(0x02E0) +#define ZD_CR185 CTL_REG(0x02E4) +#define ZD_CR186 CTL_REG(0x02E8) +#define ZD_CR187 CTL_REG(0x02EC) +#define ZD_CR188 CTL_REG(0x02F0) +#define ZD_CR189 CTL_REG(0x02F4) +#define ZD_CR190 CTL_REG(0x02F8) +#define ZD_CR191 CTL_REG(0x02FC) +#define ZD_CR192 CTL_REG(0x0300) +#define ZD_CR193 CTL_REG(0x0304) +#define ZD_CR194 CTL_REG(0x0308) +#define ZD_CR195 CTL_REG(0x030C) +#define ZD_CR196 CTL_REG(0x0310) +#define ZD_CR197 CTL_REG(0x0314) +#define ZD_CR198 CTL_REG(0x0318) +#define ZD_CR199 CTL_REG(0x031C) +#define ZD_CR200 CTL_REG(0x0320) +#define ZD_CR201 CTL_REG(0x0324) +#define ZD_CR202 CTL_REG(0x0328) +#define ZD_CR203 CTL_REG(0x032C) /* I2C bus template value & flash + * control + */ +#define ZD_CR204 CTL_REG(0x0330) +#define ZD_CR205 CTL_REG(0x0334) +#define ZD_CR206 CTL_REG(0x0338) +#define ZD_CR207 CTL_REG(0x033C) +#define ZD_CR208 CTL_REG(0x0340) +#define ZD_CR209 CTL_REG(0x0344) +#define ZD_CR210 CTL_REG(0x0348) +#define ZD_CR211 CTL_REG(0x034C) +#define ZD_CR212 CTL_REG(0x0350) +#define ZD_CR213 CTL_REG(0x0354) +#define ZD_CR214 CTL_REG(0x0358) +#define ZD_CR215 CTL_REG(0x035C) +#define ZD_CR216 CTL_REG(0x0360) +#define ZD_CR217 CTL_REG(0x0364) +#define ZD_CR218 CTL_REG(0x0368) +#define ZD_CR219 CTL_REG(0x036C) +#define ZD_CR220 CTL_REG(0x0370) +#define ZD_CR221 CTL_REG(0x0374) +#define ZD_CR222 CTL_REG(0x0378) +#define ZD_CR223 CTL_REG(0x037C) +#define ZD_CR224 CTL_REG(0x0380) +#define ZD_CR225 CTL_REG(0x0384) +#define ZD_CR226 CTL_REG(0x0388) +#define ZD_CR227 CTL_REG(0x038C) +#define ZD_CR228 CTL_REG(0x0390) +#define ZD_CR229 CTL_REG(0x0394) +#define ZD_CR230 CTL_REG(0x0398) +#define ZD_CR231 CTL_REG(0x039C) +#define ZD_CR232 CTL_REG(0x03A0) +#define ZD_CR233 CTL_REG(0x03A4) +#define ZD_CR234 CTL_REG(0x03A8) +#define ZD_CR235 CTL_REG(0x03AC) +#define ZD_CR236 CTL_REG(0x03B0) + +#define ZD_CR240 CTL_REG(0x03C0) +/* bit 7: host-controlled RF register writes + * ZD_CR241-ZD_CR245: for hardware controlled writing of RF bits, not needed for + * USB */ -#define CR241 CTL_REG(0x03C4) -#define CR242 CTL_REG(0x03C8) -#define CR243 CTL_REG(0x03CC) -#define CR244 CTL_REG(0x03D0) -#define CR245 CTL_REG(0x03D4) - -#define CR251 CTL_REG(0x03EC) /* only used for activation and deactivation of - * Airoha RFs AL2230 and AL7230B - */ -#define CR252 CTL_REG(0x03F0) -#define CR253 CTL_REG(0x03F4) -#define CR254 CTL_REG(0x03F8) -#define CR255 CTL_REG(0x03FC) +#define ZD_CR241 CTL_REG(0x03C4) +#define ZD_CR242 CTL_REG(0x03C8) +#define ZD_CR243 CTL_REG(0x03CC) +#define ZD_CR244 CTL_REG(0x03D0) +#define ZD_CR245 CTL_REG(0x03D4) + +#define ZD_CR251 CTL_REG(0x03EC) /* only used for activation and + * deactivation of Airoha RFs AL2230 + * and AL7230B + */ +#define ZD_CR252 CTL_REG(0x03F0) +#define ZD_CR253 CTL_REG(0x03F4) +#define ZD_CR254 CTL_REG(0x03F8) +#define ZD_CR255 CTL_REG(0x03FC) #define CR_MAX_PHY_REG 255 diff --git a/drivers/net/wireless/zd1211rw/zd_rf.h b/drivers/net/wireless/zd1211rw/zd_rf.h index 79dc1035592d..725b7c99b23d 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf.h +++ b/drivers/net/wireless/zd1211rw/zd_rf.h @@ -55,7 +55,7 @@ struct zd_rf { * defaults to 1 (yes) */ u8 update_channel_int:1; - /* whether CR47 should be patched from the EEPROM, if the appropriate + /* whether ZD_CR47 should be patched from the EEPROM, if the appropriate * flag is set in the POD. The vendor driver suggests that this should * be done for all RF's, but a bug in their code prevents but their * HW_OverWritePhyRegFromE2P() routine from ever taking effect. */ diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c index 74a8f7a55591..12babcb633c3 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c @@ -61,31 +61,31 @@ static const u32 zd1211b_al2230_table[][3] = { }; static const struct zd_ioreq16 zd1211b_ioreqs_shared_1[] = { - { CR240, 0x57 }, { CR9, 0xe0 }, + { ZD_CR240, 0x57 }, { ZD_CR9, 0xe0 }, }; static const struct zd_ioreq16 ioreqs_init_al2230s[] = { - { CR47, 0x1e }, /* MARK_002 */ - { CR106, 0x22 }, - { CR107, 0x2a }, /* MARK_002 */ - { CR109, 0x13 }, /* MARK_002 */ - { CR118, 0xf8 }, /* MARK_002 */ - { CR119, 0x12 }, { CR122, 0xe0 }, - { CR128, 0x10 }, /* MARK_001 from 0xe->0x10 */ - { CR129, 0x0e }, /* MARK_001 from 0xd->0x0e */ - { CR130, 0x10 }, /* MARK_001 from 0xb->0x0d */ + { ZD_CR47, 0x1e }, /* MARK_002 */ + { ZD_CR106, 0x22 }, + { ZD_CR107, 0x2a }, /* MARK_002 */ + { ZD_CR109, 0x13 }, /* MARK_002 */ + { ZD_CR118, 0xf8 }, /* MARK_002 */ + { ZD_CR119, 0x12 }, { ZD_CR122, 0xe0 }, + { ZD_CR128, 0x10 }, /* MARK_001 from 0xe->0x10 */ + { ZD_CR129, 0x0e }, /* MARK_001 from 0xd->0x0e */ + { ZD_CR130, 0x10 }, /* MARK_001 from 0xb->0x0d */ }; static int zd1211b_al2230_finalize_rf(struct zd_chip *chip) { int r; static const struct zd_ioreq16 ioreqs[] = { - { CR80, 0x30 }, { CR81, 0x30 }, { CR79, 0x58 }, - { CR12, 0xf0 }, { CR77, 0x1b }, { CR78, 0x58 }, - { CR203, 0x06 }, + { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, { ZD_CR79, 0x58 }, + { ZD_CR12, 0xf0 }, { ZD_CR77, 0x1b }, { ZD_CR78, 0x58 }, + { ZD_CR203, 0x06 }, { }, - { CR240, 0x80 }, + { ZD_CR240, 0x80 }, }; r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); @@ -94,12 +94,12 @@ static int zd1211b_al2230_finalize_rf(struct zd_chip *chip) /* related to antenna selection? */ if (chip->new_phy_layout) { - r = zd_iowrite16_locked(chip, 0xe1, CR9); + r = zd_iowrite16_locked(chip, 0xe1, ZD_CR9); if (r) return r; } - return zd_iowrite16_locked(chip, 0x06, CR203); + return zd_iowrite16_locked(chip, 0x06, ZD_CR203); } static int zd1211_al2230_init_hw(struct zd_rf *rf) @@ -108,40 +108,40 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf) struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs_init[] = { - { CR15, 0x20 }, { CR23, 0x40 }, { CR24, 0x20 }, - { CR26, 0x11 }, { CR28, 0x3e }, { CR29, 0x00 }, - { CR44, 0x33 }, { CR106, 0x2a }, { CR107, 0x1a }, - { CR109, 0x09 }, { CR110, 0x27 }, { CR111, 0x2b }, - { CR112, 0x2b }, { CR119, 0x0a }, { CR10, 0x89 }, + { ZD_CR15, 0x20 }, { ZD_CR23, 0x40 }, { ZD_CR24, 0x20 }, + { ZD_CR26, 0x11 }, { ZD_CR28, 0x3e }, { ZD_CR29, 0x00 }, + { ZD_CR44, 0x33 }, { ZD_CR106, 0x2a }, { ZD_CR107, 0x1a }, + { ZD_CR109, 0x09 }, { ZD_CR110, 0x27 }, { ZD_CR111, 0x2b }, + { ZD_CR112, 0x2b }, { ZD_CR119, 0x0a }, { ZD_CR10, 0x89 }, /* for newest (3rd cut) AL2300 */ - { CR17, 0x28 }, - { CR26, 0x93 }, { CR34, 0x30 }, + { ZD_CR17, 0x28 }, + { ZD_CR26, 0x93 }, { ZD_CR34, 0x30 }, /* for newest (3rd cut) AL2300 */ - { CR35, 0x3e }, - { CR41, 0x24 }, { CR44, 0x32 }, + { ZD_CR35, 0x3e }, + { ZD_CR41, 0x24 }, { ZD_CR44, 0x32 }, /* for newest (3rd cut) AL2300 */ - { CR46, 0x96 }, - { CR47, 0x1e }, { CR79, 0x58 }, { CR80, 0x30 }, - { CR81, 0x30 }, { CR87, 0x0a }, { CR89, 0x04 }, - { CR92, 0x0a }, { CR99, 0x28 }, { CR100, 0x00 }, - { CR101, 0x13 }, { CR102, 0x27 }, { CR106, 0x24 }, - { CR107, 0x2a }, { CR109, 0x09 }, { CR110, 0x13 }, - { CR111, 0x1f }, { CR112, 0x1f }, { CR113, 0x27 }, - { CR114, 0x27 }, + { ZD_CR46, 0x96 }, + { ZD_CR47, 0x1e }, { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, + { ZD_CR81, 0x30 }, { ZD_CR87, 0x0a }, { ZD_CR89, 0x04 }, + { ZD_CR92, 0x0a }, { ZD_CR99, 0x28 }, { ZD_CR100, 0x00 }, + { ZD_CR101, 0x13 }, { ZD_CR102, 0x27 }, { ZD_CR106, 0x24 }, + { ZD_CR107, 0x2a }, { ZD_CR109, 0x09 }, { ZD_CR110, 0x13 }, + { ZD_CR111, 0x1f }, { ZD_CR112, 0x1f }, { ZD_CR113, 0x27 }, + { ZD_CR114, 0x27 }, /* for newest (3rd cut) AL2300 */ - { CR115, 0x24 }, - { CR116, 0x24 }, { CR117, 0xf4 }, { CR118, 0xfc }, - { CR119, 0x10 }, { CR120, 0x4f }, { CR121, 0x77 }, - { CR122, 0xe0 }, { CR137, 0x88 }, { CR252, 0xff }, - { CR253, 0xff }, + { ZD_CR115, 0x24 }, + { ZD_CR116, 0x24 }, { ZD_CR117, 0xf4 }, { ZD_CR118, 0xfc }, + { ZD_CR119, 0x10 }, { ZD_CR120, 0x4f }, { ZD_CR121, 0x77 }, + { ZD_CR122, 0xe0 }, { ZD_CR137, 0x88 }, { ZD_CR252, 0xff }, + { ZD_CR253, 0xff }, }; static const struct zd_ioreq16 ioreqs_pll[] = { /* shdnb(PLL_ON)=0 */ - { CR251, 0x2f }, + { ZD_CR251, 0x2f }, /* shdnb(PLL_ON)=1 */ - { CR251, 0x3f }, - { CR138, 0x28 }, { CR203, 0x06 }, + { ZD_CR251, 0x3f }, + { ZD_CR138, 0x28 }, { ZD_CR203, 0x06 }, }; static const u32 rv1[] = { @@ -161,7 +161,7 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf) 0x0805b6, 0x011687, 0x000688, - 0x0403b9, /* external control TX power (CR31) */ + 0x0403b9, /* external control TX power (ZD_CR31) */ 0x00dbba, 0x00099b, 0x0bdffc, @@ -221,52 +221,54 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf) struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs1[] = { - { CR10, 0x89 }, { CR15, 0x20 }, - { CR17, 0x2B }, /* for newest(3rd cut) AL2230 */ - { CR23, 0x40 }, { CR24, 0x20 }, { CR26, 0x93 }, - { CR28, 0x3e }, { CR29, 0x00 }, - { CR33, 0x28 }, /* 5621 */ - { CR34, 0x30 }, - { CR35, 0x3e }, /* for newest(3rd cut) AL2230 */ - { CR41, 0x24 }, { CR44, 0x32 }, - { CR46, 0x99 }, /* for newest(3rd cut) AL2230 */ - { CR47, 0x1e }, + { ZD_CR10, 0x89 }, { ZD_CR15, 0x20 }, + { ZD_CR17, 0x2B }, /* for newest(3rd cut) AL2230 */ + { ZD_CR23, 0x40 }, { ZD_CR24, 0x20 }, { ZD_CR26, 0x93 }, + { ZD_CR28, 0x3e }, { ZD_CR29, 0x00 }, + { ZD_CR33, 0x28 }, /* 5621 */ + { ZD_CR34, 0x30 }, + { ZD_CR35, 0x3e }, /* for newest(3rd cut) AL2230 */ + { ZD_CR41, 0x24 }, { ZD_CR44, 0x32 }, + { ZD_CR46, 0x99 }, /* for newest(3rd cut) AL2230 */ + { ZD_CR47, 0x1e }, /* ZD1211B 05.06.10 */ - { CR48, 0x06 }, { CR49, 0xf9 }, { CR51, 0x01 }, - { CR52, 0x80 }, { CR53, 0x7e }, { CR65, 0x00 }, - { CR66, 0x00 }, { CR67, 0x00 }, { CR68, 0x00 }, - { CR69, 0x28 }, - - { CR79, 0x58 }, { CR80, 0x30 }, { CR81, 0x30 }, - { CR87, 0x0a }, { CR89, 0x04 }, - { CR91, 0x00 }, /* 5621 */ - { CR92, 0x0a }, - { CR98, 0x8d }, /* 4804, for 1212 new algorithm */ - { CR99, 0x00 }, /* 5621 */ - { CR101, 0x13 }, { CR102, 0x27 }, - { CR106, 0x24 }, /* for newest(3rd cut) AL2230 */ - { CR107, 0x2a }, - { CR109, 0x13 }, /* 4804, for 1212 new algorithm */ - { CR110, 0x1f }, /* 4804, for 1212 new algorithm */ - { CR111, 0x1f }, { CR112, 0x1f }, { CR113, 0x27 }, - { CR114, 0x27 }, - { CR115, 0x26 }, /* 24->26 at 4902 for newest(3rd cut) AL2230 */ - { CR116, 0x24 }, - { CR117, 0xfa }, /* for 1211b */ - { CR118, 0xfa }, /* for 1211b */ - { CR119, 0x10 }, - { CR120, 0x4f }, - { CR121, 0x6c }, /* for 1211b */ - { CR122, 0xfc }, /* E0->FC at 4902 */ - { CR123, 0x57 }, /* 5623 */ - { CR125, 0xad }, /* 4804, for 1212 new algorithm */ - { CR126, 0x6c }, /* 5614 */ - { CR127, 0x03 }, /* 4804, for 1212 new algorithm */ - { CR137, 0x50 }, /* 5614 */ - { CR138, 0xa8 }, - { CR144, 0xac }, /* 5621 */ - { CR150, 0x0d }, { CR252, 0x34 }, { CR253, 0x34 }, + { ZD_CR48, 0x06 }, { ZD_CR49, 0xf9 }, { ZD_CR51, 0x01 }, + { ZD_CR52, 0x80 }, { ZD_CR53, 0x7e }, { ZD_CR65, 0x00 }, + { ZD_CR66, 0x00 }, { ZD_CR67, 0x00 }, { ZD_CR68, 0x00 }, + { ZD_CR69, 0x28 }, + + { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, + { ZD_CR87, 0x0a }, { ZD_CR89, 0x04 }, + { ZD_CR91, 0x00 }, /* 5621 */ + { ZD_CR92, 0x0a }, + { ZD_CR98, 0x8d }, /* 4804, for 1212 new algorithm */ + { ZD_CR99, 0x00 }, /* 5621 */ + { ZD_CR101, 0x13 }, { ZD_CR102, 0x27 }, + { ZD_CR106, 0x24 }, /* for newest(3rd cut) AL2230 */ + { ZD_CR107, 0x2a }, + { ZD_CR109, 0x13 }, /* 4804, for 1212 new algorithm */ + { ZD_CR110, 0x1f }, /* 4804, for 1212 new algorithm */ + { ZD_CR111, 0x1f }, { ZD_CR112, 0x1f }, { ZD_CR113, 0x27 }, + { ZD_CR114, 0x27 }, + { ZD_CR115, 0x26 }, /* 24->26 at 4902 for newest(3rd cut) + * AL2230 + */ + { ZD_CR116, 0x24 }, + { ZD_CR117, 0xfa }, /* for 1211b */ + { ZD_CR118, 0xfa }, /* for 1211b */ + { ZD_CR119, 0x10 }, + { ZD_CR120, 0x4f }, + { ZD_CR121, 0x6c }, /* for 1211b */ + { ZD_CR122, 0xfc }, /* E0->FC at 4902 */ + { ZD_CR123, 0x57 }, /* 5623 */ + { ZD_CR125, 0xad }, /* 4804, for 1212 new algorithm */ + { ZD_CR126, 0x6c }, /* 5614 */ + { ZD_CR127, 0x03 }, /* 4804, for 1212 new algorithm */ + { ZD_CR137, 0x50 }, /* 5614 */ + { ZD_CR138, 0xa8 }, + { ZD_CR144, 0xac }, /* 5621 */ + { ZD_CR150, 0x0d }, { ZD_CR252, 0x34 }, { ZD_CR253, 0x34 }, }; static const u32 rv1[] = { @@ -284,7 +286,7 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf) 0x6da010, /* Reg6 update for MP versio */ 0xe36280, /* Modified by jxiao for Bor-Chin on 2004/08/02 */ 0x116000, - 0x9dc020, /* External control TX power (CR31) */ + 0x9dc020, /* External control TX power (ZD_CR31) */ 0x5ddb00, /* RegA update for MP version */ 0xd99000, /* RegB update for MP version */ 0x3ffbd0, /* RegC update for MP version */ @@ -295,8 +297,8 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf) }; static const struct zd_ioreq16 ioreqs2[] = { - { CR251, 0x2f }, /* shdnb(PLL_ON)=0 */ - { CR251, 0x7f }, /* shdnb(PLL_ON)=1 */ + { ZD_CR251, 0x2f }, /* shdnb(PLL_ON)=0 */ + { ZD_CR251, 0x7f }, /* shdnb(PLL_ON)=1 */ }; static const u32 rv3[] = { @@ -308,7 +310,7 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf) static const struct zd_ioreq16 ioreqs3[] = { /* related to 6M band edge patching, happens unconditionally */ - { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, + { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, }; r = zd_iowrite16a_locked(chip, zd1211b_ioreqs_shared_1, @@ -361,8 +363,8 @@ static int zd1211_al2230_set_channel(struct zd_rf *rf, u8 channel) const u32 *rv = zd1211_al2230_table[channel-1]; struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR138, 0x28 }, - { CR203, 0x06 }, + { ZD_CR138, 0x28 }, + { ZD_CR203, 0x06 }, }; r = zd_rfwritev_locked(chip, rv, 3, RF_RV_BITS); @@ -393,8 +395,8 @@ static int zd1211_al2230_switch_radio_on(struct zd_rf *rf) { struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR11, 0x00 }, - { CR251, 0x3f }, + { ZD_CR11, 0x00 }, + { ZD_CR251, 0x3f }, }; return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); @@ -404,8 +406,8 @@ static int zd1211b_al2230_switch_radio_on(struct zd_rf *rf) { struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR11, 0x00 }, - { CR251, 0x7f }, + { ZD_CR11, 0x00 }, + { ZD_CR251, 0x7f }, }; return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); @@ -415,8 +417,8 @@ static int al2230_switch_radio_off(struct zd_rf *rf) { struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR11, 0x04 }, - { CR251, 0x2f }, + { ZD_CR11, 0x04 }, + { ZD_CR251, 0x2f }, }; return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c index 65095d661e6b..385c670d1293 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c @@ -68,19 +68,19 @@ static const u32 rv_init2[] = { }; static const struct zd_ioreq16 ioreqs_sw[] = { - { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, - { CR38, 0x38 }, { CR136, 0xdf }, + { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, + { ZD_CR38, 0x38 }, { ZD_CR136, 0xdf }, }; static int zd1211b_al7230b_finalize(struct zd_chip *chip) { int r; static const struct zd_ioreq16 ioreqs[] = { - { CR80, 0x30 }, { CR81, 0x30 }, { CR79, 0x58 }, - { CR12, 0xf0 }, { CR77, 0x1b }, { CR78, 0x58 }, - { CR203, 0x04 }, + { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, { ZD_CR79, 0x58 }, + { ZD_CR12, 0xf0 }, { ZD_CR77, 0x1b }, { ZD_CR78, 0x58 }, + { ZD_CR203, 0x04 }, { }, - { CR240, 0x80 }, + { ZD_CR240, 0x80 }, }; r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); @@ -89,12 +89,12 @@ static int zd1211b_al7230b_finalize(struct zd_chip *chip) if (chip->new_phy_layout) { /* antenna selection? */ - r = zd_iowrite16_locked(chip, 0xe5, CR9); + r = zd_iowrite16_locked(chip, 0xe5, ZD_CR9); if (r) return r; } - return zd_iowrite16_locked(chip, 0x04, CR203); + return zd_iowrite16_locked(chip, 0x04, ZD_CR203); } static int zd1211_al7230b_init_hw(struct zd_rf *rf) @@ -106,66 +106,66 @@ static int zd1211_al7230b_init_hw(struct zd_rf *rf) * specified */ static const struct zd_ioreq16 ioreqs_1[] = { /* This one is 7230-specific, and happens before the rest */ - { CR240, 0x57 }, + { ZD_CR240, 0x57 }, { }, - { CR15, 0x20 }, { CR23, 0x40 }, { CR24, 0x20 }, - { CR26, 0x11 }, { CR28, 0x3e }, { CR29, 0x00 }, - { CR44, 0x33 }, + { ZD_CR15, 0x20 }, { ZD_CR23, 0x40 }, { ZD_CR24, 0x20 }, + { ZD_CR26, 0x11 }, { ZD_CR28, 0x3e }, { ZD_CR29, 0x00 }, + { ZD_CR44, 0x33 }, /* This value is different for 7230 (was: 0x2a) */ - { CR106, 0x22 }, - { CR107, 0x1a }, { CR109, 0x09 }, { CR110, 0x27 }, - { CR111, 0x2b }, { CR112, 0x2b }, { CR119, 0x0a }, + { ZD_CR106, 0x22 }, + { ZD_CR107, 0x1a }, { ZD_CR109, 0x09 }, { ZD_CR110, 0x27 }, + { ZD_CR111, 0x2b }, { ZD_CR112, 0x2b }, { ZD_CR119, 0x0a }, /* This happened further down in AL2230, * and the value changed (was: 0xe0) */ - { CR122, 0xfc }, - { CR10, 0x89 }, + { ZD_CR122, 0xfc }, + { ZD_CR10, 0x89 }, /* for newest (3rd cut) AL2300 */ - { CR17, 0x28 }, - { CR26, 0x93 }, { CR34, 0x30 }, + { ZD_CR17, 0x28 }, + { ZD_CR26, 0x93 }, { ZD_CR34, 0x30 }, /* for newest (3rd cut) AL2300 */ - { CR35, 0x3e }, - { CR41, 0x24 }, { CR44, 0x32 }, + { ZD_CR35, 0x3e }, + { ZD_CR41, 0x24 }, { ZD_CR44, 0x32 }, /* for newest (3rd cut) AL2300 */ - { CR46, 0x96 }, - { CR47, 0x1e }, { CR79, 0x58 }, { CR80, 0x30 }, - { CR81, 0x30 }, { CR87, 0x0a }, { CR89, 0x04 }, - { CR92, 0x0a }, { CR99, 0x28 }, + { ZD_CR46, 0x96 }, + { ZD_CR47, 0x1e }, { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, + { ZD_CR81, 0x30 }, { ZD_CR87, 0x0a }, { ZD_CR89, 0x04 }, + { ZD_CR92, 0x0a }, { ZD_CR99, 0x28 }, /* This value is different for 7230 (was: 0x00) */ - { CR100, 0x02 }, - { CR101, 0x13 }, { CR102, 0x27 }, + { ZD_CR100, 0x02 }, + { ZD_CR101, 0x13 }, { ZD_CR102, 0x27 }, /* This value is different for 7230 (was: 0x24) */ - { CR106, 0x22 }, + { ZD_CR106, 0x22 }, /* This value is different for 7230 (was: 0x2a) */ - { CR107, 0x3f }, - { CR109, 0x09 }, + { ZD_CR107, 0x3f }, + { ZD_CR109, 0x09 }, /* This value is different for 7230 (was: 0x13) */ - { CR110, 0x1f }, - { CR111, 0x1f }, { CR112, 0x1f }, { CR113, 0x27 }, - { CR114, 0x27 }, + { ZD_CR110, 0x1f }, + { ZD_CR111, 0x1f }, { ZD_CR112, 0x1f }, { ZD_CR113, 0x27 }, + { ZD_CR114, 0x27 }, /* for newest (3rd cut) AL2300 */ - { CR115, 0x24 }, + { ZD_CR115, 0x24 }, /* This value is different for 7230 (was: 0x24) */ - { CR116, 0x3f }, + { ZD_CR116, 0x3f }, /* This value is different for 7230 (was: 0xf4) */ - { CR117, 0xfa }, - { CR118, 0xfc }, { CR119, 0x10 }, { CR120, 0x4f }, - { CR121, 0x77 }, { CR137, 0x88 }, + { ZD_CR117, 0xfa }, + { ZD_CR118, 0xfc }, { ZD_CR119, 0x10 }, { ZD_CR120, 0x4f }, + { ZD_CR121, 0x77 }, { ZD_CR137, 0x88 }, /* This one is 7230-specific */ - { CR138, 0xa8 }, + { ZD_CR138, 0xa8 }, /* This value is different for 7230 (was: 0xff) */ - { CR252, 0x34 }, + { ZD_CR252, 0x34 }, /* This value is different for 7230 (was: 0xff) */ - { CR253, 0x34 }, + { ZD_CR253, 0x34 }, /* PLL_OFF */ - { CR251, 0x2f }, + { ZD_CR251, 0x2f }, }; static const struct zd_ioreq16 ioreqs_2[] = { - { CR251, 0x3f }, /* PLL_ON */ - { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, - { CR38, 0x38 }, { CR136, 0xdf }, + { ZD_CR251, 0x3f }, /* PLL_ON */ + { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, + { ZD_CR38, 0x38 }, { ZD_CR136, 0xdf }, }; r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1)); @@ -192,10 +192,10 @@ static int zd1211_al7230b_init_hw(struct zd_rf *rf) if (r) return r; - r = zd_iowrite16_locked(chip, 0x06, CR203); + r = zd_iowrite16_locked(chip, 0x06, ZD_CR203); if (r) return r; - r = zd_iowrite16_locked(chip, 0x80, CR240); + r = zd_iowrite16_locked(chip, 0x80, ZD_CR240); if (r) return r; @@ -208,79 +208,79 @@ static int zd1211b_al7230b_init_hw(struct zd_rf *rf) struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs_1[] = { - { CR240, 0x57 }, { CR9, 0x9 }, + { ZD_CR240, 0x57 }, { ZD_CR9, 0x9 }, { }, - { CR10, 0x8b }, { CR15, 0x20 }, - { CR17, 0x2B }, /* for newest (3rd cut) AL2230 */ - { CR20, 0x10 }, /* 4N25->Stone Request */ - { CR23, 0x40 }, { CR24, 0x20 }, { CR26, 0x93 }, - { CR28, 0x3e }, { CR29, 0x00 }, - { CR33, 0x28 }, /* 5613 */ - { CR34, 0x30 }, - { CR35, 0x3e }, /* for newest (3rd cut) AL2230 */ - { CR41, 0x24 }, { CR44, 0x32 }, - { CR46, 0x99 }, /* for newest (3rd cut) AL2230 */ - { CR47, 0x1e }, + { ZD_CR10, 0x8b }, { ZD_CR15, 0x20 }, + { ZD_CR17, 0x2B }, /* for newest (3rd cut) AL2230 */ + { ZD_CR20, 0x10 }, /* 4N25->Stone Request */ + { ZD_CR23, 0x40 }, { ZD_CR24, 0x20 }, { ZD_CR26, 0x93 }, + { ZD_CR28, 0x3e }, { ZD_CR29, 0x00 }, + { ZD_CR33, 0x28 }, /* 5613 */ + { ZD_CR34, 0x30 }, + { ZD_CR35, 0x3e }, /* for newest (3rd cut) AL2230 */ + { ZD_CR41, 0x24 }, { ZD_CR44, 0x32 }, + { ZD_CR46, 0x99 }, /* for newest (3rd cut) AL2230 */ + { ZD_CR47, 0x1e }, /* ZD1215 5610 */ - { CR48, 0x00 }, { CR49, 0x00 }, { CR51, 0x01 }, - { CR52, 0x80 }, { CR53, 0x7e }, { CR65, 0x00 }, - { CR66, 0x00 }, { CR67, 0x00 }, { CR68, 0x00 }, - { CR69, 0x28 }, - - { CR79, 0x58 }, { CR80, 0x30 }, { CR81, 0x30 }, - { CR87, 0x0A }, { CR89, 0x04 }, - { CR90, 0x58 }, /* 5112 */ - { CR91, 0x00 }, /* 5613 */ - { CR92, 0x0a }, - { CR98, 0x8d }, /* 4804, for 1212 new algorithm */ - { CR99, 0x00 }, { CR100, 0x02 }, { CR101, 0x13 }, - { CR102, 0x27 }, - { CR106, 0x20 }, /* change to 0x24 for AL7230B */ - { CR109, 0x13 }, /* 4804, for 1212 new algorithm */ - { CR112, 0x1f }, + { ZD_CR48, 0x00 }, { ZD_CR49, 0x00 }, { ZD_CR51, 0x01 }, + { ZD_CR52, 0x80 }, { ZD_CR53, 0x7e }, { ZD_CR65, 0x00 }, + { ZD_CR66, 0x00 }, { ZD_CR67, 0x00 }, { ZD_CR68, 0x00 }, + { ZD_CR69, 0x28 }, + + { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, + { ZD_CR87, 0x0A }, { ZD_CR89, 0x04 }, + { ZD_CR90, 0x58 }, /* 5112 */ + { ZD_CR91, 0x00 }, /* 5613 */ + { ZD_CR92, 0x0a }, + { ZD_CR98, 0x8d }, /* 4804, for 1212 new algorithm */ + { ZD_CR99, 0x00 }, { ZD_CR100, 0x02 }, { ZD_CR101, 0x13 }, + { ZD_CR102, 0x27 }, + { ZD_CR106, 0x20 }, /* change to 0x24 for AL7230B */ + { ZD_CR109, 0x13 }, /* 4804, for 1212 new algorithm */ + { ZD_CR112, 0x1f }, }; static const struct zd_ioreq16 ioreqs_new_phy[] = { - { CR107, 0x28 }, - { CR110, 0x1f }, /* 5127, 0x13->0x1f */ - { CR111, 0x1f }, /* 0x13 to 0x1f for AL7230B */ - { CR116, 0x2a }, { CR118, 0xfa }, { CR119, 0x12 }, - { CR121, 0x6c }, /* 5613 */ + { ZD_CR107, 0x28 }, + { ZD_CR110, 0x1f }, /* 5127, 0x13->0x1f */ + { ZD_CR111, 0x1f }, /* 0x13 to 0x1f for AL7230B */ + { ZD_CR116, 0x2a }, { ZD_CR118, 0xfa }, { ZD_CR119, 0x12 }, + { ZD_CR121, 0x6c }, /* 5613 */ }; static const struct zd_ioreq16 ioreqs_old_phy[] = { - { CR107, 0x24 }, - { CR110, 0x13 }, /* 5127, 0x13->0x1f */ - { CR111, 0x13 }, /* 0x13 to 0x1f for AL7230B */ - { CR116, 0x24 }, { CR118, 0xfc }, { CR119, 0x11 }, - { CR121, 0x6a }, /* 5613 */ + { ZD_CR107, 0x24 }, + { ZD_CR110, 0x13 }, /* 5127, 0x13->0x1f */ + { ZD_CR111, 0x13 }, /* 0x13 to 0x1f for AL7230B */ + { ZD_CR116, 0x24 }, { ZD_CR118, 0xfc }, { ZD_CR119, 0x11 }, + { ZD_CR121, 0x6a }, /* 5613 */ }; static const struct zd_ioreq16 ioreqs_2[] = { - { CR113, 0x27 }, { CR114, 0x27 }, { CR115, 0x24 }, - { CR117, 0xfa }, { CR120, 0x4f }, - { CR122, 0xfc }, /* E0->FCh at 4901 */ - { CR123, 0x57 }, /* 5613 */ - { CR125, 0xad }, /* 4804, for 1212 new algorithm */ - { CR126, 0x6c }, /* 5613 */ - { CR127, 0x03 }, /* 4804, for 1212 new algorithm */ - { CR130, 0x10 }, - { CR131, 0x00 }, /* 5112 */ - { CR137, 0x50 }, /* 5613 */ - { CR138, 0xa8 }, /* 5112 */ - { CR144, 0xac }, /* 5613 */ - { CR148, 0x40 }, /* 5112 */ - { CR149, 0x40 }, /* 4O07, 50->40 */ - { CR150, 0x1a }, /* 5112, 0C->1A */ - { CR252, 0x34 }, { CR253, 0x34 }, - { CR251, 0x2f }, /* PLL_OFF */ + { ZD_CR113, 0x27 }, { ZD_CR114, 0x27 }, { ZD_CR115, 0x24 }, + { ZD_CR117, 0xfa }, { ZD_CR120, 0x4f }, + { ZD_CR122, 0xfc }, /* E0->FCh at 4901 */ + { ZD_CR123, 0x57 }, /* 5613 */ + { ZD_CR125, 0xad }, /* 4804, for 1212 new algorithm */ + { ZD_CR126, 0x6c }, /* 5613 */ + { ZD_CR127, 0x03 }, /* 4804, for 1212 new algorithm */ + { ZD_CR130, 0x10 }, + { ZD_CR131, 0x00 }, /* 5112 */ + { ZD_CR137, 0x50 }, /* 5613 */ + { ZD_CR138, 0xa8 }, /* 5112 */ + { ZD_CR144, 0xac }, /* 5613 */ + { ZD_CR148, 0x40 }, /* 5112 */ + { ZD_CR149, 0x40 }, /* 4O07, 50->40 */ + { ZD_CR150, 0x1a }, /* 5112, 0C->1A */ + { ZD_CR252, 0x34 }, { ZD_CR253, 0x34 }, + { ZD_CR251, 0x2f }, /* PLL_OFF */ }; static const struct zd_ioreq16 ioreqs_3[] = { - { CR251, 0x7f }, /* PLL_ON */ - { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, - { CR38, 0x38 }, { CR136, 0xdf }, + { ZD_CR251, 0x7f }, /* PLL_ON */ + { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, + { ZD_CR38, 0x38 }, { ZD_CR136, 0xdf }, }; r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1)); @@ -331,16 +331,16 @@ static int zd1211_al7230b_set_channel(struct zd_rf *rf, u8 channel) static const struct zd_ioreq16 ioreqs[] = { /* PLL_ON */ - { CR251, 0x3f }, - { CR203, 0x06 }, { CR240, 0x08 }, + { ZD_CR251, 0x3f }, + { ZD_CR203, 0x06 }, { ZD_CR240, 0x08 }, }; - r = zd_iowrite16_locked(chip, 0x57, CR240); + r = zd_iowrite16_locked(chip, 0x57, ZD_CR240); if (r) return r; /* PLL_OFF */ - r = zd_iowrite16_locked(chip, 0x2f, CR251); + r = zd_iowrite16_locked(chip, 0x2f, ZD_CR251); if (r) return r; @@ -376,15 +376,15 @@ static int zd1211b_al7230b_set_channel(struct zd_rf *rf, u8 channel) const u32 *rv = chan_rv[channel-1]; struct zd_chip *chip = zd_rf_to_chip(rf); - r = zd_iowrite16_locked(chip, 0x57, CR240); + r = zd_iowrite16_locked(chip, 0x57, ZD_CR240); if (r) return r; - r = zd_iowrite16_locked(chip, 0xe4, CR9); + r = zd_iowrite16_locked(chip, 0xe4, ZD_CR9); if (r) return r; /* PLL_OFF */ - r = zd_iowrite16_locked(chip, 0x2f, CR251); + r = zd_iowrite16_locked(chip, 0x2f, ZD_CR251); if (r) return r; r = zd_rfwritev_cr_locked(chip, std_rv, ARRAY_SIZE(std_rv)); @@ -410,7 +410,7 @@ static int zd1211b_al7230b_set_channel(struct zd_rf *rf, u8 channel) if (r) return r; - r = zd_iowrite16_locked(chip, 0x7f, CR251); + r = zd_iowrite16_locked(chip, 0x7f, ZD_CR251); if (r) return r; @@ -421,8 +421,8 @@ static int zd1211_al7230b_switch_radio_on(struct zd_rf *rf) { struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR11, 0x00 }, - { CR251, 0x3f }, + { ZD_CR11, 0x00 }, + { ZD_CR251, 0x3f }, }; return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); @@ -432,8 +432,8 @@ static int zd1211b_al7230b_switch_radio_on(struct zd_rf *rf) { struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR11, 0x00 }, - { CR251, 0x7f }, + { ZD_CR11, 0x00 }, + { ZD_CR251, 0x7f }, }; return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); @@ -443,8 +443,8 @@ static int al7230b_switch_radio_off(struct zd_rf *rf) { struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR11, 0x04 }, - { CR251, 0x2f }, + { ZD_CR11, 0x04 }, + { ZD_CR251, 0x2f }, }; return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); @@ -456,7 +456,7 @@ static int zd1211b_al7230b_patch_6m(struct zd_rf *rf, u8 channel) { struct zd_chip *chip = zd_rf_to_chip(rf); struct zd_ioreq16 ioreqs[] = { - { CR128, 0x14 }, { CR129, 0x12 }, + { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, }; /* FIXME: Channel 11 is not the edge for all regulatory domains. */ diff --git a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c index e36117486c91..784d9ccb8fef 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c @@ -152,44 +152,44 @@ static int rf2959_init_hw(struct zd_rf *rf) struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR2, 0x1E }, { CR9, 0x20 }, { CR10, 0x89 }, - { CR11, 0x00 }, { CR15, 0xD0 }, { CR17, 0x68 }, - { CR19, 0x4a }, { CR20, 0x0c }, { CR21, 0x0E }, - { CR23, 0x48 }, + { ZD_CR2, 0x1E }, { ZD_CR9, 0x20 }, { ZD_CR10, 0x89 }, + { ZD_CR11, 0x00 }, { ZD_CR15, 0xD0 }, { ZD_CR17, 0x68 }, + { ZD_CR19, 0x4a }, { ZD_CR20, 0x0c }, { ZD_CR21, 0x0E }, + { ZD_CR23, 0x48 }, /* normal size for cca threshold */ - { CR24, 0x14 }, - /* { CR24, 0x20 }, */ - { CR26, 0x90 }, { CR27, 0x30 }, { CR29, 0x20 }, - { CR31, 0xb2 }, { CR32, 0x43 }, { CR33, 0x28 }, - { CR38, 0x30 }, { CR34, 0x0f }, { CR35, 0xF0 }, - { CR41, 0x2a }, { CR46, 0x7F }, { CR47, 0x1E }, - { CR51, 0xc5 }, { CR52, 0xc5 }, { CR53, 0xc5 }, - { CR79, 0x58 }, { CR80, 0x30 }, { CR81, 0x30 }, - { CR82, 0x00 }, { CR83, 0x24 }, { CR84, 0x04 }, - { CR85, 0x00 }, { CR86, 0x10 }, { CR87, 0x2A }, - { CR88, 0x10 }, { CR89, 0x24 }, { CR90, 0x18 }, - /* { CR91, 0x18 }, */ + { ZD_CR24, 0x14 }, + /* { ZD_CR24, 0x20 }, */ + { ZD_CR26, 0x90 }, { ZD_CR27, 0x30 }, { ZD_CR29, 0x20 }, + { ZD_CR31, 0xb2 }, { ZD_CR32, 0x43 }, { ZD_CR33, 0x28 }, + { ZD_CR38, 0x30 }, { ZD_CR34, 0x0f }, { ZD_CR35, 0xF0 }, + { ZD_CR41, 0x2a }, { ZD_CR46, 0x7F }, { ZD_CR47, 0x1E }, + { ZD_CR51, 0xc5 }, { ZD_CR52, 0xc5 }, { ZD_CR53, 0xc5 }, + { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, + { ZD_CR82, 0x00 }, { ZD_CR83, 0x24 }, { ZD_CR84, 0x04 }, + { ZD_CR85, 0x00 }, { ZD_CR86, 0x10 }, { ZD_CR87, 0x2A }, + { ZD_CR88, 0x10 }, { ZD_CR89, 0x24 }, { ZD_CR90, 0x18 }, + /* { ZD_CR91, 0x18 }, */ /* should solve continuous CTS frame problems */ - { CR91, 0x00 }, - { CR92, 0x0a }, { CR93, 0x00 }, { CR94, 0x01 }, - { CR95, 0x00 }, { CR96, 0x40 }, { CR97, 0x37 }, - { CR98, 0x05 }, { CR99, 0x28 }, { CR100, 0x00 }, - { CR101, 0x13 }, { CR102, 0x27 }, { CR103, 0x27 }, - { CR104, 0x18 }, { CR105, 0x12 }, + { ZD_CR91, 0x00 }, + { ZD_CR92, 0x0a }, { ZD_CR93, 0x00 }, { ZD_CR94, 0x01 }, + { ZD_CR95, 0x00 }, { ZD_CR96, 0x40 }, { ZD_CR97, 0x37 }, + { ZD_CR98, 0x05 }, { ZD_CR99, 0x28 }, { ZD_CR100, 0x00 }, + { ZD_CR101, 0x13 }, { ZD_CR102, 0x27 }, { ZD_CR103, 0x27 }, + { ZD_CR104, 0x18 }, { ZD_CR105, 0x12 }, /* normal size */ - { CR106, 0x1a }, - /* { CR106, 0x22 }, */ - { CR107, 0x24 }, { CR108, 0x0a }, { CR109, 0x13 }, - { CR110, 0x2F }, { CR111, 0x27 }, { CR112, 0x27 }, - { CR113, 0x27 }, { CR114, 0x27 }, { CR115, 0x40 }, - { CR116, 0x40 }, { CR117, 0xF0 }, { CR118, 0xF0 }, - { CR119, 0x16 }, + { ZD_CR106, 0x1a }, + /* { ZD_CR106, 0x22 }, */ + { ZD_CR107, 0x24 }, { ZD_CR108, 0x0a }, { ZD_CR109, 0x13 }, + { ZD_CR110, 0x2F }, { ZD_CR111, 0x27 }, { ZD_CR112, 0x27 }, + { ZD_CR113, 0x27 }, { ZD_CR114, 0x27 }, { ZD_CR115, 0x40 }, + { ZD_CR116, 0x40 }, { ZD_CR117, 0xF0 }, { ZD_CR118, 0xF0 }, + { ZD_CR119, 0x16 }, /* no TX continuation */ - { CR122, 0x00 }, - /* { CR122, 0xff }, */ - { CR127, 0x03 }, { CR131, 0x08 }, { CR138, 0x28 }, - { CR148, 0x44 }, { CR150, 0x10 }, { CR169, 0xBB }, - { CR170, 0xBB }, + { ZD_CR122, 0x00 }, + /* { ZD_CR122, 0xff }, */ + { ZD_CR127, 0x03 }, { ZD_CR131, 0x08 }, { ZD_CR138, 0x28 }, + { ZD_CR148, 0x44 }, { ZD_CR150, 0x10 }, { ZD_CR169, 0xBB }, + { ZD_CR170, 0xBB }, }; static const u32 rv[] = { @@ -210,7 +210,7 @@ static int rf2959_init_hw(struct zd_rf *rf) */ 0x294128, /* internal power */ /* 0x28252c, */ /* External control TX power */ - /* CR31_CCK, CR51_6-36M, CR52_48M, CR53_54M */ + /* ZD_CR31_CCK, ZD_CR51_6-36M, ZD_CR52_48M, ZD_CR53_54M */ 0x2c0000, 0x300000, 0x340000, /* REG13(0xD) */ @@ -245,8 +245,8 @@ static int rf2959_set_channel(struct zd_rf *rf, u8 channel) static int rf2959_switch_radio_on(struct zd_rf *rf) { static const struct zd_ioreq16 ioreqs[] = { - { CR10, 0x89 }, - { CR11, 0x00 }, + { ZD_CR10, 0x89 }, + { ZD_CR11, 0x00 }, }; struct zd_chip *chip = zd_rf_to_chip(rf); @@ -256,8 +256,8 @@ static int rf2959_switch_radio_on(struct zd_rf *rf) static int rf2959_switch_radio_off(struct zd_rf *rf) { static const struct zd_ioreq16 ioreqs[] = { - { CR10, 0x15 }, - { CR11, 0x81 }, + { ZD_CR10, 0x15 }, + { ZD_CR11, 0x81 }, }; struct zd_chip *chip = zd_rf_to_chip(rf); diff --git a/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c b/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c index ba0a0ccb1fa0..c4d324e19c24 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c @@ -314,42 +314,44 @@ static int uw2453_init_hw(struct zd_rf *rf) struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR10, 0x89 }, { CR15, 0x20 }, - { CR17, 0x28 }, /* 6112 no change */ - { CR23, 0x38 }, { CR24, 0x20 }, { CR26, 0x93 }, - { CR27, 0x15 }, { CR28, 0x3e }, { CR29, 0x00 }, - { CR33, 0x28 }, { CR34, 0x30 }, - { CR35, 0x43 }, /* 6112 3e->43 */ - { CR41, 0x24 }, { CR44, 0x32 }, - { CR46, 0x92 }, /* 6112 96->92 */ - { CR47, 0x1e }, - { CR48, 0x04 }, /* 5602 Roger */ - { CR49, 0xfa }, { CR79, 0x58 }, { CR80, 0x30 }, - { CR81, 0x30 }, { CR87, 0x0a }, { CR89, 0x04 }, - { CR91, 0x00 }, { CR92, 0x0a }, { CR98, 0x8d }, - { CR99, 0x28 }, { CR100, 0x02 }, - { CR101, 0x09 }, /* 6112 13->1f 6220 1f->13 6407 13->9 */ - { CR102, 0x27 }, - { CR106, 0x1c }, /* 5d07 5112 1f->1c 6220 1c->1f 6221 1f->1c */ - { CR107, 0x1c }, /* 6220 1c->1a 5221 1a->1c */ - { CR109, 0x13 }, - { CR110, 0x1f }, /* 6112 13->1f 6221 1f->13 6407 13->0x09 */ - { CR111, 0x13 }, { CR112, 0x1f }, { CR113, 0x27 }, - { CR114, 0x23 }, /* 6221 27->23 */ - { CR115, 0x24 }, /* 6112 24->1c 6220 1c->24 */ - { CR116, 0x24 }, /* 6220 1c->24 */ - { CR117, 0xfa }, /* 6112 fa->f8 6220 f8->f4 6220 f4->fa */ - { CR118, 0xf0 }, /* 5d07 6112 f0->f2 6220 f2->f0 */ - { CR119, 0x1a }, /* 6112 1a->10 6220 10->14 6220 14->1a */ - { CR120, 0x4f }, - { CR121, 0x1f }, /* 6220 4f->1f */ - { CR122, 0xf0 }, { CR123, 0x57 }, { CR125, 0xad }, - { CR126, 0x6c }, { CR127, 0x03 }, - { CR128, 0x14 }, /* 6302 12->11 */ - { CR129, 0x12 }, /* 6301 10->0f */ - { CR130, 0x10 }, { CR137, 0x50 }, { CR138, 0xa8 }, - { CR144, 0xac }, { CR146, 0x20 }, { CR252, 0xff }, - { CR253, 0xff }, + { ZD_CR10, 0x89 }, { ZD_CR15, 0x20 }, + { ZD_CR17, 0x28 }, /* 6112 no change */ + { ZD_CR23, 0x38 }, { ZD_CR24, 0x20 }, { ZD_CR26, 0x93 }, + { ZD_CR27, 0x15 }, { ZD_CR28, 0x3e }, { ZD_CR29, 0x00 }, + { ZD_CR33, 0x28 }, { ZD_CR34, 0x30 }, + { ZD_CR35, 0x43 }, /* 6112 3e->43 */ + { ZD_CR41, 0x24 }, { ZD_CR44, 0x32 }, + { ZD_CR46, 0x92 }, /* 6112 96->92 */ + { ZD_CR47, 0x1e }, + { ZD_CR48, 0x04 }, /* 5602 Roger */ + { ZD_CR49, 0xfa }, { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, + { ZD_CR81, 0x30 }, { ZD_CR87, 0x0a }, { ZD_CR89, 0x04 }, + { ZD_CR91, 0x00 }, { ZD_CR92, 0x0a }, { ZD_CR98, 0x8d }, + { ZD_CR99, 0x28 }, { ZD_CR100, 0x02 }, + { ZD_CR101, 0x09 }, /* 6112 13->1f 6220 1f->13 6407 13->9 */ + { ZD_CR102, 0x27 }, + { ZD_CR106, 0x1c }, /* 5d07 5112 1f->1c 6220 1c->1f + * 6221 1f->1c + */ + { ZD_CR107, 0x1c }, /* 6220 1c->1a 5221 1a->1c */ + { ZD_CR109, 0x13 }, + { ZD_CR110, 0x1f }, /* 6112 13->1f 6221 1f->13 6407 13->0x09 */ + { ZD_CR111, 0x13 }, { ZD_CR112, 0x1f }, { ZD_CR113, 0x27 }, + { ZD_CR114, 0x23 }, /* 6221 27->23 */ + { ZD_CR115, 0x24 }, /* 6112 24->1c 6220 1c->24 */ + { ZD_CR116, 0x24 }, /* 6220 1c->24 */ + { ZD_CR117, 0xfa }, /* 6112 fa->f8 6220 f8->f4 6220 f4->fa */ + { ZD_CR118, 0xf0 }, /* 5d07 6112 f0->f2 6220 f2->f0 */ + { ZD_CR119, 0x1a }, /* 6112 1a->10 6220 10->14 6220 14->1a */ + { ZD_CR120, 0x4f }, + { ZD_CR121, 0x1f }, /* 6220 4f->1f */ + { ZD_CR122, 0xf0 }, { ZD_CR123, 0x57 }, { ZD_CR125, 0xad }, + { ZD_CR126, 0x6c }, { ZD_CR127, 0x03 }, + { ZD_CR128, 0x14 }, /* 6302 12->11 */ + { ZD_CR129, 0x12 }, /* 6301 10->0f */ + { ZD_CR130, 0x10 }, { ZD_CR137, 0x50 }, { ZD_CR138, 0xa8 }, + { ZD_CR144, 0xac }, { ZD_CR146, 0x20 }, { ZD_CR252, 0xff }, + { ZD_CR253, 0xff }, }; static const u32 rv[] = { @@ -433,7 +435,7 @@ static int uw2453_init_hw(struct zd_rf *rf) * the one that produced a lock. */ UW2453_PRIV(rf)->config = found_config + 1; - return zd_iowrite16_locked(chip, 0x06, CR203); + return zd_iowrite16_locked(chip, 0x06, ZD_CR203); } static int uw2453_set_channel(struct zd_rf *rf, u8 channel) @@ -445,8 +447,8 @@ static int uw2453_set_channel(struct zd_rf *rf, u8 channel) struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR80, 0x30 }, { CR81, 0x30 }, { CR79, 0x58 }, - { CR12, 0xf0 }, { CR77, 0x1b }, { CR78, 0x58 }, + { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, { ZD_CR79, 0x58 }, + { ZD_CR12, 0xf0 }, { ZD_CR77, 0x1b }, { ZD_CR78, 0x58 }, }; r = uw2453_synth_set_channel(chip, channel, autocal); @@ -474,7 +476,7 @@ static int uw2453_set_channel(struct zd_rf *rf, u8 channel) if (r) return r; - return zd_iowrite16_locked(chip, 0x06, CR203); + return zd_iowrite16_locked(chip, 0x06, ZD_CR203); } static int uw2453_switch_radio_on(struct zd_rf *rf) @@ -482,7 +484,7 @@ static int uw2453_switch_radio_on(struct zd_rf *rf) int r; struct zd_chip *chip = zd_rf_to_chip(rf); struct zd_ioreq16 ioreqs[] = { - { CR11, 0x00 }, { CR251, 0x3f }, + { ZD_CR11, 0x00 }, { ZD_CR251, 0x3f }, }; /* enter RXTX mode */ @@ -501,7 +503,7 @@ static int uw2453_switch_radio_off(struct zd_rf *rf) int r; struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR11, 0x04 }, { CR251, 0x2f }, + { ZD_CR11, 0x04 }, { ZD_CR251, 0x2f }, }; /* enter IDLE mode */ diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index ab607bbd6291..0e819943b9e4 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -1893,10 +1893,10 @@ int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits) dev_dbg_f(zd_usb_dev(usb), "value %#09x bits %d\n", value, bits); - r = zd_usb_ioread16(usb, &bit_value_template, CR203); + r = zd_usb_ioread16(usb, &bit_value_template, ZD_CR203); if (r) { dev_dbg_f(zd_usb_dev(usb), - "error %d: Couldn't read CR203\n", r); + "error %d: Couldn't read ZD_CR203\n", r); return r; } bit_value_template &= ~(RF_IF_LE|RF_CLK|RF_DATA); diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h index 325d0f989257..bf942843b733 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.h +++ b/drivers/net/wireless/zd1211rw/zd_usb.h @@ -109,7 +109,7 @@ struct usb_req_rfwrite { __le16 bits; /* RF2595: 24 */ __le16 bit_values[0]; - /* (CR203 & ~(RF_IF_LE | RF_CLK | RF_DATA)) | (bit ? RF_DATA : 0) */ + /* (ZD_CR203 & ~(RF_IF_LE | RF_CLK | RF_DATA)) | (bit ? RF_DATA : 0) */ } __packed; /* USB interrupt */ diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c index 22b8c3505991..1ce729d6af75 100644 --- a/drivers/net/xen-netback/xenbus.c +++ b/drivers/net/xen-netback/xenbus.c @@ -26,7 +26,7 @@ struct backend_info { struct xenvif *vif; enum xenbus_state frontend_state; struct xenbus_watch hotplug_status_watch; - int have_hotplug_status_watch:1; + u8 have_hotplug_status_watch:1; }; static int connect_rings(struct backend_info *); diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 5c8d9c385be0..db9a763aaa7f 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -1140,6 +1140,42 @@ static void xennet_uninit(struct net_device *dev) gnttab_free_grant_references(np->gref_rx_head); } +static u32 xennet_fix_features(struct net_device *dev, u32 features) +{ + struct netfront_info *np = netdev_priv(dev); + int val; + + if (features & NETIF_F_SG) { + if (xenbus_scanf(XBT_NIL, np->xbdev->otherend, "feature-sg", + "%d", &val) < 0) + val = 0; + + if (!val) + features &= ~NETIF_F_SG; + } + + if (features & NETIF_F_TSO) { + if (xenbus_scanf(XBT_NIL, np->xbdev->otherend, + "feature-gso-tcpv4", "%d", &val) < 0) + val = 0; + + if (!val) + features &= ~NETIF_F_TSO; + } + + return features; +} + +static int xennet_set_features(struct net_device *dev, u32 features) +{ + if (!(features & NETIF_F_SG) && dev->mtu > ETH_DATA_LEN) { + netdev_info(dev, "Reducing MTU because no SG offload"); + dev->mtu = ETH_DATA_LEN; + } + + return 0; +} + static const struct net_device_ops xennet_netdev_ops = { .ndo_open = xennet_open, .ndo_uninit = xennet_uninit, @@ -1148,6 +1184,8 @@ static const struct net_device_ops xennet_netdev_ops = { .ndo_change_mtu = xennet_change_mtu, .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, + .ndo_fix_features = xennet_fix_features, + .ndo_set_features = xennet_set_features, }; static struct net_device * __devinit xennet_create_dev(struct xenbus_device *dev) @@ -1209,7 +1247,17 @@ static struct net_device * __devinit xennet_create_dev(struct xenbus_device *dev netdev->netdev_ops = &xennet_netdev_ops; netif_napi_add(netdev, &np->napi, xennet_poll, 64); - netdev->features = NETIF_F_IP_CSUM; + netdev->features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM | + NETIF_F_GSO_ROBUST; + netdev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO; + + /* + * Assume that all hw features are available for now. This set + * will be adjusted by the call to netdev_update_features() in + * xennet_connect() which is the earliest point where we can + * negotiate with the backend regarding supported features. + */ + netdev->features |= netdev->hw_features; SET_ETHTOOL_OPS(netdev, &xennet_ethtool_ops); SET_NETDEV_DEV(netdev, &dev->dev); @@ -1416,8 +1464,7 @@ static int setup_netfront(struct xenbus_device *dev, struct netfront_info *info) goto fail; err = bind_evtchn_to_irqhandler(info->evtchn, xennet_interrupt, - IRQF_SAMPLE_RANDOM, netdev->name, - netdev); + 0, netdev->name, netdev); if (err < 0) goto fail; netdev->irq = err; @@ -1510,54 +1557,6 @@ again: return err; } -static int xennet_set_sg(struct net_device *dev, u32 data) -{ - if (data) { - struct netfront_info *np = netdev_priv(dev); - int val; - - if (xenbus_scanf(XBT_NIL, np->xbdev->otherend, "feature-sg", - "%d", &val) < 0) - val = 0; - if (!val) - return -ENOSYS; - } else if (dev->mtu > ETH_DATA_LEN) - dev->mtu = ETH_DATA_LEN; - - return ethtool_op_set_sg(dev, data); -} - -static int xennet_set_tso(struct net_device *dev, u32 data) -{ - if (data) { - struct netfront_info *np = netdev_priv(dev); - int val; - - if (xenbus_scanf(XBT_NIL, np->xbdev->otherend, - "feature-gso-tcpv4", "%d", &val) < 0) - val = 0; - if (!val) - return -ENOSYS; - } - - return ethtool_op_set_tso(dev, data); -} - -static void xennet_set_features(struct net_device *dev) -{ - /* Turn off all GSO bits except ROBUST. */ - dev->features &= ~NETIF_F_GSO_MASK; - dev->features |= NETIF_F_GSO_ROBUST; - xennet_set_sg(dev, 0); - - /* We need checksum offload to enable scatter/gather and TSO. */ - if (!(dev->features & NETIF_F_IP_CSUM)) - return; - - if (!xennet_set_sg(dev, 1)) - xennet_set_tso(dev, 1); -} - static int xennet_connect(struct net_device *dev) { struct netfront_info *np = netdev_priv(dev); @@ -1582,7 +1581,7 @@ static int xennet_connect(struct net_device *dev) if (err) return err; - xennet_set_features(dev); + netdev_update_features(dev); spin_lock_bh(&np->rx_lock); spin_lock_irq(&np->tx_lock); @@ -1710,9 +1709,6 @@ static void xennet_get_strings(struct net_device *dev, u32 stringset, u8 * data) static const struct ethtool_ops xennet_ethtool_ops = { - .set_tx_csum = ethtool_op_set_tx_csum, - .set_sg = xennet_set_sg, - .set_tso = xennet_set_tso, .get_link = ethtool_op_get_link, .get_sset_count = xennet_get_sset_count, |